Project
Loading...
Searching...
No Matches
BareElinkDecoder.h
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12#ifndef O2_MCH_RAW_BARE_ELINK_DECODER_H
13#define O2_MCH_RAW_BARE_ELINK_DECODER_H
14
15#include "Assertions.h"
19#include <bitset>
20#include <fmt/format.h>
21#include <fmt/printf.h>
22#include <functional>
23#include <iostream>
24#include <stdexcept>
25#include <vector>
26#include <cassert>
27
28namespace o2::mch::raw
29{
30
41template <typename CHARGESUM>
43{
44 public:
50 BareElinkDecoder(DsElecId dsId, DecodedDataHandlers decodedDataHandlers);
51
55
57 void append(bool bit0, bool bit1);
59
60 // /// linkId is the GBT id this Elink is part of
61 // uint8_t linkId() const;
62
66
68 int len() const;
69
72 void reset();
74
75 private:
77 enum class State : int {
78 LookingForSync, //< we've not found a sync yet
79 LookingForHeader, //< we've looking for a 50-bits header
80 ReadingNofSamples, //< we're (about to) read nof of samples
81 ReadingTimestamp, //< we're (about to) read a timestamp (for the current cluster)
82 ReadingSample, //< we're (about to) read a sample (for the current cluster)
83 ReadingClusterSum //< we're (about to) read a chargesum (for the current cluster)
84 };
85
86 std::string name(State state) const;
87 void appendOneBit(bool bit);
88 void changeState(State newState, int newCheckpoint);
89 void changeToReadingData();
90 void clear(int checkpoint);
91 void findSync();
92 void handlReadClusterSum();
93 void handleHeader();
94 void handleReadClusterSum();
95 void handleReadData();
96 void handleReadSample();
97 void handleReadTimestamp();
98 void oneLess10BitWord();
99 void process();
100 void sendCluster();
101 void sendHBPacket();
102 void softReset();
103
104 template <typename T>
105 friend std::ostream& operator<<(std::ostream& os, const o2::mch::raw::BareElinkDecoder<T>& e);
106
107 private:
108 DsElecId mDsId;
109 DecodedDataHandlers mDecodedDataHandlers; //< The structure with the callables that deal with the Sampa packets and the decoding errors
110 SampaHeader mSampaHeader; //< Current SampaHeader
111 uint64_t mBitBuffer; //< Our internal bit stream buffer
115
116 uint64_t mNofSync; //< Number of SYNC words we've seen so far
117 uint64_t mNofBitSeen; //< Total number of bits seen
118 uint64_t mNofHeaderSeen; //< Total number of headers seen
119 uint64_t mNofHammingErrors; //< Total number of hamming errors seen
120 uint64_t mNofHeaderParityErrors; //< Total number of header parity errors seen
122
123 uint64_t mCheckpoint; //< mask of the next state transition check to be done in process()
124 uint16_t mNof10BitsWordsToRead; //< number of 10 bits words to be read
125
126 uint10_t mClusterSize;
127 uint16_t mNofSamples;
128 uint16_t mTimestamp;
129 std::vector<uint16_t> mSamples;
130 uint32_t mClusterSum;
131 uint64_t mMask;
132
133 State mState; //< the state we are in
134};
135
136constexpr int HEADERSIZE = 50;
137
138std::string bitBufferString(const std::bitset<50>& bs, int imax);
139
140template <typename CHARGESUM>
142 DecodedDataHandlers decodedDataHandlers)
143 : mDsId{dsId},
144 mDecodedDataHandlers{decodedDataHandlers},
145 mSampaHeader{},
146 mBitBuffer{},
147 mNofSync{},
148 mNofBitSeen{},
149 mNofHeaderSeen{},
150 mNofHammingErrors{},
151 mNofHeaderParityErrors{},
152 mCheckpoint{(static_cast<uint64_t>(1) << HEADERSIZE)},
153 mNof10BitsWordsToRead{},
154 mClusterSize{},
155 mNofSamples{},
156 mTimestamp{},
157 mSamples{},
158 mClusterSum{},
159 mState{State::LookingForSync},
160 mMask{1}
161{
162}
163
164template <typename CHARGESUM>
166{
167 mNofBitSeen++;
168
169 mBitBuffer += bit * mMask;
170 mMask *= 2;
171
172 if (mMask == mCheckpoint) {
173 process();
174 }
175}
176
177template <typename CHARGESUM>
178void BareElinkDecoder<CHARGESUM>::append(bool bit0, bool bit1)
179{
180 appendOneBit(bit0);
181 appendOneBit(bit1);
182}
183
184template <typename CHARGESUM>
185void BareElinkDecoder<CHARGESUM>::changeState(State newState, int newCheckpoint)
186{
187 mState = newState;
188 clear(newCheckpoint);
189}
190
191template <typename CHARGESUM>
192void BareElinkDecoder<CHARGESUM>::clear(int checkpoint)
193{
194 mBitBuffer = 0;
195 mCheckpoint = static_cast<uint64_t>(1) << checkpoint;
196 mMask = 1;
197}
198
204template <typename CHARGESUM>
205void BareElinkDecoder<CHARGESUM>::findSync()
206{
207 assert(mState == State::LookingForSync);
208 if (mBitBuffer != sampaSyncWord) {
209 mBitBuffer >>= 1;
210 mMask /= 2;
211 return;
212 }
213 changeState(State::LookingForHeader, HEADERSIZE);
214 mNofSync++;
215}
216
217template <typename CHARGESUM>
218void BareElinkDecoder<CHARGESUM>::handleHeader()
219{
220 assert(mState == State::LookingForHeader);
221
222 mSampaHeader.uint64(mBitBuffer);
223
224 ++mNofHeaderSeen;
225
226 if (mSampaHeader.hasError()) {
227 ++mNofHammingErrors;
228 }
229
230 switch (mSampaHeader.packetType()) {
236 // data with a problem is still data, i.e. there will
237 // probably be some data words to read in...
238 // so we fallthrough the simple Data case
240 mNof10BitsWordsToRead = mSampaHeader.nof10BitWords();
241 changeState(State::ReadingNofSamples, 10);
242 break;
244 mNofSync++;
245 softReset();
246 break;
248 if (mSampaHeader.isHeartbeat()) {
249 sendHBPacket();
250 changeState(State::LookingForHeader, HEADERSIZE);
251 } else {
252 softReset();
253 }
254 break;
255 default:
256 throw std::logic_error("that should not be possible");
257 break;
258 }
259}
260
261template <typename CHARGESUM>
262void BareElinkDecoder<CHARGESUM>::handleReadClusterSum()
263{
264 mClusterSum = mBitBuffer;
265 oneLess10BitWord();
266 oneLess10BitWord();
267 sendCluster();
268 if (mNof10BitsWordsToRead) {
269 changeState(State::ReadingNofSamples, 10);
270 } else {
271 changeState(State::LookingForHeader, HEADERSIZE);
272 }
273}
274
275template <typename CHARGESUM>
276void BareElinkDecoder<CHARGESUM>::handleReadData()
277{
278 assert(mState == State::ReadingTimestamp || mState == State::ReadingSample);
279 if (mState == State::ReadingTimestamp) {
280 mTimestamp = mBitBuffer;
281 }
282 oneLess10BitWord();
283 changeToReadingData();
284}
285
286template <typename CHARGESUM>
287void BareElinkDecoder<CHARGESUM>::handleReadSample()
288{
289 mSamples.push_back(mBitBuffer);
290 if (mNofSamples > 0) {
291 --mNofSamples;
292 }
293 oneLess10BitWord();
294 if (mNofSamples) {
295 changeToReadingData();
296 } else {
297 sendCluster();
298 if (mNof10BitsWordsToRead) {
299 changeState(State::ReadingNofSamples, 10);
300 } else {
301 changeState(State::LookingForHeader, HEADERSIZE);
302 }
303 }
304}
305
306template <typename CHARGESUM>
307void BareElinkDecoder<CHARGESUM>::handleReadTimestamp()
308{
309 assert(mState == State::ReadingNofSamples);
310 oneLess10BitWord();
311 mNofSamples = mBitBuffer;
312 mClusterSize = mNofSamples;
313 changeState(State::ReadingTimestamp, 10);
314}
315
316template <typename CHARGESUM>
318{
319 return static_cast<int>(std::floor(log2(1.0 * mMask)) + 1);
320}
321
322template <typename CHARGESUM>
323std::string BareElinkDecoder<CHARGESUM>::name(State s) const
324{
325 switch (s) {
326 case State::LookingForSync:
327 return "LookingForSync";
328 break;
329 case State::LookingForHeader:
330 return "LookingForHeader";
331 break;
332 case State::ReadingNofSamples:
333 return "ReadingNofSamples";
334 break;
335 case State::ReadingTimestamp:
336 return "ReadingTimestamp";
337 break;
338 case State::ReadingSample:
339 return "ReadingSample";
340 break;
341 case State::ReadingClusterSum:
342 return "ReadingClusterSum";
343 break;
344 };
345}
346
347template <typename CHARGESUM>
348void BareElinkDecoder<CHARGESUM>::oneLess10BitWord()
349{
350 if (mNof10BitsWordsToRead > 0) {
351 --mNof10BitsWordsToRead;
352 }
353}
354
356template <typename CHARGESUM>
357void BareElinkDecoder<CHARGESUM>::process()
358{
359 switch (mState) {
360 case State::LookingForSync:
361 findSync();
362 break;
363 case State::LookingForHeader:
364 handleHeader();
365 break;
366 case State::ReadingNofSamples:
367 handleReadTimestamp();
368 break;
369 case State::ReadingTimestamp:
370 handleReadData();
371 break;
372 case State::ReadingSample:
373 handleReadSample();
374 break;
375 case State::ReadingClusterSum:
376 handleReadClusterSum();
377 break;
378 }
379};
380
381template <typename CHARGESUM>
382void BareElinkDecoder<CHARGESUM>::softReset()
383{
385}
386
387template <typename CHARGESUM>
389{
390 softReset();
391 mState = State::LookingForSync;
392}
393
394template <typename CHARGESUM>
395std::ostream& operator<<(std::ostream& os, const o2::mch::raw::BareElinkDecoder<CHARGESUM>& e)
396{
397 os << fmt::format("ID{:2d} cruId {:2d} sync {:6d} cp 0x{:6x} mask 0x{:6x} state {:17s} len {:6d} nseen {:6d} errH {:6} errP {:6} head {:6d} n10w {:6d} nsamples {:6d} mode {} bbuf {:s}",
398 e.mLinkId, e.mCruId, e.mNofSync, e.mCheckpoint, e.mMask,
399 e.name(e.mState),
400 e.len(), e.mNofBitSeen,
401 e.mNofHeaderSeen,
402 e.mNofHammingErrors,
403 e.mNofHeaderParityErrors,
404 e.mNof10BitsWordsToRead,
405 e.mNofSamples,
406 (e.mClusterSumMode ? "CLUSUM" : "SAMPLE"),
407 bitBufferString(e.mBitBuffer, e.mMask));
408 return os;
409}
410
411template <typename CHARGESUM>
412void BareElinkDecoder<CHARGESUM>::sendHBPacket()
413{
414 SampaHeartBeatHandler handler = mDecodedDataHandlers.sampaHeartBeatHandler;
415 if (handler) {
416 handler(mDsId, mSampaHeader.chipAddress() % 2, mSampaHeader.bunchCrossingCounter());
417 }
418}
419
420} // namespace o2::mch::raw
421
422#endif
benchmark::State & state
Main element of the MCH Bare Raw Data Format decoder.
BareElinkDecoder(DsElecId dsId, DecodedDataHandlers decodedDataHandlers)
int len() const
Current number of bits we're holding.
void append(bool bit0, bool bit1)
Append two bits (from the same dual sampa, one per sampa) to the Elink.
friend std::ostream & operator<<(std::ostream &os, const o2::mch::raw::BareElinkDecoder< T > &e)
SampaHeader is the 50-bits header word used in Sampa data transmission protocol.
Definition SampaHeader.h:51
GLuint const GLchar * name
Definition glcorearb.h:781
constexpr int HEADERSIZE
uint16_t uint10_t
Definition DataFormats.h:67
constexpr uint64_t sampaSyncWord
std::string bitBufferString(const std::bitset< 50 > &bs, int imax)
std::function< void(DsElecId dsId, uint8_t chip, uint20_t bunchCrossing)> SampaHeartBeatHandler
std::ostream & operator<<(std::ostream &stream, o2::InteractionRecord const &ir)
vec clear()