LCOV - code coverage report
Current view: top level - MUON/MUONraw - AliMUONTrackerDDLDecoder.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 115 336 34.2 %
Date: 2016-06-14 17:26:59 Functions: 27 82 32.9 %

          Line data    Source code
       1             : #ifndef ALIMUONTRACKERDDLDECODER_H
       2             : #define ALIMUONTRACKERDDLDECODER_H
       3             : /**************************************************************************
       4             :  * This file is property of and copyright by the ALICE HLT Project        *
       5             :  * All rights reserved.                                                   *
       6             :  *                                                                        *
       7             :  * Primary Authors:                                                       *
       8             :  *   Artur Szostak <artursz@iafrica.com>                                  *
       9             :  *                                                                        *
      10             :  * Permission to use, copy, modify and distribute this software and its   *
      11             :  * documentation strictly for non-commercial purposes is hereby granted   *
      12             :  * without fee, provided that the above copyright notice appears in all   *
      13             :  * copies and that both the copyright notice and this permission notice   *
      14             :  * appear in the supporting documentation. The authors make no claims     *
      15             :  * about the suitability of this software for any purpose. It is          *
      16             :  * provided "as is" without express or implied warranty.                  *
      17             :  **************************************************************************/
      18             : 
      19             : /* $Id$ */
      20             : 
      21             : ///
      22             : /// \file   AliMUONTrackerDDLDecoder.h
      23             : /// \author Artur Szostak <artursz@iafrica.com>
      24             : /// \date   28-11-2007
      25             : /// \brief  Implementation of a high performance DDL decoder for the muon tracking stations.
      26             : ///
      27             : /// This file implementes the AliMUONTrackerDDLDecoder class, which contains
      28             : /// the core logic for decoding the payload in DDL streams coming from the muon
      29             : /// spectrometer's tracking chambers in a very efficient manner.
      30             : ///
      31             : /// This implementation is derived from work done by Christian Finck for the
      32             : /// AliMUONPayloadTracker.
      33             : ///
      34             : /// Note to maintainers: Please remember that this file is used by the online
      35             : /// dHLT system. As an online system, the dHLT requires the fastest code possible
      36             : /// in the decoders to satisfy its timing constraints. The performance impact
      37             : /// must be checked before any proposed modification is made to this file.
      38             : ///
      39             : 
      40             : #include <string.h>
      41             : #include "AliMUONTrackerDDLDecoderEventHandler.h"
      42             : 
      43             : /// \ingroup raw
      44             : /// \class AliMUONTrackerDDLDecoder
      45             : /// \brief A high performance decoder class for MUON tracking DDL data.
      46             : ///
      47             : /// This class implements a high performance decoder for decoding DDL payload
      48             : /// data coming from the muon spectrometers tracking chambers.
      49             : /// It has been implemented using the event driven paradigm with templates,
      50             : /// which allows us to minimise the number of method calls made in the inner
      51             : /// loops of the algorithm and minimise the memory footprint. At least for
      52             : /// optimised production compilations.
      53             : /// The decoder class only contains the basic decoding and error checking logic.
      54             : /// It calls methods such as OnNewBlock, OnNewBusPatch, OnData etc in
      55             : /// the event handler during the decoding to return the decoded data.
      56             : /// The event handler class is nothing more than a callback interface to deliver
      57             : /// the next chunks of decoded data.
      58             : /// To actually do something with the data, one needs to implement a custom
      59             : /// event handler (callback) class by inheriting from AliMUONTrackerDDLDecoderEventHandler
      60             : /// and overriding the callback methods like so:
      61             : /// \code
      62             : ///  class MyCustomHandler : public AliMUONTrackerDDLDecoderEventHandler
      63             : ///  {
      64             : ///  public:
      65             : ///     void OnData(UInt_t data, bool parityError)
      66             : ///     {
      67             : ///       // I can do something with 'data' here and check if there was
      68             : ///       // a parity error with 'parityError'.
      69             : ///     }
      70             : ///  };
      71             : /// \endcode
      72             : ///
      73             : /// Once the custom handler is written then the decoder is instantiated as
      74             : /// shown below, to use your new custom handler. Also to start decoding one needs
      75             : /// to call the Decode() method of the decoder.
      76             : /// \code
      77             : ///  AliMUONTrackerDDLDecoder<MyCustomHandler> myDecoder;
      78             : ///  muDecoder.Decoder(buffer, bufferSize);
      79             : /// \endcode
      80             : ///
      81             : /// Note that this class was written as a template on purpose. To maximise the
      82             : /// compilers chance to make optimisations and inline the code we must use a template.
      83             : /// Depending on exactly what you do inside your handler, the decoder could be
      84             : /// significantly slower if run time polymorphism was used, i.e. making the class
      85             : /// AliMUONTrackerDDLDecoderEventHandler abstract and using virtual methods.
      86             : ///
      87             : /// There has been a change to the data format that the real detector generates.
      88             : /// Two trailer words are added to the end of the DDL payload which indicated
      89             : /// the end of data. The decoder is initialised by default to automatically
      90             : /// check for these and deal with it correctly, if they exist or not.
      91             : /// However, if you want to override this behaviour then set the flag
      92             : /// fAutoDetectTrailer to false with AutoDetectTrailer(false). Then if you have
      93             : /// data with the old data format you should set fCheckForTrailer to false with
      94             : /// CheckForTrailer(false), otherwise for real data it should be
      95             : /// fCheckForTrailer = true. Only when fAutoDetectTrailer is true will the
      96             : /// fCheckForTrailer flag be ignored and no warnings will be generated for an
      97             : /// incorrect data format.
      98             : ///
      99             : /// \author Artur Szostak <artursz@iafrica.com>
     100             : 
     101             : template <class EventHandler>
     102          32 : class AliMUONTrackerDDLDecoder
     103             : {
     104             : public:
     105             : 
     106             :         /// Default contructor.
     107             :         AliMUONTrackerDDLDecoder() :
     108          24 :                 fExitOnError(true), fTryRecover(false),
     109          12 :                 fSendDataOnParityError(false), fHadError(false),
     110          12 :                 fAutoDetectTrailer(true), fCheckForTrailer(true),
     111          12 :                 fMaxBlocks(2), fMaxDSPs(5), fMaxBusPatches(5), fHandler()
     112          36 :         {}
     113             :         
     114             :         /// Constant method to return the event handler instance.
     115           0 :         const EventHandler& GetHandler() const { return fHandler; }
     116             :         
     117             :         /// Returns the event handler instance.
     118       15204 :         EventHandler& GetHandler() { return fHandler; }
     119             :         
     120             :         /// Returns the "exit on error" flag.
     121             :         /// i.e. should the decoder stop on the very first error found.
     122             :         bool ExitOnError() const { return fExitOnError; }
     123             :         
     124             :         /// Sets the "exit on error" flag.
     125             :         /// i.e. should the decoder stop on the very first error found.
     126          12 :         void ExitOnError(bool value) { fExitOnError = value; }
     127             :         
     128             :         /// Returns the "try to recover from errors" flag.
     129             :         /// i.e. should the decoder try to recover from errors found in the
     130             :         /// payload headers or trailers.
     131           0 :         bool TryRecover() const { return fTryRecover; }
     132             :         
     133             :         /// Sets the "try to recover from errors" flag.
     134             :         /// i.e. should the decoder try to recover from errors found in the
     135             :         /// payload headers or trailers.
     136           4 :         void TryRecover(bool value) { fTryRecover = value; }
     137             :         
     138             :         /// Returns the flag indicating if the raw data words in the bus patches
     139             :         /// that failed their parity tests (i.e. parity error / bit flip in the
     140             :         /// raw data word) will be sent to the event handler anyway through OnData.
     141             :         bool SendDataOnParityError() const { return fSendDataOnParityError; }
     142             :         
     143             :         /// Sets the flag indicating if the raw data words in the bus patches
     144             :         /// that failed their parity tests (i.e. parity error / bit flip in the
     145             :         /// raw data word) will be sent to the event handler anyway through OnData.
     146          12 :         void SendDataOnParityError(bool value) { fSendDataOnParityError = value; }
     147             :         
     148             :         /// Returns the maximum block count expected in the DDL payload.
     149          18 :         UInt_t MaxBlocks() const { return fMaxBlocks; }
     150             :         
     151             :         /// Sets the maximum block count expected in the DDL payload.
     152           0 :         void MaxBlocks(UInt_t n) { fMaxBlocks = n; }
     153             :         
     154             :         /// Returns the maximum DSP header count expected in any given block
     155             :         /// structure within the DDL payload.
     156          18 :         UInt_t MaxDSPs() const { return fMaxDSPs; }
     157             :         
     158             :         /// Sets the maximum DSP header count expected in any given block structure
     159             :         /// within the DDL payload.
     160           0 :         void MaxDSPs(UInt_t n) { fMaxDSPs = n; }
     161             :         
     162             :         /// Returns the maximum number of bus patches expected in any given DSP
     163             :         /// structure within the DDL payload.
     164          18 :         UInt_t MaxBusPatches() const { return fMaxBusPatches; }
     165             :         
     166             :         /// Sets the maximum number of bus patches expected in any given DSP
     167             :         /// structure within the DDL payload.
     168           0 :         void MaxBusPatches(UInt_t n) { fMaxBusPatches = n; }
     169             :         
     170             :         /// Returns the value of the auto-detect trailer flag.
     171           0 :         bool AutoDetectTrailer() const { return fAutoDetectTrailer; }
     172             :         
     173             :         /// Sets the value of the auto-detect trailer flag.
     174           3 :         void AutoDetectTrailer(bool value) { fAutoDetectTrailer = value; }
     175             :         
     176             :         /// Returns the value of the flag to check for the end of DDL trailer.
     177           0 :         bool CheckForTrailer() const { return fCheckForTrailer; }
     178             :         
     179             :         /// Sets the value of the flag to check for the end of DDL trailer.
     180           3 :         void CheckForTrailer(bool value) { fCheckForTrailer = value; }
     181             :         
     182             :         /// This method decodes the DDL payload contained in the buffer.
     183             :         bool Decode(const void* buffer, UInt_t bufferSize);
     184             :         
     185             :         /// First try fix data corruption and then decode the DDL payload.
     186             :         bool Decode(void* buffer, UInt_t bufferSize);
     187             :         
     188             :         /// Returns the block marker key.
     189             :         static UInt_t BlockDataKeyWord() { return fgkBlockDataKey; }
     190             :         
     191             :         /// Returns the DSP marker key.
     192             :         static UInt_t DspDataKeyWord() { return fgkDSPDataKey; }
     193             :         
     194             :         /// Returns the bus patch marker key.
     195             :         static UInt_t BusPatchDataKeyWord() { return fgkBusPatchDataKey; }
     196             :         
     197             :         /// Returns the expected padding word value.
     198             :         static UInt_t PaddingWord() { return fgkPaddingWord; }
     199             :         
     200             :         /// Returns the expected end of DDL marker.
     201             :         static UInt_t EndOfDDLWord() { return fgkEndOfDDL; }
     202             :         
     203             : private:
     204             : 
     205             :         bool fExitOnError; ///< Indicates if we should exit on the very first error.
     206             :         bool fTryRecover; ///< Indicates if we should try recover from a corrupt structure header or DDL trailer.
     207             :         bool fSendDataOnParityError; ///< If set to true then we issue a OnData() event even if the data word had a parity error.
     208             :         bool fHadError; ///< Indicates if we had an error decoding the data.
     209             :         bool fAutoDetectTrailer; ///< Indicates if we should automatically check for the end of DDL trailer (Default = true).
     210             :         bool fCheckForTrailer; ///< Indicates if we should check for the end of DDL trailer (Default = true). This flag is ignored if fAutoDetectTrailer is true.
     211             :         UInt_t fMaxBlocks; ///< Maximum number of block structures allowed in a DDL stream.
     212             :         UInt_t fMaxDSPs; ///< Maximum number of DSP structures allowed in a DDL stream.
     213             :         UInt_t fMaxBusPatches; ///< Maximum number of bus patch structures allowed in a DDL stream.
     214             :         EventHandler fHandler; ///< The event handler which deals with parsing events.
     215             : 
     216             :         void DecodeBuffer(const UChar_t* start, const UChar_t* end);
     217             :         
     218             :         bool DecodeBlockData(
     219             :                         const AliMUONBlockHeaderStruct* blockHeader,
     220             :                         const UChar_t* start, const UChar_t* end
     221             :                 );
     222             : 
     223             :         bool DecodeDSPData(const UChar_t* start, const UChar_t* end);
     224             :         
     225             :         bool DecodeBusPatchData(const UChar_t* start, const UChar_t* end);
     226             : 
     227             :         /// Possible results that can be returned by the TryRecoverStruct method.
     228             :         enum RecoverResult
     229             :         {
     230             :                 kRecoverFailed,        ///< The recovery failed. Cannot continue parsing.
     231             :                 kStructRecovered,      ///< Indicates that we recovered from a corrupt structure header and can continue processing the given structure.
     232             :                 kContinueToNextStruct  ///< Must continue parsing the next structure and ignore the current one.
     233             :         };
     234             : 
     235             :         RecoverResult TryRecoverStruct(
     236             :                         UInt_t expectedKey,
     237             :                         UInt_t headerSize,
     238             :                         UInt_t totalLength,
     239             :                         UInt_t length,
     240             :                         const UChar_t* structStart,
     241             :                         const UChar_t* bufferEnd,
     242             :                         const UChar_t*& dataEnd,
     243             :                         const UChar_t*& structEnd,
     244             :                         const UChar_t*& current
     245             :                 );
     246             :         
     247             :         const UChar_t* FindKey(
     248             :                         UInt_t key, const UChar_t* start, const UChar_t* end
     249             :                 );
     250             :         
     251             :         bool ParityIsOk(UInt_t data);
     252             :         
     253             :         static const UInt_t fgkBlockDataKey;     ///< The key word expected to identify block structure headers.
     254             :         static const UInt_t fgkDSPDataKey;       ///< The key word expected to identify DSP structure headers.
     255             :         static const UInt_t fgkBusPatchDataKey;  ///< The key word expected to identify bus patch headers.
     256             :         static const UInt_t fgkPaddingWord;      ///< The expected format of the padding word in the DDL payload.
     257             :         static const UInt_t fgkEndOfDDL;         ///< The end of DDL trailer word.
     258             : };
     259             : 
     260             : //_____________________________________________________________________________
     261             : 
     262             : // The following are the structure header keys which are used to identify the kind
     263             : // of structure header we are dealing with: block, DSP or bus patch header.
     264             : template <class EventHandler>
     265             : const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkBlockDataKey = 0xFC0000FC;
     266             : template <class EventHandler>
     267             : const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkDSPDataKey = 0xF000000F;
     268             : template <class EventHandler>
     269             : const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkBusPatchDataKey = 0xB000000B;
     270             : template <class EventHandler>
     271             : const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkPaddingWord = 0xBEEFFACE;
     272             : template <class EventHandler>
     273             : const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkEndOfDDL = 0xD000000D;
     274             : 
     275             : 
     276             : template <class EventHandler>
     277             : bool AliMUONTrackerDDLDecoder<EventHandler>::Decode(const void* buffer, UInt_t bufferSize)
     278             : {
     279             :         /// This method should be called to actually decode the DDL payload
     280             :         /// contained in a memory buffer. The payload should be for a muon tracking
     281             :         /// chamber DDL stream.
     282             :         /// As the decoder progresses it will make method calls to the event handler
     283             :         /// instance (which can be accessed with the GetHandler() method) to indicate
     284             :         /// the start of the new block, DSP and bus patch headers. For every raw
     285             :         /// data word the OnData method of the event handler is called.
     286             :         ///
     287             :         /// If an error occurs during the parse because the data is corrupt then
     288             :         /// the OnError method is called indicating what the problem was.
     289             :         /// Decoding will stop at this point unless the fExitOnError flag is set
     290             :         /// to false. Also raw data words which contain a parity error are only
     291             :         /// sent to the event handler with OnData if the fSendDataOnParityError
     292             :         /// flag is set to true. There is also an optional flag fTryRecover which
     293             :         /// can enable logic which will attempt to recover the header structures found
     294             :         /// in the DDL payload if they are found to be inconsistent (assumed corrupt).
     295             :         /// fTryRecover set to true will also enable recovery from a corrupt
     296             :         /// DDL trailer marking the end of DDL payload.
     297             :         ///
     298             :         /// \param buffer  This is the pointer to the start of the memory buffer
     299             :         ///     containing the DDL payload. Remember that this must be the start of
     300             :         ///     the payload and not the DDL stream. That is, this pointer should be
     301             :         ///     equal to: DDL start pointer + 8 * sizeof(UInt_t).
     302             :         /// \param bufferSize  This is the pointer to the first byte just past the
     303             :         ///     end of the block structure.
     304             :         /// \return Returns false if there was any problem with decoding the data,
     305             :         ///     and true otherwise. Note: the data may have been partially decoded
     306             :         ///     even if false was returned, which would be indicated by at least one
     307             :         ///     call to the event handlers OnData method.
     308             :         
     309         160 :         assert( buffer != NULL );
     310             :         
     311          80 :         fHadError = false;
     312             :         
     313             :         // We are basically implementing something like a recursive decent parser.
     314             :         // So start by marking the start of buffer position and end of buffer.
     315             :         const UChar_t* start = reinterpret_cast<const UChar_t*>(buffer);
     316          80 :         const UChar_t* end = start + bufferSize;
     317             :         
     318          80 :         fHandler.OnNewBuffer(buffer, bufferSize);
     319          80 :         DecodeBuffer(start, end);
     320          80 :         fHandler.OnEndOfBuffer(buffer, bufferSize);
     321          80 :         return not fHadError;
     322             : }
     323             : 
     324             : 
     325             : template <class EventHandler>
     326             : bool AliMUONTrackerDDLDecoder<EventHandler>::Decode(void* buffer, UInt_t bufferSize)
     327             : {
     328             :         /// This decoding method performs a special checks to see if the DDL
     329             :         /// corruption is fixable and then fixes the buffer by modifying it directly.
     330             :         /// The fixes only apply if the fTryRecover flag is enabled.
     331             :         /// \note buffer might be modified.
     332             :         
     333         160 :         assert( buffer != NULL );
     334          80 :         if (fTryRecover)
     335             :         {
     336             :                 ///////////////////////////////////////////////////////
     337             :                 // Trick to recover B off data Runs : 119041, 119047, 119055, 119057
     338             :                 // A. Baldisseri May 2010
     339             :                 // Check if 16 32-bit words from a buspatch have been inserted
     340             :                 // incorrectly immediately at the beginning of the DDL payload.
     341             :                 UChar_t* bufferChar = reinterpret_cast<UChar_t*>(buffer);
     342           0 :                 UInt_t* bufferInt = reinterpret_cast<UInt_t*>(buffer);
     343           0 :                 if (bufferSize > 18*4 // is the buffer large enough to check the header.
     344           0 :                     and bufferInt[0] != fgkBlockDataKey and bufferInt[16] == fgkBlockDataKey // was the header incorrectly moved.
     345           0 :                     and bufferSize > bufferInt[17]*4 + sizeof(AliMUONBlockHeaderStruct) // is the buffer large enough for the second block header.
     346           0 :                     and bufferInt[bufferInt[17]] == fgkBlockDataKey  // Check that the second header is in the correct location.
     347           0 :                     and bufferInt[17] == bufferInt[18] + 8  // Make sure that both lengths are correct.
     348           0 :                     and (bufferInt[17] + bufferInt[bufferInt[17]+1]+2)*4 == bufferSize // Check that both blocks will have the correct size if we make the fix.
     349             :                    )
     350             :                 {
     351           0 :                         UChar_t tmpbuf[16*4];
     352           0 :                         memcpy(tmpbuf, bufferChar, 16*4);
     353           0 :                         size_t sizeToMove = bufferInt[17]*4-16*4;
     354           0 :                         memmove(bufferChar, bufferChar+16*4, sizeToMove);
     355           0 :                         memcpy(bufferChar + sizeToMove, tmpbuf, 16*4);
     356           0 :                 }
     357           0 :         }
     358          80 :         return Decode(reinterpret_cast<const void*>(buffer), bufferSize);
     359             : }
     360             : 
     361             : 
     362             : template <class EventHandler>
     363             : void AliMUONTrackerDDLDecoder<EventHandler>::DecodeBuffer(
     364             :                 const UChar_t* start, const UChar_t* end
     365             :         )
     366             : {
     367             :         /// This method decodes the buffer's payload data. It unpacks the block
     368             :         /// structures contained inside and then for each block it calls the
     369             :         /// OnNewBlock method for the event handler to signal the start of each new
     370             :         /// block structure. OnEndOfBlock is called once each block is processed.
     371             :         /// \param start  This is the pointer to the start of the buffer.
     372             :         /// \param end  This is the pointer to the first byte just past the
     373             :         ///             end of the buffer.
     374             :         /// fHadError is set to true if there were any errors decoding the buffer
     375             :         /// and the OnError method of the callback event handler is called for
     376             :         /// each error.
     377             :         
     378         160 :         const UChar_t* current = start;
     379          80 :         const UInt_t* bufferStart = reinterpret_cast<const UInt_t*>(start);
     380          80 :         const UInt_t* bufferEnd = reinterpret_cast<const UInt_t*>(end);
     381             :         bool problemWithTrailer = false;
     382             :         
     383             :         // The DDL payload normally has a 2 word trailer which contains the end of
     384             :         // DDL markers 0xD000000D. But this is not the case for older simulated
     385             :         // data so if we are auto-detecting the trailer then we need to carefully
     386             :         // check if these words are there or not.
     387             :         const UChar_t* endOfBlocks = end;
     388          80 :         const UInt_t* trailerWords = reinterpret_cast<const UInt_t*>(end) - 2;
     389          80 :         if (fAutoDetectTrailer)
     390             :         {
     391         160 :                 if (trailerWords >= bufferStart and trailerWords < bufferEnd
     392         240 :                     and *trailerWords == fgkEndOfDDL and *(trailerWords+1) == fgkEndOfDDL
     393             :                    )
     394             :                 {
     395             :                         // Found the trailer so reposition the end of blocks marker.
     396          80 :                         endOfBlocks = reinterpret_cast<const UChar_t*>(trailerWords);
     397          80 :                 }
     398             :                 // else assume we are dealing with the older data format.
     399             :         }
     400           0 :         else if (fCheckForTrailer)
     401             :         {
     402           0 :                 if (trailerWords >= bufferStart and trailerWords < bufferEnd
     403           0 :                     and *trailerWords == fgkEndOfDDL and *(trailerWords+1) == fgkEndOfDDL
     404             :                    )
     405             :                 {
     406             :                         // Found the trailer so reposition the end of blocks marker.
     407           0 :                         endOfBlocks = reinterpret_cast<const UChar_t*>(trailerWords);
     408           0 :                 }
     409             :                 else
     410             :                 {
     411           0 :                         if (trailerWords+1 >= bufferStart and trailerWords+1 < bufferEnd and *(trailerWords+1) == fgkEndOfDDL)
     412           0 :                                 fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords+1);
     413           0 :                         else if (trailerWords >= bufferStart and trailerWords < bufferEnd and *(trailerWords) == fgkEndOfDDL)
     414           0 :                                 fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords);
     415             :                         else
     416           0 :                                 fHandler.OnError(EventHandler::kNoDDLTrailerWords, end);
     417             :         
     418             :                         // Stop the decoding if so requested by the user, otherwise
     419             :                         // remember about the error so that we return false from the
     420             :                         // Decode() method and continue decoding.
     421           0 :                         fHadError = true;
     422           0 :                         if (fExitOnError) return;
     423             :                         
     424             :                         // Mark that there was a problem with the trailer so that
     425             :                         // for subsequent errors we try to deal with this better.
     426             :                         problemWithTrailer = true;
     427             :                         
     428             :                         // We can also try figure out how many trailer words there
     429             :                         // actually are and move the end of blocks marker back.
     430             :                         
     431           0 :                         if (fTryRecover)
     432             :                         {
     433             :                                 trailerWords = bufferEnd;
     434             :                                 // There should only be a max of 2 trailer words.
     435           0 :                                 if (trailerWords-2 >= bufferStart and trailerWords-2 < bufferEnd and *(trailerWords-2) == fgkEndOfDDL)
     436           0 :                                         trailerWords -= 2;
     437           0 :                                 else if (trailerWords-1 >= bufferStart and trailerWords-1 < bufferEnd and *(trailerWords-1) == fgkEndOfDDL)
     438           0 :                                         trailerWords -= 1;
     439           0 :                                 endOfBlocks = reinterpret_cast<const UChar_t*>(trailerWords);
     440           0 :                         }
     441             :                 }
     442             :         }
     443             : 
     444             :         UInt_t blockCount = 0; // Indicates the number of blocks decoded.
     445         320 :         while (current < endOfBlocks)
     446             :         {
     447             :                 // Mark the start of the block structure.
     448             :                 const UChar_t* blockStart = current;
     449             :                 
     450             :                 // Get the block header, move the current pointer just past the end
     451             :                 // of the header and check that we have not overflowed the buffer.
     452             :                 const AliMUONBlockHeaderStruct* blockHeader
     453         160 :                         = reinterpret_cast<const AliMUONBlockHeaderStruct*>(blockStart);
     454         160 :                 current += sizeof(AliMUONBlockHeaderStruct);
     455         320 :                 if (current > endOfBlocks or current < start)
     456             :                 {
     457             :                         // If we overflowed the pointer and already had an error then
     458             :                         // we are clearly lost so just stop decoding before we segfault.
     459           0 :                         if (current < start and fHadError) return;
     460             :                         
     461             :                         // We first check if we actually hit the end of DDL markers
     462             :                         // If we did then either we did not/could not recover from
     463             :                         // a corrupt trailer or we did not detect a correct trailer
     464             :                         // in auto-detect mode.
     465           0 :                         trailerWords = reinterpret_cast<const UInt_t*>(blockHeader);
     466             :                         // The "trailerWords+1 <= bufferEnd" checks that we are
     467             :                         // not reading beyond the end of the buffer.
     468           0 :                         if (trailerWords+1 <= bufferEnd and *trailerWords == fgkEndOfDDL)
     469             :                         {
     470             :                                 // If we aready knew the trailer was corrupt then just
     471             :                                 // return because the error was already announced.
     472           0 :                                 if (problemWithTrailer) return;
     473             :                                 
     474           0 :                                 if (fAutoDetectTrailer)
     475             :                                 {
     476             :                                         // If we got here then there is at least one correct trailer
     477             :                                         // word, but since we did not detect a correct trailer then
     478             :                                         // there must be only one. Announce the error and exit.
     479           0 :                                         fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords);
     480           0 :                                         fHadError = true;
     481           0 :                                         return;
     482             :                                 }
     483             :                         }
     484             :                         
     485             :                         // So we only got part of a block header at the very end
     486             :                         // of the buffer. Nothing to do but report the error and exit.
     487           0 :                         if (blockCount == fMaxBlocks)
     488             :                                 // Special case where we got all the blocks we
     489             :                                 // expected, so the remaining data must be rubbish.
     490           0 :                                 fHandler.OnError(EventHandler::kBufferTooBig, blockHeader);
     491             :                         else
     492           0 :                                 fHandler.OnError(EventHandler::kNoBlockHeader, blockHeader);
     493           0 :                         fHadError = true;
     494           0 :                         return;
     495             :                 }
     496             :                 
     497             :                 // The header fits the buffer so we can mark the data start and
     498             :                 // read from the header to find the end of data and block pointers.
     499             :                 const UChar_t* dataStart = current;
     500         160 :                 current += blockHeader->fLength * sizeof(UInt_t);
     501         160 :                 const UChar_t* dataEnd = current;
     502         320 :                 const UChar_t* blockEnd = blockStart
     503         160 :                         + blockHeader->fTotalLength * sizeof(UInt_t);
     504             :                 
     505             :                 // Now we need to check for the following things:
     506             :                 // 1) Is the end of block or end of data pointer outside the buffer
     507             :                 //    boundaries.
     508             :                 // 2) Are the values for these pointers the same.
     509             :                 // 3) Is the expected data key in the header present.
     510             :                 // If any of the above fail then we know there is a problem with
     511             :                 // the block header. It must be corrupted somehow.
     512         320 :                 if (blockHeader->fDataKey != fgkBlockDataKey
     513         480 :                     or dataEnd > endOfBlocks or dataEnd < start
     514         480 :                     or blockEnd > endOfBlocks or blockEnd < start
     515         320 :                     or dataEnd != blockEnd)
     516             :                 {
     517             :                         // So let us see what exactly is wrong and report this.
     518           0 :                         if (blockCount == fMaxBlocks)
     519             :                         {
     520             :                                 // Special case where we got all the blocks we
     521             :                                 // expected, so the remaining data must be rubbish.
     522             :                                 // Don't even bother trying to recover the data.
     523           0 :                                 fHandler.OnError(EventHandler::kBufferTooBig, blockHeader);
     524           0 :                                 fHadError = true;
     525           0 :                                 return;
     526             :                         }
     527           0 :                         if (blockHeader->fDataKey != fgkBlockDataKey)
     528           0 :                                 fHandler.OnError(EventHandler::kBadBlockKey, &blockHeader->fDataKey);
     529           0 :                         if (blockEnd > endOfBlocks or blockEnd < start)
     530           0 :                                 fHandler.OnError(EventHandler::kBadBlockLength, &blockHeader->fLength);
     531           0 :                         if (dataEnd > endOfBlocks or dataEnd < start)
     532           0 :                                 fHandler.OnError(EventHandler::kBadBlockTotalLength, &blockHeader->fTotalLength);
     533           0 :                         if (dataEnd != blockEnd)
     534           0 :                                 fHandler.OnError(EventHandler::kBlockLengthMismatch, blockHeader);
     535             :                         
     536             :                         // Stop the decoding if so requested by the user, otherwise
     537             :                         // remember about the error so that we return false from the
     538             :                         // Decode() method and continue decoding.
     539           0 :                         fHadError = true;
     540           0 :                         if (fExitOnError) return;
     541             :                         
     542             :                         // Try to recover from the corrupt header.
     543           0 :                         RecoverResult result = TryRecoverStruct(
     544             :                                         fgkBlockDataKey, sizeof(AliMUONBlockHeaderStruct),
     545           0 :                                         blockHeader->fTotalLength, blockHeader->fLength,
     546             :                                         blockStart, endOfBlocks, dataEnd, blockEnd, current
     547             :                                 );
     548           0 :                         if (result == kContinueToNextStruct)
     549           0 :                                 continue; // Try the next block at 'current'.
     550           0 :                         if (result == kRecoverFailed) return;
     551           0 :                 }
     552             :                 
     553             :                 // At this point we certainly have a valid block header, so we
     554             :                 // need to check if we have more blocks than we expected. If not
     555             :                 // then we can indicate we have another block and decode its data.
     556         320 :                 if (++blockCount > fMaxBlocks)
     557             :                 {
     558         160 :                         fHandler.OnError(EventHandler::kTooManyBlocks, current);
     559             :                         
     560             :                         // In this case we stop the decoding because clearly
     561             :                         // something is seriously wrong with the data if we are
     562             :                         // getting more blocks than expected.
     563           0 :                         fHadError = true;
     564           0 :                         return;
     565             :                 }
     566             :                 
     567         160 :                 fHandler.OnNewBlock(blockHeader, dataStart);
     568         160 :                 if (not DecodeBlockData(blockHeader, dataStart, dataEnd))
     569             :                 {
     570             :                         // At this point we had a problem decoding the block structure's
     571             :                         // data. Thus we should stop further decoding if so requested by
     572             :                         // the user. Note the fHadError flag is already marked inside
     573             :                         // DecodeBlockData.
     574           0 :                         if (fExitOnError)
     575             :                         {
     576           0 :                                 fHandler.OnEndOfBlock(blockHeader, dataStart);
     577           0 :                                 return;
     578             :                         }
     579             :                 }
     580         160 :                 fHandler.OnEndOfBlock(blockHeader, dataStart);
     581         320 :         }
     582         160 : }
     583             : 
     584             : 
     585             : template <class EventHandler>
     586             : bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeBlockData(
     587             :                 const AliMUONBlockHeaderStruct* blockHeader,
     588             :                 const UChar_t* start, const UChar_t* end
     589             :         )
     590             : {
     591             :         /// This method decodes a block structure's data payload. It unpacks the
     592             :         /// DSP structures contained inside and then for each DSP it calls the
     593             :         /// OnNewDSP method for the event handler to signal the start of each new
     594             :         /// DSP structure.
     595             :         /// \param blockHeader
     596             :         /// \param start  This is the pointer to the start of the block
     597             :         ///               structure's data.
     598             :         /// \param end  This is the pointer to the first byte just past the
     599             :         ///             end of the block structure.
     600             :         /// \return If the block structure's data was decoded without errors
     601             :         ///      or we could recover from the errors, then true is returned.
     602             :         ///      False is returned otherwise.
     603             :         
     604         320 :         const UChar_t* current = start;
     605             :         
     606             :         UInt_t dspCount = 0; // Indicates the number of DSPs decoded.
     607        1056 :         while (current < end)
     608             :         {
     609             :                 // Mark the start of the DSP structure.
     610             :                 const UChar_t* dspStart = current;
     611             :                 
     612             :                 // Get the DSP header, move the current pointer just past the end
     613             :                 // of the header and check that we have not overflowed the buffer.
     614             :                 const AliMUONDSPHeaderStruct* dspHeader
     615         736 :                         = reinterpret_cast<const AliMUONDSPHeaderStruct*>(dspStart);
     616         736 :                 current += sizeof(AliMUONDSPHeaderStruct);
     617        1472 :                 if (current > end or current < start)
     618             :                 {
     619             :                         // If we overflowed the pointer and already had an error then
     620             :                         // we are clearly lost so just stop decoding before we segfault.
     621           0 :                         if (current < start and fHadError) return false;
     622             :                         
     623             :                         // So we only got part of a DSP header at the very end of
     624             :                         // the block structure buffer. Nothing to do but report the
     625             :                         // error and exit. Set fHadError in case of further decoding.
     626           0 :                         fHandler.OnError(EventHandler::kNoDSPHeader, dspHeader);
     627           0 :                         fHadError = true;
     628           0 :                         return false;
     629             :                 }
     630             :                 
     631             :                 // The header fits the buffer so we can mark the data start and
     632             :                 // read from the header to find the end of data and DSP pointers.
     633             :                 const UChar_t* dataStart = current;
     634         736 :                 current += dspHeader->fLength * sizeof(UInt_t);
     635         736 :                 const UChar_t* dataEnd = current;
     636         736 :                 const UChar_t* dspEnd = dspStart + dspHeader->fTotalLength * sizeof(UInt_t);
     637             :                 
     638             :                 // Now we need to check for the following things:
     639             :                 // 1) Is the end of DSP or end of data pointer outside the buffer
     640             :                 //    boundaries.
     641             :                 // 2) Are the values for these pointers the same.
     642             :                 // 3) Is the expected data key in the header present.
     643             :                 // If any of the above fail then we know there is a problem with
     644             :                 // the DSP header. It must be corrupted somehow.
     645        1472 :                 if (dspHeader->fDataKey != fgkDSPDataKey
     646        2208 :                     or dataEnd > end or dataEnd < start
     647        2208 :                     or dspEnd > end or dspEnd < start
     648        1472 :                     or dataEnd != dspEnd)
     649             :                 {
     650             :                         // So let us see what exactly is wrong and report this.
     651           0 :                         if (dspHeader->fDataKey != fgkDSPDataKey)
     652           0 :                                 fHandler.OnError(EventHandler::kBadDSPKey, &dspHeader->fDataKey);
     653           0 :                         if (dspEnd > end or dspEnd < start)
     654           0 :                                 fHandler.OnError(EventHandler::kBadDSPLength, &dspHeader->fLength);
     655           0 :                         if (dataEnd > end or dataEnd < start)
     656           0 :                                 fHandler.OnError(EventHandler::kBadDSPTotalLength, &dspHeader->fTotalLength);
     657           0 :                         if (dataEnd != dspEnd)
     658           0 :                                 fHandler.OnError(EventHandler::kDSPLengthMismatch, dspHeader);
     659             :                         
     660             :                         // Indicate we had and error and stop the decoding if so
     661             :                         // requested by the user.
     662           0 :                         fHadError = true;
     663           0 :                         if (fExitOnError) return false;
     664             :                         
     665             :                         // Try to recover from the corrupt header.
     666           0 :                         RecoverResult result = TryRecoverStruct(
     667             :                                         fgkDSPDataKey, sizeof(AliMUONDSPHeaderStruct),
     668           0 :                                         dspHeader->fTotalLength, dspHeader->fLength,
     669             :                                         dspStart, end, dataEnd, dspEnd, current
     670             :                                 );
     671           0 :                         if (result == kContinueToNextStruct)
     672           0 :                                 continue; // Try the next DSP at 'current'.
     673           0 :                         if (result == kRecoverFailed) return false;
     674           0 :                 }
     675             :                 
     676             :                 // At this point we certainly have a valid DSP header, so we
     677             :                 // need to check if we have more DSPs than we expected. If not
     678             :                 // then we can indicate we have another DSP and decode its data.
     679        1472 :                 if (++dspCount > fMaxDSPs)
     680             :                 {
     681         736 :                         fHandler.OnError(EventHandler::kTooManyDSPs, current);
     682             :                         
     683             :                         // In this case we stop further decoding of the block
     684             :                         // structure data because clearly something is seriously
     685             :                         // wrong if we are getting more DSPs than expected.
     686             :                         // Indicate that we had an error so the Decode() method
     687             :                         // returns false.
     688           0 :                         fHadError = true;
     689           0 :                         return false;
     690             :                 }
     691             :                 
     692         736 :                 fHandler.OnNewDSP(dspHeader, dataStart);
     693             :                 
     694             :                 // Check the error word in the header.
     695         736 :                 if (dspHeader->fErrorWord != 0x0)
     696             :                 {
     697           0 :                         if (dspHeader->fErrorWord == (0x000000B1 | blockHeader->fDSPId)
     698           0 :                             or dspHeader->fErrorWord == (0x00000091 | blockHeader->fDSPId)
     699             :                            )
     700             :                         {
     701             :                                 // An event with a glitch in the readout has been detected.
     702             :                                 // It means that somewhere a 1 byte word has been randomly
     703             :                                 // inserted and all the readout sequence is shifted until
     704             :                                 // the next event.
     705           0 :                                 fHandler.OnError(EventHandler::kGlitchFound, &dspHeader->fErrorWord);
     706           0 :                         }
     707           0 :                         else if ((dspHeader->fErrorWord & 0x0000FFF0) == 0x220)
     708             :                         {
     709             :                                 // Detected a TOKEN_LOST error which can affect the dead time in the DAQ.
     710           0 :                                 fHandler.OnError(EventHandler::kTokenLost, &dspHeader->fErrorWord);
     711           0 :                         }
     712             :                         else
     713             :                         {
     714             :                                 // The DSP error code is non-zero but has an unknown code.
     715           0 :                                 fHandler.OnError(EventHandler::kUnknownDspError, &dspHeader->fErrorWord);
     716             :                         }
     717             :                         
     718           0 :                         fHadError = true;
     719           0 :                         if (fExitOnError)
     720             :                         {
     721           0 :                                 fHandler.OnEndOfDSP(dspHeader, dataStart);
     722           0 :                                 return false;
     723             :                         }
     724             :                         
     725             :                         // Try recover by finding the very next DSP and continue
     726             :                         // decoding from there. Note: to achieve this all we have to
     727             :                         // do is continue to the next iteration, because the logic
     728             :                         // will land up calling the FindKey method within the
     729             :                         // TryRecoverStruct method above.
     730           0 :                         if (fTryRecover)
     731             :                         {
     732           0 :                                 fHandler.OnEndOfDSP(dspHeader, dataStart);
     733           0 :                                 continue;
     734             :                         }
     735             :                 }
     736             :                 
     737             :                 // Check if we are padding. If we are, then the bus patch data is
     738             :                 // actually 4 bytes smaller and the last word is a padding word.
     739         736 :                 if (dspHeader->fPaddingWord == 1)
     740             :                 {
     741          50 :                         dataEnd -= sizeof(UInt_t);
     742             :                         
     743             :                         // Check the pad word is correct.
     744          50 :                         const UInt_t* padWord = reinterpret_cast<const UInt_t*>(dataEnd);
     745          50 :                         if (*padWord != fgkPaddingWord)
     746             :                         {
     747           0 :                                 fHandler.OnError(EventHandler::kBadPaddingWord, padWord);
     748           0 :                                 fHadError = true;
     749           0 :                                 if (fExitOnError)
     750             :                                 {
     751           0 :                                         fHandler.OnEndOfDSP(dspHeader, dataStart);
     752           0 :                                         return false;
     753             :                                 }
     754             :                         }
     755          50 :                 }
     756             :                 
     757         736 :                 if (not DecodeDSPData(dataStart, dataEnd))
     758             :                 {
     759             :                         // At this point we had a problem decoding the DSP structure's
     760             :                         // data, thus we should stop further decoding if so requested by
     761             :                         // the user. Note the fHadError flag is already marked inside
     762             :                         // DecodeDSPData.
     763           0 :                         if (fExitOnError)
     764             :                         {
     765           0 :                                 fHandler.OnEndOfDSP(dspHeader, dataStart);
     766           0 :                                 return false;
     767             :                         }
     768             :                 }
     769         736 :                 fHandler.OnEndOfDSP(dspHeader, dataStart);
     770        1472 :         }
     771             :         
     772         160 :         return true;
     773         160 : }
     774             : 
     775             : 
     776             : template <class EventHandler>
     777             : bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeDSPData(
     778             :                 const UChar_t* start, const UChar_t* end
     779             :         )
     780             : {
     781             :         /// This method decodes a DSP structure's data payload. It finds all the
     782             :         /// bus patches found inside and for each it calls the OnNewBusPatch method
     783             :         /// for the event handler to signal the start of each new bus patch.
     784             :         /// \param start  This is the pointer to the start of the DSP structure's data.
     785             :         /// \param end  This is the pointer to the first byte just past the
     786             :         ///             end of the DSP structure.
     787             :         /// \return If the DSP structure's data was decoded without errors
     788             :         ///      or we could recover from the errors, then true is returned.
     789             :         ///      False is returned otherwise.
     790             :         
     791        1472 :         const UChar_t* current = start;
     792             :         
     793             :         UInt_t busPatchCount = 0; // Indicates the number of bus patches decoded.
     794        5024 :         while (current < end)
     795             :         {
     796             :                 // Mark the start of the bus patch structure.
     797             :                 const UChar_t* busPatchStart = current;
     798             :                 
     799             :                 // Get the bus patch header, move the current pointer just past
     800             :                 // the end of the header and check that we have not overflowed
     801             :                 // the buffer.
     802             :                 const AliMUONBusPatchHeaderStruct* busPatchHeader
     803        3552 :                         = reinterpret_cast<const AliMUONBusPatchHeaderStruct*>(busPatchStart);
     804        3552 :                 current += sizeof(AliMUONBusPatchHeaderStruct);
     805        7104 :                 if (current > end or current < start)
     806             :                 {
     807             :                         // If we overflowed the pointer and already had an error then
     808             :                         // we are clearly lost so just stop decoding before we segfault.
     809           0 :                         if (current < start and fHadError) return false;
     810             :                         
     811             :                         // So we only got part of a bus patch header at the very
     812             :                         // end of the DSP structure buffer. Nothing to do but
     813             :                         // report the error and exit. Set fHadError in case of
     814             :                         // further decoding.
     815           0 :                         fHandler.OnError(EventHandler::kNoBusPatchHeader, busPatchHeader);
     816           0 :                         fHadError = true;
     817           0 :                         return false;
     818             :                 }
     819             :                 
     820             :                 // The header fits the buffer so we can mark the data start and
     821             :                 // read from the header to find the end of data and bus patch
     822             :                 // structure pointers.
     823             :                 const UChar_t* dataStart = current;
     824        3552 :                 current += busPatchHeader->fLength * sizeof(UInt_t);
     825        3552 :                 const UChar_t* dataEnd = current;
     826        7104 :                 const UChar_t* busPatchEnd = busPatchStart
     827        3552 :                         + busPatchHeader->fTotalLength * sizeof(UInt_t);
     828             :                 
     829             :                 // Now we need to check for the following things:
     830             :                 // 1) Is the end of bus patch structure or end of data pointer
     831             :                 //    outside the buffer boundaries.
     832             :                 // 2) Are the values for these pointers the same.
     833             :                 // 3) Is the expected data key in the header present.
     834             :                 // If any of the above fail then we know there is a problem with
     835             :                 // the bus patch header. It must be corrupted somehow.
     836        7104 :                 if (busPatchHeader->fDataKey != fgkBusPatchDataKey
     837       10656 :                     or dataEnd > end or dataEnd < start
     838       10656 :                     or busPatchEnd > end or busPatchEnd < start
     839        7104 :                     or dataEnd != busPatchEnd)
     840             :                 {
     841             :                         // So let us see what exactly is wrong and report this.
     842           0 :                         if (busPatchHeader->fDataKey != fgkBusPatchDataKey)
     843           0 :                                 fHandler.OnError(EventHandler::kBadBusPatchKey, &busPatchHeader->fDataKey);
     844           0 :                         if (busPatchEnd > end or busPatchEnd < start)
     845           0 :                                 fHandler.OnError(EventHandler::kBadBusPatchLength, &busPatchHeader->fLength);
     846           0 :                         if (dataEnd > end or dataEnd < start)
     847           0 :                                 fHandler.OnError(EventHandler::kBadBusPatchTotalLength, &busPatchHeader->fTotalLength);
     848           0 :                         if (dataEnd != busPatchEnd)
     849           0 :                                 fHandler.OnError(EventHandler::kBusPatchLengthMismatch, busPatchHeader);
     850             :                         
     851             :                         // Indicate we had and error and stop the decoding if so
     852             :                         // requested by the user.
     853           0 :                         fHadError = true;
     854           0 :                         if (fExitOnError) return false;
     855             :                         
     856             :                         // Try to recover from the corrupt header.
     857           0 :                         RecoverResult result = TryRecoverStruct(
     858             :                                         fgkBusPatchDataKey, sizeof(AliMUONBusPatchHeaderStruct),
     859           0 :                                         busPatchHeader->fTotalLength, busPatchHeader->fLength,
     860             :                                         busPatchStart, end, dataEnd, busPatchEnd, current
     861             :                                 );
     862           0 :                         if (result == kContinueToNextStruct)
     863           0 :                                 continue; // Try the next bus patch at 'current'.
     864           0 :                         if (result == kRecoverFailed) return false;
     865           0 :                 }
     866             :                 
     867             :                 // At this point we certainly have a valid bus patch header, so
     868             :                 // we need to check if we have more bus patches than we expected.
     869             :                 // If not then we can indicate we have another bus patch and
     870             :                 // decode its data.
     871        7104 :                 if (++busPatchCount > fMaxBusPatches)
     872             :                 {
     873        3552 :                         fHandler.OnError(EventHandler::kTooManyBusPatches, current);
     874             :                         
     875             :                         // In this case we stop further decoding of the DSP
     876             :                         // structure's data because clearly something is seriously
     877             :                         // wrong if we are getting more bus patches than expected.
     878             :                         // Indicate that we had an error so the Decode() method
     879             :                         // returns false.
     880           0 :                         fHadError = true;
     881           0 :                         return false;
     882             :                 }
     883             :                 
     884        3552 :                 fHandler.OnNewBusPatch(busPatchHeader, dataStart);
     885        3552 :                 if (not DecodeBusPatchData(dataStart, dataEnd))
     886             :                 {
     887             :                         // At this point we had a problem decoding the bus patch data,
     888             :                         // thus we should stop further decoding if so requested by the
     889             :                         // user. Note the fHadError flag is already marked inside
     890             :                         // DecodeBusPatchData.
     891           0 :                         if (fExitOnError)
     892             :                         {
     893           0 :                                 fHandler.OnEndOfBusPatch(busPatchHeader, dataStart);
     894           0 :                                 return false;
     895             :                         }
     896             :                 }
     897        3552 :                 fHandler.OnEndOfBusPatch(busPatchHeader, dataStart);
     898        7104 :         }
     899             :         
     900         736 :         return true;
     901         736 : }
     902             : 
     903             : 
     904             : template <class EventHandler>
     905             : bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeBusPatchData(
     906             :                 const UChar_t* start, const UChar_t* end
     907             :         )
     908             : {
     909             :         /// This method decodes a single bus patch's data payload.
     910             :         /// It will check the parity of the raw data words and send them
     911             :         /// to the event handler instance with calls to OnData.
     912             :         /// \param start  This is the pointer to the start of the bus patch
     913             :         ///               structure's data.
     914             :         /// \param end  This is the pointer to the first byte just past the
     915             :         ///             end of the bus patch structure.
     916             :         /// \return If the bus patch's data was decoded without errors
     917             :         ///      or we could recover from the errors, then true is returned.
     918             :         ///      False is returned otherwise.
     919             : 
     920             :         // Assert that 'end' is always larger than start by n*sizeof(UInt_t)
     921             :         // where n is a positive integer. This should be the case because we
     922             :         // always add multiples of sizeof(UInt_t) to the 'current' pointer in
     923             :         // all the DecodeXYZ methods.
     924        7104 :         assert( UInt_t(end - start) % 4 == 0 );
     925             :         
     926             :         // Now step through all the data words and issue OnData events.
     927             :         // We also need to check parity and signal OnError if it is not valid
     928             :         // for any of the data words.
     929        3552 :         const UInt_t* data = reinterpret_cast<const UInt_t*>(start);
     930        3552 :         const UInt_t* dataEnd = reinterpret_cast<const UInt_t*>(end);
     931        8520 :         for (; data < dataEnd; data++)
     932             :         {
     933        1416 :                 if (ParityIsOk(*data))
     934             :                 {
     935        1416 :                         fHandler.OnData(*data, false);
     936         708 :                 }
     937             :                 else
     938             :                 {
     939             :                         // Indicate we had a parity error and exit immediately
     940             :                         // if the user so requested.
     941           0 :                         fHandler.OnError(EventHandler::kParityError, data);
     942           0 :                         fHadError = true;
     943           0 :                         if (fExitOnError) return false;
     944             :                         
     945           0 :                         if (fSendDataOnParityError)
     946           0 :                                 fHandler.OnData(*data, true);
     947             :                 }
     948             :         }
     949             :         
     950        3552 :         return true;
     951        3552 : }
     952             : 
     953             : 
     954             : template <class EventHandler>
     955             : typename AliMUONTrackerDDLDecoder<EventHandler>::RecoverResult
     956             : AliMUONTrackerDDLDecoder<EventHandler>::TryRecoverStruct(
     957             :                 UInt_t expectedKey,
     958             :                 UInt_t headerSize,
     959             :                 UInt_t totalLength,
     960             :                 UInt_t length,
     961             :                 const UChar_t* structStart,
     962             :                 const UChar_t* bufferEnd,
     963             :                 const UChar_t*& dataEnd,
     964             :                 const UChar_t*& structEnd,
     965             :                 const UChar_t*& current
     966             :         )
     967             : {
     968             :         /// This method attempts to recover from a corrupt structure header by
     969             :         /// figuring out which of the structure size indicators is correct.
     970             :         /// This is possible because each header has some redundant information.
     971             :         /// The recovery procedure is only attempted if fTryRecover was set to
     972             :         /// true. If the recovery procedure is successful then this method will
     973             :         /// also update the pointers indicating the start of data, end of structure
     974             :         /// and current parsing position with the correct values.
     975             :         ///
     976             :         /// [in]  \param expectedKey This is the expected block key for the header
     977             :         ///           currently being processed.
     978             :         /// [in]  \param headerSize  The expected header size as given by the sizeof
     979             :         ///           operator for example.
     980             :         /// [in]  \param totalLength The total length as given by the fTotalLength
     981             :         ///           field in the current header being handled.
     982             :         /// [in]  \param length  The data length as given by the fLength field
     983             :         ///           in the current header being handled.
     984             :         /// [in]  \param structStart A pointer to the start of the structure header.
     985             :         /// [in]  \param bufferEnd A pointer to the first byte just past the end
     986             :         ///           of the buffer. This could be the pointer to the first byte
     987             :         ///           just past the end of the parent structure if we are dealing
     988             :         ///           with a DSP structure or bus patch. The parent structure for
     989             :         ///           the DSP is a block structure and for a bus patch it is a DSP.
     990             :         /// [out] \param dataEnd This is the pointer to the first byte just past
     991             :         ///           the end of the structure being processed. It should be equal to
     992             :         ///           structStart + sizeof(structure header) + fLength, where fLength
     993             :         ///           is the field found in the structure's header itself. This value
     994             :         ///           will be corrected and updated if we could recover from the
     995             :         ///           corruption in the header.
     996             :         /// [out] \param structEnd A pointer to the first byte just past the end of
     997             :         ///           the structure. This value should be set equal to
     998             :         ///           structStart + fTotalLength * sizeof(UInt_t), where fTotalLength
     999             :         ///           is the field found in the structure's header itself. This value
    1000             :         ///           will be corrected and updated if we could recover from the
    1001             :         ///           corruption in the header.
    1002             :         /// [out] \param current This is the pointer to the current location in
    1003             :         ///           the DDL payload being parsed. It should in principle point
    1004             :         ///           to the start of the structures data. This value will be
    1005             :         ///           corrected and updated if we could recover from the corruption
    1006             :         ///           in the header.
    1007             :         ///
    1008             :         /// \return Returns the result of the recovery attempt, which can be one
    1009             :         ///    of the following:
    1010             :         ///      kRecoverFailed - The recovery failed completely so the caller
    1011             :         ///           cannot continue parsing any more structures. If the failure
    1012             :         ///           is within a DSP then one could still continue parsing
    1013             :         ///           from the next block. Similarly for bus patches, parsing could
    1014             :         ///           continue from the next DSP structure.
    1015             :         ///      kStructRecovered - Indicates that we recovered from a corrupt
    1016             :         ///           structure header and can continue processing the data of the
    1017             :         ///           structure in question.
    1018             :         ///      kContinueToNextStruct - Either fTryRecover was set to false or we
    1019             :         ///           could not recover from the corrupt header but we did find the
    1020             :         ///           start of another header matching the expected key so parsing
    1021             :         ///           can continue from the updated current position.
    1022             : 
    1023             :         // Check if the user wants us to try and recover from a corrupt header.
    1024           0 :         if (not fTryRecover) return kContinueToNextStruct;
    1025             :         
    1026             :         // If the user wants us to try recover, then try to recover what the
    1027             :         // correct values for dataEnd, structEnd and current were supposed to be.
    1028             :         // The recovery procedure is as follows: We have 4 conditions for a correct
    1029             :         // header:
    1030             :         //   1) The header key is what we expect.
    1031             :         //   2) The totalLength equals length + headerSize.
    1032             :         //   3) The word at dataEnd contains a valid key. (implies length is
    1033             :         //      correct.)
    1034             :         //   4) The word at structEnd contains a valid key. (implies totalLength
    1035             :         //      is correct.)
    1036             :         // If any 2 of these conditions hold then we know that only one of the
    1037             :         // header fields is corrupt and we have enough information to reconstruct
    1038             :         // the third field. Note that if conditions 3 and 4 are true then this
    1039             :         // implies 2 is also true. (not necessarily the other way around though.)
    1040             :         // The valid key mentioned above at dataEnd and structEnd should be:
    1041             :         //   a) A bus patch key, DSP key or end of buffer if expectedKey indicates
    1042             :         //      a buspatch.
    1043             :         //   b) A DSP key, block structure key or end of buffer if expectedKey
    1044             :         //      indicates a DSP.
    1045             :         //   c) A block structure key or end of buffer if expectedKey indicates
    1046             :         //      a DSP.
    1047           0 :         const UInt_t* headerKey = reinterpret_cast<const UInt_t*>(structStart);
    1048           0 :         bool headerKeyOk = (expectedKey == *headerKey);
    1049             :         
    1050           0 :         bool lengthsMatch = (totalLength*4 == length*4 + headerSize);
    1051             :         
    1052             :         bool lengthIsCorrect = false;
    1053             :         bool totalLengthIsCorrect = false;
    1054           0 :         const UInt_t* keyAtDataEnd = reinterpret_cast<const UInt_t*>(dataEnd);
    1055           0 :         const UInt_t* keyAtStructEnd = reinterpret_cast<const UInt_t*>(structEnd);
    1056             :         
    1057             : 
    1058           0 :         if ( expectedKey == fgkBlockDataKey )
    1059             :         {
    1060           0 :                 if (dataEnd == bufferEnd)
    1061             :                 {
    1062             :                         // Are we at the end of the buffer?
    1063             :                         lengthIsCorrect = true;
    1064           0 :                 }
    1065             :                 else
    1066             :                 {
    1067             :                         // Must check that we can read another 4 bytes before
    1068             :                         // checking the key at dataEnd.
    1069           0 :                         if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
    1070             :                         {
    1071           0 :                                 if (*keyAtDataEnd == fgkBlockDataKey)
    1072           0 :                                         lengthIsCorrect = true;
    1073             :                         }
    1074             :                 }
    1075             :                 
    1076           0 :                 if (structEnd == bufferEnd)
    1077             :                 {
    1078             :                         // Are we at the end of the buffer?
    1079             :                         totalLengthIsCorrect = true;
    1080           0 :                 }
    1081             :                 else
    1082             :                 {
    1083             :                         // Must check that we can read another 4 bytes before
    1084             :                         // checking the key at structEnd.
    1085           0 :                         if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
    1086             :                         {
    1087           0 :                                 if (*keyAtStructEnd == fgkBlockDataKey)
    1088           0 :                                         totalLengthIsCorrect = true;
    1089             :                         }
    1090             :                 }
    1091             :         }        
    1092             :                         
    1093           0 :         else if ( expectedKey == fgkDSPDataKey )
    1094             :         {
    1095           0 :                 if (dataEnd == bufferEnd)
    1096             :                 {
    1097             :                         // Are we at the end of the buffer?
    1098             :                         lengthIsCorrect = true;
    1099           0 :                 }
    1100             :                 else
    1101             :                 {
    1102             :                         // Must check that we can read another 4 bytes before
    1103             :                         // checking the key at dataEnd.
    1104           0 :                         if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
    1105             :                         {
    1106           0 :                                 if (*keyAtDataEnd == fgkBlockDataKey
    1107           0 :                                     or *keyAtDataEnd == fgkDSPDataKey)
    1108           0 :                                         lengthIsCorrect = true;
    1109             :                         }
    1110             :                 }
    1111             :                 
    1112           0 :                 if (structEnd == bufferEnd)
    1113             :                 {
    1114             :                         // Are we at the end of the buffer?
    1115             :                         totalLengthIsCorrect = true;
    1116           0 :                 }
    1117             :                 else
    1118             :                 {
    1119             :                         // Must check that we can read another 4 bytes before
    1120             :                         // checking the key at structEnd.
    1121           0 :                         if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
    1122             :                         {
    1123           0 :                                 if (*keyAtStructEnd == fgkBlockDataKey
    1124           0 :                                     or *keyAtStructEnd == fgkDSPDataKey)
    1125           0 :                                         totalLengthIsCorrect = true;
    1126             :                         }
    1127             :                 }
    1128             :         }        
    1129           0 :         else if ( expectedKey == fgkBusPatchDataKey )
    1130             :         {
    1131           0 :                 if (dataEnd == bufferEnd)
    1132             :                 {
    1133             :                         // Are we at the end of the buffer?
    1134             :                         lengthIsCorrect = true;
    1135           0 :                 }
    1136             :                 else
    1137             :                 {
    1138             :                         // Must check that we can read another 4 bytes before
    1139             :                         // checking the key at dataEnd.
    1140           0 :                         if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
    1141             :                         {
    1142           0 :                                 if (*keyAtDataEnd == fgkDSPDataKey
    1143           0 :                                     or *keyAtDataEnd == fgkBusPatchDataKey)
    1144           0 :                                         lengthIsCorrect = true;
    1145             :                         }
    1146             :                 }
    1147             :                 
    1148           0 :                 if (structEnd == bufferEnd)
    1149             :                 {
    1150             :                         // Are we at the end of the buffer?
    1151             :                         totalLengthIsCorrect = true;
    1152           0 :                 }
    1153             :                 else
    1154             :                 {
    1155             :                         // Must check that we can read another 4 bytes before
    1156             :                         // checking the key at structEnd.
    1157           0 :                         if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
    1158             :                         {
    1159           0 :                                 if (*keyAtStructEnd == fgkDSPDataKey
    1160           0 :                                     or *keyAtStructEnd == fgkBusPatchDataKey)
    1161           0 :                                         totalLengthIsCorrect = true;
    1162             :                         }
    1163             :                 }
    1164             :         }
    1165             :         
    1166           0 :         if (headerKeyOk and lengthIsCorrect)
    1167             :         {
    1168             :                 // totalLength was wrong, dataEnd is correct.
    1169           0 :                 structEnd = dataEnd;
    1170           0 :                 current = dataEnd;
    1171           0 :                 return kStructRecovered;
    1172             :         }
    1173           0 :         if (headerKeyOk and totalLengthIsCorrect)
    1174             :         {
    1175             :                 // Length was wrong, structEnd is correct.
    1176           0 :                 dataEnd = structEnd;
    1177           0 :                 current = structEnd;
    1178           0 :                 return kStructRecovered;
    1179             :         }
    1180           0 :         if (lengthsMatch and lengthIsCorrect and totalLengthIsCorrect)
    1181             :         {
    1182             :                 // The header's key was wrong but the lengths and pointers are OK.
    1183           0 :                 return kStructRecovered;
    1184             :         }
    1185             :         
    1186             :         // Could not recover the header from the available information, so find
    1187             :         // the next key in the stream that is the same as the currently expected
    1188             :         // one and continue decoding from there.
    1189           0 :         const UChar_t* location = FindKey(
    1190           0 :                         expectedKey, structStart + sizeof(UInt_t), bufferEnd
    1191             :                 );
    1192           0 :         if (location != NULL)
    1193             :         {
    1194           0 :                 current = location;
    1195           0 :                 return kContinueToNextStruct;
    1196             :         }
    1197             : 
    1198           0 :         return kRecoverFailed;
    1199           0 : }
    1200             : 
    1201             : 
    1202             : template <class EventHandler>
    1203             : const UChar_t* AliMUONTrackerDDLDecoder<EventHandler>::FindKey(
    1204             :                 UInt_t key, const UChar_t* start, const UChar_t* end
    1205             :         )
    1206             : {
    1207             :         /// Searches for the first occurrence of the key value in the buffer marked by
    1208             :         /// 'start' and 'end'. 'start' should point to the start of the buffer and 'end'
    1209             :         /// should point to 'start + bufferSize', i.e. just past the last byte of the
    1210             :         /// buffer. If the key was found then the pointer to that location is returned
    1211             :         /// otherwise NULL is returned.
    1212             :         
    1213           0 :         if (end + sizeof(UInt_t) < start) return NULL;  // check for pointer overflow.
    1214             :         const UChar_t* current = start;
    1215           0 :         while (current + sizeof(UInt_t) <= end)
    1216             :         {
    1217           0 :                 UInt_t data = * reinterpret_cast<const UInt_t*>(current);
    1218           0 :                 if (data == key) return current;
    1219           0 :                 current++;
    1220           0 :         }
    1221           0 :         return NULL;
    1222           0 : }
    1223             : 
    1224             : 
    1225             : template <class EventHandler>
    1226             : bool AliMUONTrackerDDLDecoder<EventHandler>::ParityIsOk(UInt_t data)
    1227             : {
    1228             :         /// Optimised parity check addapted from:
    1229             :         /// http://graphics.stanford.edu/~seander/bithacks.html#ParityParallel
    1230             :         
    1231             :         // parity of the 32 bits must be zero if the last bit is equal
    1232             :         // to the parity of the first 31 bits.
    1233             :         // Reason: the parity bit xor the parity of the first 31 bits must give
    1234             :         // zero, unless there was a bit error.
    1235        1416 :         data ^= data >> 16;
    1236         708 :         data ^= data >> 8;
    1237         708 :         data ^= data >> 4;
    1238         708 :         data &= 0xf;
    1239         708 :         data = ((0x6996 >> data) & 1);
    1240         708 :         return data == 0;
    1241             : }
    1242             : 
    1243             : #endif // ALIMUONTRACKERDDLDECODER_H

Generated by: LCOV version 1.11