6332e351f08150a67b978c8874249ab2fd8d9634
[u/mrichter/AliRoot.git] / MUON / AliMUONRawStreamTrackerHP.cxx
1 /**************************************************************************
2  * This file is property of and copyright by the ALICE HLT Project        *
3  * All rights reserved.                                                   *
4  *                                                                        *
5  * Primary Authors:                                                       *
6  *   Artur Szostak <artursz@iafrica.com>                                  *
7  *                                                                        *
8  * Permission to use, copy, modify and distribute this software and its   *
9  * documentation strictly for non-commercial purposes is hereby granted   *
10  * without fee, provided that the above copyright notice appears in all   *
11  * copies and that both the copyright notice and this permission notice   *
12  * appear in the supporting documentation. The authors make no claims     *
13  * about the suitability of this software for any purpose. It is          *
14  * provided "as is" without express or implied warranty.                  *
15  **************************************************************************/
16
17 /* $Id$*/
18
19 ///
20 /// \file   AliMUONRawStreamTrackerHP.cxx
21 /// \author Artur Szostak <artursz@iafrica.com>
22 /// \date   29-11-2007
23 /// \brief  Implementation of the the high performance decoder AliMUONRawStreamTrackerHP.
24 ///
25
26 //-----------------------------------------------------------------------------
27 /// \ingroup raw
28 /// \class AliMUONRawStreamTrackerHP
29 /// \brief A high performance stream decoder for muon tracking DDL streams.
30 ///
31 /// This is the raw stream class which interfaces between the high performance
32 /// core decoder and the AliRawReader class.
33 /// To gain the most out of the decoder, the Next() method which returns batches
34 /// of decoded digit / channel information should be used. That is:
35 /// \code
36 ///   const AliBusPatch* Next();
37 /// \endcode
38 ///
39 /// This decoder tries to implement as similar an interface as possible to
40 /// AliMUONRawStreamTracker where possible. However certain constructs which
41 /// would slow us down too much are avoided.
42 ///
43 /// \author Artur Szostak <artursz@iafrica.com>
44 //-----------------------------------------------------------------------------
45
46 #include "AliMUONRawStreamTrackerHP.h"
47 #include "AliRawReader.h"
48 #include "AliLog.h"
49 #include <cassert>
50 #include <iostream>
51 #include <iomanip>
52 using std::cout;
53 using std::endl;
54 using std::hex;
55 using std::dec;
56
57 /// \cond CLASSIMP
58 ClassImp(AliMUONRawStreamTrackerHP)
59 /// \endcond
60
61
62 AliMUONRawStreamTrackerHP::AliMUONRawStreamTrackerHP() :
63         AliMUONVRawStreamTracker(),
64         fDecoder(),
65         fDDL(0),
66         fBufferSize(8192),
67         fBuffer(new UChar_t[8192]),
68         fCurrentBusPatch(NULL),
69         fCurrentData(NULL),
70         fEndOfData(NULL),
71         fHadError(kFALSE),
72         fDone(kFALSE)
73 {
74         ///
75         /// Default constructor.
76         ///
77         
78         // Must set this flag to get all information about parity errors though
79         // the OnData method. OnError gets them either way.
80         fDecoder.ExitOnError(false);
81         fDecoder.SendDataOnParityError(true);
82
83         fDecoder.GetHandler().SetMaxStructs(
84                         fDecoder.MaxBlocks(),
85                         fDecoder.MaxDSPs(),
86                         fDecoder.MaxBusPatches()
87                 );
88
89         fDecoder.GetHandler().SetRawStream(this);
90 }
91
92
93 AliMUONRawStreamTrackerHP::AliMUONRawStreamTrackerHP(AliRawReader* rawReader) :
94         AliMUONVRawStreamTracker(rawReader),
95         fDecoder(),
96         fDDL(0),
97         fBufferSize(8192),
98         fBuffer(new UChar_t[8192]),
99         fCurrentBusPatch(NULL),
100         fCurrentData(NULL),
101         fEndOfData(NULL),
102         fHadError(kFALSE),
103         fDone(kFALSE)
104 {
105         ///
106         /// Constructor with AliRawReader as argument.
107         ///
108         
109         // Must set this flag to get all information about parity errors though
110         // the OnData method. OnError gets them either way.
111         fDecoder.ExitOnError(false);
112         fDecoder.SendDataOnParityError(true);
113
114         fDecoder.GetHandler().SetMaxStructs(
115                         fDecoder.MaxBlocks(),
116                         fDecoder.MaxDSPs(),
117                         fDecoder.MaxBusPatches()
118                 );
119         
120         fDecoder.GetHandler().SetRawStream(this);
121 }
122
123
124 AliMUONRawStreamTrackerHP::~AliMUONRawStreamTrackerHP()
125 {
126         ///
127         /// Default destructor.
128         ///
129         
130         if (fBuffer != NULL)
131         {
132                 delete [] fBuffer;
133         }
134 }
135
136
137 void AliMUONRawStreamTrackerHP::First()
138 {
139         /// Initialise or reset the iterator.
140         /// The first DDL will be found and decoded.
141         
142         assert( GetReader() != NULL );
143         
144         fDDL = 0;
145         fDone = kFALSE;
146         NextDDL();
147 }
148
149
150 Bool_t AliMUONRawStreamTrackerHP::NextDDL()
151 {
152         /// Reading the next tracker DDL and decode the payload with the 
153         /// high performance decoder.
154         /// \return kTRUE if the next DDL was successfully read and kFALSE otherwise.
155
156         assert( GetReader() != NULL );
157         
158         while (fDDL < GetMaxDDL())
159         {
160                 GetReader()->Reset();
161                 GetReader()->Select("MUONTRK", fDDL, fDDL);  // Select the DDL file to be read.
162                 if (GetReader()->ReadHeader()) break;
163                 AliDebug(3, Form("Skipping DDL %d which does not seem to be there", fDDL+1));
164                 fDDL++;
165         }
166
167         // If we reach the end of the DDL list for this event then reset the
168         // DDL counter, mark the iteration as done and 
169         if (fDDL >= GetMaxDDL())
170         {
171                 fDDL = 0;
172                 fDone = kTRUE;
173                 return kFALSE;
174         }
175         else
176         {
177                 fDone = kFALSE;
178         }
179
180         AliDebug(3, Form("DDL Number %d\n", fDDL));
181         
182         Int_t dataSize = GetReader()->GetDataSize(); // in bytes
183         // Check if we have enough buffer space already in fBuffer. If we do then
184         // just continue reading otherwise we need to resize the buffer.
185         if (fBufferSize < dataSize)
186         {
187                 if (fBuffer != NULL)
188                 {
189                         delete [] fBuffer;
190                         fBuffer = NULL;
191                         fBufferSize = 0;
192                 }
193                 try
194                 {
195                         fBuffer = new UChar_t[dataSize];
196                         fBufferSize = dataSize;
197                 }
198                 catch (const std::bad_alloc&)
199                 {
200                         AliError("Could not allocate more buffer space. Cannot decode DDL.");
201                         return kFALSE;
202                 }
203         }
204         
205         if (not GetReader()->ReadNext(fBuffer, dataSize))
206         {
207                 return kFALSE;
208         }
209         
210 #ifndef R__BYTESWAP
211         Swap(reinterpret_cast<UInt_t*>(fBuffer), dataSize / sizeof(UInt_t)); // Swap needed for mac power pc.
212 #endif
213         
214         bool result = false;
215         try
216         {
217                 // Since we might allocate memory inside OnNewBuffer in the event
218                 // handler we need to trap any memory allocation exception to be robust.
219                 result = fDecoder.Decode(fBuffer, dataSize);
220                 fHadError = (result == true ? kFALSE : kTRUE);
221         }
222         catch (const std::bad_alloc&)
223         {
224                 AliError("Could not allocate more buffer space. Cannot decode DDL.");
225                 return kFALSE;
226         }
227
228         // Update the current bus patch pointers.
229         fCurrentBusPatch = fDecoder.GetHandler().FirstBusPatch();
230         if (fCurrentBusPatch != fDecoder.GetHandler().EndOfBusPatch())
231         {
232                 fCurrentData = fCurrentBusPatch->GetData();
233                 fEndOfData = fCurrentData + fCurrentBusPatch->GetDataCount();
234         }
235         else
236         {
237                 // If the DDL did not have any bus patches then mark both fCurrentData
238                 // and fEndOfData as NULL so that in Next() we are forced to find the
239                 // first non empty DDL.
240                 fCurrentData = fEndOfData = NULL;
241         }
242
243         fDDL++; // Remember to increment index to next DDL.
244         return kTRUE;
245 }
246
247
248 Bool_t AliMUONRawStreamTrackerHP::IsDone() const
249 {
250         /// Indicates whether the iteration is finished or not.
251         /// \return kTRUE if we already read all the digits and kFALSE if not.
252         
253         return fDone;
254 }
255
256
257 Bool_t AliMUONRawStreamTrackerHP::Next(
258                 Int_t& busPatchId, UShort_t& manuId, UChar_t& manuChannel,
259                 UShort_t& adc
260         )
261 {
262         /// Advance one step in the iteration. Returns false if finished.
263         /// [out] \param busPatchId  This is filled with the bus patch ID of the digit.
264         /// [out] \param manuId      This is filled with the MANU ID of the digit.
265         /// [out] \param manuChannel This is filled with the MANU channel ID of the digit.
266         /// [out] \param adc         This is filled with the ADC signal value of the digit.
267         /// \return kTRUE if we read another digit and kFALSE if we have read all the
268         ///    digits already, i.e. at the end of the iteration.
269         
270 retry:
271         // Check if we still have data to be returned for the current bus patch.
272         if (fCurrentData != fEndOfData)
273         {
274                 busPatchId = fCurrentBusPatch->GetBusPatchId();
275                 AliMUONTrackerDDLDecoderEventHandler::UnpackADC(*fCurrentData, manuId, manuChannel, adc);
276                 fCurrentData++;
277                 return kTRUE;
278         }
279         else
280         {
281                 // We hit the end of the current bus patch so check if we have any more
282                 // bus patches to process for the current DDL. If we do, then increment
283                 // the current bus patch, make sure it is not the last one and then try
284                 // reading the first element again.
285                 if (fCurrentBusPatch != fDecoder.GetHandler().EndOfBusPatch())
286                 {
287                         fCurrentBusPatch++;
288                         if (fCurrentBusPatch != fDecoder.GetHandler().EndOfBusPatch())
289                         {
290                                 fCurrentData = fCurrentBusPatch->GetData();
291                                 fEndOfData = fCurrentData + fCurrentBusPatch->GetDataCount();
292                                 goto retry;
293                         }
294                 }
295
296                 // This was the last bus patch in the DDL so read in the next one and
297                 // try reading the first data element again.
298                 // Note: fCurrentBusPatch is set inside NextDDL().
299                 if (NextDDL()) goto retry;
300         }
301         return kFALSE;
302 }
303
304
305 void AliMUONRawStreamTrackerHP::SetMaxBlock(Int_t blk)
306 {
307         /// Set maximum number of blocks per DDL allowed.
308         fDecoder.MaxBlocks( (UInt_t) blk );
309         
310         fDecoder.GetHandler().SetMaxStructs(
311                         fDecoder.MaxBlocks(),
312                         fDecoder.MaxDSPs(),
313                         fDecoder.MaxBusPatches()
314                 );
315 }
316
317
318 void AliMUONRawStreamTrackerHP::SetMaxDsp(Int_t dsp)
319 {
320         /// Set maximum number of Dsp per block allowed.
321         fDecoder.MaxDSPs( (UInt_t) dsp );
322         
323         fDecoder.GetHandler().SetMaxStructs(
324                         fDecoder.MaxBlocks(),
325                         fDecoder.MaxDSPs(),
326                         fDecoder.MaxBusPatches()
327                 );
328 }
329
330
331 void AliMUONRawStreamTrackerHP::SetMaxBus(Int_t bus)
332 {
333         /// Set maximum number of Buspatch per Dsp allowed.
334         fDecoder.MaxBusPatches( (UInt_t) bus );
335         
336         fDecoder.GetHandler().SetMaxStructs(
337                         fDecoder.MaxBlocks(),
338                         fDecoder.MaxDSPs(),
339                         fDecoder.MaxBusPatches()
340                 );
341 }
342
343 ///////////////////////////////////////////////////////////////////////////////
344
345 void AliMUONRawStreamTrackerHP::AliBlockHeader::Print() const
346 {
347         /// Print header to screen.
348         
349         cout << "CRT info"        << endl;
350         if (fHeader == NULL)
351         {
352                 cout << "Header is NULL" << endl;
353                 return;
354         }
355         cout << "DataKey: 0x"     << hex << fHeader->fDataKey << dec << endl;
356         cout << "TotalLength: "   << fHeader->fTotalLength << endl;
357         cout << "Length: "        << fHeader->fLength << endl;
358         cout << "DspId: "         << fHeader->fDSPId << endl;
359         cout << "L0Trigger: "     << fHeader->fL0Trigger << endl;
360         cout << "MiniEventId: "   << fHeader->fMiniEventId<< endl; 
361         cout << "EventId1: "      << fHeader->fEventId1 << endl;
362         cout << "EventId2: "      << fHeader->fEventId2 << endl;
363 }
364
365
366 void AliMUONRawStreamTrackerHP::AliDspHeader::Print() const
367 {
368         /// Print header to screen.
369         
370         cout << "FRT info"        << endl;
371         if (fHeader == NULL)
372         {
373                 cout << "Header is NULL" << endl;
374                 return;
375         }
376         cout << "DataKey: 0x"     << hex << fHeader->fDataKey << dec << endl;
377         cout << "TotalLength: "   << fHeader->fTotalLength << endl;
378         cout << "Length : "       << fHeader->fLength << endl;
379         cout << "DspId: "         << fHeader->fDSPId << endl;
380         cout << "BlkL1ATrigger: " << fHeader->fBlkL1ATrigger << endl;
381         cout << "MiniEventId: "   << fHeader->fMiniEventId << endl;
382         cout << "L1ATrigger: "    << fHeader->fL1ATrigger << endl;
383         cout << "L1RTrigger: "    << fHeader->fL1RTrigger << endl;
384         cout << "PaddingWord: "   << fHeader->fPaddingWord << endl;
385         cout << "ErrorWord: "     << fHeader->fErrorWord << endl;
386 }
387
388
389 void AliMUONRawStreamTrackerHP::AliBusPatch::Print(const Option_t* opt) const
390 {
391         /// Print header to screen.
392         cout << "Bus patch info" << endl;
393         if (fHeader == NULL)
394         {
395                 cout << "Header is NULL" << endl;
396                 return;
397         }
398         cout << "DataKey: 0x"    << hex << fHeader->fDataKey << dec << endl;
399         cout << "fTotalLength: " << fHeader->fTotalLength << endl;
400         cout << "fLength: "      << fHeader->fLength << endl;
401         cout << "fBusPatchId: "  << fHeader->fBusPatchId << endl;
402
403         if (TString(opt).Contains("all"))
404         {
405                 for (UInt_t i = 0; i < fHeader->fLength; ++i)
406                         cout << "Data["<< i << "] = " << fData[i] << endl;
407         }
408 }
409
410 ///////////////////////////////////////////////////////////////////////////////
411
412 AliMUONRawStreamTrackerHP::AliDecoderEventHandler::AliDecoderEventHandler() :
413         fRawStream(NULL),
414         fBufferStart(NULL),
415         fBlockCount(0),
416         fBlocks(NULL),
417         fDSPs(NULL),
418         fBusPatches(NULL),
419         fEndOfBusPatches(NULL),
420         fMaxChannels(8192),
421         fParityOk(new Bool_t[8192]),
422         fCurrentBlock(NULL),
423         fCurrentDSP(NULL),
424         fCurrentBusPatch(NULL),
425         fCurrentParityOkFlag(NULL),
426         fParityErrors(0),
427         fGlitchErrors(0),
428         fPaddingErrors(0),
429         fWarnings(kTRUE)
430 {
431         /// Default constructor initialises the internal parity flags buffer to
432         /// store 8192 elements. This array will grow dynamically if needed.
433 }
434
435
436 AliMUONRawStreamTrackerHP::AliDecoderEventHandler::~AliDecoderEventHandler()
437 {
438         /// Default destructor cleans up the allocated memory.
439         
440         if (fParityOk != NULL) delete [] fParityOk;
441         if (fBlocks != NULL) delete [] fBlocks;
442         if (fDSPs != NULL) delete [] fDSPs;
443         if (fBusPatches != NULL) delete [] fBusPatches;
444 }
445
446
447 void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::SetMaxStructs(
448                 UInt_t maxBlocks, UInt_t maxDsps, UInt_t maxBusPatches
449         )
450 {
451         /// Sets the maximum number of structures allowed.
452         
453         // Start by clearing the current arrays.
454         if (fBlocks != NULL)
455         {
456                 delete [] fBlocks;
457                 fBlocks = NULL;
458         }
459         if (fDSPs != NULL)
460         {
461                 delete [] fDSPs;
462                 fDSPs = NULL;
463         }
464         if (fBusPatches != NULL)
465         {
466                 delete [] fBusPatches;
467                 fBusPatches = NULL;
468         }
469         fCurrentBlock = NULL;
470         fCurrentDSP = NULL;
471         fCurrentBusPatch = NULL;
472         
473         // Allocate new memory.
474         fBlocks = new AliBlockHeader[maxBlocks];
475         fDSPs = new AliDspHeader[maxBlocks*maxDsps];
476         fBusPatches = new AliBusPatch[maxBlocks*maxDsps*maxBusPatches];
477         fEndOfBusPatches = fEndOfBusPatches;
478 }
479
480
481 void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::OnNewBuffer(
482                 const void* buffer, UInt_t bufferSize
483         )
484 {
485         /// This is called by the high performance decoder when a new DDL payload
486         /// is about to be decoded.
487         /// \param buffer  The pointer to the buffer storing the DDL payload.
488         /// \param bufferSize  The size of the buffer in bytes.
489
490         assert( fRawStream != NULL );
491         
492         // remember the start of the buffer to be used in OnError.
493         fBufferStart = buffer;
494
495         // Reset error counters.
496         fParityErrors = 0;
497         fGlitchErrors = 0;
498         fPaddingErrors = 0;
499
500         // Check if we will have enough space in the fParityOk array.
501         // If we do not then we need to resize the array.
502         // bufferSize / sizeof(UInt_t) will be a safe over estimate of the
503         // number of channels that we will find.
504         UInt_t maxChannelsPossible = bufferSize / sizeof(UInt_t);
505         if (maxChannelsPossible > fMaxChannels)
506         {
507                 if (fParityOk != NULL)
508                 {
509                         delete [] fParityOk;
510                         fParityOk = NULL;
511                         fMaxChannels = 0;
512                 }
513                 fParityOk = new Bool_t[maxChannelsPossible];
514                 fMaxChannels = maxChannelsPossible;
515         }
516         
517         // Reset the current pointers which will be used to track where we need to
518         // fill fBlocks, fDSPs, fBusPatches and the parity flag. We have to subtract
519         // one space because we will increment the pointer the first time in the
520         // OnNewXZY methods.
521         fCurrentBlock = fBlocks-1;
522         fCurrentDSP = fDSPs-1;
523         fCurrentBusPatch = fBusPatches-1;
524         fCurrentParityOkFlag = fParityOk-1;
525         fBlockCount = 0;
526 }
527
528
529 void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::OnError(
530                 ErrorCode error, const void* location
531         )
532 {
533         /// This is called by the high performance decoder when a error occurs
534         /// when trying to decode the DDL payload. This indicates corruption in
535         /// the data. This method converts the error code to a descriptive message
536         /// and log this with the raw reader.
537         /// \param error  The error code indicating the problem.
538         /// \param location  A pointer to the location within the DDL payload buffer
539         ///              being decoded where the problem with the data was found.
540
541         assert( fRawStream != NULL );
542         assert( fRawStream->GetReader() != NULL );
543         
544         Char_t* message = NULL;
545         UInt_t word = 0;
546
547         switch (error)
548         {
549         case kGlitchFound:
550                 message = Form(
551                         "Glitch error detected in DSP %d, skipping event ",
552                         fCurrentBlock->GetDspId()
553                 );
554                 fRawStream->GetReader()->AddMajorErrorLog(error, message);
555                 break;
556
557         case kBadPaddingWord:
558                 // We subtract 1 from the current numbers of blocks, DSPs
559                 // and bus patches to get the indices.
560                 message = Form(
561                         "Padding word error for iBlock %d, iDsp %d, iBus %d\n", 
562                         fBlockCount-1,
563                         fCurrentBlock->GetDspCount()-1,
564                         fCurrentDSP->GetBusPatchCount()-1
565                 );
566                 fRawStream->GetReader()->AddMinorErrorLog(error, message);
567                 break;
568
569         case kParityError:
570                 // location points to the incorrect data word and
571                 // fCurrentBusPatch->GetData() returns a pointer to the start of
572                 // bus patches data, so the difference divided by 4 gives the 32
573                 // bit word number.
574                 word = ((unsigned long)location - (unsigned long)fCurrentBusPatch->GetData())
575                                 / sizeof(UInt_t);
576                 message = Form(
577                         "Parity error in word %d for manuId %d and channel %d in buspatch %d\n", 
578                         word,
579                         fCurrentBusPatch->GetManuId(word),
580                         fCurrentBusPatch->GetChannelId(word),
581                         fCurrentBusPatch->GetBusPatchId()
582                 );
583                 fRawStream->GetReader()->AddMinorErrorLog(error, message);
584                 break;
585
586         default:
587                 message = Form(
588                         "%s (At byte %d in DDL.)",
589                         ErrorCodeToMessage(error),
590                         (unsigned long)location - (unsigned long)fBufferStart + sizeof(AliRawDataHeader)
591                 );
592                 fRawStream->GetReader()->AddMajorErrorLog(error, message);
593                 break;
594         }
595
596         if (fWarnings)
597         {
598                 AliWarningGeneral(
599                                 "AliMUONRawStreamTrackerHP::AliDecoderEventHandler",
600                                 message
601                         );
602         }
603 }
604