]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - MUON/AliMUONTrackerDDLDecoder.h
- update track cuts
[u/mrichter/AliRoot.git] / MUON / AliMUONTrackerDDLDecoder.h
index d7305f0397d6145cc3793ca27692880907df6b74..d23a26308ab989154851d1273eb34a1ccadf68bb 100644 (file)
@@ -25,7 +25,7 @@
 /// \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
+/// the core logic for decoding the payload in DDL streams coming from the muon
 /// spectrometer's tracking chambers in a very efficient manner.
 ///
 /// This implementation is derived from work done by Christian Finck for the
 /// must be checked before any proposed modification is made to this file.
 ///
 
+#include <string.h>
 #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.
+/// It has been implemented using the event driven paradigm with templates,
+/// which allows us to minimise the number of method calls made in the inner
+/// loops of the algorithm and minimise the memory footprint. At least for
+/// optimised production compilations.
 /// 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
+/// 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)
+///     void OnData(UInt_t data, bool parityError)
 ///     {
-///       // I can do something with 'data' here.
+///       // I can do something with 'data' here and check if there was
+///       // a parity error with 'parityError'.
 ///     }
 ///  };
 /// \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
+/// Once the custom handler is written then the decoder is instantiated as
+/// shown below, to use your new custom handler. Also to start decoding one needs
 /// to call the Decode() method of the decoder.
 /// \code
 ///  AliMUONTrackerDDLDecoder<MyCustomHandler> myDecoder;
 /// \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
+/// compilers chance to make optimisations and inline the code we must use a template.
+/// Depending on exactly what you do inside your handler, the decoder could be
+/// significantly slower if run time polymorphism was used, i.e. making the class
 /// AliMUONTrackerDDLDecoderEventHandler abstract and using virtual methods.
 ///
+/// There has been a change to the data format that the real detector generates.
+/// Two trailer words are added to the end of the DDL payload which indicated
+/// the end of data. The decoder is initialised by default to automatically
+/// check for these and deal with it correctly, if they exist or not.
+/// However, if you want to override this behaviour then set the flag
+/// fAutoDetectTrailer to false with AutoDetectTrailer(false). Then if you have
+/// data with the old data format you should set fCheckForTrailer to false with
+/// CheckForTrailer(false), otherwise for real data it should be
+/// fCheckForTrailer = true. Only when fAutoDetectTrailer is true will the
+/// fCheckForTrailer flag be ignored and no warnings will be generated for an
+/// incorrect data format.
+///
 /// \author Artur Szostak <artursz@iafrica.com>
 
 template <class EventHandler>
@@ -97,6 +107,7 @@ public:
        AliMUONTrackerDDLDecoder() :
                fExitOnError(true), fTryRecover(false),
                fSendDataOnParityError(false), fHadError(false),
+               fAutoDetectTrailer(true), fCheckForTrailer(true),
                fMaxBlocks(2), fMaxDSPs(5), fMaxBusPatches(5), fHandler()
        {}
        
@@ -116,12 +127,12 @@ public:
        
        /// Returns the "try to recover from errors" flag.
        /// i.e. should the decoder try to recover from errors found in the
-       /// payload headers.
+       /// payload headers or trailers.
        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.
+       /// payload headers or trailers.
        void TryRecover(bool value) { fTryRecover = value; }
        
        /// Returns the flag indicating if the raw data words in the bus patches
@@ -156,20 +167,54 @@ public:
        /// structure within the DDL payload.
        void MaxBusPatches(UInt_t n) { fMaxBusPatches = n; }
        
+       /// Returns the value of the auto-detect trailer flag.
+       bool AutoDetectTrailer() const { return fAutoDetectTrailer; }
+       
+       /// Sets the value of the auto-detect trailer flag.
+       void AutoDetectTrailer(bool value) { fAutoDetectTrailer = value; }
+       
+       /// Returns the value of the flag to check for the end of DDL trailer.
+       bool CheckForTrailer() const { return fCheckForTrailer; }
+       
+       /// Sets the value of the flag to check for the end of DDL trailer.
+       void CheckForTrailer(bool value) { fCheckForTrailer = value; }
+       
        /// This method decodes the DDL payload contained in the buffer.
        bool Decode(const void* buffer, UInt_t bufferSize);
        
+       /// First try fix data corruption and then decode the DDL payload.
+       bool Decode(void* buffer, UInt_t bufferSize);
+       
+       /// Returns the block marker key.
+       static UInt_t BlockDataKeyWord() { return fgkBlockDataKey; }
+       
+       /// Returns the DSP marker key.
+       static UInt_t DspDataKeyWord() { return fgkDSPDataKey; }
+       
+       /// Returns the bus patch marker key.
+       static UInt_t BusPatchDataKeyWord() { return fgkBusPatchDataKey; }
+       
+       /// Returns the expected padding word value.
+       static UInt_t PaddingWord() { return fgkPaddingWord; }
+       
+       /// Returns the expected end of DDL marker.
+       static UInt_t EndOfDDLWord() { return fgkEndOfDDL; }
+       
 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 fTryRecover; ///< Indicates if we should try recover from a corrupt structure header or DDL trailer.
        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.
+       bool fAutoDetectTrailer; ///< Indicates if we should automatically check for the end of DDL trailer (Default = true).
+       bool fCheckForTrailer; ///< Indicates if we should check for the end of DDL trailer (Default = true). This flag is ignored if fAutoDetectTrailer is true.
        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.
 
+       void DecodeBuffer(const UChar_t* start, const UChar_t* end);
+       
        bool DecodeBlockData(
                        const AliMUONBlockHeaderStruct* blockHeader,
                        const UChar_t* start, const UChar_t* end
@@ -209,6 +254,7 @@ private:
        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.
+       static const UInt_t fgkEndOfDDL;         ///< The end of DDL trailer word.
 };
 
 //_____________________________________________________________________________
@@ -223,125 +269,8 @@ 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>
+const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkEndOfDDL = 0xD000000D;
 
 
 template <class EventHandler>
@@ -363,6 +292,8 @@ bool AliMUONTrackerDDLDecoder<EventHandler>::Decode(const void* buffer, UInt_t b
        /// 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).
+       /// fTryRecover set to true will also enable recovery from a corrupt
+       /// DDL trailer marking the end of DDL payload.
        ///
        /// \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
@@ -380,15 +311,138 @@ bool AliMUONTrackerDDLDecoder<EventHandler>::Decode(const void* buffer, UInt_t b
        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;
+       // So start by marking the start of buffer position and end of buffer.
+       const UChar_t* start = reinterpret_cast<const UChar_t*>(buffer);
+       const UChar_t* end = start + bufferSize;
        
-       // Signal a new buffer event.
        fHandler.OnNewBuffer(buffer, bufferSize);
+       DecodeBuffer(start, end);
+       fHandler.OnEndOfBuffer(buffer, bufferSize);
+       return not fHadError;
+}
+
+
+template <class EventHandler>
+bool AliMUONTrackerDDLDecoder<EventHandler>::Decode(void* buffer, UInt_t bufferSize)
+{
+       /// This decoding method performs a special checks to see if the DDL
+       /// corruption is fixable and then fixes the buffer by modifying it directly.
+       /// The fixes only apply if the fTryRecover flag is enabled.
+       /// \note buffer might be modified.
+       
+       assert( buffer != NULL );
+       if (fTryRecover)
+       {
+               ///////////////////////////////////////////////////////
+               // Trick to recover B off data Runs : 119041, 119047, 119055, 119057
+               // A. Baldisseri May 2010
+               // Check if 16 32-bit words from a buspatch have been inserted
+               // incorrectly immediately at the beginning of the DDL payload.
+               UChar_t* bufferChar = reinterpret_cast<UChar_t*>(buffer);
+               UInt_t* bufferInt = reinterpret_cast<UInt_t*>(buffer);
+               if (bufferSize > 18*4 // is the buffer large enough to check the header.
+                   and bufferInt[0] != fgkBlockDataKey and bufferInt[16] == fgkBlockDataKey // was the header incorrectly moved.
+                   and bufferSize > bufferInt[17]*4 + sizeof(AliMUONBlockHeaderStruct) // is the buffer large enough for the second block header.
+                   and bufferInt[bufferInt[17]] == fgkBlockDataKey  // Check that the second header is in the correct location.
+                   and bufferInt[17] == bufferInt[18] + 8  // Make sure that both lengths are correct.
+                   and (bufferInt[17] + bufferInt[bufferInt[17]+1]+2)*4 == bufferSize // Check that both blocks will have the correct size if we make the fix.
+                  )
+               {
+                       UChar_t tmpbuf[16*4];
+                       memcpy(tmpbuf, bufferChar, 16*4);
+                       size_t sizeToMove = bufferInt[17]*4-16*4;
+                       memmove(bufferChar, bufferChar+16*4, sizeToMove);
+                       memcpy(bufferChar + sizeToMove, tmpbuf, 16*4);
+               }
+       }
+       return Decode(reinterpret_cast<const void*>(buffer), bufferSize);
+}
+
+
+template <class EventHandler>
+void AliMUONTrackerDDLDecoder<EventHandler>::DecodeBuffer(
+               const UChar_t* start, const UChar_t* end
+       )
+{
+       /// This method decodes the buffer's payload data. It unpacks the block
+       /// structures contained inside and then for each block it calls the
+       /// OnNewBlock method for the event handler to signal the start of each new
+       /// block structure. OnEndOfBlock is called once each block is processed.
+       /// \param start  This is the pointer to the start of the buffer.
+       /// \param end  This is the pointer to the first byte just past the
+       ///             end of the buffer.
+       /// fHadError is set to true if there were any errors decoding the buffer
+       /// and the OnError method of the callback event handler is called for
+       /// each error.
+       
+       const UChar_t* current = start;
+       const UInt_t* bufferStart = reinterpret_cast<const UInt_t*>(start);
+       const UInt_t* bufferEnd = reinterpret_cast<const UInt_t*>(end);
+       bool problemWithTrailer = false;
+       
+       // The DDL payload normally has a 2 word trailer which contains the end of
+       // DDL markers 0xD000000D. But this is not the case for older simulated
+       // data so if we are auto-detecting the trailer then we need to carefully
+       // check if these words are there or not.
+       const UChar_t* endOfBlocks = end;
+       const UInt_t* trailerWords = reinterpret_cast<const UInt_t*>(end) - 2;
+       if (fAutoDetectTrailer)
+       {
+               if (trailerWords >= bufferStart and trailerWords < bufferEnd
+                   and *trailerWords == fgkEndOfDDL and *(trailerWords+1) == fgkEndOfDDL
+                  )
+               {
+                       // Found the trailer so reposition the end of blocks marker.
+                       endOfBlocks = reinterpret_cast<const UChar_t*>(trailerWords);
+               }
+               // else assume we are dealing with the older data format.
+       }
+       else if (fCheckForTrailer)
+       {
+               if (trailerWords >= bufferStart and trailerWords < bufferEnd
+                   and *trailerWords == fgkEndOfDDL and *(trailerWords+1) == fgkEndOfDDL
+                  )
+               {
+                       // Found the trailer so reposition the end of blocks marker.
+                       endOfBlocks = reinterpret_cast<const UChar_t*>(trailerWords);
+               }
+               else
+               {
+                       if (trailerWords+1 >= bufferStart and trailerWords+1 < bufferEnd and *(trailerWords+1) == fgkEndOfDDL)
+                               fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords+1);
+                       else if (trailerWords >= bufferStart and trailerWords < bufferEnd and *(trailerWords) == fgkEndOfDDL)
+                               fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords);
+                       else
+                               fHandler.OnError(EventHandler::kNoDDLTrailerWords, end);
+       
+                       // Stop the decoding if so requested by the user, otherwise
+                       // remember about the error so that we return false from the
+                       // Decode() method and continue decoding.
+                       fHadError = true;
+                       if (fExitOnError) return;
+                       
+                       // Mark that there was a problem with the trailer so that
+                       // for subsequent errors we try to deal with this better.
+                       problemWithTrailer = true;
+                       
+                       // We can also try figure out how many trailer words there
+                       // actually are and move the end of blocks marker back.
+                       
+                       if (fTryRecover)
+                       {
+                               trailerWords = bufferEnd;
+                               // There should only be a max of 2 trailer words.
+                               if (trailerWords-2 >= bufferStart and trailerWords-2 < bufferEnd and *(trailerWords-2) == fgkEndOfDDL)
+                                       trailerWords -= 2;
+                               else if (trailerWords-1 >= bufferStart and trailerWords-1 < bufferEnd and *(trailerWords-1) == fgkEndOfDDL)
+                                       trailerWords -= 1;
+                               endOfBlocks = reinterpret_cast<const UChar_t*>(trailerWords);
+                       }
+               }
+       }
 
        UInt_t blockCount = 0; // Indicates the number of blocks decoded.
-       while (current < end)
+       while (current < endOfBlocks)
        {
                // Mark the start of the block structure.
                const UChar_t* blockStart = current;
@@ -398,8 +452,36 @@ bool AliMUONTrackerDDLDecoder<EventHandler>::Decode(const void* buffer, UInt_t b
                const AliMUONBlockHeaderStruct* blockHeader
                        = reinterpret_cast<const AliMUONBlockHeaderStruct*>(blockStart);
                current += sizeof(AliMUONBlockHeaderStruct);
-               if (current > end)
+               if (current > endOfBlocks or current < start)
                {
+                       // If we overflowed the pointer and already had an error then
+                       // we are clearly lost so just stop decoding before we segfault.
+                       if (current < start and fHadError) return;
+                       
+                       // We first check if we actually hit the end of DDL markers
+                       // If we did then either we did not/could not recover from
+                       // a corrupt trailer or we did not detect a correct trailer
+                       // in auto-detect mode.
+                       trailerWords = reinterpret_cast<const UInt_t*>(blockHeader);
+                       // The "trailerWords+1 <= bufferEnd" checks that we are
+                       // not reading beyond the end of the buffer.
+                       if (trailerWords+1 <= bufferEnd and *trailerWords == fgkEndOfDDL)
+                       {
+                               // If we aready knew the trailer was corrupt then just
+                               // return because the error was already announced.
+                               if (problemWithTrailer) return;
+                               
+                               if (fAutoDetectTrailer)
+                               {
+                                       // If we got here then there is at least one correct trailer
+                                       // word, but since we did not detect a correct trailer then
+                                       // there must be only one. Announce the error and exit.
+                                       fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords);
+                                       fHadError = true;
+                                       return;
+                               }
+                       }
+                       
                        // 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)
@@ -408,7 +490,8 @@ bool AliMUONTrackerDDLDecoder<EventHandler>::Decode(const void* buffer, UInt_t b
                                fHandler.OnError(EventHandler::kBufferTooBig, blockHeader);
                        else
                                fHandler.OnError(EventHandler::kNoBlockHeader, blockHeader);
-                       return false;
+                       fHadError = true;
+                       return;
                }
                
                // The header fits the buffer so we can mark the data start and
@@ -427,7 +510,9 @@ bool AliMUONTrackerDDLDecoder<EventHandler>::Decode(const void* buffer, UInt_t b
                // 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)
+                   or dataEnd > endOfBlocks or dataEnd < start
+                   or blockEnd > endOfBlocks or blockEnd < start
+                   or dataEnd != blockEnd)
                {
                        // So let us see what exactly is wrong and report this.
                        if (blockCount == fMaxBlocks)
@@ -436,34 +521,33 @@ bool AliMUONTrackerDDLDecoder<EventHandler>::Decode(const void* buffer, UInt_t b
                                // expected, so the remaining data must be rubbish.
                                // Don't even bother trying to recover the data.
                                fHandler.OnError(EventHandler::kBufferTooBig, blockHeader);
-                               return false;
+                               fHadError = true;
+                               return;
                        }
                        if (blockHeader->fDataKey != fgkBlockDataKey)
                                fHandler.OnError(EventHandler::kBadBlockKey, &blockHeader->fDataKey);
-                       if (blockEnd > end)
+                       if (blockEnd > endOfBlocks or blockEnd < start)
                                fHandler.OnError(EventHandler::kBadBlockLength, &blockHeader->fLength);
-                       if (dataEnd > end)
+                       if (dataEnd > endOfBlocks or dataEnd < start)
                                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;
+                       // remember about the error so that we return false from the
+                       // Decode() method and continue decoding.
+                       fHadError = true;
+                       if (fExitOnError) return;
                        
                        // Try to recover from the corrupt header.
                        RecoverResult result = TryRecoverStruct(
                                        fgkBlockDataKey, sizeof(AliMUONBlockHeaderStruct),
                                        blockHeader->fTotalLength, blockHeader->fLength,
-                                       blockStart, end, dataEnd, blockEnd, current
+                                       blockStart, endOfBlocks, dataEnd, blockEnd, current
                                );
                        if (result == kContinueToNextStruct)
                                continue; // Try the next block at 'current'.
-                       if (result == kRecoverFailed) return false;
+                       if (result == kRecoverFailed) return;
                }
                
                // At this point we certainly have a valid block header, so we
@@ -476,20 +560,25 @@ bool AliMUONTrackerDDLDecoder<EventHandler>::Decode(const void* buffer, UInt_t b
                        // 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;
+                       fHadError = true;
+                       return;
                }
                
                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;
+               if (not DecodeBlockData(blockHeader, dataStart, dataEnd))
+               {
+                       // 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)
+                       {
+                               fHandler.OnEndOfBlock(blockHeader, dataStart);
+                               return;
+                       }
+               }
+               fHandler.OnEndOfBlock(blockHeader, dataStart);
        }
-       
-       return not fHadError;
 }
 
 
@@ -525,8 +614,12 @@ bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeBlockData(
                const AliMUONDSPHeaderStruct* dspHeader
                        = reinterpret_cast<const AliMUONDSPHeaderStruct*>(dspStart);
                current += sizeof(AliMUONDSPHeaderStruct);
-               if (current > end)
+               if (current > end or current < start)
                {
+                       // If we overflowed the pointer and already had an error then
+                       // we are clearly lost so just stop decoding before we segfault.
+                       if (current < start and fHadError) return false;
+                       
                        // 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.
@@ -550,14 +643,16 @@ bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeBlockData(
                // 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)
+                   or dataEnd > end or dataEnd < start
+                   or dspEnd > end or dspEnd < start
+                   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)
+                       if (dspEnd > end or dspEnd < start)
                                fHandler.OnError(EventHandler::kBadDSPLength, &dspHeader->fLength);
-                       if (dataEnd > end)
+                       if (dataEnd > end or dataEnd < start)
                                fHandler.OnError(EventHandler::kBadDSPTotalLength, &dspHeader->fTotalLength);
                        if (dataEnd != dspEnd)
                                fHandler.OnError(EventHandler::kDSPLengthMismatch, dspHeader);
@@ -597,24 +692,46 @@ bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeBlockData(
                fHandler.OnNewDSP(dspHeader, dataStart);
                
                // Check the error word in the header.
-               if (dspHeader->fErrorWord == (0x000000B1 | blockHeader->fDSPId)
-                   or dspHeader->fErrorWord == (0x00000091 | blockHeader->fDSPId)
-                  )
+               if (dspHeader->fErrorWord != 0x0)
                {
-                       // 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);
+                       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);
+                       }
+                       else if ((dspHeader->fErrorWord & 0x0000FFF0) == 0x220)
+                       {
+                               // Detected a TOKEN_LOST error which can affect the dead time in the DAQ.
+                               fHandler.OnError(EventHandler::kTokenLost, &dspHeader->fErrorWord);
+                       }
+                       else
+                       {
+                               // The DSP error code is non-zero but has an unknown code.
+                               fHandler.OnError(EventHandler::kUnknownDspError, &dspHeader->fErrorWord);
+                       }
+                       
                        fHadError = true;
-                       if (fExitOnError) return false;
+                       if (fExitOnError)
+                       {
+                               fHandler.OnEndOfDSP(dspHeader, dataStart);
+                               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
+                       // decoding from there. Note: to achieve this 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;
+                       if (fTryRecover)
+                       {
+                               fHandler.OnEndOfDSP(dspHeader, dataStart);
+                               continue;
+                       }
                }
                
                // Check if we are padding. If we are, then the bus patch data is
@@ -629,17 +746,27 @@ bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeBlockData(
                        {
                                fHandler.OnError(EventHandler::kBadPaddingWord, padWord);
                                fHadError = true;
-                               if (fExitOnError) return false;
+                               if (fExitOnError)
+                               {
+                                       fHandler.OnEndOfDSP(dspHeader, dataStart);
+                                       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;
+               if (not DecodeDSPData(dataStart, dataEnd))
+               {
+                       // 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)
+                       {
+                               fHandler.OnEndOfDSP(dspHeader, dataStart);
+                               return false;
+                       }
+               }
+               fHandler.OnEndOfDSP(dspHeader, dataStart);
        }
        
        return true;
@@ -675,8 +802,12 @@ bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeDSPData(
                const AliMUONBusPatchHeaderStruct* busPatchHeader
                        = reinterpret_cast<const AliMUONBusPatchHeaderStruct*>(busPatchStart);
                current += sizeof(AliMUONBusPatchHeaderStruct);
-               if (current > end)
+               if (current > end or current < start)
                {
+                       // If we overflowed the pointer and already had an error then
+                       // we are clearly lost so just stop decoding before we segfault.
+                       if (current < start and fHadError) return false;
+                       
                        // 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
@@ -703,14 +834,16 @@ bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeDSPData(
                // 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)
+                   or dataEnd > end or dataEnd < start
+                   or busPatchEnd > end or busPatchEnd < start
+                   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)
+                       if (busPatchEnd > end or busPatchEnd < start)
                                fHandler.OnError(EventHandler::kBadBusPatchLength, &busPatchHeader->fLength);
-                       if (dataEnd > end)
+                       if (dataEnd > end or dataEnd < start)
                                fHandler.OnError(EventHandler::kBadBusPatchTotalLength, &busPatchHeader->fTotalLength);
                        if (dataEnd != busPatchEnd)
                                fHandler.OnError(EventHandler::kBusPatchLengthMismatch, busPatchHeader);
@@ -749,13 +882,19 @@ bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeDSPData(
                }
                
                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;
+               if (not DecodeBusPatchData(dataStart, dataEnd))
+               {
+                       // 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)
+                       {
+                               fHandler.OnEndOfBusPatch(busPatchHeader, dataStart);
+                               return false;
+                       }
+               }
+               fHandler.OnEndOfBusPatch(busPatchHeader, dataStart);
        }
        
        return true;
@@ -793,7 +932,7 @@ bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeBusPatchData(
        {
                if (ParityIsOk(*data))
                {
-                       fHandler.OnData(*data);
+                       fHandler.OnData(*data, false);
                }
                else
                {
@@ -804,7 +943,7 @@ bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeBusPatchData(
                        if (fExitOnError) return false;
                        
                        if (fSendDataOnParityError)
-                               fHandler.OnData(*data);
+                               fHandler.OnData(*data, true);
                }
        }
        
@@ -908,16 +1047,16 @@ AliMUONTrackerDDLDecoder<EventHandler>::TryRecoverStruct(
        const UInt_t* headerKey = reinterpret_cast<const UInt_t*>(structStart);
        bool headerKeyOk = (expectedKey == *headerKey);
        
-       bool lengthsMatch = (totalLength == length + headerSize);
+       bool lengthsMatch = (totalLength*4 == length*4 + 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 ( expectedKey == fgkBlockDataKey )
+        {
                if (dataEnd == bufferEnd)
                {
                        // Are we at the end of the buffer?
@@ -927,7 +1066,7 @@ AliMUONTrackerDDLDecoder<EventHandler>::TryRecoverStruct(
                {
                        // Must check that we can read another 4 bytes before
                        // checking the key at dataEnd.
-                       if (dataEnd + sizeof(UInt_t) <= bufferEnd)
+                       if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
                        {
                                if (*keyAtDataEnd == fgkBlockDataKey)
                                        lengthIsCorrect = true;
@@ -943,16 +1082,16 @@ AliMUONTrackerDDLDecoder<EventHandler>::TryRecoverStruct(
                {
                        // Must check that we can read another 4 bytes before
                        // checking the key at structEnd.
-                       if (structEnd + sizeof(UInt_t) <= bufferEnd)
+                       if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
                        {
                                if (*keyAtStructEnd == fgkBlockDataKey)
                                        totalLengthIsCorrect = true;
                        }
                }
+        }        
                        
-               break;
-       
-       case fgkDSPDataKey:
+        else if ( expectedKey == fgkDSPDataKey )
+        {
                if (dataEnd == bufferEnd)
                {
                        // Are we at the end of the buffer?
@@ -962,7 +1101,7 @@ AliMUONTrackerDDLDecoder<EventHandler>::TryRecoverStruct(
                {
                        // Must check that we can read another 4 bytes before
                        // checking the key at dataEnd.
-                       if (dataEnd + sizeof(UInt_t) <= bufferEnd)
+                       if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
                        {
                                if (*keyAtDataEnd == fgkBlockDataKey
                                    or *keyAtDataEnd == fgkDSPDataKey)
@@ -979,17 +1118,16 @@ AliMUONTrackerDDLDecoder<EventHandler>::TryRecoverStruct(
                {
                        // Must check that we can read another 4 bytes before
                        // checking the key at structEnd.
-                       if (structEnd + sizeof(UInt_t) <= bufferEnd)
+                       if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
                        {
                                if (*keyAtStructEnd == fgkBlockDataKey
                                    or *keyAtStructEnd == fgkDSPDataKey)
                                        totalLengthIsCorrect = true;
                        }
                }
-                       
-               break;
-       
-       case fgkBusPatchDataKey:
+        }        
+        else if ( expectedKey == fgkBusPatchDataKey )
+        {
                if (dataEnd == bufferEnd)
                {
                        // Are we at the end of the buffer?
@@ -999,7 +1137,7 @@ AliMUONTrackerDDLDecoder<EventHandler>::TryRecoverStruct(
                {
                        // Must check that we can read another 4 bytes before
                        // checking the key at dataEnd.
-                       if (dataEnd + sizeof(UInt_t) <= bufferEnd)
+                       if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
                        {
                                if (*keyAtDataEnd == fgkDSPDataKey
                                    or *keyAtDataEnd == fgkBusPatchDataKey)
@@ -1016,20 +1154,14 @@ AliMUONTrackerDDLDecoder<EventHandler>::TryRecoverStruct(
                {
                        // Must check that we can read another 4 bytes before
                        // checking the key at structEnd.
-                       if (structEnd + sizeof(UInt_t) <= bufferEnd)
+                       if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
                        {
                                if (*keyAtStructEnd == fgkDSPDataKey
                                    or *keyAtStructEnd == fgkBusPatchDataKey)
                                        totalLengthIsCorrect = true;
                        }
                }
-                       
-               break;
-               
-       default:
-               // lengthIsCorrect and totalLengthIsCorrect already set to false.
-               break;
-       }
+        }
        
        if (headerKeyOk and lengthIsCorrect)
        {
@@ -1077,7 +1209,8 @@ const UChar_t* AliMUONTrackerDDLDecoder<EventHandler>::FindKey(
        /// 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.
+       
+       if (end + sizeof(UInt_t) < start) return NULL;  // check for pointer overflow.
        const UChar_t* current = start;
        while (current + sizeof(UInt_t) <= end)
        {