]> git.uio.no Git - u/mrichter/AliRoot.git/commitdiff
Adding the new high performance decoder.
authorivana <ivana@f7af4fe6-9843-0410-8265-dc069ae4e863>
Thu, 6 Dec 2007 11:38:45 +0000 (11:38 +0000)
committerivana <ivana@f7af4fe6-9843-0410-8265-dc069ae4e863>
Thu, 6 Dec 2007 11:38:45 +0000 (11:38 +0000)
The new decoder can be used during reconstruction by setting
the reconstruction option to "useFastDecoder".
(Artur)

MUON/AliMUONDigitMaker.cxx
MUON/AliMUONDigitMaker.h
MUON/AliMUONRawStreamTracker.cxx
MUON/AliMUONRawStreamTracker.h
MUON/AliMUONRawStreamTrackerHP.cxx [new file with mode: 0644]
MUON/AliMUONRawStreamTrackerHP.h [new file with mode: 0644]
MUON/AliMUONReconstructor.cxx
MUON/AliMUONTrackerDDLDecoder.h [new file with mode: 0644]
MUON/AliMUONTrackerDDLDecoderEventHandler.h [new file with mode: 0644]
MUON/AliMUONVRawStreamTracker.cxx [new file with mode: 0644]
MUON/AliMUONVRawStreamTracker.h [new file with mode: 0644]

index c8de1ccf91928732548f40efc2cb8f1ccf1bcd28..4b9238868bf3eaa9376ef9fae1fa5741a1e70602 100644 (file)
@@ -53,6 +53,7 @@
 #include "AliMUONLocalStruct.h"
 #include "AliMUONLocalTrigger.h"
 #include "AliMUONRawStreamTracker.h"
+#include "AliMUONRawStreamTrackerHP.h"
 #include "AliMUONRawStreamTrigger.h"
 #include "AliMUONRegHeader.h"
 #include "AliMUONTriggerCircuit.h"
@@ -73,11 +74,11 @@ ClassImp(AliMUONDigitMaker) // Class implementation in ROOT context
 /// \endcond
 
 //__________________________________________________________________________
-AliMUONDigitMaker::AliMUONDigitMaker(Bool_t enableErrorLogger)
+AliMUONDigitMaker::AliMUONDigitMaker(Bool_t enableErrorLogger, Bool_t useFastDecoder)
   : TObject(),
     fScalerEvent(kFALSE),
     fMakeTriggerDigits(kFALSE),
-    fRawStreamTracker(new AliMUONRawStreamTracker()),    
+    fRawStreamTracker(NULL),
     fRawStreamTrigger(new AliMUONRawStreamTrigger()),    
     fTrackerTimer(),
     fTriggerTimer(),
@@ -88,6 +89,11 @@ AliMUONDigitMaker::AliMUONDigitMaker(Bool_t enableErrorLogger)
   /// ctor 
 
   AliDebug(1,"");
+  
+  if (useFastDecoder)
+    fRawStreamTracker = new AliMUONRawStreamTrackerHP();
+  else
+    fRawStreamTracker = new AliMUONRawStreamTracker();
 
   // Standard Constructor
   if (enableErrorLogger) {
index ca6dee251a0799cc983bba6ee8d85dbc12d0536c..8aa4d00ee11ca05f2b1112be5a48a41e5c12695e 100644 (file)
@@ -19,7 +19,7 @@ class TArrayS;
 class AliRawReader;
 class AliMUONLocalStruct;
 
-class AliMUONRawStreamTracker;
+class AliMUONVRawStreamTracker;
 class AliMUONRawStreamTrigger;
 
 class AliMUONVDigitStore;
@@ -28,7 +28,7 @@ class AliMUONVTriggerStore;
 class AliMUONDigitMaker : public TObject 
 {
  public:
-  AliMUONDigitMaker(Bool_t enableErrorLogger = kTRUE); // Constructor
+  AliMUONDigitMaker(Bool_t enableErrorLogger = kTRUE, Bool_t useFastDecoder = kTRUE); // Constructor
   virtual ~AliMUONDigitMaker(void); // Destructor
     
   // write raw data
@@ -60,7 +60,7 @@ private:
   Bool_t fScalerEvent;       //!< flag to generates scaler event
   Bool_t fMakeTriggerDigits; //!< whether or not we should generate digits for the trigger
   
-  AliMUONRawStreamTracker* fRawStreamTracker;  //!< pointer of raw stream for tracker
+  AliMUONVRawStreamTracker* fRawStreamTracker; //!< pointer of raw stream for tracker
   AliMUONRawStreamTrigger* fRawStreamTrigger;  //!< pointer of raw stream for trigger
 
   TStopwatch fTrackerTimer;                    //!< time watcher for tracker part
index 9fe368911707280f166d9fbd2d91759b61266c99..3323407892489d8121b18e534c9b6efa8f62ae0d 100644 (file)
@@ -13,7 +13,7 @@
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/
 
-/* $Id $ */
+/* $Id$ */
 
 
 //-----------------------------------------------------------------------------
@@ -55,7 +55,7 @@ const Int_t AliMUONRawStreamTracker::fgkMaxDDL = 20;
 
 //___________________________________________
 AliMUONRawStreamTracker::AliMUONRawStreamTracker()
- : AliMUONRawStream(),
+ : AliMUONVRawStreamTracker(),
    fPayload(new AliMUONPayloadTracker()),
    fCurrentDDL(0),
    fCurrentDDLIndex(fgkMaxDDL),
@@ -66,7 +66,8 @@ AliMUONRawStreamTracker::AliMUONRawStreamTracker()
    fCurrentBusStruct(0),
    fCurrentBusStructIndex(0),
    fCurrentDataIndex(0),
-   fDDL(0)
+   fDDL(0),
+   fChannelBuffer()
 {
   ///
   /// create an object to read MUON raw digits
@@ -78,7 +79,7 @@ AliMUONRawStreamTracker::AliMUONRawStreamTracker()
 
 //_________________________________________________________________
 AliMUONRawStreamTracker::AliMUONRawStreamTracker(AliRawReader* rawReader)
-: AliMUONRawStream(rawReader),
+: AliMUONVRawStreamTracker(rawReader),
   fPayload(new AliMUONPayloadTracker()),
   fCurrentDDL(0),
   fCurrentDDLIndex(fgkMaxDDL),
@@ -89,7 +90,8 @@ AliMUONRawStreamTracker::AliMUONRawStreamTracker(AliRawReader* rawReader)
   fCurrentBusStruct(0),
   fCurrentBusStructIndex(0),
   fCurrentDataIndex(0),
-  fDDL(0)
+  fDDL(0),
+  fChannelBuffer()
 {
   ///
   /// ctor with AliRawReader as argument
@@ -142,6 +144,26 @@ AliMUONRawStreamTracker::Next(Int_t& busPatchId,
   return kTRUE;
 }
 
+//______________________________________________________
+UInt_t AliMUONRawStreamTracker::Next(const AliChannelInfo*& channels)
+{
+  /// This method actually just wraps around the single step Next() method
+  /// for now and returns channels one at a time.
+
+  Int_t busPatchId; UShort_t manuId; UChar_t manuChannel; UShort_t adc;
+  Bool_t ok = Next(busPatchId, manuId, manuChannel, adc);
+  if (ok)
+  {
+        fChannelBuffer = AliChannelInfo(busPatchId, manuId, manuChannel, adc);
+        channels = &fChannelBuffer;
+       return 1;
+  }
+  else
+  {
+       return 0;
+  }
+}
+
 //______________________________________________________
 Bool_t
 AliMUONRawStreamTracker::IsDone() const
index ad1adaa660ee9940976acd19aa44f3d82551b255..6945f47354260601e67d7aa76c344f8ff3f1f745 100644 (file)
@@ -13,7 +13,7 @@
 
 #include <TObject.h>
 #include "AliMUONPayloadTracker.h"
-#include "AliMUONRawStream.h"
+#include "AliMUONVRawStreamTracker.h"
 
 class AliRawReader;
 class AliMUONDDLTracker;
@@ -21,7 +21,7 @@ class AliMUONDspHeader;
 class AliMUONBusStruct;
 class AliMUONBlockHeader;
 
-class AliMUONRawStreamTracker: public AliMUONRawStream {
+class AliMUONRawStreamTracker: public AliMUONVRawStreamTracker {
   public :
     AliMUONRawStreamTracker();
     AliMUONRawStreamTracker(AliRawReader* rawReader);
@@ -46,6 +46,9 @@ class AliMUONRawStreamTracker: public AliMUONRawStream {
     virtual Bool_t Next(Int_t& busPatchId, 
                         UShort_t& manuId, UChar_t& manuChannel, 
                         UShort_t& adc);
+
+    /// Returns the next batch of decoded channel data.
+    virtual UInt_t Next(const AliChannelInfo*& channels);
     
     virtual Bool_t NextDDL();
 
@@ -121,6 +124,7 @@ class AliMUONRawStreamTracker: public AliMUONRawStream {
     Int_t fCurrentBusStructIndex;            //!< for iterator: current bus index    
     Int_t fCurrentDataIndex;                 //!< for iterator: current data index
     Int_t  fDDL;                             //!< number of DDL    
+    AliChannelInfo fChannelBuffer;           //!< Single channel buffer for Next() method.
     static const Int_t  fgkMaxDDL;           //!< maximum number of DDLs
 
     ClassDef(AliMUONRawStreamTracker, 4)    // base class for reading MUON raw digits
diff --git a/MUON/AliMUONRawStreamTrackerHP.cxx b/MUON/AliMUONRawStreamTrackerHP.cxx
new file mode 100644 (file)
index 0000000..909fe1c
--- /dev/null
@@ -0,0 +1,375 @@
+/**************************************************************************
+ * This file is property of and copyright by the ALICE HLT Project        *
+ * All rights reserved.                                                   *
+ *                                                                        *
+ * Primary Authors:                                                       *
+ *   Artur Szostak <artursz@iafrica.com>                                  *
+ *                                                                        *
+ * Permission to use, copy, modify and distribute this software and its   *
+ * documentation strictly for non-commercial purposes is hereby granted   *
+ * without fee, provided that the above copyright notice appears in all   *
+ * copies and that both the copyright notice and this permission notice   *
+ * appear in the supporting documentation. The authors make no claims     *
+ * about the suitability of this software for any purpose. It is          *
+ * provided "as is" without express or implied warranty.                  *
+ **************************************************************************/
+
+/* $Id$*/
+
+///
+/// \file   AliMUONRawStreamTrackerHP.cxx
+/// \author Artur Szostak <artursz@iafrica.com>
+/// \date   29-11-2007
+/// \brief  Implementation of the the high performance decoder AliMUONRawStreamTrackerHP.
+///
+
+//-----------------------------------------------------------------------------
+/// \ingroup raw
+/// \class AliMUONRawStreamTrackerHP
+/// \brief A high performance stream decoder for muon tracking DDL streams.
+///
+/// This is the raw stream class which interfaces between the high performance
+/// core decoder and the AliRawReader class.
+/// To gain the most out of the decoder, the Next() method which returns batches
+/// of decoded digit / channel information should be used. That is:
+/// \code
+///   UInt_t Next(const AliChannelInfo*& channels);
+/// \endcode
+///
+/// \author Artur Szostak <artursz@iafrica.com>
+//-----------------------------------------------------------------------------
+
+#include "AliMUONRawStreamTrackerHP.h"
+#include "AliRawReader.h"
+#include "AliLog.h"
+#include <cassert>
+
+/// \cond CLASSIMP
+ClassImp(AliMUONRawStreamTrackerHP)
+/// \endcond
+
+
+AliMUONRawStreamTrackerHP::AliMUONRawStreamTrackerHP() :
+       AliMUONVRawStreamTracker(),
+       fDecoder(),
+       fDDL(0),
+       fCurrentChannel(0),
+       fBufferSize(8192),
+       fBuffer(new UChar_t[8192]),
+       fHadError(kFALSE)
+{
+       ///
+       /// Default constructor.
+       ///
+}
+
+
+AliMUONRawStreamTrackerHP::AliMUONRawStreamTrackerHP(AliRawReader* rawReader) :
+       AliMUONVRawStreamTracker(rawReader),
+       fDecoder(),
+       fDDL(0),
+       fCurrentChannel(0),
+       fBufferSize(8192),
+       fBuffer(new UChar_t[8192]),
+       fHadError(kFALSE)
+{
+       ///
+       /// Constructor with AliRawReader as argument.
+       ///
+       
+       fDecoder.GetHandler().SetRawStream(this);
+}
+
+
+AliMUONRawStreamTrackerHP::~AliMUONRawStreamTrackerHP()
+{
+       ///
+       /// Default destructor.
+       ///
+       
+       if (fBuffer != NULL)
+       {
+               delete [] fBuffer;
+       }
+}
+
+
+void AliMUONRawStreamTrackerHP::First()
+{
+       /// Initialise or reset the iterator.
+       /// The first DDL will be found and decoded.
+       
+       assert( GetReader() != NULL );
+       
+       fDDL = 0;
+       NextDDL();
+}
+
+
+Bool_t AliMUONRawStreamTrackerHP::NextDDL()
+{
+       /// Reading the next tracker DDL and decode the payload with the 
+       /// high performance decoder.
+       /// \return kTRUE if the next DDL was successfully read and kFALSE otherwise.
+
+       assert( GetReader() != NULL );
+       
+       if (IsDone()) return kFALSE;
+       
+       do
+       {
+               GetReader()->Reset();
+               GetReader()->Select("MUONTRK", fDDL, fDDL);  // Select the DDL file to be read.
+               if (GetReader()->ReadHeader()) break;
+               AliDebug(3, Form("Skipping DDL %d which does not seem to be there", fDDL+1));
+               fDDL++;
+       }
+       while (fDDL < GetMaxDDL());
+       
+       AliDebug(3, Form("DDL Number %d\n", fDDL));
+       
+       Int_t dataSize = GetReader()->GetDataSize(); // in bytes
+       // Check if we have enough buffer space already in fBuffer. If we do then
+       // just continue reading otherwise we need to resize the buffer.
+       if (fBufferSize < dataSize)
+       {
+               if (fBuffer != NULL)
+               {
+                       delete [] fBuffer;
+                       fBuffer = NULL;
+                       fBufferSize = 0;
+               }
+               try
+               {
+                       fBuffer = new UChar_t[dataSize];
+                       fBufferSize = dataSize;
+               }
+               catch (const std::bad_alloc&)
+               {
+                       AliError("Could not allocate more buffer space. Cannot decode DDL.");
+                       return kFALSE;
+               }
+       }
+       
+       if (not GetReader()->ReadNext(fBuffer, dataSize))
+       {
+               return kFALSE;
+       }
+       
+#ifndef R__BYTESWAP
+       Swap(fBuffer, dataSize); // Swap needed for mac power pc.
+#endif
+       
+       bool result = false;
+       try
+       {
+               // Since we might allocate memory inside OnNewBuffer in the event
+               // handler we need to trap any memory allocation exception to be robust.
+               result = fDecoder.Decode(fBuffer, dataSize);
+       }
+       catch (const std::bad_alloc&)
+       {
+               AliError("Could not allocate more buffer space. Cannot decode DDL.");
+               return kFALSE;
+       }
+       
+       fCurrentChannel = 0;
+       fDDL++; // Remember to increment index to next DDL.
+       return result;
+}
+
+
+Bool_t AliMUONRawStreamTrackerHP::IsDone() const
+{
+       /// Indicates whether the iteration is finished or not.
+       /// \return kTRUE if we already read all the digits and kFALSE if not.
+       
+       return fDDL == GetMaxDDL();
+}
+
+
+Bool_t AliMUONRawStreamTrackerHP::Next(
+               Int_t& busPatchId, UShort_t& manuId, UChar_t& manuChannel,
+               UShort_t& adc
+       )
+{
+       /// Advance one step in the iteration. Returns false if finished.
+       /// [out] \param busPatchId  This is filled with the bus patch ID of the digit.
+       /// [out] \param manuId      This is filled with the MANU ID of the digit.
+       /// [out] \param manuChannel This is filled with the MANU channel ID of the digit.
+       /// [out] \param adc         This is filled with the ADC signal value of the digit.
+       /// \return kTRUE if we read another digit and kFALSE if we have read all the
+       ///    digits already, i.e. at the end of the iteration.
+       
+       if (fCurrentChannel < fDecoder.GetHandler().ChannelCount())
+       {
+               const AliChannelInfo& channel = fDecoder.GetHandler().Channels()[fCurrentChannel];
+               busPatchId = channel.BusPatchId();
+               manuId = channel.ManuId();
+               manuChannel = channel.ChannelId();
+               adc = channel.ADC();
+               fCurrentChannel++;
+               return kTRUE;
+       }
+       else
+       {
+               if (NextDDL())
+               {
+                       if (fCurrentChannel < fDecoder.GetHandler().ChannelCount())
+                       {
+                               const AliChannelInfo& channel = fDecoder.GetHandler().Channels()[fCurrentChannel];
+                               busPatchId = channel.BusPatchId();
+                               manuId = channel.ManuId();
+                               manuChannel = channel.ChannelId();
+                               adc = channel.ADC();
+                               fCurrentChannel++;
+                               return kTRUE;
+                       }
+               }
+       }
+       return kFALSE;
+}
+
+
+UInt_t AliMUONRawStreamTrackerHP::Next(const AliChannelInfo*& channels)
+{
+       /// Returns the next batch of decoded channel data.
+       /// [out] \param channels This is filled with a pointer to an array of
+       ///          channels / digits that were decoded. This method does not
+       ///          modify 'channels' if zero is returned.
+       /// \return The number of elements in the array pointed to by 'channels'
+       ///    is returned. If zero is returned then there are no more channels to read.
+       
+       // Check if we are already at the end of the channels array. If so then we
+       // need to fetch the next non empty DDL.
+       if (fCurrentChannel >= fDecoder.GetHandler().ChannelCount())
+       {
+               do
+               {
+                       if (not NextDDL()) return 0;
+               }
+               // Make sure to keep going even for empty DDL payloads:
+               while (fDecoder.GetHandler().ChannelCount() == 0);
+       }
+       channels = fDecoder.GetHandler().Channels() + fCurrentChannel;
+       return fDecoder.GetHandler().ChannelCount() - fCurrentChannel;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+AliMUONRawStreamTrackerHP::AliDecoderEventHandler::AliDecoderEventHandler() :
+       fBusPatchId(0),
+       fChannelCount(0),
+       fMaxChannels(8192),
+       fChannelBuffer(new AliChannelInfo[8192]),
+       fRawStream(NULL),
+       fBufferStart(NULL)
+{
+       /// Default constructor initialises the internal buffer to store decoded
+       /// channel / digit data to 8192 elements.
+       /// This array will grow dynamically if needed.
+}
+
+
+AliMUONRawStreamTrackerHP::AliDecoderEventHandler::~AliDecoderEventHandler()
+{
+       /// Default destructor cleans up the allocated memory.
+       
+       if (fChannelBuffer != NULL)
+       {
+               delete [] fChannelBuffer;
+       }
+}
+
+void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::OnNewBuffer(
+               const void* buffer, UInt_t bufferSize
+       )
+{
+       /// This is called by the high performance decoder when a new DDL payload
+       /// is about to be decoded.
+       /// \param buffer  The pointer to the buffer storing the DDL payload.
+       /// \param bufferSize  The size of the buffer in bytes.
+
+       // remember the start of the buffer to be used in OnError.
+       fBufferStart = buffer;
+       
+       // Reset the number of channels found.
+       fChannelCount = 0;
+       
+       // Check if we will have enough space in the fChannelBuffer array.
+       // If we do not then we need to resize the array.
+       // bufferSize / sizeof(UInt_t) will be a safe over estimate of the
+       // number of channels that we will find.
+       UInt_t maxPossibleChannels = bufferSize / sizeof(UInt_t);
+       if (maxPossibleChannels > fMaxChannels)
+       {
+               if (fChannelBuffer != NULL)
+               {
+                       delete [] fChannelBuffer;
+                       fChannelBuffer = NULL;
+                       fMaxChannels = 0;
+               }
+               fChannelBuffer = new AliChannelInfo[maxPossibleChannels];
+               fMaxChannels = maxPossibleChannels;
+       }
+}
+
+
+void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::OnNewBusPatch(
+               const AliMUONBusPatchHeaderStruct* header, const void* /*data*/
+       )
+{
+       /// This is called by the high performance decoder when a new bus patch
+       /// is found within the DDL payload. All we do is remember the bus patch ID.
+       /// \param header  The bus patch header structure.
+       /// \param data  The bus patch data (not used in this method).
+       
+       fBusPatchId = header->fBusPatchId;
+}
+
+
+void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::OnData(UInt_t data)
+{
+       /// This is called by the high performance decoder when a new bus patch
+       /// is found within the DDL payload. All we do is remember the bus patch ID.
+       /// \param data  The bus patch data (not used in this method).
+       
+       assert( fChannelCount < fMaxChannels );
+       
+       UShort_t manuId; UChar_t channelId; UShort_t adc;
+       UnpackADC(data, manuId, channelId, adc);
+       fChannelBuffer[fChannelCount] = AliChannelInfo(fBusPatchId, manuId, channelId, adc);
+       fChannelCount++;
+}
+
+
+void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::OnError(
+               ErrorCode error, const void* location
+       )
+{
+       /// This is called by the high performance decoder when a error occurs
+       /// when trying to decode the DDL payload. This indicates corruption in
+       /// the data. This method converts the error code to a descriptive message
+       /// and log this with the raw reader.
+       /// \param error  The error code indicating the problem.
+       /// \param location  A pointer to the location within the DDL payload buffer
+       ///              being decoded where the problem with the data was found.
+
+       assert( fRawStream != NULL );
+       assert( fRawStream->GetReader() != NULL );
+       
+       const char* msg = ErrorCodeToMessage(error);
+       unsigned long pos = (unsigned long)location - (unsigned long)fBufferStart;
+       
+       switch (error)
+       {
+       case kBadPaddingWord:
+       case kParityError:
+               fRawStream->GetReader()->AddMinorErrorLog(error, Form("%s [At byte: %d]", msg, pos));
+               break;
+       default:
+               fRawStream->GetReader()->AddMajorErrorLog(error, Form("%s [At byte: %d]", msg, pos));
+               break;
+       }
+}
+
diff --git a/MUON/AliMUONRawStreamTrackerHP.h b/MUON/AliMUONRawStreamTrackerHP.h
new file mode 100644 (file)
index 0000000..f4fbc8e
--- /dev/null
@@ -0,0 +1,146 @@
+#ifndef ALIMUONRAWSTREAMTRACKERHP_H
+#define ALIMUONRAWSTREAMTRACKERHP_H
+/* This file is property of and copyright by the ALICE HLT Project        *
+ * ALICE Experiment at CERN, All rights reserved.                         *
+ * See cxx source for full Copyright notice                               */
+
+/* $Id$*/
+
+///
+/// \file   AliMUONRawStreamTrackerHP.h
+/// \author Artur Szostak <artursz@iafrica.com>
+/// \date   29-11-2007
+/// \brief  Declaration of the high performance decoder for muon trigger chamber raw streams.
+///
+
+#include "AliMUONVRawStreamTracker.h"
+#include "AliMUONTrackerDDLDecoder.h"
+
+class AliMUONRawStreamTrackerHP : public AliMUONVRawStreamTracker
+{
+public:
+
+       /// Default constructor.
+       AliMUONRawStreamTrackerHP();
+       
+       /// Constructor for setting the raw reader.
+       AliMUONRawStreamTrackerHP(AliRawReader* rawReader);
+       
+       /// Default destructor.
+       virtual ~AliMUONRawStreamTrackerHP();
+       
+       // The following public methods are all inherited from AliMUONVRawStreamTracker:
+       
+       /// Initialize iterator
+       virtual void First();
+       
+       /// DDL iterator 
+       virtual Bool_t NextDDL();
+       
+       /// Whether the iteration is finished or not
+       virtual Bool_t IsDone() const;
+       
+       /// Nothing is actually done in the AddErrorMessage method because we log
+       /// the error messages as we find them in AliDecoderEventHandler::OnError().
+       virtual void AddErrorMessage() {};
+       
+       /// Advance one step in the iteration. Returns false if finished.
+       virtual Bool_t Next(Int_t& busPatchId,
+                               UShort_t& manuId, UChar_t& manuChannel,
+                               UShort_t& adc);
+       
+       /// Returns the next batch of decoded channel data.
+       virtual UInt_t Next(const AliChannelInfo*& channels);
+       
+       /// Return maximum number of blocks per DDL allowed.
+       virtual Int_t GetMaxBlock() const { return (Int_t) fDecoder.MaxBlocks(); }
+       /// Return maximum number of Dsp per block allowed.
+       virtual Int_t GetMaxDsp() const { return (Int_t) fDecoder.MaxDSPs(); }
+       /// Return maximum number of Buspatch per Dsp allowed.
+       virtual Int_t GetMaxBus() const { return (Int_t) fDecoder.MaxBusPatches(); }
+       
+       /// Set maximum number of blocks per DDL allowed.
+       virtual void SetMaxBlock(Int_t blk) { fDecoder.MaxBlocks( (UInt_t) blk ); }
+       /// Set maximum number of Dsp per block allowed.
+       virtual void SetMaxDsp(Int_t dsp) { fDecoder.MaxDSPs( (UInt_t) dsp ); }
+       /// Set maximum number of Buspatch per Dsp allowed.
+       virtual void SetMaxBus(Int_t bus) { fDecoder.MaxBusPatches( (UInt_t) bus ); }
+       
+       /// Return number of the current DDL.
+       virtual Int_t GetDDL() const { return fDDL - 1; }
+       
+       /// check error/Warning presence
+       virtual Bool_t IsErrorMessage() const { return fHadError; }
+
+private:
+
+       // Do not allow copying of this class.
+        /// Not implemented
+       AliMUONRawStreamTrackerHP(const AliMUONRawStreamTrackerHP& stream);
+        /// Not implemented
+       AliMUONRawStreamTrackerHP& operator = (const AliMUONRawStreamTrackerHP& stream);
+       
+       /// This is the custom event handler (callback interface) class which
+       /// unpacks raw data words and fills an internal buffer with decoded digits
+       /// as they are decoded by the high performance decoder.
+       /// Any errors are logged to the parent AliMUONVRawStreamTracker, so one
+       /// must set this pointer appropriately before decoding and DDL payload.
+       class AliDecoderEventHandler : public AliMUONTrackerDDLDecoderEventHandler
+       {
+       public:
+       
+               /// Default constructor.
+               AliDecoderEventHandler();
+               /// Default destructor.
+               virtual ~AliDecoderEventHandler();
+               
+               /// Sets the raw stream object which should be the parent of this class.
+               void SetRawStream(AliMUONVRawStreamTracker* rawStream) { fRawStream = rawStream; }
+               
+               /// Return the number of channels in the buffer returned by Channels().
+               UInt_t ChannelCount() const { return fChannelCount; }
+               
+               /// Return the buffer of decoded channel data.
+               const AliChannelInfo* Channels() const { return fChannelBuffer; }
+               
+               // The following methods are inherited from AliMUONTrackerDDLDecoderEventHandler:
+               
+               /// New buffer handler.
+               void OnNewBuffer(const void* buffer, UInt_t bufferSize);
+               
+               /// New bus patch handler.
+               void OnNewBusPatch(const AliMUONBusPatchHeaderStruct* header, const void* data);
+               
+               /// Raw data word handler.
+               void OnData(UInt_t data);
+               
+               /// Error handler.
+               void OnError(ErrorCode error, const void* location);
+       
+       private:
+       
+               // Do not allow copying of this class.
+                /// Not implemented
+               AliDecoderEventHandler(const AliDecoderEventHandler& /*obj*/);
+                /// Not implemented
+               AliDecoderEventHandler& operator = (const AliDecoderEventHandler& /*obj*/);
+
+               Int_t fBusPatchId;     //!< The bus patch ID of the current bus patch being decoded.
+               UInt_t fChannelCount;  //!< Number of elements in fChannelBuffer.
+               UInt_t fMaxChannels;   //!< Maximum number of elements that can be stored in fChannelBuffer.
+               AliChannelInfo* fChannelBuffer;  //!< Buffer of decoded channel structures.
+               AliMUONVRawStreamTracker* fRawStream; //!< Pointer to the parent raw stream object.
+               const void* fBufferStart;   //!< Pointer to the start of the current DDL payload buffer.
+       };
+       
+       AliMUONTrackerDDLDecoder<AliDecoderEventHandler> fDecoder;  //!< The decoder for the DDL payload.
+       Int_t fDDL;         //!< The current DDL number being handled.
+       UInt_t fCurrentChannel;  //!< The current channel to return by Next().
+       Int_t fBufferSize;  //!< This is the buffer size in bytes of fBuffer.
+       UChar_t* fBuffer;   //!< This is the buffer in which we store the DDL payload read from AliRawReader.
+       Bool_t fHadError;   //!< Flag indicating if there was a decoding error or not.
+
+       ClassDef(AliMUONRawStreamTrackerHP, 0) // High performance decoder for reading MUON raw digits from tracking chamber DDL data.
+};
+
+#endif  // ALIMUONRAWSTREAMTRACKERHP_H
index 691613603671418468e20c32a4c85e1887327ab7..e9a2340f9b47f72ea6d636de1327b6929a30655b 100644 (file)
@@ -66,6 +66,9 @@
 ///
 /// TRIGGERDISABLE : disable the treatment of MUON trigger
 ///
+/// USEFASTDECODER : makes the digit maker class use the high performance decoder
+///                  AliMUONTrackerDDLDecoder instead of AliMUONPayloadTracker.
+///
 /// \author Laurent Aphecetche, Subatech
 //-----------------------------------------------------------------------------
 
@@ -268,7 +271,14 @@ AliMUONReconstructor::CreateDigitMaker() const
 
   AliCodeTimerAuto("")
 
-  fDigitMaker = new AliMUONDigitMaker;
+  TString option = GetOption();
+  Bool_t enableErrorLogging = kTRUE;
+  Bool_t useFastDecoder = kFALSE;
+  if (option.Contains("useFastDecoder"))
+  {
+    useFastDecoder = kTRUE;
+  }
+  fDigitMaker = new AliMUONDigitMaker(enableErrorLogging, useFastDecoder);
 }
 
 //_____________________________________________________________________________
diff --git a/MUON/AliMUONTrackerDDLDecoder.h b/MUON/AliMUONTrackerDDLDecoder.h
new file mode 100644 (file)
index 0000000..d7305f0
--- /dev/null
@@ -0,0 +1,1110 @@
+#ifndef ALIMUONTRACKERDDLDECODER_H
+#define ALIMUONTRACKERDDLDECODER_H
+/**************************************************************************
+ * This file is property of and copyright by the ALICE HLT Project        *
+ * All rights reserved.                                                   *
+ *                                                                        *
+ * Primary Authors:                                                       *
+ *   Artur Szostak <artursz@iafrica.com>                                  *
+ *                                                                        *
+ * Permission to use, copy, modify and distribute this software and its   *
+ * documentation strictly for non-commercial purposes is hereby granted   *
+ * without fee, provided that the above copyright notice appears in all   *
+ * copies and that both the copyright notice and this permission notice   *
+ * appear in the supporting documentation. The authors make no claims     *
+ * about the suitability of this software for any purpose. It is          *
+ * provided "as is" without express or implied warranty.                  *
+ **************************************************************************/
+
+/* $Id$ */
+
+///
+/// \file   AliMUONTrackerDDLDecoder.h
+/// \author Artur Szostak <artursz@iafrica.com>
+/// \date   28-11-2007
+/// \brief  Implementation of a high performance DDL decoder for the muon tracking stations.
+///
+/// This file implementes the AliMUONTrackerDDLDecoder class, which contains
+/// the core logic for decoding the payload in DDL streams comming from the muon
+/// spectrometer's tracking chambers in a very efficient manner.
+///
+/// This implementation is derived from work done by Christian Finck for the
+/// AliMUONPayloadTracker.
+///
+/// Note to maintainers: Please remember that this file is used by the online
+/// dHLT system. As an online system, the dHLT requires the fastest code possible
+/// in the decoders to satisfy its timing constraints. The performance impact
+/// must be checked before any proposed modification is made to this file.
+///
+
+#include "AliMUONTrackerDDLDecoderEventHandler.h"
+
+#include <cassert>
+#include <ostream>
+#include <Rtypes.h>
+
+
+/// \ingroup raw
+/// \class AliMUONTrackerDDLDecoder
+/// \brief A high performance decoder class for MUON tracking DDL data.
+///
+/// This class implements a high performance decoder for decoding DDL payload
+/// data coming from the muon spectrometers tracking chambers.
+/// It has been implemented using the event driven paradigm, which allows us
+/// to minimise the number of method calls made in the inner loops of the algorithm
+/// and minimise the memory footprint.
+/// The decoder class only contains the basic decoding and error checking logic.
+/// It calls methods such as OnNewBlock, OnNewBusPatch, OnData etc in
+/// the event handler during the decoding to return the decoded data.
+/// The event handler class is nothing more than a callback interface to deliver
+/// the next chunks of decoded data.
+/// To actually do something with the data one needs to implement a custom
+/// event handler (callback) class by inheriting from AliMUONTrackerDDLDecoderEventHandler
+/// and overriding the callback methods like so:
+/// \code
+///  class MyCustomHandler : public AliMUONTrackerDDLDecoderEventHandler
+///  {
+///  public:
+///     void OnData(UInt_t data)
+///     {
+///       // I can do something with 'data' here.
+///     }
+///  };
+/// \endcode
+///
+/// Once the custom handler is written then the decoder is in instantiated as
+/// shown below, to use your new custom handler. And to start decoding one needs
+/// to call the Decode() method of the decoder.
+/// \code
+///  AliMUONTrackerDDLDecoder<MyCustomHandler> myDecoder;
+///  muDecoder.Decoder(buffer, bufferSize);
+/// \endcode
+///
+/// Note that this class was written as a template on purpose. To maximise the
+/// compilers chance to make optimisations and inlining code must use a template.
+/// Depending on exactly what you do inside your handler the decoder will be
+/// significantly slower if run time polymorphism was used i.e. making the class
+/// AliMUONTrackerDDLDecoderEventHandler abstract and using virtual methods.
+///
+/// \author Artur Szostak <artursz@iafrica.com>
+
+template <class EventHandler>
+class AliMUONTrackerDDLDecoder
+{
+public:
+
+       /// Default contructor.
+       AliMUONTrackerDDLDecoder() :
+               fExitOnError(true), fTryRecover(false),
+               fSendDataOnParityError(false), fHadError(false),
+               fMaxBlocks(2), fMaxDSPs(5), fMaxBusPatches(5), fHandler()
+       {}
+       
+       /// Constant method to return the event handler instance.
+       const EventHandler& GetHandler() const { return fHandler; }
+       
+       /// Returns the event handler instance.
+       EventHandler& GetHandler() { return fHandler; }
+       
+       /// Returns the "exit on error" flag.
+       /// i.e. should the decoder stop on the very first error found.
+       bool ExitOnError() const { return fExitOnError; }
+       
+       /// Sets the "exit on error" flag.
+       /// i.e. should the decoder stop on the very first error found.
+       void ExitOnError(bool value) { fExitOnError = value; }
+       
+       /// Returns the "try to recover from errors" flag.
+       /// i.e. should the decoder try to recover from errors found in the
+       /// payload headers.
+       bool TryRecover() const { return fTryRecover; }
+       
+       /// Sets the "try to recover from errors" flag.
+       /// i.e. should the decoder try to recover from errors found in the
+       /// payload headers.
+       void TryRecover(bool value) { fTryRecover = value; }
+       
+       /// Returns the flag indicating if the raw data words in the bus patches
+       /// that failed their parity tests (i.e. parity error / bit flip in the
+       /// raw data word) will be sent to the event handler anyway through OnData.
+       bool SendDataOnParityError() const { return fSendDataOnParityError; }
+       
+       /// Sets the flag indicating if the raw data words in the bus patches
+       /// that failed their parity tests (i.e. parity error / bit flip in the
+       /// raw data word) will be sent to the event handler anyway through OnData.
+       void SendDataOnParityError(bool value) { fSendDataOnParityError = value; }
+       
+       /// Returns the maximum block count expected in the DDL payload.
+       UInt_t MaxBlocks() const { return fMaxBlocks; }
+       
+       /// Sets the maximum block count expected in the DDL payload.
+       void MaxBlocks(UInt_t n) { fMaxBlocks = n; }
+       
+       /// Returns the maximum DSP header count expected in any given block
+       /// structure within the DDL payload.
+       UInt_t MaxDSPs() const { return fMaxDSPs; }
+       
+       /// Sets the maximum DSP header count expected in any given block structure
+       /// within the DDL payload.
+       void MaxDSPs(UInt_t n) { fMaxDSPs = n; }
+       
+       /// Returns the maximum number of bus patches expected in any given DSP
+       /// structure within the DDL payload.
+       UInt_t MaxBusPatches() const { return fMaxBusPatches; }
+       
+       /// Sets the maximum number of bus patches expected in any given DSP
+       /// structure within the DDL payload.
+       void MaxBusPatches(UInt_t n) { fMaxBusPatches = n; }
+       
+       /// This method decodes the DDL payload contained in the buffer.
+       bool Decode(const void* buffer, UInt_t bufferSize);
+       
+private:
+
+       bool fExitOnError; ///< Indicates if we should exit on the very first error.
+       bool fTryRecover; ///< Indicates if we should try recover from a corrupt structure header.
+       bool fSendDataOnParityError; ///< If set to true then we issue a OnData() event even if the data word had a parity error.
+       bool fHadError; ///< Indicates if we had an error decoding the data.
+       UInt_t fMaxBlocks; ///< Maximum number of block structures allowed in a DDL stream.
+       UInt_t fMaxDSPs; ///< Maximum number of DSP structures allowed in a DDL stream.
+       UInt_t fMaxBusPatches; ///< Maximum number of bus patch structures allowed in a DDL stream.
+       EventHandler fHandler; ///< The event handler which deals with parsing events.
+
+       bool DecodeBlockData(
+                       const AliMUONBlockHeaderStruct* blockHeader,
+                       const UChar_t* start, const UChar_t* end
+               );
+
+       bool DecodeDSPData(const UChar_t* start, const UChar_t* end);
+       
+       bool DecodeBusPatchData(const UChar_t* start, const UChar_t* end);
+
+       /// Possible results that can be returned by the TryRecoverStruct method.
+       enum RecoverResult
+       {
+               kRecoverFailed,        ///< The recovery failed. Cannot continue parsing.
+               kStructRecovered,      ///< Indicates that we recovered from a corrupt structure header and can continue processing the given structure.
+               kContinueToNextStruct  ///< Must continue parsing the next structure and ignore the current one.
+       };
+
+       RecoverResult TryRecoverStruct(
+                       UInt_t expectedKey,
+                       UInt_t headerSize,
+                       UInt_t totalLength,
+                       UInt_t length,
+                       const UChar_t* structStart,
+                       const UChar_t* bufferEnd,
+                       const UChar_t*& dataEnd,
+                       const UChar_t*& structEnd,
+                       const UChar_t*& current
+               );
+       
+       const UChar_t* FindKey(
+                       UInt_t key, const UChar_t* start, const UChar_t* end
+               );
+       
+       bool ParityIsOk(UInt_t data);
+       
+       static const UInt_t fgkBlockDataKey;     ///< The key word expected to identify block structure headers.
+       static const UInt_t fgkDSPDataKey;       ///< The key word expected to identify DSP structure headers.
+       static const UInt_t fgkBusPatchDataKey;  ///< The key word expected to identify bus patch headers.
+       static const UInt_t fgkPaddingWord;      ///< The expected format of the padding word in the DDL payload.
+};
+
+//_____________________________________________________________________________
+
+// The following are the structure header keys which are used to identify the kind
+// of structure header we are dealing with: block, DSP or bus patch header.
+template <class EventHandler>
+const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkBlockDataKey = 0xFC0000FC;
+template <class EventHandler>
+const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkDSPDataKey = 0xF000000F;
+template <class EventHandler>
+const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkBusPatchDataKey = 0xB000000B;
+template <class EventHandler>
+const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkPaddingWord = 0xBEEFFACE;
+
+
+inline const char* AliMUONTrackerDDLDecoderEventHandler::ErrorCodeToString(ErrorCode code)
+{
+       /// This is a utility method which converts an error code to a string
+       /// representation for printing purposes.
+       /// \param code  The error code as received in OnError for example.
+       /// \return  An ANSI string containing the name of the error code symbol.
+       
+       switch (code)
+       {
+       case kNoError: return "kNoError";
+       case kBufferTooBig: return "kBufferTooBig";
+       case kTooManyBlocks: return "kTooManyBlocks";
+       case kTooManyDSPs: return "kTooManyDSPs";
+       case kTooManyBusPatches: return "kTooManyBusPatches";
+       case kNoBlockHeader: return "kNoBlockHeader";
+       case kBadBlockKey: return "kBadBlockKey";
+       case kBadBlockLength: return "kBadBlockLength";
+       case kBadBlockTotalLength: return "kBadBlockTotalLength";
+       case kBlockLengthMismatch: return "kBlockLengthMismatch";
+       case kNoDSPHeader: return "kNoDSPHeader";
+       case kBadDSPKey: return "kBadDSPKey";
+       case kBadDSPLength: return "kBadDSPLength";
+       case kBadDSPTotalLength: return "kBadDSPTotalLength";
+       case kDSPLengthMismatch: return "kDSPLengthMismatch";
+       case kNoBusPatchHeader: return "kNoBusPatchHeader";
+       case kBadBusPatchKey: return "kBadBusPatchKey";
+       case kBadBusPatchLength: return "kBadBusPatchLength";
+       case kBadBusPatchTotalLength: return "kBadBusPatchTotalLength";
+       case kBusPatchLengthMismatch: return "kBusPatchLengthMismatch";
+       case kGlitchFound: return "kGlitchFound";
+       case kBadPaddingWord: return "kBadPaddingWord";
+       case kParityError: return "kParityError";
+       default: return "INVALID";
+       }
+}
+
+
+inline const char* AliMUONTrackerDDLDecoderEventHandler::ErrorCodeToMessage(ErrorCode code)
+{
+       /// This is a utility method which converts an error code to user friendly
+       /// descriptive message useful for printing to the screen.
+       /// \param code  The error code as received in OnError for example.
+       /// \return  An ANSI string containing a descriptive message of the error.
+       
+       switch (code)
+       {
+       case kNoError:
+               return "Decoding was successful.";
+       case kBufferTooBig:
+               return "The DDL raw data is larger than indicated by the headers;"
+                      " extra bytes are probably just garbage.";
+       case kTooManyBlocks:
+               return "Too many block structures found.";
+       case kTooManyDSPs:
+               return "Too many DSP structures found in the block.";
+       case kTooManyBusPatches:
+               return "Too many bus patch structures found in the DSP structure.";
+       case kNoBlockHeader:
+               return "Missing a block header.";
+       case kBadBlockKey:
+               return "The block header key word does not contain the correct value.";
+       case kBadBlockLength:
+               return "The block length field points past the end of the raw data size.";
+       case kBadBlockTotalLength:
+               return "The total block length field points past the end of the"
+                      " raw data size.";
+       case kBlockLengthMismatch:
+               return "The block length and total length fields do not correspond."
+                      " One or both of these values is incorrect.";
+       case kNoDSPHeader:
+               return "Missing a DSP header.";
+       case kBadDSPKey:
+               return "The DSP header key word does not contain the correct value.";
+       case kBadDSPLength:
+               return "The DSP structure length field points past the end of the"
+                      " block structure.";
+       case kBadDSPTotalLength:
+               return "The total DSP structure length field points past the end of"
+                      " the block structure.";
+       case kDSPLengthMismatch:
+               return "The DSP structure length and total length fields do not"
+                      " correspond. One or both of these values is incorrect.";
+       case kNoBusPatchHeader:
+               return "Missing a bus patch header.";
+       case kBadBusPatchKey:
+               return "The bus patch header key word does not contain the correct value.";
+       case kBadBusPatchLength:
+               return "The bus patch length field points past the end of the"
+                      " DSP structure.";
+       case kBadBusPatchTotalLength:
+               return "The total bus patch length field points past the end of"
+                      " the DSP structure.";
+       case kBusPatchLengthMismatch:
+               return "The bus patch length and total length fields do not correspond."
+                      " One or both of these values is incorrect.";
+       case kGlitchFound:
+               return "Found a glitch. This means a 1 byte word has been randomly"
+                      " inserted into the raw data by mistake.";
+       case kBadPaddingWord:
+               return "The padding word does not contain the correct value.";
+       case kParityError:
+               return "Found a parity error in the data word.";
+       default:
+               return "Unknown error code!";
+       }
+}
+
+
+inline std::ostream& operator << (std::ostream& os, AliMUONTrackerDDLDecoderEventHandler::ErrorCode code)
+{
+       /// This is the stream operator for std::ostream classes to be able to
+       /// easily write the error messages associated with the error codes generated
+       /// by the decoder to 'cout' or 'cerr' for example.
+       
+       os << AliMUONTrackerDDLDecoderEventHandler::ErrorCodeToMessage(code);
+       return os;
+}
+
+
+template <class EventHandler>
+bool AliMUONTrackerDDLDecoder<EventHandler>::Decode(const void* buffer, UInt_t bufferSize)
+{
+       /// This method should be called to actually decode the DDL payload
+       /// contained in a memory buffer. The payload should be for a muon tracking
+       /// chamber DDL stream.
+       /// As the decoder progresses it will make method calls to the event handler
+       /// instance (which can be accessed with the GetHandler() method) to indicate
+       /// the start of the new block, DSP and bus patch headers. For every raw
+       /// data word the OnData method of the event handler is called.
+       ///
+       /// If an error occurs during the parse because the data is corrupt then
+       /// the OnError method is called indicating what the problem was.
+       /// Decoding will stop at this point unless the fExitOnError flag is set
+       /// to false. Also raw data words which contain a parity error are only
+       /// sent to the event handler with OnData if the fSendDataOnParityError
+       /// flag is set to true. There is also an optional flag fTryRecover which
+       /// can enable logic which will attempt to recover the header structures found
+       /// in the DDL payload if they are found to be inconsistent (assumed corrupt).
+       ///
+       /// \param buffer  This is the pointer to the start of the memory buffer
+       ///     containing the DDL payload. Remember that this must be the start of
+       ///     the payload and not the DDL stream. That is, this pointer should be
+       ///     equal to: DDL start pointer + 8 * sizeof(UInt_t).
+       /// \param bufferSize  This is the pointer to the first byte just past the
+       ///     end of the block structure.
+       /// \return Returns false if there was any problem with decoding the data,
+       ///     and true otherwise. Note: the data may have been partially decoded
+       ///     even if false was returned, which would be indicated by at least one
+       ///     call to the event handlers OnData method.
+       
+       assert( buffer != NULL );
+       
+       fHadError = false;
+       
+       // We are basically implementing something like a recursive decent parser.
+       // So start by marking the current buffer position and end of buffer.
+       const UChar_t* current = reinterpret_cast<const UChar_t*>(buffer);
+       const UChar_t* end = current + bufferSize;
+       
+       // Signal a new buffer event.
+       fHandler.OnNewBuffer(buffer, bufferSize);
+
+       UInt_t blockCount = 0; // Indicates the number of blocks decoded.
+       while (current < end)
+       {
+               // Mark the start of the block structure.
+               const UChar_t* blockStart = current;
+               
+               // Get the block header, move the current pointer just past the end
+               // of the header and check that we have not overflowed the buffer.
+               const AliMUONBlockHeaderStruct* blockHeader
+                       = reinterpret_cast<const AliMUONBlockHeaderStruct*>(blockStart);
+               current += sizeof(AliMUONBlockHeaderStruct);
+               if (current > end)
+               {
+                       // So we only got part of a block header at the very end
+                       // of the buffer. Nothing to do but report the error and exit.
+                       if (blockCount == fMaxBlocks)
+                               // Special case where we got all the blocks we
+                               // expected, so the remaining data must be rubbish.
+                               fHandler.OnError(EventHandler::kBufferTooBig, blockHeader);
+                       else
+                               fHandler.OnError(EventHandler::kNoBlockHeader, blockHeader);
+                       return false;
+               }
+               
+               // The header fits the buffer so we can mark the data start and
+               // read from the header to find the end of data and block pointers.
+               const UChar_t* dataStart = current;
+               current += blockHeader->fLength * sizeof(UInt_t);
+               const UChar_t* dataEnd = current;
+               const UChar_t* blockEnd = blockStart
+                       + blockHeader->fTotalLength * sizeof(UInt_t);
+               
+               // Now we need to check for the following things:
+               // 1) Is the end of block or end of data pointer outside the buffer
+               //    boundaries.
+               // 2) Are the values for these pointers the same.
+               // 3) Is the expected data key in the header present.
+               // If any of the above fail then we know there is a problem with
+               // the block header. It must be corrupted somehow.
+               if (blockHeader->fDataKey != fgkBlockDataKey
+                   or dataEnd > end or blockEnd > end or dataEnd != blockEnd)
+               {
+                       // So let us see what exactly is wrong and report this.
+                       if (blockCount == fMaxBlocks)
+                       {
+                               // Special case where we got all the blocks we
+                               // expected, so the remaining data must be rubbish.
+                               // Don't even bother trying to recover the data.
+                               fHandler.OnError(EventHandler::kBufferTooBig, blockHeader);
+                               return false;
+                       }
+                       if (blockHeader->fDataKey != fgkBlockDataKey)
+                               fHandler.OnError(EventHandler::kBadBlockKey, &blockHeader->fDataKey);
+                       if (blockEnd > end)
+                               fHandler.OnError(EventHandler::kBadBlockLength, &blockHeader->fLength);
+                       if (dataEnd > end)
+                               fHandler.OnError(EventHandler::kBadBlockTotalLength, &blockHeader->fTotalLength);
+                       if (dataEnd != blockEnd)
+                               fHandler.OnError(EventHandler::kBlockLengthMismatch, blockHeader);
+                       
+                       // Stop the decoding if so requested by the user, otherwise
+                       // remember about the error so that we return false from this
+                       // routine and continue decoding.
+                       if (fExitOnError)
+                               return false;
+                       else
+                               fHadError = true;
+                       
+                       // Try to recover from the corrupt header.
+                       RecoverResult result = TryRecoverStruct(
+                                       fgkBlockDataKey, sizeof(AliMUONBlockHeaderStruct),
+                                       blockHeader->fTotalLength, blockHeader->fLength,
+                                       blockStart, end, dataEnd, blockEnd, current
+                               );
+                       if (result == kContinueToNextStruct)
+                               continue; // Try the next block at 'current'.
+                       if (result == kRecoverFailed) return false;
+               }
+               
+               // At this point we certainly have a valid block header, so we
+               // need to check if we have more blocks than we expected. If not
+               // then we can indicate we have another block and decode its data.
+               if (++blockCount > fMaxBlocks)
+               {
+                       fHandler.OnError(EventHandler::kTooManyBlocks, current);
+                       
+                       // In this case we stop the decoding because clearly
+                       // something is seriously wrong with the data if we are
+                       // getting more blocks than expected.
+                       return false;
+               }
+               
+               fHandler.OnNewBlock(blockHeader, dataStart);
+               if (DecodeBlockData(blockHeader, dataStart, dataEnd)) continue;
+               
+               // At this point we had a problem decoding the block structure's
+               // data. Thus we should stop further decoding if so requested by
+               // the user. Note the fHadError flag is already marked inside
+               // DecodeBlockData.
+               if (fExitOnError) return false;
+       }
+       
+       return not fHadError;
+}
+
+
+template <class EventHandler>
+bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeBlockData(
+               const AliMUONBlockHeaderStruct* blockHeader,
+               const UChar_t* start, const UChar_t* end
+       )
+{
+       /// This method decodes a block structure's data payload. It unpacks the
+       /// DSP structures contained inside and then for each DSP it calls the
+       /// OnNewDSP method for the event handler to signal the start of each new
+       /// DSP structure.
+       /// \param blockHeader
+       /// \param start  This is the pointer to the start of the block
+       ///               structure's data.
+       /// \param end  This is the pointer to the first byte just past the
+       ///             end of the block structure.
+       /// \return If the block structure's data was decoded without errors
+       ///      or we could recover from the errors, then true is returned.
+       ///      False is returned otherwise.
+       
+       const UChar_t* current = start;
+       
+       UInt_t dspCount = 0; // Indicates the number of DSPs decoded.
+       while (current < end)
+       {
+               // Mark the start of the DSP structure.
+               const UChar_t* dspStart = current;
+               
+               // Get the DSP header, move the current pointer just past the end
+               // of the header and check that we have not overflowed the buffer.
+               const AliMUONDSPHeaderStruct* dspHeader
+                       = reinterpret_cast<const AliMUONDSPHeaderStruct*>(dspStart);
+               current += sizeof(AliMUONDSPHeaderStruct);
+               if (current > end)
+               {
+                       // So we only got part of a DSP header at the very end of
+                       // the block structure buffer. Nothing to do but report the
+                       // error and exit. Set fHadError in case of further decoding.
+                       fHandler.OnError(EventHandler::kNoDSPHeader, dspHeader);
+                       fHadError = true;
+                       return false;
+               }
+               
+               // The header fits the buffer so we can mark the data start and
+               // read from the header to find the end of data and DSP pointers.
+               const UChar_t* dataStart = current;
+               current += dspHeader->fLength * sizeof(UInt_t);
+               const UChar_t* dataEnd = current;
+               const UChar_t* dspEnd = dspStart + dspHeader->fTotalLength * sizeof(UInt_t);
+               
+               // Now we need to check for the following things:
+               // 1) Is the end of DSP or end of data pointer outside the buffer
+               //    boundaries.
+               // 2) Are the values for these pointers the same.
+               // 3) Is the expected data key in the header present.
+               // If any of the above fail then we know there is a problem with
+               // the DSP header. It must be corrupted somehow.
+               if (dspHeader->fDataKey != fgkDSPDataKey
+                   or dataEnd > end or dspEnd > end or dataEnd != dspEnd)
+               {
+                       // So let us see what exactly is wrong and report this.
+                       if (dspHeader->fDataKey != fgkDSPDataKey)
+                               fHandler.OnError(EventHandler::kBadDSPKey, &dspHeader->fDataKey);
+                       if (dspEnd > end)
+                               fHandler.OnError(EventHandler::kBadDSPLength, &dspHeader->fLength);
+                       if (dataEnd > end)
+                               fHandler.OnError(EventHandler::kBadDSPTotalLength, &dspHeader->fTotalLength);
+                       if (dataEnd != dspEnd)
+                               fHandler.OnError(EventHandler::kDSPLengthMismatch, dspHeader);
+                       
+                       // Indicate we had and error and stop the decoding if so
+                       // requested by the user.
+                       fHadError = true;
+                       if (fExitOnError) return false;
+                       
+                       // Try to recover from the corrupt header.
+                       RecoverResult result = TryRecoverStruct(
+                                       fgkDSPDataKey, sizeof(AliMUONDSPHeaderStruct),
+                                       dspHeader->fTotalLength, dspHeader->fLength,
+                                       dspStart, end, dataEnd, dspEnd, current
+                               );
+                       if (result == kContinueToNextStruct)
+                               continue; // Try the next DSP at 'current'.
+                       if (result == kRecoverFailed) return false;
+               }
+               
+               // At this point we certainly have a valid DSP header, so we
+               // need to check if we have more DSPs than we expected. If not
+               // then we can indicate we have another DSP and decode its data.
+               if (++dspCount > fMaxDSPs)
+               {
+                       fHandler.OnError(EventHandler::kTooManyDSPs, current);
+                       
+                       // In this case we stop further decoding of the block
+                       // structure data because clearly something is seriously
+                       // wrong if we are getting more DSPs than expected.
+                       // Indicate that we had an error so the Decode() method
+                       // returns false.
+                       fHadError = true;
+                       return false;
+               }
+               
+               fHandler.OnNewDSP(dspHeader, dataStart);
+               
+               // Check the error word in the header.
+               if (dspHeader->fErrorWord == (0x000000B1 | blockHeader->fDSPId)
+                   or dspHeader->fErrorWord == (0x00000091 | blockHeader->fDSPId)
+                  )
+               {
+                       // An event with a glitch in the readout has been detected.
+                       // It means that somewhere a 1 byte word has been randomly
+                       // inserted and all the readout sequence is shifted until
+                       // the next event.
+                       fHandler.OnError(EventHandler::kGlitchFound, &dspHeader->fErrorWord);
+                       fHadError = true;
+                       if (fExitOnError) return false;
+                       
+                       // Try recover by finding the very next DSP and continue
+                       // decoding from there. Note: to achieve all we have to do
+                       // is continue to the next iteration, because the logic
+                       // will land up calling the FindKey method within the
+                       // TryRecoverStruct method above.
+                       if (fTryRecover) continue;
+               }
+               
+               // Check if we are padding. If we are, then the bus patch data is
+               // actually 4 bytes smaller and the last word is a padding word.
+               if (dspHeader->fPaddingWord == 1)
+               {
+                       dataEnd -= sizeof(UInt_t);
+                       
+                       // Check the pad word is correct.
+                       const UInt_t* padWord = reinterpret_cast<const UInt_t*>(dataEnd);
+                       if (*padWord != fgkPaddingWord)
+                       {
+                               fHandler.OnError(EventHandler::kBadPaddingWord, padWord);
+                               fHadError = true;
+                               if (fExitOnError) return false;
+                       }
+               }
+               
+               if (DecodeDSPData(dataStart, dataEnd)) continue;
+               
+               // At this point we had a problem decoding the DSP structure's
+               // data, thus we should stop further decoding if so requested by
+               // the user. Note the fHadError flag is already marked inside
+               // DecodeDSPData.
+               if (fExitOnError) return false;
+       }
+       
+       return true;
+}
+
+
+template <class EventHandler>
+bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeDSPData(
+               const UChar_t* start, const UChar_t* end
+       )
+{
+       /// This method decodes a DSP structure's data payload. It finds all the
+       /// bus patches found inside and for each it calls the OnNewBusPatch method
+       /// for the event handler to signal the start of each new bus patch.
+       /// \param start  This is the pointer to the start of the DSP structure's data.
+       /// \param end  This is the pointer to the first byte just past the
+       ///             end of the DSP structure.
+       /// \return If the DSP structure's data was decoded without errors
+       ///      or we could recover from the errors, then true is returned.
+       ///      False is returned otherwise.
+       
+       const UChar_t* current = start;
+       
+       UInt_t busPatchCount = 0; // Indicates the number of bus patches decoded.
+       while (current < end)
+       {
+               // Mark the start of the bus patch structure.
+               const UChar_t* busPatchStart = current;
+               
+               // Get the bus patch header, move the current pointer just past
+               // the end of the header and check that we have not overflowed
+               // the buffer.
+               const AliMUONBusPatchHeaderStruct* busPatchHeader
+                       = reinterpret_cast<const AliMUONBusPatchHeaderStruct*>(busPatchStart);
+               current += sizeof(AliMUONBusPatchHeaderStruct);
+               if (current > end)
+               {
+                       // So we only got part of a bus patch header at the very
+                       // end of the DSP structure buffer. Nothing to do but
+                       // report the error and exit. Set fHadError in case of
+                       // further decoding.
+                       fHandler.OnError(EventHandler::kNoBusPatchHeader, busPatchHeader);
+                       fHadError = true;
+                       return false;
+               }
+               
+               // The header fits the buffer so we can mark the data start and
+               // read from the header to find the end of data and bus patch
+               // structure pointers.
+               const UChar_t* dataStart = current;
+               current += busPatchHeader->fLength * sizeof(UInt_t);
+               const UChar_t* dataEnd = current;
+               const UChar_t* busPatchEnd = busPatchStart
+                       + busPatchHeader->fTotalLength * sizeof(UInt_t);
+               
+               // Now we need to check for the following things:
+               // 1) Is the end of bus patch structure or end of data pointer
+               //    outside the buffer boundaries.
+               // 2) Are the values for these pointers the same.
+               // 3) Is the expected data key in the header present.
+               // If any of the above fail then we know there is a problem with
+               // the bus patch header. It must be corrupted somehow.
+               if (busPatchHeader->fDataKey != fgkBusPatchDataKey
+                   or dataEnd > end or busPatchEnd > end or dataEnd != busPatchEnd)
+               {
+                       // So let us see what exactly is wrong and report this.
+                       if (busPatchHeader->fDataKey != fgkBusPatchDataKey)
+                               fHandler.OnError(EventHandler::kBadBusPatchKey, &busPatchHeader->fDataKey);
+                       if (busPatchEnd > end)
+                               fHandler.OnError(EventHandler::kBadBusPatchLength, &busPatchHeader->fLength);
+                       if (dataEnd > end)
+                               fHandler.OnError(EventHandler::kBadBusPatchTotalLength, &busPatchHeader->fTotalLength);
+                       if (dataEnd != busPatchEnd)
+                               fHandler.OnError(EventHandler::kBusPatchLengthMismatch, busPatchHeader);
+                       
+                       // Indicate we had and error and stop the decoding if so
+                       // requested by the user.
+                       fHadError = true;
+                       if (fExitOnError) return false;
+                       
+                       // Try to recover from the corrupt header.
+                       RecoverResult result = TryRecoverStruct(
+                                       fgkBusPatchDataKey, sizeof(AliMUONBusPatchHeaderStruct),
+                                       busPatchHeader->fTotalLength, busPatchHeader->fLength,
+                                       busPatchStart, end, dataEnd, busPatchEnd, current
+                               );
+                       if (result == kContinueToNextStruct)
+                               continue; // Try the next bus patch at 'current'.
+                       if (result == kRecoverFailed) return false;
+               }
+               
+               // At this point we certainly have a valid bus patch header, so
+               // we need to check if we have more bus patches than we expected.
+               // If not then we can indicate we have another bus patch and
+               // decode its data.
+               if (++busPatchCount > fMaxBusPatches)
+               {
+                       fHandler.OnError(EventHandler::kTooManyBusPatches, current);
+                       
+                       // In this case we stop further decoding of the DSP
+                       // structure's data because clearly something is seriously
+                       // wrong if we are getting more bus patches than expected.
+                       // Indicate that we had an error so the Decode() method
+                       // returns false.
+                       fHadError = true;
+                       return false;
+               }
+               
+               fHandler.OnNewBusPatch(busPatchHeader, dataStart);
+               if (DecodeBusPatchData(dataStart, dataEnd)) continue;
+               
+               // At this point we had a problem decoding the bus patch data,
+               // thus we should stop further decoding if so requested by the
+               // user. Note the fHadError flag is already marked inside
+               // DecodeBusPatchData.
+               if (fExitOnError) return false;
+       }
+       
+       return true;
+}
+
+
+template <class EventHandler>
+bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeBusPatchData(
+               const UChar_t* start, const UChar_t* end
+       )
+{
+       /// This method decodes a single bus patch's data payload.
+       /// It will check the parity of the raw data words and send them
+       /// to the event handler instance with calls to OnData.
+       /// \param start  This is the pointer to the start of the bus patch
+       ///               structure's data.
+       /// \param end  This is the pointer to the first byte just past the
+       ///             end of the bus patch structure.
+       /// \return If the bus patch's data was decoded without errors
+       ///      or we could recover from the errors, then true is returned.
+       ///      False is returned otherwise.
+
+       // Assert that 'end' is always larger than start by n*sizeof(UInt_t)
+       // where n is a positive integer. This should be the case because we
+       // always add multiples of sizeof(UInt_t) to the 'current' pointer in
+       // all the DecodeXYZ methods.
+       assert( UInt_t(end - start) % 4 == 0 );
+       
+       // Now step through all the data words and issue OnData events.
+       // We also need to check parity and signal OnError if it is not valid
+       // for any of the data words.
+       const UInt_t* data = reinterpret_cast<const UInt_t*>(start);
+       const UInt_t* dataEnd = reinterpret_cast<const UInt_t*>(end);
+       for (; data < dataEnd; data++)
+       {
+               if (ParityIsOk(*data))
+               {
+                       fHandler.OnData(*data);
+               }
+               else
+               {
+                       // Indicate we had a parity error and exit immediately
+                       // if the user so requested.
+                       fHandler.OnError(EventHandler::kParityError, data);
+                       fHadError = true;
+                       if (fExitOnError) return false;
+                       
+                       if (fSendDataOnParityError)
+                               fHandler.OnData(*data);
+               }
+       }
+       
+       return true;
+}
+
+
+template <class EventHandler>
+typename AliMUONTrackerDDLDecoder<EventHandler>::RecoverResult
+AliMUONTrackerDDLDecoder<EventHandler>::TryRecoverStruct(
+               UInt_t expectedKey,
+               UInt_t headerSize,
+               UInt_t totalLength,
+               UInt_t length,
+               const UChar_t* structStart,
+               const UChar_t* bufferEnd,
+               const UChar_t*& dataEnd,
+               const UChar_t*& structEnd,
+               const UChar_t*& current
+       )
+{
+       /// This method attempts to recover from a corrupt structure header by
+       /// figuring out which of the structure size indicators is correct.
+       /// This is possible because each header has some redundant information.
+       /// The recovery procedure is only attempted if fTryRecover was set to
+       /// true. If the recovery procedure is successful then this method will
+       /// also update the pointers indicating the start of data, end of structure
+       /// and current parsing position with the correct values.
+       ///
+       /// [in]  \param expectedKey This is the expected block key for the header
+       ///           currently being processed.
+       /// [in]  \param headerSize  The expected header size as given by the sizeof
+       ///           operator for example.
+       /// [in]  \param totalLength The total length as given by the fTotalLength
+       ///           field in the current header being handled.
+       /// [in]  \param length  The data length as given by the fLength field
+       ///           in the current header being handled.
+       /// [in]  \param structStart A pointer to the start of the structure header.
+       /// [in]  \param bufferEnd A pointer to the first byte just past the end
+       ///           of the buffer. This could be the pointer to the first byte
+       ///           just past the end of the parent structure if we are dealing
+       ///           with a DSP structure or bus patch. The parent structure for
+       ///           the DSP is a block structure and for a bus patch it is a DSP.
+       /// [out] \param dataEnd This is the pointer to the first byte just past
+       ///           the end of the structure being processed. It should be equal to
+       ///           structStart + sizeof(structure header) + fLength, where fLength
+       ///           is the field found in the structure's header itself. This value
+       ///           will be corrected and updated if we could recover from the
+       ///           corruption in the header.
+       /// [out] \param structEnd A pointer to the first byte just past the end of
+       ///           the structure. This value should be set equal to
+       ///           structStart + fTotalLength * sizeof(UInt_t), where fTotalLength
+       ///           is the field found in the structure's header itself. This value
+       ///           will be corrected and updated if we could recover from the
+       ///           corruption in the header.
+       /// [out] \param current This is the pointer to the current location in
+       ///           the DDL payload being parsed. It should in principle point
+       ///           to the start of the structures data. This value will be
+       ///           corrected and updated if we could recover from the corruption
+       ///           in the header.
+       ///
+       /// \return Returns the result of the recovery attempt, which can be one
+       ///    of the following:
+       ///      kRecoverFailed - The recovery failed completely so the caller
+       ///           cannot continue parsing any more structures. If the failure
+       ///           is within a DSP then one could still continue parsing
+       ///           from the next block. Similarly for bus patches, parsing could
+       ///           continue from the next DSP structure.
+       ///      kStructRecovered - Indicates that we recovered from a corrupt
+       ///           structure header and can continue processing the data of the
+       ///           structure in question.
+       ///      kContinueToNextStruct - Either fTryRecover was set to false or we
+       ///           could not recover from the corrupt header but we did find the
+       ///           start of another header matching the expected key so parsing
+       ///           can continue from the updated current position.
+
+       // Check if the user wants us to try and recover from a corrupt header.
+       if (not fTryRecover) return kContinueToNextStruct;
+       
+       // If the user wants us to try recover, then try to recover what the
+       // correct values for dataEnd, structEnd and current were supposed to be.
+       // The recovery procedure is as follows: We have 4 conditions for a correct
+       // header:
+       //   1) The header key is what we expect.
+       //   2) The totalLength equals length + headerSize.
+       //   3) The word at dataEnd contains a valid key. (implies length is
+       //      correct.)
+       //   4) The word at structEnd contains a valid key. (implies totalLength
+       //      is correct.)
+       // If any 2 of these conditions hold then we know that only one of the
+       // header fields is corrupt and we have enough information to reconstruct
+       // the third field. Note that if conditions 3 and 4 are true then this
+       // implies 2 is also true. (not necessarily the other way around though.)
+       // The valid key mentioned above at dataEnd and structEnd should be:
+       //   a) A bus patch key, DSP key or end of buffer if expectedKey indicates
+       //      a buspatch.
+       //   b) A DSP key, block structure key or end of buffer if expectedKey
+       //      indicates a DSP.
+       //   c) A block structure key or end of buffer if expectedKey indicates
+       //      a DSP.
+       const UInt_t* headerKey = reinterpret_cast<const UInt_t*>(structStart);
+       bool headerKeyOk = (expectedKey == *headerKey);
+       
+       bool lengthsMatch = (totalLength == length + headerSize);
+       
+       bool lengthIsCorrect = false;
+       bool totalLengthIsCorrect = false;
+       const UInt_t* keyAtDataEnd = reinterpret_cast<const UInt_t*>(dataEnd);
+       const UInt_t* keyAtStructEnd = reinterpret_cast<const UInt_t*>(structEnd);
+       
+       switch (expectedKey)
+       {
+       case fgkBlockDataKey:
+               if (dataEnd == bufferEnd)
+               {
+                       // Are we at the end of the buffer?
+                       lengthIsCorrect = true;
+               }
+               else
+               {
+                       // Must check that we can read another 4 bytes before
+                       // checking the key at dataEnd.
+                       if (dataEnd + sizeof(UInt_t) <= bufferEnd)
+                       {
+                               if (*keyAtDataEnd == fgkBlockDataKey)
+                                       lengthIsCorrect = true;
+                       }
+               }
+               
+               if (structEnd == bufferEnd)
+               {
+                       // Are we at the end of the buffer?
+                       totalLengthIsCorrect = true;
+               }
+               else
+               {
+                       // Must check that we can read another 4 bytes before
+                       // checking the key at structEnd.
+                       if (structEnd + sizeof(UInt_t) <= bufferEnd)
+                       {
+                               if (*keyAtStructEnd == fgkBlockDataKey)
+                                       totalLengthIsCorrect = true;
+                       }
+               }
+                       
+               break;
+       
+       case fgkDSPDataKey:
+               if (dataEnd == bufferEnd)
+               {
+                       // Are we at the end of the buffer?
+                       lengthIsCorrect = true;
+               }
+               else
+               {
+                       // Must check that we can read another 4 bytes before
+                       // checking the key at dataEnd.
+                       if (dataEnd + sizeof(UInt_t) <= bufferEnd)
+                       {
+                               if (*keyAtDataEnd == fgkBlockDataKey
+                                   or *keyAtDataEnd == fgkDSPDataKey)
+                                       lengthIsCorrect = true;
+                       }
+               }
+               
+               if (structEnd == bufferEnd)
+               {
+                       // Are we at the end of the buffer?
+                       totalLengthIsCorrect = true;
+               }
+               else
+               {
+                       // Must check that we can read another 4 bytes before
+                       // checking the key at structEnd.
+                       if (structEnd + sizeof(UInt_t) <= bufferEnd)
+                       {
+                               if (*keyAtStructEnd == fgkBlockDataKey
+                                   or *keyAtStructEnd == fgkDSPDataKey)
+                                       totalLengthIsCorrect = true;
+                       }
+               }
+                       
+               break;
+       
+       case fgkBusPatchDataKey:
+               if (dataEnd == bufferEnd)
+               {
+                       // Are we at the end of the buffer?
+                       lengthIsCorrect = true;
+               }
+               else
+               {
+                       // Must check that we can read another 4 bytes before
+                       // checking the key at dataEnd.
+                       if (dataEnd + sizeof(UInt_t) <= bufferEnd)
+                       {
+                               if (*keyAtDataEnd == fgkDSPDataKey
+                                   or *keyAtDataEnd == fgkBusPatchDataKey)
+                                       lengthIsCorrect = true;
+                       }
+               }
+               
+               if (structEnd == bufferEnd)
+               {
+                       // Are we at the end of the buffer?
+                       totalLengthIsCorrect = true;
+               }
+               else
+               {
+                       // Must check that we can read another 4 bytes before
+                       // checking the key at structEnd.
+                       if (structEnd + sizeof(UInt_t) <= bufferEnd)
+                       {
+                               if (*keyAtStructEnd == fgkDSPDataKey
+                                   or *keyAtStructEnd == fgkBusPatchDataKey)
+                                       totalLengthIsCorrect = true;
+                       }
+               }
+                       
+               break;
+               
+       default:
+               // lengthIsCorrect and totalLengthIsCorrect already set to false.
+               break;
+       }
+       
+       if (headerKeyOk and lengthIsCorrect)
+       {
+               // totalLength was wrong, dataEnd is correct.
+               structEnd = dataEnd;
+               current = dataEnd;
+               return kStructRecovered;
+       }
+       if (headerKeyOk and totalLengthIsCorrect)
+       {
+               // Length was wrong, structEnd is correct.
+               dataEnd = structEnd;
+               current = structEnd;
+               return kStructRecovered;
+       }
+       if (lengthsMatch and lengthIsCorrect and totalLengthIsCorrect)
+       {
+               // The header's key was wrong but the lengths and pointers are OK.
+               return kStructRecovered;
+       }
+       
+       // Could not recover the header from the available information, so find
+       // the next key in the stream that is the same as the currently expected
+       // one and continue decoding from there.
+       const UChar_t* location = FindKey(
+                       expectedKey, structStart + sizeof(UInt_t), bufferEnd
+               );
+       if (location != NULL)
+       {
+               current = location;
+               return kContinueToNextStruct;
+       }
+
+       return kRecoverFailed;
+}
+
+
+template <class EventHandler>
+const UChar_t* AliMUONTrackerDDLDecoder<EventHandler>::FindKey(
+               UInt_t key, const UChar_t* start, const UChar_t* end
+       )
+{
+       /// Searches for the first occurrence of the key value in the buffer marked by
+       /// 'start' and 'end'. 'start' should point to the start of the buffer and 'end'
+       /// should point to 'start + bufferSize', i.e. just past the last byte of the
+       /// buffer. If the key was found then the pointer to that location is returned
+       /// otherwise NULL is returned.
+       const UChar_t* current = start;
+       while (current + sizeof(UInt_t) <= end)
+       {
+               UInt_t data = * reinterpret_cast<const UInt_t*>(current);
+               if (data == key) return current;
+               current++;
+       }
+       return NULL;
+}
+
+
+template <class EventHandler>
+bool AliMUONTrackerDDLDecoder<EventHandler>::ParityIsOk(UInt_t data)
+{
+       /// Optimised parity check addapted from:
+       /// http://graphics.stanford.edu/~seander/bithacks.html#ParityParallel
+       
+       // parity of the 32 bits must be zero if the last bit is equal
+       // to the parity of the first 31 bits.
+       // Reason: the parity bit xor the parity of the first 31 bits must give
+       // zero, unless there was a bit error.
+       data ^= data >> 16;
+       data ^= data >> 8;
+       data ^= data >> 4;
+       data &= 0xf;
+       data = ((0x6996 >> data) & 1);
+       return data == 0;
+}
+
+#endif // ALIMUONTRACKERDDLDECODER_H
diff --git a/MUON/AliMUONTrackerDDLDecoderEventHandler.h b/MUON/AliMUONTrackerDDLDecoderEventHandler.h
new file mode 100644 (file)
index 0000000..6608f83
--- /dev/null
@@ -0,0 +1,231 @@
+#ifndef ALIMUONTRACKERDDLDECODEREVENTHANDLER_H
+#define ALIMUONTRACKERDDLDECODEREVENTHANDLER_H
+/**************************************************************************
+ * This file is property of and copyright by the ALICE HLT Project        *
+ * All rights reserved.                                                   *
+ *                                                                        *
+ * Primary Authors:                                                       *
+ *   Artur Szostak <artursz@iafrica.com>                                  *
+ *                                                                        *
+ * Permission to use, copy, modify and distribute this software and its   *
+ * documentation strictly for non-commercial purposes is hereby granted   *
+ * without fee, provided that the above copyright notice appears in all   *
+ * copies and that both the copyright notice and this permission notice   *
+ * appear in the supporting documentation. The authors make no claims     *
+ * about the suitability of this software for any purpose. It is          *
+ * provided "as is" without express or implied warranty.                  *
+ **************************************************************************/
+
+/* $Id$ */
+
+///
+/// \file   AliMUONTrackerDDLDecoderEventHandler.h
+/// \author Artur Szostak <artursz@iafrica.com>
+/// \date   28-11-2007
+/// \brief  Implementation of a high performance DDL decoder event handler 
+/// for the muon tracking stations.
+///
+
+#include <cassert>
+#include <ostream>
+#include <Rtypes.h>
+
+
+// We use C binding for the structures because C is more uniform with its application
+// binary interface (ABI) between compilers.
+extern "C"
+{
+
+// The following structures are the headers found in the DDL payload from the
+// muon tracking chambers. The specification is defined in ALICE-INT-2005-012
+// (https://edms.cern.ch/file/591904/1/ALICE-INT-2005-012.pdf)
+
+/// The block header structure of the Tracker DDL payload.
+struct AliMUONBlockHeaderStruct
+{
+       UInt_t     fDataKey;        ///< Data key word for CRT header 
+       UInt_t     fTotalLength;    ///< total length of block structure (w/o padding word)
+       UInt_t     fLength;         ///< length of raw data
+       UInt_t     fDSPId;          ///< DSP id
+       UInt_t     fL0Trigger;      ///< L0 trigger word
+       UInt_t     fMiniEventId;    ///< Bunch Crossing for mini-event id (see TDR chapter 8)
+       UInt_t     fEventId1;       ///< Event Id in bunch crossing
+       UInt_t     fEventId2;       ///< Event Id in orbit number
+};
+
+/// The DSP header structure of the Tracker DDL payload.
+struct AliMUONDSPHeaderStruct
+{
+       UInt_t     fDataKey;          ///< Data key word for FRT header 
+       UInt_t     fTotalLength;      ///< total length of block structure
+       UInt_t     fLength;           ///< length of raw data
+       UInt_t     fDSPId;            ///< DSP id
+       UInt_t     fBlkL1ATrigger;    ///< L1 accept in Block Structure (CRT)
+       UInt_t     fMiniEventId;      ///< Mini Event Id in bunch crossing 
+       UInt_t     fL1ATrigger;       ///< Number of L1 accept in DSP Structure (FRT)
+       UInt_t     fL1RTrigger;       ///< Number of L1 reject in DSP Structure (FRT)
+       UInt_t     fPaddingWord;      ///< padding dummy word for 64 bits transfer
+       UInt_t     fErrorWord;        ///< Error word
+};
+
+/// The bus patch header structure of the Tracker DDL payload.
+struct AliMUONBusPatchHeaderStruct
+{
+       UInt_t     fDataKey;       ///< Data key word for bus patch header 
+       UInt_t     fTotalLength;   ///< total length of bus patch structure
+       UInt_t     fLength;        ///< length of raw data
+       UInt_t     fBusPatchId;    ///< bus patch id
+};
+
+} // extern "C"
+
+
+/// \ingroup raw
+/// \class AliMUONTrackerDDLDecoderEventHandler
+/// \brief Callback event handler class for the AliMUONTrackerDDLDecoder.
+///
+/// This class is the base class defining what methods the event handler for the
+/// high performance decoder should have. This handler actually does nothing.
+/// The user of this decoder will have to derive from this class a custom event
+/// handler that actually does something within the callback methods OnNewBusPatch,
+/// OnData, OnError etc...
+///
+/// \author Artur Szostak <artursz@iafrica.com>
+
+class AliMUONTrackerDDLDecoderEventHandler
+{
+public:
+
+       /// The only reason for a virtual destructor is to make -Weffc++ shutup.
+       /// This should not really be here.
+       virtual ~AliMUONTrackerDDLDecoderEventHandler() {}
+
+       /// All the possible error codes for the parsing.
+       enum ErrorCode
+       {
+               kNoError = 0,                  /// Decoding was successful.
+               // Offset our error codes to stay clear of any common codes in AliMUONRawStreamTracker:
+               kBufferTooBig = 10,            /// The DDL raw data is larger than indicated by the headers; extra bytes are probably just garbage.
+               kTooManyBlocks = 11,           /// Too many block structures found.
+               kTooManyDSPs = 12,             /// Too many DSP structures found in the block.
+               kTooManyBusPatches = 13,       /// Too many bus patch structures found in the DSP structure.
+               kNoBlockHeader = 14,           /// Missing a block header.
+               kBadBlockKey = 15,             /// The block header key word does not contain the correct value.
+               kBadBlockLength = 16,          /// The block length field points past the end of the raw data size.
+               kBadBlockTotalLength = 17,     /// The total block length field points past the end of the raw data size.
+               kBlockLengthMismatch = 18,     /// The block length and total length fields do not correspond. One or both of these values is incorrect.
+               kNoDSPHeader = 19,             /// Missing a DSP header.
+               kBadDSPKey = 20,               /// The DSP header key word does not contain the correct value.
+               kBadDSPLength = 21,            /// The DSP structure length field points past the end of the block structure.
+               kBadDSPTotalLength = 22,       /// The total DSP structure length field points past the end of the block structure.
+               kDSPLengthMismatch = 23,       /// The DSP structure length and total length fields do not correspond. One or both of these values is incorrect.
+               kNoBusPatchHeader = 24,        /// Missing a bus patch header.
+               kBadBusPatchKey = 25,          /// The bus patch header key word does not contain the correct value.
+               kBadBusPatchLength = 26,       /// The bus patch length field points past the end of the DSP structure.
+               kBadBusPatchTotalLength = 27,  /// The total bus patch length field points past the end of the DSP structure.
+               kBusPatchLengthMismatch = 28,  /// The bus patch length and total length fields do not correspond. One or both of these values is incorrect.
+               // match up error codes with AliMUONRawStreamTracker:
+               kGlitchFound = 1,              /// Found a glitch. This means a 1 byte word has been randomly inserted into the raw data by mistake.
+               kBadPaddingWord = 2,           /// The padding word does not contain the correct value.
+               kParityError = 3               /// Found a parity error in the data word.
+       };
+
+       // The following methods should be overridden for specific processing to
+       // take place in your event handler.
+
+       /// The OnNewBuffer method will be called whenever a new buffer containing
+       /// a DDL payload is about to be processed.
+       /// The default behaviour of this method is to do nothing.
+       /// - param const void*  The pointer to the start of the memory buffer storing
+       ///                the DDL payload.
+       /// - param UInt_t The size in bytes of the memory buffer.
+       void OnNewBuffer(const void* /*buffer*/, UInt_t /*bufferSize*/) {}
+       
+       /// OnNewBlock is called whenever a new block header is found in the payload.
+       /// The default behaviour of this method is to do nothing.
+       /// - param const AliMUONBlockHeaderStruct* This is a pointer to the block header as found in the
+       ///                DDL payload.
+       /// - param const void* This is a pointer to the start of the block's contents.
+       /// Note: both pointers point into the memory buffer being parsed so the
+       /// contents must not be modified. On the other hand this is very efficient
+       /// because no memory copying is required.
+       void OnNewBlock(const AliMUONBlockHeaderStruct* /*header*/, const void* /*data*/) {}
+       
+       /// OnNewDSP is called whenever a new DSP header is found in the payload.
+       /// Every DSP header recevied by a call to OnNewDSP is associated to the
+       /// block header received in the most recent call to OnNewBlock.
+       /// The default behaviour of this method is to do nothing.
+       /// - param const AliMUONDSPHeaderStruct*  This is a pointer to the DSP header as found in the
+       ///                DDL payload.
+       /// - param const void*  This is a pointer to the start of the DSP's contents.
+       /// Note: both pointers point into the memory buffer being parsed so the
+       /// contents must not be modified. On the other hand this is very efficient
+       /// because no memory copying is required.
+       void OnNewDSP(const AliMUONDSPHeaderStruct* /*header*/, const void* /*data*/) {}
+       
+       /// OnNewBusPatch is called whenever a new bus patch header is found in
+       /// the payload. Every bus patch recevied by a call to OnNewBusPatch is
+       /// associated to the DSP header received in the most recent call to OnNewDSP.
+       /// The default behaviour of this method is to do nothing.
+       /// - param const AliMUONBusPatchHeaderStruct*  This is a pointer to the bus patch header as found
+       ///                 in the DDL payload.
+       /// - param const void*  This is a pointer to the start of the bus patch's contents,
+       ///              specifically the raw data words.
+       /// Note: both pointers point into the memory buffer being parsed so the
+       /// contents must not be modified. On the other hand this is very efficient
+       /// because no memory copying is required.
+       void OnNewBusPatch(const AliMUONBusPatchHeaderStruct* /*header*/, const void* /*data*/) {}
+       
+       /// OnData is called for every raw data word found within a bus patch.
+       /// Every data ward recevied by a call to OnData is associated to the bus patch
+       /// header received in the most recent call to OnNewBusPatch.
+       /// The default behaviour of this method is to do nothing.
+       /// - param UInt_t  This is the raw data word as found within the bus patch payload.
+       void OnData(UInt_t /*data*/) {}
+       
+       /// Whenever a parsing error of the DDL payload is encountered because of
+       /// corruption of the raw data (eg. bit flips) the OnError method is called
+       /// imediately at the point this error is discovered.
+       /// The default behaviour of this method is to do nothing.
+       /// - param ErrorCode  This is an error code indicating the kind of problem
+       ///               encountered with the DDL payload.
+       /// - param const void*  This is a pointer into the DDL payload memory buffer
+       ///         indicating the exact location where the parsing error happened
+       ///         or i.e. the location of the corruption.
+       /// Note that a relative offset in bytes from the start of the memory buffer
+       /// can be calculated by: storing the buffer pointer recevied in OnNewBuffer
+       /// earlier in fBufferStart for example, and then the offset is given by:
+       ///   offset = (unsigned long)location - (unsigned long)fBufferStart;
+       void OnError(ErrorCode /*error*/, const void* /*location*/) {}
+       
+       /// This is a utility method which will unpack the MANU ID, channel ID and
+       /// ADC signal value from a raw data word. It should normally be used in
+       /// OnData() to unpack these fields.
+       /// [in]  \param data  This is the raw data word found in the DDL payload.
+       /// [out] \param manuId    This is filled with the unpacked MANU ID.
+       /// [out] \param channelId This is filled with the unpacked MANU channel ID.
+       /// [out] \param adc       This is filled with the unpacked ADC signal.
+       static void UnpackADC(
+                       UInt_t data,
+                       UShort_t& manuId, UChar_t& channelId, UShort_t& adc
+               )
+       {
+               manuId = (UShort_t)(data >> 18) & 0x7FF;
+               channelId = (Char_t)(data >> 12) & 0x3F;
+               adc = (UShort_t)(data & 0xFFF);
+       }
+       
+       /// This is a utility method which converts an error code to a string
+       /// respresentation for printing purposes.
+       /// \param code  The error code as received in OnError for example.
+       /// \return  An ANSI string containing the name of the error code symbol.
+       static const char* ErrorCodeToString(ErrorCode code);
+       
+       /// This is a utility method which converts an error code to user friendly
+       /// descriptive message useful for printing to the screen.
+       /// \param code  The error code as received in OnError for example.
+       /// \return  An ANSI string containing a descriptive message of the error.
+       static const char* ErrorCodeToMessage(ErrorCode code);
+};
+
+#endif // ALIMUONTRACKERDDLDECODEREVENTHANDLER_H
diff --git a/MUON/AliMUONVRawStreamTracker.cxx b/MUON/AliMUONVRawStreamTracker.cxx
new file mode 100644 (file)
index 0000000..b1e068d
--- /dev/null
@@ -0,0 +1,72 @@
+/**************************************************************************
+ * This file is property of and copyright by the ALICE HLT Project        *
+ * All rights reserved.                                                   *
+ *                                                                        *
+ * Primary Authors:                                                       *
+ *   Artur Szostak <artursz@iafrica.com>                                  *
+ *                                                                        *
+ * Permission to use, copy, modify and distribute this software and its   *
+ * documentation strictly for non-commercial purposes is hereby granted   *
+ * without fee, provided that the above copyright notice appears in all   *
+ * copies and that both the copyright notice and this permission notice   *
+ * appear in the supporting documentation. The authors make no claims     *
+ * about the suitability of this software for any purpose. It is          *
+ * provided "as is" without express or implied warranty.                  *
+ **************************************************************************/
+
+/* $Id$*/
+
+///
+/// \file   AliMUONVRawStreamTracker.cxx
+/// \author Artur Szostak <artursz@iafrica.com>
+/// \date   28-11-2007
+/// \brief  Implementation of the constructors and destructors for AliMUONVRawStreamTracker.
+///
+
+//-----------------------------------------------------------------------------
+/// \ingroup raw
+/// \class AliMUONVRawStreamTracker
+/// \brief This class is the base class for raw stream decoders than need to deal with
+/// raw data coming from the muon tracking chambers.
+///
+/// The classes that derive from this abstract class should loops over all MUON
+/// digits in the raw data given by the AliRawReader.
+/// The Next methods should be overridden so that they step through the all the
+/// digits and return kFALSE or zero when done. kTRUE or the number of digits
+/// decoded should be returned if any digits were actually found.
+///
+/// \author Artur Szostak <artursz@iafrica.com>
+//-----------------------------------------------------------------------------
+
+#include "AliMUONVRawStreamTracker.h"
+
+/// \cond CLASSIMP
+ClassImp(AliMUONVRawStreamTracker)
+/// \endcond
+
+const Int_t AliMUONVRawStreamTracker::fgkMaxDDL = 20;
+
+
+AliMUONVRawStreamTracker::AliMUONVRawStreamTracker() : AliMUONRawStream()
+{
+       ///
+       /// Default constructor.
+       ///
+}
+
+
+AliMUONVRawStreamTracker::AliMUONVRawStreamTracker(AliRawReader* rawReader) :
+       AliMUONRawStream(rawReader)
+{
+       ///
+       /// Constructor with AliRawReader as argument.
+       ///
+}
+
+
+AliMUONVRawStreamTracker::~AliMUONVRawStreamTracker()
+{
+       ///
+       /// Default destructor.
+       ///
+}
diff --git a/MUON/AliMUONVRawStreamTracker.h b/MUON/AliMUONVRawStreamTracker.h
new file mode 100644 (file)
index 0000000..a1997d0
--- /dev/null
@@ -0,0 +1,113 @@
+#ifndef ALIMUONVRAWSTREAMTRACKER_H
+#define ALIMUONVRAWSTREAMTRACKER_H
+/* This file is property of and copyright by the ALICE HLT Project        *
+ * ALICE Experiment at CERN, All rights reserved.                         *
+ * See cxx source for full Copyright notice                               */
+
+/* $Id$*/
+
+///
+/// \file   AliMUONVRawStreamTracker.h
+/// \author Artur Szostak <artursz@iafrica.com>
+/// \date   28-11-2007
+/// \brief  Declaration of the abstract base class for muon trigger chamber raw stream decoders.
+///
+
+#include "AliMUONRawStream.h"
+
+class AliMUONVRawStreamTracker : public AliMUONRawStream
+{
+public:
+
+       /// Default constructor.
+       AliMUONVRawStreamTracker();
+       
+       /// Constructor setting the raw reader.
+       AliMUONVRawStreamTracker(AliRawReader* rawReader);
+       
+       /// Default destructor.
+       virtual ~AliMUONVRawStreamTracker();
+       
+       /// Advance one step in the iteration. Returns false if finished.
+       virtual Bool_t Next(Int_t& busPatchId,
+                               UShort_t& manuId, UChar_t& manuChannel,
+                               UShort_t& adc) = 0;
+       
+       /// Class used in the following Next() method to return blocks of decoded
+       /// channel data. This is better because we generate a lot fewer method calls.
+       class AliChannelInfo
+       {
+       public:
+               /// Default constructor.
+               AliChannelInfo(Int_t busPatchId = 0, UShort_t manuId = 0, UChar_t channelId = 0, UShort_t adc = 0) :
+                       fBusPatchId(busPatchId), fManuId(manuId), fChannelId(channelId), fADC(adc)
+               {}
+               
+               /// Returns the bus patch ID.
+               Int_t BusPatchId() const { return fBusPatchId; }
+               /// Returns the MANU ID.
+               UShort_t ManuId() const { return fManuId; }
+               /// Returns the channel ID.
+               UShort_t ChannelId() const { return fChannelId; }
+               /// ADC signal.
+               UShort_t ADC() const { return fADC; }
+       
+       private:
+               Int_t fBusPatchId;  //!< The bus patch ID for this channel.
+               UShort_t fManuId;   //!< MANU ID.
+               UChar_t fChannelId; //!< MANU channel ID.
+               UShort_t fADC;      //!< ADC signal.
+       };
+       
+       /// Returns the next batch of decoded channel data.
+       /// [out] \param channels  This is filled with the pointer to the array
+       ///                        containing the channel information.
+       /// \return The number of elements in the 'channels' array is returned.
+       ///     Zero is returned if there are no more digits to be fetched.
+       virtual UInt_t Next(const AliChannelInfo*& channels) = 0;
+       
+       /// Return maximum number of DDLs
+       static Int_t GetMaxDDL() { return fgkMaxDDL; };
+       
+       /// Return maximum number of blocks per DDL allowed.
+       virtual Int_t GetMaxBlock() const = 0;
+       /// Return maximum number of Dsp per block allowed.
+       virtual Int_t GetMaxDsp()   const = 0;
+       /// Return maximum number of Buspatch per Dsp allowed.
+       virtual Int_t GetMaxBus()   const = 0;
+       
+       /// Set maximum number of blocks per DDL allowed.
+       virtual void SetMaxBlock(Int_t blk) = 0;
+       /// Set maximum number of Dsp per block allowed.
+       virtual void SetMaxDsp(Int_t dsp) = 0;
+       /// Set maximum number of Buspatch per Dsp allowed.
+       virtual void SetMaxBus(Int_t bus) = 0;
+       
+       /// Return number of the current DDL.
+       virtual Int_t GetDDL() const = 0;
+       
+       /// check error/Warning presence
+       virtual Bool_t IsErrorMessage() const = 0;
+       
+       /// error numbers
+       enum rawStreamTrackerError
+       {
+               kGlitchErr      = 1, ///< glitch error
+               kPaddingWordErr = 2, ///< padding word error
+               kParityErr      = 3  ///< parity error
+       };
+
+private:
+
+       // Do not allow copying of this class.
+        /// Not implemented
+       AliMUONVRawStreamTracker(const AliMUONVRawStreamTracker& stream);
+        /// Not implemented
+       AliMUONVRawStreamTracker& operator = (const AliMUONVRawStreamTracker& stream);
+
+       static const Int_t fgkMaxDDL;   //!< maximum number of DDLs
+
+       ClassDef(AliMUONVRawStreamTracker, 0) // Base class for reading MUON raw digits from tracking chambers.
+};
+
+#endif  // ALIMUONVRAWSTREAMTRACKER_H