Previous commit had the bad side-effect of changing the behaviour of Raw QA to comput...
[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 "AliMUONTrackerDDLDecoder.h"
48 #include "AliMUONDspHeader.h"
49 #include "AliMUONBlockHeader.h"
50 #include "AliMUONBusStruct.h"
51 #include "AliMUONDDLTracker.h"
52 #include "AliRawReader.h"
53 #include "AliLog.h"
54 #include <cassert>
55 #include <iostream>
56 using std::cout;
57 using std::endl;
58 using std::hex;
59 using std::dec;
60
61 /// \cond CLASSIMP
62 ClassImp(AliMUONRawStreamTrackerHP)
63 /// \endcond
64
65 const Int_t AliMUONRawStreamTrackerHP::fgkMaxDDL = 20;
66
67 AliMUONRawStreamTrackerHP::AliMUONRawStreamTrackerHP() :
68         TObject(),
69 fEnableErrorLogger(kFALSE),
70         fDecoder(),
71         fDDL(0),
72         fBufferSize(8192),
73         fBuffer(new UChar_t[8192]),
74         fkCurrentBusPatch(NULL),
75         fkCurrentData(NULL),
76         fkEndOfData(NULL),
77         fHadError(kFALSE),
78         fDone(kFALSE),
79         fDDLObject(NULL),
80 fTotalNumberOfGlitchErrors(0),
81 fTotalNumberOfParityErrors(0),
82 fTotalNumberOfPaddingErrors(0)
83 {
84         ///
85         /// Default constructor.
86         ///
87         
88         // Must set this flag to get all information about parity errors though
89         // the OnData method. OnError gets them either way.
90         fDecoder.ExitOnError(false);
91         fDecoder.SendDataOnParityError(true);
92
93         fDecoder.GetHandler().SetMaxStructs(
94                         fDecoder.MaxBlocks(),
95                         fDecoder.MaxDSPs(),
96                         fDecoder.MaxBusPatches()
97                 );
98 }
99
100
101 AliMUONRawStreamTrackerHP::AliMUONRawStreamTrackerHP(AliRawReader* rawReader) :
102 TObject(),
103 fEnableErrorLogger(kFALSE),
104         fDecoder(),
105         fDDL(0),
106         fBufferSize(8192),
107         fBuffer(new UChar_t[8192]),
108         fkCurrentBusPatch(NULL),
109         fkCurrentData(NULL),
110         fkEndOfData(NULL),
111         fHadError(kFALSE),
112         fDone(kFALSE),
113 fDDLObject(NULL),
114 fTotalNumberOfGlitchErrors(0),
115 fTotalNumberOfParityErrors(0),
116 fTotalNumberOfPaddingErrors(0)
117 {
118         ///
119         /// Constructor with AliRawReader as argument.
120         ///
121         
122         // Must set this flag to get all information about parity errors though
123         // the OnData method. OnError gets them either way.
124         fDecoder.ExitOnError(false);
125         fDecoder.SendDataOnParityError(true);
126
127         fDecoder.GetHandler().SetMaxStructs(
128                         fDecoder.MaxBlocks(),
129                         fDecoder.MaxDSPs(),
130                         fDecoder.MaxBusPatches()
131                 );
132   
133   fDecoder.GetHandler().SetReader(rawReader);
134 }
135
136
137 AliMUONRawStreamTrackerHP::~AliMUONRawStreamTrackerHP()
138 {
139         ///
140         /// Default destructor.
141         ///
142         
143         if (fBuffer != NULL)
144         {
145                 delete [] fBuffer;
146         }
147         if (fDDLObject != NULL)
148         {
149                 delete fDDLObject;
150         }
151 }
152
153
154 void AliMUONRawStreamTrackerHP::First()
155 {
156         /// Initialise or reset the iterator.
157         /// The first DDL will be found and decoded.
158         
159         assert( GetReader() != NULL );
160         
161         fDDL = 0;
162         fDone = kFALSE;
163         NextDDL();
164   fTotalNumberOfGlitchErrors = 0;
165   fTotalNumberOfPaddingErrors = 0;
166   fTotalNumberOfParityErrors = 0;
167 }
168
169
170 Bool_t AliMUONRawStreamTrackerHP::NextDDL()
171 {
172         /// Reading the next tracker DDL and decode the payload with the 
173         /// high performance decoder.
174         /// \return kTRUE if the next DDL was successfully read and kFALSE otherwise.
175
176         assert( GetReader() != NULL );
177         
178         // The temporary object if generated in GetDDLTracker, is now stale,
179         // so delete it.
180         if (fDDLObject != NULL)
181         {
182                 delete fDDLObject;
183                 fDDLObject = NULL;
184         }
185         
186         // Better to reset these pointers.
187         fkCurrentBusPatch = NULL;
188         fkCurrentData = NULL;
189         fkEndOfData = NULL;
190         
191         while (fDDL < GetMaxDDL())
192         {
193                 GetReader()->Reset();
194                 GetReader()->Select("MUONTRK", fDDL, fDDL);  // Select the DDL file to be read.
195                 if (GetReader()->ReadHeader()) break;
196                 AliDebug(3, Form("Skipping DDL %d which does not seem to be there", fDDL+1));
197                 fDDL++;
198         }
199
200         // If we reach the end of the DDL list for this event then reset the
201         // DDL counter, mark the iteration as done and exit.
202         if (fDDL >= GetMaxDDL())
203         {
204                 fDDL = 0;
205                 fDone = kTRUE;
206                 return kFALSE;
207         }
208         else
209         {
210                 fDone = kFALSE;
211         }
212
213         AliDebug(3, Form("DDL Number %d\n", fDDL));
214         
215         Int_t dataSize = GetReader()->GetDataSize(); // in bytes
216         // Check if we have enough buffer space already in fBuffer. If we do then
217         // just continue reading otherwise we need to resize the buffer.
218         if (fBufferSize < dataSize)
219         {
220                 if (fBuffer != NULL)
221                 {
222                         delete [] fBuffer;
223                         fBuffer = NULL;
224                         fBufferSize = 0;
225                 }
226                 try
227                 {
228                         fBuffer = new UChar_t[dataSize];
229                         fBufferSize = dataSize;
230                 }
231                 catch (const std::bad_alloc&)
232                 {
233                         AliError("Could not allocate more buffer space. Cannot decode DDL.");
234                         return kFALSE;
235                 }
236         }
237         
238         if (not GetReader()->ReadNext(fBuffer, dataSize))
239         {
240                 return kFALSE;
241         }
242         
243 #ifndef R__BYTESWAP
244         Swap(reinterpret_cast<UInt_t*>(fBuffer), dataSize / sizeof(UInt_t)); // Swap needed for mac power pc.
245 #endif
246         
247         bool result = false;
248         try
249         {
250                 // Since we might allocate memory inside OnNewBuffer in the event
251                 // handler we need to trap any memory allocation exception to be robust.
252                 result = fDecoder.Decode(fBuffer, dataSize);
253                 fHadError = (result == true ? kFALSE : kTRUE);
254     fTotalNumberOfGlitchErrors += fDecoder.GetHandler().GlitchErrorCount();
255     fTotalNumberOfParityErrors += fDecoder.GetHandler().ParityErrorCount();
256                 fTotalNumberOfPaddingErrors += fDecoder.GetHandler().PaddingErrorCount();
257         }
258         catch (const std::bad_alloc&)
259         {
260                 AliError("Could not allocate more buffer space. Cannot decode DDL.");
261                 return kFALSE;
262         }
263
264         // Update the current bus patch pointers.
265         fkCurrentBusPatch = fDecoder.GetHandler().FirstBusPatch();
266         if (fkCurrentBusPatch != fDecoder.GetHandler().EndOfBusPatch())
267         {
268                 fkCurrentData = fkCurrentBusPatch->GetData();
269                 fkEndOfData = fkCurrentData + fkCurrentBusPatch->GetDataCount();
270         }
271         else
272         {
273                 // If the DDL did not have any bus patches then mark both fCurrentData
274                 // and fEndOfData as NULL so that in Next() we are forced to find the
275                 // first non empty DDL.
276                 fkCurrentData = fkEndOfData = NULL;
277         }
278
279         fDDL++; // Remember to increment index to next DDL.
280         return kTRUE;
281 }
282
283
284 Bool_t AliMUONRawStreamTrackerHP::IsDone() const
285 {
286         /// Indicates whether the iteration is finished or not.
287         /// \return kTRUE if we already read all the digits and kFALSE if not.
288         
289         return fDone;
290 }
291
292
293 Bool_t AliMUONRawStreamTrackerHP::Next(Int_t& busPatchId, 
294                                        UShort_t& manuId, 
295                                        UChar_t& manuChannel,
296                                        UShort_t& adc, 
297                                        Bool_t skipParityErrors)
298 {
299         /// Advance one step in the iteration. Returns false if finished.
300         /// [out] \param busPatchId  This is filled with the bus patch ID of the digit.
301         /// [out] \param manuId      This is filled with the MANU ID of the digit.
302         /// [out] \param manuChannel This is filled with the MANU channel ID of the digit.
303         /// [out] \param adc         This is filled with the ADC signal value of the digit.
304   /// [in] \param skipParityErrors If this is kTRUE, we'll skip the buspatches that
305   ///                              have some parity errors
306         /// \return kTRUE if we read another digit and kFALSE if we have read all the
307         ///    digits already, i.e. at the end of the iteration.
308         
309         if (fkCurrentData == NULL) return kFALSE;
310         
311 retry:
312         // Check if we still have data to be returned for the current bus patch.
313         if (fkCurrentData != fkEndOfData)
314         {
315                 busPatchId = fkCurrentBusPatch->GetBusPatchId();
316                 AliMUONTrackerDDLDecoderEventHandler::UnpackADC(*fkCurrentData, manuId, manuChannel, adc);
317                 fkCurrentData++;
318                 return kTRUE;
319         }
320         else
321         {
322                 // We hit the end of the current bus patch so check if we have any more
323                 // bus patches to process for the current DDL. If we do, then increment
324                 // the current bus patch, make sure it is not the last one and then try
325                 // reading the first element again.
326                 if (fkCurrentBusPatch != fDecoder.GetHandler().EndOfBusPatch())
327                 {
328                         fkCurrentBusPatch++;
329                         if (fkCurrentBusPatch != fDecoder.GetHandler().EndOfBusPatch())
330                         {
331                                 fkCurrentData = fkCurrentBusPatch->GetData();
332                                 fkEndOfData = fkCurrentData + fkCurrentBusPatch->GetDataCount();
333         if ( skipParityErrors ) 
334         {
335           Bool_t ok(kTRUE);
336           for ( Int_t i = 0; i < fkCurrentBusPatch->GetLength() && ok; ++ i )
337           {
338             ok = fkCurrentBusPatch->IsParityOk(i);
339           }
340           if (!ok) fkCurrentData = fkEndOfData;
341         }
342                                 goto retry;
343                         }
344                 }
345
346                 // This was the last bus patch in the DDL so read in the next one and
347                 // try reading the first data element again.
348                 // Note: fCurrentBusPatch is set inside NextDDL().
349                 if (NextDDL()) goto retry;
350         }
351         return kFALSE;
352 }
353
354
355 AliMUONDDLTracker* AliMUONRawStreamTrackerHP::GetDDLTracker() const
356 {
357         /// Construct and return a pointer to the DDL payload object.
358         /// \return Pointer to internally constructed AliMUONDDLTracker object.
359         ///         The object is owned by this class and should not be deleted
360         ///         by the caller.
361         ///
362         /// \note This method should not be used just to gain access to the DDL
363         /// payload, unless there is a good reason to have the AliMUONDDLTracker
364         /// object. For example, if you want to modify the data and then save it
365         /// to another DDL stream. Otherwise it can be an order of magnitude
366         /// faster to access the DDL headers and data with the GetBlockHeader,
367         /// GetDspHeader and GetBusPatch methods for example.
368         /// Refer to the MUONRawStreamTracker.C macro to see how to use the fast
369         /// decoder interface optimally.
370         
371         if (fDDLObject != NULL) return fDDLObject;
372         
373         fDDLObject = new AliMUONDDLTracker;
374         for (Int_t iBlock = 0; iBlock < (Int_t)GetBlockCount(); iBlock++)
375         {
376                 AliMUONBlockHeader blockHeader;
377                 AliMUONDspHeader dspHeader;
378                 AliMUONBusStruct busPatch;
379                 
380                 const AliBlockHeader* bh = GetBlockHeader(iBlock);
381                 // Copy block header and add it to the DDL object.
382                 memcpy(blockHeader.GetHeader(), bh->GetHeader(), sizeof(AliMUONBlockHeaderStruct));
383                 fDDLObject->AddBlkHeader(blockHeader);
384                 
385                 for (Int_t iDsp = 0; iDsp < (Int_t)bh->GetDspCount(); iDsp++)
386                 {
387                         const AliDspHeader* dh = bh->GetDspHeader(iDsp);
388                         // Copy DSP header and add it to the DDL object.
389                         memcpy(dspHeader.GetHeader(), dh->GetHeader(), sizeof(AliMUONDSPHeaderStruct));
390                         fDDLObject->AddDspHeader(dspHeader, iBlock);
391                         
392                         const AliBusPatch* bp = dh->GetFirstBusPatch();
393                         while (bp != NULL)
394                         {
395                                 // Copy bus patch header, data and add everything into DDL object.
396                                 memcpy(busPatch.GetHeader(), bp->GetHeader(), sizeof(AliMUONBusPatchHeaderStruct));
397                                 busPatch.SetAlloc(bp->GetLength());
398                                 memcpy(busPatch.GetData(), bp->GetData(), bp->GetDataCount()*sizeof(UInt_t));
399                                 busPatch.SetBlockId(iBlock);
400                                 busPatch.SetDspId(iDsp);
401                                 fDDLObject->AddBusPatch(busPatch, iBlock, iDsp);
402                                 bp = bp->Next();
403                         }
404                 }
405         }
406         
407         return fDDLObject;
408 }
409
410
411 void AliMUONRawStreamTrackerHP::SetMaxBlock(Int_t blk)
412 {
413         /// Set maximum number of blocks per DDL allowed.
414         fDecoder.MaxBlocks( (UInt_t) blk );
415         
416         fDecoder.GetHandler().SetMaxStructs(
417                         fDecoder.MaxBlocks(),
418                         fDecoder.MaxDSPs(),
419                         fDecoder.MaxBusPatches()
420                 );
421 }
422
423
424 void AliMUONRawStreamTrackerHP::SetMaxDsp(Int_t dsp)
425 {
426         /// Set maximum number of Dsp per block allowed.
427         fDecoder.MaxDSPs( (UInt_t) dsp );
428         
429         fDecoder.GetHandler().SetMaxStructs(
430                         fDecoder.MaxBlocks(),
431                         fDecoder.MaxDSPs(),
432                         fDecoder.MaxBusPatches()
433                 );
434 }
435
436
437 void AliMUONRawStreamTrackerHP::SetMaxBus(Int_t bus)
438 {
439         /// Set maximum number of Buspatch per Dsp allowed.
440         fDecoder.MaxBusPatches( (UInt_t) bus );
441         
442         fDecoder.GetHandler().SetMaxStructs(
443                         fDecoder.MaxBlocks(),
444                         fDecoder.MaxDSPs(),
445                         fDecoder.MaxBusPatches()
446                 );
447 }
448
449 AliRawReader* AliMUONRawStreamTrackerHP::GetReader()
450 {
451   return fDecoder.GetHandler().GetReader();
452 }
453
454 void AliMUONRawStreamTrackerHP::SetReader(AliRawReader* reader)
455 {
456   fDecoder.GetHandler().SetReader(reader);
457 }
458
459 ///////////////////////////////////////////////////////////////////////////////
460
461 void AliMUONRawStreamTrackerHP::AliBlockHeader::Print() const
462 {
463         /// Print header to screen.
464         
465         cout << "CRT info"        << endl;
466         if (fHeader == NULL)
467         {
468                 cout << "Header is NULL" << endl;
469                 return;
470         }
471         cout << "DataKey: 0x"     << hex << fHeader->fDataKey << dec << endl;
472         cout << "TotalLength: "   << fHeader->fTotalLength << endl;
473         cout << "Length: "        << fHeader->fLength << endl;
474         cout << "DspId: "         << fHeader->fDSPId << endl;
475         cout << "L0Trigger: "     << fHeader->fL0Trigger << endl;
476         cout << "MiniEventId: "   << fHeader->fMiniEventId<< endl; 
477         cout << "EventId1: "      << fHeader->fEventId1 << endl;
478         cout << "EventId2: "      << fHeader->fEventId2 << endl;
479 }
480
481
482 void AliMUONRawStreamTrackerHP::AliDspHeader::Print() const
483 {
484         /// Print header to screen.
485         
486         cout << "FRT info"        << endl;
487         if (fHeader == NULL)
488         {
489                 cout << "Header is NULL" << endl;
490                 return;
491         }
492         cout << "DataKey: 0x"     << hex << fHeader->fDataKey << dec << endl;
493         cout << "TotalLength: "   << fHeader->fTotalLength << endl;
494         cout << "Length : "       << fHeader->fLength << endl;
495         cout << "DspId: "         << fHeader->fDSPId << endl;
496         cout << "BlkL1ATrigger: " << fHeader->fBlkL1ATrigger << endl;
497         cout << "MiniEventId: "   << fHeader->fMiniEventId << endl;
498         cout << "L1ATrigger: "    << fHeader->fL1ATrigger << endl;
499         cout << "L1RTrigger: "    << fHeader->fL1RTrigger << endl;
500         cout << "PaddingWord: "   << fHeader->fPaddingWord << endl;
501         cout << "ErrorWord: "     << fHeader->fErrorWord << endl;
502 }
503
504
505 void AliMUONRawStreamTrackerHP::AliBusPatch::Print(const Option_t* opt) const
506 {
507         /// Print header to screen.
508         cout << "Bus patch info" << endl;
509         if (fHeader == NULL)
510         {
511                 cout << "Header is NULL" << endl;
512                 return;
513         }
514         cout << "DataKey: 0x"    << hex << fHeader->fDataKey << dec << endl;
515         cout << "fTotalLength: " << fHeader->fTotalLength << endl;
516         cout << "fLength: "      << fHeader->fLength << endl;
517         cout << "fBusPatchId: "  << fHeader->fBusPatchId << endl;
518
519         if (TString(opt).Contains("all"))
520         {
521                 for (UInt_t i = 0; i < fHeader->fLength; ++i)
522                         cout << "Data["<< i << "] = " << fData[i] << endl;
523         }
524 }
525
526 ///////////////////////////////////////////////////////////////////////////////
527
528 AliMUONRawStreamTrackerHP::AliDecoderEventHandler::AliDecoderEventHandler() :
529 fRawReader(0x0),
530         fBufferStart(NULL),
531         fBlockCount(0),
532         fBlocks(NULL),
533         fDSPs(NULL),
534         fBusPatches(NULL),
535         fEndOfBusPatches(NULL),
536         fMaxChannels(8192),
537         fParityOk(new Bool_t[8192]),
538         fCurrentBlock(NULL),
539         fCurrentDSP(NULL),
540         fCurrentBusPatch(NULL),
541         fCurrentParityOkFlag(NULL),
542         fParityErrors(0),
543         fGlitchErrors(0),
544         fPaddingErrors(0),
545         fWarnings(kTRUE),
546   fMaxBlocks(),
547   fMaxDsps(),
548   fMaxBusPatches()
549 {
550         /// Default constructor initialises the internal parity flags buffer to
551         /// store 8192 elements. This array will grow dynamically if needed.
552 }
553
554
555 AliMUONRawStreamTrackerHP::AliDecoderEventHandler::~AliDecoderEventHandler()
556 {
557         /// Default destructor cleans up the allocated memory.
558         
559         if (fParityOk != NULL) delete [] fParityOk;
560         if (fBlocks != NULL) delete [] fBlocks;
561         if (fDSPs != NULL) delete [] fDSPs;
562         if (fBusPatches != NULL) delete [] fBusPatches;
563 }
564
565
566 void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::SetMaxStructs(
567                 UInt_t maxBlocks, UInt_t maxDsps, UInt_t maxBusPatches
568         )
569 {
570         /// Sets the maximum number of structures allowed.
571         
572         // Start by clearing the current arrays.
573         if (fBlocks != NULL)
574         {
575                 delete [] fBlocks;
576                 fBlocks = NULL;
577         }
578         if (fDSPs != NULL)
579         {
580                 delete [] fDSPs;
581                 fDSPs = NULL;
582         }
583         if (fBusPatches != NULL)
584         {
585                 delete [] fBusPatches;
586                 fBusPatches = NULL;
587         }
588         fCurrentBlock = NULL;
589         fCurrentDSP = NULL;
590         fCurrentBusPatch = NULL;
591         
592         // Allocate new memory.
593         fBlocks = new AliBlockHeader[maxBlocks];
594         fDSPs = new AliDspHeader[maxBlocks*maxDsps];
595         fBusPatches = new AliBusPatch[maxBlocks*maxDsps*maxBusPatches];
596         fEndOfBusPatches = fBusPatches;
597
598   fMaxBlocks = maxBlocks;
599   fMaxDsps = maxDsps;
600   fMaxBusPatches = maxBusPatches;
601 }
602
603
604 void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::OnNewBuffer(
605                 const void* buffer, UInt_t bufferSize
606         )
607 {
608         /// This is called by the high performance decoder when a new DDL payload
609         /// is about to be decoded.
610         /// \param buffer  The pointer to the buffer storing the DDL payload.
611         /// \param bufferSize  The size of the buffer in bytes.
612
613         // remember the start of the buffer to be used in OnError.
614         fBufferStart = buffer;
615
616         // Reset error counters.
617         fParityErrors = 0;
618         fGlitchErrors = 0;
619         fPaddingErrors = 0;
620
621         // Check if we will have enough space in the fParityOk array.
622         // If we do not then we need to resize the array.
623         // bufferSize / sizeof(UInt_t) will be a safe over estimate of the
624         // number of channels that we will find.
625         UInt_t maxChannelsPossible = bufferSize / sizeof(UInt_t);
626         if (maxChannelsPossible > fMaxChannels)
627         {
628                 if (fParityOk != NULL)
629                 {
630                         delete [] fParityOk;
631                         fParityOk = NULL;
632                         fMaxChannels = 0;
633                 }
634                 fParityOk = new Bool_t[maxChannelsPossible];
635                 fMaxChannels = maxChannelsPossible;
636         }
637         
638         // Reset the current pointers which will be used to track where we need to
639         // fill fBlocks, fDSPs, fBusPatches and the parity flag. We have to subtract
640         // one space because we will increment the pointer the first time in the
641         // OnNewXZY methods.
642         fCurrentBlock = fBlocks-1;
643         fCurrentDSP = fDSPs-1;
644         fCurrentBusPatch = fBusPatches-1;
645         fCurrentParityOkFlag = fParityOk-1;
646         fBlockCount = 0;
647 }
648
649
650 void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::OnError(
651                 ErrorCode error, const void* location
652         )
653 {
654         /// This is called by the high performance decoder when a error occurs
655         /// when trying to decode the DDL payload. This indicates corruption in
656         /// the data. This method converts the error code to a descriptive message
657         /// and logs this with the raw reader.
658         /// \param error  The error code indicating the problem.
659         /// \param location  A pointer to the location within the DDL payload buffer
660         ///              being decoded where the problem with the data was found.
661
662         assert( fRawReader != NULL );
663         
664         Char_t* message = NULL;
665         UInt_t word = 0;
666
667         switch (error)
668         {
669         case kGlitchFound:
670                 fGlitchErrors++;
671                 message = Form(
672                         "Glitch error detected in DSP %d, skipping event ",
673                         fCurrentBlock->GetDspId()
674                 );
675                 fRawReader->AddMajorErrorLog(error, message);
676                 break;
677
678         case kBadPaddingWord:
679                 fPaddingErrors++;
680                 // We subtract 1 from the current numbers of blocks, DSPs
681                 // and bus patches to get the indices.
682                 message = Form(
683                         "Padding word error for iBlock %d, iDsp %d, iBus %d\n", 
684                         fBlockCount-1,
685                         fCurrentBlock->GetDspCount()-1,
686                         fCurrentDSP->GetBusPatchCount()-1
687                 );
688                 fRawReader->AddMinorErrorLog(error, message);
689                 break;
690
691         case kParityError:
692                 fParityErrors++;
693                 // location points to the incorrect data word and
694                 // fCurrentBusPatch->GetData() returns a pointer to the start of
695                 // bus patches data, so the difference divided by 4 gives the 32
696                 // bit word number.
697                 word = ((unsigned long)location - (unsigned long)fCurrentBusPatch->GetData())
698                                 / sizeof(UInt_t);
699                 message = Form(
700                         "Parity error in word %d for manuId %d and channel %d in buspatch %d\n", 
701                         word,
702                         fCurrentBusPatch->GetManuId(word),
703                         fCurrentBusPatch->GetChannelId(word),
704                         fCurrentBusPatch->GetBusPatchId()
705                 );
706                 fRawReader->AddMinorErrorLog(error, message);
707                 break;
708
709         default:
710                 message = Form(
711                         "%s (At byte %d in DDL.)",
712                         ErrorCodeToMessage(error),
713                         (unsigned long)location - (unsigned long)fBufferStart + sizeof(AliRawDataHeader)
714                 );
715                 fRawReader->AddMajorErrorLog(error, message);
716                 break;
717         }
718
719         if (fWarnings)
720         {
721                 AliWarningGeneral(
722                                 "AliMUONRawStreamTrackerHP::AliDecoderEventHandler",
723                                 message
724                         );
725         }
726 }
727