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>
41 void append(uint64_t data50, uint8_t error,
bool incomplete);
49 enum class State :
int {
56 std::string asString(State
state)
const;
58 using uint10_t = uint16_t;
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();
79 void sendError(int8_t chip, uint32_t error)
const;
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";
124 sendError(
static_cast<int8_t
>(mSampaHeader.chipAddress()),
static_cast<uint32_t
>(
ErrorTruncatedDataUL));
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";
176 sendError(
static_cast<int8_t
>(mSampaHeader.chipAddress()),
static_cast<uint32_t
>(
ErrorBadIncompleteWord));
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";
209 sendError(
static_cast<int8_t
>(mSampaHeader.chipAddress()),
static_cast<uint32_t
>(
ErrorBadSyncPacket));
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";
231 sendError(
static_cast<int8_t
>(mSampaHeader.chipAddress()),
static_cast<uint32_t
>(
ErrorBadDataPacket));
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++) {
317 header += (
static_cast<uint64_t
>(mHeaderParts[
i]) << (10 *
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>
379void UserLogicElinkDecoder<CHARGESUM>::sendError(int8_t chip, uint32_t error)
const
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";
412 sendError(
static_cast<int8_t
>(mSampaHeader.chipAddress()),
static_cast<uint32_t
>(
ErrorBadClusterSize));
415 mErrorMessage =
"number of samples bigger than nof10BitWords";
416 sendError(
static_cast<int8_t
>(mSampaHeader.chipAddress()),
static_cast<uint32_t
>(
ErrorBadClusterSize));
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);
489 os <<
" empty handler ";
492 os << fmt::format(
"moreWords: {:5} moreSample: {:5} ",
493 e.moreWordsToRead(), e.moreSampleToRead());
496 os <<
" ERROR:" << e.errorMessage();
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)
SampaChannelHandler sampaChannelHandler
Piece of data for one Sampa channel.