]> git.uio.no Git - u/mrichter/AliRoot.git/blob - MUON/AliMUONRawStreamTrackerHP.cxx
Updated documentation
[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 "AliMUONDspHeader.h"
48 #include "AliMUONBlockHeader.h"
49 #include "AliMUONBusStruct.h"
50 #include "AliMUONDDLTracker.h"
51 #include "AliRawReader.h"
52 #include "AliLog.h"
53 #include <cassert>
54 #include <iostream>
55 #include <iomanip>
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         fCurrentBusPatch(NULL),
73         fCurrentData(NULL),
74         fEndOfData(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         fCurrentBusPatch(NULL),
105         fCurrentData(NULL),
106         fEndOfData(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         fCurrentBusPatch = NULL;
178         fCurrentData = NULL;
179         fEndOfData = 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         fCurrentBusPatch = fDecoder.GetHandler().FirstBusPatch();
253         if (fCurrentBusPatch != fDecoder.GetHandler().EndOfBusPatch())
254         {
255                 fCurrentData = fCurrentBusPatch->GetData();
256                 fEndOfData = fCurrentData + fCurrentBusPatch->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                 fCurrentData = fEndOfData = 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
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         /// \return kTRUE if we read another digit and kFALSE if we have read all the
291         ///    digits already, i.e. at the end of the iteration.
292         
293         if (fCurrentData == NULL) return kFALSE;
294         
295 retry:
296         // Check if we still have data to be returned for the current bus patch.
297         if (fCurrentData != fEndOfData)
298         {
299                 busPatchId = fCurrentBusPatch->GetBusPatchId();
300                 AliMUONTrackerDDLDecoderEventHandler::UnpackADC(*fCurrentData, manuId, manuChannel, adc);
301                 fCurrentData++;
302                 return kTRUE;
303         }
304         else
305         {
306                 // We hit the end of the current bus patch so check if we have any more
307                 // bus patches to process for the current DDL. If we do, then increment
308                 // the current bus patch, make sure it is not the last one and then try
309                 // reading the first element again.
310                 if (fCurrentBusPatch != fDecoder.GetHandler().EndOfBusPatch())
311                 {
312                         fCurrentBusPatch++;
313                         if (fCurrentBusPatch != fDecoder.GetHandler().EndOfBusPatch())
314                         {
315                                 fCurrentData = fCurrentBusPatch->GetData();
316                                 fEndOfData = fCurrentData + fCurrentBusPatch->GetDataCount();
317                                 goto retry;
318                         }
319                 }
320
321                 // This was the last bus patch in the DDL so read in the next one and
322                 // try reading the first data element again.
323                 // Note: fCurrentBusPatch is set inside NextDDL().
324                 if (NextDDL()) goto retry;
325         }
326         return kFALSE;
327 }
328
329
330 AliMUONDDLTracker* AliMUONRawStreamTrackerHP::GetDDLTracker() const
331 {
332         /// Construct and return a pointer to the DDL payload object.
333         /// \return Pointer to internally constructed AliMUONDDLTracker object.
334         ///         The object is owned by this class and should not be deleted
335         ///         by the caller.
336         ///
337         /// \note This method should not be used just to gain access to the DDL
338         /// payload, unless there is a good reason to have the AliMUONDDLTracker
339         /// object. For example, if you want to modify the data and then save it
340         /// to another DDL stream. Otherwise it can be an order of magnitude
341         /// faster to access the DDL headers and data with the GetBlockHeader,
342         /// GetDspHeader and GetBusPatch methods for example.
343         /// Refer to the MUONRawStreamTracker.C macro to see how to use the fast
344         /// decoder interface optimally.
345         
346         if (fDDLObject != NULL) return fDDLObject;
347         
348         fDDLObject = new AliMUONDDLTracker;
349         for (Int_t iBlock = 0; iBlock < (Int_t)GetBlockCount(); iBlock++)
350         {
351                 AliMUONBlockHeader blockHeader;
352                 AliMUONDspHeader dspHeader;
353                 AliMUONBusStruct busPatch;
354                 
355                 const AliBlockHeader* bh = GetBlockHeader(iBlock);
356                 // Copy block header and add it to the DDL object.
357                 memcpy(blockHeader.GetHeader(), bh->GetHeader(), sizeof(AliMUONBlockHeaderStruct));
358                 fDDLObject->AddBlkHeader(blockHeader);
359                 
360                 for (Int_t iDsp = 0; iDsp < (Int_t)bh->GetDspCount(); iDsp++)
361                 {
362                         const AliDspHeader* dh = bh->GetDspHeader(iDsp);
363                         // Copy DSP header and add it to the DDL object.
364                         memcpy(dspHeader.GetHeader(), dh->GetHeader(), sizeof(AliMUONDSPHeaderStruct));
365                         fDDLObject->AddDspHeader(dspHeader, iBlock);
366                         
367                         const AliBusPatch* bp = dh->GetFirstBusPatch();
368                         while (bp != NULL)
369                         {
370                                 // Copy bus patch header, data and add everything into DDL object.
371                                 memcpy(busPatch.GetHeader(), bp->GetHeader(), sizeof(AliMUONBusPatchHeaderStruct));
372                                 busPatch.SetAlloc(bp->GetLength());
373                                 memcpy(busPatch.GetData(), bp->GetData(), bp->GetDataCount()*sizeof(UInt_t));
374                                 busPatch.SetBlockId(iBlock);
375                                 busPatch.SetDspId(iDsp);
376                                 fDDLObject->AddBusPatch(busPatch, iBlock, iDsp);
377                                 bp = bp->Next();
378                         }
379                 }
380         }
381         
382         return fDDLObject;
383 }
384
385
386 void AliMUONRawStreamTrackerHP::SetMaxBlock(Int_t blk)
387 {
388         /// Set maximum number of blocks per DDL allowed.
389         fDecoder.MaxBlocks( (UInt_t) blk );
390         
391         fDecoder.GetHandler().SetMaxStructs(
392                         fDecoder.MaxBlocks(),
393                         fDecoder.MaxDSPs(),
394                         fDecoder.MaxBusPatches()
395                 );
396 }
397
398
399 void AliMUONRawStreamTrackerHP::SetMaxDsp(Int_t dsp)
400 {
401         /// Set maximum number of Dsp per block allowed.
402         fDecoder.MaxDSPs( (UInt_t) dsp );
403         
404         fDecoder.GetHandler().SetMaxStructs(
405                         fDecoder.MaxBlocks(),
406                         fDecoder.MaxDSPs(),
407                         fDecoder.MaxBusPatches()
408                 );
409 }
410
411
412 void AliMUONRawStreamTrackerHP::SetMaxBus(Int_t bus)
413 {
414         /// Set maximum number of Buspatch per Dsp allowed.
415         fDecoder.MaxBusPatches( (UInt_t) bus );
416         
417         fDecoder.GetHandler().SetMaxStructs(
418                         fDecoder.MaxBlocks(),
419                         fDecoder.MaxDSPs(),
420                         fDecoder.MaxBusPatches()
421                 );
422 }
423
424 ///////////////////////////////////////////////////////////////////////////////
425
426 void AliMUONRawStreamTrackerHP::AliBlockHeader::Print() const
427 {
428         /// Print header to screen.
429         
430         cout << "CRT info"        << endl;
431         if (fHeader == NULL)
432         {
433                 cout << "Header is NULL" << endl;
434                 return;
435         }
436         cout << "DataKey: 0x"     << hex << fHeader->fDataKey << dec << endl;
437         cout << "TotalLength: "   << fHeader->fTotalLength << endl;
438         cout << "Length: "        << fHeader->fLength << endl;
439         cout << "DspId: "         << fHeader->fDSPId << endl;
440         cout << "L0Trigger: "     << fHeader->fL0Trigger << endl;
441         cout << "MiniEventId: "   << fHeader->fMiniEventId<< endl; 
442         cout << "EventId1: "      << fHeader->fEventId1 << endl;
443         cout << "EventId2: "      << fHeader->fEventId2 << endl;
444 }
445
446
447 void AliMUONRawStreamTrackerHP::AliDspHeader::Print() const
448 {
449         /// Print header to screen.
450         
451         cout << "FRT info"        << endl;
452         if (fHeader == NULL)
453         {
454                 cout << "Header is NULL" << endl;
455                 return;
456         }
457         cout << "DataKey: 0x"     << hex << fHeader->fDataKey << dec << endl;
458         cout << "TotalLength: "   << fHeader->fTotalLength << endl;
459         cout << "Length : "       << fHeader->fLength << endl;
460         cout << "DspId: "         << fHeader->fDSPId << endl;
461         cout << "BlkL1ATrigger: " << fHeader->fBlkL1ATrigger << endl;
462         cout << "MiniEventId: "   << fHeader->fMiniEventId << endl;
463         cout << "L1ATrigger: "    << fHeader->fL1ATrigger << endl;
464         cout << "L1RTrigger: "    << fHeader->fL1RTrigger << endl;
465         cout << "PaddingWord: "   << fHeader->fPaddingWord << endl;
466         cout << "ErrorWord: "     << fHeader->fErrorWord << endl;
467 }
468
469
470 void AliMUONRawStreamTrackerHP::AliBusPatch::Print(const Option_t* opt) const
471 {
472         /// Print header to screen.
473         cout << "Bus patch info" << endl;
474         if (fHeader == NULL)
475         {
476                 cout << "Header is NULL" << endl;
477                 return;
478         }
479         cout << "DataKey: 0x"    << hex << fHeader->fDataKey << dec << endl;
480         cout << "fTotalLength: " << fHeader->fTotalLength << endl;
481         cout << "fLength: "      << fHeader->fLength << endl;
482         cout << "fBusPatchId: "  << fHeader->fBusPatchId << endl;
483
484         if (TString(opt).Contains("all"))
485         {
486                 for (UInt_t i = 0; i < fHeader->fLength; ++i)
487                         cout << "Data["<< i << "] = " << fData[i] << endl;
488         }
489 }
490
491 ///////////////////////////////////////////////////////////////////////////////
492
493 AliMUONRawStreamTrackerHP::AliDecoderEventHandler::AliDecoderEventHandler() :
494         fRawStream(NULL),
495         fBufferStart(NULL),
496         fBlockCount(0),
497         fBlocks(NULL),
498         fDSPs(NULL),
499         fBusPatches(NULL),
500         fEndOfBusPatches(NULL),
501         fMaxChannels(8192),
502         fParityOk(new Bool_t[8192]),
503         fCurrentBlock(NULL),
504         fCurrentDSP(NULL),
505         fCurrentBusPatch(NULL),
506         fCurrentParityOkFlag(NULL),
507         fParityErrors(0),
508         fGlitchErrors(0),
509         fPaddingErrors(0),
510         fWarnings(kTRUE)
511 {
512         /// Default constructor initialises the internal parity flags buffer to
513         /// store 8192 elements. This array will grow dynamically if needed.
514 }
515
516
517 AliMUONRawStreamTrackerHP::AliDecoderEventHandler::~AliDecoderEventHandler()
518 {
519         /// Default destructor cleans up the allocated memory.
520         
521         if (fParityOk != NULL) delete [] fParityOk;
522         if (fBlocks != NULL) delete [] fBlocks;
523         if (fDSPs != NULL) delete [] fDSPs;
524         if (fBusPatches != NULL) delete [] fBusPatches;
525 }
526
527
528 void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::SetMaxStructs(
529                 UInt_t maxBlocks, UInt_t maxDsps, UInt_t maxBusPatches
530         )
531 {
532         /// Sets the maximum number of structures allowed.
533         
534         // Start by clearing the current arrays.
535         if (fBlocks != NULL)
536         {
537                 delete [] fBlocks;
538                 fBlocks = NULL;
539         }
540         if (fDSPs != NULL)
541         {
542                 delete [] fDSPs;
543                 fDSPs = NULL;
544         }
545         if (fBusPatches != NULL)
546         {
547                 delete [] fBusPatches;
548                 fBusPatches = NULL;
549         }
550         fCurrentBlock = NULL;
551         fCurrentDSP = NULL;
552         fCurrentBusPatch = NULL;
553         
554         // Allocate new memory.
555         fBlocks = new AliBlockHeader[maxBlocks];
556         fDSPs = new AliDspHeader[maxBlocks*maxDsps];
557         fBusPatches = new AliBusPatch[maxBlocks*maxDsps*maxBusPatches];
558         fEndOfBusPatches = fBusPatches;
559 }
560
561
562 void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::OnNewBuffer(
563                 const void* buffer, UInt_t bufferSize
564         )
565 {
566         /// This is called by the high performance decoder when a new DDL payload
567         /// is about to be decoded.
568         /// \param buffer  The pointer to the buffer storing the DDL payload.
569         /// \param bufferSize  The size of the buffer in bytes.
570
571         assert( fRawStream != NULL );
572         
573         // remember the start of the buffer to be used in OnError.
574         fBufferStart = buffer;
575
576         // Reset error counters.
577         fParityErrors = 0;
578         fGlitchErrors = 0;
579         fPaddingErrors = 0;
580
581         // Check if we will have enough space in the fParityOk array.
582         // If we do not then we need to resize the array.
583         // bufferSize / sizeof(UInt_t) will be a safe over estimate of the
584         // number of channels that we will find.
585         UInt_t maxChannelsPossible = bufferSize / sizeof(UInt_t);
586         if (maxChannelsPossible > fMaxChannels)
587         {
588                 if (fParityOk != NULL)
589                 {
590                         delete [] fParityOk;
591                         fParityOk = NULL;
592                         fMaxChannels = 0;
593                 }
594                 fParityOk = new Bool_t[maxChannelsPossible];
595                 fMaxChannels = maxChannelsPossible;
596         }
597         
598         // Reset the current pointers which will be used to track where we need to
599         // fill fBlocks, fDSPs, fBusPatches and the parity flag. We have to subtract
600         // one space because we will increment the pointer the first time in the
601         // OnNewXZY methods.
602         fCurrentBlock = fBlocks-1;
603         fCurrentDSP = fDSPs-1;
604         fCurrentBusPatch = fBusPatches-1;
605         fCurrentParityOkFlag = fParityOk-1;
606         fBlockCount = 0;
607 }
608
609
610 void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::OnError(
611                 ErrorCode error, const void* location
612         )
613 {
614         /// This is called by the high performance decoder when a error occurs
615         /// when trying to decode the DDL payload. This indicates corruption in
616         /// the data. This method converts the error code to a descriptive message
617         /// and logs this with the raw reader.
618         /// \param error  The error code indicating the problem.
619         /// \param location  A pointer to the location within the DDL payload buffer
620         ///              being decoded where the problem with the data was found.
621
622         assert( fRawStream != NULL );
623         assert( fRawStream->GetReader() != NULL );
624         
625         Char_t* message = NULL;
626         UInt_t word = 0;
627
628         switch (error)
629         {
630         case kGlitchFound:
631                 fGlitchErrors++;
632                 message = Form(
633                         "Glitch error detected in DSP %d, skipping event ",
634                         fCurrentBlock->GetDspId()
635                 );
636                 fRawStream->GetReader()->AddMajorErrorLog(error, message);
637                 break;
638
639         case kBadPaddingWord:
640                 fPaddingErrors++;
641                 // We subtract 1 from the current numbers of blocks, DSPs
642                 // and bus patches to get the indices.
643                 message = Form(
644                         "Padding word error for iBlock %d, iDsp %d, iBus %d\n", 
645                         fBlockCount-1,
646                         fCurrentBlock->GetDspCount()-1,
647                         fCurrentDSP->GetBusPatchCount()-1
648                 );
649                 fRawStream->GetReader()->AddMinorErrorLog(error, message);
650                 break;
651
652         case kParityError:
653                 fParityErrors++;
654                 // location points to the incorrect data word and
655                 // fCurrentBusPatch->GetData() returns a pointer to the start of
656                 // bus patches data, so the difference divided by 4 gives the 32
657                 // bit word number.
658                 word = ((unsigned long)location - (unsigned long)fCurrentBusPatch->GetData())
659                                 / sizeof(UInt_t);
660                 message = Form(
661                         "Parity error in word %d for manuId %d and channel %d in buspatch %d\n", 
662                         word,
663                         fCurrentBusPatch->GetManuId(word),
664                         fCurrentBusPatch->GetChannelId(word),
665                         fCurrentBusPatch->GetBusPatchId()
666                 );
667                 fRawStream->GetReader()->AddMinorErrorLog(error, message);
668                 break;
669
670         default:
671                 message = Form(
672                         "%s (At byte %d in DDL.)",
673                         ErrorCodeToMessage(error),
674                         (unsigned long)location - (unsigned long)fBufferStart + sizeof(AliRawDataHeader)
675                 );
676                 fRawStream->GetReader()->AddMajorErrorLog(error, message);
677                 break;
678         }
679
680         if (fWarnings)
681         {
682                 AliWarningGeneral(
683                                 "AliMUONRawStreamTrackerHP::AliDecoderEventHandler",
684                                 message
685                         );
686         }
687 }
688