- bugfix to correctly treat corrupted tracklet endmarkers
[u/mrichter/AliRoot.git] / TRD / AliTRDrawStream.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 ////////////////////////////////////////////////////////////////////////////
17 //                                                                        //
18 //  Decoding data from the TRD raw stream                                 //
19 //  and translation into ADC values, on-line tracklets and tracks         //
20 //                                                                        //
21 //  Author: J. Klein (jochen.klein@cern.ch)                               //
22 //                                                                        //
23 ////////////////////////////////////////////////////////////////////////////
24
25 #include <cstdio>
26 #include <cstdarg>
27
28 #include "TClonesArray.h"
29 #include "TTree.h"
30
31 #include "AliLog.h"
32 #include "AliRawReader.h"
33 #include "AliTRDcalibDB.h"
34 #include "AliTRDdigitsManager.h"
35 #include "AliTRDdigitsParam.h"
36 #include "AliTRDcalibDB.h"
37 #include "AliTRDmcmSim.h"
38 #include "AliTRDtrapConfig.h"
39 #include "AliTRDarrayADC.h"
40 #include "AliTRDarrayDictionary.h"
41 #include "AliTRDSignalIndex.h"
42 #include "AliTRDtrackletWord.h"
43 #include "AliTRDtrackletMCM.h"
44 #include "AliESDTrdTrack.h"
45 #include "AliTreeLoader.h"
46 #include "AliLoader.h"
47
48 #include "AliTRDrawStream.h"
49
50 // temporary
51 #include "AliRunLoader.h"
52
53 ClassImp(AliTRDrawStream)
54
55 // some static information
56 Int_t AliTRDrawStream::fgMcmOrder[] = {12, 13, 14, 15,
57                                        8, 9, 10, 11,
58                                        4, 5, 6, 7,
59                                        0, 1, 2, 3};
60 Int_t  AliTRDrawStream::fgRobOrder [] = {0, 1, 2, 3};
61 const Int_t  AliTRDrawStream::fgkNlinks = 12;
62 const Int_t  AliTRDrawStream::fgkNstacks = 5;
63 const Int_t  AliTRDrawStream::fgkNsectors = 18;
64 const Int_t  AliTRDrawStream::fgkNtriggers = 12;
65 const UInt_t AliTRDrawStream::fgkDataEndmarker     = 0x00000000;
66 const UInt_t AliTRDrawStream::fgkTrackletEndmarker = 0x10001000;
67 const UInt_t AliTRDrawStream::fgkStackEndmarker[] = { 0xe0d01000, 0xe0d10000 };
68
69 const char* AliTRDrawStream::fgkErrorMessages[] = {
70   "Unknown error",
71   "Link monitor active",
72   "Event counter mismatch",
73   "not a TRD equipment (1024-1041)",
74   "Invalid Stack header",
75   "Invalid detector number",
76   "No digits could be retrieved from the digitsmanager",
77   "HC header mismatch",
78   "HC check bits wrong",
79   "Unexpected position in readout stream",
80   "Invalid testpattern mode",
81   "Testpattern mismatch",
82   "Number of timebins changed",
83   "ADC mask inconsistent",
84   "ADC check bits invalid",
85   "Missing ADC data",
86   "Missing expected ADC channels",
87   "Missing MCM headers",
88   "Missing TP data",
89   "CRC mismatch"
90 };
91
92 Int_t AliTRDrawStream::fgErrorDebugLevel[] = {
93   0,
94   0,
95   2,
96   1,
97   0,
98   1,
99   1,
100   0,
101   1,
102   2,
103   1,
104   0,
105   1,
106   1,
107   2,
108   1,
109   1,
110   1,
111   0,
112   0
113 };
114
115 AliTRDrawStream::ErrorBehav_t AliTRDrawStream::fgErrorBehav[] = {
116   AliTRDrawStream::kTolerate,
117   AliTRDrawStream::kDiscardHC,
118   AliTRDrawStream::kTolerate,
119   AliTRDrawStream::kAbort,
120   AliTRDrawStream::kAbort,
121   AliTRDrawStream::kAbort,
122   AliTRDrawStream::kAbort,
123   AliTRDrawStream::kDiscardHC,
124   AliTRDrawStream::kDiscardHC,
125   AliTRDrawStream::kTolerate,
126   AliTRDrawStream::kTolerate,
127   AliTRDrawStream::kTolerate,
128   AliTRDrawStream::kTolerate,
129   AliTRDrawStream::kTolerate,
130   AliTRDrawStream::kTolerate,
131   AliTRDrawStream::kTolerate,
132   AliTRDrawStream::kTolerate,
133   AliTRDrawStream::kTolerate,
134   AliTRDrawStream::kTolerate,
135   AliTRDrawStream::kTolerate
136 };
137
138 AliTRDrawStream::AliTRDrawStream(AliRawReader *rawReader) :
139   fStoreError(&AliTRDrawStream::ForgetError),
140   fRawReader(rawReader),
141   fDigitsManager(0x0),
142   fDigitsParam(0x0),
143   fErrors(0x0),
144   fLastError(),
145   fErrorFlags(0),
146   fStats(),
147   fPayloadStart(0x0),
148   fPayloadCurr(0x0),
149   fPayloadSize(0),
150   fNtimebins(-1),
151   fLastEvId(-1),
152   fCurrSlot(-1),
153   fCurrLink(-1),
154   fCurrRobPos(-1),
155   fCurrMcmPos(-1),
156   fCurrEquipmentId(0),
157   fCurrSmHeaderSize(0),
158   fCurrSmHeaderVersion(0),
159   fCurrTrailerReadout(0),
160   fCurrTrgHeaderAvail(0),
161   fCurrTrgHeaderReadout(0),
162   fCurrTrkHeaderAvail(0),
163   fCurrStackEndmarkerAvail(0),
164   fCurrEvType(0),
165   fCurrTriggerEnable(0),
166   fCurrTriggerFired(0),
167   fCurrTrackEnable(0),
168   fCurrTrackletEnable(0),
169   fCurrStackMask(0),
170   fCurrTrkHeaderIndexWord(0x0),
171   fCurrTrkHeaderSize(0x0),
172   fCurrTrkFlags(0x0),
173   fCurrTrgHeaderIndexWord(0x0),
174   fCurrTrgHeaderSize(0x0),
175   fCurrTrgFlags(0x0),
176   fCurrStackIndexWord(0x0),
177   fCurrStackHeaderSize(0x0),
178   fCurrStackHeaderVersion(0x0),
179   fCurrLinkMask(0x0),
180   fCurrCleanCheckout(0x0),
181   fCurrBoardId(0x0),
182   fCurrHwRev(-1),
183   fCurrHwRevTMU(0x0),
184   fCurrLinkMonitorFlags(0x0),
185   fCurrLinkDataTypeFlags(0x0),
186   fCurrLinkDebugFlags(0x0),
187   fCurrMatchFlagsSRAM(0),
188   fCurrMatchFlagsPostBP(0),
189   fCurrChecksumStack(),
190   fCurrChecksumSIU(0),
191   fCurrSpecial(-1),
192   fCurrMajor(-1),
193   fCurrMinor(-1),
194   fCurrAddHcWords(-1),
195   fCurrSm(-1),
196   fCurrStack(-1),
197   fCurrLayer(-1),
198   fCurrSide(-1),
199   fCurrHC(-1),
200   fCurrCheck(-1),
201   fCurrNtimebins(-1),
202   fCurrBC(-1),
203   fCurrPtrgCnt(-1),
204   fCurrPtrgPhase(-1),
205   fNDumpMCMs(0),
206   fTrackletArray(0x0),
207   fAdcArray(0x0),
208   fSignalIndex(0x0),
209   fTrackletTree(0x0),
210   fTracklets(0x0),
211   fTracks(0x0),
212   fMarkers(0x0)
213 {
214   // default constructor
215
216   fCurrTrkHeaderIndexWord = new UInt_t[fgkNstacks];
217   fCurrTrkHeaderSize      = new UInt_t[fgkNstacks];
218   fCurrTrkFlags           = new ULong64_t[fgkNsectors*fgkNstacks];
219   fCurrTrgHeaderIndexWord = new UInt_t[fgkNtriggers];
220   fCurrTrgHeaderSize      = new UInt_t[fgkNtriggers];
221   fCurrTrgFlags           = new UInt_t[fgkNsectors];
222   fCurrStackIndexWord     = new UInt_t[fgkNstacks];
223   fCurrStackHeaderSize    = new UInt_t[fgkNstacks];
224   fCurrStackHeaderVersion = new UInt_t[fgkNstacks];
225   fCurrLinkMask           = new UInt_t[fgkNstacks];
226   fCurrCleanCheckout      = new UInt_t[fgkNstacks];
227   fCurrBoardId            = new UInt_t[fgkNstacks];
228   fCurrHwRevTMU           = new UInt_t[fgkNstacks];
229   fCurrLinkMonitorFlags   = new UInt_t[fgkNstacks * fgkNlinks];
230   fCurrLinkDataTypeFlags  = new UInt_t[fgkNstacks * fgkNlinks];
231   fCurrLinkDebugFlags     = new UInt_t[fgkNstacks * fgkNlinks];
232   for (Int_t iSector = 0; iSector < fgkNsectors; iSector++)
233     fCurrTrgFlags[iSector] = 0;
234   for (Int_t i = 0; i < 100; i++)
235     fDumpMCM[i] = 0;
236
237   // preparing TClonesArray
238   fTrackletArray = new TClonesArray("AliTRDtrackletWord", 256);
239
240   // setting up the error tree
241   fErrors = new TTree("errorStats", "Error statistics");
242   fErrors->SetDirectory(0x0);
243   fErrors->Branch("error", &fLastError);
244   fErrors->SetCircular(1000);
245   for (Int_t i = 0; i < 100; i++) {
246     fErrorBuffer[i] = 0;
247   }
248
249 }
250
251 AliTRDrawStream::~AliTRDrawStream()
252 {
253   // destructor
254
255   delete fErrors;
256
257   delete [] fCurrTrkHeaderIndexWord;
258   delete [] fCurrTrkHeaderSize;
259   delete [] fCurrTrkFlags;
260   delete [] fCurrTrgHeaderIndexWord;
261   delete [] fCurrTrgHeaderSize;
262   delete [] fCurrTrgFlags;
263   delete [] fCurrStackIndexWord;
264   delete [] fCurrStackHeaderSize;
265   delete [] fCurrStackHeaderVersion;
266   delete [] fCurrLinkMask;
267   delete [] fCurrCleanCheckout;
268   delete [] fCurrBoardId;
269   delete [] fCurrHwRevTMU;
270   delete [] fCurrLinkMonitorFlags;
271   delete [] fCurrLinkDataTypeFlags;
272   delete [] fCurrLinkDebugFlags;
273 }
274
275 Bool_t AliTRDrawStream::ReadEvent(TTree *trackletTree)
276 {
277   // read the current event from the raw reader and fill it to the digits manager
278
279   if (!fRawReader) {
280     AliError("No raw reader available");
281     return kFALSE;
282   }
283
284   // tracklet output
285   ConnectTracklets(trackletTree);
286
287   // some preparations
288   fDigitsParam = 0x0;
289
290   // loop over all DDLs
291   // data starts with GTU payload, i.e. SM index word
292   UChar_t *buffer = 0x0;
293
294   while (fRawReader->ReadNextData(buffer)) {
295
296     fCurrEquipmentId = fRawReader->GetEquipmentId();
297     AliDebug(2, Form("equipment: %i", fCurrEquipmentId));
298
299     if (fCurrEquipmentId < kDDLOffset || fCurrEquipmentId > kDDLMax) {
300       EquipmentError(kNonTrdEq, "Skipping");
301       continue;
302     }
303
304     if (fMarkers)
305       new ((*fMarkers)[fMarkers->GetEntriesFast()])
306         AliTRDrawStreamError(-kSecactive, fCurrEquipmentId - kDDLOffset);
307
308     ReadGTUHeaders((UInt_t*) buffer);
309
310     if (fCurrTrailerReadout)
311       ReadGTUTrailer();
312
313     // loop over all active links
314     AliDebug(2, Form("Stack mask 0x%02x", fCurrStackMask));
315     for (Int_t iStack = 0; iStack < fgkNstacks; iStack++) {
316       fCurrSlot = iStack;
317       if ((fCurrStackMask & (1 << fCurrSlot)) == 0)
318         continue;
319
320       AliDebug(2, Form("Stack %i, Link mask: 0x%02x", fCurrSlot, fCurrLinkMask[fCurrSlot]));
321       for (Int_t iLink = 0; iLink < fgkNlinks; iLink++) {
322         fCurrLink = iLink;
323         fCurrHC   = (fCurrEquipmentId - kDDLOffset) * fgkNstacks * fgkNlinks +
324           fCurrSlot * fgkNlinks + iLink;
325         if ((fCurrLinkMask[fCurrSlot] & (1 << fCurrLink)) == 0)
326           continue;
327
328         Int_t   size  = 0;
329
330         fErrorFlags = 0;
331         // check for link monitor error flag
332         if (fCurrLinkMonitorFlags[fCurrSlot*fgkNlinks + fCurrLink] != 0) {
333           LinkError(kLinkMonitor);
334           if (fgErrorBehav[kLinkMonitor] == kTolerate)
335             size += ReadLinkData();
336         }
337         else
338           // read the data from one HC
339           size += ReadLinkData();
340
341         // read all data endmarkers
342         size += SeekNextLink();
343       }
344
345       // continue with next stack
346       SeekNextStack();
347     }
348   }
349
350   return kTRUE;
351 }
352
353
354 Bool_t AliTRDrawStream::NextDDL()
355 {
356   // continue reading with the next equipment
357
358   if (!fRawReader)
359     return kFALSE;
360
361   fCurrEquipmentId = 0;
362   fCurrSlot = 0;
363   fCurrLink = 0;
364
365   UChar_t *buffer = 0x0;
366
367   while (fRawReader->ReadNextData(buffer)) {
368
369     fCurrEquipmentId = fRawReader->GetEquipmentId();
370     AliDebug(2, Form("equipment: %i", fCurrEquipmentId));
371
372     if (fCurrEquipmentId < kDDLOffset || fCurrEquipmentId > kDDLMax) {
373       EquipmentError(kNonTrdEq, "Skipping");
374       continue;
375     }
376
377     if (fMarkers)
378       new ((*fMarkers)[fMarkers->GetEntriesFast()])
379         AliTRDrawStreamError(-kSecactive, fCurrEquipmentId - kDDLOffset);
380
381     ReadGTUHeaders((UInt_t*) buffer);
382
383     if (fCurrTrailerReadout)
384       ReadGTUTrailer();
385
386     return kTRUE;
387   }
388
389   return kFALSE;
390 }
391
392
393 Int_t AliTRDrawStream::NextChamber(AliTRDdigitsManager *digMgr)
394 {
395   // read the data for the next chamber
396   // in case you only want to read the data of a single chamber
397   // to read all data ReadEvent(...) is recommended
398
399   fDigitsManager = digMgr;
400   fDigitsParam   = 0x0;
401
402   fErrorFlags = 0;
403
404   // tracklet output preparation
405   TTree *trklTree = 0x0;
406   AliRunLoader *rl = AliRunLoader::Instance();
407   AliLoader* trdLoader = rl ? rl->GetLoader("TRDLoader") : NULL;
408   AliDataLoader *trklLoader = trdLoader ? trdLoader->GetDataLoader("tracklets") : NULL;
409   if (trklLoader) {
410     AliTreeLoader *trklTreeLoader = (AliTreeLoader*) trklLoader->GetBaseLoader("tracklets-raw");
411     if (trklTreeLoader)
412       trklTree = trklTreeLoader->Tree();
413     else
414       trklTree = trklLoader->Tree();
415   }
416
417   if (fTrackletTree != trklTree)
418     ConnectTracklets(trklTree);
419
420   if (!fRawReader) {
421     AliError("No raw reader available");
422     return -1;
423   }
424
425   while (fCurrSlot < 0 || fCurrSlot >= fgkNstacks) {
426     if (!NextDDL()) {
427       fCurrSlot = -1;
428       return -1;
429     }
430     while ((fCurrSlot < fgkNstacks) &&
431            (((fCurrStackMask & (1 << fCurrSlot)) == 0) ||
432             ((fCurrLinkMask[fCurrSlot] & (1 << fCurrLink))) == 0)) {
433       fCurrLink++;
434       if (fCurrLink >= fgkNlinks) {
435         fCurrLink = 0;
436         fCurrSlot++;
437       }
438     }
439   }
440
441   AliDebug(2, Form("Stack %i, Link %i, mask: 0x%02x", fCurrSlot, fCurrLink, fCurrLinkMask[fCurrSlot]));
442   fCurrHC   = (fCurrEquipmentId - kDDLOffset) * fgkNlinks * fgkNstacks +
443     fCurrSlot * fgkNlinks + fCurrLink;
444
445   if (fCurrLinkMonitorFlags[fCurrSlot*fgkNlinks + fCurrLink] != 0) {
446     LinkError(kLinkMonitor);
447     if (fgErrorBehav[kLinkMonitor] == kTolerate)
448       ReadLinkData();
449   }
450   else
451     // read the data from one HC
452     ReadLinkData();
453
454   // read all data endmarkers
455   SeekNextLink();
456
457   if (fCurrLink % 2 == 0) {
458     // if we just read the A-side HC then also check the B-side
459     fCurrLink++;
460     fCurrHC++;
461     if (fCurrLinkMask[fCurrSlot] & (1 << fCurrLink)) {
462       if (fCurrLinkMonitorFlags[fCurrSlot*fgkNlinks + fCurrLink] != 0) {
463         LinkError(kLinkMonitor);
464         if (fgErrorBehav[kLinkMonitor] == kTolerate)
465           ReadLinkData();
466       }
467       else {
468         ReadLinkData();
469       }
470       SeekNextLink();
471     }
472   }
473
474   do {
475     if ((fCurrStackMask & (1 << fCurrSlot)) == 0) {
476       fCurrLink = 0;
477       fCurrSlot++;
478     }
479     else {
480       fCurrLink++;
481       if (fCurrLink >= fgkNlinks) {
482         SeekNextStack();
483         fCurrLink = 0;
484         fCurrSlot++;
485       }
486     }
487   } while ((fCurrSlot < fgkNstacks) &&
488            (((fCurrStackMask & (1 << fCurrSlot)) == 0) ||
489             ((fCurrLinkMask[fCurrSlot] & (1 << fCurrLink))) == 0));
490
491   // return chamber information from HC if it is valid
492   // otherwise return information from link position
493   if (fCurrSm < 0 || fCurrSm >= fgkNsectors || fCurrStack < 0 || fCurrStack >= fgkNstacks || fCurrLayer < 0 || fCurrLayer >= fgkNlinks/2)
494     return ((fCurrEquipmentId-kDDLOffset) + fCurrSlot * fgkNlinks/2 + fCurrLink/2);
495   else
496     return (fCurrSm * fgkNstacks*fgkNlinks/2 + fCurrStack * fgkNlinks/2 + fCurrLayer);
497 }
498
499
500 Int_t AliTRDrawStream::ReadGTUHeaders(UInt_t *buffer)
501 {
502   // check the data source and read the headers
503
504   if (fCurrEquipmentId >= kDDLOffset && fCurrEquipmentId <= kDDLMax) {
505     // this is ROC data
506
507     // setting the pointer to data and current reading position
508     fPayloadCurr = fPayloadStart = buffer;
509     fPayloadSize = fRawReader->GetDataSize() / sizeof(UInt_t);
510     fStats.fStatsSector[fCurrEquipmentId - kDDLOffset].fBytes = fRawReader->GetDataSize();
511     AliDebug(2, Form("Read buffer of size: %i", fRawReader->GetDataSize()));
512
513     AliDebug(1, DumpRaw("raw data", fPayloadCurr, TMath::Min(fPayloadSize, 1000)));
514
515     // read SM header
516     if (ReadSmHeader() < 0) {
517       AliError(Form("Reading SM header failed, skipping this DDL %i", fCurrEquipmentId));
518       return -1;
519     }
520
521     // read tracking headers (if available)
522     if (fCurrTrkHeaderAvail) {
523       for (Int_t iStack = 0; iStack < fgkNstacks; iStack++) {
524         if ((fCurrStackMask & (1 << iStack)) != 0)
525           ReadTrackingHeader(iStack);
526       }
527     }
528
529     // read trigger header(s) (if available)
530     if (fCurrTrgHeaderAvail)
531       ReadTriggerHeaders();
532
533     // read stack header
534     for (Int_t iStack = 0; iStack < fgkNstacks; iStack++) {
535       if ((fCurrStackMask & (1 << iStack)) != 0)
536         ReadStackHeader(iStack);
537     }
538
539     return 0;
540   }
541   else
542     return -1;
543 }
544
545 Int_t AliTRDrawStream::ReadSmHeader()
546 {
547   // read the SMU index header at the current reading position
548   // and store the information in the corresponding variables
549
550   if (fPayloadCurr - fPayloadStart >= fPayloadSize - 1) {
551     EquipmentError(kUnknown, "SM Header incomplete");
552     return -1;
553   }
554
555   fCurrTrgFlags[fCurrEquipmentId-kDDLOffset] = 0;
556
557   fCurrSmHeaderSize           = ((*fPayloadCurr) >> 16) & 0xffff;
558   fCurrSmHeaderVersion        = ((*fPayloadCurr) >> 12) &    0xf;
559   fCurrTrackEnable            = ((*fPayloadCurr) >>  6) &    0x1;
560   fCurrTrackletEnable         = ((*fPayloadCurr) >>  5) &    0x1;
561   fCurrStackMask              = ((*fPayloadCurr)      ) &   0x1f;
562   fCurrHwRev                  = (fPayloadCurr[1] >> 12) & 0xffff;
563   fCurrStackEndmarkerAvail    = 0;
564
565   switch (fCurrSmHeaderVersion) {
566   case 0xb:
567     fCurrTrailerReadout = 0;
568     fCurrTrgHeaderAvail = 0;
569     fCurrEvType = 0;
570     fCurrTrkHeaderAvail = 0;
571
572     DecodeGTUtracks();
573     break;
574
575   case 0xc:
576     fCurrTrailerReadout = ((*fPayloadCurr) >> 10) &    0x1;
577     fCurrTrgHeaderAvail = 1;
578     fCurrTrgHeaderReadout = ((*fPayloadCurr) >>  9) &    0x1;
579     fCurrEvType         = ((*fPayloadCurr) >>  7) &    0x3;
580     fCurrTrkHeaderAvail = fCurrTrackEnable;
581     fCurrTriggerEnable  = (fPayloadCurr[2] >>  8) &  0xfff;
582     fCurrTriggerFired   = (fPayloadCurr[2] >>  20) &  0xfff;
583     fCurrTrgFlags[fCurrEquipmentId-kDDLOffset] = fCurrTriggerFired;
584     break;
585
586   case 0xd:
587     fCurrTrailerReadout = ((*fPayloadCurr) >> 10) &    0x1;
588     fCurrTrgHeaderAvail = 1;
589     fCurrTrgHeaderReadout = ((*fPayloadCurr) >>  9) &    0x1;
590     fCurrEvType         = ((*fPayloadCurr) >>  7) &    0x3;
591     fCurrTrkHeaderAvail = fCurrTrackEnable;
592     fCurrTriggerEnable  = (fPayloadCurr[2] >>  8) &  0xfff;
593     fCurrTriggerFired   = (fPayloadCurr[2] >>  20) &  0xfff;
594     fCurrTrgFlags[fCurrEquipmentId-kDDLOffset] = fCurrTriggerFired;
595     fCurrStackEndmarkerAvail    = 1;
596     break;
597
598   default:
599     AliError(Form("unknown SM header version: 0x%x", fCurrSmHeaderVersion));
600   }
601
602   AliDebug(5, Form("SM header: size: %i, version: %i, track enable: %i, tracklet enable: %i, stack mask: %2x, trailer: %i, trgheader: %i, trkheader: %i",
603                    fCurrSmHeaderSize,
604                    fCurrSmHeaderVersion,
605                    fCurrTrackEnable,
606                    fCurrTrackletEnable,
607                    fCurrStackMask,
608                    fCurrTrailerReadout,
609                    fCurrTrgHeaderAvail,
610                    fCurrTrkHeaderAvail ));
611
612   // jump to the first word after the SM header
613   fPayloadCurr += fCurrSmHeaderSize + 1;
614
615   return fCurrSmHeaderSize + 1;
616 }
617
618 Int_t AliTRDrawStream::DecodeGTUtracks()
619 {
620   // decode GTU track words
621   // this depends on the hardware revision of the SMU
622
623   Int_t sector = fCurrEquipmentId-kDDLOffset;
624
625   if ((sector < 0) || (sector > 17)) {
626     AliError(Form("Invalid sector %i for GTU tracks", sector));
627     return -1;
628   }
629
630   AliDebug(1, DumpRaw(Form("GTU tracks in sector %2i (hw rev %i)", sector, fCurrHwRev),
631                       fPayloadCurr + 4, 10, 0xffe0ffff));
632
633   fCurrTrgFlags[sector] = 0;
634
635   if (fCurrHwRev < 1772) {
636     UInt_t    fastWord;         // fast trigger word
637     ULong64_t trackWord = 0;    // extended track word
638     Int_t stack = 0;
639     Int_t idx = 0;
640     for (UInt_t iWord = 4; iWord < fCurrSmHeaderSize; iWord++) {
641       if (fPayloadCurr[iWord] == 0x10000000) { // stack boundary marker
642         stack++;
643         idx = 0;
644       }
645       else {
646         if ((idx == 0) &&
647             ((fPayloadCurr[iWord] & 0xfffff0f0) == 0x13370000)) {
648           fastWord = fPayloadCurr[iWord];
649           fCurrTrgFlags[sector] |= 1 << (stack+11); // assume tracking done if fast word sent
650           AliDebug(1, Form("stack %i: fast trigger word: 0x%08x", stack, fastWord));
651           continue;
652         }
653         else if ((idx & 0x1) == 0x1) {
654           trackWord |= ((ULong64_t) fPayloadCurr[iWord]) << 32;
655           AliDebug(1,Form("track debug word: 0x%016llx", trackWord));
656           if (fTracks) {
657             AliESDTrdTrack *trk = new ((*fTracks)[fTracks->GetEntriesFast()])
658               AliESDTrdTrack();
659
660             trk->SetSector(sector);
661             trk->SetStack((trackWord >> 60) & 0x7);
662             trk->SetA(0);
663             trk->SetB(0);
664             trk->SetPID(0);
665             trk->SetLayerMask((trackWord >> 16) & 0x3f);
666             trk->SetTrackletIndex((trackWord >> 22) & 0x3f, 0);
667             trk->SetTrackletIndex((trackWord >> 28) & 0x3f, 1);
668             trk->SetTrackletIndex((trackWord >> 34) & 0x3f, 2);
669             trk->SetTrackletIndex((trackWord >> 40) & 0x3f, 3);
670             trk->SetTrackletIndex((trackWord >> 46) & 0x3f, 4);
671             trk->SetTrackletIndex((trackWord >> 52) & 0x3f, 5);
672
673             trk->SetFlags(0);
674             trk->SetReserved(0);
675             trk->SetLabel(-3);
676
677             Float_t pt = (((Int_t) (trackWord & 0xffff) ^ 0x8000) - 0x8000)/128.;
678             if (TMath::Abs(pt) > 0.1) {
679               trk->SetA((Int_t) (0.15*51625./100./pt / 160e-4 * 2));
680             }
681           }
682         }
683         else {
684           trackWord = fPayloadCurr[iWord];
685         }
686         idx++;
687       }
688     }
689   }
690   else if (fCurrHwRev < 1804) {
691     UInt_t    fastWord;         // fast trigger word
692     ULong64_t trackWord = 0;    // extended track word
693     Int_t stack = 0;
694     Int_t idx = 0;
695     for (UInt_t iWord = 4; iWord < fCurrSmHeaderSize; iWord++) {
696       if (fPayloadCurr[iWord] == 0xffe0ffff) { // stack boundary marker
697         stack++;
698         idx = 0;
699       }
700       else {
701         if ((idx == 0) &&
702             ((fPayloadCurr[iWord] & 0xfffff0f0) == 0x13370000)) {
703           fastWord = fPayloadCurr[iWord];
704           fCurrTrgFlags[sector] |= 1 << (stack+11); // assume tracking done if fast word sent
705           AliDebug(1, Form("stack %i: fast trigger word: 0x%08x", stack, fastWord));
706           continue;
707         }
708         else if ((idx & 0x1) == 0x1) {
709           trackWord |= ((ULong64_t) fPayloadCurr[iWord]) << 32;
710           AliDebug(1, Form("track debug word: 0x%016llx", trackWord));
711           if (fTracks) {
712             AliESDTrdTrack *trk = new ((*fTracks)[fTracks->GetEntriesFast()])
713               AliESDTrdTrack();
714
715             trk->SetSector(fCurrEquipmentId-kDDLOffset);
716             trk->SetStack((trackWord >> 60) & 0x7);
717             trk->SetA(0);
718             trk->SetB(0);
719             trk->SetPID(0);
720             trk->SetLayerMask((trackWord >> 16) & 0x3f);
721             trk->SetTrackletIndex((trackWord >> 22) & 0x3f, 0);
722             trk->SetTrackletIndex((trackWord >> 28) & 0x3f, 1);
723             trk->SetTrackletIndex((trackWord >> 34) & 0x3f, 2);
724             trk->SetTrackletIndex((trackWord >> 40) & 0x3f, 3);
725             trk->SetTrackletIndex((trackWord >> 46) & 0x3f, 4);
726             trk->SetTrackletIndex((trackWord >> 52) & 0x3f, 5);
727
728             trk->SetFlags(0);
729             trk->SetReserved(0);
730             trk->SetLabel(-3);
731
732             Float_t pt = (((Int_t) (trackWord & 0xffff) ^ 0x8000) - 0x8000)/128.;
733             if (TMath::Abs(pt) > 0.1) {
734               trk->SetA((Int_t) (-0.15*51625./100./pt / 160e-4 * 2));
735             }
736           }
737         }
738         else {
739           trackWord = fPayloadCurr[iWord];
740         }
741         idx++;
742       }
743     }
744   }
745   else if (fCurrHwRev < 1819) {
746     UInt_t    fastWord;         // fast trigger word
747     ULong64_t trackWord = 0;    // extended track word
748     Int_t stack = 0;
749     Int_t idx = 0;
750     for (UInt_t iWord = 4; iWord < fCurrSmHeaderSize; iWord++) {
751       if (fPayloadCurr[iWord] == 0xffe0ffff) { // stack boundary marker
752         stack++;
753         idx = 0;
754       }
755       else {
756         if ((idx == 0) &&
757             ((fPayloadCurr[iWord] & 0xfffff0f0) == 0x13370000)) {
758           fastWord = fPayloadCurr[iWord];
759           if (fastWord & (1 << 13))
760             fCurrTrgFlags[sector] |= 1 << (stack+11);
761           AliDebug(1, Form("stack %i: fast trigger word: 0x%08x", stack, fastWord));
762           continue;
763         }
764         else if ((idx & 0x1) == 0x1) {
765           trackWord |= ((ULong64_t) fPayloadCurr[iWord]) << 32;
766           AliDebug(1, Form("track debug word: 0x%016llx", trackWord));
767
768           if (fTracks) {
769             AliESDTrdTrack *trk = new ((*fTracks)[fTracks->GetEntriesFast()])
770               AliESDTrdTrack();
771
772             trk->SetSector(fCurrEquipmentId-kDDLOffset);
773             trk->SetStack((trackWord >> 60) & 0x7);
774             trk->SetA(0);
775             trk->SetB(0);
776             // trk->SetPt(((trackWord & 0xffff) ^ 0x8000) - 0x8000);
777             trk->SetPID(0);
778             trk->SetLayerMask((trackWord >> 16) & 0x3f);
779             trk->SetTrackletIndex((trackWord >> 22) & 0x3f, 0);
780             trk->SetTrackletIndex((trackWord >> 28) & 0x3f, 1);
781             trk->SetTrackletIndex((trackWord >> 34) & 0x3f, 2);
782             trk->SetTrackletIndex((trackWord >> 40) & 0x3f, 3);
783             trk->SetTrackletIndex((trackWord >> 46) & 0x3f, 4);
784             trk->SetTrackletIndex((trackWord >> 52) & 0x3f, 5);
785
786             trk->SetFlags(0);
787             trk->SetReserved(0);
788             trk->SetLabel(-3);
789
790             Float_t pt = (((Int_t) (trackWord & 0xffff) ^ 0x8000) - 0x8000)/128.;
791             if (TMath::Abs(pt) > 0.1) {
792               trk->SetA((Int_t) (0.15*51625./100./trk->Pt() / 160e-4 * 2));
793             }
794           }
795         }
796         else {
797           trackWord = fPayloadCurr[iWord];
798         }
799         idx++;
800       }
801     }
802   }
803   else if (fCurrHwRev < 1860) {
804     UInt_t    fastWord;         // fast trigger word
805     ULong64_t trackWord = 0;    // extended track word
806     Int_t stack = 0;
807     Int_t idx = 0;
808     Bool_t upperWord = kFALSE;
809     Int_t word = 0;
810     for (UInt_t iWord = 4; iWord < fCurrSmHeaderSize; iWord++) {
811       if (fPayloadCurr[iWord] == 0xffe0ffff) { // stack boundary marker
812         stack++;
813         idx = 0;
814         upperWord = kFALSE;
815       }
816       else {
817         // assemble the 32-bit words out of 16-bit blocks
818         if (upperWord) {
819           word |= (fPayloadCurr[iWord] & 0xffff0000);
820           upperWord = kFALSE;
821         }
822         else {
823           // lower word is read first
824           word = (fPayloadCurr[iWord] & 0xffff0000) >> 16;
825           upperWord = kTRUE;
826           continue;
827         }
828
829         if ((word & 0xffff0008) == 0x13370008) {
830           fastWord = word;
831           AliDebug(1, Form("stack %i: fast track word: 0x%08x", stack, fastWord));
832           if (fastWord & (1 << 13))
833             fCurrTrgFlags[sector] |= 1 << (stack+11);
834           continue;
835         }
836         else if ((idx & 0x1) == 0x1) {
837           trackWord |= ((ULong64_t) word) << 32;
838           AliDebug(1, Form("track debug word: 0x%016llx", trackWord));
839           if (fTracks) {
840             AliESDTrdTrack *trk = new ((*fTracks)[fTracks->GetEntriesFast()])
841               AliESDTrdTrack();
842
843             trk->SetSector(fCurrEquipmentId-kDDLOffset);
844             trk->SetStack((trackWord >> 60) & 0x7);
845             trk->SetA(0);
846             trk->SetB(0);
847             trk->SetPID(0);
848             trk->SetLayerMask((trackWord >> 16) & 0x3f);
849             trk->SetTrackletIndex((trackWord >> 22) & 0x3f, 0);
850             trk->SetTrackletIndex((trackWord >> 28) & 0x3f, 1);
851             trk->SetTrackletIndex((trackWord >> 34) & 0x3f, 2);
852             trk->SetTrackletIndex((trackWord >> 40) & 0x3f, 3);
853             trk->SetTrackletIndex((trackWord >> 46) & 0x3f, 4);
854             trk->SetTrackletIndex((trackWord >> 52) & 0x3f, 5);
855
856             trk->SetFlags(0);
857             trk->SetReserved(0);
858             trk->SetLabel(-3);
859
860             Float_t pt = (((Int_t) (trackWord & 0xffff) ^ 0x8000) - 0x8000)/128.;
861             if (TMath::Abs(pt) > 0.1) {
862               trk->SetA((Int_t) (0.15*51625./100./pt / 160e-4 * 2));
863             }
864           }
865         }
866         else {
867           trackWord = word;
868         }
869         idx++;
870       }
871     }
872
873   }
874   else {
875     ULong64_t trackWord = 0; // this is the debug word
876     Int_t stack = 0;
877     Int_t idx = 0;
878     Bool_t upperWord = kFALSE;
879     Int_t word = 0;
880     for (UInt_t iWord = 4; iWord < fCurrSmHeaderSize; iWord++) {
881       if (fPayloadCurr[iWord] == 0xffe0ffff) {
882         stack++;
883         idx = 0;
884         upperWord = kFALSE;
885       }
886       else {
887         // assemble the 32-bit words out of 16-bit blocks
888         if (upperWord) {
889           word |= (fPayloadCurr[iWord] & 0xffff0000);
890           upperWord = kFALSE;
891         }
892         else {
893           // lower word is read first
894           word = (fPayloadCurr[iWord] & 0xffff0000) >> 16;
895           upperWord = kTRUE;
896           continue;
897         }
898
899         if ((word & 0xffff0008) == 0x13370008) {
900           AliDebug(1, Form("stack %i: fast track word: 0x%08x", stack, word));
901           continue;
902         }
903         else if ((word & 0xffff0010) == 0x13370010) {
904           AliDebug(1, Form("stack %i: tracking done word: 0x%08x", stack, word));
905           fCurrTrgFlags[sector] |= 1 << (stack+11);
906           continue;
907         }
908         else if ((idx & 0x1) == 0x1) {
909           trackWord |= ((ULong64_t) word) << 32;
910           AliDebug(1, Form("track debug word: 0x%16llx", trackWord));
911           if (fTracks) {
912             AliESDTrdTrack *trk = new ((*fTracks)[fTracks->GetEntriesFast()])
913               AliESDTrdTrack();
914             trk->SetSector(fCurrEquipmentId-kDDLOffset);
915             trk->SetStack((trackWord >> 60) & 0x7);
916             trk->SetA(0);
917             trk->SetB(0);
918             trk->SetPID(0);
919             trk->SetLayerMask((trackWord >> 16) & 0x3f);
920             trk->SetTrackletIndex((trackWord >> 22) & 0x3f, 0);
921             trk->SetTrackletIndex((trackWord >> 28) & 0x3f, 1);
922             trk->SetTrackletIndex((trackWord >> 34) & 0x3f, 2);
923             trk->SetTrackletIndex((trackWord >> 40) & 0x3f, 3);
924             trk->SetTrackletIndex((trackWord >> 46) & 0x3f, 4);
925             trk->SetTrackletIndex((trackWord >> 52) & 0x3f, 5);
926
927             trk->SetFlags(0);
928             trk->SetReserved(0);
929             trk->SetLabel(-3);
930
931             Float_t pt = (((Int_t) (trackWord & 0xffff) ^ 0x8000) - 0x8000)/128.;
932             if (TMath::Abs(pt) > 0.1) {
933               trk->SetA(-(Int_t) (0.15*51625./100./pt / 160e-4 * 2));
934             }
935           }
936         }
937         else {
938           trackWord = word;
939         }
940         idx++;
941       }
942     }
943   }
944   return 0;
945 }
946
947 Int_t AliTRDrawStream::ReadTrackingHeader(Int_t stack)
948 {
949   // read the tracking information and store it for the given stack
950
951   // index word
952
953   fCurrTrkHeaderIndexWord[stack] = *fPayloadCurr;
954   fCurrTrkHeaderSize[stack]      = ((*fPayloadCurr) >> 16) & 0x3ff;
955
956   AliDebug(1, Form("tracking header index word: 0x%08x, size: %i (hw rev: %i)",
957                    fCurrTrkHeaderIndexWord[stack], fCurrTrkHeaderSize[stack], fCurrHwRev));
958   Int_t trackingTime = *fPayloadCurr & 0x3ff;
959
960   fCurrTrgFlags[fCurrEquipmentId-kDDLOffset] |= ((fCurrTrkHeaderIndexWord[stack] >> 10) & 0x1) << (22 + stack);
961   fPayloadCurr++;
962
963   // data words
964   ULong64_t trackWord = 0;
965   Int_t idx = 0;
966   Int_t trackIndex = fTracks ? fTracks->GetEntriesFast() : -1;
967
968   for (UInt_t iWord = 0; iWord < fCurrTrkHeaderSize[stack]; iWord++) {
969
970     if (!(idx & 0x1)) {
971       // first part of 64-bit word
972       trackWord = fPayloadCurr[iWord];
973     }
974     else {
975       trackWord |= ((ULong64_t) fPayloadCurr[iWord]) << 32;
976
977       if (trackWord & (1ul << 63)) {
978         if ((trackWord & (0x3ful << 56)) != 0) {
979           // track word
980           AliDebug(2, Form("track word: 0x%016llx", trackWord));
981
982           if (fTracks) {
983             AliESDTrdTrack *trk = new ((*fTracks)[fTracks->GetEntriesFast()])
984               AliESDTrdTrack();
985
986             trk->SetSector(fCurrEquipmentId-kDDLOffset);
987             trk->SetLayerMask((trackWord >> 56) & 0x3f);
988             trk->SetA( (((trackWord >> 38) & 0x3ffff) ^ 0x20000) - 0x20000);
989             trk->SetB( (((trackWord >> 20) & 0x3ffff) ^ 0x20000) - 0x20000);
990             trk->SetC( (((trackWord >> 8)  &  0xffff) ^  0x8000) -  0x8000);
991             trk->SetPID((trackWord >>  0) & 0xff);
992             trk->SetStack(stack);
993             trk->SetLabel(-3);
994
995             // now compare the track word with the one generated from the ESD information
996             if (trackWord != trk->GetTrackWord(0)) {
997               AliError(Form("track word 0x%016llx does not match the read one 0x%016llx",
998                             trk->GetTrackWord(0), trackWord));
999             }
1000           }
1001         }
1002         else {
1003           // done marker (so far only used to set trigger flag)
1004           fCurrTrgFlags[fCurrEquipmentId-kDDLOffset] |= 1 << (27 + stack);
1005           fCurrTrkFlags[(fCurrEquipmentId-kDDLOffset)*fgkNstacks + stack] = trackWord;
1006
1007           AliDebug(2, Form("tracking done marker: 0x%016llx, trigger flags: 0x%08x",
1008                            trackWord, fCurrTrgFlags[fCurrEquipmentId-kDDLOffset]));
1009           AliDebug(2, Form("seg / stack / first / last / done / index : %i %i %lli %lli %lli %i",
1010                            fCurrEquipmentId - kDDLOffset, stack,
1011                            (trackWord >> 20) & 0x3ff,
1012                            (trackWord >> 10) & 0x3ff,
1013                            (trackWord >>  0) & 0x3ff,
1014                            trackingTime));
1015         }
1016       }
1017       else {
1018         // extended track word
1019         AliDebug(2, Form("extended track word: 0x%016llx", trackWord));
1020
1021         if (fTracks) {
1022           AliESDTrdTrack *trk = (AliESDTrdTrack*) (*fTracks)[trackIndex];
1023
1024           trk->SetFlags((trackWord >> 52) & 0x7ff);
1025           trk->SetReserved((trackWord >> 49) & 0x7);
1026           trk->SetY((trackWord >> 36) & 0x1fff);
1027           trk->SetTrackletIndex((trackWord >>  0) & 0x3f, 0);
1028           trk->SetTrackletIndex((trackWord >>  6) & 0x3f, 1);
1029           trk->SetTrackletIndex((trackWord >> 12) & 0x3f, 2);
1030           trk->SetTrackletIndex((trackWord >> 18) & 0x3f, 3);
1031           trk->SetTrackletIndex((trackWord >> 24) & 0x3f, 4);
1032           trk->SetTrackletIndex((trackWord >> 30) & 0x3f, 5);
1033
1034           if (trackWord != trk->GetExtendedTrackWord(0)) {
1035             AliError(Form("extended track word 0x%016llx does not match the read one 0x%016llx",
1036                           trk->GetExtendedTrackWord(0), trackWord));
1037             }
1038
1039           trackIndex++;
1040         }
1041       }
1042     }
1043     idx++;
1044   }
1045
1046   fPayloadCurr += fCurrTrkHeaderSize[stack];
1047
1048   return fCurrTrkHeaderSize[stack];
1049 }
1050
1051 Int_t AliTRDrawStream::ReadTriggerHeaders()
1052 {
1053   // read all trigger headers present
1054
1055   AliDebug(1, Form("trigger mask: 0x%03x, fired: 0x%03x\n",
1056                    fCurrTriggerEnable, fCurrTriggerFired));
1057   // loop over potential trigger blocks
1058   for (Int_t iTrigger = 0; iTrigger < fgkNtriggers; iTrigger++) {
1059     // check for trigger enable
1060     if (fCurrTriggerEnable & (1 << iTrigger)) {
1061       // check for readout mode and trigger fired
1062       if ((fCurrTrgHeaderReadout == 0) || (fCurrTriggerFired & (1 << iTrigger))) {
1063         // index word
1064         AliDebug(1, Form("trigger index word %i: 0x%08x\n", iTrigger, *fPayloadCurr));
1065         fCurrTrgHeaderIndexWord[iTrigger] = *fPayloadCurr;
1066         fCurrTrgHeaderSize[iTrigger]      = ((*fPayloadCurr) >> 16) & 0x3ff;
1067         if (iTrigger == 7) {
1068           // timeout trigger, use to extract tracking time
1069           fCurrTrgFlags[fCurrEquipmentId-kDDLOffset] |= (*fPayloadCurr & 0x3ff) << 12;
1070         }
1071
1072         fPayloadCurr++;
1073         // data words
1074         fPayloadCurr += fCurrTrgHeaderSize[iTrigger];
1075       }
1076     }
1077   }
1078
1079   return 0;
1080 }
1081
1082 Int_t AliTRDrawStream::ReadStackHeader(Int_t stack)
1083 {
1084   // read the stack header
1085   // and store the information in the corresponding variables
1086
1087   fCurrStackIndexWord[stack]     = *fPayloadCurr;
1088   fCurrStackHeaderSize[stack]    = (((*fPayloadCurr) >> 16) & 0xffff) + 1;
1089   fCurrStackHeaderVersion[stack] = ((*fPayloadCurr) >> 12) & 0xf;
1090   fCurrLinkMask[stack]           = (*fPayloadCurr) & 0xfff;
1091
1092   // dumping stack header
1093   AliDebug(1, DumpRaw(Form("stack %i header", stack), fPayloadCurr, fCurrStackHeaderSize[stack]));
1094
1095   if (fPayloadCurr - fPayloadStart >= fPayloadSize - (Int_t) fCurrStackHeaderSize[stack]) {
1096     EquipmentError(kStackHeaderInvalid, "Stack index header %i incomplete", stack);
1097     // dumping stack header
1098     AliError(DumpRaw(Form("stack %i header", stack), fPayloadCurr, fCurrStackHeaderSize[stack]));
1099
1100     return -1;
1101   }
1102
1103   switch (fCurrStackHeaderVersion[stack]) {
1104   case 0xa:
1105     if (fCurrStackHeaderSize[stack] < 8) {
1106       LinkError(kStackHeaderInvalid, "Stack header smaller than expected!");
1107       return -1;
1108     }
1109
1110     fCurrCleanCheckout[stack] = fPayloadCurr[1] & 0x1;
1111     fCurrBoardId[stack]       = (fPayloadCurr[1] >> 8) & 0xff;
1112     fCurrHwRevTMU[stack]      = (fPayloadCurr[1] >> 16) & 0xffff;
1113
1114     for (Int_t iLayer = 0; iLayer < 6; iLayer++) {
1115       // A side
1116       fCurrLinkMonitorFlags  [stack*fgkNlinks + iLayer*2]      = fPayloadCurr[iLayer+2] & 0xf;
1117       fCurrLinkDataTypeFlags [stack*fgkNlinks + iLayer*2]      = (fPayloadCurr[iLayer+2] >> 4) & 0x3;
1118       fCurrLinkDebugFlags    [stack*fgkNlinks + iLayer*2]      = (fPayloadCurr[iLayer+2] >> 12) & 0xf;
1119       // B side
1120       fCurrLinkMonitorFlags  [stack*fgkNlinks + iLayer*2 + 1]  = (fPayloadCurr[iLayer+2] >> 16) & 0xf;
1121       fCurrLinkDataTypeFlags [stack*fgkNlinks + iLayer*2 + 1]  = (fPayloadCurr[iLayer+2] >> 20) & 0x3;
1122       fCurrLinkDebugFlags    [stack*fgkNlinks + iLayer*2 + 1]  = (fPayloadCurr[iLayer+2] >> 28) & 0xf;
1123     }
1124     break;
1125
1126   default:
1127     LinkError(kStackHeaderInvalid, "Invalid Stack Header version %x", fCurrStackHeaderVersion[stack]);
1128   }
1129
1130   fPayloadCurr += fCurrStackHeaderSize[stack];
1131
1132   return fCurrStackHeaderSize[stack];
1133 }
1134
1135 Int_t AliTRDrawStream::ReadGTUTrailer()
1136 {
1137   // read the SM trailer containing CRCs from various stages
1138
1139   UInt_t* trailer = fPayloadStart + fPayloadSize -1;
1140
1141   // look for the trailer index word from the end
1142   for (Int_t iWord = 0; iWord < fPayloadSize; iWord++) {
1143     if ((fPayloadStart[fPayloadSize-1-iWord] & 0xffff) == 0x1f51) {
1144       trailer = fPayloadStart + fPayloadSize - 1 - iWord;
1145       break;
1146     }
1147   }
1148
1149   if (((*trailer) & 0xffff) == 0x1f51) {
1150     UInt_t trailerIndexWord = (*trailer);
1151     Int_t trailerSize = (trailerIndexWord >> 16) & 0xffff;
1152     AliDebug(2, DumpRaw("GTU trailer", trailer, trailerSize+1));
1153     // parse the trailer
1154     if (trailerSize >= 4) {
1155       // match flags from GTU
1156       fCurrMatchFlagsSRAM     = (trailer[1] >>  0) &    0x1f;
1157       fCurrMatchFlagsPostBP   = (trailer[1] >>  5) &    0x1f;
1158       // individual checksums
1159       fCurrChecksumStack[0]   = (trailer[1] >> 16) &  0xffff;
1160       fCurrChecksumStack[1]   = (trailer[2] >>  0) &  0xffff;
1161       fCurrChecksumStack[2]   = (trailer[2] >> 16) &  0xffff;
1162       fCurrChecksumStack[3]   = (trailer[3] >>  0) &  0xffff;
1163       fCurrChecksumStack[4]   = (trailer[3] >> 16) &  0xffff;
1164       fCurrChecksumSIU        = trailer[4];
1165
1166       if ((fCurrMatchFlagsSRAM & fCurrStackMask) != fCurrStackMask)
1167         EquipmentError(kCRCmismatch, "CRC mismatch SRAM: 0x%02x", fCurrMatchFlagsSRAM);
1168       if ((fCurrMatchFlagsPostBP & fCurrStackMask) != fCurrStackMask)
1169         EquipmentError(kCRCmismatch, "CRC mismatch BP: 0x%02x", fCurrMatchFlagsPostBP);
1170
1171     }
1172     else {
1173       LinkError(kUnknown, "Invalid GTU trailer");
1174     }
1175   }
1176   else
1177     EquipmentError(kUnknown, "trailer index marker mismatch");
1178
1179   return 0;
1180 }
1181
1182 Int_t AliTRDrawStream::ReadLinkData()
1183 {
1184   // read the data in one link (one HC) until the data endmarker is reached
1185   // returns the number of words read!
1186
1187   Int_t count = 0;
1188   UInt_t* startPosLink = fPayloadCurr;
1189
1190   AliDebug(1, DumpRaw(Form("link data from seg %2i slot %i link %2i", fCurrEquipmentId-kDDLOffset, fCurrSlot, fCurrLink),
1191                       fPayloadCurr, TMath::Min((Int_t) (fPayloadSize - (fPayloadCurr-fPayloadStart)), 100), 0x00000000));
1192
1193   if (fMarkers)
1194     new ((*fMarkers)[fMarkers->GetEntriesFast()])
1195       AliTRDrawStreamError(-kHCactive, fCurrEquipmentId-kDDLOffset, fCurrSlot, fCurrLink);
1196
1197   if (fErrorFlags & kDiscardHC)
1198     return count;
1199
1200   if (fCurrTrackletEnable) {
1201     count += ReadTracklets();
1202     if (fErrorFlags & kDiscardHC)
1203       return count;
1204   }
1205
1206   AliDebug(1, DumpRaw("HC header", fPayloadCurr, 4, 0x00000000));
1207   count += ReadHcHeader();
1208   if (fErrorFlags & kDiscardHC)
1209     return count;
1210
1211   Int_t det = fCurrSm * 30 + fCurrStack * 6 + fCurrLayer;
1212
1213   if (det > -1 && det < 540) {
1214
1215     // ----- check which kind of data -----
1216     if (fCurrMajor & 0x40) {
1217       if ((fCurrMajor & 0x7) == 0x7) {
1218         AliDebug(1, "This is a config event");
1219         UInt_t *startPos = fPayloadCurr;
1220         while (fPayloadCurr - fPayloadStart < fPayloadSize &&
1221                *fPayloadCurr != fgkDataEndmarker)
1222           fPayloadCurr++;
1223         count += fPayloadCurr - startPos;
1224
1225         // feeding TRAP config
1226         AliTRDtrapConfig *trapcfg = AliTRDcalibDB::Instance()->GetTrapConfig();
1227         AliTRDmcmSim::ReadPackedConfig(trapcfg, fCurrHC, startPos, fPayloadCurr - startPos);
1228       }
1229       else {
1230         Int_t tpmode = fCurrMajor & 0x7;
1231         AliDebug(1, Form("Checking testpattern (mode %i) data", tpmode));
1232         count += ReadTPData(tpmode);
1233       }
1234     }
1235     else {
1236       // reading real data
1237       if (fDigitsManager) {
1238         if ((fAdcArray = fDigitsManager->GetDigits(det))) {
1239           //fAdcArray->Expand();
1240           if (fAdcArray->GetNtime() != fCurrNtimebins)
1241             fAdcArray->Allocate(16, 144, fCurrNtimebins);
1242         }
1243         else {
1244           LinkError(kNoDigits);
1245         }
1246
1247         if (!fDigitsParam) {
1248           fDigitsParam = fDigitsManager->GetDigitsParam();
1249         }
1250         if (fDigitsParam) {
1251           fDigitsParam->SetPretriggerPhase(det, fCurrPtrgPhase);
1252           fDigitsParam->SetNTimeBins(det, fCurrNtimebins);
1253           fDigitsParam->SetADCbaseline(det, 10);
1254         }
1255
1256         if (fDigitsManager->UsesDictionaries()) {
1257           fDigitsManager->GetDictionary(det, 0)->Reset();
1258           fDigitsManager->GetDictionary(det, 1)->Reset();
1259           fDigitsManager->GetDictionary(det, 2)->Reset();
1260         }
1261
1262         if ((fSignalIndex = fDigitsManager->GetIndexes(det))) {
1263           fSignalIndex->SetSM(fCurrSm);
1264           fSignalIndex->SetStack(fCurrStack);
1265           fSignalIndex->SetLayer(fCurrLayer);
1266           fSignalIndex->SetDetNumber(det);
1267           if (!fSignalIndex->IsAllocated())
1268             fSignalIndex->Allocate(16, 144, fCurrNtimebins);
1269         }
1270
1271         if (fCurrMajor & 0x20) {
1272           AliDebug(1, "This is a zs event");
1273           count += ReadZSData();
1274         }
1275         else {
1276           AliDebug(1, "This is a nozs event");
1277           count += ReadNonZSData();
1278         }
1279       }
1280       else {
1281         // just read until data endmarkers
1282         while (fPayloadCurr - fPayloadStart < fPayloadSize &&
1283                *fPayloadCurr != fgkDataEndmarker)
1284           fPayloadCurr++;
1285       }
1286     }
1287   }
1288   else {
1289     LinkError(kInvalidDetector, "%i", det);
1290     while (fPayloadCurr - fPayloadStart < fPayloadSize &&
1291            *fPayloadCurr != fgkDataEndmarker)
1292       fPayloadCurr++;
1293   }
1294
1295   if (fCurrSm > -1 && fCurrSm < 18) {
1296     fStats.fStatsSector[fCurrSm].fStatsHC[fCurrHC%60].fBytes     += (fPayloadCurr - startPosLink) * sizeof(UInt_t);
1297     fStats.fStatsSector[fCurrSm].fStatsHC[fCurrHC%60].fBytesRead += count * sizeof(UInt_t);
1298     fStats.fStatsSector[fCurrSm].fBytesRead                      += count * sizeof(UInt_t);
1299     fStats.fBytesRead                                            += count * sizeof(UInt_t);
1300   }
1301
1302   return count;
1303 }
1304
1305 Int_t AliTRDrawStream::ReadTracklets()
1306 {
1307   // read the tracklets from one HC
1308
1309   fTrackletArray->Clear();
1310
1311   UInt_t *start = fPayloadCurr;
1312   while (*(fPayloadCurr) != fgkTrackletEndmarker &&
1313          *(fPayloadCurr) != fgkStackEndmarker[0] &&
1314          *(fPayloadCurr) != fgkStackEndmarker[1] &&
1315          fPayloadCurr - fPayloadStart < (fPayloadSize - 1)) {
1316     new ((*fTrackletArray)[fTrackletArray->GetEntriesFast()]) AliTRDtrackletWord(*(fPayloadCurr), fCurrHC);
1317
1318     fPayloadCurr++;
1319   }
1320
1321   if (fTrackletArray->GetEntriesFast() > 0) {
1322     AliDebug(1, Form("Found %i tracklets in %i %i %i (ev. %i)", fTrackletArray->GetEntriesFast(),
1323                      (fCurrEquipmentId-kDDLOffset), fCurrSlot, fCurrLink, fRawReader->GetEventIndex()));
1324     if (fCurrSm > -1 && fCurrSm < 18) {
1325       fStats.fStatsSector[fCurrSm].fStatsHC[fCurrHC%60].fNTracklets += fTrackletArray->GetEntriesFast();
1326       fStats.fStatsSector[fCurrSm].fNTracklets                      += fTrackletArray->GetEntriesFast();
1327     }
1328     if (fTrackletTree)
1329       fTrackletTree->Fill();
1330     if (fTracklets)
1331       for (Int_t iTracklet = 0; iTracklet < fTrackletArray->GetEntriesFast(); iTracklet++) {
1332         new ((*fTracklets)[fTracklets->GetEntriesFast()]) AliTRDtrackletWord(*((AliTRDtrackletWord*)(*fTrackletArray)[iTracklet]));
1333       }
1334   }
1335
1336   // loop over remaining tracklet endmarkers
1337   while ((*(fPayloadCurr) == fgkTrackletEndmarker &&
1338           fPayloadCurr - fPayloadStart < fPayloadSize))
1339     fPayloadCurr++;
1340
1341   return fPayloadCurr - start;
1342 }
1343
1344 Int_t AliTRDrawStream::ReadHcHeader()
1345 {
1346   // read and parse the HC header of one HC
1347   // and store the information in the corresponding variables
1348
1349   AliDebug(1, Form("HC header: 0x%08x", *fPayloadCurr));
1350   UInt_t *start = fPayloadCurr;
1351   // check not to be at the data endmarker
1352   if (*fPayloadCurr == fgkDataEndmarker ||
1353       *(fPayloadCurr) == fgkStackEndmarker[0] ||
1354       *(fPayloadCurr) == fgkStackEndmarker[1]) {
1355     LinkError(kHCmismatch, "found endmarker where HC header should be");
1356     return 0;
1357   }
1358
1359   fCurrSpecial    = (*fPayloadCurr >> 31) & 0x1;
1360   fCurrMajor      = (*fPayloadCurr >> 24) & 0x7f;
1361   fCurrMinor      = (*fPayloadCurr >> 17) & 0x7f;
1362   fCurrAddHcWords = (*fPayloadCurr >> 14) & 0x7;
1363   fCurrSm         = (*fPayloadCurr >> 9) & 0x1f;
1364   fCurrLayer      = (*fPayloadCurr >> 6) & 0x7;
1365   fCurrStack      = (*fPayloadCurr >> 3) & 0x7;
1366   fCurrSide       = (*fPayloadCurr >> 2) & 0x1;
1367   fCurrCheck      = (*fPayloadCurr) & 0x3;
1368
1369   if ((fCurrSm != (((Int_t) fCurrEquipmentId) - kDDLOffset)) ||
1370       (fCurrStack != fCurrSlot) ||
1371       (fCurrLayer != fCurrLink / 2) ||
1372       (fCurrSide != fCurrLink % 2)) {
1373     LinkError(kHCmismatch,
1374               "HC: %i, %i, %i, %i\n 0x%08x 0x%08x 0x%08x 0x%08x",
1375               fCurrSm, fCurrStack, fCurrLayer, fCurrSide,
1376               fPayloadCurr[0], fPayloadCurr[1], fPayloadCurr[2], fPayloadCurr[3]);
1377   }
1378   if (fCurrCheck != 0x1) {
1379     LinkError(kHCcheckFailed);
1380   }
1381
1382   if (fCurrAddHcWords > 0) {
1383     fCurrNtimebins = (fPayloadCurr[1] >> 26) & 0x3f;
1384     fCurrBC = (fPayloadCurr[1] >> 10) & 0xffff;
1385     fCurrPtrgCnt = (fPayloadCurr[1] >> 6) & 0xf;
1386     fCurrPtrgPhase = (fPayloadCurr[1] >> 2) & 0xf;
1387   }
1388
1389   fPayloadCurr += 1 + fCurrAddHcWords;
1390
1391   return (fPayloadCurr - start);
1392 }
1393
1394 Int_t AliTRDrawStream::ReadTPData(Int_t mode)
1395 {
1396   // testing of testpattern 1 to 3 (hardcoded), 0 missing
1397   // evcnt checking missing
1398   Int_t cpu = 0;
1399   Int_t cpufromchannel[] = {0, 0, 0, 0, 0,  1, 1, 1, 1, 1,  2, 2, 2, 2, 2,  3, 3, 3, 3, 3, 3};
1400   Int_t evno  = -1;
1401   Int_t evcnt = 0;
1402   Int_t count = 0;
1403   Int_t mcmcount = -1;
1404   Int_t wordcount = 0;
1405   Int_t channelcount = 0;
1406   UInt_t expword = 0;
1407   UInt_t expadcval = 0;
1408   UInt_t diff = 0;
1409   Int_t lastmcmpos = -1;
1410   Int_t lastrobpos = -1;
1411
1412   UInt_t* start = fPayloadCurr;
1413
1414   while (*(fPayloadCurr) != fgkDataEndmarker &&
1415          fPayloadCurr - fPayloadStart < fPayloadSize - 1) {
1416
1417     // ----- Checking MCM Header -----
1418     AliDebug(2, DumpMcmHeader("MCM header: ", *fPayloadCurr));
1419     UInt_t *startPosMCM = fPayloadCurr;
1420     mcmcount++;
1421
1422     // ----- checking for proper readout order - ROB -----
1423     fCurrRobPos = ROB(*fPayloadCurr);
1424     if (GetROBReadoutPos(ROB(*fPayloadCurr) / 2) >= lastrobpos) {
1425       if (GetROBReadoutPos(ROB(*fPayloadCurr) / 2) > lastrobpos)
1426         lastmcmpos = -1;
1427       lastrobpos = GetROBReadoutPos(ROB(*fPayloadCurr) / 2);
1428     }
1429     else {
1430       ROBError(kPosUnexp, Form("#%i after #%i in readout order", GetROBReadoutPos(ROB(*fPayloadCurr) / 2), lastrobpos));
1431     }
1432
1433     // ----- checking for proper readout order - MCM -----
1434     fCurrMcmPos = MCM(*fPayloadCurr);
1435     if (GetMCMReadoutPos(MCM(*fPayloadCurr)) > lastmcmpos) {
1436       lastmcmpos = GetMCMReadoutPos(MCM(*fPayloadCurr));
1437     }
1438     else {
1439       MCMError(kPosUnexp, Form("#%i after #%i in readout order", GetMCMReadoutPos(MCM(*fPayloadCurr)), lastmcmpos));
1440     }
1441
1442     if (EvNo(*fPayloadCurr) != (evno & 0xfffff)) {
1443       if (evno == -1) {
1444         evno = EvNo(*fPayloadCurr);
1445       }
1446       else {
1447         MCMError(kEvCntMismatch, "%i <-> %i", evno, EvNo(*fPayloadCurr));
1448       }
1449     }
1450
1451     fPayloadCurr++;
1452
1453     evcnt = 0x3f & *fPayloadCurr >> 26;
1454     cpu = -1;
1455     channelcount = 0;
1456     while (channelcount < 21) {
1457       count = 0;
1458       if (cpu != cpufromchannel[channelcount]) {
1459         cpu = cpufromchannel[channelcount];
1460         expadcval = (1 << 9) | (fCurrRobPos << 6) | (fCurrMcmPos << 2) | cpu;
1461         wordcount = 0;
1462       }
1463
1464       while (count < 10) {
1465         if (*fPayloadCurr == fgkDataEndmarker) {
1466           MCMError(kMissTpData);
1467           return (fPayloadCurr - start);
1468         }
1469
1470         if (channelcount % 2 == 0)
1471           expword = 0x3;
1472         else
1473           expword = 0x2;
1474
1475         if (mode == 1) {
1476           // ----- TP 1 -----
1477           expword |= expadcval << 2;
1478           expadcval = ( (expadcval << 1) | ( ( (expadcval >> 9) ^ (expadcval >> 6) ) & 1) ) & 0x3FF;
1479           expword |= expadcval << 12;
1480           expadcval = ( (expadcval << 1) | ( ( (expadcval >> 9) ^ (expadcval >> 6) ) & 1) ) & 0x3FF;
1481           expword |= expadcval << 22;
1482           expadcval = ( (expadcval << 1) | ( ( (expadcval >> 9) ^ (expadcval >> 6) ) & 1) ) & 0x3FF;
1483         }
1484         else if (mode == 2) {
1485           // ----- TP 2 ------
1486           expword = ((0x3f & evcnt) << 26) | ((fCurrSm + 1) << 21) | ((fCurrLayer + 1) << 18) |
1487             ((fCurrStack + 1) << 15) |
1488             (fCurrRobPos << 12) | (fCurrMcmPos << 8) | (cpu << 6) | (wordcount + 1);
1489         }
1490         else if (mode == 3) {
1491           // ----- TP 3 -----
1492           expword = ((0xfff & evcnt) << 20) | (fCurrSm << 15) | (fCurrLink/2 << 12) | (fCurrStack << 9) |
1493             (fCurrRobPos << 6) | (fCurrMcmPos << 2) | (cpu << 0);
1494         }
1495         else {
1496           expword = 0;
1497           LinkError(kTPmodeInvalid, "Just reading");
1498         }
1499
1500         diff = *fPayloadCurr ^ expword;
1501         AliDebug(11, Form("Comparing ch %2i, word %2i (cpu %i): 0x%08x <-> 0x%08x",
1502                           channelcount, wordcount, cpu, *fPayloadCurr, expword));
1503
1504         if (diff != 0) {
1505           MCMError(kTPmismatch,
1506                    "Seen 0x%08x, expected 0x%08x, diff: 0x%08x, 0x%04x, 0x%02x - word %2i (cpu %i, ch %i)",
1507                    *fPayloadCurr, expword, diff,
1508                    0xffff & (diff | diff >> 16),
1509                    0xff & (diff | diff >> 8 | diff >> 16 | diff >> 24),
1510                    wordcount, cpu, channelcount);;
1511         }
1512         fPayloadCurr++;
1513         count++;
1514         wordcount++;
1515         if (*fPayloadCurr == fgkDataEndmarker)
1516           return (fPayloadCurr - start);
1517       }
1518       channelcount++;
1519     }
1520     // continue with next MCM
1521
1522     if (IsDumping() && DumpingMCM(fCurrHC/2, fCurrRobPos, fCurrMcmPos)) {
1523       AliInfo(DumpRaw(Form("Event %i: Det %3i ROB %i MCM %2i", fRawReader->GetEventIndex(), fCurrHC/2, fCurrRobPos, fCurrMcmPos),
1524                       startPosMCM, fPayloadCurr - startPosMCM));
1525     }
1526
1527   }
1528   return fPayloadCurr - start;
1529 }
1530
1531
1532 Int_t AliTRDrawStream::ReadZSData()
1533 {
1534   // read the zs data from one link from the current reading position
1535
1536   UInt_t *start = fPayloadCurr;
1537
1538   Int_t mcmcount = 0;
1539   Int_t mcmcountExp = fCurrStack == 2 ? 48 : 64;
1540   Int_t channelcount = 0;
1541   Int_t channelcountExp = 0;
1542   Int_t channelcountMax = 0;
1543   Int_t timebins;
1544   Int_t currentTimebin = 0;
1545   Int_t adcwc = 0;
1546   Int_t evno = -1;
1547   Int_t lastmcmpos = -1;
1548   Int_t lastrobpos = -1;
1549
1550   if (fCurrNtimebins != fNtimebins) {
1551     if (fNtimebins > 0)
1552       LinkError(kNtimebinsChanged,
1553                 "No. of timebins changed from %i to %i", fNtimebins, fCurrNtimebins);
1554     fNtimebins = fCurrNtimebins;
1555   }
1556
1557   timebins = fNtimebins;
1558
1559   while (*(fPayloadCurr) != fgkDataEndmarker &&
1560          *(fPayloadCurr) != fgkStackEndmarker[0] &&
1561          *(fPayloadCurr) != fgkStackEndmarker[1] &&
1562          fPayloadCurr - fPayloadStart < fPayloadSize) {
1563
1564     // ----- Checking MCM Header -----
1565     AliDebug(2, DumpMcmHeader("MCM header: ", *fPayloadCurr));
1566     UInt_t *startPosMCM = fPayloadCurr;
1567
1568     // ----- checking for proper readout order - ROB -----
1569     fCurrRobPos = ROB(*fPayloadCurr);
1570     if (GetROBReadoutPos(ROB(*fPayloadCurr) / 2) >= lastrobpos) {
1571       if (GetROBReadoutPos(ROB(*fPayloadCurr) / 2) > lastrobpos)
1572         lastmcmpos = -1;
1573       lastrobpos = GetROBReadoutPos(ROB(*fPayloadCurr) / 2);
1574     }
1575     else {
1576       ROBError(kPosUnexp, Form("#%i after #%i and #%i in readout order",
1577                                GetROBReadoutPos(ROB(*fPayloadCurr) / 2), lastrobpos, GetROBReadoutPos(fCurrRobPos)));
1578     }
1579
1580     // ----- checking for proper readout order - MCM -----
1581     fCurrMcmPos = MCM(*fPayloadCurr);
1582     if (GetMCMReadoutPos(MCM(*fPayloadCurr)) > lastmcmpos) {
1583       lastmcmpos = GetMCMReadoutPos(MCM(*fPayloadCurr));
1584     }
1585     else {
1586       MCMError(kPosUnexp, Form("#%i after #%i and #%i in readout order",
1587                                GetMCMReadoutPos(MCM(*fPayloadCurr)), lastmcmpos, GetMCMReadoutPos(fCurrMcmPos)));
1588     }
1589
1590     if (EvNo(*fPayloadCurr) != (evno & 0xfffff)) {
1591       if (evno == -1) {
1592         evno = EvNo(*fPayloadCurr);
1593       }
1594       else {
1595         MCMError(kEvCntMismatch, "%i <-> %i", evno, EvNo(*fPayloadCurr));
1596       }
1597     }
1598     Int_t adccoloff = AdcColOffset(*fPayloadCurr);
1599     Int_t padcoloff = PadColOffset(*fPayloadCurr);
1600     Int_t row = Row(*fPayloadCurr);
1601     fPayloadCurr++;
1602
1603     if ((row > 11) && (fCurrStack == 2)) {
1604       MCMError(kUnknown, "Data in padrow > 11 for stack 2");
1605     }
1606
1607     if (fErrorFlags & (kDiscardMCM | kDiscardHC | kDiscardDDL))
1608       break; //???
1609
1610     // ----- Reading ADC channels -----
1611     AliDebug(2, DumpAdcMask("ADC mask: ", *fPayloadCurr));
1612
1613     // ----- analysing the ADC mask -----
1614     channelcount = 0;
1615     channelcountExp = GetNActiveChannelsFromMask(*fPayloadCurr);
1616     channelcountMax = GetNActiveChannels(*fPayloadCurr);
1617     Int_t channelmask = GetActiveChannels(*fPayloadCurr);
1618     Int_t channelno = -1;
1619     fPayloadCurr++;
1620
1621     if (channelcountExp != channelcountMax) {
1622       if (channelcountExp > channelcountMax) {
1623         Int_t temp = channelcountExp;
1624         channelcountExp = channelcountMax;
1625         channelcountMax = temp;
1626       }
1627       while (channelcountExp < channelcountMax && channelcountExp < 21 &&
1628              fPayloadCurr - fPayloadStart < fPayloadSize - 10 * channelcountExp - 1) {
1629         MCMError(kAdcMaskInconsistent,
1630                  "Possible MCM-H: 0x%08x, possible ADC-mask: 0x%08x",
1631                  *(fPayloadCurr + 10 * channelcountExp),
1632                  *(fPayloadCurr + 10 * channelcountExp + 1) );
1633         if (!CouldBeMCMhdr( *(fPayloadCurr + 10 * channelcountExp)) && !CouldBeADCmask( *(fPayloadCurr + 10 * channelcountExp + 1)))
1634           channelcountExp++;
1635         else {
1636           break;
1637         }
1638       }
1639       MCMError(kAdcMaskInconsistent,
1640                "Inconsistency in no. of active channels: Counter: %i, Mask: %i, chosen: %i!",
1641                GetNActiveChannels(fPayloadCurr[-1]), GetNActiveChannelsFromMask(fPayloadCurr[-1]), channelcountExp);
1642     }
1643     AliDebug(2, Form("expecting %i active channels, %i timebins", channelcountExp, fCurrNtimebins));
1644
1645     // ----- reading marked ADC channels -----
1646     while (channelcount < channelcountExp && *(fPayloadCurr) != fgkDataEndmarker) {
1647       if (channelno < 20)
1648         channelno++;
1649       while (channelno < 20 && (channelmask & 1 << channelno) == 0)
1650         channelno++;
1651
1652       if (fCurrNtimebins > 30) {
1653         currentTimebin = ((*fPayloadCurr >> 2) & 0x3f);
1654         timebins = ((*fPayloadCurr >> 8) & 0xf) * 3;
1655       }
1656       else {
1657         currentTimebin = 0;
1658       }
1659
1660       adcwc = 0;
1661       Int_t nADCwords = (timebins + 2) / 3;
1662       AliDebug(3, Form("Now reading %i words for channel %2i", nADCwords, channelno));
1663       Int_t adccol = adccoloff - channelno;
1664       Int_t padcol = padcoloff - channelno;
1665 //      if (adccol < 3 || adccol > 165)
1666 //      AliInfo(Form("writing channel %i of det %3i %i:%2i to adcrow/-col: %i/%i padcol: %i",
1667 //                   channelno, fCurrHC/2, fCurrRobPos, fCurrMcmPos, row, adccol, padcol));
1668
1669       while ((adcwc < nADCwords) &&
1670              (*(fPayloadCurr) != fgkDataEndmarker) &&
1671              (fPayloadCurr - fPayloadStart < fPayloadSize)) {
1672         int check = 0x3 & *fPayloadCurr;
1673         if (channelno % 2 != 0) { // odd channel
1674           if (check != 0x2 && channelno < 21) {
1675             MCMError(kAdcCheckInvalid,
1676                      "%i for %2i. ADC word in odd channel %i",
1677                      check, adcwc+1, channelno);
1678           }
1679         }
1680         else {                  // even channel
1681           if (check != 0x3 && channelno < 21) {
1682             MCMError(kAdcCheckInvalid,
1683                      "%i for %2i. ADC word in even channel %i",
1684                      check, adcwc+1, channelno);
1685           }
1686         }
1687
1688         // filling the actual timebin data
1689         int tb2 = 0x3ff & *fPayloadCurr >> 22;
1690         int tb1 = 0x3ff & *fPayloadCurr >> 12;
1691         int tb0 = 0x3ff & *fPayloadCurr >> 2;
1692         if (adcwc != 0 || fCurrNtimebins <= 30)
1693           fAdcArray->SetDataByAdcCol(row, adccol, currentTimebin++, tb0);
1694         else
1695           tb0 = -1;
1696         fAdcArray->SetDataByAdcCol(row, adccol, currentTimebin++, tb1);
1697         fAdcArray->SetDataByAdcCol(row, adccol, currentTimebin++, tb2);
1698
1699         adcwc++;
1700         fPayloadCurr++;
1701       }
1702
1703       if (adcwc != nADCwords)
1704         MCMError(kAdcDataAbort);
1705
1706       // adding index
1707       if (padcol > 0 && padcol < 144) {
1708         fSignalIndex->AddIndexRC(row, padcol);
1709       }
1710
1711       channelcount++;
1712     }
1713
1714     if (fCurrSm > -1 && fCurrSm < 18) {
1715       fStats.fStatsSector[fCurrSm].fStatsHC[fCurrHC%60].fNChannels += channelcount;
1716       fStats.fStatsSector[fCurrSm].fNChannels                      += channelcount;
1717     }
1718     if (channelcount != channelcountExp)
1719       MCMError(kAdcChannelsMiss);
1720
1721     mcmcount++;
1722     if (fCurrSm > -1 && fCurrSm < 18) {
1723       fStats.fStatsSector[fCurrSm].fStatsHC[fCurrHC%60].fNMCMs++;
1724       fStats.fStatsSector[fCurrSm].fNMCMs++;
1725     }
1726
1727     if (IsDumping() && DumpingMCM(fCurrHC/2, fCurrRobPos, fCurrMcmPos)) {
1728       AliInfo(DumpRaw(Form("Event %i: Det %3i ROB %i MCM %2i", fRawReader->GetEventIndex(), fCurrHC/2, fCurrRobPos, fCurrMcmPos),
1729                       startPosMCM, fPayloadCurr - startPosMCM));
1730     }
1731
1732     // continue with next MCM
1733   }
1734
1735   // check for missing MCMs (if header suppression is inactive)
1736   if (((fCurrMajor & 0x1) == 0) && (mcmcount != mcmcountExp)) {
1737     LinkError(kMissMcmHeaders,
1738               "No. of MCM headers %i not as expected: %i",
1739               mcmcount, mcmcountExp);
1740   }
1741
1742   return (fPayloadCurr - start);
1743 }
1744
1745 Int_t AliTRDrawStream::ReadNonZSData()
1746 {
1747   // read the non-zs data from one link from the current reading position
1748
1749   UInt_t *start = fPayloadCurr;
1750
1751   Int_t mcmcount = 0;
1752   Int_t mcmcountExp = fCurrStack == 2 ? 48 : 64;
1753   Int_t channelcount = 0;
1754   Int_t channelcountExp = 0;
1755   Int_t timebins;
1756   Int_t currentTimebin = 0;
1757   Int_t adcwc = 0;
1758   Int_t evno = -1;
1759   Int_t lastmcmpos = -1;
1760   Int_t lastrobpos = -1;
1761
1762   if (fCurrNtimebins != fNtimebins) {
1763     if (fNtimebins > 0)
1764       LinkError(kNtimebinsChanged,
1765                 "No. of timebins changed from %i to %i", fNtimebins, fCurrNtimebins);
1766     fNtimebins = fCurrNtimebins;
1767   }
1768
1769   timebins = fNtimebins;
1770
1771   while (*(fPayloadCurr) != fgkDataEndmarker &&
1772          fPayloadCurr - fPayloadStart < fPayloadSize - 2) {
1773
1774     // ----- Checking MCM Header -----
1775     AliDebug(2, Form("MCM header: 0x%08x", *fPayloadCurr));
1776
1777     // ----- checking for proper readout order - ROB -----
1778     fCurrRobPos = ROB(*fPayloadCurr);
1779     if (GetROBReadoutPos(ROB(*fPayloadCurr) / 2) >= lastrobpos) {
1780       if (GetROBReadoutPos(ROB(*fPayloadCurr) / 2) > lastrobpos)
1781         lastmcmpos = -1;
1782       lastrobpos = GetROBReadoutPos(ROB(*fPayloadCurr) / 2);
1783     }
1784     else {
1785       ROBError(kPosUnexp, Form("#%i after #%i in readout order", GetROBReadoutPos(ROB(*fPayloadCurr) / 2), lastrobpos));
1786     }
1787
1788     // ----- checking for proper readout order - MCM -----
1789     fCurrMcmPos = MCM(*fPayloadCurr);
1790     if (GetMCMReadoutPos(MCM(*fPayloadCurr)) > lastmcmpos) {
1791       lastmcmpos = GetMCMReadoutPos(MCM(*fPayloadCurr));
1792     }
1793     else {
1794       MCMError(kPosUnexp, Form("#%i after #%i in readout order", GetMCMReadoutPos(MCM(*fPayloadCurr)), lastmcmpos));
1795     }
1796
1797     if (EvNo(*fPayloadCurr) != (evno & 0xfffff)) {
1798       if (evno == -1) {
1799         evno = EvNo(*fPayloadCurr);
1800       }
1801       else {
1802         MCMError(kEvCntMismatch, "%i <-> %i", evno, EvNo(*fPayloadCurr));
1803       }
1804     }
1805
1806     channelcount = 0;
1807     channelcountExp = 21;
1808     int channelno = -1;
1809
1810     Int_t adccoloff = AdcColOffset(*fPayloadCurr);
1811     Int_t padcoloff = PadColOffset(*fPayloadCurr);
1812     Int_t row = Row(*fPayloadCurr);
1813
1814     fPayloadCurr++;
1815
1816     // ----- reading marked ADC channels -----
1817     while (channelcount < channelcountExp &&
1818            *(fPayloadCurr) != fgkDataEndmarker) {
1819       if (channelno < 20)
1820         channelno++;
1821
1822       currentTimebin = 0;
1823
1824       adcwc = 0;
1825       Int_t nADCwords = (timebins + 2) / 3;
1826       AliDebug(2, Form("Now looking %i words", nADCwords));
1827       Int_t adccol = adccoloff - channelno;
1828       Int_t padcol = padcoloff - channelno;
1829       while ((adcwc < nADCwords) &&
1830              (*(fPayloadCurr) != fgkDataEndmarker) &&
1831              (fPayloadCurr - fPayloadStart < fPayloadSize)) {
1832         int check = 0x3 & *fPayloadCurr;
1833         if (channelno % 2 != 0) { // odd channel
1834           if (check != 0x2 && channelno < 21) {
1835             MCMError(kAdcCheckInvalid,
1836                      "%i for %2i. ADC word in odd channel %i",
1837                      check, adcwc+1, channelno);
1838           }
1839         }
1840         else {                  // even channel
1841           if (check != 0x3 && channelno < 21) {
1842             MCMError(kAdcCheckInvalid,
1843                      "%i for %2i. ADC word in even channel %i",
1844                      check, adcwc+1, channelno);
1845           }
1846         }
1847
1848         // filling the actual timebin data
1849         int tb2 = 0x3ff & *fPayloadCurr >> 22;
1850         int tb1 = 0x3ff & *fPayloadCurr >> 12;
1851         int tb0 = 0x3ff & *fPayloadCurr >> 2;
1852         if (adcwc != 0 || fCurrNtimebins <= 30)
1853           fAdcArray->SetDataByAdcCol(row, adccol, currentTimebin++, tb0);
1854         else
1855           tb0 = -1;
1856         fAdcArray->SetDataByAdcCol(row, adccol, currentTimebin++, tb1);
1857         fAdcArray->SetDataByAdcCol(row, adccol, currentTimebin++, tb2);
1858
1859         adcwc++;
1860         fPayloadCurr++;
1861       }
1862
1863       if (adcwc != nADCwords)
1864         MCMError(kAdcDataAbort);
1865
1866       // adding index
1867       if (padcol > 0 && padcol < 144) {
1868         fSignalIndex->AddIndexRC(row, padcol);
1869       }
1870
1871       channelcount++;
1872     }
1873
1874     if (channelcount != channelcountExp)
1875       MCMError(kAdcChannelsMiss);
1876     mcmcount++;
1877     // continue with next MCM
1878   }
1879
1880   // check for missing MCMs (if header suppression is inactive)
1881   if (mcmcount != mcmcountExp) {
1882     LinkError(kMissMcmHeaders,
1883               "%i not as expected: %i", mcmcount, mcmcountExp);
1884   }
1885
1886   return (fPayloadCurr - start);
1887 }
1888
1889 Int_t AliTRDrawStream::SeekNextStack()
1890 {
1891   // proceed in raw data stream till the next stack
1892
1893   if (!fCurrStackEndmarkerAvail)
1894     return 0;
1895
1896   UInt_t *start = fPayloadCurr;
1897
1898   // read until data endmarkers
1899   while ((fPayloadCurr - fPayloadStart < fPayloadSize-1) &&
1900          ((fPayloadCurr[0] != fgkStackEndmarker[0]) ||
1901           (fPayloadCurr[1] != fgkStackEndmarker[1])))
1902     fPayloadCurr++;
1903
1904   if ((fPayloadCurr - start) != 0)
1905     StackError(kUnknown, "skipped %i words to reach stack endmarker", fPayloadCurr - start);
1906
1907   AliDebug(2, Form("stack endmarker: 0x%08x 0x%08x", fPayloadCurr[0], fPayloadCurr[1]));
1908
1909   // goto next stack
1910   fPayloadCurr++;
1911   fPayloadCurr++;
1912
1913   return (fPayloadCurr-start);
1914 }
1915
1916 Int_t AliTRDrawStream::SeekNextLink()
1917 {
1918   // proceed in raw data stream till the next link
1919
1920   UInt_t *start = fPayloadCurr;
1921
1922   // read until data endmarkers
1923   while (fPayloadCurr - fPayloadStart < fPayloadSize &&
1924          ((fPayloadCurr[0] != fgkStackEndmarker[0]) ||
1925           (fPayloadCurr[1] != fgkStackEndmarker[1])) &&
1926          *fPayloadCurr != fgkDataEndmarker)
1927     fPayloadCurr++;
1928
1929   // read all data endmarkers
1930   while (fPayloadCurr - fPayloadStart < fPayloadSize &&
1931          *fPayloadCurr == fgkDataEndmarker)
1932     fPayloadCurr++;
1933
1934   return (fPayloadCurr - start);
1935 }
1936
1937 Bool_t AliTRDrawStream::ConnectTracklets(TTree *trklTree)
1938 {
1939   // connect the tracklet tree used to store the tracklet output
1940
1941   fTrackletTree = trklTree;
1942   if (!fTrackletTree)
1943     return kTRUE;
1944
1945   if (!fTrackletTree->GetBranch("hc"))
1946     fTrackletTree->Branch("hc", &fCurrHC, "hc/I");
1947   else
1948     fTrackletTree->SetBranchAddress("hc", &fCurrHC);
1949
1950   if (!fTrackletTree->GetBranch("trkl"))
1951     fTrackletTree->Branch("trkl", &fTrackletArray);
1952   else
1953     fTrackletTree->SetBranchAddress("trkl", &fTrackletArray);
1954
1955   return kTRUE;
1956 }
1957
1958
1959 void AliTRDrawStream::EquipmentError(ErrorCode_t err, const char *const msg, ...)
1960 {
1961   // register error according to error code on equipment level
1962   // and return the corresponding error message
1963
1964   fLastError.fSector = fCurrEquipmentId - kDDLOffset;
1965   fLastError.fStack  = -1;
1966   fLastError.fLink   = -1;
1967   fLastError.fRob    = -1;
1968   fLastError.fMcm    = -1;
1969   fLastError.fError  = err;
1970   (this->*fStoreError)();
1971
1972   va_list ap;
1973   if (fgErrorDebugLevel[err] > 10)
1974     AliDebug(fgErrorDebugLevel[err],
1975              Form("Event %6i: Eq. %2d - %s : %s",
1976                   fRawReader->GetEventIndex(), fCurrEquipmentId, fgkErrorMessages[err],
1977                   (va_start(ap, msg), vsprintf(fErrorBuffer, msg, ap), va_end(ap), fErrorBuffer) ));
1978   else
1979     AliError(Form("Event %6i: Eq. %2d - %s : %s",
1980                   fRawReader->GetEventIndex(), fCurrEquipmentId, fgkErrorMessages[err],
1981                   (va_start(ap, msg), vsprintf(fErrorBuffer, msg, ap), va_end(ap), fErrorBuffer) ));
1982   fErrorFlags |= fgErrorBehav[err];
1983 }
1984
1985
1986 void AliTRDrawStream::StackError(ErrorCode_t err, const char *const msg, ...)
1987 {
1988   // register error according to error code on stack level
1989   // and return the corresponding error message
1990
1991   fLastError.fSector = fCurrEquipmentId - kDDLOffset;
1992   fLastError.fStack  = fCurrSlot;
1993   fLastError.fLink   = -1;
1994   fLastError.fRob    = -1;
1995   fLastError.fMcm    = -1;
1996   fLastError.fError  = err;
1997   (this->*fStoreError)();
1998
1999   va_list ap;
2000   if (fgErrorDebugLevel[err] > 0)
2001     AliDebug(fgErrorDebugLevel[err],
2002              Form("Event %6i: Eq. %2d S %i - %s : %s",
2003                   fRawReader->GetEventIndex(), fCurrEquipmentId, fCurrSlot, fgkErrorMessages[err],
2004                   (va_start(ap, msg), vsprintf(fErrorBuffer, msg, ap), va_end(ap), fErrorBuffer) ));
2005   else
2006     AliError(Form("Event %6i: Eq. %2d S %i - %s : %s",
2007                   fRawReader->GetEventIndex(), fCurrEquipmentId, fCurrSlot, fgkErrorMessages[err],
2008                   (va_start(ap, msg), vsprintf(fErrorBuffer, msg, ap), va_end(ap), fErrorBuffer) ));
2009   fErrorFlags |= fgErrorBehav[err];
2010 }
2011
2012
2013 void AliTRDrawStream::LinkError(ErrorCode_t err, const char *const msg, ...)
2014 {
2015   // register error according to error code on link level
2016   // and return the corresponding error message
2017
2018   fLastError.fSector = fCurrEquipmentId - kDDLOffset;
2019   fLastError.fStack  = fCurrSlot;
2020   fLastError.fLink   = fCurrLink;
2021   fLastError.fRob    = -1;
2022   fLastError.fMcm    = -1;
2023   fLastError.fError  = err;
2024   (this->*fStoreError)();
2025
2026   va_list ap;
2027   if (fgErrorDebugLevel[err] > 0)
2028     AliDebug(fgErrorDebugLevel[err],
2029              Form("Event %6i: Eq. %2d S %i l %2i - %s : %s",
2030                   fRawReader->GetEventIndex(), fCurrEquipmentId, fCurrSlot, fCurrLink, fgkErrorMessages[err],
2031                   (va_start(ap, msg), vsprintf(fErrorBuffer, msg, ap), va_end(ap), fErrorBuffer) ));
2032   else
2033     AliError(Form("Event %6i: Eq. %2d S %i l %2i - %s : %s",
2034                   fRawReader->GetEventIndex(), fCurrEquipmentId, fCurrSlot, fCurrLink, fgkErrorMessages[err],
2035                   (va_start(ap, msg), vsprintf(fErrorBuffer, msg, ap), va_end(ap), fErrorBuffer) ));
2036   fErrorFlags |= fgErrorBehav[err];
2037 }
2038
2039
2040 void AliTRDrawStream::ROBError(ErrorCode_t err, const char *const msg, ...)
2041 {
2042   // register error according to error code on ROB level
2043   // and return the corresponding error message
2044
2045   fLastError.fSector = fCurrEquipmentId - kDDLOffset;
2046   fLastError.fStack  = fCurrSlot;
2047   fLastError.fLink   = fCurrLink;
2048   fLastError.fRob    = fCurrRobPos;
2049   fLastError.fMcm    = -1;
2050   fLastError.fError  = err;
2051   (this->*fStoreError)();
2052
2053   va_list ap;
2054   if (fgErrorDebugLevel[err] > 0)
2055     AliDebug(fgErrorDebugLevel[err],
2056              Form("Event %6i: Eq. %2d S %i l %2i ROB %i - %s : %s",
2057                   fRawReader->GetEventIndex(), fCurrEquipmentId, fCurrSlot, fCurrLink, fCurrRobPos, fgkErrorMessages[err],
2058                   (va_start(ap, msg), vsprintf(fErrorBuffer, msg, ap), va_end(ap), fErrorBuffer) ));
2059   else
2060     AliError(Form("Event %6i: Eq. %2d S %i l %2i ROB %i - %s : %s",
2061                   fRawReader->GetEventIndex(), fCurrEquipmentId, fCurrSlot, fCurrLink, fCurrRobPos, fgkErrorMessages[err],
2062                   (va_start(ap, msg), vsprintf(fErrorBuffer, msg, ap), va_end(ap), fErrorBuffer) ));
2063   fErrorFlags |= fgErrorBehav[err];
2064 }
2065
2066
2067 void AliTRDrawStream::MCMError(ErrorCode_t err, const char *const msg, ...)
2068 {
2069   // register error according to error code on MCM level
2070   // and return the corresponding error message
2071
2072   fLastError.fSector = fCurrEquipmentId - kDDLOffset;
2073   fLastError.fStack  = fCurrSlot;
2074   fLastError.fLink   = fCurrLink;
2075   fLastError.fRob    = fCurrRobPos;
2076   fLastError.fMcm    = fCurrMcmPos;
2077   fLastError.fError  = err;
2078   (this->*fStoreError)();
2079
2080   va_list ap;
2081   if (fgErrorDebugLevel[err] > 0)
2082     AliDebug(fgErrorDebugLevel[err],
2083              Form("Event %6i: Eq. %2d S %i l %2i ROB %i MCM %2i - %s : %s",
2084                   fRawReader->GetEventIndex(), fCurrEquipmentId, fCurrSlot, fCurrLink, fCurrRobPos, fCurrMcmPos, fgkErrorMessages[err],
2085                   (va_start(ap, msg), vsprintf(fErrorBuffer, msg, ap), va_end(ap), fErrorBuffer) ));
2086   else
2087     AliError(Form("Event %6i: Eq. %2d S %i l %2i ROB %i MCM %2i - %s : %s",
2088                   fRawReader->GetEventIndex(), fCurrEquipmentId, fCurrSlot, fCurrLink, fCurrRobPos, fCurrMcmPos, fgkErrorMessages[err],
2089                   (va_start(ap, msg), vsprintf(fErrorBuffer, msg, ap), va_end(ap), fErrorBuffer) ));
2090   fErrorFlags |= fgErrorBehav[err];
2091 }
2092
2093 const char* AliTRDrawStream::GetErrorMessage(ErrorCode_t errCode)
2094 {
2095   // return the error message for the given error code
2096
2097   if (errCode > 0 && errCode < kLastErrorCode)
2098     return fgkErrorMessages[errCode];
2099   else
2100     return "";
2101 }
2102
2103 void AliTRDrawStream::AliTRDrawStats::ClearStats()
2104 {
2105   // clear statistics (includes clearing sector-wise statistics)
2106
2107   fBytesRead = 0;
2108   for (Int_t iSector = 0; iSector < 18; iSector++) {
2109     fStatsSector[iSector].ClearStats();
2110   }
2111
2112 }
2113
2114 void AliTRDrawStream::AliTRDrawStats::AliTRDrawStatsSector::ClearStats()
2115 {
2116   // clear statistics (includes clearing HC-wise statistics)
2117
2118   fBytes = 0;
2119   fBytesRead = 0;
2120   fNTracklets = 0;
2121   fNMCMs = 0;
2122   fNChannels = 0;
2123
2124   for (Int_t iHC = 0; iHC < 60; iHC++) {
2125     fStatsHC[iHC].ClearStats();
2126   }
2127 }
2128
2129 void AliTRDrawStream::AliTRDrawStats::AliTRDrawStatsSector::AliTRDrawStatsHC::ClearStats()
2130 {
2131   // clear statistics
2132
2133   fBytes = 0;
2134   fBytesRead = 0;
2135   fNTracklets = 0;
2136   fNMCMs = 0;
2137   fNChannels = 0;
2138 }
2139
2140 void AliTRDrawStream::SetDumpMCM(Int_t det, Int_t rob, Int_t mcm, Bool_t dump)
2141 {
2142   // mark MCM for dumping of raw data
2143
2144   if (dump) {
2145     fDumpMCM[fNDumpMCMs++] = (det << 7) | (rob << 4) | mcm;
2146   }
2147   else {
2148     Int_t iMCM;
2149     for (iMCM = 0; iMCM < fNDumpMCMs; iMCM++) {
2150       if (fDumpMCM[iMCM] == ((det << 7) | (rob << 4) | mcm)) {
2151         fNDumpMCMs--;
2152         break;
2153       }
2154     }
2155     for ( ; iMCM < fNDumpMCMs; iMCM++) {
2156       fDumpMCM[iMCM] = fDumpMCM[iMCM+1];
2157     }
2158   }
2159 }
2160
2161 Bool_t AliTRDrawStream::DumpingMCM(Int_t det, Int_t rob, Int_t mcm)  const
2162 {
2163   // check if MCM data should be dumped
2164
2165   for (Int_t iMCM = 0; iMCM < fNDumpMCMs; iMCM++) {
2166     if (fDumpMCM[iMCM] == ((det << 7) | (rob << 4) | mcm)) {
2167       return kTRUE;
2168     }
2169   }
2170   return kFALSE;
2171 }
2172
2173 TString AliTRDrawStream::DumpRaw(TString title, const UInt_t *start, Int_t length, UInt_t endmarker)
2174 {
2175   // dump raw data
2176
2177   title += "\n";
2178   for (Int_t pos = 0; pos < length; pos += 4) {
2179     if ((start[pos+0] != endmarker) && pos+0 < length)
2180       if ((start[pos+1] != endmarker && pos+1 < length))
2181         if ((start[pos+2] != endmarker && pos+2 < length))
2182           if ((start[pos+3] != endmarker && pos+3 < length))
2183             title += Form("   0x%08x 0x%08x 0x%08x 0x%08x\n",
2184                           start[pos+0], start[pos+1], start[pos+2], start[pos+3]);
2185           else {
2186             title += Form("   0x%08x 0x%08x 0x%08x 0x%08x\n",
2187                           start[pos+0], start[pos+1], start[pos+2], start[pos+3]);
2188             return title;
2189           }
2190         else {
2191           title += Form("   0x%08x 0x%08x 0x%08x\n",
2192                         start[pos+0], start[pos+1], start[pos+2]);
2193           return title;
2194         }
2195       else {
2196         title += Form("   0x%08x 0x%08x\n",
2197                       start[pos+0], start[pos+1]);
2198         return title;
2199       }
2200     else {
2201       title += Form("   0x%08x\n",
2202                     start[pos+0]);
2203       return title;
2204     }
2205   }
2206   return title;
2207 }
2208
2209 TString AliTRDrawStream::DumpMcmHeader(TString title, UInt_t word)
2210 {
2211   title += Form("0x%08x -> ROB: %i, MCM: %2i",
2212                 word, ROB(word), MCM(word));
2213   return title;
2214 }
2215
2216 TString AliTRDrawStream::DumpAdcMask(TString title, UInt_t word)
2217 {
2218   title += Form("0x%08x -> #ch : %2i, 0x%06x (%2i ch)",
2219                 word, GetNActiveChannels(word), GetActiveChannels(word), GetNActiveChannelsFromMask(word));
2220   return title;
2221 }
2222
2223 AliTRDrawStream::AliTRDrawStreamError::AliTRDrawStreamError(Int_t error, Int_t sector, Int_t stack, Int_t link, Int_t rob, Int_t mcm) :
2224   fError(error),
2225   fSector(sector),
2226   fStack(stack),
2227   fLink(link),
2228   fRob(rob),
2229   fMcm(mcm)
2230 {
2231   // ctor
2232
2233 }
2234
2235 void AliTRDrawStream::SortTracklets(TClonesArray *trklArray, TList &sortedTracklets, Int_t *indices)
2236 {
2237   // sort tracklets for referencing from GTU tracks
2238
2239   if (!trklArray)
2240     return;
2241
2242   Int_t nTracklets = trklArray->GetEntriesFast();
2243
2244   Int_t lastHC = -1;
2245   for (Int_t iTracklet = 0; iTracklet < nTracklets; iTracklet++) {
2246     AliTRDtrackletBase *trkl = (AliTRDtrackletBase*) ((*trklArray)[iTracklet]);
2247     Int_t hc = trkl->GetHCId();
2248     if ((hc < 0) || (hc >= 1080)) {
2249       AliErrorClass(Form("HC for tracklet: 0x%08x out of range: %i", trkl->GetTrackletWord(), trkl->GetHCId()));
2250       continue;
2251     }
2252     AliDebugClass(5, Form("hc: %4i : 0x%08x z: %2i", hc, trkl->GetTrackletWord(), trkl->GetZbin()));
2253     if (hc != lastHC) {
2254       AliDebugClass(2, Form("set tracklet index for HC %i to %i", hc, iTracklet));
2255       indices[hc] = iTracklet + 1;
2256       lastHC = hc;
2257     }
2258   }
2259
2260   for (Int_t iDet = 0; iDet < 540; iDet++) {
2261     Int_t trklIndexA = indices[2*iDet + 0] - 1;
2262     Int_t trklIndexB = indices[2*iDet + 1] - 1;
2263     Int_t trklIndex  = sortedTracklets.GetEntries();
2264     AliTRDtrackletBase *trklA = trklIndexA > -1 ? (AliTRDtrackletBase*) ((*trklArray)[trklIndexA]) : 0x0;
2265     AliTRDtrackletBase *trklB = trklIndexB > -1 ? (AliTRDtrackletBase*) ((*trklArray)[trklIndexB]) : 0x0;
2266     AliTRDtrackletBase *trklNext = 0x0;
2267     while (trklA != 0x0 || trklB != 0x0) {
2268       AliDebugClass(5, Form("det %i - A: %i/%i -> %p, B: %i/%i -> %p",
2269                        iDet, trklIndexA, nTracklets, trklA, trklIndexB, nTracklets, trklB));
2270       if (trklA == 0x0) {
2271         trklNext = trklB;
2272         trklIndexB++;
2273         trklB = trklIndexB < nTracklets ? (AliTRDtrackletBase*) ((*trklArray)[trklIndexB]) : 0x0;
2274         if (trklB && trklB->GetHCId() != 2*iDet + 1)
2275           trklB = 0x0;
2276       }
2277       else if (trklB == 0x0) {
2278         trklNext = trklA;
2279         trklIndexA++;
2280         trklA = trklIndexA < nTracklets ? (AliTRDtrackletBase*) ((*trklArray)[trklIndexA]) : 0x0;
2281         if (trklA && trklA->GetHCId() != 2*iDet)
2282           trklA = 0x0;
2283       }
2284       else {
2285         if (trklA->GetZbin() <= trklB->GetZbin()) {
2286           trklNext = trklA;
2287           trklIndexA++;
2288           trklA = trklIndexA < nTracklets ? (AliTRDtrackletBase*) ((*trklArray)[trklIndexA]) : 0x0;
2289           if (trklA && trklA->GetHCId() != 2*iDet)
2290             trklA = 0x0;
2291         }
2292         else {
2293           trklNext = trklB;
2294           trklIndexB++;
2295           trklB = trklIndexB < nTracklets ? (AliTRDtrackletBase*) ((*trklArray)[trklIndexB]) : 0x0;
2296           if (trklB && trklB->GetHCId() != 2*iDet + 1)
2297             trklB = 0x0;
2298         }
2299       }
2300       if (trklNext) {
2301         Int_t label = -2; // mark raw tracklets with label -2
2302         if (AliTRDtrackletMCM *trklMCM = dynamic_cast<AliTRDtrackletMCM*> (trklNext))
2303           label = trklMCM->GetLabel();
2304         AliESDTrdTracklet *esdTracklet = new AliESDTrdTracklet(trklNext->GetTrackletWord(), trklNext->GetHCId(), label);
2305         sortedTracklets.Add(esdTracklet);
2306       }
2307     }
2308
2309     // updating tracklet indices as in output
2310     if (sortedTracklets.GetEntries() != trklIndex) {
2311       indices[2*iDet + 0] = indices[2*iDet + 1] = trklIndex;
2312     } else {
2313       indices[2*iDet + 0] = indices[2*iDet + 1] = -1;
2314     }
2315   }
2316 }