AliRoot Core  v5-06-30 (35d6c57)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
AliMUONTrackerDDLDecoder.h
Go to the documentation of this file.
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 
39 
40 #include <string.h>
42 
100 
101 template <class EventHandler>
103 {
104 public:
105 
108  fExitOnError(true), fTryRecover(false),
109  fSendDataOnParityError(false), fHadError(false),
112  {}
113 
115  const EventHandler& GetHandler() const { return fHandler; }
116 
118  EventHandler& GetHandler() { return fHandler; }
119 
122  bool ExitOnError() const { return fExitOnError; }
123 
126  void ExitOnError(bool value) { fExitOnError = value; }
127 
131  bool TryRecover() const { return fTryRecover; }
132 
136  void TryRecover(bool value) { fTryRecover = value; }
137 
142 
146  void SendDataOnParityError(bool value) { fSendDataOnParityError = value; }
147 
149  UInt_t MaxBlocks() const { return fMaxBlocks; }
150 
152  void MaxBlocks(UInt_t n) { fMaxBlocks = n; }
153 
156  UInt_t MaxDSPs() const { return fMaxDSPs; }
157 
160  void MaxDSPs(UInt_t n) { fMaxDSPs = n; }
161 
164  UInt_t MaxBusPatches() const { return fMaxBusPatches; }
165 
168  void MaxBusPatches(UInt_t n) { fMaxBusPatches = n; }
169 
171  bool AutoDetectTrailer() const { return fAutoDetectTrailer; }
172 
174  void AutoDetectTrailer(bool value) { fAutoDetectTrailer = value; }
175 
177  bool CheckForTrailer() const { return fCheckForTrailer; }
178 
180  void CheckForTrailer(bool value) { fCheckForTrailer = value; }
181 
183  bool Decode(const void* buffer, UInt_t bufferSize);
184 
186  bool Decode(void* buffer, UInt_t bufferSize);
187 
189  static UInt_t BlockDataKeyWord() { return fgkBlockDataKey; }
190 
192  static UInt_t DspDataKeyWord() { return fgkDSPDataKey; }
193 
195  static UInt_t BusPatchDataKeyWord() { return fgkBusPatchDataKey; }
196 
198  static UInt_t PaddingWord() { return fgkPaddingWord; }
199 
201  static UInt_t EndOfDDLWord() { return fgkEndOfDDL; }
202 
203 private:
204 
206  bool fTryRecover;
208  bool fHadError;
211  UInt_t fMaxBlocks;
212  UInt_t fMaxDSPs;
213  UInt_t fMaxBusPatches;
214  EventHandler fHandler;
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 
229  {
233  };
234 
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;
254  static const UInt_t fgkDSPDataKey;
255  static const UInt_t fgkBusPatchDataKey;
256  static const UInt_t fgkPaddingWord;
257  static const UInt_t fgkEndOfDDL;
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>
266 template <class EventHandler>
268 template <class EventHandler>
270 template <class EventHandler>
272 template <class EventHandler>
274 
275 
276 template <class EventHandler>
277 bool AliMUONTrackerDDLDecoder<EventHandler>::Decode(const void* buffer, UInt_t bufferSize)
278 {
308 
309  assert( buffer != NULL );
310 
311  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  const UChar_t* end = start + bufferSize;
317 
318  fHandler.OnNewBuffer(buffer, bufferSize);
319  DecodeBuffer(start, end);
320  fHandler.OnEndOfBuffer(buffer, bufferSize);
321  return not fHadError;
322 }
323 
324 
325 template <class EventHandler>
326 bool AliMUONTrackerDDLDecoder<EventHandler>::Decode(void* buffer, UInt_t bufferSize)
327 {
332 
333  assert( buffer != NULL );
334  if (fTryRecover)
335  {
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  UInt_t* bufferInt = reinterpret_cast<UInt_t*>(buffer);
343  if (bufferSize > 18*4 // is the buffer large enough to check the header.
344  and bufferInt[0] != fgkBlockDataKey and bufferInt[16] == fgkBlockDataKey // was the header incorrectly moved.
345  and bufferSize > bufferInt[17]*4 + sizeof(AliMUONBlockHeaderStruct) // is the buffer large enough for the second block header.
346  and bufferInt[bufferInt[17]] == fgkBlockDataKey // Check that the second header is in the correct location.
347  and bufferInt[17] == bufferInt[18] + 8 // Make sure that both lengths are correct.
348  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  UChar_t tmpbuf[16*4];
352  memcpy(tmpbuf, bufferChar, 16*4);
353  size_t sizeToMove = bufferInt[17]*4-16*4;
354  memmove(bufferChar, bufferChar+16*4, sizeToMove);
355  memcpy(bufferChar + sizeToMove, tmpbuf, 16*4);
356  }
357  }
358  return Decode(reinterpret_cast<const void*>(buffer), bufferSize);
359 }
360 
361 
362 template <class EventHandler>
364  const UChar_t* start, const UChar_t* end
365  )
366 {
377 
378  const UChar_t* current = start;
379  const UInt_t* bufferStart = reinterpret_cast<const UInt_t*>(start);
380  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  const UInt_t* trailerWords = reinterpret_cast<const UInt_t*>(end) - 2;
389  if (fAutoDetectTrailer)
390  {
391  if (trailerWords >= bufferStart and trailerWords < bufferEnd
392  and *trailerWords == fgkEndOfDDL and *(trailerWords+1) == fgkEndOfDDL
393  )
394  {
395  // Found the trailer so reposition the end of blocks marker.
396  endOfBlocks = reinterpret_cast<const UChar_t*>(trailerWords);
397  }
398  // else assume we are dealing with the older data format.
399  }
400  else if (fCheckForTrailer)
401  {
402  if (trailerWords >= bufferStart and trailerWords < bufferEnd
403  and *trailerWords == fgkEndOfDDL and *(trailerWords+1) == fgkEndOfDDL
404  )
405  {
406  // Found the trailer so reposition the end of blocks marker.
407  endOfBlocks = reinterpret_cast<const UChar_t*>(trailerWords);
408  }
409  else
410  {
411  if (trailerWords+1 >= bufferStart and trailerWords+1 < bufferEnd and *(trailerWords+1) == fgkEndOfDDL)
412  fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords+1);
413  else if (trailerWords >= bufferStart and trailerWords < bufferEnd and *(trailerWords) == fgkEndOfDDL)
414  fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords);
415  else
416  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  fHadError = true;
422  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  if (fTryRecover)
432  {
433  trailerWords = bufferEnd;
434  // There should only be a max of 2 trailer words.
435  if (trailerWords-2 >= bufferStart and trailerWords-2 < bufferEnd and *(trailerWords-2) == fgkEndOfDDL)
436  trailerWords -= 2;
437  else if (trailerWords-1 >= bufferStart and trailerWords-1 < bufferEnd and *(trailerWords-1) == fgkEndOfDDL)
438  trailerWords -= 1;
439  endOfBlocks = reinterpret_cast<const UChar_t*>(trailerWords);
440  }
441  }
442  }
443 
444  UInt_t blockCount = 0; // Indicates the number of blocks decoded.
445  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  = reinterpret_cast<const AliMUONBlockHeaderStruct*>(blockStart);
454  current += sizeof(AliMUONBlockHeaderStruct);
455  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  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  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  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  if (problemWithTrailer) return;
473 
474  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  fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords);
480  fHadError = true;
481  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  if (blockCount == fMaxBlocks)
488  // Special case where we got all the blocks we
489  // expected, so the remaining data must be rubbish.
490  fHandler.OnError(EventHandler::kBufferTooBig, blockHeader);
491  else
492  fHandler.OnError(EventHandler::kNoBlockHeader, blockHeader);
493  fHadError = true;
494  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  current += blockHeader->fLength * sizeof(UInt_t);
501  const UChar_t* dataEnd = current;
502  const UChar_t* blockEnd = blockStart
503  + 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  if (blockHeader->fDataKey != fgkBlockDataKey
513  or dataEnd > endOfBlocks or dataEnd < start
514  or blockEnd > endOfBlocks or blockEnd < start
515  or dataEnd != blockEnd)
516  {
517  // So let us see what exactly is wrong and report this.
518  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  fHandler.OnError(EventHandler::kBufferTooBig, blockHeader);
524  fHadError = true;
525  return;
526  }
527  if (blockHeader->fDataKey != fgkBlockDataKey)
528  fHandler.OnError(EventHandler::kBadBlockKey, &blockHeader->fDataKey);
529  if (blockEnd > endOfBlocks or blockEnd < start)
530  fHandler.OnError(EventHandler::kBadBlockLength, &blockHeader->fLength);
531  if (dataEnd > endOfBlocks or dataEnd < start)
532  fHandler.OnError(EventHandler::kBadBlockTotalLength, &blockHeader->fTotalLength);
533  if (dataEnd != blockEnd)
534  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  fHadError = true;
540  if (fExitOnError) return;
541 
542  // Try to recover from the corrupt header.
543  RecoverResult result = TryRecoverStruct(
544  fgkBlockDataKey, sizeof(AliMUONBlockHeaderStruct),
545  blockHeader->fTotalLength, blockHeader->fLength,
546  blockStart, endOfBlocks, dataEnd, blockEnd, current
547  );
548  if (result == kContinueToNextStruct)
549  continue; // Try the next block at 'current'.
550  if (result == kRecoverFailed) return;
551  }
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  if (++blockCount > fMaxBlocks)
557  {
558  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  fHadError = true;
564  return;
565  }
566 
567  fHandler.OnNewBlock(blockHeader, dataStart);
568  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  if (fExitOnError)
575  {
576  fHandler.OnEndOfBlock(blockHeader, dataStart);
577  return;
578  }
579  }
580  fHandler.OnEndOfBlock(blockHeader, dataStart);
581  }
582 }
583 
584 
585 template <class EventHandler>
587  const AliMUONBlockHeaderStruct* blockHeader,
588  const UChar_t* start, const UChar_t* end
589  )
590 {
603 
604  const UChar_t* current = start;
605 
606  UInt_t dspCount = 0; // Indicates the number of DSPs decoded.
607  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  = reinterpret_cast<const AliMUONDSPHeaderStruct*>(dspStart);
616  current += sizeof(AliMUONDSPHeaderStruct);
617  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  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  fHandler.OnError(EventHandler::kNoDSPHeader, dspHeader);
627  fHadError = true;
628  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  current += dspHeader->fLength * sizeof(UInt_t);
635  const UChar_t* dataEnd = current;
636  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  if (dspHeader->fDataKey != fgkDSPDataKey
646  or dataEnd > end or dataEnd < start
647  or dspEnd > end or dspEnd < start
648  or dataEnd != dspEnd)
649  {
650  // So let us see what exactly is wrong and report this.
651  if (dspHeader->fDataKey != fgkDSPDataKey)
652  fHandler.OnError(EventHandler::kBadDSPKey, &dspHeader->fDataKey);
653  if (dspEnd > end or dspEnd < start)
654  fHandler.OnError(EventHandler::kBadDSPLength, &dspHeader->fLength);
655  if (dataEnd > end or dataEnd < start)
656  fHandler.OnError(EventHandler::kBadDSPTotalLength, &dspHeader->fTotalLength);
657  if (dataEnd != dspEnd)
658  fHandler.OnError(EventHandler::kDSPLengthMismatch, dspHeader);
659 
660  // Indicate we had and error and stop the decoding if so
661  // requested by the user.
662  fHadError = true;
663  if (fExitOnError) return false;
664 
665  // Try to recover from the corrupt header.
666  RecoverResult result = TryRecoverStruct(
667  fgkDSPDataKey, sizeof(AliMUONDSPHeaderStruct),
668  dspHeader->fTotalLength, dspHeader->fLength,
669  dspStart, end, dataEnd, dspEnd, current
670  );
671  if (result == kContinueToNextStruct)
672  continue; // Try the next DSP at 'current'.
673  if (result == kRecoverFailed) return false;
674  }
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  if (++dspCount > fMaxDSPs)
680  {
681  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  fHadError = true;
689  return false;
690  }
691 
692  fHandler.OnNewDSP(dspHeader, dataStart);
693 
694  // Check the error word in the header.
695  if (dspHeader->fErrorWord != 0x0)
696  {
697  if (dspHeader->fErrorWord == (0x000000B1 | blockHeader->fDSPId)
698  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  fHandler.OnError(EventHandler::kGlitchFound, &dspHeader->fErrorWord);
706  }
707  else if ((dspHeader->fErrorWord & 0x0000FFF0) == 0x220)
708  {
709  // Detected a TOKEN_LOST error which can affect the dead time in the DAQ.
710  fHandler.OnError(EventHandler::kTokenLost, &dspHeader->fErrorWord);
711  }
712  else
713  {
714  // The DSP error code is non-zero but has an unknown code.
715  fHandler.OnError(EventHandler::kUnknownDspError, &dspHeader->fErrorWord);
716  }
717 
718  fHadError = true;
719  if (fExitOnError)
720  {
721  fHandler.OnEndOfDSP(dspHeader, dataStart);
722  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  if (fTryRecover)
731  {
732  fHandler.OnEndOfDSP(dspHeader, dataStart);
733  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  if (dspHeader->fPaddingWord == 1)
740  {
741  dataEnd -= sizeof(UInt_t);
742 
743  // Check the pad word is correct.
744  const UInt_t* padWord = reinterpret_cast<const UInt_t*>(dataEnd);
745  if (*padWord != fgkPaddingWord)
746  {
747  fHandler.OnError(EventHandler::kBadPaddingWord, padWord);
748  fHadError = true;
749  if (fExitOnError)
750  {
751  fHandler.OnEndOfDSP(dspHeader, dataStart);
752  return false;
753  }
754  }
755  }
756 
757  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  if (fExitOnError)
764  {
765  fHandler.OnEndOfDSP(dspHeader, dataStart);
766  return false;
767  }
768  }
769  fHandler.OnEndOfDSP(dspHeader, dataStart);
770  }
771 
772  return true;
773 }
774 
775 
776 template <class EventHandler>
778  const UChar_t* start, const UChar_t* end
779  )
780 {
790 
791  const UChar_t* current = start;
792 
793  UInt_t busPatchCount = 0; // Indicates the number of bus patches decoded.
794  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  = reinterpret_cast<const AliMUONBusPatchHeaderStruct*>(busPatchStart);
804  current += sizeof(AliMUONBusPatchHeaderStruct);
805  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  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  fHandler.OnError(EventHandler::kNoBusPatchHeader, busPatchHeader);
816  fHadError = true;
817  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  current += busPatchHeader->fLength * sizeof(UInt_t);
825  const UChar_t* dataEnd = current;
826  const UChar_t* busPatchEnd = busPatchStart
827  + 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  if (busPatchHeader->fDataKey != fgkBusPatchDataKey
837  or dataEnd > end or dataEnd < start
838  or busPatchEnd > end or busPatchEnd < start
839  or dataEnd != busPatchEnd)
840  {
841  // So let us see what exactly is wrong and report this.
842  if (busPatchHeader->fDataKey != fgkBusPatchDataKey)
843  fHandler.OnError(EventHandler::kBadBusPatchKey, &busPatchHeader->fDataKey);
844  if (busPatchEnd > end or busPatchEnd < start)
845  fHandler.OnError(EventHandler::kBadBusPatchLength, &busPatchHeader->fLength);
846  if (dataEnd > end or dataEnd < start)
847  fHandler.OnError(EventHandler::kBadBusPatchTotalLength, &busPatchHeader->fTotalLength);
848  if (dataEnd != busPatchEnd)
849  fHandler.OnError(EventHandler::kBusPatchLengthMismatch, busPatchHeader);
850 
851  // Indicate we had and error and stop the decoding if so
852  // requested by the user.
853  fHadError = true;
854  if (fExitOnError) return false;
855 
856  // Try to recover from the corrupt header.
857  RecoverResult result = TryRecoverStruct(
858  fgkBusPatchDataKey, sizeof(AliMUONBusPatchHeaderStruct),
859  busPatchHeader->fTotalLength, busPatchHeader->fLength,
860  busPatchStart, end, dataEnd, busPatchEnd, current
861  );
862  if (result == kContinueToNextStruct)
863  continue; // Try the next bus patch at 'current'.
864  if (result == kRecoverFailed) return false;
865  }
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  if (++busPatchCount > fMaxBusPatches)
872  {
873  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  fHadError = true;
881  return false;
882  }
883 
884  fHandler.OnNewBusPatch(busPatchHeader, dataStart);
885  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  if (fExitOnError)
892  {
893  fHandler.OnEndOfBusPatch(busPatchHeader, dataStart);
894  return false;
895  }
896  }
897  fHandler.OnEndOfBusPatch(busPatchHeader, dataStart);
898  }
899 
900  return true;
901 }
902 
903 
904 template <class EventHandler>
906  const UChar_t* start, const UChar_t* end
907  )
908 {
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  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  const UInt_t* data = reinterpret_cast<const UInt_t*>(start);
930  const UInt_t* dataEnd = reinterpret_cast<const UInt_t*>(end);
931  for (; data < dataEnd; data++)
932  {
933  if (ParityIsOk(*data))
934  {
935  fHandler.OnData(*data, false);
936  }
937  else
938  {
939  // Indicate we had a parity error and exit immediately
940  // if the user so requested.
941  fHandler.OnError(EventHandler::kParityError, data);
942  fHadError = true;
943  if (fExitOnError) return false;
944 
945  if (fSendDataOnParityError)
946  fHandler.OnData(*data, true);
947  }
948  }
949 
950  return true;
951 }
952 
953 
954 template <class EventHandler>
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 {
1022 
1023  // Check if the user wants us to try and recover from a corrupt header.
1024  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  const UInt_t* headerKey = reinterpret_cast<const UInt_t*>(structStart);
1048  bool headerKeyOk = (expectedKey == *headerKey);
1049 
1050  bool lengthsMatch = (totalLength*4 == length*4 + headerSize);
1051 
1052  bool lengthIsCorrect = false;
1053  bool totalLengthIsCorrect = false;
1054  const UInt_t* keyAtDataEnd = reinterpret_cast<const UInt_t*>(dataEnd);
1055  const UInt_t* keyAtStructEnd = reinterpret_cast<const UInt_t*>(structEnd);
1056 
1057 
1058  if ( expectedKey == fgkBlockDataKey )
1059  {
1060  if (dataEnd == bufferEnd)
1061  {
1062  // Are we at the end of the buffer?
1063  lengthIsCorrect = true;
1064  }
1065  else
1066  {
1067  // Must check that we can read another 4 bytes before
1068  // checking the key at dataEnd.
1069  if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
1070  {
1071  if (*keyAtDataEnd == fgkBlockDataKey)
1072  lengthIsCorrect = true;
1073  }
1074  }
1075 
1076  if (structEnd == bufferEnd)
1077  {
1078  // Are we at the end of the buffer?
1079  totalLengthIsCorrect = true;
1080  }
1081  else
1082  {
1083  // Must check that we can read another 4 bytes before
1084  // checking the key at structEnd.
1085  if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
1086  {
1087  if (*keyAtStructEnd == fgkBlockDataKey)
1088  totalLengthIsCorrect = true;
1089  }
1090  }
1091  }
1092 
1093  else if ( expectedKey == fgkDSPDataKey )
1094  {
1095  if (dataEnd == bufferEnd)
1096  {
1097  // Are we at the end of the buffer?
1098  lengthIsCorrect = true;
1099  }
1100  else
1101  {
1102  // Must check that we can read another 4 bytes before
1103  // checking the key at dataEnd.
1104  if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
1105  {
1106  if (*keyAtDataEnd == fgkBlockDataKey
1107  or *keyAtDataEnd == fgkDSPDataKey)
1108  lengthIsCorrect = true;
1109  }
1110  }
1111 
1112  if (structEnd == bufferEnd)
1113  {
1114  // Are we at the end of the buffer?
1115  totalLengthIsCorrect = true;
1116  }
1117  else
1118  {
1119  // Must check that we can read another 4 bytes before
1120  // checking the key at structEnd.
1121  if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
1122  {
1123  if (*keyAtStructEnd == fgkBlockDataKey
1124  or *keyAtStructEnd == fgkDSPDataKey)
1125  totalLengthIsCorrect = true;
1126  }
1127  }
1128  }
1129  else if ( expectedKey == fgkBusPatchDataKey )
1130  {
1131  if (dataEnd == bufferEnd)
1132  {
1133  // Are we at the end of the buffer?
1134  lengthIsCorrect = true;
1135  }
1136  else
1137  {
1138  // Must check that we can read another 4 bytes before
1139  // checking the key at dataEnd.
1140  if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
1141  {
1142  if (*keyAtDataEnd == fgkDSPDataKey
1143  or *keyAtDataEnd == fgkBusPatchDataKey)
1144  lengthIsCorrect = true;
1145  }
1146  }
1147 
1148  if (structEnd == bufferEnd)
1149  {
1150  // Are we at the end of the buffer?
1151  totalLengthIsCorrect = true;
1152  }
1153  else
1154  {
1155  // Must check that we can read another 4 bytes before
1156  // checking the key at structEnd.
1157  if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
1158  {
1159  if (*keyAtStructEnd == fgkDSPDataKey
1160  or *keyAtStructEnd == fgkBusPatchDataKey)
1161  totalLengthIsCorrect = true;
1162  }
1163  }
1164  }
1165 
1166  if (headerKeyOk and lengthIsCorrect)
1167  {
1168  // totalLength was wrong, dataEnd is correct.
1169  structEnd = dataEnd;
1170  current = dataEnd;
1171  return kStructRecovered;
1172  }
1173  if (headerKeyOk and totalLengthIsCorrect)
1174  {
1175  // Length was wrong, structEnd is correct.
1176  dataEnd = structEnd;
1177  current = structEnd;
1178  return kStructRecovered;
1179  }
1180  if (lengthsMatch and lengthIsCorrect and totalLengthIsCorrect)
1181  {
1182  // The header's key was wrong but the lengths and pointers are OK.
1183  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  const UChar_t* location = FindKey(
1190  expectedKey, structStart + sizeof(UInt_t), bufferEnd
1191  );
1192  if (location != NULL)
1193  {
1194  current = location;
1195  return kContinueToNextStruct;
1196  }
1197 
1198  return kRecoverFailed;
1199 }
1200 
1201 
1202 template <class EventHandler>
1204  UInt_t key, const UChar_t* start, const UChar_t* end
1205  )
1206 {
1212 
1213  if (end + sizeof(UInt_t) < start) return NULL; // check for pointer overflow.
1214  const UChar_t* current = start;
1215  while (current + sizeof(UInt_t) <= end)
1216  {
1217  UInt_t data = * reinterpret_cast<const UInt_t*>(current);
1218  if (data == key) return current;
1219  current++;
1220  }
1221  return NULL;
1222 }
1223 
1224 
1225 template <class EventHandler>
1227 {
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  data ^= data >> 16;
1236  data ^= data >> 8;
1237  data ^= data >> 4;
1238  data &= 0xf;
1239  data = ((0x6996 >> data) & 1);
1240  return data == 0;
1241 }
1242 
1243 #endif // ALIMUONTRACKERDDLDECODER_H
A high performance decoder class for MUON tracking DDL data.
Indicates that we recovered from a corrupt structure header and can continue processing the given str...
The DSP header structure of the Tracker DDL payload.
bool fExitOnError
Indicates if we should exit on the very first error.
UInt_t fDataKey
Data key word for bus patch header.
bool DecodeBlockData(const AliMUONBlockHeaderStruct *blockHeader, const UChar_t *start, const UChar_t *end)
static const UInt_t fgkBlockDataKey
The key word expected to identify block structure headers.
bool fAutoDetectTrailer
Indicates if we should automatically check for the end of DDL trailer (Default = true).
AliMUONTrackerDDLDecoder()
Default contructor.
static UInt_t DspDataKeyWord()
Returns the DSP marker key.
Must continue parsing the next structure and ignore the current one.
The bus patch header structure of the Tracker DDL payload.
bool AutoDetectTrailer() const
Returns the value of the auto-detect trailer flag.
EventHandler fHandler
The event handler which deals with parsing events.
UInt_t fTotalLength
total length of block structure
bool DecodeDSPData(const UChar_t *start, const UChar_t *end)
static const UInt_t fgkPaddingWord
The expected format of the padding word in the DDL payload.
void DecodeBuffer(const UChar_t *start, const UChar_t *end)
const UChar_t * FindKey(UInt_t key, const UChar_t *start, const UChar_t *end)
static UInt_t PaddingWord()
Returns the expected padding word value.
UInt_t fMaxDSPs
Maximum number of DSP structures allowed in a DDL stream.
void CheckForTrailer(bool value)
Sets the value of the flag to check for the end of DDL trailer.
void AutoDetectTrailer(bool value)
Sets the value of the auto-detect trailer flag.
Implementation of a high performance DDL decoder event handler for the muon tracking stations...
UInt_t fDataKey
Data key word for CRT header.
bool fCheckForTrailer
Indicates if we should check for the end of DDL trailer (Default = true). This flag is ignored if fAu...
RecoverResult
Possible results that can be returned by the TryRecoverStruct method.
bool CheckForTrailer() const
Returns the value of the flag to check for the end of DDL trailer.
EventHandler & GetHandler()
Returns the event handler instance.
UInt_t fTotalLength
total length of block structure (w/o padding word)
bool DecodeBusPatchData(const UChar_t *start, const UChar_t *end)
RecoverResult TryRecoverStruct(UInt_t expectedKey, UInt_t headerSize, UInt_t totalLength, UInt_t length, const UChar_t *structStart, const UChar_t *bufferEnd, const UChar_t *&dataEnd, const UChar_t *&structEnd, const UChar_t *&current)
UInt_t MaxBlocks() const
Returns the maximum block count expected in the DDL payload.
static const UInt_t fgkDSPDataKey
The key word expected to identify DSP structure headers.
static UInt_t EndOfDDLWord()
Returns the expected end of DDL marker.
UInt_t fMaxBusPatches
Maximum number of bus patch structures allowed in a DDL stream.
UInt_t fMaxBlocks
Maximum number of block structures allowed in a DDL stream.
bool fHadError
Indicates if we had an error decoding the data.
static const UInt_t fgkBusPatchDataKey
The key word expected to identify bus patch headers.
static const UInt_t fgkEndOfDDL
The end of DDL trailer word.
UInt_t fTotalLength
total length of bus patch structure
static UInt_t BlockDataKeyWord()
Returns the block marker key.
The block header structure of the Tracker DDL payload.
static UInt_t BusPatchDataKeyWord()
Returns the bus patch marker key.
bool Decode(const void *buffer, UInt_t bufferSize)
This method decodes the DDL payload contained in the buffer.
The recovery failed. Cannot continue parsing.
bool fSendDataOnParityError
If set to true then we issue a OnData() event even if the data word had a parity error.
bool fTryRecover
Indicates if we should try recover from a corrupt structure header or DDL trailer.
void MaxBlocks(UInt_t n)
Sets the maximum block count expected in the DDL payload.
UInt_t fPaddingWord
padding dummy word for 64 bits transfer
UInt_t fDataKey
Data key word for FRT header.
const EventHandler & GetHandler() const
Constant method to return the event handler instance.