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