]> git.uio.no Git - u/mrichter/AliRoot.git/blob - RAW/AliRawReader.cxx
Runing the online reconstruction in the Amore framework (Cvetan)
[u/mrichter/AliRoot.git] / RAW / AliRawReader.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 /* $Id$ */
17
18 ///////////////////////////////////////////////////////////////////////////////
19 ///
20 /// This is the base class for reading raw data.
21 ///
22 /// The derived classes, which operate on concrete raw data formats,
23 /// should implement
24 /// - ReadHeader to read the next (data/equipment) header
25 /// - ReadNextData to read the next raw data block (=1 DDL)
26 /// - ReadNext to read a given number of bytes
27 /// - several getters like GetType
28 ///
29 /// Sequential access to the raw data is provided by the methods
30 /// ReadHeader, ReadNextData, ReadNextInt, ReadNextShort, ReadNextChar
31 ///
32 /// If only data from a specific detector (and a given range of DDL numbers)
33 /// should be read, this can be achieved by the Select method.
34 /// Several getters provide information about the current event and the
35 /// current type of raw data.
36 ///
37 ///////////////////////////////////////////////////////////////////////////////
38
39 #include <TClass.h>
40 #include <TPluginManager.h>
41 #include <TROOT.h>
42 #include <TInterpreter.h>
43 #include <TSystem.h>
44
45 #include <Riostream.h>
46 #include "AliRawReader.h"
47 #include "AliRawReaderFile.h"
48 #include "AliRawReaderDate.h"
49 #include "AliRawReaderRoot.h"
50 #include "AliRawReaderChain.h"
51 #include "AliDAQ.h"
52 #include "AliLog.h"
53
54 ClassImp(AliRawReader)
55
56
57 AliRawReader::AliRawReader() :
58   fEquipmentIdsIn(NULL),
59   fEquipmentIdsOut(NULL),
60   fRequireHeader(kTRUE),
61   fHeader(NULL),
62   fCount(0),
63   fSelectEquipmentType(-1),
64   fSelectMinEquipmentId(-1),
65   fSelectMaxEquipmentId(-1),
66   fSkipInvalid(kFALSE),
67   fSelectEventType(-1),
68   fSelectTriggerMask(0),
69   fSelectTriggerExpr(),
70   fErrorCode(0),
71   fEventNumber(-1),
72   fErrorLogs("AliRawDataErrorLog",100),
73   fHeaderSwapped(NULL),
74   fIsValid(kTRUE)
75 {
76 // default constructor: initialize data members
77 // Allocate the swapped header in case of Mac
78 #ifndef R__BYTESWAP
79   fHeaderSwapped=new AliRawDataHeader();
80 #endif
81 }
82
83 Bool_t AliRawReader::LoadEquipmentIdsMap(const char *fileName)
84 {
85   // Open the mapping file
86   // and load the mapping data
87   ifstream input(fileName);
88   if (input.is_open()) {
89     Warning("AliRawReader","Equipment ID mapping file is found !");
90     const Int_t kMaxDDL = 256;
91     fEquipmentIdsIn = new TArrayI(kMaxDDL);
92     fEquipmentIdsOut = new TArrayI(kMaxDDL);
93     Int_t equipIn, equipOut;
94     Int_t nIds = 0;
95     while (input >> equipIn >> equipOut) {
96       if (nIds >= kMaxDDL) {
97         Error("AliRawReader","Too many equipment Id mappings found ! Truncating the list !");
98         break;
99       }
100       fEquipmentIdsIn->AddAt(equipIn,nIds); 
101       fEquipmentIdsOut->AddAt(equipOut,nIds);
102       nIds++;
103     }
104     fEquipmentIdsIn->Set(nIds);
105     fEquipmentIdsOut->Set(nIds);
106     input.close();
107     return kTRUE;
108   }
109   else {
110     Error("AliRawReader","equipment id map file is not found ! Skipping the mapping !");
111     return kFALSE;
112   }
113 }
114
115 AliRawReader::AliRawReader(const AliRawReader& rawReader) :
116   TObject(rawReader),
117   fEquipmentIdsIn(rawReader.fEquipmentIdsIn),
118   fEquipmentIdsOut(rawReader.fEquipmentIdsOut),
119   fRequireHeader(rawReader.fRequireHeader),
120   fHeader(rawReader.fHeader),
121   fCount(rawReader.fCount),
122   fSelectEquipmentType(rawReader.fSelectEquipmentType),
123   fSelectMinEquipmentId(rawReader.fSelectMinEquipmentId),
124   fSelectMaxEquipmentId(rawReader.fSelectMaxEquipmentId),
125   fSkipInvalid(rawReader.fSkipInvalid),
126   fSelectEventType(rawReader.fSelectEventType),
127   fSelectTriggerMask(rawReader.fSelectTriggerMask),
128   fSelectTriggerExpr(rawReader.fSelectTriggerExpr),
129   fErrorCode(0),
130   fEventNumber(-1),
131   fErrorLogs("AliRawDataErrorLog",100),
132   fHeaderSwapped(NULL),
133   fIsValid(rawReader.fIsValid)
134 {
135 // copy constructor
136 // Allocate the swapped header in case of Mac
137 #ifndef R__BYTESWAP
138   fHeaderSwapped=new AliRawDataHeader(*rawReader.fHeaderSwapped);
139 #endif
140 }
141
142 AliRawReader& AliRawReader::operator = (const AliRawReader& rawReader)
143 {
144 // assignment operator
145   fEquipmentIdsIn = rawReader.fEquipmentIdsIn;
146   fEquipmentIdsOut = rawReader.fEquipmentIdsOut;
147
148   fHeader = rawReader.fHeader;
149   fCount = rawReader.fCount;
150
151   fSelectEquipmentType = rawReader.fSelectEquipmentType;
152   fSelectMinEquipmentId = rawReader.fSelectMinEquipmentId;
153   fSelectMaxEquipmentId = rawReader.fSelectMaxEquipmentId;
154   fSkipInvalid = rawReader.fSkipInvalid;
155   fSelectEventType = rawReader.fSelectEventType;
156   fSelectTriggerMask = rawReader.fSelectTriggerMask;
157   fSelectTriggerExpr = rawReader.fSelectTriggerExpr;
158
159   fErrorCode = rawReader.fErrorCode;
160
161   fEventNumber = rawReader.fEventNumber;
162   fErrorLogs = *((TClonesArray*)rawReader.fErrorLogs.Clone());
163
164   fIsValid = rawReader.fIsValid;
165
166   return *this;
167 }
168
169 AliRawReader::~AliRawReader()
170 {
171   // destructor
172   // delete the mapping arrays if
173   // initialized
174   if (fEquipmentIdsIn) delete fEquipmentIdsIn;
175   if (fEquipmentIdsOut) delete fEquipmentIdsOut;
176   fErrorLogs.Delete();
177   if (fHeaderSwapped) delete fHeaderSwapped;
178 }
179
180 AliRawReader* AliRawReader::Create(const char *uri)
181 {
182   // RawReader's factory
183   // It instantiate corresponding raw-reader implementation class object
184   // depending on the URI provided
185   // Normal URIs point to files, while the URI starting with
186   // 'mem://:' or 'mem://<filename>' will create
187   // AliRawReaderDateOnline object which is supposed to be used
188   // in the online reconstruction
189
190   TString strURI = uri;
191
192   if (strURI.IsNull()) {
193     AliWarningClass("No raw-reader created");
194     return NULL;
195   }
196
197   TObjArray *fields = strURI.Tokenize("?");
198   TString &fileURI = ((TObjString*)fields->At(0))->String();
199
200   AliRawReader *rawReader = NULL;
201   if (fileURI.BeginsWith("mem://") || fileURI.BeginsWith("^")) {
202     if (fileURI.BeginsWith("mem://")) fileURI.ReplaceAll("mem://","");
203     AliInfoClass(Form("Creating raw-reader in order to read events in shared memory (option=%s)",fileURI.Data()));
204
205     TPluginManager* pluginManager = gROOT->GetPluginManager();
206     TString rawReaderName = "AliRawReaderDateOnline";
207     TPluginHandler* pluginHandler = pluginManager->FindHandler("AliRawReader", "online");
208     // if not, add a plugin for it
209     if (!pluginHandler) {
210       pluginManager->AddHandler("AliRawReader", "online", 
211                                 "AliRawReaderDateOnline", "RAWDatarecOnline", "AliRawReaderDateOnline(const char*)");
212       pluginHandler = pluginManager->FindHandler("AliRawReader", "online");
213     }
214     if (pluginHandler && (pluginHandler->LoadPlugin() == 0)) {
215       rawReader = (AliRawReader*)pluginHandler->ExecPlugin(1,fileURI.Data());
216     }
217     else {
218       delete fields;
219       return NULL;
220     }
221   }
222   else if (fileURI.BeginsWith("amore://")) {
223     // A special raw-data URL used in case
224     // the raw-data reading is steered from
225     // ouside, i.e. from AMORE
226     fileURI.ReplaceAll("amore://","");
227     AliInfoClass("Creating raw-reader in order to read events sent by AMORE");
228     rawReader = new AliRawReaderDate((void *)NULL);
229   }
230   else if (fileURI.BeginsWith("collection://")) {
231     fileURI.ReplaceAll("collection://","");
232     AliInfoClass(Form("Creating raw-reader in order to read raw-data files collection defined in %s",fileURI.Data()));
233     rawReader = new AliRawReaderChain(fileURI);
234   }
235   else {
236     AliInfoClass(Form("Creating raw-reader in order to read raw-data file: %s",fileURI.Data()));
237     TString filename(gSystem->ExpandPathName(fileURI.Data()));
238     if (filename.EndsWith("/")) {
239       rawReader = new AliRawReaderFile(filename);
240     } else if (filename.EndsWith(".root")) {
241       rawReader = new AliRawReaderRoot(filename);
242     } else {
243       rawReader = new AliRawReaderDate(filename);
244     }
245   }
246
247   if (!rawReader->IsRawReaderValid()) {
248     AliErrorClass(Form("Raw-reader is invalid - check the input URI (%s)",fileURI.Data()));
249     delete rawReader;
250     fields->Delete();
251     delete fields;
252     return NULL;
253   }
254
255   // Now apply event selection criteria (if specified)
256   if (fields->GetEntries() > 1) {
257     Int_t eventType = -1;
258     ULong64_t triggerMask = 0;
259     TString triggerExpr;
260     for(Int_t i = 1; i < fields->GetEntries(); i++) {
261       if (!fields->At(i)) continue;
262       TString &option = ((TObjString*)fields->At(i))->String();
263       if (option.BeginsWith("EventType=",TString::kIgnoreCase)) {
264         option.ReplaceAll("EventType=","");
265         eventType = option.Atoi();
266         continue;
267       }
268       if (option.BeginsWith("Trigger=",TString::kIgnoreCase)) {
269         option.ReplaceAll("Trigger=","");
270         if (option.IsDigit()) {
271           triggerMask = option.Atoll();
272         }
273         else {
274           triggerExpr = option.Data();
275         }
276         continue;
277       }
278       AliWarningClass(Form("Ignoring invalid event selection option: %s",option.Data()));
279     }
280     AliInfoClass(Form("Event selection criteria specified:   eventype=%d   trigger mask=%llx   trigger expression=%s",
281                  eventType,triggerMask,triggerExpr.Data()));
282     rawReader->SelectEvents(eventType,triggerMask,triggerExpr.Data());
283   }
284
285   fields->Delete();
286   delete fields;
287
288   return rawReader;
289 }
290
291 Int_t AliRawReader::GetMappedEquipmentId() const
292 {
293   if (!fEquipmentIdsIn || !fEquipmentIdsOut) {
294     Error("AliRawReader","equipment Ids mapping is not initialized !");
295     return GetEquipmentId();
296   }
297   Int_t equipmentId = GetEquipmentId();
298   for(Int_t iId = 0; iId < fEquipmentIdsIn->GetSize(); iId++) {
299     if (equipmentId == fEquipmentIdsIn->At(iId)) {
300       equipmentId = fEquipmentIdsOut->At(iId);
301       break;
302     }
303   }
304   return equipmentId;
305 }
306
307 Int_t AliRawReader::GetDetectorID() const
308 {
309   // Get the detector ID
310   // The list of detector IDs
311   // can be found in AliDAQ.h
312   Int_t equipmentId;
313   if (fEquipmentIdsIn && fEquipmentIdsIn)
314     equipmentId = GetMappedEquipmentId();
315   else
316     equipmentId = GetEquipmentId();
317
318   if (equipmentId >= 0) {
319     Int_t ddlIndex;
320     return AliDAQ::DetectorIDFromDdlID(equipmentId,ddlIndex);
321   }
322   else
323     return -1;
324 }
325
326 Int_t AliRawReader::GetDDLID() const
327 {
328   // Get the DDL ID (within one sub-detector)
329   // The list of detector IDs
330   // can be found in AliDAQ.h
331   Int_t equipmentId;
332   if (fEquipmentIdsIn && fEquipmentIdsIn)
333     equipmentId = GetMappedEquipmentId();
334   else
335     equipmentId = GetEquipmentId();
336
337   if (equipmentId >= 0) {
338     Int_t ddlIndex;
339     AliDAQ::DetectorIDFromDdlID(equipmentId,ddlIndex);
340     return ddlIndex;
341   }
342   else
343     return -1;
344 }
345
346 void AliRawReader::Select(const char *detectorName, Int_t minDDLID, Int_t maxDDLID)
347 {
348 // read only data of the detector with the given name and in the given
349 // range of DDLs (minDDLID <= DDLID <= maxDDLID).
350 // no selection is applied if a value < 0 is used.
351   Int_t detectorID = AliDAQ::DetectorID(detectorName);
352   if(detectorID >= 0)
353     Select(detectorID,minDDLID,maxDDLID);
354 }
355
356 void AliRawReader::Select(Int_t detectorID, Int_t minDDLID, Int_t maxDDLID)
357 {
358 // read only data of the detector with the given ID and in the given
359 // range of DDLs (minDDLID <= DDLID <= maxDDLID).
360 // no selection is applied if a value < 0 is used.
361
362   fSelectEquipmentType = -1;
363
364   if (minDDLID < 0)
365     fSelectMinEquipmentId = AliDAQ::DdlIDOffset(detectorID);
366   else
367     fSelectMinEquipmentId = AliDAQ::DdlID(detectorID,minDDLID);
368
369   if (maxDDLID < 0)
370     fSelectMaxEquipmentId = AliDAQ::DdlID(detectorID,AliDAQ::NumberOfDdls(detectorID)-1);
371   else
372     fSelectMaxEquipmentId = AliDAQ::DdlID(detectorID,maxDDLID);
373 }
374
375 void AliRawReader::SelectEquipment(Int_t equipmentType, 
376                                    Int_t minEquipmentId, Int_t maxEquipmentId)
377 {
378 // read only data of the equipment with the given type and in the given
379 // range of IDs (minEquipmentId <= EquipmentId <= maxEquipmentId).
380 // no selection is applied if a value < 0 is used.
381
382   fSelectEquipmentType = equipmentType;
383   fSelectMinEquipmentId = minEquipmentId;
384   fSelectMaxEquipmentId = maxEquipmentId;
385 }
386
387 void AliRawReader::SelectEvents(Int_t type, ULong64_t triggerMask,
388                                 const char *triggerExpr)
389 {
390 // read only events with the given type and optionally
391 // trigger mask.
392 // no selection is applied if value = 0 is used.
393 // Trigger selection can be done via string (triggerExpr)
394 // which defines the trigger logic to be used. It works only
395 // after LoadTriggerClass() method is called for all involved
396 // trigger classes.
397
398   fSelectEventType = type;
399   fSelectTriggerMask = triggerMask;
400   if (triggerExpr) fSelectTriggerExpr = triggerExpr;
401 }
402
403 void AliRawReader::LoadTriggerClass(const char* name, Int_t index)
404 {
405   // Loads the list of trigger classes defined.
406   // Used in conjunction with IsEventSelected in the
407   // case when the trigger selection is given by
408   // fSelectedTriggerExpr
409
410   if (fSelectTriggerExpr.IsNull()) return;
411
412   fSelectTriggerExpr.ReplaceAll(name,Form("[%d]",index));
413 }
414
415 Bool_t AliRawReader::IsSelected() const
416 {
417 // apply the selection (if any)
418
419   if (fSkipInvalid && !IsValid()) return kFALSE;
420
421   if (fSelectEquipmentType >= 0)
422     if (GetEquipmentType() != fSelectEquipmentType) return kFALSE;
423
424   Int_t equipmentId;
425   if (fEquipmentIdsIn && fEquipmentIdsIn)
426     equipmentId = GetMappedEquipmentId();
427   else
428     equipmentId = GetEquipmentId();
429
430   if ((fSelectMinEquipmentId >= 0) && 
431       (equipmentId < fSelectMinEquipmentId))
432     return kFALSE;
433   if ((fSelectMaxEquipmentId >= 0) && 
434       (equipmentId > fSelectMaxEquipmentId))
435     return kFALSE;
436
437   return kTRUE;
438 }
439
440 Bool_t AliRawReader::IsEventSelected() const
441 {
442   // apply the event selection (if any)
443
444   // First check the event type
445   if (fSelectEventType >= 0) {
446     if (GetType() != (UInt_t) fSelectEventType) return kFALSE;
447   }
448
449   // Then check the trigger pattern and compared it
450   // to the required trigger mask
451   if (fSelectTriggerMask != 0) {
452     if ((GetClassMask() & fSelectTriggerMask) != fSelectTriggerMask) return kFALSE;
453   }
454
455   if (!fSelectTriggerExpr.IsNull()) {
456     TString expr(fSelectTriggerExpr);
457     ULong64_t mask = GetClassMask();
458     for(Int_t itrigger = 0; itrigger < 50; itrigger++) {
459       if (mask & (1 << itrigger)) {
460         expr.ReplaceAll(Form("[%d]",itrigger),"1");
461       }
462       else {
463         expr.ReplaceAll(Form("[%d]",itrigger),"0");
464       }
465     }
466     Int_t error;
467     if ((gROOT->ProcessLineFast(expr.Data(),&error) == 0) &&
468         (error == TInterpreter::kNoError)) {
469       return kFALSE;
470     }
471   }
472
473   return kTRUE;
474 }
475
476 UInt_t AliRawReader::SwapWord(UInt_t x) const
477 {
478    // Swap the endianess of the integer value 'x'
479
480    return (((x & 0x000000ffU) << 24) | ((x & 0x0000ff00U) <<  8) |
481            ((x & 0x00ff0000U) >>  8) | ((x & 0xff000000U) >> 24));
482 }
483
484 UShort_t AliRawReader::SwapShort(UShort_t x) const
485 {
486    // Swap the endianess of the short value 'x'
487
488    return (((x & 0x00ffU) <<  8) | ((x & 0xff00U) >>  8)) ;
489 }
490
491 Bool_t AliRawReader::ReadNextInt(UInt_t& data)
492 {
493 // reads the next 4 bytes at the current position
494 // returns kFALSE if the data could not be read
495
496   while (fCount == 0) {
497     if (!ReadHeader()) return kFALSE;
498   }
499   if (fCount < (Int_t) sizeof(data)) {
500     Error("ReadNextInt", 
501           "too few data left (%d bytes) to read an UInt_t!", fCount);
502     return kFALSE;
503   }
504   if (!ReadNext((UChar_t*) &data, sizeof(data))) {
505     Error("ReadNextInt", "could not read data!");
506     return kFALSE;
507   }
508 #ifndef R__BYTESWAP
509   data=SwapWord(data);
510 #endif
511   return kTRUE;
512 }
513
514 Bool_t AliRawReader::ReadNextShort(UShort_t& data)
515 {
516 // reads the next 2 bytes at the current position
517 // returns kFALSE if the data could not be read
518
519   while (fCount == 0) {
520     if (!ReadHeader()) return kFALSE;
521   }
522   if (fCount < (Int_t) sizeof(data)) {
523     Error("ReadNextShort", 
524           "too few data left (%d bytes) to read an UShort_t!", fCount);
525     return kFALSE;
526   }
527   if (!ReadNext((UChar_t*) &data, sizeof(data))) {
528     Error("ReadNextShort", "could not read data!");
529     return kFALSE;
530   }
531 #ifndef R__BYTESWAP
532   data=SwapShort(data);
533 #endif
534   return kTRUE;
535 }
536
537 Bool_t AliRawReader::ReadNextChar(UChar_t& data)
538 {
539 // reads the next 1 byte at the current stream position
540 // returns kFALSE if the data could not be read
541
542   while (fCount == 0) {
543     if (!ReadHeader()) return kFALSE;
544   }
545   if (!ReadNext((UChar_t*) &data, sizeof(data))) {
546     Error("ReadNextChar", "could not read data!");
547     return kFALSE;
548   }
549   return kTRUE;
550 }
551
552 Bool_t  AliRawReader::GotoEvent(Int_t event)
553 {
554   // Random access to certain
555   // event index. Could be very slow
556   // for some non-root raw-readers.
557   // So it should be reimplemented there.
558   if (event < fEventNumber) RewindEvents();
559
560   while (fEventNumber < event) {
561     if (!NextEvent()) return kFALSE;
562   }
563
564   return kTRUE;
565 }
566
567 Int_t AliRawReader::CheckData() const
568 {
569 // check the consistency of the data
570 // derived classes should overwrite the default method which returns 0 (no err)
571
572   return 0;
573 }
574
575
576 void AliRawReader::DumpData(Int_t limit)
577 {
578 // print the raw data
579 // if limit is not negative, only the first and last "limit" lines of raw data
580 // are printed
581
582   Reset();
583   if (!ReadHeader()) {
584     Error("DumpData", "no header");
585     return;
586   }
587   printf("header:\n"
588          " type = %d  run = %d  ", GetType(), GetRunNumber());
589   if (GetEventId()) {
590     printf("event = %8.8x %8.8x\n", GetEventId()[1], GetEventId()[0]);
591   } else {
592     printf("event = -------- --------\n");
593   }
594   if (GetTriggerPattern()) {
595     printf(" trigger = %8.8x %8.8x  ",
596            GetTriggerPattern()[1], GetTriggerPattern()[0]);
597   } else {
598     printf(" trigger = -------- --------  ");
599   }
600   if (GetDetectorPattern()) {
601     printf("detector = %8.8x\n", GetDetectorPattern()[0]);
602   } else {
603     printf("detector = --------\n");
604   }
605   if (GetAttributes()) {
606     printf(" attributes = %8.8x %8.8x %8.8x  ",
607            GetAttributes()[2], GetAttributes()[1], GetAttributes()[0]);
608   } else {
609     printf(" attributes = -------- -------- --------  ");
610   }
611   printf("GDC = %d\n", GetGDCId());
612   printf("\n");
613
614   do {
615     printf("-------------------------------------------------------------------------------\n");
616     printf("LDC = %d\n", GetLDCId());
617
618     printf("equipment:\n"
619            " size = %d  type = %d  id = %d\n",
620            GetEquipmentSize(), GetEquipmentType(), GetEquipmentId());
621     if (GetEquipmentAttributes()) {
622       printf(" attributes = %8.8x %8.8x %8.8x  ", GetEquipmentAttributes()[2],
623              GetEquipmentAttributes()[1], GetEquipmentAttributes()[0]);
624     } else {
625       printf(" attributes = -------- -------- --------  ");
626     }
627     printf("element size = %d\n", GetEquipmentElementSize());
628
629     printf("data header:\n"
630            " size = %d  version = %d  valid = %d  compression = %d\n",
631            GetDataSize(), GetVersion(), IsValid(), IsCompressed());
632
633     printf("\n");
634     if (limit == 0) continue;
635
636     Int_t size = GetDataSize();
637     char line[70];
638     for (Int_t i = 0; i < 70; i++) line[i] = ' ';
639     line[69] = '\0';
640     Int_t pos = 0;
641     Int_t max = 16;
642     UChar_t byte;
643
644     for (Int_t n = 0; n < size; n++) {
645       if (!ReadNextChar(byte)) {
646         Error("DumpData", "couldn't read byte number %d\n", n);
647         break;
648       }
649       if (pos >= max) {
650         printf("%8.8x  %s\n", n-pos, line);
651         for (Int_t i = 0; i < 70; i++) line[i] = ' ';
652         line[69] = '\0';
653         pos = 0;
654         if ((limit > 0) && (n/max == limit)) {
655           Int_t nContinue = ((size-1)/max+1-limit) * max;
656           if (nContinue > n) {
657             printf(" [skipping %d bytes]\n", nContinue-n);
658             n = nContinue-1;
659             continue;
660           }
661         }
662       }
663       Int_t offset = pos/4;
664       if ((byte > 0x20) && (byte < 0x7f)) {
665         line[pos+offset] = byte;
666       } else {
667         line[pos+offset] = '.';
668       }
669       char hex[3];
670       sprintf(hex, "%2.2x", byte);
671       line[max+max/4+3+2*pos+offset] = hex[0];
672       line[max+max/4+4+2*pos+offset] = hex[1];
673       pos++;
674     }
675
676     if (pos > 0) printf("%8.8x  %s\n", size-pos, line);
677     printf("\n");
678            
679   } while (ReadHeader());
680 }
681
682 void AliRawReader::AddErrorLog(AliRawDataErrorLog::ERawDataErrorLevel level,
683                                Int_t code,
684                                const char *message)
685 {
686   // Add a raw data error message to the list
687   // of raw-data decoding errors
688   if (fEventNumber < 0) {
689     return;
690   }
691   Int_t ddlId = GetEquipmentId();
692   if (ddlId < 0) {
693     AliError("No ddl raw data have been read so far! Impossible to add a raw data error log!");
694     return;
695   }
696
697   Int_t prevEventNumber = -1;
698   Int_t prevDdlId = -1;
699   Int_t prevErrorCode = -1;
700   AliRawDataErrorLog *prevLog = (AliRawDataErrorLog *)fErrorLogs.Last();
701   if (prevLog) {
702     prevEventNumber = prevLog->GetEventNumber();
703     prevDdlId       = prevLog->GetDdlID();
704     prevErrorCode   = prevLog->GetErrorCode();
705   }
706
707   if ((prevEventNumber != fEventNumber) ||
708       (prevDdlId != ddlId) ||
709       (prevErrorCode != code)) {
710     new (fErrorLogs[fErrorLogs.GetEntriesFast()])
711       AliRawDataErrorLog(fEventNumber,
712                          ddlId,
713                          level,
714                          code,
715                          message);
716   }
717   else
718     if (prevLog) prevLog->AddCount();
719
720 }
721
722 Bool_t AliRawReader::GotoEventWithID(Int_t event, 
723                                      UInt_t period,
724                                      UInt_t orbitID,
725                                      UShort_t bcID)
726 {
727   // Go to certain event number by
728   // checking the event ID.
729   // Useful in case event-selection
730   // is applied and the 'event' is
731   // relative
732   if (!GotoEvent(event)) return kFALSE;
733
734   while (GetBCID()    != period  ||
735          GetOrbitID() != orbitID ||
736          GetPeriod()  != bcID) {
737     if (!NextEvent()) return kFALSE;
738   }
739
740   return kTRUE;
741 }
742