CbmRoot
Loading...
Searching...
No Matches
much/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
7#include "StsXyterMessage.h"
8
9#include <cassert>
10#include <cmath>
11#include <utility>
12#include <vector>
13
14using std::unique_ptr;
15using std::vector;
16
17namespace cbm::algo::much
18{
19
20 UnpackMS::UnpackMS(const UnpackPar& pars) : fParams(pars) {}
21 UnpackMS::~UnpackMS() = default;
22
23 // ---- Algorithm execution ---------------------------------------------
24 UnpackMS::Result_t UnpackMS::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
25 const uint64_t tTimeslice) const
26 {
27
28 // --- Output data
29 Result_t result = {};
30
31 TimeSpec time;
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 const uint64_t epochLengthInNs = fkEpochLength * fkClockCycleNom / fkClockCycleDen;
36 time.currentTsTime = tTimeslice / epochLengthInNs;
37
38 // --- Current TS_MSB epoch cycle
39 auto const msTime = msDescr.idx; // Unix time of MS in ns
40 time.currentCycle = std::ldiv(msTime, fkCycleLength).quot;
41 time.currentEpoch = 0; // Needed to make each MS independent of the previous! Will be updated in message 1 if MS OK
42 time.currentEpochTime =
43 0; // Needed to make each MS independent of the previous! Will be updated in message 1 if MS OK
44
45 // --- Number of messages in microslice
46 auto msSize = msDescr.size;
47 if (msSize % sizeof(stsxyter::Message) != 0) {
48 std::get<1>(result).fNumErrInvalidMsSize++;
49 return result;
50 }
51 const uint32_t numMessages = msSize / sizeof(stsxyter::Message);
52 if (numMessages < 2) {
53 std::get<1>(result).fNumErrInvalidMsSize++;
54 return result;
55 }
56
57 const uint32_t 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 std::get<1>(result).fNumErrInvalidFirstMessage++;
66 return result;
67 }
68
69 // --- The second message must be of type ts_msb.
70 if (message[1].GetMessType() != stsxyter::MessType::TsMsb) {
71 std::get<1>(result).fNumErrInvalidFirstMessage++;
72 return result;
73 }
74 ProcessTsmsbMessage(message[1], time);
75
76 // --- Message loop
77 for (uint32_t messageNr = 2; messageNr < numMessages; messageNr++) {
78
79 // --- Action depending on message type
80 switch (message[messageNr].GetMessType()) {
81
83 ProcessHitMessage(message[messageNr], time, std::get<0>(result), std::get<1>(result));
84 break;
85 }
87 ProcessTsmsbMessage(message[messageNr], time);
88 break;
89 }
90 default: {
91 std::get<1>(result).fNumNonHitOrTsbMessage++;
92 break;
93 }
94
95 } //? Message type
96
97 } //# Messages
98
99 return result;
100 }
101 // --------------------------------------------------------------------------
102
103
104 // ----- Process hit message --------------------------------------------
105 inline void UnpackMS::ProcessHitMessage(const stsxyter::Message& message, const TimeSpec& time,
106 vector<CbmMuchDigi>& digiVec, UnpackMonitorData& monitor) const
107 {
108 // --- Check eLink and get parameters
109 uint16_t elink = message.GetLinkIndexHitBinning();
110 if (elink >= fParams.fElinkParams.size()) {
111 monitor.fNumErrElinkOutOfRange++;
112 return;
113 }
114 const UnpackElinkPar& elinkPar = fParams.fElinkParams.at(elink);
115 uint16_t channel = message.GetHitChannel();
116
117 // --- Check for masked channel
118 if (!elinkPar.fChanMask.empty() && elinkPar.fChanMask[channel] == true) {
119 return;
120 }
121
122 uint32_t address = (elinkPar.fAddress)[channel];
123
124 // --- Expand time stamp to time within timeslice (in clock cycle)
125 uint64_t messageTime = message.GetHitTimeBinning() + time.currentEpochTime;
126
127 // --- Convert time stamp from clock cycles to ns. Round to nearest full ns.
128 messageTime = (messageTime * fkClockCycleNom + fkClockCycleDen / 2) / fkClockCycleDen;
129
130 // --- Correct ASIC-wise offsets
131 messageTime -= elinkPar.fTimeOffset;
132
133 // --- Charge
134 double charge = message.GetHitAdc();
135
136 // --- Create output digi
137 digiVec.emplace_back(address, charge, messageTime);
138 }
139 // --------------------------------------------------------------------------
140
141
142 // ----- Process an epoch (TS_MSB) message ------------------------------
143 inline void UnpackMS::ProcessTsmsbMessage(const stsxyter::Message& message, TimeSpec& time) const
144 {
145 // The compression of time is based on the hierarchy epoch cycle - epoch - message time.
146 // Cycles are counted from the start of Unix time and are multiples of an epoch (ts_msb).
147 // The epoch number is counted within each cycle. The time in the hit message is expressed
148 // in units of the readout clock cycle relative to the current epoch.
149 // The ts_msb message indicates the start of a new epoch. Its basic information is the epoch
150 // number within the current cycle. A cycle wrap resets the epoch number to zero, so it is
151 // indicated by the epoch number being smaller than the previous one (epoch messages are
152 // seemingly not consecutively in the data stream, but only if there are hit messages in between).
153 auto epoch = message.GetTsMsbValBinning();
154
155 // --- Cycle wrap
156 if (epoch < time.currentEpoch) time.currentCycle++;
157
158 // --- Update current epoch counter
159 time.currentEpoch = epoch;
160
161 // --- Calculate epoch time in clocks cycles relative to timeslice start time
163 }
164 // --------------------------------------------------------------------------
165
166
167} // namespace cbm::algo::much
std::tuple< std::vector< Digi_t >, Monitor_t, Aux_t > Result_t
static constexpr uint32_t fkClockCycleDen
void ProcessTsmsbMessage(const stsxyter::Message &message, TimeSpec &time) const
Process an epoch message (TS_MSB)
UnpackMS(const UnpackPar &pars)
Construct with parameters.
void ProcessHitMessage(const stsxyter::Message &message, const TimeSpec &time, std::vector< CbmMuchDigi > &digiVec, UnpackMonitorData &monitor) const
Process a hit message.
static constexpr uint64_t fkEpochLength
~UnpackMS() override
Destructor.
static constexpr uint64_t fkEpochsPerCycle
Result_t operator()(const uint8_t *msContent, const fles::MicrosliceDescriptor &msDescr, const uint64_t tTimeslice) const override
Algorithm execution.
static constexpr uint32_t fkClockCycleNom
UnpackPar fParams
Parameter container.
static constexpr uint64_t fkCycleLength
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
uint64_t currentCycle
Current epoch cycle.
uint64_t currentEpochTime
Current epoch time relative to timeslice in clock cycles.
uint32_t currentEpoch
Current epoch number within epoch cycle.
uint64_t currentTsTime
Unix time of timeslice in units of epoch length.
uint32_t fNumErrElinkOutOfRange
Elink not contained in parameters.
Parameters required for the STS unpacking (specific to one component)
std::vector< UnpackElinkPar > fElinkParams
Parameters for each eLink.