12#ifndef O2_MCH_RAW_USER_LOGIC_ELINK_DECODER_H
13#define O2_MCH_RAW_USER_LOGIC_ELINK_DECODER_H
22#include <fmt/format.h>
23#include <fmt/printf.h>
34template <
typename CHARGESUM>
49 enum class State :
int {
56 std::string asString(State
state)
const;
63 const DsElecId& dsId()
const {
return mDsId; }
66 bool hasError()
const;
67 bool isHeaderComplete()
const {
return mHeaderParts.size() == 5; }
68 bool moreSampleToRead()
const {
return mSamplesToRead > 0; }
69 bool moreWordsToRead()
const {
return mNof10BitWords > 0; }
70 std::ostream& debugHeader()
const;
71 std::string errorMessage()
const;
72 bool append10(uint10_t data10);
73 void completeHeader();
74 void oneLess10BitWord();
75 void prepareAndSendCluster();
76 bool checkDataHeader();
80 void setClusterSize(uint10_t
value);
81 void setClusterTime(uint10_t
value);
82 void setHeaderPart(uint10_t data10);
83 void setSample(uint10_t
value);
84 void transition(State to);
90 std::vector<uint10_t> mSamples{};
91 std::vector<uint10_t> mHeaderParts{};
93 uint10_t mNof10BitWords{};
94 uint10_t mClusterSize{};
95 uint10_t mSamplesToRead{};
96 uint10_t mClusterTime{};
97 std::optional<std::string> mErrorMessage{std::nullopt};
106template <
typename CHARGESUM>
109 : mDsId{dsId}, mDecodedDataHandlers{decodedDataHandlers}, mState{State::WaitingSync}
113template <
typename CHARGESUM>
117 debugHeader() << (*this) << fmt::format(
" --> append50 {:013x} error {} incomplete {} data10={:d} {:d} {:d} {:d} {:d}\n", data50,
error, incomplete,
static_cast<uint10_t
>(data50 & 0x3FF),
static_cast<uint10_t
>((data50 & 0xFFC00) >> 10),
static_cast<uint10_t
>((data50 & 0x3FF00000) >> 20),
static_cast<uint10_t
>((data50 & 0xFFC0000000) >> 30),
static_cast<uint10_t
>((data50 & 0x3FF0000000000) >> 40));
122 debugHeader() << (*this) <<
" data truncated by User Logic --> resetting\n";
131 debugHeader() << (*this) << fmt::format(
" --> SYNC word found {:013x} state={}\n", data50,
asString(mState));
133 if (mState != State::WaitingHeader && mState != State::WaitingSync) {
135 debugHeader() << (*this) <<
" SYNC word found while decoding payload --> resetting\n";
141 transition(State::WaitingHeader);
149 for (
i = 0;
i < 5;
i++) {
150 bool packetEnd = append10(
static_cast<uint10_t
>(
data & 0x3FF));
154 debugHeader() << (*this) << fmt::format(
" --> incomplete {} packetEnd @i={}\n", incomplete, packetEnd,
i);
159 debugHeader() << (*this) <<
" reset due to hasError\n";
164 if (incomplete && packetEnd) {
166 debugHeader() << (*this) <<
" stop due to isIncomplete\n";
172 if (incomplete && (
i == 5) && (mState != State::WaitingSync)) {
174 debugHeader() << (*this) <<
" data packet end not found when isIncomplete --> resetting\n";
181template <
typename CHARGESUM>
194template <
typename CHARGESUM>
199 debugHeader() << (*this) << fmt::format(
" --> data10 {:d} state {}\n", data10,
asString(mState));
202 case State::WaitingHeader:
203 setHeaderPart(data10);
204 if (isHeaderComplete()) {
207 if (!
isSync(mSampaHeader.uint64())) {
208 mErrorMessage =
"badly formatted Sync packet";
213 if (mSampaHeader.isHeartbeat()) {
215 transition(State::WaitingHeader);
218 mErrorMessage =
"badly formatted Heartbeat packet";
223 if (checkDataHeader()) {
224 if (mSampaHeader.nof10BitWords() > 2) {
225 transition(State::WaitingSize);
230 mErrorMessage =
"badly formatted Data packet";
237 case State::WaitingSize:
238 if (moreWordsToRead()) {
239 setClusterSize(data10);
243 transition(State::WaitingTime);
245 mErrorMessage =
"WaitingSize but no more words";
249 case State::WaitingTime:
250 if (moreWordsToRead()) {
251 setClusterTime(data10);
252 transition(State::WaitingSample);
254 mErrorMessage =
"WaitingTime but no more words";
258 case State::WaitingSample:
259 if (moreSampleToRead()) {
262 if (!moreSampleToRead()) {
263 if (moreWordsToRead()) {
264 transition(State::WaitingSize);
266 transition(State::WaitingHeader);
277template <
typename CHARGESUM>
278std::string UserLogicElinkDecoder<CHARGESUM>::asString(State
s)
const
281 case State::WaitingSync:
282 return "WaitingSync";
284 case State::WaitingHeader:
285 return "WaitingHeader";
287 case State::WaitingSize:
288 return "WaitingSize";
290 case State::WaitingTime:
291 return "WaitingTime";
293 case State::WaitingSample:
294 return "WaitingSample";
302template <
typename CHARGESUM>
303void UserLogicElinkDecoder<CHARGESUM>::clear()
306 mHeaderParts.clear();
309 mErrorMessage = std::nullopt;
312template <
typename CHARGESUM>
313void UserLogicElinkDecoder<CHARGESUM>::completeHeader()
316 for (
auto i = 0;
i < mHeaderParts.size();
i++) {
320 mSampaHeader = SampaHeader(header);
321 mNof10BitWords = mSampaHeader.nof10BitWords();
324 debugHeader() << (*this) << fmt::format(
" --> completeHeader {:013X}\n", header);
325 debugHeader() <<
"\n";
328 while (std::getline(
s, part,
'\n')) {
329 debugHeader() << (*this) << part <<
"\n";
331 debugHeader() <<
"\n";
334 mHeaderParts.clear();
337template <
typename CHARGESUM>
338std::ostream& UserLogicElinkDecoder<CHARGESUM>::debugHeader()
const
340 return std::cout <<
"---";
343template <
typename CHARGESUM>
344std::string UserLogicElinkDecoder<CHARGESUM>::errorMessage()
const
346 return hasError() ? mErrorMessage.value() :
"";
349template <
typename CHARGESUM>
350bool UserLogicElinkDecoder<CHARGESUM>::hasError()
const
352 return mErrorMessage.has_value();
355template <
typename CHARGESUM>
359 debugHeader() << (*this) <<
" ---> reset\n";
362 transition(State::WaitingSync);
365template <
typename CHARGESUM>
369 debugHeader() << (*this) <<
" --> "
370 << fmt::format(
" calling channelHandler for {} ch {} = {}\n",
378template <
typename CHARGESUM>
382 debugHeader() << (*this) <<
" --> "
383 << fmt::format(
" calling errorHandler for {} chip {} = {}\n",
388 handler(mDsId, chip,
error);
392template <
typename CHARGESUM>
393void UserLogicElinkDecoder<CHARGESUM>::oneLess10BitWord()
395 mNof10BitWords = std::max(0, mNof10BitWords - 1);
398template <
typename CHARGESUM>
399void UserLogicElinkDecoder<CHARGESUM>::setClusterSize(
uint10_t value)
402 mClusterSize =
value;
406 mSamplesToRead = mClusterSize;
408 int checkSize = mSamplesToRead + 2 - mSampaHeader.nof10BitWords();
409 mErrorMessage = std::nullopt;
410 if (mClusterSize == 0) {
411 mErrorMessage =
"cluster size is zero";
415 mErrorMessage =
"number of samples bigger than nof10BitWords";
419 debugHeader() << (*this) <<
" --> size=" << mClusterSize <<
" samples=" << mSamplesToRead <<
"\n";
423template <
typename CHARGESUM>
424void UserLogicElinkDecoder<CHARGESUM>::setClusterTime(
uint10_t value)
427 mClusterTime =
value;
429 debugHeader() << (*this) <<
" --> time=" << mClusterTime <<
"\n";
433template <
typename CHARGESUM>
434void UserLogicElinkDecoder<CHARGESUM>::setHeaderPart(
uint10_t a)
437 mHeaderParts.emplace_back(
a);
439 debugHeader() << (*this) << fmt::format(
" --> readHeader {:08X}\n",
a);
443template <
typename CHARGESUM>
444void UserLogicElinkDecoder<CHARGESUM>::setSample(
uint10_t sample)
447 debugHeader() << (*this) <<
" --> sample = " << sample <<
"\n";
451 mSamples.emplace_back(sample);
453 if (mSamplesToRead == 0) {
454 prepareAndSendCluster();
458template <
typename CHARGESUM>
459void UserLogicElinkDecoder<CHARGESUM>::sendHBPacket()
463 handler(mDsId, mSampaHeader.chipAddress() % 2, mSampaHeader.bunchCrossingCounter());
467template <
typename CHARGESUM>
468void UserLogicElinkDecoder<CHARGESUM>::transition(State to)
471 debugHeader() << (*this) <<
" --> Transition from " <<
asString(mState) <<
" to " <<
asString(to) <<
"\n";
479 os << fmt::format(
"{} n10={:4d} size={:4d} t={:4d} ",
asString(
e.mDsId),
e.mNof10BitWords,
e.mClusterSize,
e.mClusterTime);
480 os << fmt::format(
"h({:2d})= ",
e.mHeaderParts.size());
481 for (
auto h :
e.mHeaderParts) {
482 os << fmt::format(
"{:4d} ",
h);
484 os << fmt::format(
"s({:2d})= ",
e.mSamples.size());
485 for (
auto s :
e.mSamples) {
486 os << fmt::format(
"{:4d} ",
s);
488 if (!
e.mDecodedDataHandlers.sampaChannelHandler) {
489 os <<
" empty handler ";
492 os << fmt::format(
"moreWords: {:5} moreSample: {:5} ",
493 e.moreWordsToRead(),
e.moreSampleToRead());
496 os <<
" ERROR:" <<
e.errorMessage();
unsigned short int uint16_t
std::vector< std::string > header
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error s
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char Directory with events to Events directory is and not inside events Show standalone event Run event generator maximum time bin of continuous for triggered for automatic continuous for automatic continuous triggered uint64_t
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char e
char error[CURL_ERROR_SIZE]
Class for time synchronization of RawReader instances.
void append(uint64_t data50, uint8_t error, bool incomplete)
Append 50 bits-worth of data.
friend std::ostream & operator<<(std::ostream &os, const o2::mch::raw::UserLogicElinkDecoder< T > &e)
UserLogicElinkDecoder(DsElecId dsId, DecodedDataHandlers decodedDataHandlers)
GLsizei const GLfloat * value
GLboolean GLboolean GLboolean GLboolean a
DualSampaChannelId getDualSampaChannelId(const SampaHeader &sh)
Return channel number (0..63)
@ ErrorBadHeartBeatPacket
@ ErrorUnexpectedSyncPacket
constexpr uint64_t sampaSyncWord
constexpr bool isSync(uint64_t data)
std::string asString(const SampaCluster &sc)
std::function< void(DsElecId dsId, int8_t chip, uint32_t error)> SampaErrorHandler
std::function< void(DsElecId dsId, uint8_t chip, uint20_t bunchCrossing)> SampaHeartBeatHandler
std::ostream & operator<<(std::ostream &stream, o2::InteractionRecord const &ir)
Piece of data for one Sampa channel.