Skip to content
Snippets Groups Projects
Commit ed99bb35 authored by David Schledt's avatar David Schledt Committed by Pierre-Alain Loizeau
Browse files

Add intermediate feature extraction format unpacker for the upcoming mCBM campaign

The code is implemented in a way that should make it easy to implement further revision in the format by using templates for the sys_ver.
parent bf5ea0c7
No related branches found
No related tags found
1 merge request!1704Add intermediate feature extraction format unpacker for the upcoming mCBM campaign
Pipeline #27887 passed
......@@ -134,7 +134,7 @@ SET_SOURCE_FILES_PROPERTIES(tof/etof/star_rhicf.c PROPERTIES COMPILE_FLAGS -Wno-
list(APPEND HEADERS base/CbmDigiData.h global/CbmDigiEvent.h global/CbmDigiTimeslice.h
bmon/CbmBmonDigiData.h sts/CbmStsDigiData.h much/CbmMuchDigiData.h rich/CbmRichDigiData.h trd/CbmTrdDigiData.h
tof/CbmTofDigiData.h psd/CbmPsdDigiData.h fsd/CbmFsdDigiData.h)
tof/CbmTofDigiData.h psd/CbmPsdDigiData.h fsd/CbmFsdDigiData.h trd/CbmTrdFexMessageSpadic.h)
set(LIBRARY_NAME CbmData)
set(LINKDEF ${LIBRARY_NAME}LinkDef.h)
......
/* Copyright (C) 2024 Goethe-University Frankfurt, Frankfurt
SPDX-License-Identifier: GPL-3.0-only
Authors: David Schledt [committer] */
#ifndef CbmTrdFexMessageSpadic_H
#define CbmTrdFexMessageSpadic_H
#include "fmt/format.h"
#include <array>
#include <stdexcept>
namespace Spadic
{
template<std::uint8_t sys_ver>
constexpr std::uint8_t BytesPerWord()
{
switch (sys_ver) {
case 0x01: return 8;
case 0x10: return 8;
default: return 0;
}
}
template<size_t bytes>
struct NByteContainer {
std::array<std::uint8_t, bytes> b;
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);
return r;
}
size_t range(std::uint8_t h, std::uint8_t l)
{
if (l > h) {
throw std::invalid_argument(fmt::format("Reverse ranges not supported : low={:#x} > high={:#x}", l, h));
}
// get high and low byte positions
std::uint16_t bh = h >> 3;
std::uint16_t bl = l >> 3;
// get number of bytes that need to be accessed
std::uint16_t rbytes = bh - bl;
if ((bh + 1) > bytes) {
throw std::invalid_argument(fmt::format("High value: out-of-range, got={:#x}, size={:#x}", h, (bytes * 8 - 1)));
}
if ((bl + 1) > bytes) {
throw std::invalid_argument(fmt::format("Low value: out-of-range, got={:#x}, size={:#x}", l, (bytes * 8 - 1)));
}
// calculate bit positions for high and low byte
std::uint16_t bits_in_h = h - (8 * bh - 1);
std::uint16_t bits_in_l = l - (8 * bl);
std::uint16_t mask_h = (1 << bits_in_h) - 1;
// assemble return value
size_t r = b[bl] >> bits_in_l;
if (bh != bl) r |= (b[bh] & mask_h) << (rbytes * 8);
for (int i = 1; i < rbytes; ++i)
r |= b[bl + i] << (i * 8);
return r;
}
};
// Define template specialisations for each system version
template<std::uint8_t sys_ver>
struct FexWord {
};
// sys_ver 0x10 (c.f.git.cbm.gsi.de/trd/reports/technical-notes/integrated-data-format)
template<>
struct FexWord<0x10> {
std::uint8_t elink;
std::uint8_t channel;
std::uint64_t timestamp;
float prec_time;
std::uint16_t maxAdc;
std::uint16_t timesample;
std::uint8_t iMA;
std::uint8_t ht;
std::uint8_t mh;
FexWord(NByteContainer<BytesPerWord<0x10>()> word)
{
constexpr int hts = 62;
constexpr int els = hts - 8;
constexpr int chs = els - 4;
constexpr int maxs = chs - 9;
constexpr int imas = maxs - 3;
constexpr int trs = imas - 9;
constexpr int mhs = trs - 3;
constexpr int pts = mhs - 5;
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;
}
}
};
} // namespace Spadic
#endif // CbmTrdFexMessageSpadic_H
......@@ -13,12 +13,12 @@
#include <Logger.h>
#include <RtypesCore.h>
#include <typeinfo>
#include <algorithm>
#include <bitset>
#include <cstdint>
#include <memory>
#include <typeinfo>
CbmTrdUnpackAlgoR::CbmTrdUnpackAlgoR(/* args */) : CbmTrdUnpackAlgoBaseR("CbmTrdUnpackAlgoR") {}
......@@ -35,7 +35,9 @@ CbmTrdUnpackAlgoR::GetParContainerRequest(std::string geoTag, std::uint32_t runI
// Digest the runId information in case of runId = 0 we use the default fall back
std::string runpath = "";
if (runId != 0) { runpath = ".run" + std::to_string(runId); }
if (runId != 0) {
runpath = ".run" + std::to_string(runId);
}
// Get .asic parameter container
temppath = basepath + runpath + ".asic" + ".par";
......@@ -75,7 +77,9 @@ void CbmTrdUnpackAlgoR::digestInfoMsg(const std::uint32_t frame, std::uint16_t c
std::uint16_t elinkId)
{
/// Save info message if needed.
if (fOptOutBVec) { fOptOutBVec->emplace_back(std::make_pair(fLastFulltime, frame)); }
if (fOptOutBVec) {
fOptOutBVec->emplace_back(std::make_pair(fLastFulltime, frame));
}
fNrCreatedInfoMsgs++;
Spadic::MsInfoType infotype = getInfoType(frame, criId, crobId, elinkId);
// "Spadic_Info_Types";
......@@ -95,19 +99,27 @@ void CbmTrdUnpackAlgoR::digestMsFlags(const std::uint16_t flags, std::uint16_t c
if (flags & static_cast<std::uint16_t>(fles::MicrosliceFlags::CrcValid)) {
fNrCrcValidFlags++;
if (fMonitor) { fMonitor->FillHisto(fles::MicrosliceFlags::CrcValid, moduleid); }
if (fMonitor) {
fMonitor->FillHisto(fles::MicrosliceFlags::CrcValid, moduleid);
}
}
if (flags & static_cast<std::uint16_t>(fles::MicrosliceFlags::OverflowFlim)) {
fNrOverflowFlimFlags++;
if (fMonitor) { fMonitor->FillHisto(fles::MicrosliceFlags::OverflowFlim, moduleid); }
if (fMonitor) {
fMonitor->FillHisto(fles::MicrosliceFlags::OverflowFlim, moduleid);
}
}
if (flags & static_cast<std::uint16_t>(fles::MicrosliceFlags::OverflowUser)) {
fNrOverflowUserFlags++;
if (fMonitor) { fMonitor->FillHisto(fles::MicrosliceFlags::OverflowUser, moduleid); }
if (fMonitor) {
fMonitor->FillHisto(fles::MicrosliceFlags::OverflowUser, moduleid);
}
}
if (flags & static_cast<std::uint16_t>(fles::MicrosliceFlags::DataError)) {
fNrDataErrorFlags++;
if (fMonitor) { fMonitor->FillHisto(fles::MicrosliceFlags::DataError, moduleid); }
if (fMonitor) {
fMonitor->FillHisto(fles::MicrosliceFlags::DataError, moduleid);
}
}
}
......@@ -304,6 +316,38 @@ void CbmTrdUnpackAlgoR::makeDigi(CbmTrdRawMessageSpadic raw)
digestOutput(std::move(digi), raw);
}
// ---- makeDigi ----
void CbmTrdUnpackAlgoR::makeDigi(Spadic::FexWord<0x10> fw, std::uint32_t criid)
{
auto rawTriggerType = static_cast<Spadic::eTriggerType>(fw.ht);
auto triggerType = CbmTrdRawToDigiBaseR::GetDigiTriggerType(rawTriggerType);
// Get the address of the originating spadic
auto asicAddress = getAsicAddress(criid, 0, fw.elink);
if (asicAddress) {
// Get the unique module id from the asic address
Int_t uniqueModuleId = asicAddress / 1000;
// Get the channel id on the module
auto padChNr = getChannelId(asicAddress, fw.elink, fw.channel);
// Store the full time information to last full-time member for error message handling
// Get the time information and apply the necessary correction
ULong64_t time = (fw.timestamp - fw.prec_time) * fSpadic->GetClockCycle() + fMsStartTimeRelCC;
auto energy = fSpadic->MaxAdcToEnergyCal(fw.maxAdc);
time -= fSystemTimeOffset;
auto digi = std::unique_ptr<CbmTrdDigi>(new CbmTrdDigi(padChNr, uniqueModuleId, energy, time, triggerType, 0));
// If the message was flagged as multi hit, forward this info to the digi
if (fw.mh != 0) digi->SetTriggerType(CbmTrdDigi::eTriggerType::kMulti);
fOutputVec.emplace_back(*std::move(digi));
}
}
// ---- makeRaw ----
CbmTrdRawMessageSpadic CbmTrdUnpackAlgoR::makeRaw(const std::uint32_t frame, std::uint16_t criId, std::uint8_t crobId,
std::uint16_t elinkId, std::uint8_t istream)
......@@ -339,32 +383,46 @@ bool CbmTrdUnpackAlgoR::unpack(const fles::Timeslice* ts, std::uint16_t icomp, U
// The UTC is already to large for storing it CbmTrdRawMessageSpadic due to a cast, caused by the multiplication with a double used in the raw message
fMsStartTimeRelCC = (msdesc.idx - fTsStartTime) / fSpadic->GetClockCycle();
// 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;
// Get the hardware ids from which the current µSlice is coming
std::uint8_t crobId = 0;
auto criId = msdesc.eq_id;
// Reset the TS_MSB counter for the new µSlice we unpack
fNrTsMsbVec.clear();
fNrTsMsbVec.resize(fStreamsPerWord);
// Digest the flags from the µSlice
digestMsFlags(msdesc.flags, criId, crobId);
const auto mspointer = ts->content(icomp, imslice);
const auto mscontent = reinterpret_cast<const size_t*>(mspointer);
if (msdesc.sys_ver == 0x10) {
return unpackFex<0x10>(msdesc, mscontent);
}
else {
return unpackRaw(msdesc, mscontent);
}
return unpackOk;
}
bool CbmTrdUnpackAlgoR::unpackRaw(const fles::MicrosliceDescriptor msdesc, const size_t* mscontent)
{
// Get the µslice size in bytes to calculate the number of completed words
auto mssize = msdesc.size;
// We have 32 bit spadic frames in this readout version
std::uint32_t nwords = mssize / fBytesPerWord;
// Get the hardware ids from which the current µSlice is coming
std::uint8_t crobId = 0;
auto criId = msdesc.eq_id;
// Digest the flags from the µSlice
digestMsFlags(msdesc.flags, criId, crobId);
// Get the number of complete words in the input MS buffer.
std::uint32_t nwords = mssize / fBytesPerWord;
const auto mspointer = ts->content(icomp, imslice);
bool unpackOk = true;
// 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;
// We have 32 bit spadic frames in this readout version
const auto mscontent = reinterpret_cast<const size_t*>(mspointer);
// Reset the TS_MSB counter for the new µSlice we unpack
fNrTsMsbVec.clear();
fNrTsMsbVec.resize(fStreamsPerWord);
// Loop over all 64bit-Spadic-Words in the current µslice
for (std::uint32_t istream = 0; istream < fStreamsPerWord; istream++) {
......@@ -540,4 +598,35 @@ bool CbmTrdUnpackAlgoR::unpack(const fles::Timeslice* ts, std::uint16_t icomp, U
return unpackOk;
}
template<std::uint8_t sys_ver>
bool CbmTrdUnpackAlgoR::unpackFex(const fles::MicrosliceDescriptor msdesc, const size_t* mscontent)
{
constexpr std::uint8_t bytes = Spadic::BytesPerWord<sys_ver>();
if constexpr (bytes == 0) {
// TODO log something
return false;
}
bool unpackOk = true;
// Get the µslice size in bytes to calculate the number of completed words
auto mssize = msdesc.size;
std::uint32_t nwords = mssize / bytes;
// Get the hardware ids from which the current µSlice is coming
std::uint8_t crobId = 0;
auto criId = msdesc.eq_id;
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) {
makeDigi(fw, criId);
}
}
return unpackOk;
}
template bool CbmTrdUnpackAlgoR::unpackFex<0x10>(const fles::MicrosliceDescriptor msdesc, const size_t* mscontent);
ClassImp(CbmTrdUnpackAlgoR)
......@@ -19,6 +19,7 @@
#ifndef CbmTrdUnpackAlgoR_H
#define CbmTrdUnpackAlgoR_H
#include "CbmTrdFexMessageSpadic.h"
#include "CbmTrdRawMessageSpadic.h"
#include "CbmTrdUnpackAlgoBaseR.h"
......@@ -29,10 +30,10 @@
#include <Rtypes.h> // for types
#include <RtypesCore.h>
#include <cmath>
#include <cstdint>
#include <vector>
#include <cmath>
class CbmTrdUnpackAlgoR : public CbmTrdUnpackAlgoBaseR {
......@@ -155,6 +156,15 @@ protected:
*/
void makeDigi(CbmTrdRawMessageSpadic raw);
/**
* @brief Create an actual digi from the fex message
*
* @param fw FexWord for a given sys_ver
* @param criid the eq_is of a FLIM channel
*/
void makeDigi(Spadic::FexWord<0x10> fw, std::uint32_t criid);
/** @brief Up to now we do not need this function for this algorithm */
bool setDerivedTsParameters(size_t /*itimeslice*/) { return true; }
......@@ -171,6 +181,11 @@ protected:
*/
bool unpack(const fles::Timeslice* ts, std::uint16_t icomp, UInt_t imslice);
bool unpackRaw(const fles::MicrosliceDescriptor msdesc, const size_t* mscontent);
template<std::uint8_t sys_ver>
bool unpackFex(const fles::MicrosliceDescriptor msdesc, const size_t* mscontent);
// Parameter storage members
/** @brief Counter for the ts_msb used to reconstruct the time */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment