/************************************************************************** * This file is property of and copyright by the ALICE HLT Project * * All rights reserved. * * * * Primary Authors: * * Artur Szostak * * * * Permission to use, copy, modify and distribute this software and its * * documentation strictly for non-commercial purposes is hereby granted * * without fee, provided that the above copyright notice appears in all * * copies and that both the copyright notice and this permission notice * * appear in the supporting documentation. The authors make no claims * * about the suitability of this software for any purpose. It is * * provided "as is" without express or implied warranty. * **************************************************************************/ /* $Id$*/ /// /// \file AliMUONRawStreamTrackerHP.cxx /// \author Artur Szostak /// \date 29-11-2007 /// \brief Implementation of the the high performance decoder AliMUONRawStreamTrackerHP. /// //----------------------------------------------------------------------------- /// \ingroup raw /// \class AliMUONRawStreamTrackerHP /// \brief A high performance stream decoder for muon tracking DDL streams. /// /// This is the raw stream class which interfaces between the high performance /// core decoder and the AliRawReader class. /// To gain the most out of the decoder, the Next() method which returns batches /// of decoded digit / channel information should be used. That is: /// \code /// const AliBusPatch* Next(); /// \endcode /// /// This decoder tries to implement as similar an interface as possible to /// AliMUONRawStreamTracker where possible. However certain constructs which /// would slow us down too much are avoided. /// /// \author Artur Szostak //----------------------------------------------------------------------------- #include "AliMUONRawStreamTrackerHP.h" #include "AliMUONTrackerDDLDecoder.h" #include "AliMUONDspHeader.h" #include "AliMUONBlockHeader.h" #include "AliMUONBusStruct.h" #include "AliMUONDDLTracker.h" #include "AliMUONLogger.h" #include "AliRawReader.h" #include "AliLog.h" #include "AliDAQ.h" #include #include using std::cout; using std::endl; using std::hex; using std::dec; /// \cond CLASSIMP ClassImp(AliMUONRawStreamTrackerHP) /// \endcond const Int_t AliMUONRawStreamTrackerHP::fgkMaxDDL = 20; AliMUONRawStreamTrackerHP::AliMUONRawStreamTrackerHP() : TObject(), fRawReader(NULL), fLogger(NULL), fDetailLevel(kMediumErrorDetail), fEnableMUONErrorLogger(kFALSE), fEnableRawReaderErrorLogger(kFALSE), fWarnings(kTRUE), fDecoder(), fDDL(0), fBufferSize(8192), fBuffer(new UChar_t[8192]), fkCurrentBusPatch(NULL), fkCurrentData(NULL), fkEndOfData(NULL), fHadError(kFALSE), fDone(kFALSE), fDDLObject(NULL), fTotalNumberOfGlitchErrors(0), fTotalNumberOfParityErrors(0), fTotalNumberOfPaddingErrors(0), fTotalNumberOfTokenLostErrors(0) { /// /// Default constructor. /// // Must set this flag to get all information about parity errors though // the OnData method. OnError gets them either way. fDecoder.ExitOnError(false); fDecoder.SendDataOnParityError(true); fDecoder.GetHandler().SetMaxStructs( fDecoder.MaxBlocks(), fDecoder.MaxDSPs(), fDecoder.MaxBusPatches() ); fDecoder.GetHandler().SetRawStream(this); } AliMUONRawStreamTrackerHP::AliMUONRawStreamTrackerHP(AliRawReader* rawReader) : TObject(), fRawReader(rawReader), fLogger(NULL), fDetailLevel(kMediumErrorDetail), fEnableMUONErrorLogger(kFALSE), fEnableRawReaderErrorLogger(kFALSE), fWarnings(kTRUE), fDecoder(), fDDL(0), fBufferSize(8192), fBuffer(new UChar_t[8192]), fkCurrentBusPatch(NULL), fkCurrentData(NULL), fkEndOfData(NULL), fHadError(kFALSE), fDone(kFALSE), fDDLObject(NULL), fTotalNumberOfGlitchErrors(0), fTotalNumberOfParityErrors(0), fTotalNumberOfPaddingErrors(0), fTotalNumberOfTokenLostErrors(0) { /// /// Constructor with AliRawReader as argument. /// // Must set this flag to get all information about parity errors though // the OnData method. OnError gets them either way. fDecoder.ExitOnError(false); fDecoder.SendDataOnParityError(true); fDecoder.GetHandler().SetMaxStructs( fDecoder.MaxBlocks(), fDecoder.MaxDSPs(), fDecoder.MaxBusPatches() ); fDecoder.GetHandler().SetRawStream(this); } AliMUONRawStreamTrackerHP::~AliMUONRawStreamTrackerHP() { /// /// Default destructor. /// if (fBuffer != NULL) { delete [] fBuffer; } if (fDDLObject != NULL) { delete fDDLObject; } } void AliMUONRawStreamTrackerHP::First() { /// Initialise or reset the iterator. /// The first DDL will be found and decoded. assert( GetReader() != NULL ); fDDL = 0; fDone = kFALSE; NextDDL(); fTotalNumberOfGlitchErrors = 0; fTotalNumberOfPaddingErrors = 0; fTotalNumberOfParityErrors = 0; fTotalNumberOfTokenLostErrors = 0; } Bool_t AliMUONRawStreamTrackerHP::NextDDL() { /// Reading the next tracker DDL and decode the payload with the /// high performance decoder. /// \return kTRUE if the next DDL was successfully read and kFALSE otherwise. assert( GetReader() != NULL ); // The temporary object if generated in GetDDLTracker, is now stale, // so delete it. if (fDDLObject != NULL) { delete fDDLObject; fDDLObject = NULL; } // Better to reset these pointers. fkCurrentBusPatch = NULL; fkCurrentData = NULL; fkEndOfData = NULL; while (fDDL < GetMaxDDL()) { GetReader()->Reset(); GetReader()->Select("MUONTRK", fDDL, fDDL); // Select the DDL file to be read. if (GetReader()->ReadHeader()) break; AliDebug(3, Form("Skipping DDL %d which does not seem to be there", fDDL+1)); fDDL++; } // If we reach the end of the DDL list for this event then reset the // DDL counter, mark the iteration as done and exit. if (fDDL >= GetMaxDDL()) { fDDL = 0; fDone = kTRUE; return kFALSE; } else { fDone = kFALSE; } AliDebug(3, Form("DDL Number %d\n", fDDL)); Int_t dataSize = GetReader()->GetDataSize(); // in bytes // Check if we have enough buffer space already in fBuffer. If we do then // just continue reading otherwise we need to resize the buffer. if (fBufferSize < dataSize) { if (fBuffer != NULL) { delete [] fBuffer; fBuffer = NULL; fBufferSize = 0; } try { fBuffer = new UChar_t[dataSize]; fBufferSize = dataSize; } catch (const std::bad_alloc&) { AliError("Could not allocate more buffer space. Cannot decode DDL."); return kFALSE; } } if (not GetReader()->ReadNext(fBuffer, dataSize)) { return kFALSE; } #ifndef R__BYTESWAP Swap(reinterpret_cast(fBuffer), dataSize / sizeof(UInt_t)); // Swap needed for mac power pc. #endif fDDL++; // Remember to increment index to next DDL before the calls to // fDecoder.Decode since the callback methods of the decoder will // use AliMUONRawStreamTrackerHP::GetDDL() bool result = false; try { // Since we might allocate memory inside OnNewBuffer in the event // handler we need to trap any memory allocation exception to be robust. result = fDecoder.Decode(fBuffer, dataSize); fHadError = (result == true ? kFALSE : kTRUE); fTotalNumberOfGlitchErrors += fDecoder.GetHandler().GlitchErrorCount(); fTotalNumberOfParityErrors += fDecoder.GetHandler().ParityErrorCount(); fTotalNumberOfPaddingErrors += fDecoder.GetHandler().PaddingErrorCount(); fTotalNumberOfTokenLostErrors += fDecoder.GetHandler().TokenLostCount(); } catch (const std::bad_alloc&) { AliError("Could not allocate more buffer space. Cannot decode DDL."); return kFALSE; } // Update the current bus patch pointers. fkCurrentBusPatch = fDecoder.GetHandler().FirstBusPatch(); if (fkCurrentBusPatch != fDecoder.GetHandler().EndOfBusPatch()) { fkCurrentData = fkCurrentBusPatch->GetData(); fkEndOfData = fkCurrentData + fkCurrentBusPatch->GetDataCount(); } else { // If the DDL did not have any bus patches then mark both fCurrentData // and fEndOfData as NULL so that in Next() we are forced to find the // first non empty DDL. fkCurrentData = fkEndOfData = NULL; } return kTRUE; } Bool_t AliMUONRawStreamTrackerHP::IsDone() const { /// Indicates whether the iteration is finished or not. /// \return kTRUE if we already read all the digits and kFALSE if not. return fDone; } Bool_t AliMUONRawStreamTrackerHP::Next(Int_t& busPatchId, UShort_t& manuId, UChar_t& manuChannel, UShort_t& adc, Bool_t skipParityErrors) { /// Advance one step in the iteration. Returns false if finished. /// [out] \param busPatchId This is filled with the bus patch ID of the digit. /// [out] \param manuId This is filled with the MANU ID of the digit. /// [out] \param manuChannel This is filled with the MANU channel ID of the digit. /// [out] \param adc This is filled with the ADC signal value of the digit. /// [in] \param skipParityErrors If this is kTRUE, we'll skip the buspatches that /// have some parity errors /// \return kTRUE if we read another digit and kFALSE if we have read all the /// digits already, i.e. at the end of the iteration. if (fkCurrentData == NULL) return kFALSE; retry: // Check if we still have data to be returned for the current bus patch. if (fkCurrentData != fkEndOfData) { busPatchId = fkCurrentBusPatch->GetBusPatchId(); AliMUONTrackerDDLDecoderEventHandler::UnpackADC(*fkCurrentData, manuId, manuChannel, adc); fkCurrentData++; return kTRUE; } else { // We hit the end of the current bus patch so check if we have any more // bus patches to process for the current DDL. If we do, then increment // the current bus patch, make sure it is not the last one and then try // reading the first element again. if (fkCurrentBusPatch != fDecoder.GetHandler().EndOfBusPatch()) { fkCurrentBusPatch++; if (fkCurrentBusPatch != fDecoder.GetHandler().EndOfBusPatch()) { fkCurrentData = fkCurrentBusPatch->GetData(); fkEndOfData = fkCurrentData + fkCurrentBusPatch->GetDataCount(); if ( skipParityErrors ) { Bool_t ok(kTRUE); for ( Int_t i = 0; i < fkCurrentBusPatch->GetLength() && ok; ++ i ) { ok = fkCurrentBusPatch->IsParityOk(i); } if (!ok) fkCurrentData = fkEndOfData; } goto retry; } } // This was the last bus patch in the DDL so read in the next one and // try reading the first data element again. // Note: fCurrentBusPatch is set inside NextDDL(). if (NextDDL()) goto retry; } return kFALSE; } AliMUONDDLTracker* AliMUONRawStreamTrackerHP::GetDDLTracker() const { /// Construct and return a pointer to the DDL payload object. /// \return Pointer to internally constructed AliMUONDDLTracker object. /// The object is owned by this class and should not be deleted /// by the caller. /// /// \note This method should not be used just to gain access to the DDL /// payload, unless there is a good reason to have the AliMUONDDLTracker /// object. For example, if you want to modify the data and then save it /// to another DDL stream. Otherwise it can be an order of magnitude /// faster to access the DDL headers and data with the GetBlockHeader, /// GetDspHeader and GetBusPatch methods for example. /// Refer to the MUONRawStreamTracker.C macro to see how to use the fast /// decoder interface optimally. if (fDDLObject != NULL) return fDDLObject; fDDLObject = new AliMUONDDLTracker; for (Int_t iBlock = 0; iBlock < (Int_t)GetBlockCount(); iBlock++) { AliMUONBlockHeader blockHeader; AliMUONDspHeader dspHeader; AliMUONBusStruct busPatch; const AliBlockHeader* bh = GetBlockHeader(iBlock); // Copy block header and add it to the DDL object. memcpy(blockHeader.GetHeader(), bh->GetHeader(), sizeof(AliMUONBlockHeaderStruct)); fDDLObject->AddBlkHeader(blockHeader); for (Int_t iDsp = 0; iDsp < (Int_t)bh->GetDspCount(); iDsp++) { const AliDspHeader* dh = bh->GetDspHeader(iDsp); // Copy DSP header and add it to the DDL object. memcpy(dspHeader.GetHeader(), dh->GetHeader(), sizeof(AliMUONDSPHeaderStruct)); fDDLObject->AddDspHeader(dspHeader, iBlock); const AliBusPatch* bp = dh->GetFirstBusPatch(); while (bp != NULL) { // Copy bus patch header, data and add everything into DDL object. memcpy(busPatch.GetHeader(), bp->GetHeader(), sizeof(AliMUONBusPatchHeaderStruct)); busPatch.SetAlloc(bp->GetLength()); memcpy(busPatch.GetData(), bp->GetData(), bp->GetDataCount()*sizeof(UInt_t)); busPatch.SetBlockId(iBlock); busPatch.SetDspId(iDsp); fDDLObject->AddBusPatch(busPatch, iBlock, iDsp); bp = bp->Next(); } } } return fDDLObject; } void AliMUONRawStreamTrackerHP::SetMaxBlock(Int_t blk) { /// Set maximum number of blocks per DDL allowed. fDecoder.MaxBlocks( (UInt_t) blk ); fDecoder.GetHandler().SetMaxStructs( fDecoder.MaxBlocks(), fDecoder.MaxDSPs(), fDecoder.MaxBusPatches() ); } void AliMUONRawStreamTrackerHP::SetMaxDsp(Int_t dsp) { /// Set maximum number of Dsp per block allowed. fDecoder.MaxDSPs( (UInt_t) dsp ); fDecoder.GetHandler().SetMaxStructs( fDecoder.MaxBlocks(), fDecoder.MaxDSPs(), fDecoder.MaxBusPatches() ); } void AliMUONRawStreamTrackerHP::SetMaxBus(Int_t bus) { /// Set maximum number of Buspatch per Dsp allowed. fDecoder.MaxBusPatches( (UInt_t) bus ); fDecoder.GetHandler().SetMaxStructs( fDecoder.MaxBlocks(), fDecoder.MaxDSPs(), fDecoder.MaxBusPatches() ); } /////////////////////////////////////////////////////////////////////////////// void AliMUONRawStreamTrackerHP::AliBlockHeader::Print() const { /// Print header to screen. cout << "CRT info" << endl; if (fHeader == NULL) { cout << "Header is NULL" << endl; return; } cout << "DataKey: 0x" << hex << fHeader->fDataKey << dec << endl; cout << "TotalLength: " << fHeader->fTotalLength << endl; cout << "Length: " << fHeader->fLength << endl; cout << "DspId: " << fHeader->fDSPId << endl; cout << "L0Trigger: " << fHeader->fL0Trigger << endl; cout << "MiniEventId: " << fHeader->fMiniEventId<< endl; cout << "EventId1: " << fHeader->fEventId1 << endl; cout << "EventId2: " << fHeader->fEventId2 << endl; } void AliMUONRawStreamTrackerHP::AliDspHeader::Print() const { /// Print header to screen. cout << "FRT info" << endl; if (fHeader == NULL) { cout << "Header is NULL" << endl; return; } cout << "DataKey: 0x" << hex << fHeader->fDataKey << dec << endl; cout << "TotalLength: " << fHeader->fTotalLength << endl; cout << "Length : " << fHeader->fLength << endl; cout << "DspId: " << fHeader->fDSPId << endl; cout << "BlkL1ATrigger: " << fHeader->fBlkL1ATrigger << endl; cout << "MiniEventId: " << fHeader->fMiniEventId << endl; cout << "L1ATrigger: " << fHeader->fL1ATrigger << endl; cout << "L1RTrigger: " << fHeader->fL1RTrigger << endl; cout << "PaddingWord: " << fHeader->fPaddingWord << endl; cout << "ErrorWord: " << fHeader->fErrorWord << endl; } void AliMUONRawStreamTrackerHP::AliBusPatch::Print(const Option_t* opt) const { /// Print header to screen. cout << "Bus patch info" << endl; if (fHeader == NULL) { cout << "Header is NULL" << endl; return; } cout << "DataKey: 0x" << hex << fHeader->fDataKey << dec << endl; cout << "fTotalLength: " << fHeader->fTotalLength << endl; cout << "fLength: " << fHeader->fLength << endl; cout << "fBusPatchId: " << fHeader->fBusPatchId << endl; if (TString(opt).Contains("all")) { for (UInt_t i = 0; i < fHeader->fLength; ++i) cout << "Data["<< i << "] = " << fData[i] << endl; } } /////////////////////////////////////////////////////////////////////////////// AliMUONRawStreamTrackerHP::AliDecoderEventHandler::AliDecoderEventHandler() : fRawStream(NULL), fBufferStart(NULL), fBlockCount(0), fBlocks(NULL), fDSPs(NULL), fBusPatches(NULL), fEndOfBusPatches(NULL), fMaxChannels(8192), fParityOk(new Bool_t[8192]), fCurrentBlock(NULL), fCurrentDSP(NULL), fCurrentBusPatch(NULL), fCurrentParityOkFlag(NULL), fParityErrors(0), fGlitchErrors(0), fPaddingErrors(0), fTokenLostErrors(0), fMaxBlocks(), fMaxDsps(), fMaxBusPatches() { /// Default constructor initialises the internal parity flags buffer to /// store 8192 elements. This array will grow dynamically if needed. } AliMUONRawStreamTrackerHP::AliDecoderEventHandler::~AliDecoderEventHandler() { /// Default destructor cleans up the allocated memory. if (fParityOk != NULL) delete [] fParityOk; if (fBlocks != NULL) delete [] fBlocks; if (fDSPs != NULL) delete [] fDSPs; if (fBusPatches != NULL) delete [] fBusPatches; } void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::SetMaxStructs( UInt_t maxBlocks, UInt_t maxDsps, UInt_t maxBusPatches ) { /// Sets the maximum number of structures allowed. // Start by clearing the current arrays. if (fBlocks != NULL) { delete [] fBlocks; fBlocks = NULL; } if (fDSPs != NULL) { delete [] fDSPs; fDSPs = NULL; } if (fBusPatches != NULL) { delete [] fBusPatches; fBusPatches = NULL; } fCurrentBlock = NULL; fCurrentDSP = NULL; fCurrentBusPatch = NULL; // Allocate new memory. fBlocks = new AliBlockHeader[maxBlocks]; fDSPs = new AliDspHeader[maxBlocks*maxDsps]; fBusPatches = new AliBusPatch[maxBlocks*maxDsps*maxBusPatches]; fEndOfBusPatches = fBusPatches; fMaxBlocks = maxBlocks; fMaxDsps = maxDsps; fMaxBusPatches = maxBusPatches; } void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::OnNewBuffer( const void* buffer, UInt_t bufferSize ) { /// This is called by the high performance decoder when a new DDL payload /// is about to be decoded. /// \param buffer The pointer to the buffer storing the DDL payload. /// \param bufferSize The size of the buffer in bytes. // remember the start of the buffer to be used in OnError. fBufferStart = buffer; // Reset error counters. fParityErrors = 0; fGlitchErrors = 0; fPaddingErrors = 0; fTokenLostErrors = 0; // Check if we will have enough space in the fParityOk array. // If we do not then we need to resize the array. // bufferSize / sizeof(UInt_t) will be a safe over estimate of the // number of channels that we will find. UInt_t maxChannelsPossible = bufferSize / sizeof(UInt_t); if (maxChannelsPossible > fMaxChannels) { if (fParityOk != NULL) { delete [] fParityOk; fParityOk = NULL; fMaxChannels = 0; } fParityOk = new Bool_t[maxChannelsPossible]; fMaxChannels = maxChannelsPossible; } // Reset the current pointers which will be used to track where we need to // fill fBlocks, fDSPs, fBusPatches and the parity flag. We have to subtract // one space because we will increment the pointer the first time in the // OnNewXZY methods. fCurrentBlock = fBlocks-1; fCurrentDSP = fDSPs-1; fCurrentBusPatch = fBusPatches-1; fCurrentParityOkFlag = fParityOk-1; fBlockCount = 0; } void AliMUONRawStreamTrackerHP::Swap(UInt_t* buffer, Int_t size) const { // swap from little to big endian typedef struct { UInt_t b1:8; ///< first byte word UInt_t b2:8; ///< second byte word UInt_t b3:8; ///< third byte word UInt_t b4:8; ///< fourth byte word } RawWord; RawWord* word, temp; word = (RawWord*) buffer; for (Int_t i = 0; i < size; i++) { temp = *(((RawWord*)buffer)+i); word->b1 = temp.b4; word->b2 = temp.b3; word->b3 = temp.b2; word->b4 = temp.b1; word++; } } void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::OnError( ErrorCode error, const void* location ) { /// This is called by the high performance decoder when a error occurs /// when trying to decode the DDL payload. This indicates corruption in /// the data. This method converts the error code to a descriptive message /// and logs this with the logger object. /// \param error The error code indicating the problem. /// \param location A pointer to the location within the DDL payload buffer /// being decoded where the problem with the data was found. assert(fRawStream != NULL); const char* message = NULL; UInt_t word = 0; bool logAsMajorError = true; // Build the detailed part of the error message if high detail selected. const char* detail = ""; if (fRawStream->GetLoggingDetailLevel() == kHighErrorDetail) { bool blockPtrOk = fBlockCount > 0; bool dspPtrOk = blockPtrOk ? fCurrentBlock->GetDspCount() > 0 : false; bool buspatchPtrOk = dspPtrOk ? fCurrentDSP->GetBusPatchCount() > 0 : false; // We subtract 1 from the current numbers of blocks, DSPs // and bus patches to get the iBlock, iDsp and iBus indices. detail = Form( "At byte %lu in DDL %d, event %d, iBlock %d, iDsp %d [DSP ID: %d (0x%X)]," " iBus %d [bus patch ID: %d (0x%X)].", (unsigned long)location - (unsigned long)fBufferStart + sizeof(AliRawDataHeader), AliDAQ::DdlID("MUONTRK", fRawStream->GetDDL()), fRawStream->GetReader()->GetEventIndex(), int(fBlockCount)-1, blockPtrOk ? int(fCurrentBlock->GetDspCount())-1 : -1, blockPtrOk ? fCurrentBlock->GetDspId() : -1, blockPtrOk ? fCurrentBlock->GetDspId() : -1, dspPtrOk ? int(fCurrentDSP->GetBusPatchCount())-1 : -1, buspatchPtrOk ? fCurrentBusPatch->GetBusPatchId() : -1, buspatchPtrOk ? fCurrentBusPatch->GetBusPatchId() : -1 ); } // Build the log message. switch (error) { case kGlitchFound: fGlitchErrors++; switch (fRawStream->GetLoggingDetailLevel()) { case kLowErrorDetail: message = "Glitch error detected."; break; case kMediumErrorDetail: message = Form( "Glitch error detected in DSP %d (0x%X), skipping event.", fCurrentBlock->GetDspId(), fCurrentBlock->GetDspId() ); break; case kHighErrorDetail: default: message = Form("%s %s", ErrorCodeToMessage(error), detail); break; } logAsMajorError = true; break; case kBadPaddingWord: fPaddingErrors++; switch (fRawStream->GetLoggingDetailLevel()) { case kLowErrorDetail: message = "Padding word error detected."; break; case kMediumErrorDetail: // We subtract 1 from the current numbers of blocks, DSPs // and bus patches to get the indices. message = Form( "Padding word error for iBlock %d, iDsp %d, iBus %d.", fBlockCount-1, fCurrentBlock->GetDspCount()-1, fCurrentDSP->GetBusPatchCount()-1 ); break; case kHighErrorDetail: default: message = Form("%s %s", ErrorCodeToMessage(error), detail); break; } logAsMajorError = false; break; case kParityError: fParityErrors++; switch (fRawStream->GetLoggingDetailLevel()) { case kLowErrorDetail: message = "Parity error detected."; break; case kMediumErrorDetail: message = Form( "Parity error in buspatch %d (0x%X).", fCurrentBusPatch->GetBusPatchId(), fCurrentBusPatch->GetBusPatchId() ); break; case kHighErrorDetail: default: // location points to the incorrect data word and // fCurrentBusPatch->GetData() returns a pointer to the start of // bus patches data, so the difference divided by 4 gives the 32 // bit word number. word = (reinterpret_cast(location) - reinterpret_cast(fCurrentBusPatch->GetData())) / sizeof(UInt_t); message = Form( "Parity error in word %d for manuId %d and channel %d in buspatch %d. %s", word, fCurrentBusPatch->GetManuId(word), fCurrentBusPatch->GetChannelId(word), fCurrentBusPatch->GetBusPatchId(), detail ); break; } logAsMajorError = false; break; case kTokenLost: fTokenLostErrors++; switch (fRawStream->GetLoggingDetailLevel()) { case kLowErrorDetail: message = "Lost token error detected."; break; case kMediumErrorDetail: word = *reinterpret_cast(location); message = Form( "Lost token error detected with address 0x%X of DDL %d and code %d.", ((word & 0xFFFF0000)), fRawStream->GetDDL(), (word & 0xF) ); break; case kHighErrorDetail: default: word = *reinterpret_cast(location); message = Form( "Lost token error detected with address 0x%X and code %d. %s", ((word & 0xFFFF0000)), (word & 0xF), detail ); break; } logAsMajorError = false; break; default: switch (fRawStream->GetLoggingDetailLevel()) { case kLowErrorDetail: message = ErrorCodeToMessage(error); break; case kMediumErrorDetail: message = Form( "%s (At byte %lu)", ErrorCodeToMessage(error), (unsigned long)location - (unsigned long)fBufferStart + sizeof(AliRawDataHeader) ); break; case kHighErrorDetail: default: message = Form( "%s Error code: %d (%s). %s", ErrorCodeToMessage(error), error, ErrorCodeToString(error), detail ); break; } logAsMajorError = true; break; } // Now log the error message depending on the logging flags set. if (fRawStream->IsRawReaderErrorLoggerEnabled()) { if (logAsMajorError) fRawStream->GetReader()->AddMajorErrorLog(Int_t(error), message); else fRawStream->GetReader()->AddMinorErrorLog(Int_t(error), message); } if (fRawStream->IsMUONErrorLoggerEnabled()) { AliMUONLogger* logger = fRawStream->GetMUONErrorLogger(); if (logger != NULL) { logger->Log(message); } else { AliErrorGeneral( "AliMUONRawStreamTrackerHP::AliDecoderEventHandler", "Enabled logging to AliMUONLogger, but the logger object" " was not set with SetMUONErrorLogger()." ); } } if (fRawStream->IsWarningsEnabled()) { AliWarningGeneral( "AliMUONRawStreamTrackerHP::AliDecoderEventHandler", message ); } }