Line data Source code
1 : // $Id$
2 :
3 : /**************************************************************************
4 : * This file is property of and copyright by the ALICE HLT Project *
5 : * ALICE Experiment at CERN, All rights reserved. *
6 : * *
7 : * Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no> *
8 : * for The ALICE HLT Project. *
9 : * *
10 : * Permission to use, copy, modify and distribute this software and its *
11 : * documentation strictly for non-commercial purposes is hereby granted *
12 : * without fee, provided that the above copyright notice appears in all *
13 : * copies and that both the copyright notice and this permission notice *
14 : * appear in the supporting documentation. The authors make no claims *
15 : * about the suitability of this software for any purpose. It is *
16 : * provided "as is" without express or implied warranty. *
17 : **************************************************************************/
18 :
19 : /// @file AliRawReaderHLT.cxx
20 : /// @author Matthias Richter
21 : /// @date
22 : /// @brief AliRawReader implementation which replaces original input of
23 : /// detectors with the appropriate HLT output.
24 :
25 : #include "AliRawReaderHLT.h"
26 : #include "AliHLTOUTRawReader.h"
27 : #include "AliHLTModuleAgent.h"
28 : #include "AliHLTOUTHandler.h"
29 : #include "AliHLTOUTHandlerEquId.h"
30 : #include "AliHLTSystem.h"
31 : #include "AliHLTPluginBase.h"
32 : #include "AliHLTCDHWrapper.h"
33 : #include "AliLog.h"
34 : #include "AliDAQ.h" // RAW, for detector names and equipment ids
35 : #include "TObjString.h"
36 : #include <cassert>
37 :
38 : /** ROOT macro for the implementation of ROOT specific class methods */
39 6 : ClassImp(AliRawReaderHLT)
40 :
41 : AliRawReaderHLT::AliRawReaderHLT(AliRawReader* pRawreader, const char* options)
42 : :
43 0 : AliRawReader(),
44 0 : fpParentReader(pRawreader),
45 0 : fOptions(),
46 0 : fSystemOptions(),
47 0 : fpData(NULL),
48 0 : fDataSize(0),
49 0 : fOffset(0),
50 0 : fPosition(0),
51 0 : fEquipmentId(-1),
52 0 : fbHaveHLTData(false),
53 0 : fDetectors(),
54 0 : fpHLTOUT(NULL),
55 0 : fbReadFirst(true),
56 0 : fpDataHandler(NULL),
57 0 : fpPluginBase(new AliHLTPluginBase)
58 0 : {
59 : // see header file for class documentation
60 : // or
61 : // refer to README to build package
62 : // or
63 : // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
64 0 : fOptions=options;
65 0 : ScanOptions(options);
66 0 : }
67 :
68 : AliRawReaderHLT::~AliRawReaderHLT()
69 0 : {
70 : // see header file for class documentation
71 0 : ReleaseHLTData();
72 0 : if (fpPluginBase) delete fpPluginBase;
73 0 : fpPluginBase=NULL;
74 0 : }
75 :
76 : UInt_t AliRawReaderHLT::GetType() const
77 : {
78 : // see header file for class documentation
79 0 : return fpParentReader->GetType();
80 : }
81 :
82 : UInt_t AliRawReaderHLT::GetRunNumber() const
83 : {
84 : // see header file for class documentation
85 0 : return fpParentReader->GetRunNumber();
86 : }
87 :
88 : const UInt_t* AliRawReaderHLT::GetEventId() const
89 : {
90 : // see header file for class documentation
91 0 : return fpParentReader->GetEventId();
92 : }
93 :
94 : const UInt_t* AliRawReaderHLT::GetTriggerPattern() const
95 : {
96 : // see header file for class documentation
97 0 : return fpParentReader->GetTriggerPattern();
98 : }
99 :
100 : const UInt_t* AliRawReaderHLT::GetDetectorPattern() const
101 : {
102 : // see header file for class documentation
103 0 : return fpParentReader->GetDetectorPattern();
104 : }
105 :
106 : const UInt_t* AliRawReaderHLT::GetAttributes() const
107 : {
108 : // see header file for class documentation
109 0 : return fpParentReader->GetAttributes();
110 : }
111 :
112 : const UInt_t* AliRawReaderHLT::GetSubEventAttributes() const
113 : {
114 : // see header file for class documentation
115 0 : return fpParentReader->GetSubEventAttributes();
116 : }
117 :
118 : UInt_t AliRawReaderHLT::GetLDCId() const
119 : {
120 : // see header file for class documentation
121 0 : return fpParentReader->GetLDCId();
122 : }
123 :
124 : UInt_t AliRawReaderHLT::GetGDCId() const
125 : {
126 : // see header file for class documentation
127 0 : return fpParentReader->GetGDCId();
128 : }
129 :
130 : UInt_t AliRawReaderHLT::GetTimestamp() const
131 : {
132 : // see header file for class documentation
133 0 : return fpParentReader->GetTimestamp();
134 : }
135 :
136 : const UInt_t* AliRawReaderHLT::GetEquipmentAttributes() const
137 : {
138 : // see header file for class documentation
139 0 : return fpParentReader->GetEquipmentAttributes();
140 : }
141 :
142 : Int_t AliRawReaderHLT::GetEquipmentElementSize() const
143 : {
144 : // don't know what it really means, bu the AliRawReaderFile
145 : // just sets it to 0
146 : // do the same if we have a valid equipment data set from
147 : // the HLT stream
148 0 : if (fEquipmentId>=0) return 0;
149 0 : return fpParentReader->GetEquipmentElementSize();
150 0 : }
151 :
152 : Int_t AliRawReaderHLT::GetEquipmentHeaderSize() const
153 : {
154 : // equipment header means the additional data header?
155 : // if we have a valid equipment data set from the HLT stream
156 : // there is no additional header
157 0 : if (fEquipmentId>=0) return 0;
158 0 : return fpParentReader->GetEquipmentHeaderSize();
159 0 : }
160 :
161 : Int_t AliRawReaderHLT::GetEquipmentSize() const
162 : {
163 : // return the equipment size, that's including the CDH
164 : // fDataSize has been set to the full size of the block if it is from HLTOUT
165 : // if the data block is from the parent rawreader it is only the pointer
166 : // to the payload and the size of the CDH must be added
167 0 : if (fEquipmentId>=0) return fDataSize + (fbHaveHLTData?0:GetEquipmentHeaderSize());
168 0 : return fpParentReader->GetEquipmentSize();
169 0 : }
170 :
171 : Int_t AliRawReaderHLT::GetEquipmentType() const
172 : {
173 : // see header file for class documentation
174 0 : return fpParentReader->GetEquipmentType();
175 : }
176 :
177 : Int_t AliRawReaderHLT::GetEquipmentId() const
178 : {
179 : // id of current equipment
180 : Int_t id=-1;
181 0 : if (fEquipmentId>=0) id=fEquipmentId;
182 0 : else id=fpParentReader->GetEquipmentId();
183 0 : return id;
184 : }
185 :
186 : Bool_t AliRawReaderHLT::ReadHeader()
187 : {
188 : // read the header of the next equipment
189 : // depending on whether there is data redirected from HLT for the current event
190 : // first the data in the HLTOUT is tried
191 : Bool_t result=kFALSE;
192 0 : Bool_t firstParentCycle=fbHaveHLTData;
193 0 : while ((fbHaveHLTData=(fbHaveHLTData && ReadNextHLTData()))) {
194 : // all internal data variables set
195 0 : assert(fpData!=NULL);
196 0 : AliHLTCDHWrapper cdh((void*)fpData);
197 0 : if(cdh.GetVersion()==2){
198 0 : fHeader=reinterpret_cast<AliRawDataHeader*>(const_cast<AliHLTUInt8_t*>(fpData));
199 0 : fHeaderV3=NULL;
200 0 : } else {
201 0 : fHeader=NULL;
202 0 : fHeaderV3=reinterpret_cast<AliRawDataHeaderV3*>(const_cast<AliHLTUInt8_t*>(fpData));
203 : }
204 0 : fOffset=cdh.GetHeaderSize();
205 0 : fPosition=fOffset;
206 0 : if ((result=IsSelected())) break;
207 0 : }
208 0 : firstParentCycle&=!fbHaveHLTData; // true if it just changed from true to false
209 0 : while (!result) {
210 0 : if (firstParentCycle) {
211 : firstParentCycle=kFALSE;
212 : // reset and set the selection back to the original one
213 0 : fpParentReader->Reset();
214 0 : fpParentReader->SelectEquipment(fSelectEquipmentType, fSelectMinEquipmentId, fSelectMaxEquipmentId);
215 0 : }
216 :
217 0 : if (!(result=fpParentReader->ReadHeader())) {
218 0 : fHeader=NULL;
219 0 : fHeaderV3=NULL;
220 0 : break;
221 : }
222 0 : fHeader=const_cast<AliRawDataHeader*>(fpParentReader->GetDataHeader());
223 0 : fHeaderV3=const_cast<AliRawDataHeaderV3*>(fpParentReader->GetDataHeaderV3());
224 0 : fDataSize=fpParentReader->GetDataSize();
225 0 : fPosition=0;
226 0 : fpData=NULL;
227 :
228 : // filter out all equipment ids which should be taken from the HLT stream
229 0 : int id=fpParentReader->GetEquipmentId();
230 0 : if ((result=!IsHLTInput(id))) break;
231 0 : }
232 0 : return result;
233 0 : }
234 :
235 : Bool_t AliRawReaderHLT::ReadNextData(UChar_t*& data)
236 : {
237 : // read data from equipment, return pointer to data, GetDataSize
238 : // provides the data size
239 0 : return ReadNextData(data, kTRUE);
240 : }
241 :
242 : Bool_t AliRawReaderHLT::ReadNextData(UChar_t*& data, Bool_t readHeader)
243 : {
244 : // this function is the backbone of the ReadNext functions, it gets the
245 : // whole data block either from the HLT stream or the parent raw reader.
246 : // Each call of ReadNextData directly jumps to the next data set.
247 : Bool_t result=kTRUE;
248 :
249 : // read new header if data already read
250 0 : if (fPosition<fDataSize || (result=(readHeader && ReadHeader()))) {
251 0 : if (fbHaveHLTData && fpHLTOUT!=NULL) {
252 : // all internal data variables set
253 : result=kTRUE;
254 0 : AliHLTCDHWrapper cdh((void*) fpData);
255 0 : data=const_cast<AliHLTUInt8_t*>(fpData+cdh.GetHeaderSize());
256 : // fpData includes the CDH, set offset behind CDH
257 0 : fOffset=cdh.GetHeaderSize();
258 0 : } else {
259 : // no data in the HLT stream, read real data
260 : //AliInfo(Form("read from parent reader: min=%d max=%d", fSelectMinEquipmentId, fSelectMaxEquipmentId));
261 :
262 : // read data
263 0 : result=fpParentReader->ReadNextData(data);
264 0 : if (result) {
265 0 : fpData=data;
266 0 : fDataSize=fpParentReader->GetDataSize();
267 : // fpData is without CDH
268 0 : fOffset=0;
269 0 : } else {
270 0 : fpData=NULL;
271 0 : fDataSize=0;
272 : }
273 :
274 0 : fEquipmentId=-1;
275 : }
276 0 : fPosition=fDataSize;
277 0 : }
278 0 : return result;
279 0 : }
280 :
281 : Bool_t AliRawReaderHLT::ReadNextInt(UInt_t& data)
282 : {
283 : // see header file for class documentation
284 : int iCopy=sizeof(UInt_t);
285 0 : UChar_t* dummy=NULL;
286 0 : do {
287 0 : if (fpData && (fDataSize-fOffset)>=iCopy) {
288 0 : data=*reinterpret_cast<const UInt_t*>(fpData+fOffset);
289 0 : fOffset+=iCopy;
290 0 : return kTRUE;
291 : }
292 0 : } while (ReadNextData(dummy, kTRUE));
293 0 : return kFALSE;
294 0 : }
295 :
296 : Bool_t AliRawReaderHLT::ReadNextShort(UShort_t& data)
297 : {
298 : // see header file for class documentation
299 : int iCopy=sizeof(UShort_t);
300 0 : UChar_t* dummy=NULL;
301 0 : do {
302 0 : if (fpData && (fDataSize-fOffset)>=iCopy) {
303 0 : data=*reinterpret_cast<const UShort_t*>(fpData+fOffset);
304 0 : fOffset+=iCopy;
305 0 : return kTRUE;
306 : }
307 0 : } while (ReadNextData(dummy, kTRUE));
308 0 : return kFALSE;
309 0 : }
310 :
311 : Bool_t AliRawReaderHLT::ReadNextChar(UChar_t& data)
312 : {
313 : // see header file for class documentation
314 : int iCopy=sizeof(UChar_t);
315 0 : UChar_t* dummy=NULL;
316 0 : do {
317 0 : if (fpData && (fDataSize-fOffset)>=iCopy) {
318 0 : data=*reinterpret_cast<const UChar_t*>(fpData+fOffset);
319 0 : fOffset+=iCopy;
320 0 : return kTRUE;
321 : }
322 0 : } while (ReadNextData(dummy, kTRUE));
323 0 : return kFALSE;
324 0 : }
325 :
326 : Bool_t AliRawReaderHLT::ReadNext(UChar_t* data, Int_t size)
327 : {
328 : // see header file for class documentation
329 0 : UChar_t* dummy=NULL;
330 0 : do {
331 0 : if (fpData && (fDataSize-fOffset)>=size) {
332 : // copy remaining data
333 : int iCopy=fDataSize-fOffset;
334 0 : if (iCopy>size) iCopy=size;
335 0 : memcpy(data, fpData+fOffset, iCopy);
336 0 : fOffset+=iCopy;
337 : return kTRUE;
338 : }
339 : // By convention, the ReadNextData function stays in the
340 : // current block and does not switch to the next one
341 : // automatically -> kFALSE
342 0 : } while (ReadNextData(dummy, kFALSE));
343 0 : return kFALSE;
344 0 : }
345 :
346 : Bool_t AliRawReaderHLT::Reset()
347 : {
348 : // see header file for class documentation
349 0 : ReleaseHLTData(false/* keep HLTOUT instance */);
350 0 : Bool_t result=fpParentReader->Reset();
351 0 : fEquipmentId=-1;
352 :
353 : // check if redirection is enabled for at least one detector in the selected range
354 0 : fbHaveHLTData=EvaluateSelection();
355 :
356 : // start reading HLTOUT data blocks from the beginning
357 0 : fbReadFirst=true;
358 :
359 0 : return result;
360 : }
361 :
362 : Bool_t AliRawReaderHLT::NextEvent()
363 : {
364 : // see header file for class documentation
365 :
366 0 : ReleaseHLTData();
367 :
368 0 : Bool_t result=fpParentReader->NextEvent();
369 0 : if (result) {
370 0 : fEventNumber++;
371 0 : Reset();
372 0 : }
373 0 : return result;
374 : }
375 :
376 : Bool_t AliRawReaderHLT::RewindEvents()
377 : {
378 : // see header file for class documentation
379 0 : fEventNumber=-1;
380 0 : Reset();
381 0 : return fpParentReader->RewindEvents();
382 : }
383 :
384 : void AliRawReaderHLT::Select(Int_t detectorID, Int_t minDDLID, Int_t maxDDLID)
385 : {
386 : // see header file for class documentation
387 0 : AliRawReader::Select(detectorID, minDDLID, maxDDLID);
388 0 : fpParentReader->Select(detectorID, minDDLID, maxDDLID);
389 0 : fbHaveHLTData=EvaluateSelection();
390 0 : }
391 :
392 : // most likely we do not need this method since the base class directly forwards
393 : // to this method
394 : // void AliRawReaderHLT::Select(const char *detectorName, Int_t minDDLID, Int_t maxDDLID)
395 : // {
396 : // AliInfo(Form("detectorName=%s, minDDLID=%d, maxDDLID=%d", detectorName, minDDLID, maxDDLID));
397 : // AliRawReader::Select(detectorName, minDDLID, maxDDLID);
398 : // fpParentReader->Select(detectorName, minDDLID, maxDDLID);
399 : // }
400 :
401 : void AliRawReaderHLT::SelectEquipment(Int_t equipmentType, Int_t minEquipmentId, Int_t maxEquipmentId)
402 : {
403 : // see header file for class documentation
404 :
405 : //AliInfo(Form("equipmentType=%d, minEquipmentId=%d, maxEquipmentId=%d", equipmentType, minEquipmentId, maxEquipmentId));
406 0 : AliRawReader::SelectEquipment(equipmentType, minEquipmentId, maxEquipmentId);
407 0 : fpParentReader->SelectEquipment(equipmentType, minEquipmentId, maxEquipmentId);
408 0 : fbHaveHLTData=EvaluateSelection();
409 0 : }
410 :
411 : void AliRawReaderHLT::SkipInvalid(Bool_t skip)
412 : {
413 : // see header file for class documentation
414 :
415 0 : AliRawReader::SkipInvalid(skip);
416 0 : fpParentReader->SkipInvalid(skip);
417 0 : }
418 :
419 : /*
420 : void AliRawReaderHLT::SelectEvents(Int_t type)
421 : {
422 : // see header file for class documentation
423 :
424 : //AliInfo(Form("type=%d", type));
425 : AliRawReader::SelectEvents(type);
426 : fpParentReader->SelectEvents(type);
427 : }
428 : */
429 :
430 : int AliRawReaderHLT::ScanOptions(const char* options)
431 : {
432 : // see header file for class documentation
433 : int iResult=0;
434 0 : TString optString(options);
435 0 : TString argument;
436 0 : TString parameter;
437 0 : TString detectors;
438 0 : TObjArray* pTokens=optString.Tokenize(" ");
439 0 : if (pTokens) {
440 0 : int iEntries=pTokens->GetEntries();
441 0 : for (int i =0; i<iEntries; i++) {
442 0 : argument=((TObjString*)pTokens->At(i))->GetString();
443 : // first scan all the other options
444 : // no other options for the moment
445 :
446 : // it must be a detector name
447 0 : int detId=AliDAQ::DetectorID(argument.Data());
448 0 : if (detId>=0) {
449 0 : fDetectors.push_back(detId);
450 0 : if (!detectors.IsNull()) detectors+=" ";
451 0 : detectors+=argument;
452 : } else {
453 0 : if (!fSystemOptions.IsNull()) fSystemOptions+=" ";
454 0 : fSystemOptions+=argument;
455 : }
456 0 : }
457 0 : delete pTokens;
458 0 : }
459 :
460 0 : if (iResult>=0 && !detectors.IsNull()) {
461 0 : AliInfo(Form("running reconstruction from HLT data: %s", detectors.Data()));
462 : }
463 : return iResult;
464 0 : }
465 :
466 : Bool_t AliRawReaderHLT::ReadNextHLTData()
467 : {
468 : // see header file for class documentation
469 : bool result=kTRUE;
470 0 : if (fbReadFirst || !fpHLTOUT) {
471 0 : if (!fpHLTOUT) {
472 0 : fpHLTOUT=new AliHLTOUTRawReader(fpParentReader);
473 0 : if ((result=(fpHLTOUT!=NULL))) {
474 0 : if (!fpPluginBase) {
475 0 : AliFatal("internal data error: can not get AliHLTSystem instance from plugin");
476 0 : return false;
477 : }
478 0 : AliHLTSystem* pSystem=fpPluginBase->GetInstance();
479 0 : if (pSystem) {
480 0 : pSystem->ScanOptions(fSystemOptions.Data());
481 0 : }
482 0 : if ((result=(fpHLTOUT->Init())>=0)) {
483 : }
484 0 : }
485 : }
486 0 : if (result) {
487 0 : result=fpHLTOUT->SelectFirstDataBlock(kAliHLTAnyDataType, kAliHLTVoidDataSpec,
488 0 : AliHLTModuleAgent::kRawReader)>=0;
489 0 : }
490 0 : fbReadFirst=false;
491 0 : } else {
492 : // first release the data buffer
493 0 : ReleaseHLTData(false /* keep HLTOUT instance */);
494 0 : result=fpHLTOUT->SelectNextDataBlock()>=0;
495 : }
496 0 : if (result) {
497 0 : AliHLTComponentDataType dt=kAliHLTVoidDataType;
498 0 : AliHLTUInt32_t spec=kAliHLTVoidDataSpec;
499 0 : fpHLTOUT->GetDataBlockDescription(dt, spec);
500 0 : AliHLTUInt32_t size=0;
501 0 : AliHLTOUTHandler* pHandler=fpHLTOUT->GetHandler();
502 0 : if (pHandler) {
503 0 : if (dynamic_cast<AliHLTOUTHandlerEquId*>(pHandler)!=NULL) {
504 0 : AliHLTOUT::AliHLTOUTSelectionGuard g(fpHLTOUT);
505 0 : fEquipmentId=pHandler->ProcessData(fpHLTOUT);
506 0 : fpData=NULL;
507 0 : fDataSize=pHandler->GetProcessedData(fpData);
508 0 : if (!fpData) {
509 0 : result=fpHLTOUT->GetDataBuffer(fpData, size)>=0;
510 0 : fpDataHandler=NULL;
511 0 : AliDebug(AliLog::kDebug, Form("forward data block from HLTOUT stream to equipment %d", fEquipmentId));
512 0 : fDataSize=(int)size;
513 0 : } else {
514 : // remember the current handler in order to properly release the data buffer
515 0 : fpDataHandler=pHandler;
516 0 : AliDebug(AliLog::kDebug, Form("forward decoded data block provided by handler to equipment %d", fEquipmentId));
517 : }
518 : return kTRUE;
519 0 : } else {
520 0 : AliError(Form("handler is not of type AliHLTOUTHandlerEquId for block %x data type %s spec %#x; data block skipped",
521 : fpHLTOUT->GetDataBlockIndex(), AliHLTComponent::DataType2Text(dt).c_str(), spec));
522 : }
523 0 : } else {
524 0 : AliWarning(Form("no data handler found for block %x data type %s spec %#x; data block skipped",
525 : fpHLTOUT->GetDataBlockIndex(), AliHLTComponent::DataType2Text(dt).c_str(), spec));
526 : }
527 0 : } else {
528 0 : ReleaseHLTData(false /* keep HLTOUT instance */);
529 : }
530 0 : return kFALSE;
531 0 : }
532 :
533 : Bool_t AliRawReaderHLT::IsHLTInput(int ddlid)
534 : {
535 : // see header file for class documentation
536 0 : vector<int>::iterator detector=fDetectors.begin();
537 0 : for (; detector!=fDetectors.end(); detector++) {
538 0 : int ddlOffset=AliDAQ::DdlIDOffset(*detector);
539 0 : int nofDDLs=AliDAQ::NumberOfDdls(*detector);
540 0 : if (ddlid>=ddlOffset && ddlid<ddlOffset+nofDDLs)
541 0 : return kTRUE;
542 0 : }
543 0 : return kFALSE;
544 0 : }
545 :
546 : int AliRawReaderHLT::ReleaseHLTData(bool bReleaseHLTOUT)
547 : {
548 : // see header file for class documentation
549 0 : if (fpHLTOUT) {
550 0 : if (fpDataHandler) fpDataHandler->ReleaseProcessedData(fpData, fDataSize);
551 0 : else fpHLTOUT->ReleaseDataBuffer(fpData);
552 0 : fpDataHandler=NULL;
553 0 : if (bReleaseHLTOUT) {
554 0 : delete fpHLTOUT;
555 0 : fpHLTOUT=NULL;
556 0 : }
557 : }
558 :
559 0 : fpData=NULL;
560 0 : fDataSize=0;
561 0 : fOffset=0;
562 0 : fPosition=0;
563 0 : fEquipmentId=-1;
564 :
565 0 : return 0;
566 : }
567 :
568 : Bool_t AliRawReaderHLT::EvaluateSelection()
569 : {
570 : // see header file for class documentation
571 : Bool_t bHaveHLTData=kFALSE;
572 0 : if ((bHaveHLTData=(fDetectors.size())>0)) {
573 0 : vector<int>::iterator detector=fDetectors.begin();
574 0 : for (; detector!=fDetectors.end(); detector++) {
575 0 : int ddlOffset=AliDAQ::DdlIDOffset(*detector);
576 0 : int nofDDLs=AliDAQ::NumberOfDdls(*detector);
577 0 : if ((fSelectMinEquipmentId<0 || fSelectMinEquipmentId<ddlOffset+nofDDLs) &&
578 0 : (fSelectMaxEquipmentId<0 || fSelectMaxEquipmentId>=ddlOffset))
579 0 : break;
580 0 : }
581 0 : bHaveHLTData=detector!=fDetectors.end();
582 0 : }
583 0 : return bHaveHLTData;
584 : }
585 :
586 : AliRawReader* AliRawReaderHLTCreateInstance(AliRawReader* pParentReader, const char* options)
587 : {
588 : // see header file for class documentation
589 0 : if (!pParentReader) return NULL;
590 0 : return new AliRawReaderHLT(pParentReader, options);
591 0 : }
|