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