CMS 3D CMS Logo

RawDataUnpacker.cc
Go to the documentation of this file.
1 /****************************************************************************
2 *
3 * This is a part of TOTEM offline software.
4 * Authors:
5 * Jan Kašpar (jan.kaspar@gmail.com)
6 * Nicola Minafra
7 *
8 ****************************************************************************/
9 
13 
14 using namespace std;
15 using namespace edm;
16 using namespace pps;
17 
18 RawDataUnpacker::RawDataUnpacker(const edm::ParameterSet &iConfig)
19  : verbosity(iConfig.getUntrackedParameter<unsigned int>("verbosity", 0)) {}
20 
22  const FEDRawData &data,
23  vector<TotemFEDInfo> &fedInfoColl,
24  SimpleVFATFrameCollection &coll) const {
25  unsigned int size_in_words = data.size() / 8; // bytes -> words
26  if (size_in_words < 2) {
27  if (verbosity)
28  LogWarning("Totem") << "Error in RawDataUnpacker::run > "
29  << "Data in FED " << fedId << " too short (size = " << size_in_words << " words).";
30  return 1;
31  }
32 
33  fedInfoColl.emplace_back(fedId);
34 
35  return processOptoRxFrame((const word *)data.data(), size_in_words, fedInfoColl.back(), &coll);
36 }
37 
39  unsigned int frameSize,
40  TotemFEDInfo &fedInfo,
41  SimpleVFATFrameCollection *fc) const {
42  // get OptoRx metadata
43  unsigned long long head = buf[0];
44  unsigned long long foot = buf[frameSize - 1];
45 
46  fedInfo.setHeader(head);
47  fedInfo.setFooter(foot);
48 
49  unsigned int boe = (head >> 60) & 0xF;
50  unsigned int h0 = (head >> 0) & 0xF;
51 
52  unsigned long lv1 = (head >> 32) & 0xFFFFFF;
53  unsigned long bx = (head >> 20) & 0xFFF;
54  unsigned int optoRxId = (head >> 8) & 0xFFF;
55  unsigned int fov = (head >> 4) & 0xF;
56 
57  unsigned int eoe = (foot >> 60) & 0xF;
58  unsigned int f0 = (foot >> 0) & 0xF;
59  unsigned int fSize = (foot >> 32) & 0x3FF;
60 
61  // check header and footer structure
62  if (boe != 5 || h0 != 0 || eoe != 10 || f0 != 0 || fSize != frameSize) {
63  if (verbosity)
64  LogWarning("Totem") << "Error in RawDataUnpacker::processOptoRxFrame > "
65  << "Wrong structure of OptoRx header/footer: "
66  << "BOE=" << boe << ", H0=" << h0 << ", EOE=" << eoe << ", F0=" << f0
67  << ", size (OptoRx)=" << fSize << ", size (DATE)=" << frameSize << ". OptoRxID=" << optoRxId
68  << ". Skipping frame." << endl;
69  return 0;
70  }
71 
72  LogDebug("Totem") << "RawDataUnpacker::processOptoRxFrame: "
73  << "OptoRxId = " << optoRxId << ", BX = " << bx << ", LV1 = " << lv1
74  << ", frameSize = " << frameSize << ", fov = " << fov;
75 
78  processOptoRxFrameSampic(buf, frameSize, fedInfo, fc);
79  return 0;
80  }
81  if ((optoRxId >= FEDNumbering::MINTotemT2FEDID && optoRxId <= FEDNumbering::MAXTotemT2FEDID)) {
82  processOptoRxFrameSampic(buf, frameSize, fedInfo, fc);
83  return 0;
84  }
85 
86  // parallel or serial transmission?
87  switch (fov) {
88  case 1:
89  return processOptoRxFrameSerial(buf, frameSize, fc);
90  case 2:
91  case 3:
92  return processOptoRxFrameParallel(buf, frameSize, fedInfo, fc);
93  default:
94  break;
95  }
96 
97  if (verbosity)
98  LogWarning("Totem") << "Error in RawDataUnpacker::processOptoRxFrame > "
99  << "Unknown FOV = " << fov << endl;
100 
101  return 0;
102 }
103 
105  unsigned int frameSize,
106  SimpleVFATFrameCollection *fc) const {
107  // get OptoRx metadata
108  unsigned int optoRxId = (buf[0] >> 8) & 0xFFF;
109 
110  // get number of subframes
111  unsigned int subFrames = (frameSize - 2) / 194;
112 
113  // process all sub-frames
114  unsigned int errorCounter = 0;
115  for (unsigned int r = 0; r < subFrames; ++r) {
116  for (unsigned int c = 0; c < 4; ++c) {
117  unsigned int head = (buf[1 + 194 * r] >> (16 * c)) & 0xFFFF;
118  unsigned int foot = (buf[194 + 194 * r] >> (16 * c)) & 0xFFFF;
119 
120  LogDebug("Totem") << "r = " << r << ", c = " << c << ": "
121  << "S = " << (head & 0x1) << ", BOF = " << (head >> 12) << ", EOF = " << (foot >> 12)
122  << ", ID = " << ((head >> 8) & 0xF) << ", ID' = " << ((foot >> 8) & 0xF);
123 
124  // stop if this GOH is NOT active
125  if ((head & 0x1) == 0)
126  continue;
127 
128  LogDebug("Totem") << "Header active (" << head << " -> " << (head & 0x1) << ").";
129 
130  // check structure
131  if (head >> 12 != 0x4 || foot >> 12 != 0xB || ((head >> 8) & 0xF) != ((foot >> 8) & 0xF)) {
132  std::ostringstream oss;
133  if (head >> 12 != 0x4)
134  oss << "\n\tHeader is not 0x4 as expected (0x" << std::hex << head << ").";
135  if (foot >> 12 != 0xB)
136  oss << "\n\tFooter is not 0xB as expected (0x" << std::hex << foot << ").";
137  if (((head >> 8) & 0xF) != ((foot >> 8) & 0xF))
138  oss << "\n\tIncompatible GOH IDs in header (0x" << std::hex << ((head >> 8) & 0xF) << ") and footer (0x"
139  << std::hex << ((foot >> 8) & 0xF) << ").";
140 
141  if (verbosity)
142  LogWarning("Totem") << "Error in RawDataUnpacker::processOptoRxFrame > "
143  << "Wrong payload structure (in GOH block row " << r << " and column " << c
144  << ") in OptoRx frame ID " << optoRxId << ". GOH block omitted." << oss.str() << endl;
145 
146  errorCounter++;
147  continue;
148  }
149 
150  // allocate memory for VFAT frames
151  unsigned int goh = (head >> 8) & 0xF;
152  vector<VFATFrame::word *> dataPtrs;
153  for (unsigned int fi = 0; fi < 16; fi++) {
154  TotemFramePosition fp(0, 0, optoRxId, goh, fi);
155  dataPtrs.push_back(fc->InsertEmptyFrame(fp)->getData());
156  }
157 
158  LogDebug("Totem").log([&](auto &l) {
159  l << "transposing GOH block at prefix: " << (optoRxId * 192 + goh * 16) << ", dataPtrs = ";
160  for (auto p : dataPtrs) {
161  l << p << " ";
162  }
163  });
164  // deserialization
165  for (int i = 0; i < 192; i++) {
166  int iword = 11 - i / 16; // number of current word (11...0)
167  int ibit = 15 - i % 16; // number of current bit (15...0)
168  unsigned int w = (buf[i + 2 + 194 * r] >> (16 * c)) & 0xFFFF;
169 
170  // Fill the current bit of the current word of all VFAT frames
171  for (int idx = 0; idx < 16; idx++) {
172  if (w & (1 << idx))
173  dataPtrs[idx][iword] |= (1 << ibit);
174  }
175  }
176  }
177  }
178 
179  return errorCounter;
180 }
181 
183  unsigned int frameSize,
184  TotemFEDInfo &fedInfo,
185  SimpleVFATFrameCollection *fc) const {
186  // get OptoRx metadata
187  unsigned long long head = buf[0];
188  unsigned int optoRxId = (head >> 8) & 0xFFF;
189 
190  // recast data as buffer or 16bit words, skip header
191  const uint16_t *payload = (const uint16_t *)(buf + 1);
192 
193  // read in OrbitCounter block
194  const uint32_t *ocPtr = (const uint32_t *)payload;
195  fedInfo.setOrbitCounter(*ocPtr);
196  payload += 2;
197 
198  // size in 16bit words, without header, footer and orbit counter block
199  unsigned int nWords = (frameSize - 2) * 4 - 2;
200 
201  // process all VFAT data
202  for (unsigned int offset = 0; offset < nWords;) {
203  unsigned int wordsProcessed = processVFATDataParallel(payload + offset, nWords, optoRxId, fc);
204  offset += wordsProcessed;
205  }
206 
207  return 0;
208 }
209 
211  unsigned int maxWords,
212  unsigned int optoRxId,
213  SimpleVFATFrameCollection *fc) const {
214  // start counting processed words
215  unsigned int wordsProcessed = 1;
216 
217  // padding word? skip it
218  if (buf[0] == 0xFFFF)
219  return wordsProcessed;
220 
221  // check header flag
222  unsigned int hFlag = (buf[0] >> 8) & 0xFF;
223  if (hFlag != vmCluster && hFlag != vmRaw && hFlag != vmDiamondCompact) {
224  if (verbosity)
225  LogWarning("Totem") << "Error in RawDataUnpacker::processVFATDataParallel > "
226  << "Unknown header flag " << hFlag << ". Skipping this word." << endl;
227  return wordsProcessed;
228  }
229 
230  // compile frame position
231  // NOTE: DAQ group uses terms GOH and fiber in the other way
232  unsigned int gohIdx = (buf[0] >> 4) & 0xF;
233  unsigned int fiberIdx = (buf[0] >> 0) & 0xF;
234  TotemFramePosition fp(0, 0, optoRxId, gohIdx, fiberIdx);
235 
236  // prepare temporary VFAT frame
237  VFATFrame f;
238  VFATFrame::word *fd = f.getData();
239 
240  // copy footprint, BC, EC, Flags, ID, if they exist
241  uint8_t presenceFlags = 0;
242 
243  if (((buf[wordsProcessed] >> 12) & 0xF) == 0xA) // BC
244  {
245  presenceFlags |= 0x1;
246  fd[11] = buf[wordsProcessed];
247  wordsProcessed++;
248  }
249 
250  if (((buf[wordsProcessed] >> 12) & 0xF) == 0xC) // EC, flags
251  {
252  presenceFlags |= 0x2;
253  fd[10] = buf[wordsProcessed];
254  wordsProcessed++;
255  }
256 
257  if (((buf[wordsProcessed] >> 12) & 0xF) == 0xE) // ID
258  {
259  presenceFlags |= 0x4;
260  fd[9] = buf[wordsProcessed];
261  wordsProcessed++;
262  }
263 
264  // save offset where channel data start
265  unsigned int dataOffset = wordsProcessed;
266 
267  // find trailer
268  switch (hFlag) {
269  case vmCluster: {
270  unsigned int nCl = 0;
271  while ((buf[wordsProcessed + nCl] >> 12) != 0xF && (wordsProcessed + nCl < maxWords))
272  nCl++;
273  wordsProcessed += nCl;
274  } break;
275  case vmRaw:
276  wordsProcessed += 9;
277  break;
278  case vmDiamondCompact: {
279  wordsProcessed--;
280  while ((buf[wordsProcessed] & 0xFFF0) != 0xF000 && (wordsProcessed < maxWords))
281  wordsProcessed++;
282  } break;
283  }
284 
285  // process trailer
286  unsigned int tSig = buf[wordsProcessed] >> 12;
287  unsigned int tErrFlags = (buf[wordsProcessed] >> 8) & 0xF;
288  unsigned int tSize = buf[wordsProcessed] & 0xFF;
289 
290  f.setDAQErrorFlags(tErrFlags);
291 
292  // consistency checks
293  bool skipFrame = false;
294  stringstream ess;
295 
296  if (tSig != 0xF) {
297  if (verbosity)
298  ess << " Wrong trailer signature (" << tSig << ")." << endl;
299  skipFrame = true;
300  }
301 
302  if (tErrFlags != 0) {
303  if (verbosity)
304  ess << " Error flags not zero (" << tErrFlags << ")." << endl;
305  skipFrame = true;
306  }
307 
308  wordsProcessed++;
309 
310  if (tSize != wordsProcessed) {
311  if (verbosity)
312  ess << " Trailer size (" << tSize << ") does not match with words processed (" << wordsProcessed << ")."
313  << endl;
314  skipFrame = true;
315  }
316 
317  if (skipFrame) {
318  if (verbosity)
319  LogWarning("Totem") << "Error in RawDataUnpacker::processVFATDataParallel > Frame at " << fp
320  << " has the following problems and will be skipped.\n"
321  << endl
322  << ess.rdbuf();
323 
324  return wordsProcessed;
325  }
326 
327  // get channel data - cluster mode
328  if (hFlag == vmCluster) {
329  for (unsigned int nCl = 0; (buf[dataOffset + nCl] >> 12) != 0xF && (dataOffset + nCl < maxWords); ++nCl) {
330  const uint16_t &w = buf[dataOffset + nCl];
331  unsigned int upperBlock = w >> 8;
332  unsigned int clSize = upperBlock & 0x7F;
333  unsigned int clPos = (w >> 0) & 0xFF;
334 
335  // special case: upperBlock=0xD0 => numberOfClusters
336  if (upperBlock == 0xD0) {
337  presenceFlags |= 0x10;
338  f.setNumberOfClusters(clPos);
339  continue;
340  }
341 
342  // special case: size=0 means chip full
343  if (clSize == 0)
344  clSize = 128;
345 
346  // activate channels
347  // convention - range <pos, pos-size+1>
348  signed int chMax = clPos;
349  signed int chMin = clPos - clSize + 1;
350  if (chMax < 0 || chMax > 127 || chMin < 0 || chMin > 127 || chMin > chMax) {
351  if (verbosity)
352  LogWarning("Totem") << "Error in RawDataUnpacker::processVFATDataParallel > "
353  << "Invalid cluster (pos=" << clPos << ", size=" << clSize << ", min=" << chMin
354  << ", max=" << chMax << ") at " << fp << ". Skipping this cluster." << endl;
355  continue;
356  }
357 
358  for (signed int ch = chMin; ch <= chMax; ch++) {
359  unsigned int wi = ch / 16;
360  unsigned int bi = ch % 16;
361  fd[wi + 1] |= (1 << bi);
362  }
363  }
364  }
365 
366  // get channel data and CRC - raw mode
367  if (hFlag == vmRaw) {
368  for (unsigned int i = 0; i < 8; i++)
369  fd[8 - i] = buf[dataOffset + i];
370 
371  // copy CRC
372  presenceFlags |= 0x8;
373  fd[0] = buf[dataOffset + 8];
374  }
375 
376  // get channel data for diamond compact mode
377  if (hFlag == vmDiamondCompact) {
378  for (unsigned int i = 1; (buf[i + 1] & 0xFFF0) != 0xF000 && (i + 1 < maxWords); i++) {
379  if ((buf[i] & 0xF000) == VFAT_HEADER_OF_EC) {
380  // Event Counter word is found
381  fd[10] = buf[i];
382  continue;
383  }
384  switch (buf[i] & 0xF800) {
386  // word 2 of the diamond VFAT frame is found
387  fd[1] = buf[i + 1];
388  fd[2] = buf[i];
389  break;
391  // word 3 of the diamond VFAT frame is found
392  fd[3] = buf[i];
393  fd[4] = buf[i - 1];
394  break;
396  // word 5 of the diamond VFAT frame is found
397  fd[5] = buf[i];
398  fd[6] = buf[i - 1];
399  break;
401  // word 7 of the diamond VFAT frame is found
402  fd[7] = buf[i];
403  fd[8] = buf[i - 1];
404  break;
405  default:
406  break;
407  }
408  presenceFlags |= 0x8;
409  }
410  }
411 
412  // save frame to output
413  f.setPresenceFlags(presenceFlags);
414  fc->Insert(fp, f);
415 
416  return wordsProcessed;
417 }
418 
420  unsigned int frameSize,
421  TotemFEDInfo &fedInfo,
422  SimpleVFATFrameCollection *fc) const {
423  unsigned int optoRxId = (buf[0] >> 8) & 0xFFF;
424 
425  LogDebug("RawDataUnpacker::processOptoRxFrameSampic")
426  << "Processing sampic frame: OptoRx " << optoRxId << " framesize: " << frameSize;
427 
428  unsigned int orbitCounterVFATFrameWords = 6;
429  unsigned int sizeofVFATPayload = 12;
430 
431  const VFATFrame::word *VFATFrameWordPtr = (const VFATFrame::word *)buf;
432  VFATFrameWordPtr += orbitCounterVFATFrameWords - 1;
433 
434  LogDebug("RawDataUnpacker::processOptoRxFrameSampic")
435  << "Framesize: " << frameSize << "\tframes: " << frameSize / (sizeofVFATPayload + 2);
436 
437  unsigned int nWords = (frameSize - 2) * 4 - 2;
438 
439  for (unsigned int i = 1; i * (sizeofVFATPayload + 2) < nWords; ++i) {
440  // compile frame position
441  // NOTE: DAQ group uses terms GOH and fiber in the other way
442  unsigned int fiberIdx = (*(++VFATFrameWordPtr)) & 0xF;
443  unsigned int gohIdx = (*VFATFrameWordPtr >> 4) & 0xF;
444  TotemFramePosition fp(0, 0, optoRxId, gohIdx, fiberIdx);
445  TotemT2FramePosition fp2a(0, 0, optoRxId, gohIdx, fiberIdx, 0);
446  TotemT2FramePosition fp2b(0, 0, optoRxId, gohIdx, fiberIdx, 1);
447 
448  LogDebug("RawDataUnpacker::processOptoRxFrameSampic")
449  << "OptoRx: " << optoRxId << " Goh: " << gohIdx << " Idx: " << fiberIdx;
450 
451  // prepare temporary VFAT frame
452  VFATFrame frame(++VFATFrameWordPtr);
453  VFATFrameWordPtr += sizeofVFATPayload;
454 
455  if (*(VFATFrameWordPtr) != 0xf00e) {
456  edm::LogError("RawDataUnpacker::processOptoRxFrameSampic") << "Wrong trailer " << *VFATFrameWordPtr;
457  continue;
458  }
459  // save frame to output
460  frame.setPresenceFlags(1);
461  if ((optoRxId >= FEDNumbering::MINTotemT2FEDID && optoRxId <= FEDNumbering::MAXTotemT2FEDID)) {
462  frame.setPresenceFlags(15); // check three VFAT signature digits, CRC present
463  if (verbosity > 0)
464  edm::LogWarning("Totem") << "T2 Frame Positions created: " << fp2a << "/" << fp2b << std::endl;
465 
466  fc->Insert(
467  fp2a,
468  frame); //Fill twice with the mapping for both payloads packed into the same frame, will match only once for each
469  fc->Insert(fp2b, frame);
470  } else
471  fc->Insert(fp, frame);
472 
473  LogDebug("RawDataUnpacker::processOptoRxFrameSampic") << "Trailer: " << std::hex << *VFATFrameWordPtr;
474  }
475 
476  return 0;
477 }
OptoRx headers and footers.
Definition: TotemFEDInfo.h:17
static constexpr unsigned int VFAT_DIAMOND_HEADER_OF_WORD_7
static constexpr unsigned int VFAT_HEADER_OF_EC
VFATFrame::word * getData()
Definition: VFATFrame.h:38
int processOptoRxFrame(const word *buf, unsigned int frameSize, TotemFEDInfo &fedInfo, SimpleVFATFrameCollection *fc) const
Process one Opto-Rx (or LoneG) frame.
T w() const
uint16_t word
Definition: VFATFrame.h:21
int processOptoRxFrameSampic(const word *buffer, unsigned int frameSize, TotemFEDInfo &fedInfo, SimpleVFATFrameCollection *fc) const
Process one Opto-Rx frame that contains SAMPIC frames.
static constexpr unsigned int VFAT_DIAMOND_HEADER_OF_WORD_5
int processVFATDataParallel(const uint16_t *buf, unsigned int maxWords, unsigned int OptoRxId, SimpleVFATFrameCollection *fc) const
Process data from one VFAT in parallel (new) format.
Log< level::Error, false > LogError
static constexpr unsigned int VFAT_DIAMOND_HEADER_OF_WORD_3
void setFooter(uint64_t _f)
Definition: TotemFEDInfo.h:35
double f[11][100]
static constexpr unsigned int VFAT_DIAMOND_HEADER_OF_WORD_2
VFATFrame * InsertEmptyFrame(TotemFramePosition index)
inserts an empty (default) frame to the given position and returns pointer to the frame ...
unsigned char verbosity
int run(int fedId, const FEDRawData &data, std::vector< TotemFEDInfo > &fedInfoColl, SimpleVFATFrameCollection &coll) const
Unpack data from FED with fedId into ‘coll’ collection.
const int verbosity
void setOrbitCounter(uint32_t oc)
Definition: TotemFEDInfo.h:32
HLT enums.
char data[epos_bytes_allocation]
Definition: EPOS_Wrapper.h:80
int processOptoRxFrameSerial(const word *buffer, unsigned int frameSize, SimpleVFATFrameCollection *fc) const
Process one Opto-Rx frame in serial (old) format.
Log< level::Warning, false > LogWarning
fd
Definition: ztee.py:136
int processOptoRxFrameParallel(const word *buffer, unsigned int frameSize, TotemFEDInfo &fedInfo, SimpleVFATFrameCollection *fc) const
Process one Opto-Rx frame in parallel (new) format.
void setHeader(uint64_t _h)
Definition: TotemFEDInfo.h:24
void Insert(const TotemFramePosition &index, const VFATFrame &frame)
#define LogDebug(id)