From 29b6be6ad44a53b52ae3f60070c88e8720ad83d6 Mon Sep 17 00:00:00 2001 From: ivana Date: Tue, 15 Apr 2008 13:40:09 +0000 Subject: [PATCH] Updated the fast decoder to take into account the end of DDL (0xD000000D) trailer words which are generated by our readout electronics. The decoder auto-detects this trailer and does not complain if it is missing (unless it is corrupt). This can be turned off by setting the fAutoDetectTrailer to false. Then one can tell the decoder if it should expect the trailer or not with the fCheckForTrailer flag. fCheckForTrailer = true for the read data (or new AliRoot) and fCheckForTrailer = false for old simulated data. (Artur) --- MUON/AliMUONRawStreamTrackerHP.h | 18 +++ MUON/AliMUONTrackerDDLDecoder.h | 138 ++++++++++++++++++-- MUON/AliMUONTrackerDDLDecoderEventHandler.h | 8 ++ MUON/MUONTimeRawStreamTracker.C | 3 + 4 files changed, 158 insertions(+), 9 deletions(-) diff --git a/MUON/AliMUONRawStreamTrackerHP.h b/MUON/AliMUONRawStreamTrackerHP.h index 2ede43711ac..a2acc1fa3e7 100644 --- a/MUON/AliMUONRawStreamTrackerHP.h +++ b/MUON/AliMUONRawStreamTrackerHP.h @@ -105,6 +105,24 @@ public: /// payload headers. void TryRecover(Bool_t value) { fDecoder.TryRecover(bool(value)); } + /// Returns the auto-detect trailer words flag. + Bool_t AutoDetectTrailer() const { return Bool_t(fDecoder.AutoDetectTrailer()); } + + /// Sets the auto-detect trailer words flag. + /// When set to true the decoder will try to detect if the end of DDL + /// keys are in the trailer words or not. These are generated by the + /// detector but not the older versions of AliRoot simulations. + void AutoDetectTrailer(Bool_t value) { fDecoder.AutoDetectTrailer(bool(value)); } + + /// Returns the flag indicating if the data is expected to have the + /// end of DDL keys in the trailer. This flag is ignored if AutoDetectTrailer() + /// was set to true. + Bool_t CheckForTrailer() const { return Bool_t(fDecoder.CheckForTrailer()); } + + /// Sets the flag indicating if the trailer words should contain the + /// end of DDL key. + void CheckForTrailer(Bool_t value) { fDecoder.CheckForTrailer(bool(value)); } + /// Light weight interface class to the block header data. class AliBlockHeader { diff --git a/MUON/AliMUONTrackerDDLDecoder.h b/MUON/AliMUONTrackerDDLDecoder.h index c64c272cee2..694a0157d47 100644 --- a/MUON/AliMUONTrackerDDLDecoder.h +++ b/MUON/AliMUONTrackerDDLDecoder.h @@ -81,6 +81,18 @@ /// significantly slower if run time polymorphism was used i.e. making the class /// AliMUONTrackerDDLDecoderEventHandler abstract and using virtual methods. /// +/// There has been a change to the data format that the real detector generates. +/// Two trailer words are added to the end of the DDL payload which indicated +/// the end of data. The decoder is initialised by default to automatically +/// check for these and deal with it correctly, if they exist or not. +/// However, if you want to override this behaviour then set the flag +/// fAutoDetectTrailer to false with AutoDetectTrailer(false). Then if you have +/// data with the old data format you should set fCheckForTrailer to false with +/// CheckForTrailer(false), otherwise for real data it should be +/// fCheckForTrailer = true. Only when fAutoDetectTrailer is true will the +/// fCheckForTrailer flag be ignored and no warnings will be generated for an +/// incorrect data format. +/// /// \author Artur Szostak template @@ -92,6 +104,7 @@ public: AliMUONTrackerDDLDecoder() : fExitOnError(true), fTryRecover(false), fSendDataOnParityError(false), fHadError(false), + fAutoDetectTrailer(true), fCheckForTrailer(true), fMaxBlocks(2), fMaxDSPs(5), fMaxBusPatches(5), fHandler() {} @@ -111,12 +124,12 @@ public: /// Returns the "try to recover from errors" flag. /// i.e. should the decoder try to recover from errors found in the - /// payload headers. + /// payload headers or trailers. bool TryRecover() const { return fTryRecover; } /// Sets the "try to recover from errors" flag. /// i.e. should the decoder try to recover from errors found in the - /// payload headers. + /// payload headers or trailers. void TryRecover(bool value) { fTryRecover = value; } /// Returns the flag indicating if the raw data words in the bus patches @@ -151,15 +164,29 @@ public: /// structure within the DDL payload. void MaxBusPatches(UInt_t n) { fMaxBusPatches = n; } + /// Returns the value of the auto-detect trailer flag. + bool AutoDetectTrailer() const { return fAutoDetectTrailer; } + + /// Sets the value of the auto-detect trailer flag. + void AutoDetectTrailer(bool value) { fAutoDetectTrailer = value; } + + /// Returns the value of the flag to check for the end of DDL trailer. + bool CheckForTrailer() const { return fCheckForTrailer; } + + /// Sets the value of the flag to check for the end of DDL trailer. + void CheckForTrailer(bool value) { fCheckForTrailer = value; } + /// This method decodes the DDL payload contained in the buffer. bool Decode(const void* buffer, UInt_t bufferSize); private: bool fExitOnError; ///< Indicates if we should exit on the very first error. - bool fTryRecover; ///< Indicates if we should try recover from a corrupt structure header. + bool fTryRecover; ///< Indicates if we should try recover from a corrupt structure header or DDL trailer. bool fSendDataOnParityError; ///< If set to true then we issue a OnData() event even if the data word had a parity error. bool fHadError; ///< Indicates if we had an error decoding the data. + bool fAutoDetectTrailer; ///< Indicates if we should automatically check for the end of DDL trailer (Default = true). + bool fCheckForTrailer; ///< Indicates if we should check for the end of DDL trailer (Default = true). This flag is ignored if fAutoDetectTrailer is true. UInt_t fMaxBlocks; ///< Maximum number of block structures allowed in a DDL stream. UInt_t fMaxDSPs; ///< Maximum number of DSP structures allowed in a DDL stream. UInt_t fMaxBusPatches; ///< Maximum number of bus patch structures allowed in a DDL stream. @@ -206,6 +233,7 @@ private: static const UInt_t fgkDSPDataKey; ///< The key word expected to identify DSP structure headers. static const UInt_t fgkBusPatchDataKey; ///< The key word expected to identify bus patch headers. static const UInt_t fgkPaddingWord; ///< The expected format of the padding word in the DDL payload. + static const UInt_t fgkEndOfDDL; ///< The end of DDL trailer word. }; //_____________________________________________________________________________ @@ -220,6 +248,8 @@ template const UInt_t AliMUONTrackerDDLDecoder::fgkBusPatchDataKey = 0xB000000B; template const UInt_t AliMUONTrackerDDLDecoder::fgkPaddingWord = 0xBEEFFACE; +template +const UInt_t AliMUONTrackerDDLDecoder::fgkEndOfDDL = 0xD000000D; template @@ -241,6 +271,8 @@ bool AliMUONTrackerDDLDecoder::Decode(const void* buffer, UInt_t b /// flag is set to true. There is also an optional flag fTryRecover which /// can enable logic which will attempt to recover the header structures found /// in the DDL payload if they are found to be inconsistent (assumed corrupt). + /// fTryRecover set to true will also enable recovery from a corrupt + /// DDL trailer marking the end of DDL payload. /// /// \param buffer This is the pointer to the start of the memory buffer /// containing the DDL payload. Remember that this must be the start of @@ -286,9 +318,73 @@ void AliMUONTrackerDDLDecoder::DecodeBuffer( /// False is returned otherwise. const UChar_t* current = start; + const UInt_t* bufferStart = reinterpret_cast(start); + const UInt_t* bufferEnd = reinterpret_cast(end); + bool problemWithTrailer = false; + + // The DDL payload normally has a 2 word trailer which contains the end of + // DDL markers 0xD000000D. But this is not the case for older simulated + // data so if we are autodetecting the trailer then we need to carefully + // check if these words are there or not. + const UChar_t* endOfBlocks = end; + const UInt_t* trailerWords = reinterpret_cast(end) - 2; + if (fAutoDetectTrailer) + { + if (trailerWords >= bufferStart and *trailerWords == fgkEndOfDDL + and *(trailerWords+1) == fgkEndOfDDL + ) + { + // Found the trailer so reposition the end of blocks marker. + endOfBlocks = reinterpret_cast(trailerWords); + } + // else assume we are dealing with the older data format. + } + else if (fCheckForTrailer) + { + if (trailerWords >= bufferStart and *trailerWords == fgkEndOfDDL + and *(trailerWords+1) == fgkEndOfDDL + ) + { + // Found the trailer so reposition the end of blocks marker. + endOfBlocks = reinterpret_cast(trailerWords); + } + else + { + if (trailerWords+1 >= bufferStart and *(trailerWords+1) == fgkEndOfDDL) + fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords+1); + else if (trailerWords >= bufferStart and *(trailerWords) == fgkEndOfDDL) + fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords); + else + fHandler.OnError(EventHandler::kNoDDLTrailerWords, end); + + // Stop the decoding if so requested by the user, otherwise + // remember about the error so that we return false from the + // Decode() method and continue decoding. + fHadError = true; + if (fExitOnError) return; + + // Mark that there was a problem with the trailer so that + // for subsequest errors we try to deal with this better. + problemWithTrailer = true; + + // We can also try figure out how many trailer words there + // actually are and move the end of blocks marker back. + + if (fTryRecover) + { + trailerWords = bufferEnd; + // There should only be a max of 2 trailer words. + if (*(trailerWords-1) == fgkEndOfDDL) + trailerWords--; + else if (*(trailerWords-1) == fgkEndOfDDL) + trailerWords--; + endOfBlocks = reinterpret_cast(trailerWords); + } + } + } UInt_t blockCount = 0; // Indicates the number of blocks decoded. - while (current < end) + while (current < endOfBlocks) { // Mark the start of the block structure. const UChar_t* blockStart = current; @@ -298,8 +394,32 @@ void AliMUONTrackerDDLDecoder::DecodeBuffer( const AliMUONBlockHeaderStruct* blockHeader = reinterpret_cast(blockStart); current += sizeof(AliMUONBlockHeaderStruct); - if (current > end) + if (current > endOfBlocks) { + // We first check if we actually hit the end of DDL markers + // If we did then either we did not/could not recover from + // a corrupt trailer or we did not detect a correct trailer + // in auto-detect mode. + trailerWords = reinterpret_cast(blockHeader); + // The "trailerWords+1 <= bufferEnd" checks that we are + // not reading beyond the end of the buffer. + if (trailerWords+1 <= bufferEnd and *trailerWords == fgkEndOfDDL) + { + // If we aready knew the trailer was corrupt then just + // return because the error was already announced. + if (problemWithTrailer) return; + + if (fAutoDetectTrailer) + { + // If we got here then there is at least one correct trailer + // word, but since we did not detect a currect trailer then + // there must be only one. Announce the error and exit. + fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords); + fHadError = true; + return; + } + } + // So we only got part of a block header at the very end // of the buffer. Nothing to do but report the error and exit. if (blockCount == fMaxBlocks) @@ -328,7 +448,7 @@ void AliMUONTrackerDDLDecoder::DecodeBuffer( // If any of the above fail then we know there is a problem with // the block header. It must be corrupted somehow. if (blockHeader->fDataKey != fgkBlockDataKey - or dataEnd > end or blockEnd > end or dataEnd != blockEnd) + or dataEnd > endOfBlocks or blockEnd > endOfBlocks or dataEnd != blockEnd) { // So let us see what exactly is wrong and report this. if (blockCount == fMaxBlocks) @@ -342,9 +462,9 @@ void AliMUONTrackerDDLDecoder::DecodeBuffer( } if (blockHeader->fDataKey != fgkBlockDataKey) fHandler.OnError(EventHandler::kBadBlockKey, &blockHeader->fDataKey); - if (blockEnd > end) + if (blockEnd > endOfBlocks) fHandler.OnError(EventHandler::kBadBlockLength, &blockHeader->fLength); - if (dataEnd > end) + if (dataEnd > endOfBlocks) fHandler.OnError(EventHandler::kBadBlockTotalLength, &blockHeader->fTotalLength); if (dataEnd != blockEnd) fHandler.OnError(EventHandler::kBlockLengthMismatch, blockHeader); @@ -359,7 +479,7 @@ void AliMUONTrackerDDLDecoder::DecodeBuffer( RecoverResult result = TryRecoverStruct( fgkBlockDataKey, sizeof(AliMUONBlockHeaderStruct), blockHeader->fTotalLength, blockHeader->fLength, - blockStart, end, dataEnd, blockEnd, current + blockStart, endOfBlocks, dataEnd, blockEnd, current ); if (result == kContinueToNextStruct) continue; // Try the next block at 'current'. diff --git a/MUON/AliMUONTrackerDDLDecoderEventHandler.h b/MUON/AliMUONTrackerDDLDecoderEventHandler.h index 9303b934f61..d1df33b3b2d 100644 --- a/MUON/AliMUONTrackerDDLDecoderEventHandler.h +++ b/MUON/AliMUONTrackerDDLDecoderEventHandler.h @@ -124,6 +124,8 @@ public: kBadBusPatchLength = 26, /// The bus patch length field points past the end of the DSP structure. kBadBusPatchTotalLength = 27, /// The total bus patch length field points past the end of the DSP structure. kBusPatchLengthMismatch = 28, /// The bus patch length and total length fields do not correspond. One or both of these values is incorrect. + kNoDDLTrailerWords = 29, /// No end of DDL markers found in the trailer words. + kTooFewDDLTrailerWords = 30, /// Only one end of DDL marker trailer word found but expected two. // match up error codes with AliMUONRawStreamTracker: kGlitchFound = 1, /// Found a glitch. This means a 1 byte word has been randomly inserted into the raw data by mistake. kBadPaddingWord = 2, /// The padding word does not contain the correct value. @@ -310,6 +312,8 @@ inline const char* AliMUONTrackerDDLDecoderEventHandler::ErrorCodeToString(Error case kBadBusPatchLength: return "kBadBusPatchLength"; case kBadBusPatchTotalLength: return "kBadBusPatchTotalLength"; case kBusPatchLengthMismatch: return "kBusPatchLengthMismatch"; + case kNoDDLTrailerWords: return "kNoDDLTrailerWords"; + case kTooFewDDLTrailerWords: return "kTooFewDDLTrailerWords"; case kGlitchFound: return "kGlitchFound"; case kBadPaddingWord: return "kBadPaddingWord"; case kParityError: return "kParityError"; @@ -376,6 +380,10 @@ inline const char* AliMUONTrackerDDLDecoderEventHandler::ErrorCodeToMessage(Erro case kBusPatchLengthMismatch: return "The bus patch length and total length fields do not correspond." " One or both of these values is incorrect."; + case kNoDDLTrailerWords: + return "No end of DDL data key found in the trailer words."; + case kTooFewDDLTrailerWords: + return "Only one end of DDL data key word found in the trailer but expected two."; case kGlitchFound: return "Found a glitch. This means a 1 byte word has been randomly" " inserted into the raw data by mistake."; diff --git a/MUON/MUONTimeRawStreamTracker.C b/MUON/MUONTimeRawStreamTracker.C index d0c96748f9c..f2bc6449335 100644 --- a/MUON/MUONTimeRawStreamTracker.C +++ b/MUON/MUONTimeRawStreamTracker.C @@ -191,6 +191,7 @@ Double_t TimeUsingOldDecoder(AliBufferInfo* list, AliDigitInfo* buffer, UInt_t m AliRawReaderMemory rawReader; AliMUONRawStreamTracker rawStream(&rawReader); + rawReader.NextEvent(); TStopwatch timer; timer.Start(kTRUE); @@ -233,6 +234,7 @@ Double_t TimeUsingNewDecoder(AliBufferInfo* list, AliDigitInfo* buffer, UInt_t m AliRawReaderMemory rawReader; AliMUONRawStreamTrackerHP rawStream(&rawReader); + rawReader.NextEvent(); TStopwatch timer; timer.Start(kTRUE); @@ -280,6 +282,7 @@ Double_t TimeUsingNewDecoderOldInterface(AliBufferInfo* list, AliDigitInfo* buff AliRawReaderMemory rawReader; AliMUONRawStreamTrackerHP rawStream(&rawReader); + rawReader.NextEvent(); TStopwatch timer; timer.Start(kTRUE); -- 2.43.0