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