Project
Loading...
Searching...
No Matches
RawReaderZDC.cxx
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#include "ZDCRaw/RawReaderZDC.h"
13#include <cstdlib>
14
15namespace o2
16{
17namespace zdc
18{
19
21{
22#ifndef O2_ZDC_DEBUG
23 LOG(info) << "RawReaderZDC::clear()";
24#endif
25 for (int im = 0; im < NModules; im++) {
26 for (int ic = 0; ic < NChPerModule; ic++) {
27 mEvents[im][ic] = 0;
28 mDupOK[im][ic] = 0;
29 mDupKO[im][ic] = 0;
30 }
31 }
32 mDigitsBC.clear();
33 mDigitsCh.clear();
34 mOrbitData.clear();
35}
36
37int RawReaderZDC::processBinaryData(gsl::span<const uint8_t> payload, int linkID, uint8_t dataFormat)
38{
39 if (0 <= linkID && linkID < 16) {
40 size_t payloadSize = payload.size();
41 if (dataFormat == 2) {
42 for (int32_t ip = 0; (ip + PayloadPerGBTW) <= payloadSize; ip += PayloadPerGBTW) {
43#ifndef O2_ZDC_DEBUG
44 if (mVerbosity >= DbgExtra) {
45 o2::zdc::Digits2Raw::print_gbt_word((const uint32_t*)&payload[ip]);
46 }
47#else
48 o2::zdc::Digits2Raw::print_gbt_word((const uint32_t*)&payload[ip]);
49#endif
50 const uint32_t* gbtw = (const uint32_t*)&payload[ip];
51 if (gbtw[0] != 0xffffffff || gbtw[1] != 0xffffffff || (*((const uint16_t*)&gbtw[2])) != 0xffff) {
52 if (processWord(gbtw)) {
53 return 1;
54 }
55 }
56 }
57 } else if (dataFormat == 0) {
58 for (int32_t ip = 0; ip < payloadSize; ip += NBPerGBTW) {
59#ifndef O2_ZDC_DEBUG
60 if (mVerbosity >= DbgExtra) {
61 o2::zdc::Digits2Raw::print_gbt_word((const uint32_t*)&payload[ip]);
62 }
63#else
64 o2::zdc::Digits2Raw::print_gbt_word((const uint32_t*)&payload[ip]);
65#endif
66 if (processWord((const uint32_t*)&payload[ip])) {
67 return 1;
68 }
69 }
70 } else {
71 LOG(fatal) << "RawReaderZDC::processBinaryData - Unsupported DataFormat " << dataFormat;
72 }
73 } else {
74 // put here code in case of bad rdh.linkID value
75 LOG(info) << "WARNING! WRONG LINK ID! " << linkID;
76 return 1;
77 }
78 return 0;
79}
80
81int RawReaderZDC::processWord(const uint32_t* word)
82{
83 if (word == nullptr) {
84 LOG(error) << "NULL pointer";
85 return 1;
86 }
87 // LOGF(info, "GBT word %04x %08x %08x id=%u", *((uint16_t*)&word[2]), word[1], word[0], word[0] & 0x3);
88 if ((word[0] & 0x3) == Id_w0) {
89 mCh.w[0][NWPerGBTW - 1] = 0;
90 mCh.w[0][NWPerGBTW - 2] = 0;
91 memcpy((void*)&mCh.w[0][0], (const void*)word, PayloadPerGBTW);
92 } else if ((word[0] & 0x3) == Id_w1) {
93 if (mCh.f.fixed_0 == Id_w0) {
94 mCh.w[1][NWPerGBTW - 1] = 0;
95 mCh.w[1][NWPerGBTW - 2] = 0;
96 memcpy((void*)&mCh.w[1][0], (const void*)word, PayloadPerGBTW);
97 } else {
98 LOGF(error, "Wrong word sequence: %04x %08x %08x id=%u *%u*", *((uint16_t*)&word[2]), word[1], word[0], mCh.f.fixed_0, word[0] & 0x3);
99 mCh.f.fixed_0 = Id_wn;
100 mCh.f.fixed_1 = Id_wn;
101 mCh.f.fixed_2 = Id_wn;
102 }
103 } else if ((word[0] & 0x3) == Id_w2) {
104 if (mCh.f.fixed_0 == Id_w0 && mCh.f.fixed_1 == Id_w1) {
105 mCh.w[2][NWPerGBTW - 1] = 0;
106 mCh.w[2][NWPerGBTW - 2] = 0;
107 memcpy((void*)&mCh.w[2][0], (const void*)word, PayloadPerGBTW);
108 process(mCh);
109 } else {
110 LOGF(error, "Wrong word sequence: %04x %08x %08x id=%u %u *%u*", *((uint16_t*)&word[2]), word[1], word[0], mCh.f.fixed_0, mCh.f.fixed_1, word[0] & 0x3);
111 }
112 mCh.f.fixed_0 = Id_wn;
113 mCh.f.fixed_1 = Id_wn;
114 mCh.f.fixed_2 = Id_wn;
115 } else {
116 // Word id not foreseen in payload
117 LOGF(error, "Event format error on word %04x %08x %08x id=%u", *((uint16_t*)&word[2]), word[1], word[0], word[0] & 0x3);
118 return 1;
119 }
120 return 0;
121}
122
124{
125 InteractionRecord ir(ch.f.bc, ch.f.orbit);
126 auto& mydata = mMapData[ir];
127 int32_t im = ch.f.board;
128 int32_t ic = ch.f.ch;
129 mEvents[im][ic]++;
130 for (int32_t iwb = 0; iwb < NWPerBc; iwb++) {
131 for (int32_t iwg = 0; iwg < NWPerGBTW; iwg++) {
132 mydata.data[im][ic].w[iwb][iwg] = mCh.w[iwb][iwg];
133 }
134 }
135}
136
137// pop digits
138int RawReaderZDC::getDigits(std::vector<BCData>& digitsBC, std::vector<ChannelData>& digitsCh, std::vector<OrbitData>& orbitData)
139{
140 const char* thefcn = "RawReaderZDC::getDigits";
141
142 if (mModuleConfig == nullptr) {
143 LOG(fatal) << "Missing ModuleConfig";
144 return 0;
145 }
146
147 union {
148 uint16_t uns;
149 int16_t sig;
150 } word16;
151
152 int bcCounter = mMapData.size();
153
154 if (mVerbosity > DbgZero) {
155 LOG(info) << "Processing #bc " << bcCounter;
156 for (int ic = 0; ic < NChPerModule; ic++) {
157 for (int im = 0; im < NModules; im++) {
158 if (im == 0) {
159 printf("%6u", mEvents[im][ic]);
160 } else {
161 printf(" %6u", mEvents[im][ic]);
162 }
163 }
164 printf("\n");
165 }
166 }
167
168 for (auto& [ir, ev] : mMapData) {
169 // TODO: Error check
170 // Pedestal data
171 if (ir.bc == 3563) {
172 auto& pdata = orbitData.emplace_back();
173 pdata.ir = ir;
174 for (int32_t im = 0; im < NModules; im++) {
175 for (int32_t ic = 0; ic < NChPerModule; ic++) {
176 if (ev.data[im][ic].f.fixed_0 == Id_w0 && ev.data[im][ic].f.fixed_1 == Id_w1 && ev.data[im][ic].f.fixed_2 == Id_w2) {
177 // Protection for channels that are not supposed to readout but may be present in payload
178 // These additional channels are used just for scaler and pedestal readout at end of orbit
179 // for raw data QC only. They are skipped during digitization
180 if (mModuleConfig->modules[im].readChannel[ic]) {
181 // Identify connected channel
182 auto id = mModuleConfig->modules[im].channelID[ic];
183 word16.uns = ev.data[im][ic].f.offset;
184 pdata.data[id] = word16.sig;
185 if (ev.data[im][ic].f.dLoss) {
186 // Produce a scaler overflow to signal a problem
187 // Most significant bit indicates data loss
188 // Default initializer 0x8fff will indicate that orbit data is lost
189 pdata.scaler[id] = ev.data[im][ic].f.hits | 0x8000;
190 } else {
191 pdata.scaler[id] = ev.data[im][ic].f.hits;
192 }
193 }
194 } else if (ev.data[im][ic].f.fixed_0 == 0 && ev.data[im][ic].f.fixed_1 == 0 && ev.data[im][ic].f.fixed_2 == 0) {
195 // Empty channel
196 } else {
197 LOG(error) << "Data format error";
198 }
199 }
200 }
201 }
202 // BC data
203 auto& bcdata = digitsBC.emplace_back();
204 bcdata.ir = ir;
205 // An inconsistent event has as at least one inconsistent module
206 bool inconsistent_event = false;
207 bool inconsistent_alice_trig = false;
208 bool inconsistent_auto_trig = false;
209 bool filled_event = false;
210 bcdata.ref.setFirstEntry(digitsCh.size());
211 uint32_t ncd = 0;
212 bool alice_0 = false;
213 bool alice_1 = false;
214 bool alice_2 = false;
215 bool alice_3 = false;
216 // Channel data
217 for (int32_t im = 0; im < NModules; im++) {
219 mt.w = 0;
220 bool filled_module = false;
221 for (int32_t ic = 0; ic < NChPerModule; ic++) {
222 // Check if payload is present for channel
223 if (ev.data[im][ic].f.fixed_0 == Id_w0 && ev.data[im][ic].f.fixed_1 == Id_w1 && ev.data[im][ic].f.fixed_2 == Id_w2) {
224 if (mModuleConfig->modules[im].readChannel[ic] == false) {
225 // Channel should not be present in payload. It may happen for bc=0 and bc=3563
226 if (bcdata.ir.bc == 0 || bcdata.ir.bc == 3563) {
227 mDupOK[im][ic]++;
228 } else {
229 mDupKO[im][ic]++;
230 }
231 continue;
232 }
233 bcdata.channels |= (0x1 << (NChPerModule * im + ic)); // Flag channel as present
234 auto& ch = ev.data[im][ic];
235 uint16_t us[12];
236 us[0] = ch.f.s00;
237 us[1] = ch.f.s01;
238 us[2] = ch.f.s02;
239 us[3] = ch.f.s03;
240 us[4] = ch.f.s04;
241 us[5] = ch.f.s05;
242 us[6] = ch.f.s06;
243 us[7] = ch.f.s07;
244 us[8] = ch.f.s08;
245 us[9] = ch.f.s09;
246 us[10] = ch.f.s10;
247 us[11] = ch.f.s11;
248 // Identify connected channel
249 auto& chd = digitsCh.emplace_back();
250 auto id = mModuleConfig->modules[im].channelID[ic];
251 chd.id = id;
252 for (int32_t is = 0; is < NTimeBinsPerBC; is++) {
253 if (us[is] > ADCMax) {
254 chd.data[is] = us[is] - ADCRange;
255 } else {
256 chd.data[is] = us[is];
257 }
258 }
259 // Trigger bits
260 if (ch.f.Hit) {
261 bcdata.triggers |= (0x1 << (im * NChPerModule + ic));
262 }
263 if (filled_event == false) {
264 // ALICE trigger bits must be the same for all readout modules
265 alice_0 = ch.f.Alice_0;
266 alice_1 = ch.f.Alice_1;
267 alice_2 = ch.f.Alice_2;
268 alice_3 = ch.f.Alice_3;
269 filled_event = true;
270 } else if (alice_0 != ch.f.Alice_0 || alice_1 != ch.f.Alice_1 || alice_2 != ch.f.Alice_2 || alice_3 != ch.f.Alice_3) {
271 inconsistent_event = true;
272 inconsistent_alice_trig = true;
273 mt.f.AliceErr = true;
274 LOGF(warn, "%s (m,c)=(%d,%d) Alice [0123] %u%s%u %u%s%u %u%s%u %u%s%u", thefcn, im, ic,
275 alice_0, alice_0 == ch.f.Alice_0 ? "==" : "!=", ch.f.Alice_0,
276 alice_1, alice_1 == ch.f.Alice_1 ? "==" : "!=", ch.f.Alice_1,
277 alice_2, alice_2 == ch.f.Alice_2 ? "==" : "!=", ch.f.Alice_2,
278 alice_3, alice_3 == ch.f.Alice_3 ? "==" : "!=", ch.f.Alice_3);
279 }
280 if (filled_module == false) {
281 mt.f.Auto_m = ch.f.Auto_m;
282 mt.f.Auto_0 = ch.f.Auto_0;
283 mt.f.Auto_1 = ch.f.Auto_1;
284 mt.f.Auto_2 = ch.f.Auto_2;
285 mt.f.Auto_3 = ch.f.Auto_3;
286 mt.f.Alice_0 = ch.f.Alice_0;
287 mt.f.Alice_1 = ch.f.Alice_1;
288 mt.f.Alice_2 = ch.f.Alice_2;
289 mt.f.Alice_3 = ch.f.Alice_3;
290 filled_module = true;
291 } else if (mt.f.Auto_m != ch.f.Auto_m || mt.f.Auto_0 != ch.f.Auto_0 || mt.f.Auto_1 != ch.f.Auto_1 || mt.f.Auto_2 != ch.f.Auto_2 || mt.f.Auto_3 != ch.f.Auto_3) {
292 mt.f.AutoErr = true;
293 inconsistent_auto_trig = true;
294 LOGF(warn, "%s (m,c)=(%d,%d) Auto [m0123] %u%s%u %u%s%u %u%s%u %u%s%u %u%s%u", thefcn, im, ic,
295 mt.f.Auto_m, mt.f.Auto_m == ch.f.Auto_m ? "==" : "!=", ch.f.Auto_m,
296 mt.f.Auto_0, mt.f.Auto_0 == ch.f.Auto_0 ? "==" : "!=", ch.f.Auto_0,
297 mt.f.Auto_1, mt.f.Auto_1 == ch.f.Auto_1 ? "==" : "!=", ch.f.Auto_1,
298 mt.f.Auto_2, mt.f.Auto_2 == ch.f.Auto_2 ? "==" : "!=", ch.f.Auto_2,
299 mt.f.Auto_3, mt.f.Auto_3 == ch.f.Auto_3 ? "==" : "!=", ch.f.Auto_3);
300 }
301 ncd++;
302 } else if (ev.data[im][ic].f.fixed_0 == 0 && ev.data[im][ic].f.fixed_1 == 0 && ev.data[im][ic].f.fixed_2 == 0) {
303 // Empty channel
304 } else {
305 LOG(error) << thefcn << "RAW Data format error";
306 }
307 }
308 bcdata.moduleTriggers[im] = mt.w;
309 if (mt.f.AutoErr == true) {
310 inconsistent_event = true;
311 }
312 }
313 if (ncd == 0) {
314 // Remove empty orbits (keep pedestal information)
315 digitsBC.pop_back();
316 } else {
317 bcdata.ref.setEntries(ncd);
318 if (mDumpData) {
319 bcdata.print(mTriggerMask);
320 auto first_entry = bcdata.ref.getFirstEntry();
321 for (Int_t icd = 0; icd < ncd; icd++) {
322 digitsCh[icd + first_entry].print();
323 }
324 }
325 }
326 if (inconsistent_event) {
327 LOGF(error, "%s %u.%04u Inconsistent event:%s%s", thefcn, bcdata.ir.orbit, bcdata.ir.bc, (inconsistent_auto_trig ? " AUTOT" : ""), (inconsistent_alice_trig ? " ALICET" : ""));
328 }
329 if ((inconsistent_event && mVerbosity > DbgMinimal) || (mVerbosity >= DbgFull)) {
330 bcdata.print(mTriggerMask);
331 for (int32_t im = 0; im < NModules; im++) {
332 for (int32_t ic = 0; ic < NChPerModule; ic++) {
333 if (ev.data[im][ic].f.fixed_0 == Id_w0 && ev.data[im][ic].f.fixed_1 == Id_w1 && ev.data[im][ic].f.fixed_2 == Id_w2) {
334 for (int32_t iw = 0; iw < NWPerBc; iw++) {
335 o2::zdc::Digits2Raw::print_gbt_word((const uint32_t*)&ev.data[im][ic].w[iw][0]);
336 }
337 }
338 }
339 }
340 }
341 } // Loop on bunch crossings
342
343 inspectDup();
344
345 mMapData.clear();
346 return bcCounter;
347}
348
349//______________________________________________________________________________
351{
352 // This function allows to examine if there are duplicate channels for modules in which it
353 // is expected and for modules in which is not expected
354 // A duplicate channel is present in pedestal data for channels that are readout on
355 // one module but connected to two modules because readout is forced in the FEE.
356#ifdef O2_ZDC_DEBUG
357 LOG(info) << "RawReaderZDC::inspectDup()";
358#endif
359 for (int32_t im = 0; im < NModules; im++) {
360 for (int32_t ic = 0; ic < NChPerModule; ic++) {
361 if (mVerbosity > DbgMinimal) {
362 if (mDupOK[im][ic] > 0) {
363 LOG(info) << "DupOK module " << im << " ch " << ic << " = " << mDupOK[im][ic];
364 }
365 }
366 if (mDupKO[im][ic] > 0) {
367 LOG(error) << "DupKO module " << im << " ch " << ic << " = " << mDupKO[im][ic];
368 }
369 }
370 }
371}
372
373//______________________________________________________________________________
375{
376 mTriggerMask = 0;
377 std::string printTriggerMask{};
378
379 for (int im = 0; im < NModules; im++) {
380 if (im > 0) {
381 printTriggerMask += " ";
382 }
383 printTriggerMask += std::to_string(im);
384 printTriggerMask += "[";
385 for (int ic = 0; ic < NChPerModule; ic++) {
386 if (mModuleConfig->modules[im].trigChannel[ic]) {
387 uint32_t tmask = 0x1 << (im * NChPerModule + ic);
388 mTriggerMask = mTriggerMask | tmask;
389 printTriggerMask += "T";
390 } else {
391 printTriggerMask += " ";
392 }
393 }
394 printTriggerMask += "]";
395#ifdef O2_ZDC_DEBUG
396 uint32_t mytmask = mTriggerMask >> (im * NChPerModule);
397 LOGF(info, "Trigger mask for module %d 0123 %c%c%c%c", im, mytmask & 0x1 ? 'T' : 'N', mytmask & 0x2 ? 'T' : 'N', mytmask & 0x4 ? 'T' : 'N', mytmask & 0x8 ? 'T' : 'N');
398#endif
399 }
400 LOGF(info, "trigger_mask=0x%08x %s", mTriggerMask, printTriggerMask.c_str());
401}
402} // namespace zdc
403} // namespace o2
static void print_gbt_word(const uint32_t *word, const ModuleConfig *moduleConfig=nullptr)
int getDigits(std::vector< BCData > &digitsBC, std::vector< ChannelData > &digitsCh, std::vector< OrbitData > &orbitData)
int processBinaryData(gsl::span< const uint8_t > payload, int linkID, uint8_t dataFormat)
int processWord(const uint32_t *word)
void process(const EventChData &ch)
GLuint id
Definition glcorearb.h:650
struct o2::upgrades_utils::@463 zdc
structure to keep FT0 information
constexpr int NModules
Definition Constants.h:68
constexpr unsigned short Id_wn
constexpr int NTimeBinsPerBC
Definition Constants.h:53
constexpr int NChPerModule
Definition Constants.h:69
constexpr int NWPerGBTW
constexpr int NBPerGBTW
constexpr unsigned short Id_w1
constexpr int DbgFull
Definition Constants.h:210
constexpr int DbgExtra
Definition Constants.h:211
constexpr int ADCRange
Definition Constants.h:76
constexpr int PayloadPerGBTW
constexpr int NWPerBc
Definition Constants.h:72
constexpr unsigned short Id_w2
constexpr int DbgMinimal
Definition Constants.h:208
constexpr int DbgZero
Definition Constants.h:207
constexpr unsigned short Id_w0
constexpr int ADCMax
Definition Constants.h:76
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string to_string(gsl::span< T, Size > span)
Definition common.h:52
uint16_t bc
bunch crossing ID of interaction
std::array< Module, MaxNModules > modules
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)
struct ChannelDataV0 f
UInt_t w[NWPerBc][NWPerGBTW]