/// must be checked before any proposed modification is made to this file.
///
+#include <string.h>
#include "AliMUONTrackerDDLDecoderEventHandler.h"
/// \ingroup raw
/// This method decodes the DDL payload contained in the buffer.
bool Decode(const void* buffer, UInt_t bufferSize);
+ /// First try fix data corruption and then decode the DDL payload.
+ bool Decode(void* buffer, UInt_t bufferSize);
+
+ /// Returns the block marker key.
+ static UInt_t BlockDataKeyWord() { return fgkBlockDataKey; }
+
+ /// Returns the DSP marker key.
+ static UInt_t DspDataKeyWord() { return fgkDSPDataKey; }
+
+ /// Returns the bus patch marker key.
+ static UInt_t BusPatchDataKeyWord() { return fgkBusPatchDataKey; }
+
+ /// Returns the expected padding word value.
+ static UInt_t PaddingWord() { return fgkPaddingWord; }
+
+ /// Returns the expected end of DDL marker.
+ static UInt_t EndOfDDLWord() { return fgkEndOfDDL; }
+
private:
bool fExitOnError; ///< Indicates if we should exit on the very first error.
}
+template <class EventHandler>
+bool AliMUONTrackerDDLDecoder<EventHandler>::Decode(void* buffer, UInt_t bufferSize)
+{
+ /// This decoding method performs a special checks to see if the DDL
+ /// corruption is fixable and then fixes the buffer by modifying it directly.
+ /// The fixes only apply if the fTryRecover flag is enabled.
+ /// \note buffer might be modified.
+
+ assert( buffer != NULL );
+ if (fTryRecover)
+ {
+ ///////////////////////////////////////////////////////
+ // Trick to recover B off data Runs : 119041, 119047, 119055, 119057
+ // A. Baldisseri May 2010
+ // Check if 16 32-bit words from a buspatch have been inserted
+ // incorrectly immediately at the beginning of the DDL payload.
+ UChar_t* bufferChar = reinterpret_cast<UChar_t*>(buffer);
+ UInt_t* bufferInt = reinterpret_cast<UInt_t*>(buffer);
+ if (bufferSize > 18*4 // is the buffer large enough to check the header.
+ and bufferInt[0] != fgkBlockDataKey and bufferInt[16] == fgkBlockDataKey // was the header incorrectly moved.
+ and bufferSize > bufferInt[17]*4 + sizeof(AliMUONBlockHeaderStruct) // is the buffer large enough for the second block header.
+ and bufferInt[bufferInt[17]] == fgkBlockDataKey // Check that the second header is in the correct location.
+ and bufferInt[17] == bufferInt[18] + 8 // Make sure that both lengths are correct.
+ and (bufferInt[17] + bufferInt[bufferInt[17]+1]+2)*4 == bufferSize // Check that both blocks will have the correct size if we make the fix.
+ )
+ {
+ UChar_t tmpbuf[16*4];
+ memcpy(tmpbuf, bufferChar, 16*4);
+ size_t sizeToMove = bufferInt[17]*4-16*4;
+ memmove(bufferChar, bufferChar+16*4, sizeToMove);
+ memcpy(bufferChar + sizeToMove, tmpbuf, 16*4);
+ }
+ }
+ return Decode(reinterpret_cast<const void*>(buffer), bufferSize);
+}
+
+
template <class EventHandler>
void AliMUONTrackerDDLDecoder<EventHandler>::DecodeBuffer(
const UChar_t* start, const UChar_t* end
const UInt_t* trailerWords = reinterpret_cast<const UInt_t*>(end) - 2;
if (fAutoDetectTrailer)
{
- if (trailerWords >= bufferStart and *trailerWords == fgkEndOfDDL
- and *(trailerWords+1) == fgkEndOfDDL
+ if (trailerWords >= bufferStart and trailerWords < bufferEnd
+ and *trailerWords == fgkEndOfDDL and *(trailerWords+1) == fgkEndOfDDL
)
{
// Found the trailer so reposition the end of blocks marker.
}
else if (fCheckForTrailer)
{
- if (trailerWords >= bufferStart and *trailerWords == fgkEndOfDDL
- and *(trailerWords+1) == fgkEndOfDDL
+ if (trailerWords >= bufferStart and trailerWords < bufferEnd
+ and *trailerWords == fgkEndOfDDL and *(trailerWords+1) == fgkEndOfDDL
)
{
// Found the trailer so reposition the end of blocks marker.
}
else
{
- if (trailerWords+1 >= bufferStart and *(trailerWords+1) == fgkEndOfDDL)
+ if (trailerWords+1 >= bufferStart and trailerWords+1 < bufferEnd and *(trailerWords+1) == fgkEndOfDDL)
fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords+1);
- else if (trailerWords >= bufferStart and *(trailerWords) == fgkEndOfDDL)
+ else if (trailerWords >= bufferStart and trailerWords < bufferEnd and *(trailerWords) == fgkEndOfDDL)
fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords);
else
fHandler.OnError(EventHandler::kNoDDLTrailerWords, end);
{
trailerWords = bufferEnd;
// There should only be a max of 2 trailer words.
- if (*(trailerWords-1) == fgkEndOfDDL)
- trailerWords--;
- else if (*(trailerWords-1) == fgkEndOfDDL)
- trailerWords--;
+ if (trailerWords-2 >= bufferStart and trailerWords-2 < bufferEnd and *(trailerWords-2) == fgkEndOfDDL)
+ trailerWords -= 2;
+ else if (trailerWords-1 >= bufferStart and trailerWords-1 < bufferEnd and *(trailerWords-1) == fgkEndOfDDL)
+ trailerWords -= 1;
endOfBlocks = reinterpret_cast<const UChar_t*>(trailerWords);
}
}
const AliMUONBlockHeaderStruct* blockHeader
= reinterpret_cast<const AliMUONBlockHeaderStruct*>(blockStart);
current += sizeof(AliMUONBlockHeaderStruct);
- if (current > endOfBlocks)
+ if (current > endOfBlocks or current < start)
{
+ // If we overflowed the pointer and already had an error then
+ // we are clearly lost so just stop decoding before we segfault.
+ if (current < start and fHadError) return;
+
// We first check if we actually hit the end of DDL markers
// If we did then either we did not/could not recover from
// a corrupt trailer or we did not detect a correct trailer
// 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 > endOfBlocks or blockEnd > endOfBlocks or dataEnd != blockEnd)
+ or dataEnd > endOfBlocks or dataEnd < start
+ or blockEnd > endOfBlocks or blockEnd < start
+ or dataEnd != blockEnd)
{
// So let us see what exactly is wrong and report this.
if (blockCount == fMaxBlocks)
}
if (blockHeader->fDataKey != fgkBlockDataKey)
fHandler.OnError(EventHandler::kBadBlockKey, &blockHeader->fDataKey);
- if (blockEnd > endOfBlocks)
+ if (blockEnd > endOfBlocks or blockEnd < start)
fHandler.OnError(EventHandler::kBadBlockLength, &blockHeader->fLength);
- if (dataEnd > endOfBlocks)
+ if (dataEnd > endOfBlocks or dataEnd < start)
fHandler.OnError(EventHandler::kBadBlockTotalLength, &blockHeader->fTotalLength);
if (dataEnd != blockEnd)
fHandler.OnError(EventHandler::kBlockLengthMismatch, blockHeader);
const AliMUONDSPHeaderStruct* dspHeader
= reinterpret_cast<const AliMUONDSPHeaderStruct*>(dspStart);
current += sizeof(AliMUONDSPHeaderStruct);
- if (current > end)
+ if (current > end or current < start)
{
+ // If we overflowed the pointer and already had an error then
+ // we are clearly lost so just stop decoding before we segfault.
+ if (current < start and fHadError) return false;
+
// So we only got part of a DSP header at the very end of
// the block structure buffer. Nothing to do but report the
// error and exit. Set fHadError in case of further decoding.
// If any of the above fail then we know there is a problem with
// the DSP header. It must be corrupted somehow.
if (dspHeader->fDataKey != fgkDSPDataKey
- or dataEnd > end or dspEnd > end or dataEnd != dspEnd)
+ or dataEnd > end or dataEnd < start
+ or dspEnd > end or dspEnd < start
+ or dataEnd != dspEnd)
{
// So let us see what exactly is wrong and report this.
if (dspHeader->fDataKey != fgkDSPDataKey)
fHandler.OnError(EventHandler::kBadDSPKey, &dspHeader->fDataKey);
- if (dspEnd > end)
+ if (dspEnd > end or dspEnd < start)
fHandler.OnError(EventHandler::kBadDSPLength, &dspHeader->fLength);
- if (dataEnd > end)
+ if (dataEnd > end or dataEnd < start)
fHandler.OnError(EventHandler::kBadDSPTotalLength, &dspHeader->fTotalLength);
if (dataEnd != dspEnd)
fHandler.OnError(EventHandler::kDSPLengthMismatch, dspHeader);
fHandler.OnNewDSP(dspHeader, dataStart);
// Check the error word in the header.
- if (dspHeader->fErrorWord == (0x000000B1 | blockHeader->fDSPId)
- or dspHeader->fErrorWord == (0x00000091 | blockHeader->fDSPId)
- )
+ if (dspHeader->fErrorWord != 0x0)
{
- // An event with a glitch in the readout has been detected.
- // It means that somewhere a 1 byte word has been randomly
- // inserted and all the readout sequence is shifted until
- // the next event.
- fHandler.OnError(EventHandler::kGlitchFound, &dspHeader->fErrorWord);
+ if (dspHeader->fErrorWord == (0x000000B1 | blockHeader->fDSPId)
+ or dspHeader->fErrorWord == (0x00000091 | blockHeader->fDSPId)
+ )
+ {
+ // An event with a glitch in the readout has been detected.
+ // It means that somewhere a 1 byte word has been randomly
+ // inserted and all the readout sequence is shifted until
+ // the next event.
+ fHandler.OnError(EventHandler::kGlitchFound, &dspHeader->fErrorWord);
+ }
+ else if ((dspHeader->fErrorWord & 0x0000FFF0) == 0x220)
+ {
+ // Detected a TOKEN_LOST error which can affect the dead time in the DAQ.
+ fHandler.OnError(EventHandler::kTokenLost, &dspHeader->fErrorWord);
+ }
+ else
+ {
+ // The DSP error code is non-zero but has an unknown code.
+ fHandler.OnError(EventHandler::kUnknownDspError, &dspHeader->fErrorWord);
+ }
+
fHadError = true;
if (fExitOnError)
{
}
// Try recover by finding the very next DSP and continue
- // decoding from there. Note: to achieve all we have to do
- // is continue to the next iteration, because the logic
+ // decoding from there. Note: to achieve this all we have to
+ // do is continue to the next iteration, because the logic
// will land up calling the FindKey method within the
// TryRecoverStruct method above.
- if (fTryRecover) continue;
+ if (fTryRecover)
+ {
+ fHandler.OnEndOfDSP(dspHeader, dataStart);
+ continue;
+ }
}
// Check if we are padding. If we are, then the bus patch data is
const AliMUONBusPatchHeaderStruct* busPatchHeader
= reinterpret_cast<const AliMUONBusPatchHeaderStruct*>(busPatchStart);
current += sizeof(AliMUONBusPatchHeaderStruct);
- if (current > end)
+ if (current > end or current < start)
{
+ // If we overflowed the pointer and already had an error then
+ // we are clearly lost so just stop decoding before we segfault.
+ if (current < start and fHadError) return false;
+
// So we only got part of a bus patch header at the very
// end of the DSP structure buffer. Nothing to do but
// report the error and exit. Set fHadError in case of
// If any of the above fail then we know there is a problem with
// the bus patch header. It must be corrupted somehow.
if (busPatchHeader->fDataKey != fgkBusPatchDataKey
- or dataEnd > end or busPatchEnd > end or dataEnd != busPatchEnd)
+ or dataEnd > end or dataEnd < start
+ or busPatchEnd > end or busPatchEnd < start
+ or dataEnd != busPatchEnd)
{
// So let us see what exactly is wrong and report this.
if (busPatchHeader->fDataKey != fgkBusPatchDataKey)
fHandler.OnError(EventHandler::kBadBusPatchKey, &busPatchHeader->fDataKey);
- if (busPatchEnd > end)
+ if (busPatchEnd > end or busPatchEnd < start)
fHandler.OnError(EventHandler::kBadBusPatchLength, &busPatchHeader->fLength);
- if (dataEnd > end)
+ if (dataEnd > end or dataEnd < start)
fHandler.OnError(EventHandler::kBadBusPatchTotalLength, &busPatchHeader->fTotalLength);
if (dataEnd != busPatchEnd)
fHandler.OnError(EventHandler::kBusPatchLengthMismatch, busPatchHeader);
const UInt_t* headerKey = reinterpret_cast<const UInt_t*>(structStart);
bool headerKeyOk = (expectedKey == *headerKey);
- bool lengthsMatch = (totalLength == length + headerSize);
+ bool lengthsMatch = (totalLength*4 == length*4 + headerSize);
bool lengthIsCorrect = false;
bool totalLengthIsCorrect = false;
{
// Must check that we can read another 4 bytes before
// checking the key at dataEnd.
- if (dataEnd + sizeof(UInt_t) <= bufferEnd)
+ if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
{
if (*keyAtDataEnd == fgkBlockDataKey)
lengthIsCorrect = true;
{
// Must check that we can read another 4 bytes before
// checking the key at structEnd.
- if (structEnd + sizeof(UInt_t) <= bufferEnd)
+ if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
{
if (*keyAtStructEnd == fgkBlockDataKey)
totalLengthIsCorrect = true;
{
// Must check that we can read another 4 bytes before
// checking the key at dataEnd.
- if (dataEnd + sizeof(UInt_t) <= bufferEnd)
+ if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
{
if (*keyAtDataEnd == fgkBlockDataKey
or *keyAtDataEnd == fgkDSPDataKey)
{
// Must check that we can read another 4 bytes before
// checking the key at structEnd.
- if (structEnd + sizeof(UInt_t) <= bufferEnd)
+ if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
{
if (*keyAtStructEnd == fgkBlockDataKey
or *keyAtStructEnd == fgkDSPDataKey)
{
// Must check that we can read another 4 bytes before
// checking the key at dataEnd.
- if (dataEnd + sizeof(UInt_t) <= bufferEnd)
+ if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
{
if (*keyAtDataEnd == fgkDSPDataKey
or *keyAtDataEnd == fgkBusPatchDataKey)
{
// Must check that we can read another 4 bytes before
// checking the key at structEnd.
- if (structEnd + sizeof(UInt_t) <= bufferEnd)
+ if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
{
if (*keyAtStructEnd == fgkDSPDataKey
or *keyAtStructEnd == fgkBusPatchDataKey)
/// should point to 'start + bufferSize', i.e. just past the last byte of the
/// buffer. If the key was found then the pointer to that location is returned
/// otherwise NULL is returned.
-
+
+ if (end + sizeof(UInt_t) < start) return NULL; // check for pointer overflow.
const UChar_t* current = start;
while (current + sizeof(UInt_t) <= end)
{