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