]> git.uio.no Git - u/mrichter/AliRoot.git/blob - MUON/AliMUONTrackerDDLDecoder.h
Added fit macro from M. Putis
[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 <string.h>
41 #include "AliMUONTrackerDDLDecoderEventHandler.h"
42
43 /// \ingroup raw
44 /// \class AliMUONTrackerDDLDecoder
45 /// \brief A high performance decoder class for MUON tracking DDL data.
46 ///
47 /// This class implements a high performance decoder for decoding DDL payload
48 /// data coming from the muon spectrometers tracking chambers.
49 /// It has been implemented using the event driven paradigm with templates,
50 /// which allows us to minimise the number of method calls made in the inner
51 /// loops of the algorithm and minimise the memory footprint. At least for
52 /// optimised production compilations.
53 /// The decoder class only contains the basic decoding and error checking logic.
54 /// It calls methods such as OnNewBlock, OnNewBusPatch, OnData etc in
55 /// the event handler during the decoding to return the decoded data.
56 /// The event handler class is nothing more than a callback interface to deliver
57 /// the next chunks of decoded data.
58 /// To actually do something with the data, one needs to implement a custom
59 /// event handler (callback) class by inheriting from AliMUONTrackerDDLDecoderEventHandler
60 /// and overriding the callback methods like so:
61 /// \code
62 ///  class MyCustomHandler : public AliMUONTrackerDDLDecoderEventHandler
63 ///  {
64 ///  public:
65 ///     void OnData(UInt_t data, bool parityError)
66 ///     {
67 ///       // I can do something with 'data' here and check if there was
68 ///       // a parity error with 'parityError'.
69 ///     }
70 ///  };
71 /// \endcode
72 ///
73 /// Once the custom handler is written then the decoder is instantiated as
74 /// shown below, to use your new custom handler. Also to start decoding one needs
75 /// to call the Decode() method of the decoder.
76 /// \code
77 ///  AliMUONTrackerDDLDecoder<MyCustomHandler> myDecoder;
78 ///  muDecoder.Decoder(buffer, bufferSize);
79 /// \endcode
80 ///
81 /// Note that this class was written as a template on purpose. To maximise the
82 /// compilers chance to make optimisations and inline the code we must use a template.
83 /// Depending on exactly what you do inside your handler, the decoder could be
84 /// significantly slower if run time polymorphism was used, i.e. making the class
85 /// AliMUONTrackerDDLDecoderEventHandler abstract and using virtual methods.
86 ///
87 /// There has been a change to the data format that the real detector generates.
88 /// Two trailer words are added to the end of the DDL payload which indicated
89 /// the end of data. The decoder is initialised by default to automatically
90 /// check for these and deal with it correctly, if they exist or not.
91 /// However, if you want to override this behaviour then set the flag
92 /// fAutoDetectTrailer to false with AutoDetectTrailer(false). Then if you have
93 /// data with the old data format you should set fCheckForTrailer to false with
94 /// CheckForTrailer(false), otherwise for real data it should be
95 /// fCheckForTrailer = true. Only when fAutoDetectTrailer is true will the
96 /// fCheckForTrailer flag be ignored and no warnings will be generated for an
97 /// incorrect data format.
98 ///
99 /// \author Artur Szostak <artursz@iafrica.com>
100
101 template <class EventHandler>
102 class AliMUONTrackerDDLDecoder
103 {
104 public:
105
106         /// Default contructor.
107         AliMUONTrackerDDLDecoder() :
108                 fExitOnError(true), fTryRecover(false),
109                 fSendDataOnParityError(false), fHadError(false),
110                 fAutoDetectTrailer(true), fCheckForTrailer(true),
111                 fMaxBlocks(2), fMaxDSPs(5), fMaxBusPatches(5), fHandler()
112         {}
113         
114         /// Constant method to return the event handler instance.
115         const EventHandler& GetHandler() const { return fHandler; }
116         
117         /// Returns the event handler instance.
118         EventHandler& GetHandler() { return fHandler; }
119         
120         /// Returns the "exit on error" flag.
121         /// i.e. should the decoder stop on the very first error found.
122         bool ExitOnError() const { return fExitOnError; }
123         
124         /// Sets the "exit on error" flag.
125         /// i.e. should the decoder stop on the very first error found.
126         void ExitOnError(bool value) { fExitOnError = value; }
127         
128         /// Returns the "try to recover from errors" flag.
129         /// i.e. should the decoder try to recover from errors found in the
130         /// payload headers or trailers.
131         bool TryRecover() const { return fTryRecover; }
132         
133         /// Sets the "try to recover from errors" flag.
134         /// i.e. should the decoder try to recover from errors found in the
135         /// payload headers or trailers.
136         void TryRecover(bool value) { fTryRecover = value; }
137         
138         /// Returns the flag indicating if the raw data words in the bus patches
139         /// that failed their parity tests (i.e. parity error / bit flip in the
140         /// raw data word) will be sent to the event handler anyway through OnData.
141         bool SendDataOnParityError() const { return fSendDataOnParityError; }
142         
143         /// Sets the flag indicating if the raw data words in the bus patches
144         /// that failed their parity tests (i.e. parity error / bit flip in the
145         /// raw data word) will be sent to the event handler anyway through OnData.
146         void SendDataOnParityError(bool value) { fSendDataOnParityError = value; }
147         
148         /// Returns the maximum block count expected in the DDL payload.
149         UInt_t MaxBlocks() const { return fMaxBlocks; }
150         
151         /// Sets the maximum block count expected in the DDL payload.
152         void MaxBlocks(UInt_t n) { fMaxBlocks = n; }
153         
154         /// Returns the maximum DSP header count expected in any given block
155         /// structure within the DDL payload.
156         UInt_t MaxDSPs() const { return fMaxDSPs; }
157         
158         /// Sets the maximum DSP header count expected in any given block structure
159         /// within the DDL payload.
160         void MaxDSPs(UInt_t n) { fMaxDSPs = n; }
161         
162         /// Returns the maximum number of bus patches expected in any given DSP
163         /// structure within the DDL payload.
164         UInt_t MaxBusPatches() const { return fMaxBusPatches; }
165         
166         /// Sets the maximum number of bus patches expected in any given DSP
167         /// structure within the DDL payload.
168         void MaxBusPatches(UInt_t n) { fMaxBusPatches = n; }
169         
170         /// Returns the value of the auto-detect trailer flag.
171         bool AutoDetectTrailer() const { return fAutoDetectTrailer; }
172         
173         /// Sets the value of the auto-detect trailer flag.
174         void AutoDetectTrailer(bool value) { fAutoDetectTrailer = value; }
175         
176         /// Returns the value of the flag to check for the end of DDL trailer.
177         bool CheckForTrailer() const { return fCheckForTrailer; }
178         
179         /// Sets the value of the flag to check for the end of DDL trailer.
180         void CheckForTrailer(bool value) { fCheckForTrailer = value; }
181         
182         /// This method decodes the DDL payload contained in the buffer.
183         bool Decode(const void* buffer, UInt_t bufferSize);
184         
185         /// First try fix data corruption and then decode the DDL payload.
186         bool Decode(void* buffer, UInt_t bufferSize);
187         
188         /// Returns the block marker key.
189         static UInt_t BlockDataKeyWord() { return fgkBlockDataKey; }
190         
191         /// Returns the DSP marker key.
192         static UInt_t DspDataKeyWord() { return fgkDSPDataKey; }
193         
194         /// Returns the bus patch marker key.
195         static UInt_t BusPatchDataKeyWord() { return fgkBusPatchDataKey; }
196         
197         /// Returns the expected padding word value.
198         static UInt_t PaddingWord() { return fgkPaddingWord; }
199         
200         /// Returns the expected end of DDL marker.
201         static UInt_t EndOfDDLWord() { return fgkEndOfDDL; }
202         
203 private:
204
205         bool fExitOnError; ///< Indicates if we should exit on the very first error.
206         bool fTryRecover; ///< Indicates if we should try recover from a corrupt structure header or DDL trailer.
207         bool fSendDataOnParityError; ///< If set to true then we issue a OnData() event even if the data word had a parity error.
208         bool fHadError; ///< Indicates if we had an error decoding the data.
209         bool fAutoDetectTrailer; ///< Indicates if we should automatically check for the end of DDL trailer (Default = true).
210         bool fCheckForTrailer; ///< Indicates if we should check for the end of DDL trailer (Default = true). This flag is ignored if fAutoDetectTrailer is true.
211         UInt_t fMaxBlocks; ///< Maximum number of block structures allowed in a DDL stream.
212         UInt_t fMaxDSPs; ///< Maximum number of DSP structures allowed in a DDL stream.
213         UInt_t fMaxBusPatches; ///< Maximum number of bus patch structures allowed in a DDL stream.
214         EventHandler fHandler; ///< The event handler which deals with parsing events.
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
227         /// Possible results that can be returned by the TryRecoverStruct method.
228         enum RecoverResult
229         {
230                 kRecoverFailed,        ///< The recovery failed. Cannot continue parsing.
231                 kStructRecovered,      ///< Indicates that we recovered from a corrupt structure header and can continue processing the given structure.
232                 kContinueToNextStruct  ///< Must continue parsing the next structure and ignore the current one.
233         };
234
235         RecoverResult TryRecoverStruct(
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;     ///< The key word expected to identify block structure headers.
254         static const UInt_t fgkDSPDataKey;       ///< The key word expected to identify DSP structure headers.
255         static const UInt_t fgkBusPatchDataKey;  ///< The key word expected to identify bus patch headers.
256         static const UInt_t fgkPaddingWord;      ///< The expected format of the padding word in the DDL payload.
257         static const UInt_t fgkEndOfDDL;         ///< The end of DDL trailer word.
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>
265 const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkBlockDataKey = 0xFC0000FC;
266 template <class EventHandler>
267 const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkDSPDataKey = 0xF000000F;
268 template <class EventHandler>
269 const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkBusPatchDataKey = 0xB000000B;
270 template <class EventHandler>
271 const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkPaddingWord = 0xBEEFFACE;
272 template <class EventHandler>
273 const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkEndOfDDL = 0xD000000D;
274
275
276 template <class EventHandler>
277 bool AliMUONTrackerDDLDecoder<EventHandler>::Decode(const void* buffer, UInt_t bufferSize)
278 {
279         /// This method should be called to actually decode the DDL payload
280         /// contained in a memory buffer. The payload should be for a muon tracking
281         /// chamber DDL stream.
282         /// As the decoder progresses it will make method calls to the event handler
283         /// instance (which can be accessed with the GetHandler() method) to indicate
284         /// the start of the new block, DSP and bus patch headers. For every raw
285         /// data word the OnData method of the event handler is called.
286         ///
287         /// If an error occurs during the parse because the data is corrupt then
288         /// the OnError method is called indicating what the problem was.
289         /// Decoding will stop at this point unless the fExitOnError flag is set
290         /// to false. Also raw data words which contain a parity error are only
291         /// sent to the event handler with OnData if the fSendDataOnParityError
292         /// flag is set to true. There is also an optional flag fTryRecover which
293         /// can enable logic which will attempt to recover the header structures found
294         /// in the DDL payload if they are found to be inconsistent (assumed corrupt).
295         /// fTryRecover set to true will also enable recovery from a corrupt
296         /// DDL trailer marking the end of DDL payload.
297         ///
298         /// \param buffer  This is the pointer to the start of the memory buffer
299         ///     containing the DDL payload. Remember that this must be the start of
300         ///     the payload and not the DDL stream. That is, this pointer should be
301         ///     equal to: DDL start pointer + 8 * sizeof(UInt_t).
302         /// \param bufferSize  This is the pointer to the first byte just past the
303         ///     end of the block structure.
304         /// \return Returns false if there was any problem with decoding the data,
305         ///     and true otherwise. Note: the data may have been partially decoded
306         ///     even if false was returned, which would be indicated by at least one
307         ///     call to the event handlers OnData method.
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 {
328         /// This decoding method performs a special checks to see if the DDL
329         /// corruption is fixable and then fixes the buffer by modifying it directly.
330         /// The fixes only apply if the fTryRecover flag is enabled.
331         /// \note buffer might be modified.
332         
333         assert( buffer != NULL );
334         if (fTryRecover)
335         {
336                 ///////////////////////////////////////////////////////
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>
363 void AliMUONTrackerDDLDecoder<EventHandler>::DecodeBuffer(
364                 const UChar_t* start, const UChar_t* end
365         )
366 {
367         /// This method decodes the buffer's payload data. It unpacks the block
368         /// structures contained inside and then for each block it calls the
369         /// OnNewBlock method for the event handler to signal the start of each new
370         /// block structure. OnEndOfBlock is called once each block is processed.
371         /// \param start  This is the pointer to the start of the buffer.
372         /// \param end  This is the pointer to the first byte just past the
373         ///             end of the buffer.
374         /// fHadError is set to true if there were any errors decoding the buffer
375         /// and the OnError method of the callback event handler is called for
376         /// each error.
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>
586 bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeBlockData(
587                 const AliMUONBlockHeaderStruct* blockHeader,
588                 const UChar_t* start, const UChar_t* end
589         )
590 {
591         /// This method decodes a block structure's data payload. It unpacks the
592         /// DSP structures contained inside and then for each DSP it calls the
593         /// OnNewDSP method for the event handler to signal the start of each new
594         /// DSP structure.
595         /// \param blockHeader
596         /// \param start  This is the pointer to the start of the block
597         ///               structure's data.
598         /// \param end  This is the pointer to the first byte just past the
599         ///             end of the block structure.
600         /// \return If the block structure's data was decoded without errors
601         ///      or we could recover from the errors, then true is returned.
602         ///      False is returned otherwise.
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>
777 bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeDSPData(
778                 const UChar_t* start, const UChar_t* end
779         )
780 {
781         /// This method decodes a DSP structure's data payload. It finds all the
782         /// bus patches found inside and for each it calls the OnNewBusPatch method
783         /// for the event handler to signal the start of each new bus patch.
784         /// \param start  This is the pointer to the start of the DSP structure's data.
785         /// \param end  This is the pointer to the first byte just past the
786         ///             end of the DSP structure.
787         /// \return If the DSP structure's data was decoded without errors
788         ///      or we could recover from the errors, then true is returned.
789         ///      False is returned otherwise.
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>
905 bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeBusPatchData(
906                 const UChar_t* start, const UChar_t* end
907         )
908 {
909         /// This method decodes a single bus patch's data payload.
910         /// It will check the parity of the raw data words and send them
911         /// to the event handler instance with calls to OnData.
912         /// \param start  This is the pointer to the start of the bus patch
913         ///               structure's data.
914         /// \param end  This is the pointer to the first byte just past the
915         ///             end of the bus patch structure.
916         /// \return If the bus patch's data was decoded without errors
917         ///      or we could recover from the errors, then true is returned.
918         ///      False is returned otherwise.
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>
955 typename AliMUONTrackerDDLDecoder<EventHandler>::RecoverResult
956 AliMUONTrackerDDLDecoder<EventHandler>::TryRecoverStruct(
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 {
968         /// This method attempts to recover from a corrupt structure header by
969         /// figuring out which of the structure size indicators is correct.
970         /// This is possible because each header has some redundant information.
971         /// The recovery procedure is only attempted if fTryRecover was set to
972         /// true. If the recovery procedure is successful then this method will
973         /// also update the pointers indicating the start of data, end of structure
974         /// and current parsing position with the correct values.
975         ///
976         /// [in]  \param expectedKey This is the expected block key for the header
977         ///           currently being processed.
978         /// [in]  \param headerSize  The expected header size as given by the sizeof
979         ///           operator for example.
980         /// [in]  \param totalLength The total length as given by the fTotalLength
981         ///           field in the current header being handled.
982         /// [in]  \param length  The data length as given by the fLength field
983         ///           in the current header being handled.
984         /// [in]  \param structStart A pointer to the start of the structure header.
985         /// [in]  \param bufferEnd A pointer to the first byte just past the end
986         ///           of the buffer. This could be the pointer to the first byte
987         ///           just past the end of the parent structure if we are dealing
988         ///           with a DSP structure or bus patch. The parent structure for
989         ///           the DSP is a block structure and for a bus patch it is a DSP.
990         /// [out] \param dataEnd This is the pointer to the first byte just past
991         ///           the end of the structure being processed. It should be equal to
992         ///           structStart + sizeof(structure header) + fLength, where fLength
993         ///           is the field found in the structure's header itself. This value
994         ///           will be corrected and updated if we could recover from the
995         ///           corruption in the header.
996         /// [out] \param structEnd A pointer to the first byte just past the end of
997         ///           the structure. This value should be set equal to
998         ///           structStart + fTotalLength * sizeof(UInt_t), where fTotalLength
999         ///           is the field found in the structure's header itself. This value
1000         ///           will be corrected and updated if we could recover from the
1001         ///           corruption in the header.
1002         /// [out] \param current This is the pointer to the current location in
1003         ///           the DDL payload being parsed. It should in principle point
1004         ///           to the start of the structures data. This value will be
1005         ///           corrected and updated if we could recover from the corruption
1006         ///           in the header.
1007         ///
1008         /// \return Returns the result of the recovery attempt, which can be one
1009         ///    of the following:
1010         ///      kRecoverFailed - The recovery failed completely so the caller
1011         ///           cannot continue parsing any more structures. If the failure
1012         ///           is within a DSP then one could still continue parsing
1013         ///           from the next block. Similarly for bus patches, parsing could
1014         ///           continue from the next DSP structure.
1015         ///      kStructRecovered - Indicates that we recovered from a corrupt
1016         ///           structure header and can continue processing the data of the
1017         ///           structure in question.
1018         ///      kContinueToNextStruct - Either fTryRecover was set to false or we
1019         ///           could not recover from the corrupt header but we did find the
1020         ///           start of another header matching the expected key so parsing
1021         ///           can continue from the updated current position.
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>
1203 const UChar_t* AliMUONTrackerDDLDecoder<EventHandler>::FindKey(
1204                 UInt_t key, const UChar_t* start, const UChar_t* end
1205         )
1206 {
1207         /// Searches for the first occurrence of the key value in the buffer marked by
1208         /// 'start' and 'end'. 'start' should point to the start of the buffer and 'end'
1209         /// should point to 'start + bufferSize', i.e. just past the last byte of the
1210         /// buffer. If the key was found then the pointer to that location is returned
1211         /// otherwise NULL is returned.
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>
1226 bool AliMUONTrackerDDLDecoder<EventHandler>::ParityIsOk(UInt_t data)
1227 {
1228         /// Optimised parity check addapted from:
1229         /// http://graphics.stanford.edu/~seander/bithacks.html#ParityParallel
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