CbmRoot
Loading...
Searching...
No Matches
sts/UnpackMS.cxx
Go to the documentation of this file.
1/* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Pierre-Alain Loizeau, Volker Friese [committer] */
4
5#include "UnpackMS.h"
6
8#include "StsRecoUtils.h"
9#include "StsXyterMessage.h"
10
11#include <cassert>
12#include <cmath>
13#include <cstdint>
14#include <utility>
15#include <vector>
16
17using std::unique_ptr;
18using std::vector;
19
20namespace cbm::algo::sts
21{
22
23 UnpackMS::UnpackMS(const UnpackPar& pars) : fParams(pars) {}
24 UnpackMS::~UnpackMS() = default;
25
26 // ---- Algorithm execution ---------------------------------------------
27 UnpackMS::Result_t UnpackMS::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
28 const uint64_t tTimeslice) const
29 {
30 // --- Output data
31 Result_t result = {};
32
33 // --- Current Timeslice start time in epoch units. Note that it is always a multiple of epochs
34 // --- and the epoch is a multiple of ns.
35 TimeSpec time;
36 const uint64_t epochLengthInNs = fkEpochLength * fkClockCycleNom / fkClockCycleDen;
37 time.currentTsTime = tTimeslice / epochLengthInNs;
38
39 // --- Current TS_MSB epoch cycle
40 auto const msTime = msDescr.idx; // Unix time of MS in ns
41 time.currentCycle = std::ldiv(msTime, fkCycleLength).quot;
42
43 // --- Number of messages in microslice
44 auto msSize = msDescr.size;
45 if (msSize % sizeof(stsxyter::Message) != 0) {
46 L_(error) << "Invalid microslice size: " << msSize;
47 std::get<1>(result).fNumErrInvalidMsSize++;
48 return result;
49 }
50 const uint32_t numMessages = msSize / sizeof(stsxyter::Message);
51 if (numMessages < 2) {
52 L_(error) << "Microslice too small: " << numMessages;
53 std::get<1>(result).fNumErrInvalidMsSize++;
54 return result;
55 }
56
57 const u32 maxDigis = numMessages - 2; // -2 for the TS_MSB and EPOCH messages
58 std::get<0>(result).reserve(maxDigis);
59
60 // --- Interpret MS content as sequence of SMX messages
61 auto message = reinterpret_cast<const stsxyter::Message*>(msContent);
62
63 // --- The first message in the MS is expected to be of type EPOCH and can be ignored.
64 if (message[0].GetMessType() != stsxyter::MessType::Epoch) {
65 L_(error) << "First message in microslice is not of type EPOCH";
66 std::get<1>(result).fNumErrInvalidFirstMessage++;
67 return result;
68 }
69
70 // --- The second message must be of type ts_msb.
71 if (message[1].GetMessType() != stsxyter::MessType::TsMsb) {
72 L_(error) << "Second message in microslice is not of type TS_MSB";
73 std::get<1>(result).fNumErrInvalidFirstMessage++;
74 return result;
75 }
76 ProcessTsmsbMessage(message[1], time);
77
78 // --- Message loop
79 for (uint32_t messageNr = 2; messageNr < numMessages; messageNr++) {
80
81 // --- Action depending on message type
82 switch (message[messageNr].GetMessType()) {
83
85 ProcessHitMessage(message[messageNr], time, std::get<0>(result), std::get<1>(result), std::get<2>(result));
86 break;
87 }
89 ProcessTsmsbMessage(message[messageNr], time);
90 break;
91 }
92 default: {
93 std::get<1>(result).fNumNonHitOrTsbMessage++;
94 break;
95 }
96
97 } //? Message type
98
99 } //# Messages
100
101 return result;
102 }
103 // --------------------------------------------------------------------------
104
105
106 // ----- Process hit message --------------------------------------------
107 inline void UnpackMS::ProcessHitMessage(const stsxyter::Message& message, const TimeSpec& time,
108 vector<CbmStsDigi>& digiVec, UnpackMonitorData& monitor,
109 UnpackAuxData& aux) const
110 {
111
112 // --- Check eLink and get parameters
113 uint16_t elink = message.GetLinkIndexHitBinning();
114 if (elink >= fParams.fElinkParams.size()) {
115 monitor.fNumErrElinkOutOfRange++;
116 return;
117 }
118 const UnpackElinkPar& elinkPar = fParams.fElinkParams.at(elink);
119 uint32_t asicNr = elinkPar.fAsicNr;
120
121 // --- Check minimum adc cut
122 if (message.GetHitAdc() <= elinkPar.fAdcMinCut) {
123 return;
124 }
125
126 // --- Check for masked channel
127 const uint16_t msg_channel = message.GetHitChannel();
128 if (!elinkPar.fChanMask.empty() && elinkPar.fChanMask[msg_channel] == true) {
129 return;
130 }
131
132 // --- Hardware-to-software address
133 const auto maybe_channel = Module::ChannelInModule(msg_channel, asicNr);
134 if (!maybe_channel.has_value()) return;
135
136 // --- Expand time stamp to time within timeslice (in clock cycle)
137 uint64_t messageTime = message.GetHitTimeBinning() + time.currentEpochTime;
138
139 // --- Convert time stamp from clock cycles to ns. Round to nearest full ns.
140 messageTime = (messageTime * fkClockCycleNom + fkClockCycleDen / 2) / fkClockCycleDen;
141
142 // --- Correct ASIC-wise offsets
143 messageTime -= elinkPar.fTimeOffset;
144
145 // --- Apply walk correction if applicable
146 if (message.GetHitAdc() <= elinkPar.fWalk.size()) {
147 double walk = elinkPar.fWalk[message.GetHitAdc() - 1];
148 messageTime += walk;
149 }
150
151 // --- Charge
152 double charge = elinkPar.fAdcOffset + (message.GetHitAdc() - 1) * elinkPar.fAdcGain;
153
154 if (messageTime > CbmStsDigi::kMaxTimestamp) {
155 monitor.fNumErrTimestampOverflow++;
156 return;
157 }
158
159 // --- Create output digi
160 digiVec.emplace_back(elinkPar.fAddress, *maybe_channel, messageTime, charge);
161
162 if (fParams.fWriteAux) {
163 aux.fQaDigis.emplace_back(message.IsHitMissedEvts(), elinkPar.fAddress, *maybe_channel, messageTime, charge,
164 elink);
165 }
166 }
167 // --------------------------------------------------------------------------
168
169
170 // ----- Process an epoch (TS_MSB) message ------------------------------
171 inline void UnpackMS::ProcessTsmsbMessage(const stsxyter::Message& message, TimeSpec& time) const
172 {
173 // The compression of time is based on the hierarchy epoch cycle - epoch - message time.
174 // Cycles are counted from the start of Unix time and are multiples of an epoch (ts_msb).
175 // The epoch number is counted within each cycle. The time in the hit message is expressed
176 // in units of the readout clock cycle relative to the current epoch.
177 // The ts_msb message indicates the start of a new epoch. Its basic information is the epoch
178 // number within the current cycle. A cycle wrap resets the epoch number to zero, so it is
179 // indicated by the epoch number being smaller than the previous one (epoch messages are
180 // seemingly not consecutively in the data stream, but only if there are hit messages in between).
181 auto epoch = message.GetTsMsbValBinning();
182
183 // --- Cycle wrap
184 if (epoch < time.currentEpoch) time.currentCycle++;
185
186 // --- Update current epoch counter
187 time.currentEpoch = epoch;
188
189 // --- Calculate epoch time in clocks cycles relative to timeslice start time
191 }
192 // --------------------------------------------------------------------------
193
194
195} // namespace cbm::algo::sts
#define L_(level)
static constexpr uint32_t kMaxTimestamp
Definition CbmStsDigi.h:48
std::tuple< std::vector< Digi_t >, Monitor_t, Aux_t > Result_t
static std::optional< u16 > ChannelInModule(const u16 elink_chn, const u16 asic_idx)
Channel HW to SW conversion.
void ProcessTsmsbMessage(const stsxyter::Message &message, TimeSpec &time) const
Process an epoch message (TS_MSB)
static constexpr uint32_t fkClockCycleNom
UnpackPar fParams
Parameter container.
void ProcessHitMessage(const stsxyter::Message &message, const TimeSpec &time, std::vector< CbmStsDigi > &digiVec, UnpackMonitorData &monitor, UnpackAuxData &aux) const
Process a hit message.
static constexpr uint32_t fkClockCycleDen
Result_t operator()(const uint8_t *msContent, const fles::MicrosliceDescriptor &msDescr, const uint64_t tTimeslice) const override
Algorithm execution.
static constexpr uint64_t fkEpochsPerCycle
static constexpr uint64_t fkCycleLength
~UnpackMS() override
Destructor.
UnpackMS(const UnpackPar &pars)
Default constructor.
static constexpr uint64_t fkEpochLength
XPU_D bool IsHitMissedEvts() const
For Hit data: Returns Missed event flag (1 bit field)
XPU_D uint32_t GetTsMsbValBinning() const
For TS MSB data: Returns the TS MSB 29 bit field)
XPU_D uint16_t GetHitAdc() const
For Hit data: Returns ADC value (5 bit field)
XPU_D uint16_t GetHitChannel() const
For Hit data: Returns StsXYTER channel number (7 bit field)
XPU_D uint16_t GetLinkIndexHitBinning() const
XPU_D uint16_t GetHitTimeBinning() const
std::uint32_t u32
Definition Definitions.h:21
std::vector< QaDigi > fQaDigis
Structure to hold the current time information for the current microslice.
u64 currentEpochTime
Current epoch time relative to timeslice in clock cycles.
u64 currentTsTime
Unix time of timeslice in units of epoch length.
u64 currentCycle
Current epoch cycle.
u32 currentEpoch
Current epoch number within epoch cycle.
uint32_t fNumErrElinkOutOfRange
Elink not contained in parameters.
uint32_t fNumErrTimestampOverflow
Overflow in 64 bit time stamp.
bool fWriteAux
Write auxiliary data for module.
std::vector< UnpackElinkPar > fElinkParams
Parameters for each eLink.