1 /**************************************************************************
2 * This file is property of and copyright by the ALICE HLT Project *
3 * All rights reserved. *
6 * Artur Szostak <artursz@iafrica.com> *
8 * Permission to use, copy, modify and distribute this software and its *
9 * documentation strictly for non-commercial purposes is hereby granted *
10 * without fee, provided that the above copyright notice appears in all *
11 * copies and that both the copyright notice and this permission notice *
12 * appear in the supporting documentation. The authors make no claims *
13 * about the suitability of this software for any purpose. It is *
14 * provided "as is" without express or implied warranty. *
15 **************************************************************************/
20 /// \file AliMUONRawStreamTrackerHP.cxx
21 /// \author Artur Szostak <artursz@iafrica.com>
23 /// \brief Implementation of the the high performance decoder AliMUONRawStreamTrackerHP.
26 //-----------------------------------------------------------------------------
28 /// \class AliMUONRawStreamTrackerHP
29 /// \brief A high performance stream decoder for muon tracking DDL streams.
31 /// This is the raw stream class which interfaces between the high performance
32 /// core decoder and the AliRawReader class.
33 /// To gain the most out of the decoder, the Next() method which returns batches
34 /// of decoded digit / channel information should be used. That is:
36 /// const AliBusPatch* Next();
39 /// This decoder tries to implement as similar an interface as possible to
40 /// AliMUONRawStreamTracker where possible. However certain constructs which
41 /// would slow us down too much are avoided.
43 /// \author Artur Szostak <artursz@iafrica.com>
44 //-----------------------------------------------------------------------------
46 #include "AliMUONRawStreamTrackerHP.h"
47 #include "AliMUONTrackerDDLDecoder.h"
48 #include "AliMUONDspHeader.h"
49 #include "AliMUONBlockHeader.h"
50 #include "AliMUONBusStruct.h"
51 #include "AliMUONDDLTracker.h"
52 #include "AliRawReader.h"
62 ClassImp(AliMUONRawStreamTrackerHP)
65 const Int_t AliMUONRawStreamTrackerHP::fgkMaxDDL = 20;
67 AliMUONRawStreamTrackerHP::AliMUONRawStreamTrackerHP() :
69 fEnableErrorLogger(kFALSE),
73 fBuffer(new UChar_t[8192]),
74 fkCurrentBusPatch(NULL),
80 fTotalNumberOfGlitchErrors(0),
81 fTotalNumberOfParityErrors(0),
82 fTotalNumberOfPaddingErrors(0),
83 fTotalNumberOfTokenLostErrors(0)
86 /// Default constructor.
89 // Must set this flag to get all information about parity errors though
90 // the OnData method. OnError gets them either way.
91 fDecoder.ExitOnError(false);
92 fDecoder.SendDataOnParityError(true);
94 fDecoder.GetHandler().SetMaxStructs(
97 fDecoder.MaxBusPatches()
102 AliMUONRawStreamTrackerHP::AliMUONRawStreamTrackerHP(AliRawReader* rawReader) :
104 fEnableErrorLogger(kFALSE),
108 fBuffer(new UChar_t[8192]),
109 fkCurrentBusPatch(NULL),
115 fTotalNumberOfGlitchErrors(0),
116 fTotalNumberOfParityErrors(0),
117 fTotalNumberOfPaddingErrors(0),
118 fTotalNumberOfTokenLostErrors(0)
121 /// Constructor with AliRawReader as argument.
124 // Must set this flag to get all information about parity errors though
125 // the OnData method. OnError gets them either way.
126 fDecoder.ExitOnError(false);
127 fDecoder.SendDataOnParityError(true);
129 fDecoder.GetHandler().SetMaxStructs(
130 fDecoder.MaxBlocks(),
132 fDecoder.MaxBusPatches()
135 fDecoder.GetHandler().SetReader(rawReader);
139 AliMUONRawStreamTrackerHP::~AliMUONRawStreamTrackerHP()
142 /// Default destructor.
149 if (fDDLObject != NULL)
156 void AliMUONRawStreamTrackerHP::First()
158 /// Initialise or reset the iterator.
159 /// The first DDL will be found and decoded.
161 assert( GetReader() != NULL );
166 fTotalNumberOfGlitchErrors = 0;
167 fTotalNumberOfPaddingErrors = 0;
168 fTotalNumberOfParityErrors = 0;
169 fTotalNumberOfTokenLostErrors = 0;
173 Bool_t AliMUONRawStreamTrackerHP::NextDDL()
175 /// Reading the next tracker DDL and decode the payload with the
176 /// high performance decoder.
177 /// \return kTRUE if the next DDL was successfully read and kFALSE otherwise.
179 assert( GetReader() != NULL );
181 // The temporary object if generated in GetDDLTracker, is now stale,
183 if (fDDLObject != NULL)
189 // Better to reset these pointers.
190 fkCurrentBusPatch = NULL;
191 fkCurrentData = NULL;
194 while (fDDL < GetMaxDDL())
196 GetReader()->Reset();
197 GetReader()->Select("MUONTRK", fDDL, fDDL); // Select the DDL file to be read.
198 if (GetReader()->ReadHeader()) break;
199 AliDebug(3, Form("Skipping DDL %d which does not seem to be there", fDDL+1));
203 // If we reach the end of the DDL list for this event then reset the
204 // DDL counter, mark the iteration as done and exit.
205 if (fDDL >= GetMaxDDL())
216 AliDebug(3, Form("DDL Number %d\n", fDDL));
218 Int_t dataSize = GetReader()->GetDataSize(); // in bytes
219 // Check if we have enough buffer space already in fBuffer. If we do then
220 // just continue reading otherwise we need to resize the buffer.
221 if (fBufferSize < dataSize)
231 fBuffer = new UChar_t[dataSize];
232 fBufferSize = dataSize;
234 catch (const std::bad_alloc&)
236 AliError("Could not allocate more buffer space. Cannot decode DDL.");
241 if (not GetReader()->ReadNext(fBuffer, dataSize))
247 Swap(reinterpret_cast<UInt_t*>(fBuffer), dataSize / sizeof(UInt_t)); // Swap needed for mac power pc.
253 // Since we might allocate memory inside OnNewBuffer in the event
254 // handler we need to trap any memory allocation exception to be robust.
255 result = fDecoder.Decode(fBuffer, dataSize);
256 fHadError = (result == true ? kFALSE : kTRUE);
257 fTotalNumberOfGlitchErrors += fDecoder.GetHandler().GlitchErrorCount();
258 fTotalNumberOfParityErrors += fDecoder.GetHandler().ParityErrorCount();
259 fTotalNumberOfPaddingErrors += fDecoder.GetHandler().PaddingErrorCount();
260 fTotalNumberOfTokenLostErrors += fDecoder.GetHandler().TokenLostCount();
262 catch (const std::bad_alloc&)
264 AliError("Could not allocate more buffer space. Cannot decode DDL.");
268 // Update the current bus patch pointers.
269 fkCurrentBusPatch = fDecoder.GetHandler().FirstBusPatch();
270 if (fkCurrentBusPatch != fDecoder.GetHandler().EndOfBusPatch())
272 fkCurrentData = fkCurrentBusPatch->GetData();
273 fkEndOfData = fkCurrentData + fkCurrentBusPatch->GetDataCount();
277 // If the DDL did not have any bus patches then mark both fCurrentData
278 // and fEndOfData as NULL so that in Next() we are forced to find the
279 // first non empty DDL.
280 fkCurrentData = fkEndOfData = NULL;
283 fDDL++; // Remember to increment index to next DDL.
288 Bool_t AliMUONRawStreamTrackerHP::IsDone() const
290 /// Indicates whether the iteration is finished or not.
291 /// \return kTRUE if we already read all the digits and kFALSE if not.
297 Bool_t AliMUONRawStreamTrackerHP::Next(Int_t& busPatchId,
299 UChar_t& manuChannel,
301 Bool_t skipParityErrors)
303 /// Advance one step in the iteration. Returns false if finished.
304 /// [out] \param busPatchId This is filled with the bus patch ID of the digit.
305 /// [out] \param manuId This is filled with the MANU ID of the digit.
306 /// [out] \param manuChannel This is filled with the MANU channel ID of the digit.
307 /// [out] \param adc This is filled with the ADC signal value of the digit.
308 /// [in] \param skipParityErrors If this is kTRUE, we'll skip the buspatches that
309 /// have some parity errors
310 /// \return kTRUE if we read another digit and kFALSE if we have read all the
311 /// digits already, i.e. at the end of the iteration.
313 if (fkCurrentData == NULL) return kFALSE;
316 // Check if we still have data to be returned for the current bus patch.
317 if (fkCurrentData != fkEndOfData)
319 busPatchId = fkCurrentBusPatch->GetBusPatchId();
320 AliMUONTrackerDDLDecoderEventHandler::UnpackADC(*fkCurrentData, manuId, manuChannel, adc);
326 // We hit the end of the current bus patch so check if we have any more
327 // bus patches to process for the current DDL. If we do, then increment
328 // the current bus patch, make sure it is not the last one and then try
329 // reading the first element again.
330 if (fkCurrentBusPatch != fDecoder.GetHandler().EndOfBusPatch())
333 if (fkCurrentBusPatch != fDecoder.GetHandler().EndOfBusPatch())
335 fkCurrentData = fkCurrentBusPatch->GetData();
336 fkEndOfData = fkCurrentData + fkCurrentBusPatch->GetDataCount();
337 if ( skipParityErrors )
340 for ( Int_t i = 0; i < fkCurrentBusPatch->GetLength() && ok; ++ i )
342 ok = fkCurrentBusPatch->IsParityOk(i);
344 if (!ok) fkCurrentData = fkEndOfData;
350 // This was the last bus patch in the DDL so read in the next one and
351 // try reading the first data element again.
352 // Note: fCurrentBusPatch is set inside NextDDL().
353 if (NextDDL()) goto retry;
359 AliMUONDDLTracker* AliMUONRawStreamTrackerHP::GetDDLTracker() const
361 /// Construct and return a pointer to the DDL payload object.
362 /// \return Pointer to internally constructed AliMUONDDLTracker object.
363 /// The object is owned by this class and should not be deleted
366 /// \note This method should not be used just to gain access to the DDL
367 /// payload, unless there is a good reason to have the AliMUONDDLTracker
368 /// object. For example, if you want to modify the data and then save it
369 /// to another DDL stream. Otherwise it can be an order of magnitude
370 /// faster to access the DDL headers and data with the GetBlockHeader,
371 /// GetDspHeader and GetBusPatch methods for example.
372 /// Refer to the MUONRawStreamTracker.C macro to see how to use the fast
373 /// decoder interface optimally.
375 if (fDDLObject != NULL) return fDDLObject;
377 fDDLObject = new AliMUONDDLTracker;
378 for (Int_t iBlock = 0; iBlock < (Int_t)GetBlockCount(); iBlock++)
380 AliMUONBlockHeader blockHeader;
381 AliMUONDspHeader dspHeader;
382 AliMUONBusStruct busPatch;
384 const AliBlockHeader* bh = GetBlockHeader(iBlock);
385 // Copy block header and add it to the DDL object.
386 memcpy(blockHeader.GetHeader(), bh->GetHeader(), sizeof(AliMUONBlockHeaderStruct));
387 fDDLObject->AddBlkHeader(blockHeader);
389 for (Int_t iDsp = 0; iDsp < (Int_t)bh->GetDspCount(); iDsp++)
391 const AliDspHeader* dh = bh->GetDspHeader(iDsp);
392 // Copy DSP header and add it to the DDL object.
393 memcpy(dspHeader.GetHeader(), dh->GetHeader(), sizeof(AliMUONDSPHeaderStruct));
394 fDDLObject->AddDspHeader(dspHeader, iBlock);
396 const AliBusPatch* bp = dh->GetFirstBusPatch();
399 // Copy bus patch header, data and add everything into DDL object.
400 memcpy(busPatch.GetHeader(), bp->GetHeader(), sizeof(AliMUONBusPatchHeaderStruct));
401 busPatch.SetAlloc(bp->GetLength());
402 memcpy(busPatch.GetData(), bp->GetData(), bp->GetDataCount()*sizeof(UInt_t));
403 busPatch.SetBlockId(iBlock);
404 busPatch.SetDspId(iDsp);
405 fDDLObject->AddBusPatch(busPatch, iBlock, iDsp);
415 void AliMUONRawStreamTrackerHP::SetMaxBlock(Int_t blk)
417 /// Set maximum number of blocks per DDL allowed.
418 fDecoder.MaxBlocks( (UInt_t) blk );
420 fDecoder.GetHandler().SetMaxStructs(
421 fDecoder.MaxBlocks(),
423 fDecoder.MaxBusPatches()
428 void AliMUONRawStreamTrackerHP::SetMaxDsp(Int_t dsp)
430 /// Set maximum number of Dsp per block allowed.
431 fDecoder.MaxDSPs( (UInt_t) dsp );
433 fDecoder.GetHandler().SetMaxStructs(
434 fDecoder.MaxBlocks(),
436 fDecoder.MaxBusPatches()
441 void AliMUONRawStreamTrackerHP::SetMaxBus(Int_t bus)
443 /// Set maximum number of Buspatch per Dsp allowed.
444 fDecoder.MaxBusPatches( (UInt_t) bus );
446 fDecoder.GetHandler().SetMaxStructs(
447 fDecoder.MaxBlocks(),
449 fDecoder.MaxBusPatches()
453 AliRawReader* AliMUONRawStreamTrackerHP::GetReader()
455 return fDecoder.GetHandler().GetReader();
458 void AliMUONRawStreamTrackerHP::SetReader(AliRawReader* reader)
460 fDecoder.GetHandler().SetReader(reader);
463 ///////////////////////////////////////////////////////////////////////////////
465 void AliMUONRawStreamTrackerHP::AliBlockHeader::Print() const
467 /// Print header to screen.
469 cout << "CRT info" << endl;
472 cout << "Header is NULL" << endl;
475 cout << "DataKey: 0x" << hex << fHeader->fDataKey << dec << endl;
476 cout << "TotalLength: " << fHeader->fTotalLength << endl;
477 cout << "Length: " << fHeader->fLength << endl;
478 cout << "DspId: " << fHeader->fDSPId << endl;
479 cout << "L0Trigger: " << fHeader->fL0Trigger << endl;
480 cout << "MiniEventId: " << fHeader->fMiniEventId<< endl;
481 cout << "EventId1: " << fHeader->fEventId1 << endl;
482 cout << "EventId2: " << fHeader->fEventId2 << endl;
486 void AliMUONRawStreamTrackerHP::AliDspHeader::Print() const
488 /// Print header to screen.
490 cout << "FRT info" << endl;
493 cout << "Header is NULL" << endl;
496 cout << "DataKey: 0x" << hex << fHeader->fDataKey << dec << endl;
497 cout << "TotalLength: " << fHeader->fTotalLength << endl;
498 cout << "Length : " << fHeader->fLength << endl;
499 cout << "DspId: " << fHeader->fDSPId << endl;
500 cout << "BlkL1ATrigger: " << fHeader->fBlkL1ATrigger << endl;
501 cout << "MiniEventId: " << fHeader->fMiniEventId << endl;
502 cout << "L1ATrigger: " << fHeader->fL1ATrigger << endl;
503 cout << "L1RTrigger: " << fHeader->fL1RTrigger << endl;
504 cout << "PaddingWord: " << fHeader->fPaddingWord << endl;
505 cout << "ErrorWord: " << fHeader->fErrorWord << endl;
509 void AliMUONRawStreamTrackerHP::AliBusPatch::Print(const Option_t* opt) const
511 /// Print header to screen.
512 cout << "Bus patch info" << endl;
515 cout << "Header is NULL" << endl;
518 cout << "DataKey: 0x" << hex << fHeader->fDataKey << dec << endl;
519 cout << "fTotalLength: " << fHeader->fTotalLength << endl;
520 cout << "fLength: " << fHeader->fLength << endl;
521 cout << "fBusPatchId: " << fHeader->fBusPatchId << endl;
523 if (TString(opt).Contains("all"))
525 for (UInt_t i = 0; i < fHeader->fLength; ++i)
526 cout << "Data["<< i << "] = " << fData[i] << endl;
530 ///////////////////////////////////////////////////////////////////////////////
532 AliMUONRawStreamTrackerHP::AliDecoderEventHandler::AliDecoderEventHandler() :
539 fEndOfBusPatches(NULL),
541 fParityOk(new Bool_t[8192]),
544 fCurrentBusPatch(NULL),
545 fCurrentParityOkFlag(NULL),
555 /// Default constructor initialises the internal parity flags buffer to
556 /// store 8192 elements. This array will grow dynamically if needed.
560 AliMUONRawStreamTrackerHP::AliDecoderEventHandler::~AliDecoderEventHandler()
562 /// Default destructor cleans up the allocated memory.
564 if (fParityOk != NULL) delete [] fParityOk;
565 if (fBlocks != NULL) delete [] fBlocks;
566 if (fDSPs != NULL) delete [] fDSPs;
567 if (fBusPatches != NULL) delete [] fBusPatches;
571 void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::SetMaxStructs(
572 UInt_t maxBlocks, UInt_t maxDsps, UInt_t maxBusPatches
575 /// Sets the maximum number of structures allowed.
577 // Start by clearing the current arrays.
588 if (fBusPatches != NULL)
590 delete [] fBusPatches;
593 fCurrentBlock = NULL;
595 fCurrentBusPatch = NULL;
597 // Allocate new memory.
598 fBlocks = new AliBlockHeader[maxBlocks];
599 fDSPs = new AliDspHeader[maxBlocks*maxDsps];
600 fBusPatches = new AliBusPatch[maxBlocks*maxDsps*maxBusPatches];
601 fEndOfBusPatches = fBusPatches;
603 fMaxBlocks = maxBlocks;
605 fMaxBusPatches = maxBusPatches;
609 void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::OnNewBuffer(
610 const void* buffer, UInt_t bufferSize
613 /// This is called by the high performance decoder when a new DDL payload
614 /// is about to be decoded.
615 /// \param buffer The pointer to the buffer storing the DDL payload.
616 /// \param bufferSize The size of the buffer in bytes.
618 // remember the start of the buffer to be used in OnError.
619 fBufferStart = buffer;
621 // Reset error counters.
625 fTokenLostErrors = 0;
627 // Check if we will have enough space in the fParityOk array.
628 // If we do not then we need to resize the array.
629 // bufferSize / sizeof(UInt_t) will be a safe over estimate of the
630 // number of channels that we will find.
631 UInt_t maxChannelsPossible = bufferSize / sizeof(UInt_t);
632 if (maxChannelsPossible > fMaxChannels)
634 if (fParityOk != NULL)
640 fParityOk = new Bool_t[maxChannelsPossible];
641 fMaxChannels = maxChannelsPossible;
644 // Reset the current pointers which will be used to track where we need to
645 // fill fBlocks, fDSPs, fBusPatches and the parity flag. We have to subtract
646 // one space because we will increment the pointer the first time in the
648 fCurrentBlock = fBlocks-1;
649 fCurrentDSP = fDSPs-1;
650 fCurrentBusPatch = fBusPatches-1;
651 fCurrentParityOkFlag = fParityOk-1;
656 void AliMUONRawStreamTrackerHP::AliDecoderEventHandler::OnError(
657 ErrorCode error, const void* location
660 /// This is called by the high performance decoder when a error occurs
661 /// when trying to decode the DDL payload. This indicates corruption in
662 /// the data. This method converts the error code to a descriptive message
663 /// and logs this with the raw reader.
664 /// \param error The error code indicating the problem.
665 /// \param location A pointer to the location within the DDL payload buffer
666 /// being decoded where the problem with the data was found.
668 assert( fRawReader != NULL );
670 Char_t* message = NULL;
678 "Glitch error detected in DSP %d (0x%X), skipping event ",
679 fCurrentBlock->GetDspId(), fCurrentBlock->GetDspId()
681 fRawReader->AddMajorErrorLog(error, message);
684 case kBadPaddingWord:
686 // We subtract 1 from the current numbers of blocks, DSPs
687 // and bus patches to get the indices.
689 "Padding word error for iBlock %d, iDsp %d, iBus %d\n",
691 fCurrentBlock->GetDspCount()-1,
692 fCurrentDSP->GetBusPatchCount()-1
694 fRawReader->AddMinorErrorLog(error, message);
699 // location points to the incorrect data word and
700 // fCurrentBusPatch->GetData() returns a pointer to the start of
701 // bus patches data, so the difference divided by 4 gives the 32
703 word = ((unsigned long)location - (unsigned long)fCurrentBusPatch->GetData())
706 "Parity error in word %d for manuId %d and channel %d in buspatch %d\n",
708 fCurrentBusPatch->GetManuId(word),
709 fCurrentBusPatch->GetChannelId(word),
710 fCurrentBusPatch->GetBusPatchId()
712 fRawReader->AddMinorErrorLog(error, message);
717 word = *reinterpret_cast<const UInt_t*>(location);
719 "Lost token error detected in DSP %d (0x%X) with address 0x%X and code %d.",
720 fCurrentBlock->GetDspId(), fCurrentBlock->GetDspId(),
721 ((word & 0xFFFF0000) >> 16),
724 fRawReader->AddMinorErrorLog(error, message);
729 "%s (At byte %d in DDL.)",
730 ErrorCodeToMessage(error),
731 (unsigned long)location - (unsigned long)fBufferStart + sizeof(AliRawDataHeader)
733 fRawReader->AddMajorErrorLog(error, message);
740 "AliMUONRawStreamTrackerHP::AliDecoderEventHandler",