From 68af28cffdbcb34fb1961ff235af6799acff5475 Mon Sep 17 00:00:00 2001 From: drslebedev <dr.s.lebedev@gmail.com> Date: Wed, 30 Jun 2021 12:17:11 +0200 Subject: [PATCH] New RICH unpacker for the new data format for 2021 beamtime. * The old unpacker is still in the repository CbmMcbm2018UnpackerAlgoRich2020 * The old unpacker are still needed to analyze old data, later it will be removed * Clang-format * Update macro --- fles/mcbm2018/CMakeLists.txt | 4 +- fles/mcbm2018/CbmFlibMcbm2018LinkDef.h | 2 + .../unpacker/CbmMcbm2018UnpackerAlgoRich.cxx | 1849 +++------------- .../unpacker/CbmMcbm2018UnpackerAlgoRich.h | 404 ++-- .../CbmMcbm2018UnpackerAlgoRich2020.cxx | 1882 +++++++++++++++++ .../CbmMcbm2018UnpackerAlgoRich2020.h | 384 ++++ .../CbmMcbm2018UnpackerTaskRich2020.cxx | 258 +++ .../CbmMcbm2018UnpackerTaskRich2020.h | 75 + .../unpacker/CbmMcbm2018UnpackerUtilRich.hpp | 125 -- ...xx => CbmMcbm2018UnpackerUtilRich2020.cxx} | 2 +- ...ch.h => CbmMcbm2018UnpackerUtilRich2020.h} | 6 +- macro/beamtime/mcbm2018/MonitorRich.C | 12 +- macro/beamtime/mcbm2019/MonitorRich.C | 2 +- macro/beamtime/mcbm2019/unpack_tsa_mcbm.C | 10 +- macro/beamtime/mcbm2020/MonitorRich.C | 10 +- macro/beamtime/mcbm2020/unpack_tsa_mcbm.C | 12 +- macro/beamtime/mcbm2021/MonitorRich.C | 105 + 17 files changed, 3264 insertions(+), 1878 deletions(-) create mode 100644 fles/mcbm2018/unpacker/CbmMcbm2018UnpackerAlgoRich2020.cxx create mode 100644 fles/mcbm2018/unpacker/CbmMcbm2018UnpackerAlgoRich2020.h create mode 100644 fles/mcbm2018/unpacker/CbmMcbm2018UnpackerTaskRich2020.cxx create mode 100644 fles/mcbm2018/unpacker/CbmMcbm2018UnpackerTaskRich2020.h delete mode 100644 fles/mcbm2018/unpacker/CbmMcbm2018UnpackerUtilRich.hpp rename fles/mcbm2018/unpacker/{CbmMcbm2018UnpackerUtilRich.cxx => CbmMcbm2018UnpackerUtilRich2020.cxx} (98%) rename fles/mcbm2018/unpacker/{CbmMcbm2018UnpackerUtilRich.h => CbmMcbm2018UnpackerUtilRich2020.h} (87%) create mode 100644 macro/beamtime/mcbm2021/MonitorRich.C diff --git a/fles/mcbm2018/CMakeLists.txt b/fles/mcbm2018/CMakeLists.txt index ae02f061b7..0a1d9a4273 100644 --- a/fles/mcbm2018/CMakeLists.txt +++ b/fles/mcbm2018/CMakeLists.txt @@ -73,7 +73,9 @@ Set(SRCS unpacker/CbmMcbm2018UnpackerTaskTof.cxx unpacker/CbmMcbm2018UnpackerAlgoRich.cxx unpacker/CbmMcbm2018UnpackerTaskRich.cxx - unpacker/CbmMcbm2018UnpackerUtilRich.cxx + unpacker/CbmMcbm2018UnpackerTaskRich2020.cxx + unpacker/CbmMcbm2018UnpackerAlgoRich2020.cxx + unpacker/CbmMcbm2018UnpackerUtilRich2020.cxx unpacker/CbmMcbm2018UnpackerAlgoPsd.cxx unpacker/CbmMcbm2018UnpackerTaskPsd.cxx unpacker/CbmMcbm2018UnpackerAlgoTrdR.cxx diff --git a/fles/mcbm2018/CbmFlibMcbm2018LinkDef.h b/fles/mcbm2018/CbmFlibMcbm2018LinkDef.h index ea95ccbbca..674783848c 100644 --- a/fles/mcbm2018/CbmFlibMcbm2018LinkDef.h +++ b/fles/mcbm2018/CbmFlibMcbm2018LinkDef.h @@ -22,7 +22,9 @@ #pragma link C++ class CbmMcbm2018UnpackerAlgoTof; #pragma link C++ class CbmMcbm2018UnpackerTaskTof + ; #pragma link C++ class CbmMcbm2018UnpackerAlgoRich; +#pragma link C++ class CbmMcbm2018UnpackerAlgoRich2020; #pragma link C++ class CbmMcbm2018UnpackerTaskRich + ; +#pragma link C++ class CbmMcbm2018UnpackerTaskRich2020 + ; #pragma link C++ class CbmMcbm2018UnpackerAlgoPsd; #pragma link C++ class CbmMcbm2018UnpackerTaskPsd + ; #pragma link C++ class CbmMcbm2018UnpackerAlgoTrdR + ; diff --git a/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerAlgoRich.cxx b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerAlgoRich.cxx index 03c83ca0e5..a6daab289c 100644 --- a/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerAlgoRich.cxx +++ b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerAlgoRich.cxx @@ -5,62 +5,10 @@ /** * CbmMcbm2018UnpackerAlgoRich * E. Ovcharenko, Mar 2019 + * S. Lebedev, June 2021 * based on other detectors' classes by P.-A. Loizeau */ -/** - -Consider two consequent microslices A and B. -Each microslice contains one CTS subevent which contains at least 3 timestamp messages. -A microslice may also contain TRB subevents, each containing also one timestamp message from ch0. - -Microslice A -=================== -CTS | ch 0 re = AC0R (stands for ms A, Cts, ch 0, Rising edge) -CTS | ch 2 fe -CTS | ch 2 re = AC2R (stands for ms A, Cts, ch 2, Rising edge) -------------------- -TDC K | ch 0 re -------------------- -TDC Z | ch 0 re = AZ0R (stands for ms A, tdc Z, ch 0, Rising edge)) - | ch X re - | ch X fe - | ... -------------------- -... -=================== - -Microslice B (next after A) -=================== -CTS | ch 0 re -CTS | ch 2 fe -CTS | ch 2 re -------------------- -TDC L | ch 0 re -------------------- -TDC Z | ch 0 re - | ch Y re = (T - AZ0R) + corr - | ch Y fe - | ... -------------------- -... -=================== - -corr = -(AC2R-AC0R) - -Uncorrected full time in ns of the TIMESTAMP message calculated as -T = epoch*2048.*5. + (coarse)*5. - fine*0.005 - -Full corrected global time is then computed by adding the microslice -index from the descriptor to the corrected time: - -fullTimeCorr = (T - AZ0R) - (AC2R-AC0R) + MSidx - -*/ - -//TODO: Check that to 'real' actions are performed in the lines which are intended for debug output only. -// i.e. LOG(XXXX) << ... - #include "CbmMcbm2018UnpackerAlgoRich.h" // ROOT @@ -74,42 +22,7 @@ fullTimeCorr = (T - AZ0R) - (AC2R-AC0R) + MSidx #include <iostream> -CbmMcbm2018UnpackerAlgoRich::CbmMcbm2018UnpackerAlgoRich() - : CbmStar2019Algo() - , fbMonitorMode(kFALSE) - , fbDebugMonitorMode(kFALSE) - , fRawDataMode(kFALSE) - , fError(kFALSE) - , fTrbState(TrbNetState::IDLE) - , fErrorCorr(0) - , fbDoToTCorr(kTRUE) - , fSkipMs(kFALSE) - , fdTimeOffsetNs(0.0) - , fRICHcompIdx(6) - , //TODO experimentally obtained value - fUnpackPar(nullptr) - , fTScounter(0) - , fCurMSid(0) - , fGwordCnt(0) - , fInSubSubEvent(kFALSE) - , fCurEpochCounter(0) - , fSubSubEvId(0) - , fLastCTSch0_re_time(0.) - , fLastCTSch2_re_time(0.) - , fLastCTSch2_fe_time(0.) - , fPrevLastCTSch0_re_time(0.) - , fPrevLastCTSch2_re_time(0.) - , fPrevLastCTSch2_fe_time(0.) - , /*, - fhTDCch0re_minusCTSch0re(nullptr), - fhTDCch0re_minusCTSch2re(nullptr), - fhTDCch0re_minusCTSch2fe(nullptr), - fhTDCch0re_minusPrevCTSch0re(nullptr), - fhTDCch0re_minusPrevCTSch2re(nullptr), - fhTDCch0re_minusPrevCTSch2fe(nullptr)*/ - fMapFEE() - , fhTotMap() - , fhTot2dMap() +CbmMcbm2018UnpackerAlgoRich::CbmMcbm2018UnpackerAlgoRich() : CbmStar2019Algo() { this->Init(); //TODO why this is not called by the framework? } @@ -120,13 +33,7 @@ CbmMcbm2018UnpackerAlgoRich::~CbmMcbm2018UnpackerAlgoRich() if (nullptr != fUnpackPar) delete fUnpackPar; } -Bool_t CbmMcbm2018UnpackerAlgoRich::Init() -{ - LOG(info) << "Initializing mCBM RICH 2019 unpacker algo"; - //fhDigisInChnl = new TH2D("fhDigisInChnl","fhDigisInChnl;channel;#Digis;" ,2304 , -0.5, 2303.5, 50, -0.5, 49.5); - //fhDigisInDiRICH = new TH2D("fhDigisInDiRICH","fhDigisInDiRICH;DiRICH;#Digis;",72 , -0.5, 71.5, 300, -0.5, 299.5); - return kTRUE; -} +Bool_t CbmMcbm2018UnpackerAlgoRich::Init() { return kTRUE; } void CbmMcbm2018UnpackerAlgoRich::Reset() {} @@ -167,16 +74,8 @@ Bool_t CbmMcbm2018UnpackerAlgoRich::InitParameters() return kTRUE; } -void CbmMcbm2018UnpackerAlgoRich::InitStorage() -{ - fLastCh0_re_time.Set(fUnpackPar->GetNaddresses()); // Set the size of the array - fPrevLastCh0_re_time.Set(fUnpackPar->GetNaddresses()); // Set the size of the array -} +void CbmMcbm2018UnpackerAlgoRich::InitStorage() {} -/** - Copied from other detectors without any brain effort... - A little bug-fix added -**/ void CbmMcbm2018UnpackerAlgoRich::AddMsComponentToList(size_t component, UShort_t usDetectorId) { /// Check for duplicates and ignore if it is the case @@ -189,8 +88,7 @@ void CbmMcbm2018UnpackerAlgoRich::AddMsComponentToList(size_t component, UShort_ if (fvMsComponentsList.size() == 1) { fRICHcompIdx = component; } else { - LOG(WARN) << "fvMsComponentsList.size() > 1 for RICH. Unpacking may not " - "work due to implementation limitations."; + LOG(WARN) << "fvMsComponentsList.size() > 1 for RICH. Unpacking may not work due to implementation limitations."; } LOG(info) << "CbmMcbm2018UnpackerAlgoRich::AddMsComponentToList => Component " << component << " with detector ID 0x" @@ -199,41 +97,30 @@ void CbmMcbm2018UnpackerAlgoRich::AddMsComponentToList(size_t component, UShort_ Bool_t CbmMcbm2018UnpackerAlgoRich::ProcessTs(const fles::Timeslice& /*ts*/) { - LOG(debug2) << "CbmMcbm2018UnpackerAlgoRich::ProcessTs(ts)"; - /* - //TODO: shortcut. We love shortcuts, right? - if (fvMsComponentsList.size() == 1) { - this->ProcessTs(ts, fvMsComponentsList.at(0)); - } - - //TODO: implement case when multiple components have to be processed -*/ + LOG(debug2) << "CbmMcbm2018UnpackerAlgoRich::ProcessTs(ts): this method do not have implementation."; return kTRUE; } Bool_t CbmMcbm2018UnpackerAlgoRich::ProcessTs(const fles::Timeslice& ts, size_t component) { /// Ignore First TS as first MS is typically corrupt - if (0 == ts.index()) { return kTRUE; } // if( 0 == ts.index() ) + if (0 == ts.index()) { return kTRUE; } LOG(debug2) << "CbmMcbm2018UnpackerAlgoRich::ProcessTs(ts, " << component << ")"; - //TODO: skip if this method was called for a wrong component - //if (component != fRICHcompIdx) return kTRUE; - //FIXME: this is really nasty... - // component = fRICHcompIdx; if (1 != fvMsComponentsList.size()) { /// If no RICH component, do nothing! if (0 == fvMsComponentsList.size()) return kTRUE; /// If multiple RICH components, fail the run TString sCompList = ""; - for (UInt_t uMsCompIdx = 0; uMsCompIdx < fvMsComponentsList.size(); ++uMsCompIdx) + for (UInt_t uMsCompIdx = 0; uMsCompIdx < fvMsComponentsList.size(); ++uMsCompIdx) { sCompList += Form(" %2lu ", fvMsComponentsList[uMsCompIdx]); - LOG(fatal) << "CbmMcbm2018UnpackerAlgoRich::ProcessTs => More than 1 " - "component in list, unpacking impossible! List is " - << sCompList; - } // if( 1 != fvMsComponentsList.size() ) + } + LOG(fatal) + << "CbmMcbm2018UnpackerAlgoRich::ProcessTs => More than 1 component in list, unpacking impossible! List is " + << sCompList; + } component = fvMsComponentsList[0]; LOG(debug) << "Components: " << ts.num_components(); @@ -259,1133 +146,359 @@ Bool_t CbmMcbm2018UnpackerAlgoRich::ProcessTs(const fles::Timeslice& ts, size_t } // if( -1.0 == fdTsCoreSizeInNs ) for (size_t iMS = 0; iMS < fuNbMsLoop; ++iMS) { - fCurMSid = iMS; - LOG(debug) << "======================================================="; + fMsInd = iMS; + if (IsLog()) LOG(debug) << "======================================================="; const fles::MicrosliceView mv = ts.get_microslice(component, iMS); const fles::MicrosliceDescriptor& msDesc = mv.desc(); - ////const uint8_t* msContent = mv.content(); - LOG(debug) << "msDesc.size=" << msDesc.size; + fCurMSidx = msDesc.idx; - LOG(debug) << "msDesc.idx=" << msDesc.idx; - ////mRichSupport::PrintRaw(msDesc.size, msContent);//TODO delete - ////LOG(debug) << "======================================================="; - //////////////////////////////// - //ProcessMs(ts, component, iMS);// - //////////////////////////////// + if (IsLog()) LOG(debug) << "msDesc.size=" << msDesc.size << " msDesc.idx=" << msDesc.idx; if (!fRawDataMode) ProcessMs(ts, component, iMS); if (fRawDataMode) DebugMs(ts, component, iMS); - - LOG(debug) << "======================================================="; } - /////////////// - FinalizeTs(); // - /////////////// + FinalizeTs(); - if (0 == fTScounter % 1000) { LOG(info) << "Processed " << fTScounter << " TS"; } + if (0 == fTsCounter % 1000) { LOG(info) << "Processed " << fTsCounter << " TS"; } - fTScounter++; + fTsCounter++; /// Sort the buffers of hits due to the time offsets applied std::sort(fDigiVect.begin(), fDigiVect.end(), [](const CbmRichDigi& a, const CbmRichDigi& b) -> bool { return a.GetTime() < b.GetTime(); }); - if (fbMonitorMode || fbDebugMonitorMode) { - fhVectorSize->Fill(ts.index(), fDigiVect.size()); - fhVectorCapacity->Fill(ts.index(), fDigiVect.capacity()); - } // if( fbMonitorMode || fbDebugMonitorMode ) + return kTRUE; +} - if (fuTsMaxVectorSize < fDigiVect.size()) { - fuTsMaxVectorSize = fDigiVect.size() * fdCapacityIncFactor; - fDigiVect.shrink_to_fit(); - fDigiVect.reserve(fuTsMaxVectorSize); - } // if( fuTsMaxVectorSize < fDigiVect.size() ) - return kTRUE; +std::string CbmMcbm2018UnpackerAlgoRich::GetLogHeader(CbmMcbm2018RichMicrosliceReader& reader) +{ + std::stringstream stream; + stream << "[" << fTsCounter << "-" << fMsInd << "-" << reader.GetWordCounter() << "/" << reader.GetSize() / 4 << " " + << reader.GetWordAsHexString(reader.GetCurWord()) << "] "; + return stream.str(); +} + +bool CbmMcbm2018UnpackerAlgoRich::IsLog() +{ + //if (fTsCounter == 25215) return true; + return false; } Bool_t CbmMcbm2018UnpackerAlgoRich::ProcessMs(const fles::Timeslice& ts, size_t uMsCompIdx, size_t uMsIdx) { const fles::MicrosliceView mv = ts.get_microslice(uMsCompIdx, uMsIdx); const fles::MicrosliceDescriptor& msDesc = mv.desc(); - const uint8_t* ptr = mv.content(); - const size_t size = msDesc.size; - - if (size == 0) return kTRUE; - fGwordCnt = 0; //TODO check that this global word counter works properly - - Int_t offset; // offset in bytes - Int_t* dataPtr; - - offset = 0; - mRichSupport::SwapBytes(4, ptr + offset); - LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" - << "ok" - << "\t" - << "Reserved 0000 0000"; - fGwordCnt++; - - offset = 4; - mRichSupport::SwapBytes(4, ptr + offset); - dataPtr = (Int_t*) (ptr + offset); - Int_t mbsNumber = (Int_t)(dataPtr[0] & 0xffffff); - uint8_t mts_error_msg = (uint8_t)((dataPtr[0] >> 24) & 0xff); - ErrorMsg(static_cast<uint16_t>(mts_error_msg), RichErrorType::mtsError); - LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" - << "ok" - << "\t" - << "mbsNumber = " << mbsNumber; - fGwordCnt++; - - // We suppose that the first word is - // "HadesTransportUnitQueue - Length" - offset = 0 + 8; - mRichSupport::SwapBytes(4, ptr + offset); - dataPtr = (Int_t*) (ptr + offset); - Int_t TRBeventSize1 = (Int_t)(dataPtr[0]); - LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" - << "ok" - << "\t" - << "HadesTransportUnitQueue - Length = " << TRBeventSize1; - fGwordCnt++; - - if (*dataPtr > 0 && UInt_t(*dataPtr) == 0x80030000) { - LOG(info) << "dataPtr == 0x80030000"; - exit(EXIT_FAILURE); - } + CbmMcbm2018RichMicrosliceReader reader; + reader.SetData(mv.content(), msDesc.size); - // We suppose that the second word is - // "HadesTransportUnitQueue - Decoder (Seems to be allways the same)" - offset = 4 + 8; - mRichSupport::SwapBytes(4, ptr + offset); - dataPtr = (Int_t*) (ptr + offset); - Int_t dcdr = (Int_t)(dataPtr[0]); - if (dcdr == 0x00030062) { - LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" - << "ok" - << "\t" - << "HadesTransportUnitQueue - Decoder = " << dcdr; - fGwordCnt++; - } - else { - LOG(warning) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" - << "er" - << "\t" - << "HadesTransportUnitQueue - Decoder = " << dcdr << " is not 0x00030062 (196706) => 0x" << std::hex - << dcdr << std::dec; - fGwordCnt++; - - /// Probably corrupted MS, stop there and skip remaining data - fSkipMs = kTRUE; - return kFALSE; - } + // There are a lot of MS with 8 bytes size + // Does one need these MS? + if (reader.GetSize() <= 8) return true; - // We suppose that the third word is - // TRB event length (in bytes) - // It should be 8 less than the size specified two words ago - offset = 8 + 8; - mRichSupport::SwapBytes(4, ptr + offset); - dataPtr = (Int_t*) (ptr + offset); - Int_t TRBeventSize2 = (Int_t)(dataPtr[0]); - if (TRBeventSize2 == TRBeventSize1 - 8) { - LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" - << "ok" - << "\t" - << "TRB event - Length = " << TRBeventSize2 << " == " << TRBeventSize1 << "-8"; - fGwordCnt++; - } - else { - LOG(debug) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" - << "er" - << "\t" - << "TRB event - Length = " << TRBeventSize2 << " != " << TRBeventSize1 << "-8=" << TRBeventSize1 - 8; - fGwordCnt++; + while (true) { + ProcessTrbPacket(reader); + // -4*2 for 2 last words which contain microslice index + if (reader.GetOffset() >= reader.GetSize() - 8) break; + // -4*3 for 0xffffffff padding and 2 last words which contain microslice index + if (reader.IsNextPadding() && reader.GetOffset() >= reader.GetSize() - 12) break; } - ///////////////////////////////////////////// - ProcessTRBevent(TRBeventSize2, ptr + offset); // - ///////////////////////////////////////////// - - // Bytes in a TrbEvent - if (fbDebugMonitorMode) fhEventSize->Fill(TRBeventSize2); - - - if (fSkipMs == kTRUE) { - // problem in data; delete vectors. - fDigiVect.clear(); - fSkipMs = kFALSE; - } + uint32_t msIndexWord1 = reader.NextWord(); + if (IsLog()) LOG(DEBUG4) << GetLogHeader(reader) << "Microslice Index 1:" << reader.GetWordAsHexString(msIndexWord1); + uint32_t msIndexWord2 = reader.NextWord(); + if (IsLog()) LOG(DEBUG4) << GetLogHeader(reader) << "Microslice Index 2:" << reader.GetWordAsHexString(msIndexWord2); return kTRUE; } -Int_t CbmMcbm2018UnpackerAlgoRich::ProcessTRBevent(size_t const size, uint8_t const* const ptr) -{ - Int_t offset; // offset in bytes - Int_t* dataPtr; - - // We assume that the TRB event header is 4 words and - // the first word is already processed outside of this method - - ////////////////////////////////// - ProcessTRBeventHeader(4 * 4, ptr); // - ////////////////////////////////// - - offset = 16; // start from after the TRB event header - - // 1. Search for the CTS subevent and extract reference time - - while (static_cast<size_t>(offset) < size) { - /// Escape bad MS before doing anything - if (fSkipMs == kTRUE) break; - - // Duplicate the header word in order to avoid corrupting (by bytes swapping) - // the original data - dataPtr = (Int_t*) (ptr + offset); - Int_t headerCopy = *dataPtr; - mRichSupport::SwapBytes(4, (uint8_t*) &headerCopy); - dataPtr = &headerCopy; - - Int_t SubEvSize = (Int_t)((dataPtr[0] >> 16) & 0xffff); - Int_t HubId = (Int_t)((dataPtr[0]) & 0xffff); - - // Process only CTS subevent - //FIXME change from 0xc001 to 0xc000 at some point // ? - if ((HubId == 0xc001) || (HubId == 0xc000)) { - - // Not a very nice shortcut - // The global counter of the words is incremented for the CTS subevent header here - // However for the TRB subevent headers it is incremented in the second run, - // where only TRB subevent headers are processed and the CTS subevents are skipped - LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr((uint8_t*) &headerCopy) << "\t" - << "ok" - << "\t" - << "hub ID = 0x" << mRichSupport::GetHexRepresentation(2, (uint8_t*) &headerCopy) << "\t" - << "subevent size = " << SubEvSize; - fGwordCnt++; - - fSubSubEvId = HubId; - ////////////////////////////////////////////////////////////// - offset += (4 + ProcessCTSsubevent(SubEvSize * 4, ptr + offset)); // - ////////////////////////////////////////////////////////////// - - //std::cout<<"Words in CTS 0x"<< std::hex << HubId << std::dec <<" : "<< SubEvSize <<std::endl; - // In principle, should be reset here for safety - fSubSubEvId = 0; - } - else { - // Skip all other subevents - offset += (4 + SubEvSize * 4); - } - } - - offset = 16; // start from after the TRB event header again - - // 2. Process TRB subsubevents - - //Int_t iIter = 0; - while (static_cast<size_t>(offset) < size) { - /// Escape bad MS before doing anything - if (fSkipMs == kTRUE) break; - - //std::cout << "SE iteration " << iIter++ << "\toffset=" << offset << "\tsize=" << size << std::endl; - - // We suppose that the fifth word is the header of the subevent - // <Length> <HubId> - mRichSupport::SwapBytes(4, ptr + offset); - dataPtr = (Int_t*) (ptr + offset); - Int_t SubEvSize = (Int_t)((dataPtr[0] >> 16) & 0xffff); - Int_t HubId = (Int_t)((dataPtr[0]) & 0xffff); - - //FIXME change from 0xc001 to 0xc000 at some point // ? - if ((HubId == 0xc001) || (HubId == 0xc000)) { - ////fSubSubEvId = HubId; - ////////////////////////////////////////////////////////////////// - ////offset += (4 + ProcessCTSsubevent(SubEvSize*4, ptr+offset));// - ////////////////////////////////////////////////////////////////// - ////// In principle, should be reset here for safety - ////fSubSubEvId = 0; - - // Skip CTS subevent as it has been already processed during the first run - offset += (4 + SubEvSize * 4); - fLastFeeOnHub = false; - } - else if (HubId == 0x5555) { - LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" - << "ok" - << "\t" - << "hub ID = 0x" << mRichSupport::GetHexRepresentation(2, ptr + offset) << "\t" - << "subevent size = " << SubEvSize; - fGwordCnt++; - fLastFeeOnHub = false; - //TODO one could implement additional checks here about the - // words coming after the "event end" but we skip everything by now. - /////////////////////////////////////////////////////////////// - offset += (4 + ProcessSKIPsubevent(SubEvSize * 4, ptr + offset)); // - /////////////////////////////////////////////////////////////// - } - else if (((HubId >> 8) & 0xFF) == 0x82) { - LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" - << "ok" - << "\t" - << "hub ID = 0x" << mRichSupport::GetHexRepresentation(2, ptr + offset) << "\t" - << "subevent size = " << SubEvSize; - fGwordCnt++; - fLastFeeOnHub = false; - //std::cout<<"Hub: "<<std::hex<<HubId <<std::dec<<" Size:"<< SubEvSize<<std::endl; - ////////////////////////////////////////////////////////////// - offset += (4 + ProcessTRBsubevent(SubEvSize * 4, ptr + offset)); // - ////////////////////////////////////////////////////////////// - - //std::cout<<"Words in Hub 0x"<< std::hex << HubId << std::dec <<" : "<< SubEvSize <<std::endl; - // Bytes in a Hub - if (fbDebugMonitorMode) { - uint16_t combiner_address = ((HubId >> 4) & 0xF) * 3 + (HubId & 0xF); - fhSubEventSize->Fill(combiner_address, (SubEvSize * 4)); - } - } - else { - LOG(WARN) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" - << "ok" - << "\t" - << "hub ID = 0x" << mRichSupport::GetHexRepresentation(2, ptr + offset) << "\t" - << "subevent size = " << SubEvSize << "\n" - << "This is not a valid Combiner Id!" - << "\n" - << "prev prev2:" << mRichSupport::GetWordHexRepr(ptr + offset - 12) << "\n" - << "prev prev: " << mRichSupport::GetWordHexRepr(ptr + offset - 8) << "\n" - << "prev: " << mRichSupport::GetWordHexRepr(ptr + offset - 4) << "\n" - << "next: " << mRichSupport::GetWordHexRepr(ptr + offset + 4) << "\n" - << "next next: " << mRichSupport::GetWordHexRepr(ptr + offset + 8) << "\n"; - ////////////////////////////////////////////////////////////// - offset += (4 + SubEvSize * 4); - ////////////////////////////////////////////////////////////// - } - } - - ////LOG(debug4) << "Done processing TRB event. offset=" << offset << "\tsize=" << size; - //TODO implement checks - if (size != static_cast<size_t>(offset)) { - LOG(WARN) << "CbmMcbm2018UnpackerAlgoRich::ProcessTRBevent() warning:" - << "Number of processed bytes is not equal to the expected size. " - "This should not happen. (" - << size << " VS " << offset << ")"; - } - - return size; //TODO check -} - -// Process TRB event header. -// Input arguments are the size of the TRB event header (16 bytes) and the pointer to the first word. -// Note that the first word can already be analysed outside of this method. -// Return number of bytes processed. For this particular method the value of the input 'size' argument -// is returned as we expect that the TRB header is always 16 bytes. -Int_t CbmMcbm2018UnpackerAlgoRich::ProcessTRBeventHeader(size_t const size, uint8_t const* const ptr) +void CbmMcbm2018UnpackerAlgoRich::ProcessTrbPacket(CbmMcbm2018RichMicrosliceReader& reader) { - Int_t offset; // offset in bytes - Int_t* dataPtr; - - // Skip first word (already processed outside) - //offset = 0; - // do nothing - - // We suppose that the second word consists of - // 0002 - number of following word till the Event Data Starts (should be the same) - // 00<TriggerType>1 - value in [7:4] defines TriggerType - offset = 4; - mRichSupport::SwapBytes(4, ptr + offset); - dataPtr = (Int_t*) (ptr + offset); - Int_t checkSize = (Int_t)((dataPtr[0] >> 16) & 0xffff); - Int_t triggerType = (Int_t)((dataPtr[0] >> 4) & 0xf); - if (checkSize == 2) { - LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" - << "ok" - << "\t" - << "checkSize == 2" - << "\t" - << "trigger type = " << triggerType; - fGwordCnt++; - } - else { - LOG(warning) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" - << "er" - << "\t" - << "checkSize != 2 (" << checkSize << ")\t" - << "trigger type = " << triggerType; - fGwordCnt++; - - /// Probably corrupted MS, stop there and skip remaining data - fSkipMs = kTRUE; - return 0; - } + ProcessMbs(reader, false); // Current MBS + ProcessMbs(reader, true); // Previous MBS - /*for (size_t iWord=2; iWord<size; iWord++) { - offset = iWord*4; - LOG(debug4) << "\t" << GetWordHexRepr(ptr+offset); - }*/ - - // We suppose that the third word consists of - // 0000 <SubEventId> - offset = 8; - mRichSupport::SwapBytes(4, ptr + offset); - dataPtr = (Int_t*) (ptr + offset); - Int_t checkBytes = (Int_t)((dataPtr[0] >> 16) & 0xffff); - // Int_t SubEvId = (Int_t)((dataPtr[0]) & 0xffff); - if (checkBytes == 0) { - LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" - << "ok" - << "\t" - << "checkBytes == 0" - << "\t" - << "subevent ID = 0x" << mRichSupport::GetHexRepresentation(2, ptr + offset); - fGwordCnt++; - } - else { - LOG(warning) << "[" << fGwordCnt++ << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" - << "er" - << "\t" - << "checkBytes != 0 (" << checkBytes << ")\t" - << "subevent ID = 0x" << mRichSupport::GetHexRepresentation(2, ptr + offset); - fGwordCnt++; - - /// Probably corrupted MS, stop there and skip remaining data - fSkipMs = kTRUE; - return 0; - } + uint32_t trbNum = reader.NextWord(); // TRB trigger number + if (IsLog()) LOG(debug4) << GetLogHeader(reader) << "TRB Num:" << reader.GetWordAsHexString(trbNum); - // We suppose that the fourth word is the trigger number - offset = 12; - mRichSupport::SwapBytes(4, ptr + offset); - dataPtr = (Int_t*) (ptr + offset); - UInt_t TriggerNum = (UInt_t)(dataPtr[0]); - LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" - << "ok" - << "\t" - << "trigger num = " << TriggerNum; - fGwordCnt++; - - return size; + ProcessHubBlock(reader); } -Int_t CbmMcbm2018UnpackerAlgoRich::ProcessSKIPsubevent(size_t const size, uint8_t const* const ptr) +void CbmMcbm2018UnpackerAlgoRich::ProcessMbs(CbmMcbm2018RichMicrosliceReader& reader, bool isPrev) { - ////LOG(debug4) << "ProcessSKIPsubevent size=" << size << " bytes"; - - Int_t offset; // offset in bytes - Int_t* dataPtr; //(FU) not used - uint16_t SubEventError = 0; + uint32_t word = reader.NextWord(); + uint32_t mbsNum = word & 0xffffff; //24 bits + uint32_t nofCtsCh = (word >> 24) & 0xff; // 8 bits + if (IsLog()) + LOG(debug4) << GetLogHeader(reader) << "MBS mbsNum:0x" << std::hex << mbsNum << std::dec + << " nofCtsCh:" << nofCtsCh; - // Skip first word (already processed outside) - offset = 4; + for (uint32_t i = 0; i < nofCtsCh; i++) { + uint32_t wordEpoch = reader.NextWord(); + uint32_t epoch = CbmMcbm2018RichTdcWordReader::ProcessEpoch(wordEpoch); + if (IsLog()) LOG(debug4) << GetLogHeader(reader) << "MBS ch:" << i << " epoch:" << epoch; - //Start Error identification - mRichSupport::SwapBytes(4, ptr + offset); - dataPtr = (Int_t*) (ptr + offset); - SubEventError = (uint16_t)((dataPtr[0] >> 16) & 0xffff); - ErrorMsg(static_cast<uint16_t>(SubEventError), RichErrorType::subEventError); + uint32_t wordTime = reader.NextWord(); + CbmMcbm2018RichTdcTimeData td; + CbmMcbm2018RichTdcWordReader::ProcessTimeData(wordTime, td); + if (IsLog()) LOG(debug4) << GetLogHeader(reader) << "MBS ch:" << i << " " << td.ToString(); - offset = 8; - //End Error identification + double fullTime = CalculateTime(epoch, td.fCoarse, td.fFine); - while (static_cast<size_t>(offset) < size + 4) { - mRichSupport::SwapBytes(4, ptr + offset); - // dataPtr = (Int_t*)(ptr+offset); (FU) not used - LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset); - fGwordCnt++; - - offset += 4; - } - - ////LOG(debug4) << "Done processing SKIP subevent. offset=" << offset << "\tsize=" << size; - //TODO implement checks - if (size != static_cast<size_t>(offset - 4)) { - LOG(WARN) << "CbmMcbm2018UnpackerAlgoRich::ProcessSKIPsubevent() warning:" - << "Number of processed bytes is not equal to the expected size. " - "This should not happen."; - } - - return size; //TODO check -} - -Int_t CbmMcbm2018UnpackerAlgoRich::ProcessCTSsubevent(size_t const size, uint8_t const* const ptr) -{ - ////LOG(debug4) << "ProcessCTSsubevent size=" << size << " bytes"; - - Int_t offset; // offset in bytes - Int_t* dataPtr; - - // Skip first word (already processed outside) - - // We suppose that the second word is the header of the subsubevent - offset = 4; - mRichSupport::SwapBytes(4, ptr + offset); - dataPtr = (Int_t*) (ptr + offset); - LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" - << "ok" - << "\t" - << "CTS header"; - fGwordCnt++; - - /* (FU) not used - Short_t trigState[16]; - for (Int_t i=0; i<16; i++) { - trigState[i] = ((*dataPtr >> i) & 0x1); // 16 x 1 bit - } -*/ - Short_t nInp = ((*dataPtr >> 16) & 0xf); // 4 bits - Short_t nTrigCh = ((*dataPtr >> 20) & 0x1f); // 5 bits - Short_t inclLastIdle = ((*dataPtr >> 25) & 0x1); // 1 bit - Short_t inclTrigInfo = ((*dataPtr >> 26) & 0x1); // 1 bit - Short_t inclTS = ((*dataPtr >> 27) & 0x1); // 1 bit - Short_t ETM = ((*dataPtr >> 28) & 0x3); // 2 bits - - // in words (not bytes) - Short_t CTSinfo_size = nInp * 2 + nTrigCh * 2 + inclLastIdle * 2 + inclTrigInfo * 3 + inclTS; - switch (ETM) { - case 0: break; - case 1: CTSinfo_size += 1; break; - case 2: CTSinfo_size += 4; break; - case 3: - LOG(debug) << "ETM == 3"; - //TODO implement - break; - } - - LOG(debug) << "CTS information size (extracted from the CTS header): " << CTSinfo_size; - - offset = 8; - - while (offset - 8 < CTSinfo_size * 4) { - mRichSupport::SwapBytes(4, ptr + offset); - dataPtr = (Int_t*) (ptr + offset); - ULong_t MSidx = 102400UL * ((ULong_t)(*dataPtr) - 1); - LOG(debug) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" - << "ok" - << "\t" - << "CTS information" - << " MSidx=" << MSidx; - fGwordCnt++; - - offset += 4; - } - - // size - full size including CTS header word, CTS informations words (CTSinfo_size) and TCD data - // Thus TDC data size = full size - 1 word (header) - CTSinfo_size words (CTS informations) - /////////////////////////////////////////////////////////////////////////// - fChnlMsgCnt.fill(0); - offset += (ProcessTRBsubsubevent((size - (1 + CTSinfo_size) * 4), ptr + offset, 0, 0)); // - /////////////////////////////////////////////////////////////////////////// - - ////LOG(debug4) << "Done processing CTS subevent. offset-4=" << offset-4 << "\tsize=" << size; - //TODO implement checks - if (size != static_cast<size_t>(offset - 4)) { - LOG(WARN) << "CbmMcbm2018UnpackerAlgoRich::ProcessCTSsubevent() warning:" - << "Number of processed bytes is not equal to the expected size. " - "This should not happen."; + if (isPrev && td.fChannel == 0) fMbsPrevTimeCh0 = fullTime; + if (isPrev && td.fChannel == 1) fMbsPrevTimeCh1 = fullTime; } - return size; //TODO check + double mbsCorr = fMbsPrevTimeCh1 - fMbsPrevTimeCh0; + if (IsLog()) + LOG(debug4) << GetLogHeader(reader) << "MBS Prev ch1:" << std::setprecision(15) << fMbsPrevTimeCh1 + << " ch0:" << fMbsPrevTimeCh0 << " corr:" << mbsCorr; } -Int_t CbmMcbm2018UnpackerAlgoRich::ProcessTRBsubevent(size_t const size, uint8_t const* const ptr) +void CbmMcbm2018UnpackerAlgoRich::ProcessHubBlock(CbmMcbm2018RichMicrosliceReader& reader) { - ////LOG(debug4) << "ProcessTRBsubevent size=" << size << " bytes"; - - Int_t offset; // offset in bytes - Int_t* dataPtr; - - // Skip first word (already processed outside) - offset = 4; - - fTdcWordCorrectionCnt = 0; + uint32_t word = reader.NextWord(); + uint32_t hubId = word & 0xffff; // 16 bits + uint32_t hubSize = (word >> 16) & 0xffff; // 16 bits + if (IsLog()) + LOG(debug4) << GetLogHeader(reader) << "hubId:0x" << std::hex << hubId << std::dec << " hubSize:" << hubSize; - findTDCAlignmentError(ptr, size); + //if ((HubId == 0xc001) || (HubId == 0xc000)) //CTS subevent? + //if (HubId == 0x5555) + //if (((HubId >> 8) & 0xff) == 0x82) // TRB subevent? // TODO: check if it starts from 0x82 - //Int_t iIter = 0; - while (static_cast<size_t>(offset) < (size - 2)) { // test for cases with odd number of corrections - if (fSkipMs == kTRUE) break; - //std::cout << "SSE iteration " << iIter++ << "\toffset=" << offset << "\tsize=" << size << std::endl; + // if true then it is CTS sub-sub-event + bool isLast = false; + size_t counter = 0; + size_t totalSize = 0; + while (!isLast) { + word = reader.NextWord(); + uint32_t subSubEventId = word & 0xffff; // 16 bits + uint32_t subSubEventSize = (word >> 16) & 0xffff; // 16 bits + isLast = reader.IsLastSubSubEvent(subSubEventSize); // if true then it is CTS sub-sub-event + counter++; + totalSize += (1 + subSubEventSize); - //correct for misalignment - if (fTDCAlignmentErrorPositions.size() > static_cast<unsigned int>(fTdcWordCorrectionCnt) - && fTDCAlignmentErrorPositions[fTdcWordCorrectionCnt] == offset) { - //std::cout<<"Correction in DiRICH Header: "<< fTDCAlignmentErrorPositions[fTdcWordCorrectionCnt]<<std::endl; - offset += 2; - fTdcWordCorrectionCnt++; - } - - // We suppose that the second word is the header of the subsubevent - // <Length> <SubSubEv.Id> - mRichSupport::SwapBytes(4, ptr + offset); - dataPtr = (Int_t*) (ptr + offset); - Int_t SubSubEvSize = (Int_t)((dataPtr[0] >> 16) & 0xffff); - fSubSubEvId = (Int_t)((dataPtr[0]) & 0xffff); - - //check if it is the last DiRICH in the Hub Data stream - //TODO CHECK! - if ((static_cast<size_t>(offset) + SubSubEvSize * 4) >= size) { - LOG(debug) << "Last DiRICH on HUB"; - fLastFeeOnHub = true; - } + if (IsLog()) + LOG(debug4) << GetLogHeader(reader) << counter << ((isLast) ? " CTS" : " DiRICH") << " subSubEventId:0x" + << std::hex << subSubEventId << std::dec << " subSubEventSize:" << subSubEventSize; - if (((fSubSubEvId >> 12) & 0xF) != 0x7) { - LOG(error) << mRichSupport::GetWordHexRepr(ptr + offset - 12) << "\t" - << "er" - << "\t" - << "ILLEGAL SubSubEvent Id prev"; - LOG(error) << mRichSupport::GetWordHexRepr(ptr + offset - 8) << "\t" - << "er" - << "\t" - << "ILLEGAL SubSubEvent Id prev"; - LOG(error) << mRichSupport::GetWordHexRepr(ptr + offset - 4) << "\t" - << "er" - << "\t" - << "ILLEGAL SubSubEvent Id prev"; - LOG(error) << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" - << "er" - << "\t" - << "ILLEGAL SubSubEvent Id " - << "Offset:" << static_cast<size_t>(offset) << " Size:" << size; - LOG(error) << mRichSupport::GetWordHexRepr(ptr + offset + 4) << "\t" - << "er" - << "\t" - << "ILLEGAL SubSubEvent Id next"; - LOG(error) << mRichSupport::GetWordHexRepr(ptr + offset + 8) << "\t" - << "er" - << "\t" - << "ILLEGAL SubSubEvent Id next"; - LOG(error) << mRichSupport::GetWordHexRepr(ptr + offset + 12) << "\t" - << "er" - << "\t" - << "ILLEGAL SubSubEvent Id next"; + if (!isLast) { // DiRICH event + // check correctness of subsub event, for safety reasons + if (((subSubEventId >> 12) & 0xF) != 0x7) { + LOG(error) << GetLogHeader(reader) << "ERROR: subSubEventId has strange value:0x" << std::hex << subSubEventId + << std::dec; + } + ProcessSubSubEvent(reader, subSubEventSize, subSubEventId); } - - LOG(debug) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" - << "ok" - << "\t" - << "subsubevent ID (FPGA ID) = 0x" << mRichSupport::GetHexRepresentation(2, ptr + offset) << "\t" - << "subsubevent size = " << SubSubEvSize << " | HUB Offset:" << static_cast<size_t>(offset) - << " Size:" << size; - fGwordCnt++; - - if (size + 4 < static_cast<size_t>(offset + 4 + SubSubEvSize * 4 - fTdcWordCorrectionCnt * 2)) { - LOG(WARN) << "CbmMcbm2018UnpackerAlgoRich::ProcessTRBsubevent() warning:" - << "SubEvent out of bounds. This should not happen. (" << size << " VS " - << (offset + 4 + SubSubEvSize * 4 - fTdcWordCorrectionCnt * 2) << ")"; - - /// Probably corrupted MS, stop there and skip remaining data - //fSkipMs = kTRUE; + else { // CTS event + ProcessCtsSubSubEvent(reader, subSubEventSize, subSubEventId); } - fChnlMsgCnt.fill(0); - - // Add 4 bytes which correspond to the header word - ////////////////////////////////////////////////////////////////////// - offset += (4 + ProcessTRBsubsubevent(SubSubEvSize * 4, ptr + offset + 4, offset + 4, size)); // - ////////////////////////////////////////////////////////////////////// - - //std::cout<<"Words in DiRICH 0x"<< std::hex << fSubSubEvId << std::dec <<" : "<< SubSubEvSize <<std::endl; - if (fbDebugMonitorMode) { //This address calculation is just for mCBM; will be a problem when using full CBM RICH acceptance - uint16_t DiRICH_address = ((fSubSubEvId >> 8) & 0xF) * 18 + ((fSubSubEvId >> 4) & 0xF) * 2 + (fSubSubEvId & 0xF); - fhSubSubEventSize->Fill(DiRICH_address, - SubSubEvSize); // Words in a DiRICH + uint16_t histAddr = ((subSubEventId >> 8) & 0xF) * 18 + ((subSubEventId >> 4) & 0xF) * 2 + (subSubEventId & 0xF); + fhSubSubEventSize->Fill(histAddr, subSubEventSize); // Words in a DiRICH + } - //Words per channel - for (size_t i = 1; i < fChnlMsgCnt.size(); ++i) { - if (fChnlMsgCnt.at(i) > 0) fhChnlSize->Fill(static_cast<int>(i), fChnlMsgCnt.at(i)); - } + if ((totalSize == hubSize && !isLast) || (totalSize != hubSize && isLast)) { + if (IsLog()) LOG(error) << "ERROR: totalSize OR isLast is wrong"; } - // In principle, should be reset here for safety - fSubSubEvId = 0; + if (totalSize >= hubSize || isLast) break; } - if (static_cast<Int_t>(fTDCAlignmentErrorPositions.size()) != fTdcWordCorrectionCnt) - std::cout << "Missing Correction" << std::endl; - - // if (fTDCAlignmentErrorPositions.size() > 0){ - // std::cout<<"Offset : "<<offset-4<<" Size:"<< size <<std::endl; - // std::cout<<"END of Hub : "<<mRichSupport::GetWordHexRepr(ptr+offset-4)<<std::endl; // Last word, processed as TDCWord - // std::cout<<"END of Hub +1 : "<<mRichSupport::GetWordHexRepr(ptr+offset+0)<<std::endl; - // std::cout<<"END of Hub +2 : "<<mRichSupport::GetWordHexRepr(ptr+offset+4)<<std::endl; - // std::cout<<"END of Hub +3 : "<<mRichSupport::GetWordHexRepr(ptr+offset+8)<<std::endl; - // } - - ////LOG(debug4) << "Done processing TRB subevent. offset-4=" << offset-4 << "\tsize=" << size; - if (size != static_cast<size_t>(offset - 4)) { - LOG(WARN) << "CbmMcbm2018UnpackerAlgoRich::ProcessTRBsubevent() warning:" - << "Number of processed bytes is not equal to the expected size. " - "This should not happen. (" - << size << " VS " << (offset - 4) << ")" - << " Correction: " << fTdcWordCorrectionCnt * 2 << " fLastFeeOnHub:" << fLastFeeOnHub; - - /// Probably corrupted MS, stop there and skip remaining data - //fSkipMs = kTRUE; + // read last words + int lastWordsCounter = 0; + while (true) { + lastWordsCounter++; + word = reader.NextWord(); + if (IsLog()) LOG(debug4) << GetLogHeader(reader); + if (word == 0x600dda7a) break; + if (lastWordsCounter >= 7) { + LOG(error) << GetLogHeader(reader) + << "CbmMcbm2018UnpackerAlgoRich::ProcessHubBlock() ERROR: No word == 0x600dda7a"; + } } - - fTdcWordCorrectionGlobalCnt += fTdcWordCorrectionCnt; - - return size; //TODO check } -Int_t CbmMcbm2018UnpackerAlgoRich::ProcessTRBsubsubevent(size_t const size, uint8_t const* const ptr, - Int_t const hubOffset, size_t const hubSize) -{ //size: Size of Data from DiRICH in Bytes - ////LOG(debug4) << "ProcessTRBsubsubevent size=" << size << " bytes"; - Int_t offset = 0; // offset in bytes - fCurEpochCounter = 0; //TODO check - fInSubSubEvent = kFALSE; //TODO check - fTrbState = TrbNetState::IDLE; - Int_t TdcWordCorrection_local = 0; - Int_t WordCnt = 0; - bool break_flag = false; - - for (size_t iWord = 0; iWord < size / 4; iWord++) { // iWord is size in Lines - //correct for misalignment - //hubOffset is pointing to first word after DiRICH address - if (fTDCAlignmentErrorPositions.size() > static_cast<unsigned int>(fTdcWordCorrectionCnt) - && fTDCAlignmentErrorPositions[fTdcWordCorrectionCnt] == static_cast<Int_t>(hubOffset + offset + iWord * 4)) { - //BEGIN DEBUG - // std::cout<<"DEBUG -1: "<< mRichSupport::GetWordHexRepr(ptr-hubOffset+fTDCAlignmentErrorPositions[fTdcWordCorrectionCnt]-4) << std::endl; - // std::cout<<"DEBUG 0: "<< mRichSupport::GetWordHexRepr(ptr-hubOffset+fTDCAlignmentErrorPositions[fTdcWordCorrectionCnt]) << std::endl; - // std::cout<<"DEBUG +1: "<< mRichSupport::GetWordHexRepr(ptr-hubOffset+fTDCAlignmentErrorPositions[fTdcWordCorrectionCnt]+4) << std::endl; - // std::cout<<"DEBUG_ : "<< mRichSupport::GetWordHexRepr(ptr+iWord*4+offset) << std::endl; - // - // std::cout<<"Correction in DiRICH Header: "<< fTDCAlignmentErrorPositions[fTdcWordCorrectionCnt]<<std::endl; - - //END DEBUG - offset += 2; - fTdcWordCorrectionCnt++; - TdcWordCorrection_local++; - // repeat word - iWord--; - continue; - } - if (fSkipMs == kTRUE) break; - - - //if (fTDCAlignmentErrorPositions.size() > 0 && fLastFeeOnHub) std::cout<<"Final Word: "<< mRichSupport::GetWordHexRepr(ptr+iWord*4+offset)<<std::endl; - - ////////////////////////////// - if ((hubSize > 0) && (hubOffset + offset + iWord * 4 > hubSize)) { - //std::cout<<"BREAKING : "<<hubOffset+offset+iWord*4 <<" > "<< hubSize <<" | "<< offset << " | "<< fTdcWordCorrectionCnt <<std::endl; - break_flag = true; - break; - } - //if (isCTSWord) std::cout<<"TDCWORD: "<<mRichSupport::GetWordHexRepr(ptr+iWord*4+offset)<<std::endl; - - mRichSupport::SwapBytes(4, ptr + iWord * 4 + offset); - ProcessTDCword(ptr + iWord * 4 + offset, iWord, size); // - - WordCnt++; - - //std::cout<<" "<< iWord <<" "<< WordCnt <<std::endl; - } //END of for Loop - - // if (fTdcWordCorrectionCnt > 0){ - // std::cout<<"LAST Processed Word : "<<mRichSupport::GetWordHexRepr(ptr+(WordCnt-1)*4+offset)<<std::endl; - // } - //if (TdcWordCorrection_local != 0) printf(" --- TDC WORD FIX APPLIED ! --- [DiRICH : 0x%4x]\n",fSubSubEvId); - - if (fSkipMs == kTRUE) return 0; - - //TODO Implement checks that the first word was the header and the last word was the trailer - - //if (size != static_cast<size_t>((WordCnt)*4) && fTdcWordCorrectionCnt == 0) { - if (!((!break_flag && ((size) == static_cast<size_t>((WordCnt) *4))) - || (break_flag && ((size - (fTdcWordCorrectionCnt * 2)) == static_cast<size_t>((WordCnt) *4))))) { - LOG(WARN) << "CbmMcbm2018UnpackerAlgoRich::ProcessTRBsubsubevent() warning:" - << "Number of processed bytes is not equal to the expected size. " - "This should not happen." - << static_cast<size_t>(WordCnt * 4) << " " << size; - /// Probably corrupted MS, stop there and skip remaining data - //fSkipMs = kTRUE; +void CbmMcbm2018UnpackerAlgoRich::ProcessCtsSubSubEvent(CbmMcbm2018RichMicrosliceReader& reader, + uint32_t subSubEventSize, uint32_t subSubEventId) +{ + uint32_t word = reader.NextWord(); + uint32_t ctsState = word & 0xffff; // 16 bits + uint32_t nofInputs = (word >> 16) & 0xf; // 4 bits + uint32_t nofTrigCh = (word >> 20) & 0x1f; // 5 bits + uint32_t inclLastIdle = (word >> 25) & 0x1; // 1 bit + uint32_t inclTrigInfo = (word >> 26) & 0x1; // 1 bit + uint32_t inclTime = (word >> 27) & 0x1; // 1 bit + uint32_t ETM = (word >> 28) & 0x3; // 2 bits + uint32_t ctsInfoSize = 2 * nofInputs + 2 * nofTrigCh + 2 * inclLastIdle + 3 * inclTrigInfo + inclTime; // in words + switch (ETM) { + case 0: break; + case 1: ctsInfoSize += 1; break; + case 2: ctsInfoSize += 4; break; + case 3: break; } - - - return (WordCnt * 4 + offset); //TODO check + if (IsLog()) LOG(debug4) << GetLogHeader(reader) << "CTS ctsState:" << ctsState << " ctsInfoSize:" << ctsInfoSize; + for (uint32_t i = 0; i < ctsInfoSize; i++) { + word = reader.NextWord(); // do nothing? + if (IsLog()) LOG(debug4) << GetLogHeader(reader) << "CTS info words"; + } + int nofTimeWords = subSubEventSize - ctsInfoSize - 1; + ProcessSubSubEvent(reader, nofTimeWords, subSubEventId); } -Int_t CbmMcbm2018UnpackerAlgoRich::ProcessTDCword(uint8_t const* const ptr, Int_t const word, size_t const size) +void CbmMcbm2018UnpackerAlgoRich::ProcessSubSubEvent(CbmMcbm2018RichMicrosliceReader& reader, int nofTimeWords, + uint32_t subSubEventId) { - Int_t* tdcDataPtr = (Int_t*) ptr; - Int_t tdcData = tdcDataPtr[0]; - Int_t tdcTimeDataMarker = (tdcData >> 31) & 0x1; // 1 bit - + // Store if a certain TDC word type was analysed, + // later one can check if the order is correct + bool wasHeader = false; + bool wasEpoch = false; + bool wasTime = false; + bool wasTrailer = false; + uint32_t epoch = 0; // store last epoch obtained in sub-sub-event bool errorInData = false; - // A TDC Time i only valid after a EPOCH or another TDC value - if ((tdcTimeDataMarker == 0x1 && fTrbState == TrbNetState::TDC) - || (tdcTimeDataMarker == 0x1 && fTrbState == TrbNetState::EPOCH)) { - UInt_t tdcMarker = (tdcData >> 29) & 0x7; // 3 bits - if (tdcMarker == 0x4 || tdcMarker == 0x5) { - fDebugPrint = 0; - //////////////////////////////// - ProcessTimestampWord(tdcData); // - //////////////////////////////// - fTrbState = TrbNetState::TDC; - } - else { - std::cout << "wrong TDC Word!!" << std::endl; - errorInData = true; - } - } - else { - UInt_t tdcMarker = (tdcData >> 29) & 0x7; // 3 bits - - if (tdcMarker == 0x0) { // TDC trailer - if (fInSubSubEvent) { - if (!(fTrbState == TrbNetState::HEADER || fTrbState == TrbNetState::EPOCH || fTrbState == TrbNetState::TDC)) { - LOG(error) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" - << "er" - << "\t" - << "ILLEGAL TRAILER Position"; - errorInData = true; - } - else if ((size / 4 - static_cast<size_t>(word)) > 1) { - //Trailer only at end of SubSubEvent! - LOG(error) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" - << "er" - << "\t" - << "Trailer only at end of SubSubEvent!" << size / 4 << " " << static_cast<size_t>(word); - errorInData = true; - } - else { - fTrbState = TrbNetState::TRAILER; - - LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" - << "ok" - << "\t" - << "TDC TRAILER"; - //extract TDC Trailer Error - uint16_t errorBits = (tdcData) &0xffff; //16 bits - ErrorMsg(errorBits, RichErrorType::tdcTrailer, fSubSubEvId); - fInSubSubEvent = kFALSE; // go out of InSubSubEvent state - //fGwordCnt++; - fDebugPrint = 0; - } - } - else { - LOG(info) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" - << "er" - << "\t" - << "UNKNOWN (TDC TRAILER not after header)"; - //fSkipMs = kTRUE; + // Store last raising edge time for each channel or -1. if no time + // this array is used to match raising and falling edges + std::vector<double> raisingTime(33, -1.); + + for (int i = 0; i < nofTimeWords; i++) { + uint32_t word = reader.NextWord(); + CbmMcbm2018RichTdcWordType type = CbmMcbm2018RichTdcWordReader::GetTdcWordType(word); + + if (type == CbmMcbm2018RichTdcWordType::TimeData) { + if (!wasHeader || !wasEpoch || wasTrailer) { + LOG(error) << GetLogHeader(reader) << "illegal position of TDC Time (before header/epoch or after trailer)"; errorInData = true; - //exit(EXIT_FAILURE); //TODO probably one should get rid of explicit EXIT calls not to ruin unpacking of other detectors? + continue; } + wasTime = true; + ProcessTimeDataWord(reader, i, epoch, word, subSubEventId, raisingTime); } - else if (tdcMarker == 0x1) { // TDC header - // UInt_t randomCode = (tdcData >> 16) & 0xff; // 8 bits - // UInt_t errorBits = (tdcData) & 0xffff; //16 bits - if (!fInSubSubEvent) { - fInSubSubEvent = kTRUE; // go into InSubSubEvent state - - if (!(fTrbState == TrbNetState::IDLE || fTrbState == TrbNetState::TRAILER)) { - LOG(error) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" - << "er" - << "\t" - << "ILLEGAL HEADER Position"; - errorInData = true; - } - else if (!((((tdcData >> 8) & 0xFFFFFF) == 0x200096) || (((tdcData >> 8) & 0xFFFFFF) == 0x200095))) { - LOG(error) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" - << "er" - << "\t" - << "ILLEGAL HEADER Value"; - errorInData = true; - } - else { - fTrbState = TrbNetState::HEADER; - //extract TDC Header Error - uint8_t errorBits = (tdcData) &0xff; //8 bits - ErrorMsg(errorBits, RichErrorType::tdcHeader, fSubSubEvId); - LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" - << "ok" - << "\t" - << "TDC HEADER"; - } - //fGwordCnt++; - } - else { - LOG(info) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" - << "er" - << "\t" - << "UNKNOWN (TDC HEADER not after trailer)"; + else if (type == CbmMcbm2018RichTdcWordType::Epoch) { + if (!wasHeader || wasTrailer) { + LOG(error) << GetLogHeader(reader) << "illegal position of TDC Epoch (before header or after trailer)"; errorInData = true; - //fGwordCnt++; - //fSkipMs = kTRUE; - //exit(EXIT_FAILURE); //TODO probably one should get rid of explicit EXIT calls not to ruin unpacking of other detectors? + continue; } + wasEpoch = true; + epoch = CbmMcbm2018RichTdcWordReader::ProcessEpoch(word); + if (IsLog()) LOG(debug4) << GetLogHeader(reader) << "SubSubEv[" << i << "] epoch:" << epoch; } - else if (tdcMarker == 0x2) { // DEBUG - // UInt_t debugMode = (tdcData >> 24) & 0x1f; // 5 bits - // UInt_t debugBits = (tdcData) & 0xffffff; // 24 bits - //fTrbState = TrbNetState::DEBUG; - LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" - << "ok" - << "\t" - << "DEBUG"; - LOG(info) << "DEBUG VALUE [" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr); - errorInData = true; - //fGwordCnt++; - // currently no actions if a DEBUG message is encountered. - } - else if (tdcMarker == 0x3) { // EPOCH counter - if (!(fTrbState == TrbNetState::HEADER || fTrbState == TrbNetState::TDC || fTrbState == TrbNetState::EPOCH)) { - LOG(error) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" - << "er" - << "\t" - << "ILLEGAL EPOCH Position!"; + else if (type == CbmMcbm2018RichTdcWordType::Header) { + if (wasEpoch || wasTime || wasTrailer) { + LOG(error) << GetLogHeader(reader) << "illegal position of TDC Header (after time/epoch/trailer)"; errorInData = true; + continue; } - else if (((tdcData >> 28) & 0xF) != 0x6) { //EPOCH is always 0x6.... - LOG(error) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" - << "er" - << "\t" - << "ILLEGAL EPOCH value :"; + wasHeader = true; + uint16_t errorBits = CbmMcbm2018RichTdcWordReader::ProcessHeader(word); + ErrorMsg(errorBits, CbmMcbm2018RichErrorType::tdcHeader, subSubEventId); + if (IsLog()) LOG(debug4) << GetLogHeader(reader) << "SubSubEv[" << i << "] header"; + } + else if (type == CbmMcbm2018RichTdcWordType::Trailer) { + if (!wasEpoch || !wasTime || !wasHeader) { + LOG(error) << GetLogHeader(reader) << "illegal position of TDC Trailer (before time/epoch/header)"; errorInData = true; + continue; } - else { - fTrbState = TrbNetState::EPOCH; - fDebugPrint = 0; - fCurEpochCounter = (tdcData) &0xfffffff; // 28 bits - LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" - << "ok" - << "\t" - << "EPOCH\t" << fCurEpochCounter; - //fGwordCnt++; - } + wasTrailer = true; + uint16_t errorBits = CbmMcbm2018RichTdcWordReader::ProcessTrailer(word); + ErrorMsg(errorBits, CbmMcbm2018RichErrorType::tdcTrailer, subSubEventId); + if (IsLog()) LOG(debug4) << GetLogHeader(reader) << "SubSubEv[" << i << "] trailer"; } - else { - if (tdcTimeDataMarker != 0x1) { - LOG(error) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" - << "er" - << "\t" - << "UNKNOWN"; - errorInData = true; - } + else if (type == CbmMcbm2018RichTdcWordType::Debug) { + // for the moment do nothing + } + else if (type == CbmMcbm2018RichTdcWordType::Error) { + LOG(error) << GetLogHeader(reader) << "Wrong TDC word!!! marker:" << ((word >> 29) & 0x7); + errorInData = true; } } if (errorInData) { - //Handle error - fSkipMs = kTRUE; - fSkipCnt++; - LOG(error) << " >>> Skipping MicroTS due to error in data! <<<"; + //TODO: } +} - - return 0; //correction; +double CbmMcbm2018UnpackerAlgoRich::CalculateTime(uint32_t epoch, uint32_t coarse, uint32_t fine) +{ + return ((double) epoch) * 2048. * 5. + ((double) coarse) * 5. - ((double) fine) * 0.005; } -void CbmMcbm2018UnpackerAlgoRich::ProcessTimestampWord(Int_t tdcData) +void CbmMcbm2018UnpackerAlgoRich::ProcessTimeDataWord(CbmMcbm2018RichMicrosliceReader& reader, int iTdc, uint32_t epoch, + uint32_t tdcWord, uint32_t subSubEventId, + std::vector<double>& raisingTime) { - Int_t channel = (tdcData >> 22) & 0x7f; // 7 bits - Int_t fine = (tdcData >> 12) & 0x3ff; // 10 bits - Int_t edge = (tdcData >> 11) & 0x1; // 1 bit - Int_t coarse = (tdcData) &0x7ff; // 11 bits - Int_t epoch = fCurEpochCounter; - - //TODO move full time calculation outside - Double_t fullTime = (Double_t) epoch * 2048. * 5. + (Double_t)(coarse) *5. - (Double_t)(fine) *0.005; - - LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr((uint8_t*) &tdcData) << "\t" - << "ok" - << "\t" - << "TIMESTAMP" - << "\t" - << "ch=" << channel << "\t" - << "edge=" << edge << "\t" - << "epoch=" << epoch << "\t" - << "coarse=" << coarse << "\t" - << "fine=" << fine << "\t" - << "full=" << fullTime; - //fGwordCnt++; - - // Storing reference times - // ======================= - - ////LOG(debug4) << "fSubSubEvId=0x" << std::hex << fSubSubEvId << std::dec; - Int_t idx = fUnpackPar->GetAddressIdx(fSubSubEvId); - if (-1 == idx) { - /// Probably corrupted MS, stop there and skip remaining data - fSkipMs = kTRUE; - return; - } - ////LOG(debug4) << "fSubSubEvId=0x" << std::hex << fSubSubEvId << std::dec << " idx=" << idx; - - if ((fSubSubEvId == 0xc000) || (fSubSubEvId == 0xc001)) { - // if CTS - if ((channel == 0) && (edge == RISINGEDGEID)) { - fPrevLastCTSch0_re_time = fLastCTSch0_re_time; - fLastCTSch0_re_time = fullTime; - ////LOG(debug4) << "Storing full time for the CTS ch=0 edge=RISINGEDGEID"; - } - else if ((channel == 2) && (edge == RISINGEDGEID)) { - fPrevLastCTSch2_re_time = fLastCTSch2_re_time; - fLastCTSch2_re_time = fullTime; - ////LOG(debug4) << "Storing full time for the CTS ch=2 edge=RISINGEDGEID"; - } - else if ((channel == 2) && (edge == FALLINGEDGEID)) { - fPrevLastCTSch2_fe_time = fLastCTSch2_fe_time; - fLastCTSch2_fe_time = fullTime; - ////LOG(debug4) << "Storing full time for the CTS ch=2 edge=FALLINGEDGEID"; + CbmMcbm2018RichTdcTimeData td; + CbmMcbm2018RichTdcWordReader::ProcessTimeData(tdcWord, td); + double fullTime = CalculateTime(epoch, td.fCoarse, td.fFine); + // TODO: I do not use unpacker parameters, I use std::map to store full time + // int idx = fUnpackPar->GetAddressIdx(subSubEventId); + // if (idx == -1) { + // LOG(error) << "ERROR: No AddressIdx found for subSubEventId:0x" << std::hex << subSubEventId << std::dec; + // return; + // } + + if (td.fChannel == 0) { + if (td.IsRisingEdge()) { + fPrevLastCh0ReTime[subSubEventId] = fLastCh0ReTime[subSubEventId]; + fLastCh0ReTime[subSubEventId] = fullTime; + if (IsLog()) + LOG(debug4) << GetLogHeader(reader) << "SubSubEv[" << iTdc << "] " << td.ToString() + << " CH0 Last:" << std::setprecision(15) << fLastCh0ReTime[subSubEventId] + << " PrevLast:" << fPrevLastCh0ReTime[subSubEventId] + << " diff:" << fLastCh0ReTime[subSubEventId] - fPrevLastCh0ReTime[subSubEventId]; } } else { - // if not CTS (which means TRB) - if ((channel == 0) && (edge == RISINGEDGEID)) { - fPrevLastCh0_re_time[idx] = fLastCh0_re_time[idx]; - fLastCh0_re_time[idx] = fullTime; - ////LOG(debug4) << "Storing full time for TDC 0x" << std::hex << fSubSubEvId << std::dec << " ch=0 edge=RISINGEDGEID"; - } - } + double dT = fullTime - fPrevLastCh0ReTime[subSubEventId]; + double mbsCorr = fMbsPrevTimeCh1 - fMbsPrevTimeCh0; + double fullTimeCorr = dT - mbsCorr; + if (IsLog()) + LOG(debug4) << GetLogHeader(reader) << "SubSubEv[" << iTdc << "] " << td.ToString() + << " time:" << std::setprecision(15) << fullTime << " fullTimeCorr:" << fullTimeCorr; - // Calculation of corrected time - // ============================= - Double_t fullTimeCorr = 0.; - if (!((fSubSubEvId == 0xc000) || (fSubSubEvId == 0xc001))) { - if (channel != 0) { - Double_t dT = fullTime - fPrevLastCh0_re_time[idx]; - Double_t corr = fPrevLastCTSch2_re_time - fPrevLastCTSch0_re_time; - fullTimeCorr = dT - corr; + if (td.fChannel < 1 || td.fChannel >= raisingTime.size()) { + LOG(error) << "ERROR: channel number is out of limit. Channel:" << td.fChannel; } - } - // Filling histograms - // ================== - if (fbMonitorMode == kTRUE) { - if (!((fSubSubEvId == 0xc000) || (fSubSubEvId == 0xc001))) { - // if not CTS (which means TRB) - if ((channel == 0) && (edge == RISINGEDGEID)) { - /* Double_t dT1 = fullTime - fLastCTSch0_re_time; - Double_t dT2 = fullTime - fLastCTSch2_re_time; - Double_t dT3 = fullTime - fLastCTSch2_fe_time; - fhTDCch0re_minusCTSch0re->Fill(idx, dT1); - fhTDCch0re_minusCTSch2re->Fill(idx, dT2); - fhTDCch0re_minusCTSch2fe->Fill(idx, dT3); - - Double_t dT4 = fullTime - fPrevLastCTSch0_re_time; - Double_t dT5 = fullTime - fPrevLastCTSch2_re_time; - Double_t dT6 = fullTime - fPrevLastCTSch2_fe_time; - fhTDCch0re_minusPrevCTSch0re->Fill(idx, dT4); - fhTDCch0re_minusPrevCTSch2re->Fill(idx, dT5); - fhTDCch0re_minusPrevCTSch2fe->Fill(idx, dT6); - - LOG(debug4) << "dT1=" << dT1 << "\tdT2=" << dT2 << "\tdT3=" << dT3 - << "\tdT4=" << dT4 << "\tdT5=" << dT5 << "\tdT6=" << dT6; -*/ - } - - if ((channel != 0) && (edge == RISINGEDGEID)) { - /*Double_t dT7 = fullTime - fLastCh0_re_time[idx]; - TH2D* h1 = fhTDCre_minusTDCch0re.at(idx); - h1->Fill(channel, dT7);*/ - - Double_t dT8 = fullTime - fPrevLastCh0_re_time[idx]; - /*TH2D* h2 = fhTDCre_minusPrevTDCch0re.at(idx); - h2->Fill(channel, dT8);*/ - - Double_t corr1 = fPrevLastCTSch2_re_time - fPrevLastCTSch0_re_time; - Double_t correctedT1 = dT8 + corr1; - Double_t correctedT2 = dT8 - corr1; - /* -// TH2D* h3 = fhTDCre_corrected1.at(idx); -// h3->Fill(channel, correctedT1); -// TH2D* h4 = fhTDCre_corrected2.at(idx); -// h4->Fill(channel, correctedT2); -*/ - LOG(debug4) - /*<< "dT7=" << dT7*/ << "\tdT8=" << dT8 << "\tcorr1=" << corr1 << "\tcorrectedT1=" << correctedT1 - << "\tcorrectedT2=" << correctedT2; - } + if (td.IsRisingEdge()) { + // always store the latest raising edge. It means that in case RRFF situation only middle RF will be matched. + raisingTime[td.fChannel] = fullTimeCorr; } - } - - if (edge == RISINGEDGEID) { this->ProcessRisingEdge(fSubSubEvId, channel, fullTimeCorr); } - else { - this->ProcessFallingEdge(fSubSubEvId, channel, fullTimeCorr); - } - - fChnlMsgCnt.at(channel)++; - if (fTrbState == TrbNetState::EPOCH) fChnlMsgCnt.at(channel)++; // If there was a correp. EPOCH before -} - -void CbmMcbm2018UnpackerAlgoRich::ProcessRisingEdge(Int_t subSubEvId, Int_t channel, Double_t time) -{ - ////LOG(debug4) << "CbmMcbm2018UnpackerAlgoRich::ProcessRisingEdge()"; - - //TODO: not a very nice hack. - // All messages from ch0 are skipped. Though, probably, that is corect. - if (channel == 0) return; - - // Also skip everything from CST - if ((subSubEvId == 0xc000) || (subSubEvId == 0xc001)) return; - - fRisingEdgesBuf.push_back(CbmMcbmRichEdge(subSubEvId, channel, time)); -} - -void CbmMcbm2018UnpackerAlgoRich::ProcessFallingEdge(Int_t subSubEvId, Int_t channel, Double_t time) -{ - ////LOG(debug4) << "CbmMcbm2018UnpackerAlgoRich::ProcessFallingEdge()"; - - // Skip everything from CST - if ((subSubEvId == 0xc000) || (subSubEvId == 0xc001)) return; - - Bool_t reFound = kFALSE; - - std::vector<CbmMcbmRichEdge>::iterator reIter = fRisingEdgesBuf.begin(); - - while (reIter != fRisingEdgesBuf.end()) { - if (((*reIter).fSubSubEventID == subSubEvId) && ((*reIter).fChannel == channel)) { - Double_t reTime = (*reIter).fTime; - // Found corresponding rising edge - Double_t ToT = time - reTime; - - if ((ToT >= TOTMIN) && (ToT <= TOTMAX)) { - // Time-over-threshold is within allowed range - - reFound = kTRUE; - - LOG(debug4) << "Found pair for FPGA ID 0x" << std::hex << subSubEvId << std::dec << "\tch=" << channel - << "\tToT=" << ToT; - - //TODO implement - // Writing output digi - ////////////////////////////////////////////////// - if (fbMonitorMode) { - TH1D* h = GetTotH1(subSubEvId, channel); - if (h != nullptr) h->Fill(ToT); - - TH2D* h2 = GetTotH2(subSubEvId); - if (h2 != nullptr) h2->Fill(channel, ToT); - } - WriteOutputDigi(subSubEvId, channel, reTime, ToT, fCurMSidx); // - ////////////////////////////////////////////////// - - reIter = fRisingEdgesBuf.erase(reIter); - continue; // Take care. This has to be the last operation in this block + else { + if (raisingTime[td.fChannel] == -1.) { + //No raising channel was found before. Skip this falling edge time. + if (IsLog()) + LOG(debug4) << GetLogHeader(reader) << "SubSubEv[" << iTdc << "] " + << "No raising channel was found before. Skip this falling edge time."; } else { - //TODO: exception. By now we can just do nothing + // Matching was found, calculate ToT, if tot is in a good range -> create digi + double ToT = fullTimeCorr - raisingTime[td.fChannel]; + if (IsLog()) + LOG(debug4) << GetLogHeader(reader) << "SubSubEv[" << iTdc << "] " + << "ToT:" << ToT; + if (ToT >= fToTMin && ToT <= fToTMax) { + if (fbMonitorMode) { + TH1D* h = GetTotH1(subSubEventId, td.fChannel); + if (h != nullptr) h->Fill(ToT); + + TH2D* h2 = GetTotH2(subSubEventId); + if (h2 != nullptr) h2->Fill(td.fChannel, ToT); + } + WriteOutputDigi(subSubEventId, td.fChannel, raisingTime[td.fChannel], ToT, fCurMSidx); + } + // pair was created, set raising edge to -1. + raisingTime[td.fChannel] = -1.; } - } // end of if condition - - // This construction is a little bit tricky. - // The iterator is either incremented here or (if a pair was found) - // incremented using erase call, followed by the continue. - ++reIter; - } // end of for loop - - if (reFound == kFALSE) { - // Corresponding rising edge not found - store the falling edge in the bufer - fFallingEdgesBuf.push_back(CbmMcbmRichEdge(subSubEvId, channel, time)); + } } } @@ -1406,9 +519,7 @@ void CbmMcbm2018UnpackerAlgoRich::WriteOutputDigi(Int_t fpgaID, Int_t channel, D for (int i = fDigiVect.size() - 1; i >= 0; i--) { lastTime = fDigiVect[i].GetTime(); if (lastTime <= finalTime) { - // LOG(info) << " before:"<< fDigiVect.size(); fDigiVect.emplace(fDigiVect.begin() + i + 1, pixelUID, finalTime, tot - ToTcorr); - // LOG(info) << fDigiVect.size(); break; } } @@ -1417,184 +528,52 @@ void CbmMcbm2018UnpackerAlgoRich::WriteOutputDigi(Int_t fpgaID, Int_t channel, D fDigiVect.emplace_back(pixelUID, finalTime, tot - ToTcorr); } } - LOG(debug4) << "CbmMcbm2018UnpackerAlgoRich::WriteOutputDigi fDigiVect.size=" << fDigiVect.size(); + // LOG(debug4) << "CbmMcbm2018UnpackerAlgoRich::WriteOutputDigi fDigiVect.size=" << fDigiVect.size(); } -void CbmMcbm2018UnpackerAlgoRich::FinalizeTs() -{ - // for (int i = 0; i < fDigiVect.size();++i) { - // LOG(info) << "CbmMcbm2018UnpackerAlgoRich::Final Vector: " - // << i+1 <<"/"<<fDigiVect.size() - // << "\t" << std::setprecision(15)<< fDigiVect[i].GetTime(); - // - // - // } - LOG(debug4) << "CbmMcbm2018UnpackerAlgoRich::FinalizeTs: " << fRisingEdgesBuf.size() << " entries in fRisingEdgesBuf" - << "\t" << fFallingEdgesBuf.size() << " entries in fFallingEdgesBuf"; - - // Clear rising edges buffer - LOG(debug4) << "Rising edges: " - "----------------------------------------------------------"; - std::vector<CbmMcbmRichEdge>::iterator reIter = fRisingEdgesBuf.begin(); - while (reIter != fRisingEdgesBuf.end()) { - LOG(debug4) << "FPGA=0x" << std::hex << (*reIter).fSubSubEventID << std::dec << "\tch=" << (*reIter).fChannel; - ++reIter; - } - fRisingEdgesBuf.clear(); - - // Clear falling edges buffer - LOG(debug4) << "Falling edges: " - "---------------------------------------------------------"; - std::vector<CbmMcbmRichEdge>::iterator feIter = fFallingEdgesBuf.begin(); - while (feIter != fFallingEdgesBuf.end()) { - LOG(debug4) << "FPGA=0x" << std::hex << (*feIter).fSubSubEventID << std::dec << "\tch=" << (*feIter).fChannel; - ++feIter; - } - fFallingEdgesBuf.clear(); - - LOG(debug4) << "---------------------------------------------------------"; -} +void CbmMcbm2018UnpackerAlgoRich::FinalizeTs() {} Bool_t CbmMcbm2018UnpackerAlgoRich::CreateHistograms() { - Int_t nTDCs = fUnpackPar->GetNaddresses(); - // std::vector<TCanvas*> fcToT2d; - /* - fhTDCch0re_minusCTSch0re = new TH2D("fhTDCch0re_minusCTSch0re", "TDC ch0 re - CTS ch0 re;TDC index;ns", nTDCs, 0, nTDCs, 1000, -500., 500.); - fhTDCch0re_minusCTSch2re = new TH2D("fhTDCch0re_minusCTSch2re", "TDC ch0 re - CTS ch2 re;TDC index;ns", nTDCs, 0, nTDCs, 1000, -500., 500.); - fhTDCch0re_minusCTSch2fe = new TH2D("fhTDCch0re_minusCTSch2fe", "TDC ch0 re - CTS ch2 fe;TDC index;ns", nTDCs, 0, nTDCs, 1000, -500., 500.); - - AddHistoToVector(fhTDCch0re_minusCTSch0re, ""); - AddHistoToVector(fhTDCch0re_minusCTSch2re, ""); - AddHistoToVector(fhTDCch0re_minusCTSch2fe, ""); - - fhTDCch0re_minusPrevCTSch0re = new TH2D("fhTDCch0re_minusPrevCTSch0re", "TDC ch0 re - prev CTS ch0 re;TDC index;ns", nTDCs, 0, nTDCs, 1000, -500., 500.); - fhTDCch0re_minusPrevCTSch2re = new TH2D("fhTDCch0re_minusPrevCTSch2re", "TDC ch0 re - prev CTS ch2 re;TDC index;ns", nTDCs, 0, nTDCs, 1000, -500., 500.); - fhTDCch0re_minusPrevCTSch2fe = new TH2D("fhTDCch0re_minusPrevCTSch2fe", "TDC ch0 re - prev CTS ch2 fe;TDC index;ns", nTDCs, 0, nTDCs, 1000, -500., 500.); - - AddHistoToVector(fhTDCch0re_minusPrevCTSch0re, ""); - AddHistoToVector(fhTDCch0re_minusPrevCTSch2re, ""); - AddHistoToVector(fhTDCch0re_minusPrevCTSch2fe, ""); -*/ - - fhTdcErrors = new TH2D("fhTdcErrors", "Errors in TDC msgs;;", nTDCs, -0.5, nTDCs - 0.5, 9, -0.5, 8.5); - fhTdcErrors->GetYaxis()->SetBinLabel(1, "RingBuffOverw."); - fhTdcErrors->GetYaxis()->SetBinLabel(2, "noRefTime"); - fhTdcErrors->GetYaxis()->SetBinLabel(3, "refTimePrecedes"); - fhTdcErrors->GetYaxis()->SetBinLabel(4, "trigW/oRefTime"); - fhTdcErrors->GetYaxis()->SetBinLabel(5, "markMisRefTime"); - fhTdcErrors->GetYaxis()->SetBinLabel(6, "multiRefTime"); - fhTdcErrors->GetYaxis()->SetBinLabel(7, "refTime<40ns"); - fhTdcErrors->GetYaxis()->SetBinLabel(8, "noValidation"); - fhTdcErrors->GetYaxis()->SetBinLabel(9, "trigger!=0x1"); + int nofTdc = fUnpackPar->GetNaddresses(); + + std::vector<std::string> tdcErrorLabels = {"RingBuffOverw.", "noRefTime", "refTimePrecedes", + "trigW/oRefTime", "markMisRefTime", "multiRefTime", + "refTime<40ns", "noValidation", "trigger!=0x1"}; + fhTdcErrors = new TH2D("fhTdcErrors", "Errors in TDC msgs;;", nofTdc, -0.5, nofTdc - 0.5, tdcErrorLabels.size(), -0.5, + (double) tdcErrorLabels.size() - 0.5); + for (size_t i = 0; i < tdcErrorLabels.size(); i++) { + fhTdcErrors->GetYaxis()->SetBinLabel(i + 1, tdcErrorLabels[i].c_str()); + } fhTdcErrors->GetXaxis()->LabelsOption("v"); fhTdcErrors->GetYaxis()->SetTickSize(0.0); fhTdcErrors->GetXaxis()->SetTickSize(0.0); - //fhTdcErrors->SetGrid(); - - fhEventErrors = new TH2D("fhEventErrors", "Errors in Event/mts msgs;;", 1, -0.5, 0.5, 13, -0.5, 12.5); - fhEventErrors->GetYaxis()->SetBinLabel(1, "UDPProblem"); - fhEventErrors->GetYaxis()->SetBinLabel(2, "evNumMism"); - fhEventErrors->GetYaxis()->SetBinLabel(3, "trigMism"); - fhEventErrors->GetYaxis()->SetBinLabel(4, "wrongLength"); - fhEventErrors->GetYaxis()->SetBinLabel(5, "answMissing"); - fhEventErrors->GetYaxis()->SetBinLabel(6, "evRequFail"); - fhEventErrors->GetYaxis()->SetBinLabel(7, "evPartFound"); - fhEventErrors->GetYaxis()->SetBinLabel(8, "sevBuffProb"); - fhEventErrors->GetYaxis()->SetBinLabel(9, "brokenEv"); - fhEventErrors->GetYaxis()->SetBinLabel(10, "ethLinkDwn"); - fhEventErrors->GetYaxis()->SetBinLabel(11, "subEvBuffAlmFull"); - fhEventErrors->GetYaxis()->SetBinLabel(12, "eth/BufProb"); - fhEventErrors->GetYaxis()->SetBinLabel(13, "timingTrigErr"); - fhEventErrors->GetXaxis()->LabelsOption("v"); - fhEventErrors->GetXaxis()->SetTickSize(0.0); - fhEventErrors->GetYaxis()->SetTickSize(0.0); - - for (Int_t iTDC = 0; iTDC < nTDCs; iTDC++) { - TString histoName; - TString histoTitle; - TString subFolder; - - Int_t Addr = fUnpackPar->GetAddress(iTDC); - fMapFEE[Addr] = iTDC; - fhTdcErrors->GetXaxis()->SetBinLabel(iTDC + 1, Form("0x%4x", Addr)); - /* - histoName.Form("fhTDC%dre_minusTDC%dch0re", iTDC, iTDC); - histoTitle.Form("TDC %d re - TDC %d ch0 re;channel;ns", iTDC, iTDC); - TH2D* h1 = new TH2D(histoName, histoTitle, 32, 0., 32., 1200, 0., 600.); - fhTDCre_minusTDCch0re.push_back(h1); - AddHistoToVector(h1); - - histoName.Form("fhTDC%dre_minusPrevTDC%dch0re", iTDC, iTDC); - histoTitle.Form("TDC %d re - prev. TDC %d ch0 re;channel;ns", iTDC, iTDC); - TH2D* h2 = new TH2D(histoName, histoTitle, 32, 0., 32., 1200, 0., 600.); - fhTDCre_minusPrevTDCch0re.push_back(h2); - AddHistoToVector(h2); -*/ - /* histoName.Form("fhTDC%dre_corrected1", iTDC); - histoTitle.Form("TDC %d re corrected1;channel;ns", iTDC); - TH2D* h3 = new TH2D(histoName, histoTitle, 32, 0., 32., 1200, 0., 600.); - fhTDCre_corrected1.push_back(h3); - AddHistoToVector(h3); - - histoName.Form("fhTDC%dre_corrected2", iTDC); - histoTitle.Form("TDC %d re corrected2;channel;ns", iTDC); - TH2D* h4 = new TH2D(histoName, histoTitle, 32, 0., 32., 1200, 0., 600.); - fhTDCre_corrected2.push_back(h4); - AddHistoToVector(h4); -*/ - // TODO - //workaround we need to init all histograms for ToT here. Otherwise they will not be added to monitoring. + + for (Int_t iTdc = 0; iTdc < nofTdc; iTdc++) { + Int_t tdcId = fUnpackPar->GetAddress(iTdc); + fMapFEE[tdcId] = iTdc; + fhTdcErrors->GetXaxis()->SetBinLabel(iTdc + 1, Form("0x%4x", tdcId)); + + // init ToT histogramms for (Int_t iCh = 0; iCh <= 32; iCh++) { - Int_t tdc = fUnpackPar->GetAddress(iTDC); - GetTotH1(tdc, iCh); - } - { - Int_t tdc = fUnpackPar->GetAddress(iTDC); - GetTotH2(tdc); + GetTotH1(tdcId, iCh); } + GetTotH2(tdcId); - /*******************************************************************/ - - /// Map of hits over T0 detector and same vs time in run - { //if (iTDC == 0){ - Double_t w = 10; - Double_t h = 10; - - TCanvas* c; - TString canvasName; - TString canvasTitle; - Int_t tdc = fUnpackPar->GetAddress(iTDC); - canvasName.Form("cToT2d_TDC_0x%4x", tdc); - canvasTitle.Form("ToTs of TDC 0x%4x", tdc); - c = new TCanvas(canvasName, canvasTitle, w, h); - // fcHitMaps->Divide( 2 ); - // fcHitMaps->cd( 1 ); - // gPad->SetGridx(); - // gPad->SetGridy(); - // gPad->SetLogy(); - // fhChannelMap->Draw(); - // fcHitMaps->cd( 2 ); - // gPad->SetGridx(); - // gPad->SetGridy(); - // gPad->SetLogz(); - TH2D* h2 = GetTotH2(tdc); + { + std::stringstream cName, cTitle; + int tdc = fUnpackPar->GetAddress(iTdc); + cName << "cToT2d_TDC_0x" << std::hex << tdc; + cTitle << "ToTs of TDC 0x" << std::hex << tdc; + TCanvas* c = new TCanvas(cName.str().c_str(), cTitle.str().c_str(), 10, 10); + TH2D* h2 = GetTotH2(tdc); h2->Draw("colz"); fcTot2d.push_back(c); AddCanvasToVector(c, "ToT_Canvases"); } - /*******************************************************************/ } - AddHistoToVector(fhTdcErrors, ""); - AddHistoToVector(fhEventErrors, ""); - - fhVectorSize = new TH1I("fhVectorSize", "Size of the vector VS TS index; TS index; Size [bytes]", 10000, 0., 10000.); - fhVectorCapacity = - new TH1I("fhVectorCapacity", "Size of the vector VS TS index; TS index; Size [bytes]", 10000, 0., 10000.); - AddHistoToVector(fhVectorSize, ""); - AddHistoToVector(fhVectorCapacity, ""); if (fbDebugMonitorMode) { fhEventSize = new TH1I("fhEventSize", "Size of the Event from TrbNet; Size [bytes]", 350, 0., 70000.); @@ -1615,31 +594,31 @@ Bool_t CbmMcbm2018UnpackerAlgoRich::CreateHistograms() return kTRUE; } -TH1D* CbmMcbm2018UnpackerAlgoRich::GetTotH1(Int_t tdc, Int_t channel) +TH1D* CbmMcbm2018UnpackerAlgoRich::GetTotH1(uint32_t tdc, uint32_t channel) { TH1D* h = fhTotMap[tdc][channel]; if (h == nullptr) { - TString name, title, subFolder; - name.Form("ToT_tdc0x%x_ch%u", tdc, channel); - title.Form("%s;ToT [ns];Entries", name.Data()); - subFolder.Form("ToT/tdc0x%x", tdc); - h = new TH1D(name, title, 100, -1., 49.); - AddHistoToVector(h, std::string(subFolder.Data())); + std::stringstream name, subFolder; + name << "ToT_tdc0x" << std::hex << tdc << std::dec << "_ch" << channel; + std::string title = name.str() + ";ToT [ns];Entries"; + subFolder << "ToT/tdc0x" << std::hex << tdc; + h = new TH1D(name.str().c_str(), title.c_str(), 100, -1., 49.); + AddHistoToVector(h, subFolder.str()); fhTotMap[tdc][channel] = h; } return h; } -TH2D* CbmMcbm2018UnpackerAlgoRich::GetTotH2(Int_t tdc) +TH2D* CbmMcbm2018UnpackerAlgoRich::GetTotH2(uint32_t tdc) { TH2D* h = fhTot2dMap[tdc]; if (h == nullptr) { - TString name, title, subFolder; - name.Form("ToT_2d_tdc0x%x", tdc); - title.Form("%s;channels;ToT [ns]", name.Data()); - subFolder.Form("ToT2d"); - h = new TH2D(name, title, 33, 0, 32, 200, -1., 49.); - AddHistoToVector(h, std::string(subFolder.Data())); + std::stringstream name; + name << "ToT_2d_tdc0x" << std::hex << tdc; + std::string title = name.str() + ";channels;ToT [ns]"; + std::string subFolder = "ToT2d"; + h = new TH2D(name.str().c_str(), title.c_str(), 33, 0, 32, 200, -1., 49.); + AddHistoToVector(h, subFolder); fhTot2dMap[tdc] = h; } return h; @@ -1658,194 +637,48 @@ Bool_t CbmMcbm2018UnpackerAlgoRich::DebugMs(const fles::Timeslice& ts, size_t uM return kTRUE; } -Int_t CbmMcbm2018UnpackerAlgoRich::Debug(const uint8_t* ptr, const size_t size) -{ - - if (size == 0) return size; - - //LOG(info)<<"DEBUG MODE IS ACTIVE; Printing raw data:"; - - uint8_t nblCnt = 0; - uint8_t wrdCnt = 0; - std::cout << std::endl << "SIZE: " << std::dec << size << "Byte" << std::endl; - for (size_t i = 0; i < size; ++i) { - - //if (wrdCnt == 0) std::cout<<"HEX: "; - uint8_t* tdcDataPtr = (uint8_t*) (ptr + i); - - if (wrdCnt == 0 && nblCnt == 0) { printf("%08d : ", static_cast<int>(i)); } - - printf("%02x", unsigned(*tdcDataPtr)); - nblCnt++; - if (nblCnt % 2 == 0) { printf(" "); } - if (nblCnt % 4 == 0) { - printf(" "); - wrdCnt++; - nblCnt = 0; - } - - if (wrdCnt == 10) { - printf("\n"); - wrdCnt = 0; - } - } - printf("\n"); - return size; -} +Int_t CbmMcbm2018UnpackerAlgoRich::Debug(const uint8_t* ptr, const size_t size) { return 0; } -void CbmMcbm2018UnpackerAlgoRich::ErrorMsg(uint16_t errbits, RichErrorType type, uint16_t tdcAddr) +void CbmMcbm2018UnpackerAlgoRich::ErrorMsg(uint16_t errbits, CbmMcbm2018RichErrorType type, uint16_t tdcId) { - if (fbMonitorMode) { - switch (type) { - case RichErrorType::mtsError: - //UDP problem - if ((errbits & 0x1) == 1) fhEventErrors->Fill(0.0, 0.0); - - break; - - case RichErrorType::tdcHeader: - // min. 1 rinǵ buffer overwritten - if ((errbits & 0x1) == 1) fhTdcErrors->Fill(fMapFEE[tdcAddr], 0.0); - - break; - - case RichErrorType::tdcTrailer: - // no reference time in trigger handler in TDC - if (((errbits >> 0) & 0x1) == 1) fhTdcErrors->Fill(fMapFEE[tdcAddr], 1.0); - - // reference time precedes a non-timing trigger - if (((errbits >> 1) & 0x1) == 1) fhTdcErrors->Fill(fMapFEE[tdcAddr], 2.0); - - // timing trigger is delivered without a reference time - if (((errbits >> 2) & 0x1) == 1) fhTdcErrors->Fill(fMapFEE[tdcAddr], 3.0); - - // Set with the bit 2 to mark the missing reference time - if (((errbits >> 3) & 0x1) == 1) fhTdcErrors->Fill(fMapFEE[tdcAddr], 4.0); - - // there are more than one detected reference time - if (((errbits >> 4) & 0x1) == 1) fhTdcErrors->Fill(fMapFEE[tdcAddr], 5.0); - - // reference time was too short (<40 ns) - if (((errbits >> 5) & 0x1) == 1) fhTdcErrors->Fill(fMapFEE[tdcAddr], 6.0); - - // no trigger validation arrives from the endpoint after a valid reference time - if (((errbits >> 6) & 0x1) == 1) fhTdcErrors->Fill(fMapFEE[tdcAddr], 7.0); - - // any timing trigger type except 0x1 is send - if (((errbits >> 7) & 0x1) == 1) fhTdcErrors->Fill(fMapFEE[tdcAddr], 8.0); - - break; - - case RichErrorType::ctsHeader: - // To be implemented - break; + if (!fbMonitorMode) return; - case RichErrorType::ctsTrailer: - // To be implemented - break; - - case RichErrorType::subEventError: - // event number mismatch - if (((errbits >> 0) & 0x1) == 1) fhEventErrors->Fill(0.0, 1.0); - - // trigger code mismatch - if (((errbits >> 1) & 0x1) == 1) fhEventErrors->Fill(0.0, 2.0); - - // wrong length - if (((errbits >> 2) & 0x1) == 1) fhEventErrors->Fill(0.0, 3.0); - - // answer missing - if (((errbits >> 3) & 0x1) == 1) fhEventErrors->Fill(0.0, 4.0); - - // event number request by CTS was not available (Not found) - if (((errbits >> 4) & 0x1) == 1) fhEventErrors->Fill(0.0, 5.0); - - // event partially found in data buffer - if (((errbits >> 5) & 0x1) == 1) fhEventErrors->Fill(0.0, 6.0); - - // Severe Problem with data buffer and/or read-out - if (((errbits >> 6) & 0x1) == 1) fhEventErrors->Fill(0.0, 7.0); - - // Single broken event - if (((errbits >> 7) & 0x1) == 1) fhEventErrors->Fill(0.0, 8.0); - - // Ethernet Link down - if (((errbits >> 8) & 0x1) == 1) fhEventErrors->Fill(0.0, 9.0); - - // SubEvent buffer almost full - if (((errbits >> 9) & 0x1) == 1) fhEventErrors->Fill(0.0, 10.0); - - // Ethernet/SubEventBuilder error - if (((errbits >> 10) & 0x1) == 1) fhEventErrors->Fill(0.0, 11.0); - - // Timing trigger error - if (((errbits >> 11) & 0x1) == 1) fhEventErrors->Fill(0.0, 12.0); - - break; - - default: break; + if (type == CbmMcbm2018RichErrorType::tdcHeader) { + // Errors description in TRB manual section 11.3.2. TDC HEADER + // Bit 0: min. 1 rinǵ buffer overwritten + int nofHeaderErrorBits = 1; + int histBinOffsetHeaderError = 0; + for (int i = 0; i < nofHeaderErrorBits; i++) { + if (((errbits >> i) & 0x1) == 1) fhTdcErrors->Fill(fMapFEE[tdcId], i + histBinOffsetHeaderError); } } -} - -/* -Bool_t CbmMcbm2018UnpackerAlgoRich::FillHistograms() -{ - return kTRUE; -} -*/ -Bool_t CbmMcbm2018UnpackerAlgoRich::ResetHistograms() -{ - //TODO: do something? - return kTRUE; -} - -void CbmMcbm2018UnpackerAlgoRich::findTDCAlignmentError(uint8_t const* const ptr, size_t const size) -{ - - fTDCAlignmentErrorPositions.clear(); - - // mRichSupport::SwapBytes(4, ptr+size); - // if((((((Int_t*)(ptr+size))[0]) >> 28) & 0xF) != 0x0) { - // LOG(WARN) << "CbmMcbm2018UnpackerAlgoRich::ProcessTRBsubevent() warning:" - // << "End on Hub is not where expected. Is it a Buffer overflow? LastWord: "<<mRichSupport::GetWordHexRepr(ptr+size); - // } - // mRichSupport::SwapBytes(4, ptr+size); - - /*** - * Signature of Error: - * 82b7 8ca6 - * 8297 *34ad* - * *34ad* 66af // data Ptr - * *cf8b* *cf8b* - * 82c8 cca9 - */ - - //start at 8 to skip header of Hub and first row as this has to be checked - //stop at size -4 to avoid comparing with following hub - - for (Int_t i = 8; i < static_cast<Int_t>(size - 4); i += 4) { // i represents bytes (4 per line) - //TODO: Optimize the swaping - mRichSupport::SwapBytes(4, ptr + i - 4); - mRichSupport::SwapBytes(4, ptr + i); - mRichSupport::SwapBytes(4, ptr + i + 4); - bool problem = false; - if ((((Int_t*) (ptr + i - 4))[0] & 0xFFFF) == ((((Int_t*) (ptr + i))[0] >> 16) & 0xFFFF)) { - if ((((Int_t*) (ptr + i + 4))[0] & 0xFFFF) == ((((Int_t*) (ptr + i + 4))[0] >> 16) & 0xFFFF)) { - //Signature of problem! - problem = true; - fTDCAlignmentErrorPositions.push_back(i); - fTDCAlignmentErrorPositions.push_back(i + 6); - } + else if (type == CbmMcbm2018RichErrorType::tdcTrailer) { + // Errors description in TRB manual section 11.3.5. TDC TRAILER + // Bit 0: no reference time in trigger handler in TDC + // Bit 1: reference time precedes a non-timing trigger + // Bit 2: timing trigger is delivered without a reference time + // Bit 3: Set with the bit 2 to mark the missing reference time + // Bit 4: there are more than one detected reference time + // Bit 5: reference time was too short (<40 ns) + // Bit 6: no trigger validation arrives from the endpoint after a valid reference time + // Bit 7: any timing trigger type except 0x1 is send + int nofTrailerErrorBits = 8; + int histBinOffsetTrailerError = 1; + for (int i = 0; i < nofTrailerErrorBits; i++) { + if (((errbits >> i) & 0x1) == 1) fhTdcErrors->Fill(fMapFEE[tdcId], i + histBinOffsetTrailerError); } - - mRichSupport::SwapBytes(4, ptr + i - 4); - mRichSupport::SwapBytes(4, ptr + i); - mRichSupport::SwapBytes(4, ptr + i + 4); - - if (problem) i += 8; //jump after the problem + } + else if (type == CbmMcbm2018RichErrorType::ctsHeader) { + // To be implemented + } + else if (type == CbmMcbm2018RichErrorType::ctsTrailer) { + // To be implemented + } + else { } } +Bool_t CbmMcbm2018UnpackerAlgoRich::ResetHistograms() { return kTRUE; } + ClassImp(CbmMcbm2018UnpackerAlgoRich) diff --git a/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerAlgoRich.h b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerAlgoRich.h index f5459192e7..b449b1b391 100644 --- a/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerAlgoRich.h +++ b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerAlgoRich.h @@ -5,6 +5,7 @@ /** * CbmMcbm2018UnpackerAlgoRich * E. Ovcharenko, Mar 2019 + * S. Lebedev, June 2021 * based on other detectors' classes by P.-A. Loizeau */ @@ -14,38 +15,25 @@ #include "CbmStar2019Algo.h" // mother class // STD +#include <bitset> +#include <iomanip> #include <map> #include <vector> // ROOT +#include <Logger.h> + #include <TArrayD.h> #include <TH2D.h> // CbmRoot -#include "CbmMcbm2018UnpackerUtilRich.h" #include "CbmRichDigi.h" ////class TList; // not really needed, already declared in the mother class class CbmMcbm2018RichPar; -#define RISINGEDGEID 1 -#define FALLINGEDGEID 0 - -#define TOTMIN -20. -#define TOTMAX 100. - -enum class TrbNetState -{ - IDLE, - HEADER, - EPOCH, - TDC, - TRAILER, - CTS, - DEBUG -}; -enum class RichErrorType +enum class CbmMcbm2018RichErrorType { mtsError, tdcHeader, @@ -55,6 +43,153 @@ enum class RichErrorType subEventError }; +enum class CbmMcbm2018RichTdcWordType +{ + TimeData, + Header, + Epoch, + Trailer, + Debug, + Error +}; + +class CbmMcbm2018RichTdcTimeData { +public: + uint32_t fCoarse = 0; // 11 bits + uint32_t fEdge = 0; // 1 bit + uint32_t fFine = 0; // 10 bits + uint32_t fChannel = 0; // 7 bits + + std::string ToString() + { + std::stringstream stream; + stream << "channel:" << fChannel << " coarse:" << fCoarse << " fine:" << fFine + << " edge:" << ((fEdge == 1) ? "R" : "F"); + return stream.str(); + } + + bool IsRisingEdge() { return (fEdge == 1); } +}; + +class CbmMcbm2018RichTdcWordReader { +public: + static CbmMcbm2018RichTdcWordType GetTdcWordType(uint32_t tdcWord) + { + uint32_t tdcTimeDataMarker = (tdcWord >> 31) & 0x1; // 1 bit + uint32_t tdcMarker = (tdcWord >> 29) & 0x7; // 3 bits + + if (tdcTimeDataMarker == 0x1) { + // TODO: I also include tdcMarker == 0x5, some tdc time data words have this marker. Is it correct? + if (tdcMarker == 0x4 || tdcMarker == 0x5) { return CbmMcbm2018RichTdcWordType::TimeData; } + else { + return CbmMcbm2018RichTdcWordType::Error; + } + } + + if (tdcMarker == 0x0) return CbmMcbm2018RichTdcWordType::Trailer; + if (tdcMarker == 0x1) return CbmMcbm2018RichTdcWordType::Header; + if (tdcMarker == 0x2) return CbmMcbm2018RichTdcWordType::Debug; + if (tdcMarker == 0x3) return CbmMcbm2018RichTdcWordType::Epoch; + + return CbmMcbm2018RichTdcWordType::Error; + } + + static void ProcessTimeData(uint32_t tdcWord, CbmMcbm2018RichTdcTimeData& outData) + { + outData.fCoarse = static_cast<uint32_t>(tdcWord & 0x7ff); // 11 bits + outData.fEdge = static_cast<uint32_t>((tdcWord >> 11) & 0x1); // 1 bit + outData.fFine = static_cast<uint32_t>((tdcWord >> 12) & 0x3ff); // 10 bits + outData.fChannel = static_cast<uint32_t>((tdcWord >> 22) & 0x7f); // 7 bits + } + + static uint32_t ProcessEpoch(uint32_t tdcWord) { return static_cast<uint32_t>(tdcWord & 0xfffffff); } + + static uint16_t ProcessHeader(uint32_t tdcWord) + { + // for the moment just extract error bits + return static_cast<uint16_t>(tdcWord & 0xff); //8 bits + } + + static uint16_t ProcessTrailer(uint32_t tdcWord) + { + // for the moment just extract error bits + return static_cast<uint16_t>(tdcWord & 0xffff); + } + + static void ProcessDebug(uint32_t tdcWord) + { + LOG(debug4) << "ProcessDebug is not implemented. tdcWord:0x" << std::hex << tdcWord << std::dec; + // for the moment do nothing + } +}; + +class CbmMcbm2018RichMicrosliceReader { +private: + const uint8_t* fData = nullptr; + size_t fSize = 0; + size_t fOffset = 0; // offset in bytes + size_t fWordCounter = 0; + uint32_t fCurWord; + +public: + void SetData(const uint8_t* data, size_t size) + { + fData = data; + fSize = size; + fOffset = 0; + fWordCounter = 0; + fCurWord = 0; + } + + const uint8_t* GetData() { return fData; } + + size_t GetSize() { return fSize; } + + size_t GetOffset() { return fOffset; } + + size_t GetWordCounter() { return fWordCounter; } + + uint32_t GetCurWord() { return fCurWord; } + + std::string GetWordAsHexString(uint32_t word) + { + std::stringstream stream; + stream << "0x" << std::setfill('0') << std::setw(sizeof(uint32_t) * 2) << std::hex << word; + return stream.str(); + } + + uint32_t NextWord() + { + //mRichSupport::SwapBytes(4, fData + fOffset); + //Int_t* dataPtr = (Int_t*) (fData + fOffset); + uint32_t i = ((uint32_t*) (fData + fOffset))[0]; + //swap bytes + i = (i >> 24) | ((i << 8) & 0x00FF0000) | ((i >> 8) & 0x0000FF00) | (i << 24); + //i = ((i&0xFF)<<24) | (((i>>8)&0xFF)<<16) | (((i>>16)&0xFF)<<8) | (((i>>24)&0xFF)<<0); + + fOffset += 4; + fWordCounter++; + fCurWord = i; + //return (Int_t)(dataPtr[0]); + return i; + } + + bool IsNextPadding() + { + uint32_t nextWord = ((uint32_t*) (fData + fOffset))[0]; + if (nextWord == 0xffffffff) return true; + return false; + } + + bool IsLastSubSubEvent(uint32_t subSubEventSize) + { + uint32_t i = ((uint32_t*) (fData + fOffset + 4 * subSubEventSize))[0]; + i = (i >> 24) | ((i << 8) & 0x00ff0000) | ((i >> 8) & 0x0000ff00) | (i << 24); + if (i == 0x00015555) return true; + return false; + } +}; + class CbmMcbm2018UnpackerAlgoRich : public CbmStar2019Algo<CbmRichDigi> { public: CbmMcbm2018UnpackerAlgoRich(); @@ -106,43 +241,26 @@ private: */ void InitStorage(); + std::string GetLogHeader(CbmMcbm2018RichMicrosliceReader& reader); + void ProcessMicroslice(size_t const size, uint8_t const* const ptr); - /** - * Including header - */ - Int_t ProcessTRBevent(size_t const size, uint8_t const* const ptr); + void ProcessTrbPacket(CbmMcbm2018RichMicrosliceReader& reader); - /** - * - */ - Int_t ProcessTRBeventHeader(size_t const size, uint8_t const* const ptr); + void ProcessMbs(CbmMcbm2018RichMicrosliceReader& reader, bool isPrev); - /** - * Including header - ? - * Return number of processed bytes - */ - Int_t ProcessSKIPsubevent(size_t const size, uint8_t const* const ptr); + void ProcessHubBlock(CbmMcbm2018RichMicrosliceReader& reader); - Int_t ProcessCTSsubevent(size_t const size, uint8_t const* const ptr); + void ProcessCtsSubSubEvent(CbmMcbm2018RichMicrosliceReader& reader, uint32_t subSubEventSize, uint32_t subSubEventId); - Int_t ProcessTRBsubevent(size_t const size, uint8_t const* const ptr); + void ProcessSubSubEvent(CbmMcbm2018RichMicrosliceReader& reader, int nofTimeWords, uint32_t subSubEventId); - /** - * Including TDC header, but not including TRB subsubevent header - * Return number of processed bytes - */ - Int_t ProcessTRBsubsubevent(size_t const size, uint8_t const* const ptr, Int_t const hubOffset, size_t const hubSize); + double CalculateTime(uint32_t epoch, uint32_t coarse, uint32_t fine); - /** - * Process a word written out by the TDC - TIMESTEMP, HEADER, TRAILER, DEBUG, EPOCH, ... - */ - Int_t ProcessTDCword(uint8_t const* const ptr, Int_t const word, size_t const size); + bool IsLog(); - /** - * Process specifically a TIMESTAMP type of word - */ - void ProcessTimestampWord(Int_t tdcData); + void ProcessTimeDataWord(CbmMcbm2018RichMicrosliceReader& reader, int iTdc, uint32_t epoch, uint32_t tdcWord, + uint32_t subSubEventId, std::vector<double>& raisingTime); /** * Write a gidi object into the output collection @@ -157,7 +275,7 @@ private: /** * Write Errors to Histograms */ - void ErrorMsg(uint16_t errbits, RichErrorType type, uint16_t tdcAddr = 0); + void ErrorMsg(uint16_t errbits, CbmMcbm2018RichErrorType type, uint16_t tdcId = 0); Int_t GetPixelUID(Int_t fpgaID, Int_t ch) const { @@ -166,52 +284,35 @@ private: return ((fpgaID << 16) | (ch & 0x00FF)); } - void findTDCAlignmentError(uint8_t const* const ptr, size_t const size); +private: + double fToTMin = -20.; + double fToTMax = 100.; -private: // data members /// Control flags - Bool_t fbMonitorMode; //! Switch ON the filling of a minimal set of histograms - - Bool_t fbDebugMonitorMode; //! Switch ON the filling of a additional set of histograms - - Bool_t fRawDataMode; - - Bool_t fError; //! flag for an error in the datastream + Bool_t fbMonitorMode = false; // Switch ON the filling of a minimal set of histograms + Bool_t fbDebugMonitorMode = false; // Switch ON the filling of a additional set of histograms + Bool_t fRawDataMode = false; - TrbNetState fTrbState; // State of TrbNet (HEADER,TRAILER,...) + uint64_t fTsCounter = 0; //Counter of processed timeslices + uint32_t fMsInd = 0; // Current microslice index - uint32_t fErrorCorr; // Offset to correct a error in datastream + double fMbsPrevTimeCh0 = 0.; + double fMbsPrevTimeCh1 = 0.; - /// User setting: kTRUE activates ToT correction from Parameterfile - Bool_t fbDoToTCorr; + std::map<uint32_t, double> fLastCh0ReTime; //key:TDC ID, value:Full time of last rising edge from ch 0 + std::map<uint32_t, double> fPrevLastCh0ReTime; // key:TDC ID, value:Full time of previous last rising edge from ch 0 - Bool_t fSkipMs; - /// User settings: Data correction parameters - Double_t fdTimeOffsetNs; - - size_t fDataSize = 0; + Bool_t fbDoToTCorr = true; // kTRUE activates ToT correction from Parameterfile + Double_t fdTimeOffsetNs = 0.; // User settings: Data correction parameters /** * Bug fix / shortcut, which helps to run correct ProcessTs method. * Works only if there is one componentID assigned to the detector. */ - Int_t fRICHcompIdx; - - /** - * Unpacker parameters object - */ - CbmMcbm2018RichPar* fUnpackPar; //! - - /** - * Counter of processed timeslices - */ - uint64_t fTScounter; + Int_t fRICHcompIdx = 6; - /** - * Current microslice ID - */ - Int_t fCurMSid; //! + CbmMcbm2018RichPar* fUnpackPar = nullptr; //! /** * Current microslice index from the microslice descriptor @@ -219,164 +320,33 @@ private: // data members */ uint64_t fCurMSidx; //! - /** - * Global word counter within current microslice - */ - Int_t fGwordCnt; //! - - /** - * Flag indicating that we are in the subsubevent - */ - Bool_t fInSubSubEvent; //! - - /** - * Current epoch value - */ - UInt_t fCurEpochCounter; //! - - /** - * Current subsubevent ID - */ - Int_t fSubSubEvId; //! - - /** - * Flag to mark the last DiRICH on a Hub - */ - Bool_t fLastFeeOnHub = false; - - std::vector<Int_t> fTDCAlignmentErrorPositions; - - Int_t fTdcWordCorrectionCnt = 0; - - Int_t fTdcWordCorrectionGlobalCnt = 0; - - Int_t fSkipCnt = 0; - -private: // Stored timestamps - /** - * Full time of the last rising edge from ch 0 of CTS - */ - Double_t fLastCTSch0_re_time; //! - - /** - * Full time of the last rising edge from ch 2 of CTS - */ - Double_t fLastCTSch2_re_time; //! - - /** - * Full time of the last falling edge from ch 2 of CTS - */ - Double_t fLastCTSch2_fe_time; //! - - /** - * Full time of the last rising edge from ch 0 of CTS from the previous microslice - */ - Double_t fPrevLastCTSch0_re_time; //! - - /** - * Full time of the last rising edge from ch 2 of CTS from the previous microslice - */ - Double_t fPrevLastCTSch2_re_time; //! - - /** - * Full time of the last falling edge from ch 2 of CTS from the previous microslice - */ - Double_t fPrevLastCTSch2_fe_time; //! - - /** - * Full time of the last rising edge from ch 0 of each TDC - */ - TArrayD fLastCh0_re_time; //! - - /** - * Full time of the previous last rising edge from ch 0 of each TDC (from the previous microslice) - */ - TArrayD fPrevLastCh0_re_time; //! - -private: // digi building - void ProcessRisingEdge(Int_t subSubEvId, Int_t channel, Double_t time); - - void ProcessFallingEdge(Int_t subSubEvId, Int_t channel, Double_t time); - - /** - * Buffer for rising edges. It is filled during unpacking whenever - * the rising edge is encountered. Afterwards, when a falling edge - * is encountered, corresponding rising edge is searched here and - * removed if found. - */ - std::vector<CbmMcbmRichEdge> fRisingEdgesBuf; //! Exclude from ROOT dictionnary due to missing empty constructor!! - - /** - * Buffer of falling edges for which corresponding rising edges were not found - */ - std::vector<CbmMcbmRichEdge> fFallingEdgesBuf; //! Exclude from ROOT dictionnary due to missing empty constructor!! - public: // histograms /** * */ Bool_t CreateHistograms(); - /** - * - */ - // Bool_t FillHistograms(); - /** * */ Bool_t ResetHistograms(); - TH1D* GetTotH1(Int_t fpgaID, Int_t channel); - TH2D* GetTotH2(Int_t fpgaID); - /* - TH2D* fhTDCch0re_minusCTSch0re; //! - TH2D* fhTDCch0re_minusCTSch2re; //! - TH2D* fhTDCch0re_minusCTSch2fe; //! - TH2D* fhTDCch0re_minusPrevCTSch0re; //! - TH2D* fhTDCch0re_minusPrevCTSch2re; //! - TH2D* fhTDCch0re_minusPrevCTSch2fe; //! - - std::vector<TH2D*> fhTDCre_minusTDCch0re; //! + TH1D* GetTotH1(uint32_t fpgaID, uint32_t channel); + TH2D* GetTotH2(uint32_t fpgaID); - std::vector<TH2D*> fhTDCre_minusPrevTDCch0re; //! -*/ - std::vector<TH2D*> fhTDCre_corrected1; //! + std::vector<TCanvas*> fcTot2d; - std::vector<TH2D*> fhTDCre_corrected2; //! - - std::vector<TCanvas*> fcTot2d; //! - - TH1* fhVectorSize = nullptr; - TH1* fhVectorCapacity = nullptr; - - //TH2* fhDigisInChnl = nullptr; - //TH2* fhDigisInDiRICH = nullptr; - - TH2D* fhTdcErrors = nullptr; - TH2D* fhEventErrors = nullptr; - - TH2D* fhDiRICHWords = nullptr; - TH2D* fhChnlWords = nullptr; + TH2D* fhTdcErrors = nullptr; TH1* fhEventSize = nullptr; TH2* fhSubEventSize = nullptr; TH2* fhSubSubEventSize = nullptr; TH2* fhChnlSize = nullptr; - std::array<unsigned int, 33> fChnlMsgCnt; - - bool fDebugPrint = 0; std::map<uint16_t, uint16_t> fMapFEE; - std::map<Int_t, std::map<Int_t, TH1D*>> fhTotMap; - - std::map<Int_t, TH2D*> fhTot2dMap; - - size_t fuTsMaxVectorSize = 0; - Double_t fdCapacityIncFactor = 1.1; - - inline void SetVectCapInc(Double_t dIncFact) { fdCapacityIncFactor = dIncFact; } + std::map<uint32_t, std::map<Int_t, TH1D*>> fhTotMap; + std::map<uint32_t, TH2D*> fhTot2dMap; ClassDef(CbmMcbm2018UnpackerAlgoRich, 1); }; diff --git a/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerAlgoRich2020.cxx b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerAlgoRich2020.cxx new file mode 100644 index 0000000000..7c276ce115 --- /dev/null +++ b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerAlgoRich2020.cxx @@ -0,0 +1,1882 @@ +/* Copyright (C) 2019-2020 Justus-Liebig-Universitaet Giessen, Giessen + SPDX-License-Identifier: GPL-3.0-only + Authors: Egor Ovcharenko [committer], Pierre-Alain Loizeau */ + +/** + * CbmMcbm2018UnpackerAlgoRich20202020 + * E. Ovcharenko, Mar 2019 + * based on other detectors' classes by P.-A. Loizeau + */ + +/** + +Consider two consequent microslices A and B. +Each microslice contains one CTS subevent which contains at least 3 timestamp messages. +A microslice may also contain TRB subevents, each containing also one timestamp message from ch0. + +Microslice A +=================== +CTS | ch 0 re = AC0R (stands for ms A, Cts, ch 0, Rising edge) +CTS | ch 2 fe +CTS | ch 2 re = AC2R (stands for ms A, Cts, ch 2, Rising edge) +------------------- +TDC K | ch 0 re +------------------- +TDC Z | ch 0 re = AZ0R (stands for ms A, tdc Z, ch 0, Rising edge)) + | ch X re + | ch X fe + | ... +------------------- +... +=================== + +Microslice B (next after A) +=================== +CTS | ch 0 re +CTS | ch 2 fe +CTS | ch 2 re +------------------- +TDC L | ch 0 re +------------------- +TDC Z | ch 0 re + | ch Y re = (T - AZ0R) + corr + | ch Y fe + | ... +------------------- +... +=================== + +corr = -(AC2R-AC0R) + +Uncorrected full time in ns of the TIMESTAMP message calculated as +T = epoch*2048.*5. + (coarse)*5. - fine*0.005 + +Full corrected global time is then computed by adding the microslice +index from the descriptor to the corrected time: + +fullTimeCorr = (T - AZ0R) - (AC2R-AC0R) + MSidx + +*/ + +//TODO: Check that to 'real' actions are performed in the lines which are intended for debug output only. +// i.e. LOG(XXXX) << ... + +#include "CbmMcbm2018UnpackerAlgoRich2020.h" + +// ROOT +#include <Logger.h> + +#include <TCanvas.h> +#include <TList.h> + +// CbmRoot +#include "CbmMcbm2018RichPar.h" + +#include <iostream> + +CbmMcbm2018UnpackerAlgoRich2020::CbmMcbm2018UnpackerAlgoRich2020() + : CbmStar2019Algo() + , fbMonitorMode(kFALSE) + , fbDebugMonitorMode(kFALSE) + , fRawDataMode(kFALSE) + , fError(kFALSE) + , fTrbState(TrbNetState::IDLE) + , fErrorCorr(0) + , fbDoToTCorr(kTRUE) + , fSkipMs(kFALSE) + , fdTimeOffsetNs(0.0) + , fRICHcompIdx(6) + , //TODO experimentally obtained value + fUnpackPar(nullptr) + , fTScounter(0) + , fCurMSid(0) + , fGwordCnt(0) + , fInSubSubEvent(kFALSE) + , fCurEpochCounter(0) + , fSubSubEvId(0) + , fLastCTSch0_re_time(0.) + , fLastCTSch2_re_time(0.) + , fLastCTSch2_fe_time(0.) + , fPrevLastCTSch0_re_time(0.) + , fPrevLastCTSch2_re_time(0.) + , fPrevLastCTSch2_fe_time(0.) + , /*, + fhTDCch0re_minusCTSch0re(nullptr), + fhTDCch0re_minusCTSch2re(nullptr), + fhTDCch0re_minusCTSch2fe(nullptr), + fhTDCch0re_minusPrevCTSch0re(nullptr), + fhTDCch0re_minusPrevCTSch2re(nullptr), + fhTDCch0re_minusPrevCTSch2fe(nullptr)*/ + fMapFEE() + , fhTotMap() + , fhTot2dMap() +{ + this->Init(); //TODO why this is not called by the framework? +} + +CbmMcbm2018UnpackerAlgoRich2020::~CbmMcbm2018UnpackerAlgoRich2020() +{ + if (nullptr != fParCList) delete fParCList; + if (nullptr != fUnpackPar) delete fUnpackPar; +} + +Bool_t CbmMcbm2018UnpackerAlgoRich2020::Init() +{ + LOG(info) << "Initializing mCBM RICH 2019 unpacker algo"; + //fhDigisInChnl = new TH2D("fhDigisInChnl","fhDigisInChnl;channel;#Digis;" ,2304 , -0.5, 2303.5, 50, -0.5, 49.5); + //fhDigisInDiRICH = new TH2D("fhDigisInDiRICH","fhDigisInDiRICH;DiRICH;#Digis;",72 , -0.5, 71.5, 300, -0.5, 299.5); + return kTRUE; +} + +void CbmMcbm2018UnpackerAlgoRich2020::Reset() {} + +void CbmMcbm2018UnpackerAlgoRich2020::Finish() {} + +Bool_t CbmMcbm2018UnpackerAlgoRich2020::InitContainers() +{ + LOG(info) << "Init parameter containers for CbmMcbm2018UnpackerAlgoRich2020"; + Bool_t initOK = ReInitContainers(); + + return initOK; +} + +Bool_t CbmMcbm2018UnpackerAlgoRich2020::ReInitContainers() +{ + LOG(info) << "ReInit parameter containers for CbmMcbm2018UnpackerAlgoRich2020"; + + fUnpackPar = (CbmMcbm2018RichPar*) fParCList->FindObject("CbmMcbm2018RichPar"); + if (fUnpackPar == nullptr) { return kFALSE; } + + Bool_t initOK = InitParameters(); + + return initOK; +} + +TList* CbmMcbm2018UnpackerAlgoRich2020::GetParList() +{ + if (fParCList == nullptr) { fParCList = new TList(); } + fUnpackPar = new CbmMcbm2018RichPar("CbmMcbm2018RichPar"); + fParCList->Add(fUnpackPar); + + return fParCList; +} + +Bool_t CbmMcbm2018UnpackerAlgoRich2020::InitParameters() +{ + InitStorage(); + return kTRUE; +} + +void CbmMcbm2018UnpackerAlgoRich2020::InitStorage() +{ + fLastCh0_re_time.Set(fUnpackPar->GetNaddresses()); // Set the size of the array + fPrevLastCh0_re_time.Set(fUnpackPar->GetNaddresses()); // Set the size of the array +} + +/** + Copied from other detectors without any brain effort... + A little bug-fix added +**/ +void CbmMcbm2018UnpackerAlgoRich2020::AddMsComponentToList(size_t component, UShort_t usDetectorId) +{ + /// Check for duplicates and ignore if it is the case + for (UInt_t uCompIdx = 0; uCompIdx < fvMsComponentsList.size(); ++uCompIdx) { + if (component == fvMsComponentsList[uCompIdx]) { return; } + } + + /// Add to list + fvMsComponentsList.push_back(component); + + if (fvMsComponentsList.size() == 1) { fRICHcompIdx = component; } + else { + LOG(WARN) << "fvMsComponentsList.size() > 1 for RICH. Unpacking may not " + "work due to implementation limitations."; + } + + LOG(info) << "CbmMcbm2018UnpackerAlgoRich2020::AddMsComponentToList => Component " << component + << " with detector ID 0x" << std::hex << usDetectorId << std::dec << " added to list"; +} + +Bool_t CbmMcbm2018UnpackerAlgoRich2020::ProcessTs(const fles::Timeslice& /*ts*/) +{ + LOG(debug2) << "CbmMcbm2018UnpackerAlgoRich2020::ProcessTs(ts)"; + /* + //TODO: shortcut. We love shortcuts, right? + if (fvMsComponentsList.size() == 1) { + this->ProcessTs(ts, fvMsComponentsList.at(0)); + } + + //TODO: implement case when multiple components have to be processed +*/ + return kTRUE; +} + +Bool_t CbmMcbm2018UnpackerAlgoRich2020::ProcessTs(const fles::Timeslice& ts, size_t component) +{ + /// Ignore First TS as first MS is typically corrupt + if (0 == ts.index()) { return kTRUE; } // if( 0 == ts.index() ) + + LOG(debug2) << "CbmMcbm2018UnpackerAlgoRich2020::ProcessTs(ts, " << component << ")"; + + //TODO: skip if this method was called for a wrong component + //if (component != fRICHcompIdx) return kTRUE; + //FIXME: this is really nasty... + // component = fRICHcompIdx; + if (1 != fvMsComponentsList.size()) { + /// If no RICH component, do nothing! + if (0 == fvMsComponentsList.size()) return kTRUE; + + /// If multiple RICH components, fail the run + TString sCompList = ""; + for (UInt_t uMsCompIdx = 0; uMsCompIdx < fvMsComponentsList.size(); ++uMsCompIdx) + sCompList += Form(" %2lu ", fvMsComponentsList[uMsCompIdx]); + LOG(fatal) << "CbmMcbm2018UnpackerAlgoRich2020::ProcessTs => More than 1 " + "component in list, unpacking impossible! List is " + << sCompList; + } // if( 1 != fvMsComponentsList.size() ) + component = fvMsComponentsList[0]; + + LOG(debug) << "Components: " << ts.num_components(); + LOG(debug) << "Microslices: " << ts.num_microslices(component); + + const uint64_t compSize = ts.size_component(component); + LOG(debug) << "Component " << component << " has size " << compSize; + + /// On first TS, extract the TS parameters from header (by definition stable over time) + if (-1.0 == fdTsCoreSizeInNs) { + fuNbCoreMsPerTs = ts.num_core_microslices(); + fuNbOverMsPerTs = ts.num_microslices(0) - ts.num_core_microslices(); + fdTsCoreSizeInNs = fdMsSizeInNs * (fuNbCoreMsPerTs); + fdTsFullSizeInNs = fdMsSizeInNs * (fuNbCoreMsPerTs + fuNbOverMsPerTs); + LOG(info) << "Timeslice parameters: each TS has " << fuNbCoreMsPerTs << " Core MS and " << fuNbOverMsPerTs + << " Overlap MS, for a core duration of " << fdTsCoreSizeInNs << " ns and a full duration of " + << fdTsFullSizeInNs << " ns"; + + /// Ignore overlap ms if flag set by user + fuNbMsLoop = fuNbCoreMsPerTs; + if (kFALSE == fbIgnoreOverlapMs) fuNbMsLoop += fuNbOverMsPerTs; + LOG(info) << "In each TS " << fuNbMsLoop << " MS will be looped over"; + } // if( -1.0 == fdTsCoreSizeInNs ) + + for (size_t iMS = 0; iMS < fuNbMsLoop; ++iMS) { + fCurMSid = iMS; + LOG(debug) << "======================================================="; + const fles::MicrosliceView mv = ts.get_microslice(component, iMS); + const fles::MicrosliceDescriptor& msDesc = mv.desc(); + ////const uint8_t* msContent = mv.content(); + LOG(debug) << "msDesc.size=" << msDesc.size; + fCurMSidx = msDesc.idx; + LOG(debug) << "msDesc.idx=" << msDesc.idx; + ////mRichSupport::PrintRaw(msDesc.size, msContent);//TODO delete + ////LOG(debug) << "======================================================="; + //////////////////////////////// + //ProcessMs(ts, component, iMS);// + //////////////////////////////// + + if (!fRawDataMode) ProcessMs(ts, component, iMS); + if (fRawDataMode) DebugMs(ts, component, iMS); + + LOG(debug) << "======================================================="; + } + + /////////////// + FinalizeTs(); // + /////////////// + + if (0 == fTScounter % 1000) { LOG(info) << "Processed " << fTScounter << " TS"; } + + fTScounter++; + + /// Sort the buffers of hits due to the time offsets applied + std::sort(fDigiVect.begin(), fDigiVect.end(), + [](const CbmRichDigi& a, const CbmRichDigi& b) -> bool { return a.GetTime() < b.GetTime(); }); + + if (fbMonitorMode || fbDebugMonitorMode) { + fhVectorSize->Fill(ts.index(), fDigiVect.size()); + fhVectorCapacity->Fill(ts.index(), fDigiVect.capacity()); + } // if( fbMonitorMode || fbDebugMonitorMode ) + + if (fuTsMaxVectorSize < fDigiVect.size()) { + fuTsMaxVectorSize = fDigiVect.size() * fdCapacityIncFactor; + fDigiVect.shrink_to_fit(); + fDigiVect.reserve(fuTsMaxVectorSize); + } // if( fuTsMaxVectorSize < fDigiVect.size() ) + + return kTRUE; +} + +Bool_t CbmMcbm2018UnpackerAlgoRich2020::ProcessMs(const fles::Timeslice& ts, size_t uMsCompIdx, size_t uMsIdx) +{ + const fles::MicrosliceView mv = ts.get_microslice(uMsCompIdx, uMsIdx); + const fles::MicrosliceDescriptor& msDesc = mv.desc(); + const uint8_t* ptr = mv.content(); + const size_t size = msDesc.size; + + if (size == 0) return kTRUE; + + fGwordCnt = 0; //TODO check that this global word counter works properly + + Int_t offset; // offset in bytes + Int_t* dataPtr; + + offset = 0; + mRichSupport::SwapBytes(4, ptr + offset); + LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" + << "ok" + << "\t" + << "Reserved 0000 0000"; + fGwordCnt++; + + offset = 4; + mRichSupport::SwapBytes(4, ptr + offset); + // clang-format off + dataPtr = (Int_t*) (ptr + offset); + Int_t mbsNumber = (Int_t)(dataPtr[0] & 0xffffff); + uint8_t mts_error_msg = (uint8_t)((dataPtr[0] >> 24) & 0xff); + // clang-format on + ErrorMsg(static_cast<uint16_t>(mts_error_msg), RichErrorType::mtsError); + LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" + << "ok" + << "\t" + << "mbsNumber = " << mbsNumber; + fGwordCnt++; + + // We suppose that the first word is + // "HadesTransportUnitQueue - Length" + offset = 0 + 8; + mRichSupport::SwapBytes(4, ptr + offset); + // clang-format off + dataPtr = (Int_t*) (ptr + offset); + Int_t TRBeventSize1 = (Int_t)(dataPtr[0]); + // clang-format on + LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" + << "ok" + << "\t" + << "HadesTransportUnitQueue - Length = " << TRBeventSize1; + fGwordCnt++; + + if (*dataPtr > 0 && UInt_t(*dataPtr) == 0x80030000) { + LOG(info) << "dataPtr == 0x80030000"; + exit(EXIT_FAILURE); + } + + // We suppose that the second word is + // "HadesTransportUnitQueue - Decoder (Seems to be allways the same)" + offset = 4 + 8; + mRichSupport::SwapBytes(4, ptr + offset); + // clang-format off + dataPtr = (Int_t*) (ptr + offset); + Int_t dcdr = (Int_t)(dataPtr[0]); + // clang-format on + if (dcdr == 0x00030062) { + LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" + << "ok" + << "\t" + << "HadesTransportUnitQueue - Decoder = " << dcdr; + fGwordCnt++; + } + else { + LOG(warning) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" + << "er" + << "\t" + << "HadesTransportUnitQueue - Decoder = " << dcdr << " is not 0x00030062 (196706) => 0x" << std::hex + << dcdr << std::dec; + fGwordCnt++; + + /// Probably corrupted MS, stop there and skip remaining data + fSkipMs = kTRUE; + return kFALSE; + } + + // We suppose that the third word is + // TRB event length (in bytes) + // It should be 8 less than the size specified two words ago + offset = 8 + 8; + mRichSupport::SwapBytes(4, ptr + offset); + // clang-format off + dataPtr = (Int_t*) (ptr + offset); + Int_t TRBeventSize2 = (Int_t)(dataPtr[0]); + // clang-format on + if (TRBeventSize2 == TRBeventSize1 - 8) { + LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" + << "ok" + << "\t" + << "TRB event - Length = " << TRBeventSize2 << " == " << TRBeventSize1 << "-8"; + fGwordCnt++; + } + else { + LOG(debug) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" + << "er" + << "\t" + << "TRB event - Length = " << TRBeventSize2 << " != " << TRBeventSize1 << "-8=" << TRBeventSize1 - 8; + fGwordCnt++; + } + + ///////////////////////////////////////////// + ProcessTRBevent(TRBeventSize2, ptr + offset); // + ///////////////////////////////////////////// + + // Bytes in a TrbEvent + if (fbDebugMonitorMode) fhEventSize->Fill(TRBeventSize2); + + + if (fSkipMs == kTRUE) { + // problem in data; delete vectors. + fDigiVect.clear(); + fSkipMs = kFALSE; + } + + + return kTRUE; +} + +Int_t CbmMcbm2018UnpackerAlgoRich2020::ProcessTRBevent(size_t const size, uint8_t const* const ptr) +{ + Int_t offset; // offset in bytes + Int_t* dataPtr; + + // We assume that the TRB event header is 4 words and + // the first word is already processed outside of this method + + ////////////////////////////////// + ProcessTRBeventHeader(4 * 4, ptr); // + ////////////////////////////////// + + offset = 16; // start from after the TRB event header + + // 1. Search for the CTS subevent and extract reference time + + while (static_cast<size_t>(offset) < size) { + /// Escape bad MS before doing anything + if (fSkipMs == kTRUE) break; + + // Duplicate the header word in order to avoid corrupting (by bytes swapping) + // the original data + // clang-format off + dataPtr = (Int_t*) (ptr + offset); + + Int_t headerCopy = *dataPtr; + mRichSupport::SwapBytes(4, (uint8_t*) &headerCopy); + dataPtr = &headerCopy; + + Int_t SubEvSize = (Int_t) ((dataPtr[0] >> 16) & 0xffff); + Int_t HubId = (Int_t) ((dataPtr[0]) & 0xffff); + // clang-format on + // Process only CTS subevent + //FIXME change from 0xc001 to 0xc000 at some point // ? + if ((HubId == 0xc001) || (HubId == 0xc000)) { + + // Not a very nice shortcut + // The global counter of the words is incremented for the CTS subevent header here + // However for the TRB subevent headers it is incremented in the second run, + // where only TRB subevent headers are processed and the CTS subevents are skipped + LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr((uint8_t*) &headerCopy) << "\t" + << "ok" + << "\t" + << "hub ID = 0x" << mRichSupport::GetHexRepresentation(2, (uint8_t*) &headerCopy) << "\t" + << "subevent size = " << SubEvSize; + fGwordCnt++; + + fSubSubEvId = HubId; + ////////////////////////////////////////////////////////////// + offset += (4 + ProcessCTSsubevent(SubEvSize * 4, ptr + offset)); // + ////////////////////////////////////////////////////////////// + + //std::cout<<"Words in CTS 0x"<< std::hex << HubId << std::dec <<" : "<< SubEvSize <<std::endl; + // In principle, should be reset here for safety + fSubSubEvId = 0; + } + else { + // Skip all other subevents + offset += (4 + SubEvSize * 4); + } + } + + offset = 16; // start from after the TRB event header again + + // 2. Process TRB subsubevents + + //Int_t iIter = 0; + while (static_cast<size_t>(offset) < size) { + /// Escape bad MS before doing anything + if (fSkipMs == kTRUE) break; + + //std::cout << "SE iteration " << iIter++ << "\toffset=" << offset << "\tsize=" << size << std::endl; + + // We suppose that the fifth word is the header of the subevent + // <Length> <HubId> + mRichSupport::SwapBytes(4, ptr + offset); + // clang-format off + dataPtr = (Int_t*) (ptr + offset); + Int_t SubEvSize = (Int_t)((dataPtr[0] >> 16) & 0xffff); + Int_t HubId = (Int_t)((dataPtr[0]) & 0xffff); + // clang-format on + //FIXME change from 0xc001 to 0xc000 at some point // ? + if ((HubId == 0xc001) || (HubId == 0xc000)) { + ////fSubSubEvId = HubId; + ////////////////////////////////////////////////////////////////// + ////offset += (4 + ProcessCTSsubevent(SubEvSize*4, ptr+offset));// + ////////////////////////////////////////////////////////////////// + ////// In principle, should be reset here for safety + ////fSubSubEvId = 0; + + // Skip CTS subevent as it has been already processed during the first run + offset += (4 + SubEvSize * 4); + fLastFeeOnHub = false; + } + else if (HubId == 0x5555) { + LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" + << "ok" + << "\t" + << "hub ID = 0x" << mRichSupport::GetHexRepresentation(2, ptr + offset) << "\t" + << "subevent size = " << SubEvSize; + fGwordCnt++; + fLastFeeOnHub = false; + //TODO one could implement additional checks here about the + // words coming after the "event end" but we skip everything by now. + /////////////////////////////////////////////////////////////// + offset += (4 + ProcessSKIPsubevent(SubEvSize * 4, ptr + offset)); // + /////////////////////////////////////////////////////////////// + } + else if (((HubId >> 8) & 0xFF) == 0x82) { + LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" + << "ok" + << "\t" + << "hub ID = 0x" << mRichSupport::GetHexRepresentation(2, ptr + offset) << "\t" + << "subevent size = " << SubEvSize; + fGwordCnt++; + fLastFeeOnHub = false; + //std::cout<<"Hub: "<<std::hex<<HubId <<std::dec<<" Size:"<< SubEvSize<<std::endl; + ////////////////////////////////////////////////////////////// + offset += (4 + ProcessTRBsubevent(SubEvSize * 4, ptr + offset)); // + ////////////////////////////////////////////////////////////// + + //std::cout<<"Words in Hub 0x"<< std::hex << HubId << std::dec <<" : "<< SubEvSize <<std::endl; + // Bytes in a Hub + if (fbDebugMonitorMode) { + uint16_t combiner_address = ((HubId >> 4) & 0xF) * 3 + (HubId & 0xF); + fhSubEventSize->Fill(combiner_address, (SubEvSize * 4)); + } + } + else { + LOG(WARN) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" + << "ok" + << "\t" + << "hub ID = 0x" << mRichSupport::GetHexRepresentation(2, ptr + offset) << "\t" + << "subevent size = " << SubEvSize << "\n" + << "This is not a valid Combiner Id!" + << "\n" + << "prev prev2:" << mRichSupport::GetWordHexRepr(ptr + offset - 12) << "\n" + << "prev prev: " << mRichSupport::GetWordHexRepr(ptr + offset - 8) << "\n" + << "prev: " << mRichSupport::GetWordHexRepr(ptr + offset - 4) << "\n" + << "next: " << mRichSupport::GetWordHexRepr(ptr + offset + 4) << "\n" + << "next next: " << mRichSupport::GetWordHexRepr(ptr + offset + 8) << "\n"; + ////////////////////////////////////////////////////////////// + offset += (4 + SubEvSize * 4); + ////////////////////////////////////////////////////////////// + } + } + + ////LOG(debug4) << "Done processing TRB event. offset=" << offset << "\tsize=" << size; + //TODO implement checks + if (size != static_cast<size_t>(offset)) { + LOG(WARN) << "CbmMcbm2018UnpackerAlgoRich2020::ProcessTRBevent() warning:" + << "Number of processed bytes is not equal to the expected size. " + "This should not happen. (" + << size << " VS " << offset << ")"; + } + + return size; //TODO check +} + +// Process TRB event header. +// Input arguments are the size of the TRB event header (16 bytes) and the pointer to the first word. +// Note that the first word can already be analysed outside of this method. +// Return number of bytes processed. For this particular method the value of the input 'size' argument +// is returned as we expect that the TRB header is always 16 bytes. +Int_t CbmMcbm2018UnpackerAlgoRich2020::ProcessTRBeventHeader(size_t const size, uint8_t const* const ptr) +{ + Int_t offset; // offset in bytes + Int_t* dataPtr; + + // Skip first word (already processed outside) + //offset = 0; + // do nothing + + // We suppose that the second word consists of + // 0002 - number of following word till the Event Data Starts (should be the same) + // 00<TriggerType>1 - value in [7:4] defines TriggerType + offset = 4; + mRichSupport::SwapBytes(4, ptr + offset); + // clang-format off + dataPtr = (Int_t*) (ptr + offset); + Int_t checkSize = (Int_t)((dataPtr[0] >> 16) & 0xffff); + Int_t triggerType = (Int_t)((dataPtr[0] >> 4) & 0xf); + // clang-format on + if (checkSize == 2) { + LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" + << "ok" + << "\t" + << "checkSize == 2" + << "\t" + << "trigger type = " << triggerType; + fGwordCnt++; + } + else { + LOG(warning) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" + << "er" + << "\t" + << "checkSize != 2 (" << checkSize << ")\t" + << "trigger type = " << triggerType; + fGwordCnt++; + + /// Probably corrupted MS, stop there and skip remaining data + fSkipMs = kTRUE; + return 0; + } + + /*for (size_t iWord=2; iWord<size; iWord++) { + offset = iWord*4; + LOG(debug4) << "\t" << GetWordHexRepr(ptr+offset); + }*/ + + // We suppose that the third word consists of + // 0000 <SubEventId> + offset = 8; + mRichSupport::SwapBytes(4, ptr + offset); + // clang-format off + dataPtr = (Int_t*) (ptr + offset); + Int_t checkBytes = (Int_t)((dataPtr[0] >> 16) & 0xffff); + // clang-format on + // Int_t SubEvId = (Int_t)((dataPtr[0]) & 0xffff); + if (checkBytes == 0) { + LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" + << "ok" + << "\t" + << "checkBytes == 0" + << "\t" + << "subevent ID = 0x" << mRichSupport::GetHexRepresentation(2, ptr + offset); + fGwordCnt++; + } + else { + LOG(warning) << "[" << fGwordCnt++ << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" + << "er" + << "\t" + << "checkBytes != 0 (" << checkBytes << ")\t" + << "subevent ID = 0x" << mRichSupport::GetHexRepresentation(2, ptr + offset); + fGwordCnt++; + + /// Probably corrupted MS, stop there and skip remaining data + fSkipMs = kTRUE; + return 0; + } + + // We suppose that the fourth word is the trigger number + offset = 12; + mRichSupport::SwapBytes(4, ptr + offset); + // clang-format off + dataPtr = (Int_t*) (ptr + offset); + UInt_t TriggerNum = (UInt_t)(dataPtr[0]); + // clang-format on + LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" + << "ok" + << "\t" + << "trigger num = " << TriggerNum; + fGwordCnt++; + + return size; +} + +Int_t CbmMcbm2018UnpackerAlgoRich2020::ProcessSKIPsubevent(size_t const size, uint8_t const* const ptr) +{ + ////LOG(debug4) << "ProcessSKIPsubevent size=" << size << " bytes"; + + Int_t offset; // offset in bytes + Int_t* dataPtr; //(FU) not used + uint16_t SubEventError = 0; + + // Skip first word (already processed outside) + offset = 4; + + //Start Error identification + mRichSupport::SwapBytes(4, ptr + offset); + // clang-format off + dataPtr = (Int_t*) (ptr + offset); + SubEventError = (uint16_t)((dataPtr[0] >> 16) & 0xffff); + // clang-format on + ErrorMsg(static_cast<uint16_t>(SubEventError), RichErrorType::subEventError); + + offset = 8; + //End Error identification + + while (static_cast<size_t>(offset) < size + 4) { + mRichSupport::SwapBytes(4, ptr + offset); + // dataPtr = (Int_t*)(ptr+offset); (FU) not used + LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset); + fGwordCnt++; + + offset += 4; + } + + ////LOG(debug4) << "Done processing SKIP subevent. offset=" << offset << "\tsize=" << size; + //TODO implement checks + if (size != static_cast<size_t>(offset - 4)) { + LOG(WARN) << "CbmMcbm2018UnpackerAlgoRich2020::ProcessSKIPsubevent() warning:" + << "Number of processed bytes is not equal to the expected size. " + "This should not happen."; + } + + return size; //TODO check +} + +Int_t CbmMcbm2018UnpackerAlgoRich2020::ProcessCTSsubevent(size_t const size, uint8_t const* const ptr) +{ + ////LOG(debug4) << "ProcessCTSsubevent size=" << size << " bytes"; + + Int_t offset; // offset in bytes + Int_t* dataPtr; + + // Skip first word (already processed outside) + + // We suppose that the second word is the header of the subsubevent + offset = 4; + mRichSupport::SwapBytes(4, ptr + offset); + // clang-format off + dataPtr = (Int_t*) (ptr + offset); + // clang-format on + LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" + << "ok" + << "\t" + << "CTS header"; + fGwordCnt++; + + /* (FU) not used + Short_t trigState[16]; + for (Int_t i=0; i<16; i++) { + trigState[i] = ((*dataPtr >> i) & 0x1); // 16 x 1 bit + } +*/ + Short_t nInp = ((*dataPtr >> 16) & 0xf); // 4 bits + Short_t nTrigCh = ((*dataPtr >> 20) & 0x1f); // 5 bits + Short_t inclLastIdle = ((*dataPtr >> 25) & 0x1); // 1 bit + Short_t inclTrigInfo = ((*dataPtr >> 26) & 0x1); // 1 bit + Short_t inclTS = ((*dataPtr >> 27) & 0x1); // 1 bit + Short_t ETM = ((*dataPtr >> 28) & 0x3); // 2 bits + + // in words (not bytes) + Short_t CTSinfo_size = nInp * 2 + nTrigCh * 2 + inclLastIdle * 2 + inclTrigInfo * 3 + inclTS; + switch (ETM) { + case 0: break; + case 1: CTSinfo_size += 1; break; + case 2: CTSinfo_size += 4; break; + case 3: + LOG(debug) << "ETM == 3"; + //TODO implement + break; + } + + LOG(debug) << "CTS information size (extracted from the CTS header): " << CTSinfo_size; + + offset = 8; + + while (offset - 8 < CTSinfo_size * 4) { + mRichSupport::SwapBytes(4, ptr + offset); + // clang-format off + dataPtr = (Int_t*) (ptr + offset); + ULong_t MSidx = 102400UL * ((ULong_t)(*dataPtr) - 1); + // clang-format on + LOG(debug) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" + << "ok" + << "\t" + << "CTS information" + << " MSidx=" << MSidx; + fGwordCnt++; + + offset += 4; + } + + // size - full size including CTS header word, CTS informations words (CTSinfo_size) and TCD data + // Thus TDC data size = full size - 1 word (header) - CTSinfo_size words (CTS informations) + /////////////////////////////////////////////////////////////////////////// + fChnlMsgCnt.fill(0); + offset += (ProcessTRBsubsubevent((size - (1 + CTSinfo_size) * 4), ptr + offset, 0, 0)); // + /////////////////////////////////////////////////////////////////////////// + + ////LOG(debug4) << "Done processing CTS subevent. offset-4=" << offset-4 << "\tsize=" << size; + //TODO implement checks + if (size != static_cast<size_t>(offset - 4)) { + LOG(WARN) << "CbmMcbm2018UnpackerAlgoRich2020::ProcessCTSsubevent() warning:" + << "Number of processed bytes is not equal to the expected size. " + "This should not happen."; + } + + return size; //TODO check +} + +Int_t CbmMcbm2018UnpackerAlgoRich2020::ProcessTRBsubevent(size_t const size, uint8_t const* const ptr) +{ + ////LOG(debug4) << "ProcessTRBsubevent size=" << size << " bytes"; + + Int_t offset; // offset in bytes + Int_t* dataPtr; + + // Skip first word (already processed outside) + offset = 4; + + fTdcWordCorrectionCnt = 0; + + findTDCAlignmentError(ptr, size); + + //Int_t iIter = 0; + while (static_cast<size_t>(offset) < (size - 2)) { // test for cases with odd number of corrections + if (fSkipMs == kTRUE) break; + //std::cout << "SSE iteration " << iIter++ << "\toffset=" << offset << "\tsize=" << size << std::endl; + + //correct for misalignment + if (fTDCAlignmentErrorPositions.size() > static_cast<unsigned int>(fTdcWordCorrectionCnt) + && fTDCAlignmentErrorPositions[fTdcWordCorrectionCnt] == offset) { + //std::cout<<"Correction in DiRICH Header: "<< fTDCAlignmentErrorPositions[fTdcWordCorrectionCnt]<<std::endl; + offset += 2; + fTdcWordCorrectionCnt++; + } + + // We suppose that the second word is the header of the subsubevent + // <Length> <SubSubEv.Id> + mRichSupport::SwapBytes(4, ptr + offset); + // clang-format off + dataPtr = (Int_t*) (ptr + offset); + Int_t SubSubEvSize = (Int_t)((dataPtr[0] >> 16) & 0xffff); + fSubSubEvId = (Int_t)((dataPtr[0]) & 0xffff); + // clang-format on + //check if it is the last DiRICH in the Hub Data stream + //TODO CHECK! + if ((static_cast<size_t>(offset) + SubSubEvSize * 4) >= size) { + LOG(debug) << "Last DiRICH on HUB"; + fLastFeeOnHub = true; + } + + if (((fSubSubEvId >> 12) & 0xF) != 0x7) { + LOG(error) << mRichSupport::GetWordHexRepr(ptr + offset - 12) << "\t" + << "er" + << "\t" + << "ILLEGAL SubSubEvent Id prev"; + LOG(error) << mRichSupport::GetWordHexRepr(ptr + offset - 8) << "\t" + << "er" + << "\t" + << "ILLEGAL SubSubEvent Id prev"; + LOG(error) << mRichSupport::GetWordHexRepr(ptr + offset - 4) << "\t" + << "er" + << "\t" + << "ILLEGAL SubSubEvent Id prev"; + LOG(error) << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" + << "er" + << "\t" + << "ILLEGAL SubSubEvent Id " + << "Offset:" << static_cast<size_t>(offset) << " Size:" << size; + LOG(error) << mRichSupport::GetWordHexRepr(ptr + offset + 4) << "\t" + << "er" + << "\t" + << "ILLEGAL SubSubEvent Id next"; + LOG(error) << mRichSupport::GetWordHexRepr(ptr + offset + 8) << "\t" + << "er" + << "\t" + << "ILLEGAL SubSubEvent Id next"; + LOG(error) << mRichSupport::GetWordHexRepr(ptr + offset + 12) << "\t" + << "er" + << "\t" + << "ILLEGAL SubSubEvent Id next"; + } + + LOG(debug) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr + offset) << "\t" + << "ok" + << "\t" + << "subsubevent ID (FPGA ID) = 0x" << mRichSupport::GetHexRepresentation(2, ptr + offset) << "\t" + << "subsubevent size = " << SubSubEvSize << " | HUB Offset:" << static_cast<size_t>(offset) + << " Size:" << size; + fGwordCnt++; + + if (size + 4 < static_cast<size_t>(offset + 4 + SubSubEvSize * 4 - fTdcWordCorrectionCnt * 2)) { + LOG(WARN) << "CbmMcbm2018UnpackerAlgoRich2020::ProcessTRBsubevent() warning:" + << "SubEvent out of bounds. This should not happen. (" << size << " VS " + << (offset + 4 + SubSubEvSize * 4 - fTdcWordCorrectionCnt * 2) << ")"; + + /// Probably corrupted MS, stop there and skip remaining data + //fSkipMs = kTRUE; + } + + fChnlMsgCnt.fill(0); + + // Add 4 bytes which correspond to the header word + ////////////////////////////////////////////////////////////////////// + offset += (4 + ProcessTRBsubsubevent(SubSubEvSize * 4, ptr + offset + 4, offset + 4, size)); // + ////////////////////////////////////////////////////////////////////// + + //std::cout<<"Words in DiRICH 0x"<< std::hex << fSubSubEvId << std::dec <<" : "<< SubSubEvSize <<std::endl; + + if (fbDebugMonitorMode) { + //This address calculation is just for mCBM; will be a problem when using full CBM RICH acceptance + uint16_t DiRICH_address = ((fSubSubEvId >> 8) & 0xF) * 18 + ((fSubSubEvId >> 4) & 0xF) * 2 + (fSubSubEvId & 0xF); + fhSubSubEventSize->Fill(DiRICH_address, + SubSubEvSize); // Words in a DiRICH + + //Words per channel + for (size_t i = 1; i < fChnlMsgCnt.size(); ++i) { + if (fChnlMsgCnt.at(i) > 0) fhChnlSize->Fill(static_cast<int>(i), fChnlMsgCnt.at(i)); + } + } + + // In principle, should be reset here for safety + fSubSubEvId = 0; + } + + if (static_cast<Int_t>(fTDCAlignmentErrorPositions.size()) != fTdcWordCorrectionCnt) + std::cout << "Missing Correction" << std::endl; + + // if (fTDCAlignmentErrorPositions.size() > 0){ + // std::cout<<"Offset : "<<offset-4<<" Size:"<< size <<std::endl; + // std::cout<<"END of Hub : "<<mRichSupport::GetWordHexRepr(ptr+offset-4)<<std::endl; // Last word, processed as TDCWord + // std::cout<<"END of Hub +1 : "<<mRichSupport::GetWordHexRepr(ptr+offset+0)<<std::endl; + // std::cout<<"END of Hub +2 : "<<mRichSupport::GetWordHexRepr(ptr+offset+4)<<std::endl; + // std::cout<<"END of Hub +3 : "<<mRichSupport::GetWordHexRepr(ptr+offset+8)<<std::endl; + // } + + ////LOG(debug4) << "Done processing TRB subevent. offset-4=" << offset-4 << "\tsize=" << size; + if (size != static_cast<size_t>(offset - 4)) { + LOG(WARN) << "CbmMcbm2018UnpackerAlgoRich2020::ProcessTRBsubevent() warning:" + << "Number of processed bytes is not equal to the expected size. " + "This should not happen. (" + << size << " VS " << (offset - 4) << ")" + << " Correction: " << fTdcWordCorrectionCnt * 2 << " fLastFeeOnHub:" << fLastFeeOnHub; + + /// Probably corrupted MS, stop there and skip remaining data + //fSkipMs = kTRUE; + } + + fTdcWordCorrectionGlobalCnt += fTdcWordCorrectionCnt; + + return size; //TODO check +} + +Int_t CbmMcbm2018UnpackerAlgoRich2020::ProcessTRBsubsubevent(size_t const size, uint8_t const* const ptr, + Int_t const hubOffset, size_t const hubSize) +{ //size: Size of Data from DiRICH in Bytes + ////LOG(debug4) << "ProcessTRBsubsubevent size=" << size << " bytes"; + Int_t offset = 0; // offset in bytes + fCurEpochCounter = 0; //TODO check + fInSubSubEvent = kFALSE; //TODO check + fTrbState = TrbNetState::IDLE; + Int_t TdcWordCorrection_local = 0; + Int_t WordCnt = 0; + bool break_flag = false; + + for (size_t iWord = 0; iWord < size / 4; iWord++) { // iWord is size in Lines + //correct for misalignment + //hubOffset is pointing to first word after DiRICH address + if (fTDCAlignmentErrorPositions.size() > static_cast<unsigned int>(fTdcWordCorrectionCnt) + && fTDCAlignmentErrorPositions[fTdcWordCorrectionCnt] == static_cast<Int_t>(hubOffset + offset + iWord * 4)) { + //BEGIN DEBUG + // std::cout<<"DEBUG -1: "<< mRichSupport::GetWordHexRepr(ptr-hubOffset+fTDCAlignmentErrorPositions[fTdcWordCorrectionCnt]-4) << std::endl; + // std::cout<<"DEBUG 0: "<< mRichSupport::GetWordHexRepr(ptr-hubOffset+fTDCAlignmentErrorPositions[fTdcWordCorrectionCnt]) << std::endl; + // std::cout<<"DEBUG +1: "<< mRichSupport::GetWordHexRepr(ptr-hubOffset+fTDCAlignmentErrorPositions[fTdcWordCorrectionCnt]+4) << std::endl; + // std::cout<<"DEBUG_ : "<< mRichSupport::GetWordHexRepr(ptr+iWord*4+offset) << std::endl; + // + // std::cout<<"Correction in DiRICH Header: "<< fTDCAlignmentErrorPositions[fTdcWordCorrectionCnt]<<std::endl; + + //END DEBUG + offset += 2; + fTdcWordCorrectionCnt++; + TdcWordCorrection_local++; + // repeat word + iWord--; + continue; + } + if (fSkipMs == kTRUE) break; + + + //if (fTDCAlignmentErrorPositions.size() > 0 && fLastFeeOnHub) std::cout<<"Final Word: "<< mRichSupport::GetWordHexRepr(ptr+iWord*4+offset)<<std::endl; + + ////////////////////////////// + if ((hubSize > 0) && (hubOffset + offset + iWord * 4 > hubSize)) { + //std::cout<<"BREAKING : "<<hubOffset+offset+iWord*4 <<" > "<< hubSize <<" | "<< offset << " | "<< fTdcWordCorrectionCnt <<std::endl; + break_flag = true; + break; + } + //if (isCTSWord) std::cout<<"TDCWORD: "<<mRichSupport::GetWordHexRepr(ptr+iWord*4+offset)<<std::endl; + + mRichSupport::SwapBytes(4, ptr + iWord * 4 + offset); + ProcessTDCword(ptr + iWord * 4 + offset, iWord, size); // + + WordCnt++; + + //std::cout<<" "<< iWord <<" "<< WordCnt <<std::endl; + } //END of for Loop + + // if (fTdcWordCorrectionCnt > 0){ + // std::cout<<"LAST Processed Word : "<<mRichSupport::GetWordHexRepr(ptr+(WordCnt-1)*4+offset)<<std::endl; + // } + //if (TdcWordCorrection_local != 0) printf(" --- TDC WORD FIX APPLIED ! --- [DiRICH : 0x%4x]\n",fSubSubEvId); + + if (fSkipMs == kTRUE) return 0; + + //TODO Implement checks that the first word was the header and the last word was the trailer + + //if (size != static_cast<size_t>((WordCnt)*4) && fTdcWordCorrectionCnt == 0) { + if (!((!break_flag && ((size) == static_cast<size_t>((WordCnt) *4))) + || (break_flag && ((size - (fTdcWordCorrectionCnt * 2)) == static_cast<size_t>((WordCnt) *4))))) { + LOG(WARN) << "CbmMcbm2018UnpackerAlgoRich2020::ProcessTRBsubsubevent() warning:" + << "Number of processed bytes is not equal to the expected size. " + "This should not happen." + << static_cast<size_t>(WordCnt * 4) << " " << size; + /// Probably corrupted MS, stop there and skip remaining data + //fSkipMs = kTRUE; + } + + + return (WordCnt * 4 + offset); //TODO check +} + +Int_t CbmMcbm2018UnpackerAlgoRich2020::ProcessTDCword(uint8_t const* const ptr, Int_t const word, size_t const size) +{ + // clang-format off + Int_t* tdcDataPtr = (Int_t*) ptr; + Int_t tdcData = tdcDataPtr[0]; + Int_t tdcTimeDataMarker = (tdcData >> 31) & 0x1; // 1 bit + // clang-format on + + bool errorInData = false; + + // A TDC Time i only valid after a EPOCH or another TDC value + if ((tdcTimeDataMarker == 0x1 && fTrbState == TrbNetState::TDC) + || (tdcTimeDataMarker == 0x1 && fTrbState == TrbNetState::EPOCH)) { + UInt_t tdcMarker = (tdcData >> 29) & 0x7; // 3 bits + if (tdcMarker == 0x4 || tdcMarker == 0x5) { + fDebugPrint = 0; + //////////////////////////////// + ProcessTimestampWord(tdcData); // + //////////////////////////////// + fTrbState = TrbNetState::TDC; + } + else { + std::cout << "wrong TDC Word!!" << std::endl; + errorInData = true; + } + } + else { + UInt_t tdcMarker = (tdcData >> 29) & 0x7; // 3 bits + + if (tdcMarker == 0x0) { // TDC trailer + if (fInSubSubEvent) { + if (!(fTrbState == TrbNetState::HEADER || fTrbState == TrbNetState::EPOCH || fTrbState == TrbNetState::TDC)) { + LOG(error) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" + << "er" + << "\t" + << "ILLEGAL TRAILER Position"; + errorInData = true; + } + else if ((size / 4 - static_cast<size_t>(word)) > 1) { + //Trailer only at end of SubSubEvent! + LOG(error) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" + << "er" + << "\t" + << "Trailer only at end of SubSubEvent!" << size / 4 << " " << static_cast<size_t>(word); + errorInData = true; + } + else { + fTrbState = TrbNetState::TRAILER; + + LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" + << "ok" + << "\t" + << "TDC TRAILER"; + //extract TDC Trailer Error + uint16_t errorBits = (tdcData) &0xffff; //16 bits + ErrorMsg(errorBits, RichErrorType::tdcTrailer, fSubSubEvId); + fInSubSubEvent = kFALSE; // go out of InSubSubEvent state + //fGwordCnt++; + fDebugPrint = 0; + } + } + else { + LOG(info) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" + << "er" + << "\t" + << "UNKNOWN (TDC TRAILER not after header)"; + //fSkipMs = kTRUE; + errorInData = true; + //exit(EXIT_FAILURE); //TODO probably one should get rid of explicit EXIT calls not to ruin unpacking of other detectors? + } + } + else if (tdcMarker == 0x1) { // TDC header + // UInt_t randomCode = (tdcData >> 16) & 0xff; // 8 bits + // UInt_t errorBits = (tdcData) & 0xffff; //16 bits + if (!fInSubSubEvent) { + fInSubSubEvent = kTRUE; // go into InSubSubEvent state + + if (!(fTrbState == TrbNetState::IDLE || fTrbState == TrbNetState::TRAILER)) { + LOG(error) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" + << "er" + << "\t" + << "ILLEGAL HEADER Position"; + errorInData = true; + } + else if (!((((tdcData >> 8) & 0xFFFFFF) == 0x200096) || (((tdcData >> 8) & 0xFFFFFF) == 0x200095))) { + LOG(error) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" + << "er" + << "\t" + << "ILLEGAL HEADER Value"; + errorInData = true; + } + else { + fTrbState = TrbNetState::HEADER; + //extract TDC Header Error + uint8_t errorBits = (tdcData) &0xff; //8 bits + ErrorMsg(errorBits, RichErrorType::tdcHeader, fSubSubEvId); + LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" + << "ok" + << "\t" + << "TDC HEADER"; + } + //fGwordCnt++; + } + else { + LOG(info) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" + << "er" + << "\t" + << "UNKNOWN (TDC HEADER not after trailer)"; + errorInData = true; + //fGwordCnt++; + //fSkipMs = kTRUE; + //exit(EXIT_FAILURE); //TODO probably one should get rid of explicit EXIT calls not to ruin unpacking of other detectors? + } + } + else if (tdcMarker == 0x2) { // DEBUG + // UInt_t debugMode = (tdcData >> 24) & 0x1f; // 5 bits + // UInt_t debugBits = (tdcData) & 0xffffff; // 24 bits + //fTrbState = TrbNetState::DEBUG; + LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" + << "ok" + << "\t" + << "DEBUG"; + LOG(info) << "DEBUG VALUE [" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr); + errorInData = true; + //fGwordCnt++; + // currently no actions if a DEBUG message is encountered. + } + else if (tdcMarker == 0x3) { // EPOCH counter + if (!(fTrbState == TrbNetState::HEADER || fTrbState == TrbNetState::TDC || fTrbState == TrbNetState::EPOCH)) { + LOG(error) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" + << "er" + << "\t" + << "ILLEGAL EPOCH Position!"; + errorInData = true; + } + else if (((tdcData >> 28) & 0xF) != 0x6) { //EPOCH is always 0x6.... + LOG(error) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" + << "er" + << "\t" + << "ILLEGAL EPOCH value :"; + errorInData = true; + } + else { + fTrbState = TrbNetState::EPOCH; + fDebugPrint = 0; + fCurEpochCounter = (tdcData) &0xfffffff; // 28 bits + LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" + << "ok" + << "\t" + << "EPOCH\t" << fCurEpochCounter; + //fGwordCnt++; + } + } + else { + if (tdcTimeDataMarker != 0x1) { + LOG(error) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr(ptr) << "\t" + << "er" + << "\t" + << "UNKNOWN"; + errorInData = true; + } + } + } + + if (errorInData) { + //Handle error + fSkipMs = kTRUE; + fSkipCnt++; + LOG(error) << " >>> Skipping MicroTS due to error in data! <<<"; + } + + + return 0; //correction; +} + +void CbmMcbm2018UnpackerAlgoRich2020::ProcessTimestampWord(Int_t tdcData) +{ + Int_t channel = (tdcData >> 22) & 0x7f; // 7 bits + Int_t fine = (tdcData >> 12) & 0x3ff; // 10 bits + Int_t edge = (tdcData >> 11) & 0x1; // 1 bit + Int_t coarse = (tdcData) &0x7ff; // 11 bits + Int_t epoch = fCurEpochCounter; + + //TODO move full time calculation outside + // clang-format off + Double_t fullTime = (Double_t) epoch * 2048. * 5. + (Double_t) (coarse) *5. - (Double_t) (fine) *0.005; + // clang-format on + + LOG(debug4) << "[" << fGwordCnt << "]\t" << mRichSupport::GetWordHexRepr((uint8_t*) &tdcData) << "\t" + << "ok" + << "\t" + << "TIMESTAMP" + << "\t" + << "ch=" << channel << "\t" + << "edge=" << edge << "\t" + << "epoch=" << epoch << "\t" + << "coarse=" << coarse << "\t" + << "fine=" << fine << "\t" + << "full=" << fullTime; + //fGwordCnt++; + + // Storing reference times + // ======================= + + ////LOG(debug4) << "fSubSubEvId=0x" << std::hex << fSubSubEvId << std::dec; + Int_t idx = fUnpackPar->GetAddressIdx(fSubSubEvId); + if (-1 == idx) { + /// Probably corrupted MS, stop there and skip remaining data + fSkipMs = kTRUE; + return; + } + ////LOG(debug4) << "fSubSubEvId=0x" << std::hex << fSubSubEvId << std::dec << " idx=" << idx; + + if ((fSubSubEvId == 0xc000) || (fSubSubEvId == 0xc001)) { + // if CTS + if ((channel == 0) && (edge == RISINGEDGEID)) { + fPrevLastCTSch0_re_time = fLastCTSch0_re_time; + fLastCTSch0_re_time = fullTime; + ////LOG(debug4) << "Storing full time for the CTS ch=0 edge=RISINGEDGEID"; + } + else if ((channel == 2) && (edge == RISINGEDGEID)) { + fPrevLastCTSch2_re_time = fLastCTSch2_re_time; + fLastCTSch2_re_time = fullTime; + ////LOG(debug4) << "Storing full time for the CTS ch=2 edge=RISINGEDGEID"; + } + else if ((channel == 2) && (edge == FALLINGEDGEID)) { + fPrevLastCTSch2_fe_time = fLastCTSch2_fe_time; + fLastCTSch2_fe_time = fullTime; + ////LOG(debug4) << "Storing full time for the CTS ch=2 edge=FALLINGEDGEID"; + } + } + else { + // if not CTS (which means TRB) + if ((channel == 0) && (edge == RISINGEDGEID)) { + fPrevLastCh0_re_time[idx] = fLastCh0_re_time[idx]; + fLastCh0_re_time[idx] = fullTime; + ////LOG(debug4) << "Storing full time for TDC 0x" << std::hex << fSubSubEvId << std::dec << " ch=0 edge=RISINGEDGEID"; + } + } + + // Calculation of corrected time + // ============================= + Double_t fullTimeCorr = 0.; + if (!((fSubSubEvId == 0xc000) || (fSubSubEvId == 0xc001))) { + if (channel != 0) { + Double_t dT = fullTime - fPrevLastCh0_re_time[idx]; + Double_t corr = fPrevLastCTSch2_re_time - fPrevLastCTSch0_re_time; + fullTimeCorr = dT - corr; + } + } + + // Filling histograms + // ================== + if (fbMonitorMode == kTRUE) { + if (!((fSubSubEvId == 0xc000) || (fSubSubEvId == 0xc001))) { + // if not CTS (which means TRB) + if ((channel == 0) && (edge == RISINGEDGEID)) { + /* Double_t dT1 = fullTime - fLastCTSch0_re_time; + Double_t dT2 = fullTime - fLastCTSch2_re_time; + Double_t dT3 = fullTime - fLastCTSch2_fe_time; + fhTDCch0re_minusCTSch0re->Fill(idx, dT1); + fhTDCch0re_minusCTSch2re->Fill(idx, dT2); + fhTDCch0re_minusCTSch2fe->Fill(idx, dT3); + + Double_t dT4 = fullTime - fPrevLastCTSch0_re_time; + Double_t dT5 = fullTime - fPrevLastCTSch2_re_time; + Double_t dT6 = fullTime - fPrevLastCTSch2_fe_time; + fhTDCch0re_minusPrevCTSch0re->Fill(idx, dT4); + fhTDCch0re_minusPrevCTSch2re->Fill(idx, dT5); + fhTDCch0re_minusPrevCTSch2fe->Fill(idx, dT6); + + LOG(debug4) << "dT1=" << dT1 << "\tdT2=" << dT2 << "\tdT3=" << dT3 + << "\tdT4=" << dT4 << "\tdT5=" << dT5 << "\tdT6=" << dT6; +*/ + } + + if ((channel != 0) && (edge == RISINGEDGEID)) { + /*Double_t dT7 = fullTime - fLastCh0_re_time[idx]; + TH2D* h1 = fhTDCre_minusTDCch0re.at(idx); + h1->Fill(channel, dT7);*/ + + Double_t dT8 = fullTime - fPrevLastCh0_re_time[idx]; + /*TH2D* h2 = fhTDCre_minusPrevTDCch0re.at(idx); + h2->Fill(channel, dT8);*/ + + Double_t corr1 = fPrevLastCTSch2_re_time - fPrevLastCTSch0_re_time; + Double_t correctedT1 = dT8 + corr1; + Double_t correctedT2 = dT8 - corr1; + /* +// TH2D* h3 = fhTDCre_corrected1.at(idx); +// h3->Fill(channel, correctedT1); +// TH2D* h4 = fhTDCre_corrected2.at(idx); +// h4->Fill(channel, correctedT2); +*/ + LOG(debug4) + /*<< "dT7=" << dT7*/ << "\tdT8=" << dT8 << "\tcorr1=" << corr1 << "\tcorrectedT1=" << correctedT1 + << "\tcorrectedT2=" << correctedT2; + } + } + } + + if (edge == RISINGEDGEID) { this->ProcessRisingEdge(fSubSubEvId, channel, fullTimeCorr); } + else { + this->ProcessFallingEdge(fSubSubEvId, channel, fullTimeCorr); + } + + fChnlMsgCnt.at(channel)++; + if (fTrbState == TrbNetState::EPOCH) fChnlMsgCnt.at(channel)++; // If there was a correp. EPOCH before +} + +void CbmMcbm2018UnpackerAlgoRich2020::ProcessRisingEdge(Int_t subSubEvId, Int_t channel, Double_t time) +{ + ////LOG(debug4) << "CbmMcbm2018UnpackerAlgoRich2020::ProcessRisingEdge()"; + + //TODO: not a very nice hack. + // All messages from ch0 are skipped. Though, probably, that is corect. + if (channel == 0) return; + + // Also skip everything from CST + if ((subSubEvId == 0xc000) || (subSubEvId == 0xc001)) return; + + fRisingEdgesBuf.push_back(CbmMcbmRichEdge(subSubEvId, channel, time)); +} + +void CbmMcbm2018UnpackerAlgoRich2020::ProcessFallingEdge(Int_t subSubEvId, Int_t channel, Double_t time) +{ + ////LOG(debug4) << "CbmMcbm2018UnpackerAlgoRich2020::ProcessFallingEdge()"; + + // Skip everything from CST + if ((subSubEvId == 0xc000) || (subSubEvId == 0xc001)) return; + + Bool_t reFound = kFALSE; + + std::vector<CbmMcbmRichEdge>::iterator reIter = fRisingEdgesBuf.begin(); + + while (reIter != fRisingEdgesBuf.end()) { + if (((*reIter).fSubSubEventID == subSubEvId) && ((*reIter).fChannel == channel)) { + Double_t reTime = (*reIter).fTime; + // Found corresponding rising edge + Double_t ToT = time - reTime; + + if ((ToT >= TOTMIN) && (ToT <= TOTMAX)) { + // Time-over-threshold is within allowed range + + reFound = kTRUE; + + LOG(debug4) << "Found pair for FPGA ID 0x" << std::hex << subSubEvId << std::dec << "\tch=" << channel + << "\tToT=" << ToT; + + //TODO implement + // Writing output digi + ////////////////////////////////////////////////// + if (fbMonitorMode) { + TH1D* h = GetTotH1(subSubEvId, channel); + if (h != nullptr) h->Fill(ToT); + + TH2D* h2 = GetTotH2(subSubEvId); + if (h2 != nullptr) h2->Fill(channel, ToT); + } + WriteOutputDigi(subSubEvId, channel, reTime, ToT, fCurMSidx); // + ////////////////////////////////////////////////// + + reIter = fRisingEdgesBuf.erase(reIter); + continue; // Take care. This has to be the last operation in this block + } + else { + //TODO: exception. By now we can just do nothing + } + } // end of if condition + + // This construction is a little bit tricky. + // The iterator is either incremented here or (if a pair was found) + // incremented using erase call, followed by the continue. + ++reIter; + } // end of for loop + + if (reFound == kFALSE) { + // Corresponding rising edge not found - store the falling edge in the bufer + fFallingEdgesBuf.push_back(CbmMcbmRichEdge(subSubEvId, channel, time)); + } +} + +void CbmMcbm2018UnpackerAlgoRich2020::WriteOutputDigi(Int_t fpgaID, Int_t channel, Double_t time, Double_t tot, + uint64_t MSidx) +{ + Double_t ToTcorr = fbDoToTCorr ? fUnpackPar->GetToTshift(fpgaID, channel) : 0.; + Int_t pixelUID = this->GetPixelUID(fpgaID, channel); + //check ordering + Double_t finalTime = time + (Double_t) MSidx - fdTimeOffsetNs; + + Double_t lastTime = 0.; + + if (fDigiVect.size() < 1) { fDigiVect.emplace_back(pixelUID, finalTime, tot - ToTcorr); } + else { + lastTime = fDigiVect[fDigiVect.size() - 1].GetTime(); + if (lastTime > finalTime) { + for (int i = fDigiVect.size() - 1; i >= 0; i--) { + lastTime = fDigiVect[i].GetTime(); + if (lastTime <= finalTime) { + // LOG(info) << " before:"<< fDigiVect.size(); + fDigiVect.emplace(fDigiVect.begin() + i + 1, pixelUID, finalTime, tot - ToTcorr); + // LOG(info) << fDigiVect.size(); + break; + } + } + } + else { + fDigiVect.emplace_back(pixelUID, finalTime, tot - ToTcorr); + } + } + LOG(debug4) << "CbmMcbm2018UnpackerAlgoRich2020::WriteOutputDigi fDigiVect.size=" << fDigiVect.size(); +} + +void CbmMcbm2018UnpackerAlgoRich2020::FinalizeTs() +{ + // for (int i = 0; i < fDigiVect.size();++i) { + // LOG(info) << "CbmMcbm2018UnpackerAlgoRich2020::Final Vector: " + // << i+1 <<"/"<<fDigiVect.size() + // << "\t" << std::setprecision(15)<< fDigiVect[i].GetTime(); + // + // + // } + LOG(debug4) << "CbmMcbm2018UnpackerAlgoRich2020::FinalizeTs: " << fRisingEdgesBuf.size() + << " entries in fRisingEdgesBuf" + << "\t" << fFallingEdgesBuf.size() << " entries in fFallingEdgesBuf"; + + // Clear rising edges buffer + LOG(debug4) << "Rising edges: " + "----------------------------------------------------------"; + std::vector<CbmMcbmRichEdge>::iterator reIter = fRisingEdgesBuf.begin(); + while (reIter != fRisingEdgesBuf.end()) { + LOG(debug4) << "FPGA=0x" << std::hex << (*reIter).fSubSubEventID << std::dec << "\tch=" << (*reIter).fChannel; + ++reIter; + } + fRisingEdgesBuf.clear(); + + // Clear falling edges buffer + LOG(debug4) << "Falling edges: " + "---------------------------------------------------------"; + std::vector<CbmMcbmRichEdge>::iterator feIter = fFallingEdgesBuf.begin(); + while (feIter != fFallingEdgesBuf.end()) { + LOG(debug4) << "FPGA=0x" << std::hex << (*feIter).fSubSubEventID << std::dec << "\tch=" << (*feIter).fChannel; + ++feIter; + } + fFallingEdgesBuf.clear(); + + LOG(debug4) << "---------------------------------------------------------"; +} + +Bool_t CbmMcbm2018UnpackerAlgoRich2020::CreateHistograms() +{ + Int_t nTDCs = fUnpackPar->GetNaddresses(); + // std::vector<TCanvas*> fcToT2d; + /* + fhTDCch0re_minusCTSch0re = new TH2D("fhTDCch0re_minusCTSch0re", "TDC ch0 re - CTS ch0 re;TDC index;ns", nTDCs, 0, nTDCs, 1000, -500., 500.); + fhTDCch0re_minusCTSch2re = new TH2D("fhTDCch0re_minusCTSch2re", "TDC ch0 re - CTS ch2 re;TDC index;ns", nTDCs, 0, nTDCs, 1000, -500., 500.); + fhTDCch0re_minusCTSch2fe = new TH2D("fhTDCch0re_minusCTSch2fe", "TDC ch0 re - CTS ch2 fe;TDC index;ns", nTDCs, 0, nTDCs, 1000, -500., 500.); + + AddHistoToVector(fhTDCch0re_minusCTSch0re, ""); + AddHistoToVector(fhTDCch0re_minusCTSch2re, ""); + AddHistoToVector(fhTDCch0re_minusCTSch2fe, ""); + + fhTDCch0re_minusPrevCTSch0re = new TH2D("fhTDCch0re_minusPrevCTSch0re", "TDC ch0 re - prev CTS ch0 re;TDC index;ns", nTDCs, 0, nTDCs, 1000, -500., 500.); + fhTDCch0re_minusPrevCTSch2re = new TH2D("fhTDCch0re_minusPrevCTSch2re", "TDC ch0 re - prev CTS ch2 re;TDC index;ns", nTDCs, 0, nTDCs, 1000, -500., 500.); + fhTDCch0re_minusPrevCTSch2fe = new TH2D("fhTDCch0re_minusPrevCTSch2fe", "TDC ch0 re - prev CTS ch2 fe;TDC index;ns", nTDCs, 0, nTDCs, 1000, -500., 500.); + + AddHistoToVector(fhTDCch0re_minusPrevCTSch0re, ""); + AddHistoToVector(fhTDCch0re_minusPrevCTSch2re, ""); + AddHistoToVector(fhTDCch0re_minusPrevCTSch2fe, ""); +*/ + + fhTdcErrors = new TH2D("fhTdcErrors", "Errors in TDC msgs;;", nTDCs, -0.5, nTDCs - 0.5, 9, -0.5, 8.5); + fhTdcErrors->GetYaxis()->SetBinLabel(1, "RingBuffOverw."); + fhTdcErrors->GetYaxis()->SetBinLabel(2, "noRefTime"); + fhTdcErrors->GetYaxis()->SetBinLabel(3, "refTimePrecedes"); + fhTdcErrors->GetYaxis()->SetBinLabel(4, "trigW/oRefTime"); + fhTdcErrors->GetYaxis()->SetBinLabel(5, "markMisRefTime"); + fhTdcErrors->GetYaxis()->SetBinLabel(6, "multiRefTime"); + fhTdcErrors->GetYaxis()->SetBinLabel(7, "refTime<40ns"); + fhTdcErrors->GetYaxis()->SetBinLabel(8, "noValidation"); + fhTdcErrors->GetYaxis()->SetBinLabel(9, "trigger!=0x1"); + fhTdcErrors->GetXaxis()->LabelsOption("v"); + fhTdcErrors->GetYaxis()->SetTickSize(0.0); + fhTdcErrors->GetXaxis()->SetTickSize(0.0); + //fhTdcErrors->SetGrid(); + + fhEventErrors = new TH2D("fhEventErrors", "Errors in Event/mts msgs;;", 1, -0.5, 0.5, 13, -0.5, 12.5); + fhEventErrors->GetYaxis()->SetBinLabel(1, "UDPProblem"); + fhEventErrors->GetYaxis()->SetBinLabel(2, "evNumMism"); + fhEventErrors->GetYaxis()->SetBinLabel(3, "trigMism"); + fhEventErrors->GetYaxis()->SetBinLabel(4, "wrongLength"); + fhEventErrors->GetYaxis()->SetBinLabel(5, "answMissing"); + fhEventErrors->GetYaxis()->SetBinLabel(6, "evRequFail"); + fhEventErrors->GetYaxis()->SetBinLabel(7, "evPartFound"); + fhEventErrors->GetYaxis()->SetBinLabel(8, "sevBuffProb"); + fhEventErrors->GetYaxis()->SetBinLabel(9, "brokenEv"); + fhEventErrors->GetYaxis()->SetBinLabel(10, "ethLinkDwn"); + fhEventErrors->GetYaxis()->SetBinLabel(11, "subEvBuffAlmFull"); + fhEventErrors->GetYaxis()->SetBinLabel(12, "eth/BufProb"); + fhEventErrors->GetYaxis()->SetBinLabel(13, "timingTrigErr"); + fhEventErrors->GetXaxis()->LabelsOption("v"); + fhEventErrors->GetXaxis()->SetTickSize(0.0); + fhEventErrors->GetYaxis()->SetTickSize(0.0); + + for (Int_t iTDC = 0; iTDC < nTDCs; iTDC++) { + TString histoName; + TString histoTitle; + TString subFolder; + + Int_t Addr = fUnpackPar->GetAddress(iTDC); + fMapFEE[Addr] = iTDC; + fhTdcErrors->GetXaxis()->SetBinLabel(iTDC + 1, Form("0x%4x", Addr)); + /* + histoName.Form("fhTDC%dre_minusTDC%dch0re", iTDC, iTDC); + histoTitle.Form("TDC %d re - TDC %d ch0 re;channel;ns", iTDC, iTDC); + TH2D* h1 = new TH2D(histoName, histoTitle, 32, 0., 32., 1200, 0., 600.); + fhTDCre_minusTDCch0re.push_back(h1); + AddHistoToVector(h1); + + histoName.Form("fhTDC%dre_minusPrevTDC%dch0re", iTDC, iTDC); + histoTitle.Form("TDC %d re - prev. TDC %d ch0 re;channel;ns", iTDC, iTDC); + TH2D* h2 = new TH2D(histoName, histoTitle, 32, 0., 32., 1200, 0., 600.); + fhTDCre_minusPrevTDCch0re.push_back(h2); + AddHistoToVector(h2); +*/ + /* histoName.Form("fhTDC%dre_corrected1", iTDC); + histoTitle.Form("TDC %d re corrected1;channel;ns", iTDC); + TH2D* h3 = new TH2D(histoName, histoTitle, 32, 0., 32., 1200, 0., 600.); + fhTDCre_corrected1.push_back(h3); + AddHistoToVector(h3); + + histoName.Form("fhTDC%dre_corrected2", iTDC); + histoTitle.Form("TDC %d re corrected2;channel;ns", iTDC); + TH2D* h4 = new TH2D(histoName, histoTitle, 32, 0., 32., 1200, 0., 600.); + fhTDCre_corrected2.push_back(h4); + AddHistoToVector(h4); +*/ + // TODO + //workaround we need to init all histograms for ToT here. Otherwise they will not be added to monitoring. + for (Int_t iCh = 0; iCh <= 32; iCh++) { + Int_t tdc = fUnpackPar->GetAddress(iTDC); + GetTotH1(tdc, iCh); + } + { + Int_t tdc = fUnpackPar->GetAddress(iTDC); + GetTotH2(tdc); + } + + /*******************************************************************/ + + /// Map of hits over T0 detector and same vs time in run + { //if (iTDC == 0){ + Double_t w = 10; + Double_t h = 10; + + TCanvas* c; + TString canvasName; + TString canvasTitle; + Int_t tdc = fUnpackPar->GetAddress(iTDC); + canvasName.Form("cToT2d_TDC_0x%4x", tdc); + canvasTitle.Form("ToTs of TDC 0x%4x", tdc); + c = new TCanvas(canvasName, canvasTitle, w, h); + // fcHitMaps->Divide( 2 ); + // fcHitMaps->cd( 1 ); + // gPad->SetGridx(); + // gPad->SetGridy(); + // gPad->SetLogy(); + // fhChannelMap->Draw(); + // fcHitMaps->cd( 2 ); + // gPad->SetGridx(); + // gPad->SetGridy(); + // gPad->SetLogz(); + TH2D* h2 = GetTotH2(tdc); + h2->Draw("colz"); + fcTot2d.push_back(c); + AddCanvasToVector(c, "ToT_Canvases"); + } + /*******************************************************************/ + } + + + AddHistoToVector(fhTdcErrors, ""); + AddHistoToVector(fhEventErrors, ""); + + fhVectorSize = new TH1I("fhVectorSize", "Size of the vector VS TS index; TS index; Size [bytes]", 10000, 0., 10000.); + fhVectorCapacity = + new TH1I("fhVectorCapacity", "Size of the vector VS TS index; TS index; Size [bytes]", 10000, 0., 10000.); + AddHistoToVector(fhVectorSize, ""); + AddHistoToVector(fhVectorCapacity, ""); + + if (fbDebugMonitorMode) { + fhEventSize = new TH1I("fhEventSize", "Size of the Event from TrbNet; Size [bytes]", 350, 0., 70000.); + AddHistoToVector(fhEventSize, ""); + + fhSubEventSize = + new TH2I("fhSubEventSize", "fhSubEventSize; HubId ; Size [bytes]; Entries", 6, 0, 6, 10000, 0., 10000.); + AddHistoToVector(fhSubEventSize, ""); + + fhSubSubEventSize = + new TH2I("fhSubSubEventSize", "fhSubSubEventSize; DiRICH ; Size [words]; Entries", 72, 0, 72, 510, 0., 510.); + AddHistoToVector(fhSubSubEventSize, ""); + + fhChnlSize = new TH2I("fhChnlSize", "fhChnlSize; channel; Size [words]; Entries", 33, 0, 33, 25, 0, 25.); + AddHistoToVector(fhChnlSize, ""); + } + + return kTRUE; +} + +TH1D* CbmMcbm2018UnpackerAlgoRich2020::GetTotH1(Int_t tdc, Int_t channel) +{ + TH1D* h = fhTotMap[tdc][channel]; + if (h == nullptr) { + TString name, title, subFolder; + name.Form("ToT_tdc0x%x_ch%u", tdc, channel); + title.Form("%s;ToT [ns];Entries", name.Data()); + subFolder.Form("ToT/tdc0x%x", tdc); + h = new TH1D(name, title, 100, -1., 49.); + AddHistoToVector(h, std::string(subFolder.Data())); + fhTotMap[tdc][channel] = h; + } + return h; +} + +TH2D* CbmMcbm2018UnpackerAlgoRich2020::GetTotH2(Int_t tdc) +{ + TH2D* h = fhTot2dMap[tdc]; + if (h == nullptr) { + TString name, title, subFolder; + name.Form("ToT_2d_tdc0x%x", tdc); + title.Form("%s;channels;ToT [ns]", name.Data()); + subFolder.Form("ToT2d"); + h = new TH2D(name, title, 33, 0, 32, 200, -1., 49.); + AddHistoToVector(h, std::string(subFolder.Data())); + fhTot2dMap[tdc] = h; + } + return h; +} + +Bool_t CbmMcbm2018UnpackerAlgoRich2020::DebugMs(const fles::Timeslice& ts, size_t uMsCompIdx, size_t uMsIdx) +{ + const fles::MicrosliceView mv = ts.get_microslice(uMsCompIdx, uMsIdx); + const fles::MicrosliceDescriptor& msDesc = mv.desc(); + const uint8_t* ptr = mv.content(); + const size_t size = msDesc.size; + + if (size == 0) return kTRUE; + Debug(ptr, size); + + return kTRUE; +} + +Int_t CbmMcbm2018UnpackerAlgoRich2020::Debug(const uint8_t* ptr, const size_t size) +{ + + if (size == 0) return size; + + //LOG(info)<<"DEBUG MODE IS ACTIVE; Printing raw data:"; + + uint8_t nblCnt = 0; + uint8_t wrdCnt = 0; + std::cout << std::endl << "SIZE: " << std::dec << size << "Byte" << std::endl; + for (size_t i = 0; i < size; ++i) { + + //if (wrdCnt == 0) std::cout<<"HEX: "; + uint8_t* tdcDataPtr = (uint8_t*) (ptr + i); + + if (wrdCnt == 0 && nblCnt == 0) { printf("%08d : ", static_cast<int>(i)); } + + printf("%02x", unsigned(*tdcDataPtr)); + nblCnt++; + if (nblCnt % 2 == 0) { printf(" "); } + if (nblCnt % 4 == 0) { + printf(" "); + wrdCnt++; + nblCnt = 0; + } + + if (wrdCnt == 10) { + printf("\n"); + wrdCnt = 0; + } + } + printf("\n"); + return size; +} + + +void CbmMcbm2018UnpackerAlgoRich2020::ErrorMsg(uint16_t errbits, RichErrorType type, uint16_t tdcAddr) +{ + if (fbMonitorMode) { + switch (type) { + case RichErrorType::mtsError: + //UDP problem + if ((errbits & 0x1) == 1) fhEventErrors->Fill(0.0, 0.0); + + break; + + case RichErrorType::tdcHeader: + // min. 1 rinǵ buffer overwritten + if ((errbits & 0x1) == 1) fhTdcErrors->Fill(fMapFEE[tdcAddr], 0.0); + + break; + + case RichErrorType::tdcTrailer: + // no reference time in trigger handler in TDC + if (((errbits >> 0) & 0x1) == 1) fhTdcErrors->Fill(fMapFEE[tdcAddr], 1.0); + + // reference time precedes a non-timing trigger + if (((errbits >> 1) & 0x1) == 1) fhTdcErrors->Fill(fMapFEE[tdcAddr], 2.0); + + // timing trigger is delivered without a reference time + if (((errbits >> 2) & 0x1) == 1) fhTdcErrors->Fill(fMapFEE[tdcAddr], 3.0); + + // Set with the bit 2 to mark the missing reference time + if (((errbits >> 3) & 0x1) == 1) fhTdcErrors->Fill(fMapFEE[tdcAddr], 4.0); + + // there are more than one detected reference time + if (((errbits >> 4) & 0x1) == 1) fhTdcErrors->Fill(fMapFEE[tdcAddr], 5.0); + + // reference time was too short (<40 ns) + if (((errbits >> 5) & 0x1) == 1) fhTdcErrors->Fill(fMapFEE[tdcAddr], 6.0); + + // no trigger validation arrives from the endpoint after a valid reference time + if (((errbits >> 6) & 0x1) == 1) fhTdcErrors->Fill(fMapFEE[tdcAddr], 7.0); + + // any timing trigger type except 0x1 is send + if (((errbits >> 7) & 0x1) == 1) fhTdcErrors->Fill(fMapFEE[tdcAddr], 8.0); + + break; + + case RichErrorType::ctsHeader: + // To be implemented + break; + + case RichErrorType::ctsTrailer: + // To be implemented + break; + + case RichErrorType::subEventError: + // event number mismatch + if (((errbits >> 0) & 0x1) == 1) fhEventErrors->Fill(0.0, 1.0); + + // trigger code mismatch + if (((errbits >> 1) & 0x1) == 1) fhEventErrors->Fill(0.0, 2.0); + + // wrong length + if (((errbits >> 2) & 0x1) == 1) fhEventErrors->Fill(0.0, 3.0); + + // answer missing + if (((errbits >> 3) & 0x1) == 1) fhEventErrors->Fill(0.0, 4.0); + + // event number request by CTS was not available (Not found) + if (((errbits >> 4) & 0x1) == 1) fhEventErrors->Fill(0.0, 5.0); + + // event partially found in data buffer + if (((errbits >> 5) & 0x1) == 1) fhEventErrors->Fill(0.0, 6.0); + + // Severe Problem with data buffer and/or read-out + if (((errbits >> 6) & 0x1) == 1) fhEventErrors->Fill(0.0, 7.0); + + // Single broken event + if (((errbits >> 7) & 0x1) == 1) fhEventErrors->Fill(0.0, 8.0); + + // Ethernet Link down + if (((errbits >> 8) & 0x1) == 1) fhEventErrors->Fill(0.0, 9.0); + + // SubEvent buffer almost full + if (((errbits >> 9) & 0x1) == 1) fhEventErrors->Fill(0.0, 10.0); + + // Ethernet/SubEventBuilder error + if (((errbits >> 10) & 0x1) == 1) fhEventErrors->Fill(0.0, 11.0); + + // Timing trigger error + if (((errbits >> 11) & 0x1) == 1) fhEventErrors->Fill(0.0, 12.0); + + break; + + default: break; + } + } +} + +/* +Bool_t CbmMcbm2018UnpackerAlgoRich2020::FillHistograms() +{ + return kTRUE; +} +*/ +Bool_t CbmMcbm2018UnpackerAlgoRich2020::ResetHistograms() +{ + //TODO: do something? + return kTRUE; +} + +void CbmMcbm2018UnpackerAlgoRich2020::findTDCAlignmentError(uint8_t const* const ptr, size_t const size) +{ + + fTDCAlignmentErrorPositions.clear(); + + // mRichSupport::SwapBytes(4, ptr+size); + // if((((((Int_t*)(ptr+size))[0]) >> 28) & 0xF) != 0x0) { + // LOG(WARN) << "CbmMcbm2018UnpackerAlgoRich2020::ProcessTRBsubevent() warning:" + // << "End on Hub is not where expected. Is it a Buffer overflow? LastWord: "<<mRichSupport::GetWordHexRepr(ptr+size); + // } + // mRichSupport::SwapBytes(4, ptr+size); + + /*** + * Signature of Error: + * 82b7 8ca6 + * 8297 *34ad* + * *34ad* 66af // data Ptr + * *cf8b* *cf8b* + * 82c8 cca9 + */ + + //start at 8 to skip header of Hub and first row as this has to be checked + //stop at size -4 to avoid comparing with following hub + + for (Int_t i = 8; i < static_cast<Int_t>(size - 4); i += 4) { // i represents bytes (4 per line) + //TODO: Optimize the swaping + mRichSupport::SwapBytes(4, ptr + i - 4); + mRichSupport::SwapBytes(4, ptr + i); + mRichSupport::SwapBytes(4, ptr + i + 4); + bool problem = false; + // clang-format off + if ((((Int_t*) (ptr + i - 4))[0] & 0xFFFF) == ((((Int_t*) (ptr + i))[0] >> 16) & 0xFFFF)) { + if ((((Int_t*) (ptr + i + 4))[0] & 0xFFFF) == ((((Int_t*) (ptr + i + 4))[0] >> 16) & 0xFFFF)) { + //Signature of problem! + problem = true; + fTDCAlignmentErrorPositions.push_back(i); + fTDCAlignmentErrorPositions.push_back(i + 6); + } + } + // clang-format on + + mRichSupport::SwapBytes(4, ptr + i - 4); + mRichSupport::SwapBytes(4, ptr + i); + mRichSupport::SwapBytes(4, ptr + i + 4); + + if (problem) i += 8; //jump after the problem + } +} + +ClassImp(CbmMcbm2018UnpackerAlgoRich2020) diff --git a/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerAlgoRich2020.h b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerAlgoRich2020.h new file mode 100644 index 0000000000..de1446482c --- /dev/null +++ b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerAlgoRich2020.h @@ -0,0 +1,384 @@ +/* Copyright (C) 2019-2020 Justus-Liebig-Universitaet Giessen, Giessen + SPDX-License-Identifier: GPL-3.0-only + Authors: Egor Ovcharenko [committer] */ + +/** + * CbmMcbm2018UnpackerAlgoRich2020 + * E. Ovcharenko, Mar 2019 + * based on other detectors' classes by P.-A. Loizeau + */ + +#ifndef CbmMcbm2018UnpackerAlgoRich2020_H +#define CbmMcbm2018UnpackerAlgoRich2020_H + +#include "CbmStar2019Algo.h" // mother class + +// STD +#include <map> +#include <vector> + +// ROOT +#include <TArrayD.h> +#include <TH2D.h> + +// CbmRoot +#include "CbmMcbm2018UnpackerUtilRich2020.h" +#include "CbmRichDigi.h" + +////class TList; // not really needed, already declared in the mother class +class CbmMcbm2018RichPar; + +#define RISINGEDGEID 1 +#define FALLINGEDGEID 0 + +#define TOTMIN -20. +#define TOTMAX 100. + +enum class TrbNetState +{ + IDLE, + HEADER, + EPOCH, + TDC, + TRAILER, + CTS, + DEBUG +}; + +enum class RichErrorType +{ + mtsError, + tdcHeader, + tdcTrailer, + ctsHeader, + ctsTrailer, + subEventError +}; + +class CbmMcbm2018UnpackerAlgoRich2020 : public CbmStar2019Algo<CbmRichDigi> { +public: + CbmMcbm2018UnpackerAlgoRich2020(); + + virtual ~CbmMcbm2018UnpackerAlgoRich2020(); + + virtual Bool_t Init(); + + virtual void Reset(); + + virtual void Finish(); + + virtual Bool_t InitContainers(); + + virtual Bool_t ReInitContainers(); + + virtual TList* GetParList(); + + Bool_t InitParameters(); + + /** + * Copied from other detectors without any brain effort... + */ + void AddMsComponentToList(size_t component, UShort_t usDetectorId); + + virtual Bool_t ProcessTs(const fles::Timeslice& ts); + + virtual Bool_t ProcessTs(const fles::Timeslice& ts, size_t component); + + virtual Bool_t ProcessMs(const fles::Timeslice& ts, size_t uMsCompIdx, size_t uMsIdx); + + Bool_t DebugMs(const fles::Timeslice& ts, size_t uMsCompIdx, size_t uMsIdx); + + void SetMonitorMode(Bool_t bFlagIn = kTRUE) { fbMonitorMode = bFlagIn; } + + inline void SetTimeOffsetNs(Double_t dOffsetIn = 0.0) { fdTimeOffsetNs = dOffsetIn; } + + inline void DoTotCorr(Bool_t bDoToTCorr = kTRUE) { fbDoToTCorr = bDoToTCorr; } + + void SetRawDataMode(Bool_t bDebug = kFALSE) { fRawDataMode = bDebug; } + + Int_t Debug(const uint8_t* ptr, const size_t size); + +private: + /** + * Initialize space required for monitoring. + * This depends on the parameters read from the par file. + * This method should be called once after parameters import. + */ + void InitStorage(); + + void ProcessMicroslice(size_t const size, uint8_t const* const ptr); + + /** + * Including header + */ + Int_t ProcessTRBevent(size_t const size, uint8_t const* const ptr); + + /** + * + */ + Int_t ProcessTRBeventHeader(size_t const size, uint8_t const* const ptr); + + /** + * Including header - ? + * Return number of processed bytes + */ + Int_t ProcessSKIPsubevent(size_t const size, uint8_t const* const ptr); + + Int_t ProcessCTSsubevent(size_t const size, uint8_t const* const ptr); + + Int_t ProcessTRBsubevent(size_t const size, uint8_t const* const ptr); + + /** + * Including TDC header, but not including TRB subsubevent header + * Return number of processed bytes + */ + Int_t ProcessTRBsubsubevent(size_t const size, uint8_t const* const ptr, Int_t const hubOffset, size_t const hubSize); + + /** + * Process a word written out by the TDC - TIMESTEMP, HEADER, TRAILER, DEBUG, EPOCH, ... + */ + Int_t ProcessTDCword(uint8_t const* const ptr, Int_t const word, size_t const size); + + /** + * Process specifically a TIMESTAMP type of word + */ + void ProcessTimestampWord(Int_t tdcData); + + /** + * Write a gidi object into the output collection + */ + void WriteOutputDigi(Int_t fpgaID, Int_t channel, Double_t time, Double_t tot, uint64_t MSidx); + + /** + * Method which is called at the end of the timeslice processing + */ + void FinalizeTs(); + + /** + * Write Errors to Histograms + */ + void ErrorMsg(uint16_t errbits, RichErrorType type, uint16_t tdcAddr = 0); + + Int_t GetPixelUID(Int_t fpgaID, Int_t ch) const + { + // First 16 bits are used for the FPGA ID, then + // 8 bits unused and then 8 bits are used for the channel + return ((fpgaID << 16) | (ch & 0x00FF)); + } + + void findTDCAlignmentError(uint8_t const* const ptr, size_t const size); + +private: // data members + /// Control flags + Bool_t fbMonitorMode; //! Switch ON the filling of a minimal set of histograms + + Bool_t fbDebugMonitorMode; //! Switch ON the filling of a additional set of histograms + + Bool_t fRawDataMode; + + Bool_t fError; //! flag for an error in the datastream + + TrbNetState fTrbState; // State of TrbNet (HEADER,TRAILER,...) + + uint32_t fErrorCorr; // Offset to correct a error in datastream + + /// User setting: kTRUE activates ToT correction from Parameterfile + Bool_t fbDoToTCorr; + + Bool_t fSkipMs; + /// User settings: Data correction parameters + Double_t fdTimeOffsetNs; + + size_t fDataSize = 0; + + + /** + * Bug fix / shortcut, which helps to run correct ProcessTs method. + * Works only if there is one componentID assigned to the detector. + */ + Int_t fRICHcompIdx; + + /** + * Unpacker parameters object + */ + CbmMcbm2018RichPar* fUnpackPar; //! + + /** + * Counter of processed timeslices + */ + uint64_t fTScounter; + + /** + * Current microslice ID + */ + Int_t fCurMSid; //! + + /** + * Current microslice index from the microslice descriptor + * CBM reference time //TODO clearify + */ + uint64_t fCurMSidx; //! + + /** + * Global word counter within current microslice + */ + Int_t fGwordCnt; //! + + /** + * Flag indicating that we are in the subsubevent + */ + Bool_t fInSubSubEvent; //! + + /** + * Current epoch value + */ + UInt_t fCurEpochCounter; //! + + /** + * Current subsubevent ID + */ + Int_t fSubSubEvId; //! + + /** + * Flag to mark the last DiRICH on a Hub + */ + Bool_t fLastFeeOnHub = false; + + std::vector<Int_t> fTDCAlignmentErrorPositions; + + Int_t fTdcWordCorrectionCnt = 0; + + Int_t fTdcWordCorrectionGlobalCnt = 0; + + Int_t fSkipCnt = 0; + +private: // Stored timestamps + /** + * Full time of the last rising edge from ch 0 of CTS + */ + Double_t fLastCTSch0_re_time; //! + + /** + * Full time of the last rising edge from ch 2 of CTS + */ + Double_t fLastCTSch2_re_time; //! + + /** + * Full time of the last falling edge from ch 2 of CTS + */ + Double_t fLastCTSch2_fe_time; //! + + /** + * Full time of the last rising edge from ch 0 of CTS from the previous microslice + */ + Double_t fPrevLastCTSch0_re_time; //! + + /** + * Full time of the last rising edge from ch 2 of CTS from the previous microslice + */ + Double_t fPrevLastCTSch2_re_time; //! + + /** + * Full time of the last falling edge from ch 2 of CTS from the previous microslice + */ + Double_t fPrevLastCTSch2_fe_time; //! + + /** + * Full time of the last rising edge from ch 0 of each TDC + */ + TArrayD fLastCh0_re_time; //! + + /** + * Full time of the previous last rising edge from ch 0 of each TDC (from the previous microslice) + */ + TArrayD fPrevLastCh0_re_time; //! + +private: // digi building + void ProcessRisingEdge(Int_t subSubEvId, Int_t channel, Double_t time); + + void ProcessFallingEdge(Int_t subSubEvId, Int_t channel, Double_t time); + + /** + * Buffer for rising edges. It is filled during unpacking whenever + * the rising edge is encountered. Afterwards, when a falling edge + * is encountered, corresponding rising edge is searched here and + * removed if found. + */ + std::vector<CbmMcbmRichEdge> fRisingEdgesBuf; //! Exclude from ROOT dictionnary due to missing empty constructor!! + + /** + * Buffer of falling edges for which corresponding rising edges were not found + */ + std::vector<CbmMcbmRichEdge> fFallingEdgesBuf; //! Exclude from ROOT dictionnary due to missing empty constructor!! + +public: // histograms + /** + * + */ + Bool_t CreateHistograms(); + + /** + * + */ + // Bool_t FillHistograms(); + + /** + * + */ + Bool_t ResetHistograms(); + + TH1D* GetTotH1(Int_t fpgaID, Int_t channel); + TH2D* GetTotH2(Int_t fpgaID); + /* + TH2D* fhTDCch0re_minusCTSch0re; //! + TH2D* fhTDCch0re_minusCTSch2re; //! + TH2D* fhTDCch0re_minusCTSch2fe; //! + TH2D* fhTDCch0re_minusPrevCTSch0re; //! + TH2D* fhTDCch0re_minusPrevCTSch2re; //! + TH2D* fhTDCch0re_minusPrevCTSch2fe; //! + + std::vector<TH2D*> fhTDCre_minusTDCch0re; //! + + std::vector<TH2D*> fhTDCre_minusPrevTDCch0re; //! +*/ + std::vector<TH2D*> fhTDCre_corrected1; //! + + std::vector<TH2D*> fhTDCre_corrected2; //! + + std::vector<TCanvas*> fcTot2d; //! + + TH1* fhVectorSize = nullptr; + TH1* fhVectorCapacity = nullptr; + + //TH2* fhDigisInChnl = nullptr; + //TH2* fhDigisInDiRICH = nullptr; + + TH2D* fhTdcErrors = nullptr; + TH2D* fhEventErrors = nullptr; + + TH2D* fhDiRICHWords = nullptr; + TH2D* fhChnlWords = nullptr; + + TH1* fhEventSize = nullptr; + TH2* fhSubEventSize = nullptr; + TH2* fhSubSubEventSize = nullptr; + TH2* fhChnlSize = nullptr; + + std::array<unsigned int, 33> fChnlMsgCnt; + + bool fDebugPrint = 0; + std::map<uint16_t, uint16_t> fMapFEE; + + std::map<Int_t, std::map<Int_t, TH1D*>> fhTotMap; + + std::map<Int_t, TH2D*> fhTot2dMap; + + size_t fuTsMaxVectorSize = 0; + Double_t fdCapacityIncFactor = 1.1; + + inline void SetVectCapInc(Double_t dIncFact) { fdCapacityIncFactor = dIncFact; } + + ClassDef(CbmMcbm2018UnpackerAlgoRich2020, 1); +}; + +#endif // CbmMcbm2018UnpackerAlgoRich2020_H diff --git a/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerTaskRich2020.cxx b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerTaskRich2020.cxx new file mode 100644 index 0000000000..fab8a57010 --- /dev/null +++ b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerTaskRich2020.cxx @@ -0,0 +1,258 @@ +/* Copyright (C) 2019-2021 Justus-Liebig-Universitaet Giessen, Giessen + SPDX-License-Identifier: GPL-3.0-only + Authors: Egor Ovcharenko [committer], Pierre-Alain Loizeau */ + +/** + * CbmMcbm2018UnpackerTaskRich2020 + * E. Ovcharenko, Mar 2019 + * based on other detectors' classes by P.-A. Loizeau + */ + +//TODO: check that all data members are initialized in the constructor + +#include "CbmMcbm2018UnpackerTaskRich2020.h" + +// ROOT +#include <TCanvas.h> +#include <TClonesArray.h> +#include <TFile.h> +#include <THttpServer.h> +#include <TROOT.h> + +// FairRoot +#include <FairParGenericSet.h> +#include <FairRootManager.h> +#include <FairRun.h> +#include <FairRunOnline.h> +#include <FairRuntimeDb.h> +#include <Logger.h> + +// CbmRoot +#include "CbmMcbm2018RichPar.h" +#include "CbmMcbm2018UnpackerAlgoRich2020.h" + +#include <thread> + +#include <chrono> + +//TODO global variable, really? +Bool_t bMcbm2018UnpackerTaskRichResetHistos2020 = kFALSE; + +CbmMcbm2018UnpackerTaskRich2020::CbmMcbm2018UnpackerTaskRich2020() + : CbmMcbmUnpack() + , fbMonitorMode(kFALSE) + , fbDebugMonitorMode(kFALSE) + , fbWriteOutput(kTRUE) + , fUnpackerAlgo(new CbmMcbm2018UnpackerAlgoRich2020()) +{ +} + +CbmMcbm2018UnpackerTaskRich2020::~CbmMcbm2018UnpackerTaskRich2020() +{ + if (fUnpackerAlgo) { + delete fUnpackerAlgo; + fUnpackerAlgo = nullptr; + } +} + +Bool_t CbmMcbm2018UnpackerTaskRich2020::Init() +{ + LOG(info) << "CbmMcbm2018UnpackerTaskRich2020::Init"; + LOG(info) << "Initializing mCBM RICH 2018 Unpacker"; + + FairRootManager* ioman = FairRootManager::Instance(); + if (ioman == NULL) { LOG(fatal) << "No FairRootManager instance"; } + + /// Get address of vector from algo + fpvDigiRich = &(fUnpackerAlgo->GetVector()); + ioman->RegisterAny("RichDigi", fpvDigiRich, fbWriteOutput); + + return kTRUE; +} + +Bool_t CbmMcbm2018UnpackerTaskRich2020::DoUnpack(const fles::Timeslice& ts, size_t component) +{ + //std::this_thread::sleep_for(std::chrono::milliseconds(10)); + if (fbMonitorMode && bMcbm2018UnpackerTaskRichResetHistos2020) { + LOG(info) << "Reset RICH unpacker histos "; + fUnpackerAlgo->ResetHistograms(); + bMcbm2018UnpackerTaskRichResetHistos2020 = kFALSE; + } // if( fbMonitorMode && bMcbm2018UnpackerTaskRichResetHistos2020 ) + + if (kFALSE == fUnpackerAlgo->ProcessTs(ts, component)) { + LOG(error) << "Failed processing TS " << ts.index() << " in mRICH unpacker algorithm class"; + return kTRUE; + } // if( kFALSE == fUnpackerAlgo->ProcessTs( ts, component ) ) + + /* + /// Sort the buffers of hits due to the time offsets applied + //=> Done in the algo!!! + sort(fpvDigiRich->begin(), fpvDigiRich->end(), + [](const CbmRichDigi & a, const CbmRichDigi & b) -> bool + { + return a.GetTime() < b.GetTime(); + }); +*/ + + if (0 == fulTsCounter % 10000) LOG(info) << "Processed " << fulTsCounter << "TS"; + fulTsCounter++; + + return kTRUE; +} + +void CbmMcbm2018UnpackerTaskRich2020::Reset() { fUnpackerAlgo->ClearVector(); } + +/** + Copied from the CbmMcbm2018UnpackerTaskSts class without giving any thinking... +*/ +void CbmMcbm2018UnpackerTaskRich2020::Finish() +{ + /// If monitor mode enabled, trigger histos creation, obtain pointer on them and add them to the HTTP server + if (kTRUE == fbMonitorMode) { + /// Obtain vector of pointers on each histo from the algo (+ optionally desired folder) + std::vector<std::pair<TNamed*, std::string>> vHistos = fUnpackerAlgo->GetHistoVector(); + + /// Save old global file and folder pointer to avoid messing with FairRoot + TFile* oldFile = gFile; + TDirectory* oldDir = gDirectory; + + TFile* histoFile = nullptr; + + // open separate histo file in recreate mode + histoFile = new TFile("data/HistosUnpackerRich.root", "RECREATE"); + histoFile->cd(); + + /// Register the histos in the HTTP server + for (UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto) { + /// Make sure we end up in chosen folder + TString sFolder = vHistos[uHisto].second.data(); + if (nullptr == gDirectory->Get(sFolder)) gDirectory->mkdir(sFolder); + gDirectory->cd(sFolder); + + /// Write plot + vHistos[uHisto].first->Write(); + + histoFile->cd(); + } // for( UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto ) + + /// Restore old global file and folder pointer to avoid messing with FairRoot + gFile = oldFile; + gDirectory = oldDir; + + histoFile->Close(); + } // if( kTRUE == fbMonitorMode ) +} + +/** + Copied from the CbmMcbm2018UnpackerTaskTof class without giving any thinking... +*/ +void CbmMcbm2018UnpackerTaskRich2020::SetParContainers() +{ + LOG(info) << "Setting parameter containers for " << GetName(); + + TList* fParCList = fUnpackerAlgo->GetParList(); + + for (Int_t iparC = 0; iparC < fParCList->GetEntries(); ++iparC) { + FairParGenericSet* tempObj = (FairParGenericSet*) (fParCList->At(iparC)); + fParCList->Remove(tempObj); + + std::string sParamName {tempObj->GetName()}; + FairParGenericSet* newObj = + dynamic_cast<FairParGenericSet*>(FairRun::Instance()->GetRuntimeDb()->getContainer(sParamName.data())); + + if (nullptr == newObj) { + LOG(error) << "Failed to obtain parameter container " << sParamName << ", for parameter index " << iparC; + return; + } // if( nullptr == newObj ) + + fParCList->AddAt(newObj, iparC); + // delete tempObj; + } // for( Int_t iparC = 0; iparC < fParCList->GetEntries(); ++iparC ) +} + +/** + Copied from the CbmMcbm2018UnpackerTaskTof class without giving any thinking... +*/ +Bool_t CbmMcbm2018UnpackerTaskRich2020::InitContainers() +{ + LOG(info) << "Init parameter containers for " << GetName(); + + /// Control flags + CbmMcbm2018RichPar* pUnpackPar = + dynamic_cast<CbmMcbm2018RichPar*>(FairRun::Instance()->GetRuntimeDb()->getContainer("CbmMcbm2018RichPar")); + if (nullptr == pUnpackPar) { + LOG(error) << "Failed to obtain parameter container CbmMcbm2018RichPar"; + return kFALSE; + } // if( nullptr == pUnpackPar ) + /* + fbMonitorMode = pUnpackPar->GetMonitorMode(); + LOG(info) << "Monitor mode: " + << ( fbMonitorMode ? "ON" : "OFF" ); + + fbDebugMonitorMode = pUnpackPar->GetDebugMonitorMode(); + LOG(info) << "Debug Monitor mode: " + << ( fbDebugMonitorMode ? "ON" : "OFF" ); +*/ + Bool_t initOK = fUnpackerAlgo->InitContainers(); + + /// If monitor mode enabled, trigger histos creation, obtain pointer on them and add them to the HTTP server + if (kTRUE == fbMonitorMode) { + /// Trigger histo creation on all associated algos + initOK &= fUnpackerAlgo->CreateHistograms(); + + /// Obtain vector of pointers on each histo from the algo (+ optionally desired folder) + std::vector<std::pair<TNamed*, std::string>> vHistos = fUnpackerAlgo->GetHistoVector(); + /// Obtain vector of pointers on each canvas from the algo (+ optionally desired folder) + std::vector<std::pair<TCanvas*, std::string>> vCanvases = fUnpackerAlgo->GetCanvasVector(); + + /// Register the histos in the HTTP server + THttpServer* server = FairRunOnline::Instance()->GetHttpServer(); + if (nullptr != server) { + for (UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto) { + server->Register(Form("/rich/%s", vHistos[uHisto].second.data()), vHistos[uHisto].first); + } // for( UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto ) + for (UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv) { + server->Register(Form("/rich/%s", vCanvases[uCanv].second.data()), + gROOT->FindObject((vCanvases[uCanv].first)->GetName())); + } // for( UInt_t uCanv = 0; uCanv < vCanvases.size(); ++uCanv ) + + + server->RegisterCommand("/Reset_UnpRich_Hist", "bMcbm2018UnpackerTaskRichResetHistos2020=kTRUE"); + server->Restrict("/Reset_UnpRich_Hist", "allow=admin"); + } // if( nullptr != server ) + + } // if( kTRUE == fbMonitorMode ) + + fUnpackerAlgo->SetMonitorMode(fbMonitorMode); + + return initOK; +} + +/** + Copied from the CbmMcbm2018UnpackerTaskTof class without giving any thinking... +*/ +Bool_t CbmMcbm2018UnpackerTaskRich2020::ReInitContainers() +{ + LOG(info) << "ReInit parameter containers for " << GetName(); + Bool_t initOK = fUnpackerAlgo->ReInitContainers(); + + return initOK; +} + +/** + Copied from other detectors without any brain effort... +**/ +void CbmMcbm2018UnpackerTaskRich2020::AddMsComponentToList(size_t component, UShort_t usDetectorId) +{ + fUnpackerAlgo->AddMsComponentToList(component, usDetectorId); +} + +void CbmMcbm2018UnpackerTaskRich2020::SetNbMsInTs(size_t /*uCoreMsNb*/, size_t /*uOverlapMsNb*/) {} + +void CbmMcbm2018UnpackerTaskRich2020::SetIgnoreOverlapMs(Bool_t bFlagIn) { fUnpackerAlgo->SetIgnoreOverlapMs(bFlagIn); } + +void CbmMcbm2018UnpackerTaskRich2020::SetTimeOffsetNs(Double_t dOffsetIn) { fUnpackerAlgo->SetTimeOffsetNs(dOffsetIn); } + +void CbmMcbm2018UnpackerTaskRich2020::DoTotCorr(Bool_t bDoToTCorr) { fUnpackerAlgo->DoTotCorr(bDoToTCorr); } + +ClassImp(CbmMcbm2018UnpackerTaskRich2020) diff --git a/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerTaskRich2020.h b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerTaskRich2020.h new file mode 100644 index 0000000000..b3dbfce1a8 --- /dev/null +++ b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerTaskRich2020.h @@ -0,0 +1,75 @@ +/* Copyright (C) 2019-2020 Justus-Liebig-Universitaet Giessen, Giessen + SPDX-License-Identifier: GPL-3.0-only + Authors: Egor Ovcharenko [committer], Pierre-Alain Loizeau */ + +/** + * CbmMcbm2018UnpackerTaskRich + * E. Ovcharenko, Mar 2019 + * based on other detectors' classes by P.-A. Loizeau + */ + +#ifndef CbmMcbm2018UnpackerTaskRich2020_H +#define CbmMcbm2018UnpackerTaskRich2020_H + +#include "CbmMcbmUnpack.h" // mother class +#include "CbmRichDigi.h" + +//class TList; // Needed? +//class TClonesArray; +class CbmMcbm2018UnpackerAlgoRich2020; + +class CbmMcbm2018UnpackerTaskRich2020 : public CbmMcbmUnpack { +public: + CbmMcbm2018UnpackerTaskRich2020(); + + CbmMcbm2018UnpackerTaskRich2020(const CbmMcbm2018UnpackerTaskRich2020&) = delete; + CbmMcbm2018UnpackerTaskRich2020 operator=(const CbmMcbm2018UnpackerTaskRich2020&) = delete; + + virtual ~CbmMcbm2018UnpackerTaskRich2020(); + + virtual Bool_t Init(); + + virtual Bool_t DoUnpack(const fles::Timeslice& ts, size_t component); + + virtual void Reset(); + + virtual void Finish(); + + virtual void SetParContainers(); + + virtual Bool_t InitContainers(); + + virtual Bool_t ReInitContainers(); + + virtual void AddMsComponentToList(size_t component, UShort_t usDetectorId); + + virtual void SetNbMsInTs(size_t uCoreMsNb, size_t uOverlapMsNb); + + /// Algo settings setters + inline void SetMonitorMode(Bool_t bFlagIn = kTRUE) { fbMonitorMode = bFlagIn; } + void SetIgnoreOverlapMs(Bool_t bFlagIn = kTRUE); + void SetTimeOffsetNs(Double_t dOffsetIn = 0.0); + void DoTotCorr(Bool_t bDoToTCorr = kTRUE); + + /// Task settings + void SetWriteOutputFlag(Bool_t bFlagIn) { fbWriteOutput = bFlagIn; } + +private: + /// Control flags + Bool_t fbMonitorMode; //! Switch ON the filling of a minimal set of histograms + Bool_t fbDebugMonitorMode; //! Switch ON the filling of a additional set of histograms + Bool_t fbWriteOutput; //! If ON the output TClonesArray of digi is written to disk + + /// Statistics & first TS rejection + uint64_t fulTsCounter; + + /// Algo implementation of the unpacking + CbmMcbm2018UnpackerAlgoRich2020* fUnpackerAlgo; + + /// Output vectors + std::vector<CbmRichDigi>* fpvDigiRich = nullptr; + + ClassDef(CbmMcbm2018UnpackerTaskRich2020, 1); +}; + +#endif // CbmMcbm2018UnpackerTaskRich2020_H diff --git a/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerUtilRich.hpp b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerUtilRich.hpp deleted file mode 100644 index 9b9eff5d55..0000000000 --- a/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerUtilRich.hpp +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef CbmMcbm2018UnpackerUtilRich_HPP -#define CbmMcbm2018UnpackerUtilRich_HPP - -#include <iostream> -#include <string> - -std::string GetBinaryRepresentation(size_t const size, uint8_t const* const ptr) -{ - std::string outString; - - unsigned char* b = (unsigned char*) ptr; - unsigned char byte; - - char cStr[2]; - cStr[1] = '\0'; - - for (int i = size - 1; i >= 0; i--) { - for (int j = 7; j >= 0; j--) { - byte = (b[i] >> j) & 1; - sprintf(cStr, "%u", byte); - outString.append(cStr); - } - } - - return outString; -} - -/** - * size in bytes - */ -std::string GetHexRepresentation(size_t const size, uint8_t const* const ptr) -{ - std::string outString; - - unsigned char* b = (unsigned char*) ptr; - unsigned char byte; - - char cStr[3]; - cStr[2] = '\0'; - - for (int i = size - 1; i >= 0; i--) { - byte = b[i] & 0xff; - sprintf(cStr, "%02x", byte); - outString.append(cStr); - } - - return outString; -} - -std::string GetWordHexRepr(uint8_t const* const ptr) -{ - std::string outString; - - unsigned char* b = (unsigned char*) ptr; - unsigned char byte[4]; - byte[0] = b[3] & 0xff; - byte[1] = b[2] & 0xff; - byte[2] = b[1] & 0xff; - byte[3] = b[0] & 0xff; - - char cStr[10]; - cStr[9] = '\0'; - - sprintf(cStr, "%02x%02x %02x%02x", byte[0], byte[1], byte[2], byte[3]); - - outString.append(cStr); - - return outString; -} - -std::string GetWordHexReprInv(uint8_t const* const ptr) -{ - std::string outString; - - unsigned char* b = (unsigned char*) ptr; - unsigned char byte[4]; - byte[0] = b[0] & 0xff; - byte[1] = b[1] & 0xff; - byte[2] = b[2] & 0xff; - byte[3] = b[3] & 0xff; - - char cStr[10]; - cStr[9] = '\0'; - - sprintf(cStr, "%02x%02x %02x%02x", byte[0], byte[1], byte[2], byte[3]); - - outString.append(cStr); - - return outString; -} - -void SwapBytes(size_t const size, uint8_t const* ptr) -{ - unsigned char* b = (unsigned char*) ptr; - unsigned char byte[4]; - byte[0] = b[3] & 0xff; - byte[1] = b[2] & 0xff; - byte[2] = b[1] & 0xff; - byte[3] = b[0] & 0xff; - - b[0] = byte[0]; - b[1] = byte[1]; - b[2] = byte[2]; - b[3] = byte[3]; -} - -void PrintRaw(size_t const size, uint8_t const* const ptr) -{ - size_t nWords = size / 4; - size_t nRestBytes = size % 4; - - for (size_t iWord = 0; iWord < nWords; iWord++) { - //std::cout << GetHexRepresentation(4, ptr+iWord*4) << " "; - - std::cout << GetWordHexReprInv(ptr + iWord * 4) << " "; - } - /*if (nRestBytes > 0) { - std::cout << GetHexRepresentation(nRestBytes, ptr+nWords*4) << " " << std::endl; - } else { - std::cout << std::endl; - }*/ - std::cout << std::endl; -} - -#endif // CbmMcbm2018UnpackerUtilRich_HPP diff --git a/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerUtilRich.cxx b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerUtilRich2020.cxx similarity index 98% rename from fles/mcbm2018/unpacker/CbmMcbm2018UnpackerUtilRich.cxx rename to fles/mcbm2018/unpacker/CbmMcbm2018UnpackerUtilRich2020.cxx index 2050c5b1ba..bdb1b87062 100644 --- a/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerUtilRich.cxx +++ b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerUtilRich2020.cxx @@ -2,7 +2,7 @@ SPDX-License-Identifier: GPL-3.0-only Authors: Egor Ovcharenko [committer] */ -#include "CbmMcbm2018UnpackerUtilRich.h" +#include "CbmMcbm2018UnpackerUtilRich2020.h" #include <iostream> diff --git a/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerUtilRich.h b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerUtilRich2020.h similarity index 87% rename from fles/mcbm2018/unpacker/CbmMcbm2018UnpackerUtilRich.h rename to fles/mcbm2018/unpacker/CbmMcbm2018UnpackerUtilRich2020.h index cb9c6955ff..d5f3e9082f 100644 --- a/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerUtilRich.h +++ b/fles/mcbm2018/unpacker/CbmMcbm2018UnpackerUtilRich2020.h @@ -2,8 +2,8 @@ SPDX-License-Identifier: GPL-3.0-only Authors: Egor Ovcharenko [committer] */ -#ifndef CbmMcbm2018UnpackerUtilRich_H -#define CbmMcbm2018UnpackerUtilRich_H +#ifndef CbmMcbm2018UnpackerUtilRich2020_H +#define CbmMcbm2018UnpackerUtilRich2020_H // STD #include <string> @@ -40,4 +40,4 @@ namespace mRichSupport }; // namespace mRichSupport -#endif // CbmMcbm2018UnpackerUtilRich_H +#endif // CbmMcbm2018UnpackerUtilRich2020_H diff --git a/macro/beamtime/mcbm2018/MonitorRich.C b/macro/beamtime/mcbm2018/MonitorRich.C index ab53ebb387..a2b8026f5a 100644 --- a/macro/beamtime/mcbm2018/MonitorRich.C +++ b/macro/beamtime/mcbm2018/MonitorRich.C @@ -11,9 +11,9 @@ // In order to call later Finish, we make this global FairRunOnline* run = NULL; -void MonitorRich(TString inFile = "/Users/slebedev/Development/cbm/data/mcbm18/159_pn02_0000.tsa", +void MonitorRich(TString inFile = "/Users/slebedev/Development/cbm/data/mcbm18/out100800.tsa", TString sHostname = "localhost", Int_t iServerHttpPort = 8080, Int_t iServerRefreshRate = 100, - UInt_t uRunId = 0, UInt_t nrEvents = 0) + UInt_t uRunId = 0, UInt_t nrEvents = 10) { TString srcDir = gSystem->Getenv("VMCWORKDIR"); @@ -26,15 +26,15 @@ void MonitorRich(TString inFile = "/Users/slebedev/Development/cbm/data/mcbm1 // --- Set log output levels FairLogger::GetLogger(); - gLogger->SetLogScreenLevel("INFO"); - //gLogger->SetLogScreenLevel("DEBUG"); + //gLogger->SetLogScreenLevel("INFO"); + gLogger->SetLogScreenLevel("DEBUG4"); gLogger->SetLogVerbosityLevel("MEDIUM"); // --- Define parameter files TList* parFileList = new TList(); TString paramDir = srcDir + "/macro/beamtime/mcbm2018/"; - TString paramFileRich = paramDir + "mRichPar.par"; + TString paramFileRich = paramDir + "mRichPar.par"; // TODO: use mRichPar_70.par im mcbm2020 TObjString* parRichFileName = new TObjString(paramFileRich); parFileList->Add(parRichFileName); @@ -53,7 +53,7 @@ void MonitorRich(TString inFile = "/Users/slebedev/Development/cbm/data/mcbm1 source->SetHostName(sHostname); } - source->AddUnpacker(unpacker_rich, 0x30, kRich); //RICH trb + source->AddUnpacker(unpacker_rich, 0x30, ECbmModuleId::kRich); //RICH trb source->SetSubscriberHwm(1000); diff --git a/macro/beamtime/mcbm2019/MonitorRich.C b/macro/beamtime/mcbm2019/MonitorRich.C index 939336768c..02ae590a31 100644 --- a/macro/beamtime/mcbm2019/MonitorRich.C +++ b/macro/beamtime/mcbm2019/MonitorRich.C @@ -42,7 +42,7 @@ void MonitorRich(TString inFile = "/Users/slebedev/Development/cbm/data/mcbm1 // --- Set debug level gDebug = 0; - CbmMcbm2018UnpackerTaskRich* unpacker_rich = new CbmMcbm2018UnpackerTaskRich(); + CbmMcbm2018UnpackerTaskRich2020* unpacker_rich = new CbmMcbm2018UnpackerTaskRich2020(); unpacker_rich->SetIgnoreOverlapMs(); unpacker_rich->SetMonitorMode(); unpacker_rich->DoTotCorr(kFALSE); diff --git a/macro/beamtime/mcbm2019/unpack_tsa_mcbm.C b/macro/beamtime/mcbm2019/unpack_tsa_mcbm.C index 59178d4089..7ba1ad7776 100644 --- a/macro/beamtime/mcbm2019/unpack_tsa_mcbm.C +++ b/macro/beamtime/mcbm2019/unpack_tsa_mcbm.C @@ -77,11 +77,11 @@ void unpack_tsa_mcbm(TString inFile = "", UInt_t uRunId = 0, UInt_t nrEvents = 0 std::cout << std::endl; std::cout << ">>> unpack_tsa: Initialising..." << std::endl; - CbmMcbm2018UnpackerTaskSts* unpacker_sts = new CbmMcbm2018UnpackerTaskSts(); - CbmMcbm2018UnpackerTaskMuch* unpacker_much = new CbmMcbm2018UnpackerTaskMuch(); - CbmMcbm2018UnpackerTaskTof* unpacker_tof = new CbmMcbm2018UnpackerTaskTof(); - CbmMcbm2018UnpackerTaskRich* unpacker_rich = new CbmMcbm2018UnpackerTaskRich(); - CbmMcbm2018UnpackerTaskPsd* unpacker_psd = new CbmMcbm2018UnpackerTaskPsd(); + CbmMcbm2018UnpackerTaskSts* unpacker_sts = new CbmMcbm2018UnpackerTaskSts(); + CbmMcbm2018UnpackerTaskMuch* unpacker_much = new CbmMcbm2018UnpackerTaskMuch(); + CbmMcbm2018UnpackerTaskTof* unpacker_tof = new CbmMcbm2018UnpackerTaskTof(); + CbmMcbm2018UnpackerTaskRich2020* unpacker_rich = new CbmMcbm2018UnpackerTaskRich2020(); + CbmMcbm2018UnpackerTaskPsd* unpacker_psd = new CbmMcbm2018UnpackerTaskPsd(); unpacker_sts->SetMonitorMode(); unpacker_much->SetMonitorMode(); diff --git a/macro/beamtime/mcbm2020/MonitorRich.C b/macro/beamtime/mcbm2020/MonitorRich.C index 2f8d61543b..623f383de8 100644 --- a/macro/beamtime/mcbm2020/MonitorRich.C +++ b/macro/beamtime/mcbm2020/MonitorRich.C @@ -11,9 +11,9 @@ // In order to call later Finish, we make this global FairRunOnline* run = NULL; -void MonitorRich(TString inFile = "/Users/slebedev/Development/cbm/data/mcbm18/159_pn02_0000.tsa", +void MonitorRich(TString inFile = "/Users/slebedev/Development/cbm/data/mcbm18/2021179204256_0.tsa", TString sHostname = "localhost", Int_t iServerHttpPort = 8080, Int_t iServerRefreshRate = 100, - UInt_t uRunId = 0, UInt_t nrEvents = 0) + UInt_t uRunId = 0, UInt_t nrEvents = 1000000) { TString srcDir = gSystem->Getenv("VMCWORKDIR"); @@ -25,7 +25,7 @@ void MonitorRich(TString inFile = "/Users/slebedev/Development/cbm/data/mcbm1 // --- Set log output levels FairLogger::GetLogger(); - gLogger->SetLogScreenLevel("INFO"); + gLogger->SetLogScreenLevel("DEBUG4"); //gLogger->SetLogScreenLevel("DEBUG"); gLogger->SetLogVerbosityLevel("MEDIUM"); @@ -33,14 +33,14 @@ void MonitorRich(TString inFile = "/Users/slebedev/Development/cbm/data/mcbm1 TList* parFileList = new TList(); TString paramDir = srcDir + "/macro/beamtime/mcbm2020/"; - TString paramFileRich = paramDir + "mRichPar.par"; + TString paramFileRich = paramDir + "mRichPar_70.par"; TObjString* parRichFileName = new TObjString(paramFileRich); parFileList->Add(parRichFileName); // --- Set debug level gDebug = 0; - CbmMcbm2018UnpackerTaskRich* unpacker_rich = new CbmMcbm2018UnpackerTaskRich(); + CbmMcbm2018UnpackerTaskRich2020* unpacker_rich = new CbmMcbm2018UnpackerTaskRich2020(); unpacker_rich->SetIgnoreOverlapMs(); unpacker_rich->SetMonitorMode(); unpacker_rich->DoTotCorr(kFALSE); diff --git a/macro/beamtime/mcbm2020/unpack_tsa_mcbm.C b/macro/beamtime/mcbm2020/unpack_tsa_mcbm.C index 2914565401..1c1843096f 100644 --- a/macro/beamtime/mcbm2020/unpack_tsa_mcbm.C +++ b/macro/beamtime/mcbm2020/unpack_tsa_mcbm.C @@ -123,12 +123,12 @@ Bool_t unpack_tsa_mcbm(TString inFile = "", std::cout << std::endl; std::cout << ">>> unpack_tsa: Initialising..." << std::endl; - CbmMcbm2018UnpackerTaskSts* unpacker_sts = new CbmMcbm2018UnpackerTaskSts(); - CbmMcbm2018UnpackerTaskMuch* unpacker_much = new CbmMcbm2018UnpackerTaskMuch(); - CbmMcbm2018UnpackerTaskTrdR* unpacker_trdR = new CbmMcbm2018UnpackerTaskTrdR(); - CbmMcbm2018UnpackerTaskTof* unpacker_tof = new CbmMcbm2018UnpackerTaskTof(); - CbmMcbm2018UnpackerTaskRich* unpacker_rich = new CbmMcbm2018UnpackerTaskRich(); - CbmMcbm2018UnpackerTaskPsd* unpacker_psd = new CbmMcbm2018UnpackerTaskPsd(); + CbmMcbm2018UnpackerTaskSts* unpacker_sts = new CbmMcbm2018UnpackerTaskSts(); + CbmMcbm2018UnpackerTaskMuch* unpacker_much = new CbmMcbm2018UnpackerTaskMuch(); + CbmMcbm2018UnpackerTaskTrdR* unpacker_trdR = new CbmMcbm2018UnpackerTaskTrdR(); + CbmMcbm2018UnpackerTaskTof* unpacker_tof = new CbmMcbm2018UnpackerTaskTof(); + CbmMcbm2018UnpackerTaskRich2020* unpacker_rich = new CbmMcbm2018UnpackerTaskRich2020(); + CbmMcbm2018UnpackerTaskPsd* unpacker_psd = new CbmMcbm2018UnpackerTaskPsd(); /* * Do not generate plots by default diff --git a/macro/beamtime/mcbm2021/MonitorRich.C b/macro/beamtime/mcbm2021/MonitorRich.C new file mode 100644 index 0000000000..c2828c3166 --- /dev/null +++ b/macro/beamtime/mcbm2021/MonitorRich.C @@ -0,0 +1,105 @@ +/* Copyright (C) 2020 Facility for Antiproton and Ion Research in Europe, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pierre-Alain Loizeau [committer] */ + +/** @file MCBM RICH DATA monitoring + ** Based on MonitorT0 by P.-A. Loizeau + ** ROOT macro to read tsa files which have been produced with the new data transport + ** Convert data into cbmroot format. + ** Uses CbmMcbm2018Source as source task. + */ +// In order to call later Finish, we make this global +FairRunOnline* run = NULL; + +void MonitorRich(TString inFile = "/Users/slebedev/Development/cbm/data/mcbm18/2021179204256_0.tsa", + TString sHostname = "localhost", Int_t iServerHttpPort = 8080, Int_t iServerRefreshRate = 100, + UInt_t uRunId = 0, UInt_t nrEvents = 1000000) +{ + TString srcDir = gSystem->Getenv("VMCWORKDIR"); + + // --- Specify number of events to be produced. + // --- -1 means run until the end of the input file. + Int_t nEvents = -1; + // --- Specify output file name (this is just an example) + TString parFile = TString::Format("data/moni_rich_params_%u.root", uRunId); + + // --- Set log output levels + FairLogger::GetLogger(); + gLogger->SetLogScreenLevel("DEBUG4"); + //gLogger->SetLogScreenLevel("DEBUG"); + gLogger->SetLogVerbosityLevel("MEDIUM"); + + // --- Define parameter files + TList* parFileList = new TList(); + TString paramDir = srcDir + "/macro/beamtime/mcbm2020/"; + + TString paramFileRich = paramDir + "mRichPar_70.par"; + TObjString* parRichFileName = new TObjString(paramFileRich); + parFileList->Add(parRichFileName); + + // --- Set debug level + gDebug = 0; + + CbmMcbm2018UnpackerTaskRich* unpacker_rich = new CbmMcbm2018UnpackerTaskRich(); + unpacker_rich->SetIgnoreOverlapMs(); + unpacker_rich->SetMonitorMode(); + unpacker_rich->DoTotCorr(kFALSE); + unpacker_rich->SetWriteOutputFlag(kFALSE); /// Needed to avoid bug with FairRoot not checking if Data Sink exists + // --- Source task + CbmMcbm2018Source* source = new CbmMcbm2018Source(); + + if ("" != inFile) { source->SetFileName(inFile); } + else { + source->SetHostName(sHostname); + } + + source->AddUnpacker(unpacker_rich, 0x30, ECbmModuleId::kRich); //RICH trb + + source->SetSubscriberHwm(1000); + + // --- Run + run = new FairRunOnline(source); + run->ActivateHttpServer(iServerRefreshRate, + iServerHttpPort); // refresh each 100 events + /// To avoid the server sucking all Histos from gROOT when no output file is used + /// ===> Need to explicitely add the canvases to the server in the task! + run->GetHttpServer()->GetSniffer()->SetScanGlobalDir(kFALSE); + run->SetAutoFinish(kFALSE); + + + // ----- Runtime database --------------------------------------------- + FairRuntimeDb* rtdb = run->GetRuntimeDb(); + FairParAsciiFileIo* parIn = new FairParAsciiFileIo(); + parIn->open(parFileList, "in"); + rtdb->setFirstInput(parIn); + + run->Init(); + + // --- Start run + TStopwatch timer; + timer.Start(); + std::cout << ">>> MonitorRich: Starting run..." << std::endl; + if (0 == nrEvents) { + run->Run(nEvents, 0); // run until end of input file + } + else { + run->Run(0, nrEvents); // process 2000 Events + } + run->Finish(); + + timer.Stop(); + + std::cout << "Processed " << std::dec << source->GetTsCount() << " timeslices" << std::endl; + + // --- End-of-run info + Double_t rtime = timer.RealTime(); + Double_t ctime = timer.CpuTime(); + std::cout << std::endl << std::endl; + std::cout << ">>> MonitorRich: Macro finished successfully." << std::endl; + std::cout << ">>> MonitorRich: Real time " << rtime << " s, CPU time " << ctime << " s" << std::endl; + std::cout << std::endl; + + /// --- Screen output for automatic tests + std::cout << " Test passed" << std::endl; + std::cout << " All ok " << std::endl; +} -- GitLab