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