diff --git a/algo/detectors/trd/Unpack.cxx b/algo/detectors/trd/Unpack.cxx index 88b2f9c3583f32732361a67b024345c90af8ccd0..f6e3bb135117ab02e2be457145e656335f8d3828 100644 --- a/algo/detectors/trd/Unpack.cxx +++ b/algo/detectors/trd/Unpack.cxx @@ -11,8 +11,8 @@ using fles::Subsystem; Unpack::Unpack(const ReadoutConfig& readout) : fReadout(readout) { - constexpr i64 SystemTimeOffset = 1300; - constexpr u8 SystemVersion = 0x01; + constexpr i64 SystemTimeOffset = 1300; + constexpr std::array<u8, 2> SystemVersion = {0x01, 0x10}; // Create one algorithm per component for TRD and configure it with parameters auto equipIdsTrd = fReadout.GetEquipmentIds(); @@ -34,8 +34,10 @@ Unpack::Unpack(const ReadoutConfig& readout) : fReadout(readout) } par.fCrobParams.push_back(crobPar); } - auto algo = std::make_unique<UnpackMS>(std::move(par)); - fAlgos[{equip, SystemVersion}] = std::move(algo); + auto algo_01 = std::make_unique<UnpackMS<SystemVersion[0]>>(std::move(par)); + auto algo_10 = std::make_unique<UnpackMS<SystemVersion[1]>>(std::move(par)); + fAlgos[{equip, SystemVersion[0]}] = std::move(algo_01); + fAlgos[{equip, SystemVersion[1]}] = std::move(algo_10); L_(debug) << "--- Configured equipment " << equip << " with " << numCrobs << " crobs"; } diff --git a/algo/detectors/trd/UnpackMS.cxx b/algo/detectors/trd/UnpackMS.cxx index 0ba70becd7dd1bf874a1c216f696bfa24c9609c7..8f41dd695a9bcb9d665f2adae49b25f7fb01608f 100644 --- a/algo/detectors/trd/UnpackMS.cxx +++ b/algo/detectors/trd/UnpackMS.cxx @@ -1,6 +1,6 @@ /* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt SPDX-License-Identifier: GPL-3.0-only - Authors: Pascal Raisig, Dominik Smith [committer] */ + Authors: Pascal Raisig, Dominik Smith [committer], David Schledt */ #include "UnpackMS.h" @@ -14,214 +14,9 @@ using std::unique_ptr; namespace cbm::algo::trd { - UnpackMS::UnpackMS(const UnpackPar& pars) : fParams(pars) {} - UnpackMS::~UnpackMS() = default; - - // ---- Algorithm execution --------------------------------------------- - UnpackMS::Result_t UnpackMS::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr, - const uint64_t tTimeslice) const - { - // --- Output data - Result_t result = {}; - - MsContext ctx = {}; - - // Get the µSlice starttime relative to the timeslice starttime (constant is clock length of Spadic in ns) - ctx.fMsStartTimeRelCC = (msDescr.idx - tTimeslice) / fAsicClockCycle; - - // We only want to count on TS_MSB per Stream per TS_MSB package (each eLink sends its own TS_MSB frame) - // so we store the current TS_MSB and compare it to the incoming. - std::int8_t currTsMsb = 0; - - // Reset the TS_MSB counter for the new µSlice we unpack - ctx.fNrTsMsbVec.resize(fStreamsPerWord); - - - // Get the µslice size in bytes to calculate the number of completed words - auto mssize = msDescr.size; - - // Get the hardware ids from which the current µSlice is coming - std::uint8_t crobId = 0; - auto criId = msDescr.eq_id; - - // Digest the flags from the µSlice - digestMsFlags(msDescr.flags, result.second); - - // Get the number of complete words in the input MS buffer. - std::uint32_t nwords = mssize / fBytesPerWord; - - // We have 32 bit spadic frames in this readout version - const auto mscontent = reinterpret_cast<const size_t*>(msContent); - - result.first.reserve(nwords); - - // Loop over all 64bit-Spadic-Words in the current µslice - for (std::uint32_t istream = 0; istream < fStreamsPerWord; istream++) { - currTsMsb = -1; - for (std::uint32_t iword = 0; iword < nwords; ++iword) { - // Access the actual word from the pointer - size_t word = static_cast<size_t>(mscontent[iword]); - - // Access the actual frame[iframe] from the word. (see fStreamsPerWord) - std::uint32_t frame = (word >> (32 * istream)) & 0xffffffff; - - // Get the type of the frame - auto kWordtype = getMessageType(frame); - - // In case we saw any other word than an EPO(TS_MSB) reset the flag, - // such that we again increase by one if an EPO frame arrives - auto elinkId = (frame >> 24) & 0x3f; - - switch (kWordtype) { - case Spadic::MsMessageType::kEPO: { - auto tsmsb = getTsMsb(frame, result.second); - if (((tsmsb - currTsMsb) & 0x3f) == 1 || currTsMsb == -1) ctx.fNrTsMsbVec.at(istream)++; - currTsMsb = tsmsb; - result.second.fNumEpochMsgs++; - break; - // FIXME in the kEPO msg we also have further flags that should be extracted - } - case Spadic::MsMessageType::kSOM: { - // Create the raw message and fill it with all information we can get from the SOM msg - CbmTrdRawMessageSpadic raw = makeRaw(frame, criId, crobId, elinkId, istream, ctx); - - // FIXME since we can not deduce the sample position from the messages we need in - // future some parameter handling here to place the samples at the correct position - // 6 adc bits are stored in the som message - size_t nadcbits = 6; - size_t nadcbitstotal = 6; - // Get the first bits from the adc signal - size_t adcbuffer = frame & 0x3f; - size_t isample = 0; - size_t irda = 0; - - // Now lets check if we have rda words following our som - iword++; - word = static_cast<size_t>(mscontent[iword]); - frame = (word >> (32 * istream)) & 0xffffffff; - - // The maximum amount of samples (32) equals to 12 RDA messages - while (getMessageType(frame) == Spadic::MsMessageType::kRDA && irda < 12) { - // We have to count the number of rda frames for sample reconstruction in eom - irda++; - - // Ensure that we are on the correct eLink - elinkId = (frame >> 24) & 0x3f; - if (elinkId != raw.GetElinkId()) { - result.second.fNumElinkMis++; - } - - // We have 22 adc bits per RDA word lets add them to the buffer... - adcbuffer <<= 22; - adcbuffer |= static_cast<size_t>((frame & 0x3fffff)); - // and increase the adcbit counter by 22 bits - nadcbits += 22; - nadcbitstotal += 22; - // If we have 9 or more samples stored we can extract n samples - while (nadcbits >= 9) { - raw.IncNrSamples(); - // In case the avg baseline feature was used we need to take special care of sample 0 - if (isample == 0 && fParams.fUseBaselineAvg) - raw.SetSample(extractAvgSample(&adcbuffer, &nadcbits), isample); - else - raw.SetSample(extractSample(&adcbuffer, &nadcbits), isample); - isample++; - } - iword++; - word = static_cast<size_t>(mscontent[iword]); - frame = (word >> (32 * istream)) & 0xffffffff; - } - - if (getMessageType(frame) == Spadic::MsMessageType::kEOM) { - // Ensure that we are on the correct eLink - elinkId = (frame >> 24) & 0x3f; - if (elinkId != raw.GetElinkId()) { - result.second.fNumElinkMis++; - } - - // Number of samples indicator = nsamples % 4 - std::uint8_t nsamplesindicator = (frame >> 18) & 0x3; - // Number of required samples as indicated - std::uint64_t nreqsamples = (nadcbitstotal + 18) / 9; - std::uint8_t nn = nreqsamples % 4; - for (std::uint8_t itest = 0; itest < 3; itest++) { - if (nn == nsamplesindicator || nreqsamples == 0) break; - nreqsamples--; - nn = nreqsamples % 4; - } - - // There is a chance that the nsamplesindicator bits are corrupted, - // here we check that we do not try to extract more adcbits than actually are streamed - if (nreqsamples >= isample) { - // Now extract from the above values the number of required adc bits from the eom - std::int8_t nrequiredbits = (nreqsamples - isample) * 9 - nadcbits; - adcbuffer <<= nrequiredbits; - - // The eom carries at maximum 18 adcbits - adcbuffer |= static_cast<size_t>((frame & 0x3ffff) >> (18 - nrequiredbits)); - nadcbits += nrequiredbits; - - while (nadcbits >= 9) { - raw.IncNrSamples(); - raw.SetSample(extractSample(&adcbuffer, &nadcbits), isample); - isample++; - } - } - else { - result.second.fNumCorruptEom++; - } - result.second.fNumCreatedRawMsgs++; - - // the message is done and the raw message container should contain everything we need. - // So now we can call makeDigi(). Nevertheless there is a chance for a corrupted message, - // which ends up with 0 samples so we have to check for it. - if (isample > 0) result.first.push_back(makeDigi(raw, ctx)); - } - else { - // We move the word counter backwards by one, such that the unexpected message can correctly be digested - iword--; - result.second.fNumMissingEom++; - } - break; - } - case Spadic::MsMessageType::kRDA: { - result.second.fNumWildRda++; - break; - } - case Spadic::MsMessageType::kEOM: { - result.second.fNumWildEom++; - break; - } - case Spadic::MsMessageType::kINF: { - result.second.fNumCreatedInfoMsgs++; - digestInfoMsg(frame); - break; - } - case Spadic::MsMessageType::kNUL: { - // last word in Microslice is 0. - if (iword != (nwords - 1) || (istream != (fStreamsPerWord - 1))) { - result.second.fNumWildNul++; - } - break; - } - case Spadic::MsMessageType::kUNK: { - result.second.fNumUnknownWords++; - return result; - break; - } - default: - // We have varying msg types for different versions of the message format. - // Hence, to not produce compiler warnings we have a "default break;" here. - break; - } - } - } - return result; - } - // -------------------------------------------------------------------------- - // ---- digestBufInfoFlags ---- - Spadic::MsInfoType UnpackMS::digestBufInfoFlags(const std::uint32_t frame) const + template<uint8_t sys_ver> + Spadic::MsInfoType UnpackMS<sys_ver>::digestBufInfoFlags(const std::uint32_t frame) const { auto flag = (frame >> 15) & 0x3; Spadic::MsInfoType infotype; @@ -231,8 +26,11 @@ namespace cbm::algo::trd return infotype; } + template Spadic::MsInfoType UnpackMS<0x01>::digestBufInfoFlags(const std::uint32_t frame) const; + // ---- digestInfoMsg ---- - void UnpackMS::digestInfoMsg(const std::uint32_t frame) const + template<uint8_t sys_ver> + void UnpackMS<sys_ver>::digestInfoMsg(const std::uint32_t frame) const { /// Save info message if needed. //if (fOptOutBVec) { fOptOutBVec->emplace_back(std::make_pair(ctx.fLastFulltime, frame)); } @@ -240,8 +38,11 @@ namespace cbm::algo::trd // "Spadic_Info_Types"; } + template void UnpackMS<0x01>::digestInfoMsg(const std::uint32_t frame) const; + // ---- digestInfoMsg ---- - void UnpackMS::digestMsFlags(const std::uint16_t flags, UnpackMonitorData& monitor) const + template<uint8_t sys_ver> + void UnpackMS<sys_ver>::digestMsFlags(const std::uint16_t flags, UnpackMonitorData& monitor) const { if (flags & static_cast<std::uint16_t>(fles::MicrosliceFlags::CrcValid)) { monitor.fNumCrcValidFlags++; @@ -257,8 +58,12 @@ namespace cbm::algo::trd } } + template void UnpackMS<0x01>::digestMsFlags(const std::uint16_t flags, UnpackMonitorData& monitor) const; + template void UnpackMS<0x10>::digestMsFlags(const std::uint16_t flags, UnpackMonitorData& monitor) const; + // ---- extractSample ---- - std::float_t UnpackMS::extractAvgSample(size_t* adcbuffer, size_t* nadcbits) const + template<uint8_t sys_ver> + std::float_t UnpackMS<sys_ver>::extractAvgSample(size_t* adcbuffer, size_t* nadcbits) const { // can not extract samples from a buffer with less than 9 bits assert(*nadcbits >= 9); @@ -284,8 +89,11 @@ namespace cbm::algo::trd return sample; } + template std::float_t UnpackMS<0x01>::extractAvgSample(size_t* adcbuffer, size_t* nadcbits) const; + // ---- extractSample ---- - std::int16_t UnpackMS::extractSample(size_t* adcbuffer, size_t* nadcbits) const + template<uint8_t sys_ver> + std::int16_t UnpackMS<sys_ver>::extractSample(size_t* adcbuffer, size_t* nadcbits) const { // can not extract samples from a buffer with less than 9 bits assert(*nadcbits >= 9); @@ -305,8 +113,11 @@ namespace cbm::algo::trd return sample; } + template std::int16_t UnpackMS<0x01>::extractSample(size_t* adcbuffer, size_t* nadcbits) const; + // ---- getInfoType ---- - Spadic::MsInfoType UnpackMS::getInfoType(const std::uint32_t frame) const + template<uint8_t sys_ver> + Spadic::MsInfoType UnpackMS<sys_ver>::getInfoType(const std::uint32_t frame) const { // Set first 20 bits to 1 for the mask size_t mask = 0x000FFFFF; @@ -345,8 +156,11 @@ namespace cbm::algo::trd } } + template Spadic::MsInfoType UnpackMS<0x01>::getInfoType(const std::uint32_t frame) const; + // ---- getMessageType ---- - Spadic::MsMessageType UnpackMS::getMessageType(const std::uint32_t frame) const + template<uint8_t sys_ver> + Spadic::MsMessageType UnpackMS<sys_ver>::getMessageType(const std::uint32_t frame) const { std::uint32_t checkframe = frame; checkframe &= 0xffffff; @@ -379,8 +193,11 @@ namespace cbm::algo::trd } } + template Spadic::MsMessageType UnpackMS<0x01>::getMessageType(const std::uint32_t frame) const; + // ---- getTsMsb ---- - std::uint8_t UnpackMS::getTsMsb(const std::uint32_t frame, UnpackMonitorData& monitor) const + template<uint8_t sys_ver> + std::uint8_t UnpackMS<sys_ver>::getTsMsb(const std::uint32_t frame, UnpackMonitorData& monitor) const { if ((frame & 0xf) > 0) return -2; // if a 'error' ts_msb is received the tsmsb value is not correct. To not mess up the counting -2 is returned. @@ -404,8 +221,53 @@ namespace cbm::algo::trd return tsmsb[0]; } - // ---- makeDigi ---- - CbmTrdDigi UnpackMS::makeDigi(CbmTrdRawMessageSpadic raw, MsContext& ctx) const + template std::uint8_t UnpackMS<0x01>::getTsMsb(const std::uint32_t frame, UnpackMonitorData& monitor) const; + + + // method definition for specialization + template<uint8_t sys_ver> + CbmTrdDigi UnpackMS<sys_ver>::makeDigi(Spadic::FexWord<sys_ver> fw, size_t fMsStartTimeRel) const + { + return CbmTrdDigi(); + } + + // ---- makeDigi sys_ver <0x10> ---- + template<> + CbmTrdDigi UnpackMS<0x10>::makeDigi(Spadic::FexWord<0x10> fw, size_t fMsStartTimeRel) const + { + auto rawTriggerType = static_cast<Spadic::eTriggerType>(fw.ht); + auto triggerType = GetDigiTriggerType(rawTriggerType); + + int32_t errClass = 0; + + // Get the address of the originating spadic + const UnpackCrobPar& crobPar = fParams.fCrobParams.at(0); + const UnpackElinkPar& elinkPar = crobPar.fElinkParams.at(fw.elink); + const uint32_t asicAddress = elinkPar.fAddress; + + // Get the channel id on the module + int32_t padChNr = elinkPar.fChanAddress.at(fw.channel); + + // Get the time information and apply the necessary correction + uint64_t time = (fw.timestamp - fw.prec_time) * fAsicClockCycle + fMsStartTimeRel; + time -= elinkPar.fTimeOffset; + + auto energy = fw.maxAdc * fParams.fMaxAdcToEnergyCal; + + // Get the unique module id from the asic address + int32_t uniqueModuleId = asicAddress / 1000; + + CbmTrdDigi digi = CbmTrdDigi(padChNr, uniqueModuleId, energy, time, triggerType, errClass); + + // If the message was flagged as multi hit, forward this info to the digi + if (fw.mh != 0) digi.SetTriggerType(CbmTrdDigi::eTriggerType::kMulti); + + return digi; + } + + // ---- makeDigi from raw ---- + template<uint8_t sys_ver> + CbmTrdDigi UnpackMS<sys_ver>::makeDigi(CbmTrdRawMessageSpadic raw, MsContext& ctx) const { // Extract the trigger type and translate it to the digi enum auto rawTriggerType = static_cast<Spadic::eTriggerType>(raw.GetHitType()); @@ -454,9 +316,12 @@ namespace cbm::algo::trd return digi; } + template CbmTrdDigi UnpackMS<0x01>::makeDigi(CbmTrdRawMessageSpadic raw, MsContext& ctx) const; + // ---- makeRaw ---- - CbmTrdRawMessageSpadic UnpackMS::makeRaw(const std::uint32_t frame, std::uint16_t criId, std::uint8_t crobId, - std::uint16_t elinkId, std::uint8_t istream, MsContext& ctx) const + template<uint8_t sys_ver> + CbmTrdRawMessageSpadic UnpackMS<sys_ver>::makeRaw(const std::uint32_t frame, std::uint16_t criId, std::uint8_t crobId, + std::uint16_t elinkId, std::uint8_t istream, MsContext& ctx) const { auto chId = static_cast<std::uint8_t>(((frame >> 17) & 0xf)); auto timestamp = static_cast<std::uint8_t>((frame >> 9) & 0xff); @@ -472,9 +337,14 @@ namespace cbm::algo::trd return CbmTrdRawMessageSpadic(chId, elinkId, crobId, criId, hitType, nsamples, multihit, fulltime, samples); } + template CbmTrdRawMessageSpadic UnpackMS<0x01>::makeRaw(const std::uint32_t frame, std::uint16_t criId, + std::uint8_t crobId, std::uint16_t elinkId, + std::uint8_t istream, MsContext& ctx) const; + // ---- GetDigiTriggerType ---- - CbmTrdDigi::eTriggerType UnpackMS::GetDigiTriggerType(Spadic::eTriggerType tt) + template<uint8_t sys_ver> + CbmTrdDigi::eTriggerType UnpackMS<sys_ver>::GetDigiTriggerType(Spadic::eTriggerType tt) { // Shift self trigger to digi selftrigger // Shift neighbour trigger to digi neighbour @@ -488,8 +358,12 @@ namespace cbm::algo::trd } } + template CbmTrdDigi::eTriggerType UnpackMS<0x01>::GetDigiTriggerType(Spadic::eTriggerType tt); + template CbmTrdDigi::eTriggerType UnpackMS<0x10>::GetDigiTriggerType(Spadic::eTriggerType tt); + // --- GetCharge ---- - float_t UnpackMS::GetMaxAdcValue(const std::vector<std::int16_t>* samples) const + template<uint8_t sys_ver> + float_t UnpackMS<sys_ver>::GetMaxAdcValue(const std::vector<std::int16_t>* samples) const { // Safety for corrupted input samples assert(samples->size() >= fPeakingBinMin); @@ -515,8 +389,11 @@ namespace cbm::algo::trd return charge > 0 ? charge : 0; } + template float_t UnpackMS<0x01>::GetMaxAdcValue(const std::vector<std::int16_t>* samples) const; + // ---- GetBaseline ---- - float_t UnpackMS::GetBaseline(const std::vector<std::int16_t>* samples) const + template<uint8_t sys_ver> + float_t UnpackMS<sys_ver>::GetBaseline(const std::vector<std::int16_t>* samples) const { // The spadic 2.2 has a functionality that an average baseline can be written to the first sample. // So first we have to check if this is active. @@ -534,6 +411,248 @@ namespace cbm::algo::trd return baseline; } } + template float_t UnpackMS<0x01>::GetBaseline(const std::vector<std::int16_t>* samples) const; + + // ---- Algorithm execution sys_ver >= 0x10 --------------------------------------------- + template<std::uint8_t sys_ver> + typename UnpackMS<sys_ver>::Result_t UnpackMS<sys_ver>::operator()(const uint8_t* msContent, + const fles::MicrosliceDescriptor& msDescr, + const uint64_t tTimeslice) const + { + Result_t result = {}; + + + // Digest the flags from the µSlice + digestMsFlags(msDescr.flags, result.second); + + size_t fMsStartTimeRel = (msDescr.idx - tTimeslice) / fAsicClockCycle; + + // Get bytes per word used for the given system version + constexpr std::uint8_t bytes = Spadic::BytesPerWord<sys_ver>(); + + auto mssize = msDescr.size; + std::uint32_t nwords = mssize / bytes; + + const Spadic::NByteContainer<bytes>* bp = reinterpret_cast<const Spadic::NByteContainer<bytes>*>(msContent); + + for (std::uint32_t iword = 0; iword < nwords; ++iword) { + Spadic::NByteContainer<bytes> bCont = bp[iword]; + Spadic::FexWord<sys_ver> fw(bCont); + if (fw.ht != 0) { + result.first.push_back(makeDigi(fw, fMsStartTimeRel)); + } + } + return result; + } + + template typename UnpackMS<0x10>::Result_t UnpackMS<0x10>::operator()(const uint8_t* msContent, + const fles::MicrosliceDescriptor& msDescr, + const uint64_t tTimeslice) const; + // -------------------------------------------------------------------------- + + // ---- Algorithm execution sys_ver - 0x01 --------------------------------------------- + template<> + typename UnpackMS<0x01>::Result_t UnpackMS<0x01>::operator()(const uint8_t* msContent, + const fles::MicrosliceDescriptor& msDescr, + const uint64_t tTimeslice) const + { + // --- Output data + Result_t result = {}; + + MsContext ctx = {}; + + // Get the µSlice starttime relative to the timeslice starttime (constant is clock length of Spadic in ns) + ctx.fMsStartTimeRelCC = (msDescr.idx - tTimeslice) / fAsicClockCycle; + + // We only want to count on TS_MSB per Stream per TS_MSB package (each eLink sends its own TS_MSB frame) + // so we store the current TS_MSB and compare it to the incoming. + std::int8_t currTsMsb = 0; + + // Reset the TS_MSB counter for the new µSlice we unpack + ctx.fNrTsMsbVec.resize(fStreamsPerWord); + + + // Get the µslice size in bytes to calculate the number of completed words + auto mssize = msDescr.size; + + // Get the hardware ids from which the current µSlice is coming + std::uint8_t crobId = 0; + auto criId = msDescr.eq_id; + + // Digest the flags from the µSlice + digestMsFlags(msDescr.flags, result.second); + + // Get the number of complete words in the input MS buffer. + std::uint32_t nwords = mssize / fBytesPerWord; + + // We have 32 bit spadic frames in this readout version + const auto mscontent = reinterpret_cast<const size_t*>(msContent); + + result.first.reserve(nwords); + + // Loop over all 64bit-Spadic-Words in the current µslice + for (std::uint32_t istream = 0; istream < fStreamsPerWord; istream++) { + currTsMsb = -1; + for (std::uint32_t iword = 0; iword < nwords; ++iword) { + // Access the actual word from the pointer + size_t word = static_cast<size_t>(mscontent[iword]); + + // Access the actual frame[iframe] from the word. (see fStreamsPerWord) + std::uint32_t frame = (word >> (32 * istream)) & 0xffffffff; + + // Get the type of the frame + auto kWordtype = getMessageType(frame); + + // In case we saw any other word than an EPO(TS_MSB) reset the flag, + // such that we again increase by one if an EPO frame arrives + auto elinkId = (frame >> 24) & 0x3f; + + switch (kWordtype) { + case Spadic::MsMessageType::kEPO: { + auto tsmsb = getTsMsb(frame, result.second); + if (((tsmsb - currTsMsb) & 0x3f) == 1 || currTsMsb == -1) ctx.fNrTsMsbVec.at(istream)++; + currTsMsb = tsmsb; + result.second.fNumEpochMsgs++; + break; + // FIXME in the kEPO msg we also have further flags that should be extracted + } + case Spadic::MsMessageType::kSOM: { + // Create the raw message and fill it with all information we can get from the SOM msg + CbmTrdRawMessageSpadic raw = makeRaw(frame, criId, crobId, elinkId, istream, ctx); + + // FIXME since we can not deduce the sample position from the messages we need in + // future some parameter handling here to place the samples at the correct position + // 6 adc bits are stored in the som message + size_t nadcbits = 6; + size_t nadcbitstotal = 6; + // Get the first bits from the adc signal + size_t adcbuffer = frame & 0x3f; + size_t isample = 0; + size_t irda = 0; + + // Now lets check if we have rda words following our som + iword++; + word = static_cast<size_t>(mscontent[iword]); + frame = (word >> (32 * istream)) & 0xffffffff; + + // The maximum amount of samples (32) equals to 12 RDA messages + while (getMessageType(frame) == Spadic::MsMessageType::kRDA && irda < 12) { + // We have to count the number of rda frames for sample reconstruction in eom + irda++; + // Ensure that we are on the correct eLink + elinkId = (frame >> 24) & 0x3f; + if (elinkId != raw.GetElinkId()) { + result.second.fNumElinkMis++; + } + + // We have 22 adc bits per RDA word lets add them to the buffer... + adcbuffer <<= 22; + adcbuffer |= static_cast<size_t>((frame & 0x3fffff)); + // and increase the adcbit counter by 22 bits + nadcbits += 22; + nadcbitstotal += 22; + // If we have 9 or more samples stored we can extract n samples + while (nadcbits >= 9) { + raw.IncNrSamples(); + // In case the avg baseline feature was used we need to take special care of sample 0 + if (isample == 0 && fParams.fUseBaselineAvg) + raw.SetSample(extractAvgSample(&adcbuffer, &nadcbits), isample); + else + raw.SetSample(extractSample(&adcbuffer, &nadcbits), isample); + isample++; + } + iword++; + word = static_cast<size_t>(mscontent[iword]); + frame = (word >> (32 * istream)) & 0xffffffff; + } + + if (getMessageType(frame) == Spadic::MsMessageType::kEOM) { + // Ensure that we are on the correct eLink + elinkId = (frame >> 24) & 0x3f; + if (elinkId != raw.GetElinkId()) { + result.second.fNumElinkMis++; + } + + // Number of samples indicator = nsamples % 4 + std::uint8_t nsamplesindicator = (frame >> 18) & 0x3; + // Number of required samples as indicated + std::uint64_t nreqsamples = (nadcbitstotal + 18) / 9; + std::uint8_t nn = nreqsamples % 4; + for (std::uint8_t itest = 0; itest < 3; itest++) { + if (nn == nsamplesindicator || nreqsamples == 0) break; + nreqsamples--; + nn = nreqsamples % 4; + } + + // There is a chance that the nsamplesindicator bits are corrupted, + // here we check that we do not try to extract more adcbits than actually are streamed + if (nreqsamples >= isample) { + // Now extract from the above values the number of required adc bits from the eom + std::int8_t nrequiredbits = (nreqsamples - isample) * 9 - nadcbits; + adcbuffer <<= nrequiredbits; + + // The eom carries at maximum 18 adcbits + adcbuffer |= static_cast<size_t>((frame & 0x3ffff) >> (18 - nrequiredbits)); + nadcbits += nrequiredbits; + + while (nadcbits >= 9) { + raw.IncNrSamples(); + raw.SetSample(extractSample(&adcbuffer, &nadcbits), isample); + isample++; + } + } + else { + result.second.fNumCorruptEom++; + } + result.second.fNumCreatedRawMsgs++; + + // the message is done and the raw message container should contain everything we need. + // So now we can call makeDigi(). Nevertheless there is a chance for a corrupted message, + // which ends up with 0 samples so we have to check for it. + if (isample > 0) result.first.push_back(makeDigi(raw, ctx)); + } + else { + // We move the word counter backwards by one, such that the unexpected message can correctly be digested + iword--; + result.second.fNumMissingEom++; + } + break; + } + case Spadic::MsMessageType::kRDA: { + result.second.fNumWildRda++; + break; + } + case Spadic::MsMessageType::kEOM: { + result.second.fNumWildEom++; + break; + } + case Spadic::MsMessageType::kINF: { + result.second.fNumCreatedInfoMsgs++; + digestInfoMsg(frame); + break; + } + case Spadic::MsMessageType::kNUL: { + // last word in Microslice is 0. + if (iword != (nwords - 1) || (istream != (fStreamsPerWord - 1))) { + result.second.fNumWildNul++; + } + break; + } + case Spadic::MsMessageType::kUNK: { + result.second.fNumUnknownWords++; + return result; + break; + } + default: + // We have varying msg types for different versions of the message format. + // Hence, to not produce compiler warnings we have a "default break;" here. + break; + } + } + } + return result; + } + // -------------------------------------------------------------------------- } // namespace cbm::algo::trd diff --git a/algo/detectors/trd/UnpackMS.h b/algo/detectors/trd/UnpackMS.h index 63eaa5e12a5c6aa5f012551b88516f1fe552faf9..59d29bdf2b28721ce43d8bc969e99082a7d60735 100644 --- a/algo/detectors/trd/UnpackMS.h +++ b/algo/detectors/trd/UnpackMS.h @@ -1,10 +1,11 @@ /* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt SPDX-License-Identifier: GPL-3.0-only - Authors: Pascal Raisig, Dominik Smith [committer] */ + Authors: Pascal Raisig, Dominik Smith [committer], David Schledt */ #pragma once #include "CbmTrdDigi.h" +#include "CbmTrdFexMessageSpadic.h" #include "CbmTrdRawMessageSpadic.h" #include "MicrosliceDescriptor.hpp" #include "Timeslice.hpp" @@ -97,15 +98,16 @@ namespace cbm::algo::trd ** @since 31 January 2023 ** @brief Unpack algorithm for TRD **/ + template<uint8_t sys_ver> class UnpackMS : public UnpackMSBase<CbmTrdDigi, UnpackMonitorData> { public: /** @brief Construct from parameters **/ - UnpackMS(const UnpackPar& pars); + UnpackMS(const UnpackPar& pars) : fParams(pars) {} /** @brief Destructor **/ - ~UnpackMS() override; + ~UnpackMS() override = default; /** @brief Algorithm execution @@ -220,6 +222,12 @@ namespace cbm::algo::trd **/ CbmTrdDigi makeDigi(CbmTrdRawMessageSpadic raw, MsContext& ctx) const; + /** + ** @brief Create an actual digi from the fex message + ** @param fw + **/ + CbmTrdDigi makeDigi(Spadic::FexWord<sys_ver> fw, size_t fMsStartTimeRel) const; + /** ** @brief Get the Bin Time Shift value ** @param samples diff --git a/core/data/trd/CbmTrdFexMessageSpadic.h b/core/data/trd/CbmTrdFexMessageSpadic.h index 326813b814052150b1c10798e159447c1a377fdc..ba8c07d36845a07962448e489245b677cc85beb1 100644 --- a/core/data/trd/CbmTrdFexMessageSpadic.h +++ b/core/data/trd/CbmTrdFexMessageSpadic.h @@ -26,13 +26,12 @@ namespace Spadic template<size_t bytes> struct NByteContainer { - std::array<std::uint8_t, bytes> b; + std::uint8_t b[bytes]; operator std::uint64_t() { - std::uint64_t r = 0; - for (std::uint8_t i = 0; i < bytes; ++i) - r |= (std::uint64_t) b[i] << (8 * i); + std::uint64_t r; + memcpy(&r, b, sizeof(long)); return r; } @@ -97,16 +96,18 @@ namespace Spadic constexpr int mhs = trs - 3; constexpr int pts = mhs - 5; + std::uint64_t w = word; + ht = (word >> 62) & 0x3; // TODO ext trigger if (ht != 0) { - elink = (word >> els) & 0xff; - channel = (word >> chs) & 0xf; - maxAdc = (word >> maxs) & 0x1ff; - iMA = (word >> imas) & 0x3; - timesample = (word >> trs) & 0x1ff; - mh = (word >> mhs) & 0x3; - prec_time = (float) ((word >> pts) & 0x1f) / float(1 << 4); - timestamp = word & 0x1fffff; + elink = (w >> els) & 0xff; + channel = (w >> chs) & 0xf; + maxAdc = (w >> maxs) & 0x1ff; + iMA = (w >> imas) & 0x3; + timesample = (w >> trs) & 0x1ff; + mh = (w >> mhs) & 0x3; + prec_time = (float) ((w >> pts) & 0x1f) / float(1 << 4); + timestamp = w & 0x1fffff; } } }; diff --git a/macro/run/run_unpack_online.C b/macro/run/run_unpack_online.C index 7eb0a65d56c1e42c5060976eb7d4ce02e77b01f8..fbd6eff2661c1e9272f078b056262e6160542345 100644 --- a/macro/run/run_unpack_online.C +++ b/macro/run/run_unpack_online.C @@ -260,6 +260,10 @@ void run_unpack_online(std::vector<std::string> publisher = {"tcp://localhost:55 cbmsetup->GetGeoTag(ECbmModuleId::kTrd, trdsetuptag); // trd1Dconfig = std::make_shared<CbmTrdUnpackConfig>(trdsetuptag.Data(), runid); trd1Dconfig = std::make_shared<CbmTrdUnpackConfig>(trdsetuptag.Data()); + if (2724 <= runid) { + /// mCBM 2024 + trdsetuptag = "v24b_mcbm"; + } if (trd1Dconfig) { trd1Dconfig->SetDoWriteOutput(); // Activate the line below to write Trd1D digis to a separate "TrdSpadicDigi" branch. Can be used to separate between Fasp and Spadic digis diff --git a/macro/run/run_unpack_tsa.C b/macro/run/run_unpack_tsa.C index 55bcb30dc01d537995f532295f1332024aa07318..efa7317878d9ef8af54d55830c1440bce14a1f65 100644 --- a/macro/run/run_unpack_tsa.C +++ b/macro/run/run_unpack_tsa.C @@ -286,6 +286,10 @@ void run_unpack_tsa(std::vector<std::string> infile = {"test.tsa"}, UInt_t runid cbmsetup->GetGeoTag(ECbmModuleId::kTrd, trdsetuptag); // trd1Dconfig = std::make_shared<CbmTrdUnpackConfig>(trdsetuptag.Data(), runid); trd1Dconfig = std::make_shared<CbmTrdUnpackConfig>(trdsetuptag.Data()); + if (2724 <= runid) { + /// mCBM 2024 + trdsetuptag = "v24b_mcbm"; + } if (trd1Dconfig) { trd1Dconfig->SetDoWriteOutput(); // Activate the line below to write Trd1D digis to a separate "TrdSpadicDigi" branch. Can be used to separate between Fasp and Spadic digis