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