]> git.uio.no Git - u/mrichter/AliRoot.git/blob - MUON/AliMUONTrackerDDLDecoder.h
Major update of the way we make QA of the occupancy, and of what we
[u/mrichter/AliRoot.git] / MUON / AliMUONTrackerDDLDecoder.h
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
21 ///
22 /// \file   AliMUONTrackerDDLDecoder.h
23 /// \author Artur Szostak <artursz@iafrica.com>
24 /// \date   28-11-2007
25 /// \brief  Implementation of a high performance DDL decoder for the muon tracking stations.
26 ///
27 /// This file implementes the AliMUONTrackerDDLDecoder class, which contains
28 /// the core logic for decoding the payload in DDL streams coming from the muon
29 /// spectrometer's tracking chambers in a very efficient manner.
30 ///
31 /// This implementation is derived from work done by Christian Finck for the
32 /// AliMUONPayloadTracker.
33 ///
34 /// Note to maintainers: Please remember that this file is used by the online
35 /// dHLT system. As an online system, the dHLT requires the fastest code possible
36 /// in the decoders to satisfy its timing constraints. The performance impact
37 /// must be checked before any proposed modification is made to this file.
38 ///
39
40 #include "AliMUONTrackerDDLDecoderEventHandler.h"
41
42 /// \ingroup raw
43 /// \class AliMUONTrackerDDLDecoder
44 /// \brief A high performance decoder class for MUON tracking DDL data.
45 ///
46 /// This class implements a high performance decoder for decoding DDL payload
47 /// data coming from the muon spectrometers tracking chambers.
48 /// It has been implemented using the event driven paradigm with templates,
49 /// which allows us to minimise the number of method calls made in the inner
50 /// loops of the algorithm and minimise the memory footprint. At least for
51 /// optimised production compilations.
52 /// The decoder class only contains the basic decoding and error checking logic.
53 /// It calls methods such as OnNewBlock, OnNewBusPatch, OnData etc in
54 /// the event handler during the decoding to return the decoded data.
55 /// The event handler class is nothing more than a callback interface to deliver
56 /// the next chunks of decoded data.
57 /// To actually do something with the data, one needs to implement a custom
58 /// event handler (callback) class by inheriting from AliMUONTrackerDDLDecoderEventHandler
59 /// and overriding the callback methods like so:
60 /// \code
61 ///  class MyCustomHandler : public AliMUONTrackerDDLDecoderEventHandler
62 ///  {
63 ///  public:
64 ///     void OnData(UInt_t data, bool parityError)
65 ///     {
66 ///       // I can do something with 'data' here and check if there was
67 ///       // a parity error with 'parityError'.
68 ///     }
69 ///  };
70 /// \endcode
71 ///
72 /// Once the custom handler is written then the decoder is instantiated as
73 /// shown below, to use your new custom handler. Also to start decoding one needs
74 /// to call the Decode() method of the decoder.
75 /// \code
76 ///  AliMUONTrackerDDLDecoder<MyCustomHandler> myDecoder;
77 ///  muDecoder.Decoder(buffer, bufferSize);
78 /// \endcode
79 ///
80 /// Note that this class was written as a template on purpose. To maximise the
81 /// compilers chance to make optimisations and inline the code we must use a template.
82 /// Depending on exactly what you do inside your handler, the decoder could be
83 /// significantly slower if run time polymorphism was used, i.e. making the class
84 /// AliMUONTrackerDDLDecoderEventHandler abstract and using virtual methods.
85 ///
86 /// There has been a change to the data format that the real detector generates.
87 /// Two trailer words are added to the end of the DDL payload which indicated
88 /// the end of data. The decoder is initialised by default to automatically
89 /// check for these and deal with it correctly, if they exist or not.
90 /// However, if you want to override this behaviour then set the flag
91 /// fAutoDetectTrailer to false with AutoDetectTrailer(false). Then if you have
92 /// data with the old data format you should set fCheckForTrailer to false with
93 /// CheckForTrailer(false), otherwise for real data it should be
94 /// fCheckForTrailer = true. Only when fAutoDetectTrailer is true will the
95 /// fCheckForTrailer flag be ignored and no warnings will be generated for an
96 /// incorrect data format.
97 ///
98 /// \author Artur Szostak <artursz@iafrica.com>
99
100 template <class EventHandler>
101 class AliMUONTrackerDDLDecoder
102 {
103 public:
104
105         /// Default contructor.
106         AliMUONTrackerDDLDecoder() :
107                 fExitOnError(true), fTryRecover(false),
108                 fSendDataOnParityError(false), fHadError(false),
109                 fAutoDetectTrailer(true), fCheckForTrailer(true),
110                 fMaxBlocks(2), fMaxDSPs(5), fMaxBusPatches(5), fHandler()
111         {}
112         
113         /// Constant method to return the event handler instance.
114         const EventHandler& GetHandler() const { return fHandler; }
115         
116         /// Returns the event handler instance.
117         EventHandler& GetHandler() { return fHandler; }
118         
119         /// Returns the "exit on error" flag.
120         /// i.e. should the decoder stop on the very first error found.
121         bool ExitOnError() const { return fExitOnError; }
122         
123         /// Sets the "exit on error" flag.
124         /// i.e. should the decoder stop on the very first error found.
125         void ExitOnError(bool value) { fExitOnError = value; }
126         
127         /// Returns the "try to recover from errors" flag.
128         /// i.e. should the decoder try to recover from errors found in the
129         /// payload headers or trailers.
130         bool TryRecover() const { return fTryRecover; }
131         
132         /// Sets the "try to recover from errors" flag.
133         /// i.e. should the decoder try to recover from errors found in the
134         /// payload headers or trailers.
135         void TryRecover(bool value) { fTryRecover = value; }
136         
137         /// Returns the flag indicating if the raw data words in the bus patches
138         /// that failed their parity tests (i.e. parity error / bit flip in the
139         /// raw data word) will be sent to the event handler anyway through OnData.
140         bool SendDataOnParityError() const { return fSendDataOnParityError; }
141         
142         /// Sets the flag indicating if the raw data words in the bus patches
143         /// that failed their parity tests (i.e. parity error / bit flip in the
144         /// raw data word) will be sent to the event handler anyway through OnData.
145         void SendDataOnParityError(bool value) { fSendDataOnParityError = value; }
146         
147         /// Returns the maximum block count expected in the DDL payload.
148         UInt_t MaxBlocks() const { return fMaxBlocks; }
149         
150         /// Sets the maximum block count expected in the DDL payload.
151         void MaxBlocks(UInt_t n) { fMaxBlocks = n; }
152         
153         /// Returns the maximum DSP header count expected in any given block
154         /// structure within the DDL payload.
155         UInt_t MaxDSPs() const { return fMaxDSPs; }
156         
157         /// Sets the maximum DSP header count expected in any given block structure
158         /// within the DDL payload.
159         void MaxDSPs(UInt_t n) { fMaxDSPs = n; }
160         
161         /// Returns the maximum number of bus patches expected in any given DSP
162         /// structure within the DDL payload.
163         UInt_t MaxBusPatches() const { return fMaxBusPatches; }
164         
165         /// Sets the maximum number of bus patches expected in any given DSP
166         /// structure within the DDL payload.
167         void MaxBusPatches(UInt_t n) { fMaxBusPatches = n; }
168         
169         /// Returns the value of the auto-detect trailer flag.
170         bool AutoDetectTrailer() const { return fAutoDetectTrailer; }
171         
172         /// Sets the value of the auto-detect trailer flag.
173         void AutoDetectTrailer(bool value) { fAutoDetectTrailer = value; }
174         
175         /// Returns the value of the flag to check for the end of DDL trailer.
176         bool CheckForTrailer() const { return fCheckForTrailer; }
177         
178         /// Sets the value of the flag to check for the end of DDL trailer.
179         void CheckForTrailer(bool value) { fCheckForTrailer = value; }
180         
181         /// This method decodes the DDL payload contained in the buffer.
182         bool Decode(const void* buffer, UInt_t bufferSize);
183         
184         /// Returns the block marker key.
185         static UInt_t BlockDataKeyWord() { return fgkBlockDataKey; }
186         
187         /// Returns the DSP marker key.
188         static UInt_t DspDataKeyWord() { return fgkDSPDataKey; }
189         
190         /// Returns the bus patch marker key.
191         static UInt_t BusPatchDataKeyWord() { return fgkBusPatchDataKey; }
192         
193         /// Returns the expected padding word value.
194         static UInt_t PaddingWord() { return fgkPaddingWord; }
195         
196         /// Returns the expected end of DDL marker.
197         static UInt_t EndOfDDLWord() { return fgkEndOfDDL; }
198         
199 private:
200
201         bool fExitOnError; ///< Indicates if we should exit on the very first error.
202         bool fTryRecover; ///< Indicates if we should try recover from a corrupt structure header or DDL trailer.
203         bool fSendDataOnParityError; ///< If set to true then we issue a OnData() event even if the data word had a parity error.
204         bool fHadError; ///< Indicates if we had an error decoding the data.
205         bool fAutoDetectTrailer; ///< Indicates if we should automatically check for the end of DDL trailer (Default = true).
206         bool fCheckForTrailer; ///< Indicates if we should check for the end of DDL trailer (Default = true). This flag is ignored if fAutoDetectTrailer is true.
207         UInt_t fMaxBlocks; ///< Maximum number of block structures allowed in a DDL stream.
208         UInt_t fMaxDSPs; ///< Maximum number of DSP structures allowed in a DDL stream.
209         UInt_t fMaxBusPatches; ///< Maximum number of bus patch structures allowed in a DDL stream.
210         EventHandler fHandler; ///< The event handler which deals with parsing events.
211
212         void DecodeBuffer(const UChar_t* start, const UChar_t* end);
213         
214         bool DecodeBlockData(
215                         const AliMUONBlockHeaderStruct* blockHeader,
216                         const UChar_t* start, const UChar_t* end
217                 );
218
219         bool DecodeDSPData(const UChar_t* start, const UChar_t* end);
220         
221         bool DecodeBusPatchData(const UChar_t* start, const UChar_t* end);
222
223         /// Possible results that can be returned by the TryRecoverStruct method.
224         enum RecoverResult
225         {
226                 kRecoverFailed,        ///< The recovery failed. Cannot continue parsing.
227                 kStructRecovered,      ///< Indicates that we recovered from a corrupt structure header and can continue processing the given structure.
228                 kContinueToNextStruct  ///< Must continue parsing the next structure and ignore the current one.
229         };
230
231         RecoverResult TryRecoverStruct(
232                         UInt_t expectedKey,
233                         UInt_t headerSize,
234                         UInt_t totalLength,
235                         UInt_t length,
236                         const UChar_t* structStart,
237                         const UChar_t* bufferEnd,
238                         const UChar_t*& dataEnd,
239                         const UChar_t*& structEnd,
240                         const UChar_t*& current
241                 );
242         
243         const UChar_t* FindKey(
244                         UInt_t key, const UChar_t* start, const UChar_t* end
245                 );
246         
247         bool ParityIsOk(UInt_t data);
248         
249         static const UInt_t fgkBlockDataKey;     ///< The key word expected to identify block structure headers.
250         static const UInt_t fgkDSPDataKey;       ///< The key word expected to identify DSP structure headers.
251         static const UInt_t fgkBusPatchDataKey;  ///< The key word expected to identify bus patch headers.
252         static const UInt_t fgkPaddingWord;      ///< The expected format of the padding word in the DDL payload.
253         static const UInt_t fgkEndOfDDL;         ///< The end of DDL trailer word.
254 };
255
256 //_____________________________________________________________________________
257
258 // The following are the structure header keys which are used to identify the kind
259 // of structure header we are dealing with: block, DSP or bus patch header.
260 template <class EventHandler>
261 const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkBlockDataKey = 0xFC0000FC;
262 template <class EventHandler>
263 const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkDSPDataKey = 0xF000000F;
264 template <class EventHandler>
265 const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkBusPatchDataKey = 0xB000000B;
266 template <class EventHandler>
267 const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkPaddingWord = 0xBEEFFACE;
268 template <class EventHandler>
269 const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkEndOfDDL = 0xD000000D;
270
271
272 template <class EventHandler>
273 bool AliMUONTrackerDDLDecoder<EventHandler>::Decode(const void* buffer, UInt_t bufferSize)
274 {
275         /// This method should be called to actually decode the DDL payload
276         /// contained in a memory buffer. The payload should be for a muon tracking
277         /// chamber DDL stream.
278         /// As the decoder progresses it will make method calls to the event handler
279         /// instance (which can be accessed with the GetHandler() method) to indicate
280         /// the start of the new block, DSP and bus patch headers. For every raw
281         /// data word the OnData method of the event handler is called.
282         ///
283         /// If an error occurs during the parse because the data is corrupt then
284         /// the OnError method is called indicating what the problem was.
285         /// Decoding will stop at this point unless the fExitOnError flag is set
286         /// to false. Also raw data words which contain a parity error are only
287         /// sent to the event handler with OnData if the fSendDataOnParityError
288         /// flag is set to true. There is also an optional flag fTryRecover which
289         /// can enable logic which will attempt to recover the header structures found
290         /// in the DDL payload if they are found to be inconsistent (assumed corrupt).
291         /// fTryRecover set to true will also enable recovery from a corrupt
292         /// DDL trailer marking the end of DDL payload.
293         ///
294         /// \param buffer  This is the pointer to the start of the memory buffer
295         ///     containing the DDL payload. Remember that this must be the start of
296         ///     the payload and not the DDL stream. That is, this pointer should be
297         ///     equal to: DDL start pointer + 8 * sizeof(UInt_t).
298         /// \param bufferSize  This is the pointer to the first byte just past the
299         ///     end of the block structure.
300         /// \return Returns false if there was any problem with decoding the data,
301         ///     and true otherwise. Note: the data may have been partially decoded
302         ///     even if false was returned, which would be indicated by at least one
303         ///     call to the event handlers OnData method.
304         
305         assert( buffer != NULL );
306         
307         fHadError = false;
308         
309         // We are basically implementing something like a recursive decent parser.
310         // So start by marking the start of buffer position and end of buffer.
311         const UChar_t* start = reinterpret_cast<const UChar_t*>(buffer);
312         const UChar_t* end = start + bufferSize;
313         
314         fHandler.OnNewBuffer(buffer, bufferSize);
315         DecodeBuffer(start, end);
316         fHandler.OnEndOfBuffer(buffer, bufferSize);
317         return not fHadError;
318 }
319
320
321 template <class EventHandler>
322 void AliMUONTrackerDDLDecoder<EventHandler>::DecodeBuffer(
323                 const UChar_t* start, const UChar_t* end
324         )
325 {
326         /// This method decodes the buffer's payload data. It unpacks the block
327         /// structures contained inside and then for each block it calls the
328         /// OnNewBlock method for the event handler to signal the start of each new
329         /// block structure. OnEndOfBlock is called once each block is processed.
330         /// \param start  This is the pointer to the start of the buffer.
331         /// \param end  This is the pointer to the first byte just past the
332         ///             end of the buffer.
333         /// fHadError is set to true if there were any errors decoding the buffer
334         /// and the OnError method of the callback event handler is called for
335         /// each error.
336         
337         const UChar_t* current = start;
338         const UInt_t* bufferStart = reinterpret_cast<const UInt_t*>(start);
339         const UInt_t* bufferEnd = reinterpret_cast<const UInt_t*>(end);
340         bool problemWithTrailer = false;
341         
342         // The DDL payload normally has a 2 word trailer which contains the end of
343         // DDL markers 0xD000000D. But this is not the case for older simulated
344         // data so if we are auto-detecting the trailer then we need to carefully
345         // check if these words are there or not.
346         const UChar_t* endOfBlocks = end;
347         const UInt_t* trailerWords = reinterpret_cast<const UInt_t*>(end) - 2;
348         if (fAutoDetectTrailer)
349         {
350                 if (trailerWords >= bufferStart and trailerWords < bufferEnd
351                     and *trailerWords == fgkEndOfDDL and *(trailerWords+1) == fgkEndOfDDL
352                    )
353                 {
354                         // Found the trailer so reposition the end of blocks marker.
355                         endOfBlocks = reinterpret_cast<const UChar_t*>(trailerWords);
356                 }
357                 // else assume we are dealing with the older data format.
358         }
359         else if (fCheckForTrailer)
360         {
361                 if (trailerWords >= bufferStart and trailerWords < bufferEnd
362                     and *trailerWords == fgkEndOfDDL and *(trailerWords+1) == fgkEndOfDDL
363                    )
364                 {
365                         // Found the trailer so reposition the end of blocks marker.
366                         endOfBlocks = reinterpret_cast<const UChar_t*>(trailerWords);
367                 }
368                 else
369                 {
370                         if (trailerWords+1 >= bufferStart and trailerWords+1 < bufferEnd and *(trailerWords+1) == fgkEndOfDDL)
371                                 fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords+1);
372                         else if (trailerWords >= bufferStart and trailerWords < bufferEnd and *(trailerWords) == fgkEndOfDDL)
373                                 fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords);
374                         else
375                                 fHandler.OnError(EventHandler::kNoDDLTrailerWords, end);
376         
377                         // Stop the decoding if so requested by the user, otherwise
378                         // remember about the error so that we return false from the
379                         // Decode() method and continue decoding.
380                         fHadError = true;
381                         if (fExitOnError) return;
382                         
383                         // Mark that there was a problem with the trailer so that
384                         // for subsequent errors we try to deal with this better.
385                         problemWithTrailer = true;
386                         
387                         // We can also try figure out how many trailer words there
388                         // actually are and move the end of blocks marker back.
389                         
390                         if (fTryRecover)
391                         {
392                                 trailerWords = bufferEnd;
393                                 // There should only be a max of 2 trailer words.
394                                 if (trailerWords-2 >= bufferStart and trailerWords-2 < bufferEnd and *(trailerWords-2) == fgkEndOfDDL)
395                                         trailerWords -= 2;
396                                 else if (trailerWords-1 >= bufferStart and trailerWords-1 < bufferEnd and *(trailerWords-1) == fgkEndOfDDL)
397                                         trailerWords -= 1;
398                                 endOfBlocks = reinterpret_cast<const UChar_t*>(trailerWords);
399                         }
400                 }
401         }
402
403         UInt_t blockCount = 0; // Indicates the number of blocks decoded.
404         while (current < endOfBlocks)
405         {
406                 // Mark the start of the block structure.
407                 const UChar_t* blockStart = current;
408                 
409                 // Get the block header, move the current pointer just past the end
410                 // of the header and check that we have not overflowed the buffer.
411                 const AliMUONBlockHeaderStruct* blockHeader
412                         = reinterpret_cast<const AliMUONBlockHeaderStruct*>(blockStart);
413                 current += sizeof(AliMUONBlockHeaderStruct);
414                 if (current > endOfBlocks or current < start)
415                 {
416                         // If we overflowed the pointer and already had an error then
417                         // we are clearly lost so just stop decoding before we segfault.
418                         if (current < start and fHadError) return;
419                         
420                         // We first check if we actually hit the end of DDL markers
421                         // If we did then either we did not/could not recover from
422                         // a corrupt trailer or we did not detect a correct trailer
423                         // in auto-detect mode.
424                         trailerWords = reinterpret_cast<const UInt_t*>(blockHeader);
425                         // The "trailerWords+1 <= bufferEnd" checks that we are
426                         // not reading beyond the end of the buffer.
427                         if (trailerWords+1 <= bufferEnd and *trailerWords == fgkEndOfDDL)
428                         {
429                                 // If we aready knew the trailer was corrupt then just
430                                 // return because the error was already announced.
431                                 if (problemWithTrailer) return;
432                                 
433                                 if (fAutoDetectTrailer)
434                                 {
435                                         // If we got here then there is at least one correct trailer
436                                         // word, but since we did not detect a correct trailer then
437                                         // there must be only one. Announce the error and exit.
438                                         fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords);
439                                         fHadError = true;
440                                         return;
441                                 }
442                         }
443                         
444                         // So we only got part of a block header at the very end
445                         // of the buffer. Nothing to do but report the error and exit.
446                         if (blockCount == fMaxBlocks)
447                                 // Special case where we got all the blocks we
448                                 // expected, so the remaining data must be rubbish.
449                                 fHandler.OnError(EventHandler::kBufferTooBig, blockHeader);
450                         else
451                                 fHandler.OnError(EventHandler::kNoBlockHeader, blockHeader);
452                         fHadError = true;
453                         return;
454                 }
455                 
456                 // The header fits the buffer so we can mark the data start and
457                 // read from the header to find the end of data and block pointers.
458                 const UChar_t* dataStart = current;
459                 current += blockHeader->fLength * sizeof(UInt_t);
460                 const UChar_t* dataEnd = current;
461                 const UChar_t* blockEnd = blockStart
462                         + blockHeader->fTotalLength * sizeof(UInt_t);
463                 
464                 // Now we need to check for the following things:
465                 // 1) Is the end of block or end of data pointer outside the buffer
466                 //    boundaries.
467                 // 2) Are the values for these pointers the same.
468                 // 3) Is the expected data key in the header present.
469                 // If any of the above fail then we know there is a problem with
470                 // the block header. It must be corrupted somehow.
471                 if (blockHeader->fDataKey != fgkBlockDataKey
472                     or dataEnd > endOfBlocks or dataEnd < start
473                     or blockEnd > endOfBlocks or blockEnd < start
474                     or dataEnd != blockEnd)
475                 {
476                         // So let us see what exactly is wrong and report this.
477                         if (blockCount == fMaxBlocks)
478                         {
479                                 // Special case where we got all the blocks we
480                                 // expected, so the remaining data must be rubbish.
481                                 // Don't even bother trying to recover the data.
482                                 fHandler.OnError(EventHandler::kBufferTooBig, blockHeader);
483                                 fHadError = true;
484                                 return;
485                         }
486                         if (blockHeader->fDataKey != fgkBlockDataKey)
487                                 fHandler.OnError(EventHandler::kBadBlockKey, &blockHeader->fDataKey);
488                         if (blockEnd > endOfBlocks or blockEnd < start)
489                                 fHandler.OnError(EventHandler::kBadBlockLength, &blockHeader->fLength);
490                         if (dataEnd > endOfBlocks or dataEnd < start)
491                                 fHandler.OnError(EventHandler::kBadBlockTotalLength, &blockHeader->fTotalLength);
492                         if (dataEnd != blockEnd)
493                                 fHandler.OnError(EventHandler::kBlockLengthMismatch, blockHeader);
494                         
495                         // Stop the decoding if so requested by the user, otherwise
496                         // remember about the error so that we return false from the
497                         // Decode() method and continue decoding.
498                         fHadError = true;
499                         if (fExitOnError) return;
500                         
501                         // Try to recover from the corrupt header.
502                         RecoverResult result = TryRecoverStruct(
503                                         fgkBlockDataKey, sizeof(AliMUONBlockHeaderStruct),
504                                         blockHeader->fTotalLength, blockHeader->fLength,
505                                         blockStart, endOfBlocks, dataEnd, blockEnd, current
506                                 );
507                         if (result == kContinueToNextStruct)
508                                 continue; // Try the next block at 'current'.
509                         if (result == kRecoverFailed) return;
510                 }
511                 
512                 // At this point we certainly have a valid block header, so we
513                 // need to check if we have more blocks than we expected. If not
514                 // then we can indicate we have another block and decode its data.
515                 if (++blockCount > fMaxBlocks)
516                 {
517                         fHandler.OnError(EventHandler::kTooManyBlocks, current);
518                         
519                         // In this case we stop the decoding because clearly
520                         // something is seriously wrong with the data if we are
521                         // getting more blocks than expected.
522                         fHadError = true;
523                         return;
524                 }
525                 
526                 fHandler.OnNewBlock(blockHeader, dataStart);
527                 if (not DecodeBlockData(blockHeader, dataStart, dataEnd))
528                 {
529                         // At this point we had a problem decoding the block structure's
530                         // data. Thus we should stop further decoding if so requested by
531                         // the user. Note the fHadError flag is already marked inside
532                         // DecodeBlockData.
533                         if (fExitOnError)
534                         {
535                                 fHandler.OnEndOfBlock(blockHeader, dataStart);
536                                 return;
537                         }
538                 }
539                 fHandler.OnEndOfBlock(blockHeader, dataStart);
540         }
541 }
542
543
544 template <class EventHandler>
545 bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeBlockData(
546                 const AliMUONBlockHeaderStruct* blockHeader,
547                 const UChar_t* start, const UChar_t* end
548         )
549 {
550         /// This method decodes a block structure's data payload. It unpacks the
551         /// DSP structures contained inside and then for each DSP it calls the
552         /// OnNewDSP method for the event handler to signal the start of each new
553         /// DSP structure.
554         /// \param blockHeader
555         /// \param start  This is the pointer to the start of the block
556         ///               structure's data.
557         /// \param end  This is the pointer to the first byte just past the
558         ///             end of the block structure.
559         /// \return If the block structure's data was decoded without errors
560         ///      or we could recover from the errors, then true is returned.
561         ///      False is returned otherwise.
562         
563         const UChar_t* current = start;
564         
565         UInt_t dspCount = 0; // Indicates the number of DSPs decoded.
566         while (current < end)
567         {
568                 // Mark the start of the DSP structure.
569                 const UChar_t* dspStart = current;
570                 
571                 // Get the DSP header, move the current pointer just past the end
572                 // of the header and check that we have not overflowed the buffer.
573                 const AliMUONDSPHeaderStruct* dspHeader
574                         = reinterpret_cast<const AliMUONDSPHeaderStruct*>(dspStart);
575                 current += sizeof(AliMUONDSPHeaderStruct);
576                 if (current > end or current < start)
577                 {
578                         // If we overflowed the pointer and already had an error then
579                         // we are clearly lost so just stop decoding before we segfault.
580                         if (current < start and fHadError) return false;
581                         
582                         // So we only got part of a DSP header at the very end of
583                         // the block structure buffer. Nothing to do but report the
584                         // error and exit. Set fHadError in case of further decoding.
585                         fHandler.OnError(EventHandler::kNoDSPHeader, dspHeader);
586                         fHadError = true;
587                         return false;
588                 }
589                 
590                 // The header fits the buffer so we can mark the data start and
591                 // read from the header to find the end of data and DSP pointers.
592                 const UChar_t* dataStart = current;
593                 current += dspHeader->fLength * sizeof(UInt_t);
594                 const UChar_t* dataEnd = current;
595                 const UChar_t* dspEnd = dspStart + dspHeader->fTotalLength * sizeof(UInt_t);
596                 
597                 // Now we need to check for the following things:
598                 // 1) Is the end of DSP or end of data pointer outside the buffer
599                 //    boundaries.
600                 // 2) Are the values for these pointers the same.
601                 // 3) Is the expected data key in the header present.
602                 // If any of the above fail then we know there is a problem with
603                 // the DSP header. It must be corrupted somehow.
604                 if (dspHeader->fDataKey != fgkDSPDataKey
605                     or dataEnd > end or dataEnd < start
606                     or dspEnd > end or dspEnd < start
607                     or dataEnd != dspEnd)
608                 {
609                         // So let us see what exactly is wrong and report this.
610                         if (dspHeader->fDataKey != fgkDSPDataKey)
611                                 fHandler.OnError(EventHandler::kBadDSPKey, &dspHeader->fDataKey);
612                         if (dspEnd > end or dspEnd < start)
613                                 fHandler.OnError(EventHandler::kBadDSPLength, &dspHeader->fLength);
614                         if (dataEnd > end or dataEnd < start)
615                                 fHandler.OnError(EventHandler::kBadDSPTotalLength, &dspHeader->fTotalLength);
616                         if (dataEnd != dspEnd)
617                                 fHandler.OnError(EventHandler::kDSPLengthMismatch, dspHeader);
618                         
619                         // Indicate we had and error and stop the decoding if so
620                         // requested by the user.
621                         fHadError = true;
622                         if (fExitOnError) return false;
623                         
624                         // Try to recover from the corrupt header.
625                         RecoverResult result = TryRecoverStruct(
626                                         fgkDSPDataKey, sizeof(AliMUONDSPHeaderStruct),
627                                         dspHeader->fTotalLength, dspHeader->fLength,
628                                         dspStart, end, dataEnd, dspEnd, current
629                                 );
630                         if (result == kContinueToNextStruct)
631                                 continue; // Try the next DSP at 'current'.
632                         if (result == kRecoverFailed) return false;
633                 }
634                 
635                 // At this point we certainly have a valid DSP header, so we
636                 // need to check if we have more DSPs than we expected. If not
637                 // then we can indicate we have another DSP and decode its data.
638                 if (++dspCount > fMaxDSPs)
639                 {
640                         fHandler.OnError(EventHandler::kTooManyDSPs, current);
641                         
642                         // In this case we stop further decoding of the block
643                         // structure data because clearly something is seriously
644                         // wrong if we are getting more DSPs than expected.
645                         // Indicate that we had an error so the Decode() method
646                         // returns false.
647                         fHadError = true;
648                         return false;
649                 }
650                 
651                 fHandler.OnNewDSP(dspHeader, dataStart);
652                 
653                 // Check the error word in the header.
654                 if (dspHeader->fErrorWord != 0x0)
655                 {
656                         if (dspHeader->fErrorWord == (0x000000B1 | blockHeader->fDSPId)
657                             or dspHeader->fErrorWord == (0x00000091 | blockHeader->fDSPId)
658                            )
659                         {
660                                 // An event with a glitch in the readout has been detected.
661                                 // It means that somewhere a 1 byte word has been randomly
662                                 // inserted and all the readout sequence is shifted until
663                                 // the next event.
664                                 fHandler.OnError(EventHandler::kGlitchFound, &dspHeader->fErrorWord);
665                         }
666                         else if ((dspHeader->fErrorWord & 0x0000FFF0) == 0x220)
667                         {
668                                 // Detected a TOKEN_LOST error which can affect the dead time in the DAQ.
669                                 fHandler.OnError(EventHandler::kTokenLost, &dspHeader->fErrorWord);
670                         }
671                         else
672                         {
673                                 // The DSP error code is non-zero but has an unknown code.
674                                 fHandler.OnError(EventHandler::kUnknownDspError, &dspHeader->fErrorWord);
675                         }
676                         
677                         fHadError = true;
678                         if (fExitOnError)
679                         {
680                                 fHandler.OnEndOfDSP(dspHeader, dataStart);
681                                 return false;
682                         }
683                         
684                         // Try recover by finding the very next DSP and continue
685                         // decoding from there. Note: to achieve all we have to do
686                         // is continue to the next iteration, because the logic
687                         // will land up calling the FindKey method within the
688                         // TryRecoverStruct method above.
689                         if (fTryRecover) continue;
690                 }
691                 
692                 // Check if we are padding. If we are, then the bus patch data is
693                 // actually 4 bytes smaller and the last word is a padding word.
694                 if (dspHeader->fPaddingWord == 1)
695                 {
696                         dataEnd -= sizeof(UInt_t);
697                         
698                         // Check the pad word is correct.
699                         const UInt_t* padWord = reinterpret_cast<const UInt_t*>(dataEnd);
700                         if (*padWord != fgkPaddingWord)
701                         {
702                                 fHandler.OnError(EventHandler::kBadPaddingWord, padWord);
703                                 fHadError = true;
704                                 if (fExitOnError)
705                                 {
706                                         fHandler.OnEndOfDSP(dspHeader, dataStart);
707                                         return false;
708                                 }
709                         }
710                 }
711                 
712                 if (not DecodeDSPData(dataStart, dataEnd))
713                 {
714                         // At this point we had a problem decoding the DSP structure's
715                         // data, thus we should stop further decoding if so requested by
716                         // the user. Note the fHadError flag is already marked inside
717                         // DecodeDSPData.
718                         if (fExitOnError)
719                         {
720                                 fHandler.OnEndOfDSP(dspHeader, dataStart);
721                                 return false;
722                         }
723                 }
724                 fHandler.OnEndOfDSP(dspHeader, dataStart);
725         }
726         
727         return true;
728 }
729
730
731 template <class EventHandler>
732 bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeDSPData(
733                 const UChar_t* start, const UChar_t* end
734         )
735 {
736         /// This method decodes a DSP structure's data payload. It finds all the
737         /// bus patches found inside and for each it calls the OnNewBusPatch method
738         /// for the event handler to signal the start of each new bus patch.
739         /// \param start  This is the pointer to the start of the DSP structure's data.
740         /// \param end  This is the pointer to the first byte just past the
741         ///             end of the DSP structure.
742         /// \return If the DSP structure's data was decoded without errors
743         ///      or we could recover from the errors, then true is returned.
744         ///      False is returned otherwise.
745         
746         const UChar_t* current = start;
747         
748         UInt_t busPatchCount = 0; // Indicates the number of bus patches decoded.
749         while (current < end)
750         {
751                 // Mark the start of the bus patch structure.
752                 const UChar_t* busPatchStart = current;
753                 
754                 // Get the bus patch header, move the current pointer just past
755                 // the end of the header and check that we have not overflowed
756                 // the buffer.
757                 const AliMUONBusPatchHeaderStruct* busPatchHeader
758                         = reinterpret_cast<const AliMUONBusPatchHeaderStruct*>(busPatchStart);
759                 current += sizeof(AliMUONBusPatchHeaderStruct);
760                 if (current > end or current < start)
761                 {
762                         // If we overflowed the pointer and already had an error then
763                         // we are clearly lost so just stop decoding before we segfault.
764                         if (current < start and fHadError) return false;
765                         
766                         // So we only got part of a bus patch header at the very
767                         // end of the DSP structure buffer. Nothing to do but
768                         // report the error and exit. Set fHadError in case of
769                         // further decoding.
770                         fHandler.OnError(EventHandler::kNoBusPatchHeader, busPatchHeader);
771                         fHadError = true;
772                         return false;
773                 }
774                 
775                 // The header fits the buffer so we can mark the data start and
776                 // read from the header to find the end of data and bus patch
777                 // structure pointers.
778                 const UChar_t* dataStart = current;
779                 current += busPatchHeader->fLength * sizeof(UInt_t);
780                 const UChar_t* dataEnd = current;
781                 const UChar_t* busPatchEnd = busPatchStart
782                         + busPatchHeader->fTotalLength * sizeof(UInt_t);
783                 
784                 // Now we need to check for the following things:
785                 // 1) Is the end of bus patch structure or end of data pointer
786                 //    outside the buffer boundaries.
787                 // 2) Are the values for these pointers the same.
788                 // 3) Is the expected data key in the header present.
789                 // If any of the above fail then we know there is a problem with
790                 // the bus patch header. It must be corrupted somehow.
791                 if (busPatchHeader->fDataKey != fgkBusPatchDataKey
792                     or dataEnd > end or dataEnd < start
793                     or busPatchEnd > end or busPatchEnd < start
794                     or dataEnd != busPatchEnd)
795                 {
796                         // So let us see what exactly is wrong and report this.
797                         if (busPatchHeader->fDataKey != fgkBusPatchDataKey)
798                                 fHandler.OnError(EventHandler::kBadBusPatchKey, &busPatchHeader->fDataKey);
799                         if (busPatchEnd > end or busPatchEnd < start)
800                                 fHandler.OnError(EventHandler::kBadBusPatchLength, &busPatchHeader->fLength);
801                         if (dataEnd > end or dataEnd < start)
802                                 fHandler.OnError(EventHandler::kBadBusPatchTotalLength, &busPatchHeader->fTotalLength);
803                         if (dataEnd != busPatchEnd)
804                                 fHandler.OnError(EventHandler::kBusPatchLengthMismatch, busPatchHeader);
805                         
806                         // Indicate we had and error and stop the decoding if so
807                         // requested by the user.
808                         fHadError = true;
809                         if (fExitOnError) return false;
810                         
811                         // Try to recover from the corrupt header.
812                         RecoverResult result = TryRecoverStruct(
813                                         fgkBusPatchDataKey, sizeof(AliMUONBusPatchHeaderStruct),
814                                         busPatchHeader->fTotalLength, busPatchHeader->fLength,
815                                         busPatchStart, end, dataEnd, busPatchEnd, current
816                                 );
817                         if (result == kContinueToNextStruct)
818                                 continue; // Try the next bus patch at 'current'.
819                         if (result == kRecoverFailed) return false;
820                 }
821                 
822                 // At this point we certainly have a valid bus patch header, so
823                 // we need to check if we have more bus patches than we expected.
824                 // If not then we can indicate we have another bus patch and
825                 // decode its data.
826                 if (++busPatchCount > fMaxBusPatches)
827                 {
828                         fHandler.OnError(EventHandler::kTooManyBusPatches, current);
829                         
830                         // In this case we stop further decoding of the DSP
831                         // structure's data because clearly something is seriously
832                         // wrong if we are getting more bus patches than expected.
833                         // Indicate that we had an error so the Decode() method
834                         // returns false.
835                         fHadError = true;
836                         return false;
837                 }
838                 
839                 fHandler.OnNewBusPatch(busPatchHeader, dataStart);
840                 if (not DecodeBusPatchData(dataStart, dataEnd))
841                 {
842                         // At this point we had a problem decoding the bus patch data,
843                         // thus we should stop further decoding if so requested by the
844                         // user. Note the fHadError flag is already marked inside
845                         // DecodeBusPatchData.
846                         if (fExitOnError)
847                         {
848                                 fHandler.OnEndOfBusPatch(busPatchHeader, dataStart);
849                                 return false;
850                         }
851                 }
852                 fHandler.OnEndOfBusPatch(busPatchHeader, dataStart);
853         }
854         
855         return true;
856 }
857
858
859 template <class EventHandler>
860 bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeBusPatchData(
861                 const UChar_t* start, const UChar_t* end
862         )
863 {
864         /// This method decodes a single bus patch's data payload.
865         /// It will check the parity of the raw data words and send them
866         /// to the event handler instance with calls to OnData.
867         /// \param start  This is the pointer to the start of the bus patch
868         ///               structure's data.
869         /// \param end  This is the pointer to the first byte just past the
870         ///             end of the bus patch structure.
871         /// \return If the bus patch's data was decoded without errors
872         ///      or we could recover from the errors, then true is returned.
873         ///      False is returned otherwise.
874
875         // Assert that 'end' is always larger than start by n*sizeof(UInt_t)
876         // where n is a positive integer. This should be the case because we
877         // always add multiples of sizeof(UInt_t) to the 'current' pointer in
878         // all the DecodeXYZ methods.
879         assert( UInt_t(end - start) % 4 == 0 );
880         
881         // Now step through all the data words and issue OnData events.
882         // We also need to check parity and signal OnError if it is not valid
883         // for any of the data words.
884         const UInt_t* data = reinterpret_cast<const UInt_t*>(start);
885         const UInt_t* dataEnd = reinterpret_cast<const UInt_t*>(end);
886         for (; data < dataEnd; data++)
887         {
888                 if (ParityIsOk(*data))
889                 {
890                         fHandler.OnData(*data, false);
891                 }
892                 else
893                 {
894                         // Indicate we had a parity error and exit immediately
895                         // if the user so requested.
896                         fHandler.OnError(EventHandler::kParityError, data);
897                         fHadError = true;
898                         if (fExitOnError) return false;
899                         
900                         if (fSendDataOnParityError)
901                                 fHandler.OnData(*data, true);
902                 }
903         }
904         
905         return true;
906 }
907
908
909 template <class EventHandler>
910 typename AliMUONTrackerDDLDecoder<EventHandler>::RecoverResult
911 AliMUONTrackerDDLDecoder<EventHandler>::TryRecoverStruct(
912                 UInt_t expectedKey,
913                 UInt_t headerSize,
914                 UInt_t totalLength,
915                 UInt_t length,
916                 const UChar_t* structStart,
917                 const UChar_t* bufferEnd,
918                 const UChar_t*& dataEnd,
919                 const UChar_t*& structEnd,
920                 const UChar_t*& current
921         )
922 {
923         /// This method attempts to recover from a corrupt structure header by
924         /// figuring out which of the structure size indicators is correct.
925         /// This is possible because each header has some redundant information.
926         /// The recovery procedure is only attempted if fTryRecover was set to
927         /// true. If the recovery procedure is successful then this method will
928         /// also update the pointers indicating the start of data, end of structure
929         /// and current parsing position with the correct values.
930         ///
931         /// [in]  \param expectedKey This is the expected block key for the header
932         ///           currently being processed.
933         /// [in]  \param headerSize  The expected header size as given by the sizeof
934         ///           operator for example.
935         /// [in]  \param totalLength The total length as given by the fTotalLength
936         ///           field in the current header being handled.
937         /// [in]  \param length  The data length as given by the fLength field
938         ///           in the current header being handled.
939         /// [in]  \param structStart A pointer to the start of the structure header.
940         /// [in]  \param bufferEnd A pointer to the first byte just past the end
941         ///           of the buffer. This could be the pointer to the first byte
942         ///           just past the end of the parent structure if we are dealing
943         ///           with a DSP structure or bus patch. The parent structure for
944         ///           the DSP is a block structure and for a bus patch it is a DSP.
945         /// [out] \param dataEnd This is the pointer to the first byte just past
946         ///           the end of the structure being processed. It should be equal to
947         ///           structStart + sizeof(structure header) + fLength, where fLength
948         ///           is the field found in the structure's header itself. This value
949         ///           will be corrected and updated if we could recover from the
950         ///           corruption in the header.
951         /// [out] \param structEnd A pointer to the first byte just past the end of
952         ///           the structure. This value should be set equal to
953         ///           structStart + fTotalLength * sizeof(UInt_t), where fTotalLength
954         ///           is the field found in the structure's header itself. This value
955         ///           will be corrected and updated if we could recover from the
956         ///           corruption in the header.
957         /// [out] \param current This is the pointer to the current location in
958         ///           the DDL payload being parsed. It should in principle point
959         ///           to the start of the structures data. This value will be
960         ///           corrected and updated if we could recover from the corruption
961         ///           in the header.
962         ///
963         /// \return Returns the result of the recovery attempt, which can be one
964         ///    of the following:
965         ///      kRecoverFailed - The recovery failed completely so the caller
966         ///           cannot continue parsing any more structures. If the failure
967         ///           is within a DSP then one could still continue parsing
968         ///           from the next block. Similarly for bus patches, parsing could
969         ///           continue from the next DSP structure.
970         ///      kStructRecovered - Indicates that we recovered from a corrupt
971         ///           structure header and can continue processing the data of the
972         ///           structure in question.
973         ///      kContinueToNextStruct - Either fTryRecover was set to false or we
974         ///           could not recover from the corrupt header but we did find the
975         ///           start of another header matching the expected key so parsing
976         ///           can continue from the updated current position.
977
978         // Check if the user wants us to try and recover from a corrupt header.
979         if (not fTryRecover) return kContinueToNextStruct;
980         
981         // If the user wants us to try recover, then try to recover what the
982         // correct values for dataEnd, structEnd and current were supposed to be.
983         // The recovery procedure is as follows: We have 4 conditions for a correct
984         // header:
985         //   1) The header key is what we expect.
986         //   2) The totalLength equals length + headerSize.
987         //   3) The word at dataEnd contains a valid key. (implies length is
988         //      correct.)
989         //   4) The word at structEnd contains a valid key. (implies totalLength
990         //      is correct.)
991         // If any 2 of these conditions hold then we know that only one of the
992         // header fields is corrupt and we have enough information to reconstruct
993         // the third field. Note that if conditions 3 and 4 are true then this
994         // implies 2 is also true. (not necessarily the other way around though.)
995         // The valid key mentioned above at dataEnd and structEnd should be:
996         //   a) A bus patch key, DSP key or end of buffer if expectedKey indicates
997         //      a buspatch.
998         //   b) A DSP key, block structure key or end of buffer if expectedKey
999         //      indicates a DSP.
1000         //   c) A block structure key or end of buffer if expectedKey indicates
1001         //      a DSP.
1002         const UInt_t* headerKey = reinterpret_cast<const UInt_t*>(structStart);
1003         bool headerKeyOk = (expectedKey == *headerKey);
1004         
1005         bool lengthsMatch = (totalLength*4 == length*4 + headerSize);
1006         
1007         bool lengthIsCorrect = false;
1008         bool totalLengthIsCorrect = false;
1009         const UInt_t* keyAtDataEnd = reinterpret_cast<const UInt_t*>(dataEnd);
1010         const UInt_t* keyAtStructEnd = reinterpret_cast<const UInt_t*>(structEnd);
1011         
1012
1013         if ( expectedKey == fgkBlockDataKey )
1014         {
1015                 if (dataEnd == bufferEnd)
1016                 {
1017                         // Are we at the end of the buffer?
1018                         lengthIsCorrect = true;
1019                 }
1020                 else
1021                 {
1022                         // Must check that we can read another 4 bytes before
1023                         // checking the key at dataEnd.
1024                         if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
1025                         {
1026                                 if (*keyAtDataEnd == fgkBlockDataKey)
1027                                         lengthIsCorrect = true;
1028                         }
1029                 }
1030                 
1031                 if (structEnd == bufferEnd)
1032                 {
1033                         // Are we at the end of the buffer?
1034                         totalLengthIsCorrect = true;
1035                 }
1036                 else
1037                 {
1038                         // Must check that we can read another 4 bytes before
1039                         // checking the key at structEnd.
1040                         if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
1041                         {
1042                                 if (*keyAtStructEnd == fgkBlockDataKey)
1043                                         totalLengthIsCorrect = true;
1044                         }
1045                 }
1046         }        
1047                         
1048         else if ( expectedKey == fgkDSPDataKey )
1049         {
1050                 if (dataEnd == bufferEnd)
1051                 {
1052                         // Are we at the end of the buffer?
1053                         lengthIsCorrect = true;
1054                 }
1055                 else
1056                 {
1057                         // Must check that we can read another 4 bytes before
1058                         // checking the key at dataEnd.
1059                         if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
1060                         {
1061                                 if (*keyAtDataEnd == fgkBlockDataKey
1062                                     or *keyAtDataEnd == fgkDSPDataKey)
1063                                         lengthIsCorrect = true;
1064                         }
1065                 }
1066                 
1067                 if (structEnd == bufferEnd)
1068                 {
1069                         // Are we at the end of the buffer?
1070                         totalLengthIsCorrect = true;
1071                 }
1072                 else
1073                 {
1074                         // Must check that we can read another 4 bytes before
1075                         // checking the key at structEnd.
1076                         if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
1077                         {
1078                                 if (*keyAtStructEnd == fgkBlockDataKey
1079                                     or *keyAtStructEnd == fgkDSPDataKey)
1080                                         totalLengthIsCorrect = true;
1081                         }
1082                 }
1083         }        
1084         else if ( expectedKey == fgkBusPatchDataKey )
1085         {
1086                 if (dataEnd == bufferEnd)
1087                 {
1088                         // Are we at the end of the buffer?
1089                         lengthIsCorrect = true;
1090                 }
1091                 else
1092                 {
1093                         // Must check that we can read another 4 bytes before
1094                         // checking the key at dataEnd.
1095                         if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
1096                         {
1097                                 if (*keyAtDataEnd == fgkDSPDataKey
1098                                     or *keyAtDataEnd == fgkBusPatchDataKey)
1099                                         lengthIsCorrect = true;
1100                         }
1101                 }
1102                 
1103                 if (structEnd == bufferEnd)
1104                 {
1105                         // Are we at the end of the buffer?
1106                         totalLengthIsCorrect = true;
1107                 }
1108                 else
1109                 {
1110                         // Must check that we can read another 4 bytes before
1111                         // checking the key at structEnd.
1112                         if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
1113                         {
1114                                 if (*keyAtStructEnd == fgkDSPDataKey
1115                                     or *keyAtStructEnd == fgkBusPatchDataKey)
1116                                         totalLengthIsCorrect = true;
1117                         }
1118                 }
1119         }
1120         
1121         if (headerKeyOk and lengthIsCorrect)
1122         {
1123                 // totalLength was wrong, dataEnd is correct.
1124                 structEnd = dataEnd;
1125                 current = dataEnd;
1126                 return kStructRecovered;
1127         }
1128         if (headerKeyOk and totalLengthIsCorrect)
1129         {
1130                 // Length was wrong, structEnd is correct.
1131                 dataEnd = structEnd;
1132                 current = structEnd;
1133                 return kStructRecovered;
1134         }
1135         if (lengthsMatch and lengthIsCorrect and totalLengthIsCorrect)
1136         {
1137                 // The header's key was wrong but the lengths and pointers are OK.
1138                 return kStructRecovered;
1139         }
1140         
1141         // Could not recover the header from the available information, so find
1142         // the next key in the stream that is the same as the currently expected
1143         // one and continue decoding from there.
1144         const UChar_t* location = FindKey(
1145                         expectedKey, structStart + sizeof(UInt_t), bufferEnd
1146                 );
1147         if (location != NULL)
1148         {
1149                 current = location;
1150                 return kContinueToNextStruct;
1151         }
1152
1153         return kRecoverFailed;
1154 }
1155
1156
1157 template <class EventHandler>
1158 const UChar_t* AliMUONTrackerDDLDecoder<EventHandler>::FindKey(
1159                 UInt_t key, const UChar_t* start, const UChar_t* end
1160         )
1161 {
1162         /// Searches for the first occurrence of the key value in the buffer marked by
1163         /// 'start' and 'end'. 'start' should point to the start of the buffer and 'end'
1164         /// should point to 'start + bufferSize', i.e. just past the last byte of the
1165         /// buffer. If the key was found then the pointer to that location is returned
1166         /// otherwise NULL is returned.
1167         
1168         if (end + sizeof(UInt_t) < start) return NULL;  // check for pointer overflow.
1169         const UChar_t* current = start;
1170         while (current + sizeof(UInt_t) <= end)
1171         {
1172                 UInt_t data = * reinterpret_cast<const UInt_t*>(current);
1173                 if (data == key) return current;
1174                 current++;
1175         }
1176         return NULL;
1177 }
1178
1179
1180 template <class EventHandler>
1181 bool AliMUONTrackerDDLDecoder<EventHandler>::ParityIsOk(UInt_t data)
1182 {
1183         /// Optimised parity check addapted from:
1184         /// http://graphics.stanford.edu/~seander/bithacks.html#ParityParallel
1185         
1186         // parity of the 32 bits must be zero if the last bit is equal
1187         // to the parity of the first 31 bits.
1188         // Reason: the parity bit xor the parity of the first 31 bits must give
1189         // zero, unless there was a bit error.
1190         data ^= data >> 16;
1191         data ^= data >> 8;
1192         data ^= data >> 4;
1193         data &= 0xf;
1194         data = ((0x6996 >> data) & 1);
1195         return data == 0;
1196 }
1197
1198 #endif // ALIMUONTRACKERDDLDECODER_H