]> git.uio.no Git - u/mrichter/AliRoot.git/blob - MUON/AliMUONTriggerDDLDecoder.h
Number of readout errors was not properly histogrammed
[u/mrichter/AliRoot.git] / MUON / AliMUONTriggerDDLDecoder.h
1 #ifndef ALIMUONTRIGGERDDLDECODER_H
2 #define ALIMUONTRIGGERDDLDECODER_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   AliMUONTriggerDDLDecoder.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 trigger.
26 ///
27 /// This file implementes the AliMUONTriggerDDLDecoder class, which contains
28 /// the core logic for decoding the payload in DDL streams comming from the muon
29 /// spectrometer's hardware trigger in a very efficient manner.
30 ///
31 /// This implementation is derived from work done by Christian Finck for the
32 /// AliMUONPayloadTrigger class.
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 "AliMUONTriggerDDLDecoderEventHandler.h"
41
42 /// \ingroup raw
43 /// \class AliMUONTriggerDDLDecoder
44 /// \brief A high performance decoder class for MUON trigger DDL data.
45 ///
46 /// This class implements a high performance decoder for decoding DDL payload
47 /// data coming from the muon spectrometers trigger stations.
48 /// It has been implemented using the event driven paradigm with templates,
49 /// which allows us to minimise the number of method calls made in the inner
50 /// loops of the algorithm and minimise the memory footprint.
51 /// At least for optimised production compilations.
52 /// The decoder class only contains the basic decoding and error checking logic.
53 /// It calls methods such as OnNewBuffer, OnDarcHeader, OnNewRegionalStruct,
54 /// OnLocalStruct etc in the event handler during the decoding to return the
55 /// decoded data and headers.
56 /// The event handler class is nothing more than a callback interface to deliver
57 /// the next chunks of decoded data.
58 /// To actually do something with the data, one needs to implement a custom
59 /// event handler (callback) class by inheriting from AliMUONTriggerDDLDecoderEventHandler
60 /// and overriding the callback methods like so:
61 /// \code
62 ///  class MyCustomHandler : public AliMUONTriggerDDLDecoderEventHandler
63 ///  {
64 ///  public:
65 ///     void OnLocalStruct(const AliMUONLocalInfoStruct* localStruct,
66 ///                        const AliMUONLocalScalarsStruct* scalars)
67 ///     {
68 ///       // I can do something with the data in 'localStruct' here.
69 ///       // and the 'scalars' if they are not NULL.
70 ///     }
71 ///  };
72 /// \endcode
73 ///
74 /// Once the custom handler is written then the decoder is instantiated as
75 /// shown below, to use your new custom handler. Also to start decoding one needs
76 /// to call the Decode() method of the decoder.
77 /// \code
78 ///  AliMUONTriggerDDLDecoder<MyCustomHandler> myDecoder;
79 ///  muDecoder.Decoder(buffer, bufferSize);
80 /// \endcode
81 ///
82 /// Note that this class was written as a template on purpose. To maximise the
83 /// compilers chance to make optimisations and inline the code we must use a template.
84 /// Depending on exactly what you do inside your handler, the decoder could be
85 /// significantly slower if run time polymorphism was used, i.e. making the class
86 /// AliMUONTriggerDDLDecoderEventHandler abstract and using virtual methods.
87 ///
88 template <class EventHandler>
89 class AliMUONTriggerDDLDecoder
90 {
91 public:
92
93         /// Default contructor.
94         AliMUONTriggerDDLDecoder() :
95                 fExitOnError(true), fTryRecover(false),
96                 fAutoDetectScalars(false), fHadError(false),
97                 fNoRegionals(0), fMaxRegionals(8), fMaxLocals(16),
98                 fHandler()
99         {}
100         
101         /// Constant method to return the event handler instance.
102         const EventHandler& GetHandler() const { return fHandler; }
103         
104         /// Returns the event handler instance.
105         EventHandler& GetHandler() { return fHandler; }
106         
107         /// Returns the "exit on error" flag.
108         /// i.e. should the decoder stop on the very first error found.
109         bool ExitOnError() const { return fExitOnError; }
110         
111         /// Sets the "exit on error" flag.
112         /// i.e. should the decoder stop on the very first error found.
113         void ExitOnError(bool value) { fExitOnError = value; }
114         
115         /// Returns the "try to recover from errors" flag.
116         /// i.e. should the decoder try to recover from errors found in the
117         /// payload headers.
118         bool TryRecover() const { return fTryRecover; }
119         
120         /// Sets the "try to recover from errors" flag.
121         /// i.e. should the decoder try to recover from errors found in the
122         /// payload headers.
123         void TryRecover(bool value) { fTryRecover = value; }
124         
125         /// Returns the flag indicating if we should check for the scalars of
126         /// software triggers automatically or not.
127         bool AutoDetectScalars() const { return fAutoDetectScalars; }
128         
129         /// Sets the flag indicating if we should check for the scalars of
130         /// software triggers automatically or not. If set to true then the
131         /// scalarEvent parameter of the Decode method is ignored.
132         void AutoDetectScalars(bool value) { fAutoDetectScalars = value; }
133         
134         /// Returns the maximum regional structure count expected in the DDL payload.
135         UInt_t MaxRegionals() const { return fMaxRegionals; }
136         
137         /// Sets the maximum regional structure count expected in the DDL payload.
138         void MaxRegionals(UInt_t n) { fMaxRegionals = n; }
139         
140         /// Returns the number of regional structures we actually attempted to decode.
141         UInt_t RegionalsDecoded() const { return fNoRegionals; }
142         
143         /// Returns the maximum local structure count expected in any given regional
144         /// card structure within the DDL payload.
145         UInt_t MaxLocals() const { return fMaxLocals; }
146         
147         /// Sets the maximum local structure count expected in any given regional
148         /// card structure within the DDL payload.
149         void MaxLocals(UInt_t n) { fMaxLocals = n; }
150         
151         /// This method decodes the DDL payload contained in the buffer.
152         bool Decode(const void* buffer, UInt_t bufferSize, bool scalarEvent = false);
153         
154         /// Returns the end of DARC marker key.
155         static UInt_t EndOfDarcWord() { return fgkEndOfDarc; }
156         
157         /// Returns the end of global header marker key.
158         static UInt_t EndOfGlobalWord() { return fgkEndOfGlobal; }
159         
160         /// Returns the end of regional structure marker key.
161         static UInt_t EndOfRegionalWord() { return fgkEndOfReg; }
162         
163         /// Returns the regional error word.
164         static UInt_t RegionalErrorWord() { return fgkErrorWord; }
165         
166         /// Returns the end of local structure marker key.
167         static UInt_t EndOfLocalWord() { return fgkEndOfLocal; }
168         
169         /// Returns the local card disable word.
170         static UInt_t LocalDisableWord() { return fgkDisableWord; }
171         
172         /// Returns value of default DARC type.
173         static UInt_t DarcDefaultType() { return fgkDarcDefaultType; }
174         
175         /// Returns value of Vadorh DARC type.
176         static UInt_t DarcVadorhType()  { return fgkDarcVadorhType; }
177         
178 private:
179
180         bool fExitOnError; ///< Indicates if we should exit on the very first error.
181         bool fTryRecover; ///< Indicates if we should try recover from a corrupt structures.
182         bool fAutoDetectScalars; ///< Flag to indicate if we should auto-detect if there are scalars in the data.
183         bool fHadError; ///< Indicates if we had an error decoding the data.
184         UInt_t fNoRegionals; ///< The number of regional card structures actually decoded.
185         UInt_t fMaxRegionals; ///< Maximum number of regional card structures allowed in a DDL stream.
186         UInt_t fMaxLocals; ///< Maximum number of local card structures per regional structure allowed in a DDL stream.
187         EventHandler fHandler; ///< The event handler which deals with the generated parsing events.
188
189         void DecodeBuffer(const UChar_t* start, const UChar_t* end, bool scalarEvent);
190         void DecodeRegionalStructs(const UChar_t* start, const UChar_t* end, bool scalarEvent);
191         const UChar_t* DecodeLocalStructs(const UChar_t* start, const UChar_t* end, bool scalarEvent);
192         
193         const UChar_t* FindKey(
194                         UInt_t key, const UChar_t* start, const UChar_t* end
195                 );
196
197         static const UInt_t fgkEndOfDarc;   ///< Indicates the end of the DARC header.
198         static const UInt_t fgkEndOfGlobal; ///< Indicates the end of the global header just after the DARC header.
199         static const UInt_t fgkEndOfReg;    ///< Indicates the end of a regional card structure.
200         static const UInt_t fgkErrorWord;   ///< The error word when a regional board is missing.
201         static const UInt_t fgkEndOfLocal;  ///< Indicates the end of a local card structure.
202         static const UInt_t fgkDisableWord; ///< Word used to fill "empty" slots.
203         static const UInt_t fgkDarcDefaultType;   ///< default type for DARC def.
204         static const UInt_t fgkDarcVadorhType;    ///< default type for DARC vadorh
205 };
206
207 //_____________________________________________________________________________
208
209 // The following are the structure key words which are used to demarcate (identify
210 // the end) of the structures within the raw trigger data.
211 template <class EventHandler>
212 const UInt_t AliMUONTriggerDDLDecoder<EventHandler>::fgkEndOfDarc    = 0xDEADFACE;
213 template <class EventHandler>
214 const UInt_t AliMUONTriggerDDLDecoder<EventHandler>::fgkEndOfGlobal  = 0xDEADBEEF;
215 template <class EventHandler>
216 const UInt_t AliMUONTriggerDDLDecoder<EventHandler>::fgkEndOfReg     = 0xBEEFFACE;
217 template <class EventHandler>
218 const UInt_t AliMUONTriggerDDLDecoder<EventHandler>::fgkErrorWord    = 0xCAFEDEAD;
219 template <class EventHandler>
220 const UInt_t AliMUONTriggerDDLDecoder<EventHandler>::fgkEndOfLocal   = 0xCAFEFADE;
221 template <class EventHandler>
222 const UInt_t AliMUONTriggerDDLDecoder<EventHandler>::fgkDisableWord  = 0x10CADEAD;
223 template <class EventHandler>
224 const UInt_t AliMUONTriggerDDLDecoder<EventHandler>::fgkDarcDefaultType = 0x6;
225 template <class EventHandler>
226 const UInt_t AliMUONTriggerDDLDecoder<EventHandler>::fgkDarcVadorhType  = 0x4;
227
228
229 template <class EventHandler>
230 bool AliMUONTriggerDDLDecoder<EventHandler>::Decode(
231                 const void* buffer, UInt_t bufferSize, bool scalarEvent
232         )
233 {
234         /// This method should be called to actually decode the DDL payload
235         /// contained in a memory buffer. The payload should be in the muon trigger
236         /// system DDL stream format otherwise it will be recognised as corrupt.
237         /// As the decoder progresses it will make method calls to the event handler
238         /// instance (which can be accessed with the GetHandler() method) to indicate
239         /// the start of the DARC header, global header, new regional structures and
240         /// local card structures.
241         ///
242         /// If an error occurs during the parse, because the data is corrupt, then
243         /// the OnError method is called indicating what the problem was.
244         /// Decoding will stop at this point unless the fExitOnError flag is set
245         /// to false. There is an optional flag fTryRecover which can enable logic
246         /// which will attempt to recover from corruption of the data structures
247         /// in the DDL payload, if they are found to be inconsistent (assumed corrupt).
248         /// The recovery procedure simply involves trying to find in the DDL stream
249         /// the location of the expected end of header/structure marker/key or the
250         /// next expected key, and then continue decoding from there. This kind of
251         /// recovery logic is (and should be) turned off by default and only
252         /// enabled when trying to recover corrupted data.
253         ///
254         /// \param buffer  This is the pointer to the start of the memory buffer
255         ///     containing the DDL payload. Remember that this must be the start of
256         ///     the payload and not the DDL stream. That is, this pointer should be
257         ///     equal to: DDL start pointer + 8 * sizeof(UInt_t).
258         /// \param bufferSize  This is the pointer to the first byte just past the
259         ///     end of the block structure.
260         /// \param scalarEvent  Set to true if this DDL contains a scalar event
261         ///     and false if it is a normal physics event. If the fAutoDetectScalars
262         ///     flag is true then we ignore this parameter.
263         /// \return Returns false if there was any problem with decoding the data,
264         ///     and true otherwise. Note: the data may have been partially decoded
265         ///     even if false was returned, which would be indicated by at least one
266         ///     call to the event handler's OnLocalStruct or OnNewRegionalStruct methods.
267         
268         assert( buffer != NULL );
269         
270         fHadError = false;
271         
272         // We are basically implementing something like a recursive decent parser.
273         // So start by marking the start of buffer position and end of buffer.
274         const UChar_t* start = reinterpret_cast<const UChar_t*>(buffer);
275         const UChar_t* end = start + bufferSize;
276         
277         fHandler.OnNewBuffer(buffer, bufferSize);
278         DecodeBuffer(start, end, scalarEvent);
279         fHandler.OnEndOfBuffer(buffer, bufferSize);
280         return not fHadError;
281 }
282
283
284 template <class EventHandler>
285 void AliMUONTriggerDDLDecoder<EventHandler>::DecodeBuffer(
286                 const UChar_t* start, const UChar_t* end, bool scalarEvent
287         )
288 {
289         /// This method does the work to decode the buffer's payload data. It
290         /// unpacks the DARC header, the global header, then calls the
291         /// DecodeRegionalStructs() method to decode the regional structures.
292         /// For the DARC and global headers the methods OnDarcHeader and
293         /// OnGlobalHeader of the event handler object are called respectively.
294         /// \param start  This is the pointer to the start of the buffer to decode.
295         /// \param end  This is the pointer to the first byte just past the
296         ///             end of the buffer.
297         /// \param scalarEvent  Set to true if this DDL contains a scalar event
298         ///     and false if it is a normal physics event.
299         ///
300         /// fHadError is set to true if there were any errors decoding the buffer
301         /// and the OnError method of the callback event handler is called for
302         /// each error.
303         
304         const UChar_t* current = start;
305         
306         // Mark the DARC header, but check that we do not overrun the buffer.
307         const UInt_t* darcHeader = reinterpret_cast<const UInt_t*>(current);
308         current += sizeof(UInt_t);
309         if (current > end or current < start)
310         {
311                 // Indicate we had an error and stop the decoding because we
312                 // hit the end of the buffer already.
313                 fHandler.OnError(EventHandler::kNoDarcHeader, darcHeader);
314                 fHadError = true;
315                 return;
316         }
317         
318         // Check if we need to figure out if this is a scalar event.
319         // If we do, then we do this by checking the event type in the DARC header
320         // and double checking this by checking if the fgkEndOfDarc key is in the
321         // expected location for a scalar event DDL payload.
322         if (fAutoDetectScalars)
323         {
324                 const UInt_t* expectedEndOfDarc = reinterpret_cast<const UInt_t*>(
325                                 current + sizeof(AliMUONDarcScalarsStruct)
326                         );
327                 
328                 // First make sure not to read past the end of buffer. Then check
329                 // the value of the event type in the DARC header.
330                 // Physics events are indicated by the two trigger bits of the
331                 // DARC header set to 01b. Everything else is a software trigger
332                 // of some sort.
333                 if (reinterpret_cast<const UChar_t*>(expectedEndOfDarc+1) <= end and
334                     reinterpret_cast<const UChar_t*>(expectedEndOfDarc+1) > start and
335                     EventHandler::GetDarcEventType(*darcHeader) != 0x1
336                     and *expectedEndOfDarc == fgkEndOfDarc
337                    )
338                 {
339                         scalarEvent = true;
340                 }
341                 else
342                 {
343                         scalarEvent = false;
344                 }
345         }
346         
347         // Detect how many regional blocks we expect. If we have no idea then
348         // just use what the maximum setting is.
349         UInt_t darkType = EventHandler::GetDarcType(*darcHeader);
350         if (darkType == fgkDarcVadorhType)
351         {
352                 fNoRegionals = 1;
353         }
354         else if (darkType == fgkDarcDefaultType)
355         {
356                 fNoRegionals = 8;
357         }
358         else
359         {
360                 fNoRegionals = fMaxRegionals;
361         }
362         
363         // Check if the DARC header indicates we expect more regionals than we
364         // are allowed to decode according to our max regional structures count.
365         // If we do then this is an error and we should indicate it and exit
366         // if so requested by the user. Also we can fix the number of regionals
367         // to expect if we are trying to recover from errors.
368         if (fNoRegionals > fMaxRegionals)
369         {
370                 fHandler.OnError(EventHandler::kTooManyRegionals, darcHeader);
371                 fHadError = true;
372                 if (fExitOnError) return;
373                 if (fTryRecover)
374                 {
375                         fNoRegionals = fMaxRegionals;
376                 }
377         }
378         
379         // Check that the DARC header indicates correctly if we are a scalar event or not.
380         bool darcShowsScalar = (EventHandler::GetDarcEventType(*darcHeader) != 0x1);
381         if (darcShowsScalar != scalarEvent)
382         {
383                 // Indicate we had an error and stop the decoding if so requested
384                 // by the user.
385                 fHandler.OnError(EventHandler::kWrongEventType, darcHeader);
386                 fHadError = true;
387                 if (fExitOnError) return;
388         }
389         
390         // Decode the DARC scalars if this is a scalar event.
391         const AliMUONDarcScalarsStruct* darcScalars = NULL;
392         if (scalarEvent)
393         {
394                 darcScalars = reinterpret_cast<const AliMUONDarcScalarsStruct*>(current);
395                 current += sizeof(AliMUONDarcScalarsStruct);
396                 if (current > end or current < start)
397                 {
398                         // If we overflowed the pointer and already had an error then
399                         // we are clearly lost so just stop decoding before we segfault.
400                         if (current < start and fHadError) return;
401                         
402                         // Indicate we had an error and stop the decoding because we
403                         // hit the end of the buffer already.
404                         fHandler.OnError(EventHandler::kNoDarcScalars, darcScalars);
405                         fHadError = true;
406                         return;
407                 }
408         }
409         
410         // Now check that the end of DARC header marker is OK.
411         const UInt_t* endOfDarc = reinterpret_cast<const UInt_t*>(current);
412         current += sizeof(UInt_t);
413         if (current > end or current < start)
414         {
415                 // If we overflowed the pointer and already had an error then
416                 // we are clearly lost so just stop decoding before we segfault.
417                 if (current < start and fHadError) return;
418                 
419                 // Indicate we had an error and stop the decoding because we
420                 // hit the end of the buffer already.
421                 fHandler.OnError(EventHandler::kNoEndOfDarc, endOfDarc);
422                 fHadError = true;
423                 return;
424         }
425         if (*endOfDarc != fgkEndOfDarc)
426         {
427                 // Indicate we had an error and stop the decoding if so requested
428                 // by the user.
429                 fHandler.OnError(EventHandler::kBadEndOfDarc, endOfDarc);
430                 fHadError = true;
431                 if (fExitOnError) return;
432                 
433                 // If the user requested for us to try and recover from structure
434                 // errors then we need to try locate the key in the data stream
435                 // and continue decoding from there.
436                 if (fTryRecover)
437                 {
438                         const UChar_t* keypos = FindKey(fgkEndOfDarc,
439                                         reinterpret_cast<const UChar_t*>(darcHeader),
440                                         end
441                                 );
442                         if (keypos != NULL)
443                         {
444                                 // remember to continue decoding just past the key.
445                                 current = keypos + sizeof(UInt_t);
446                         }
447                 }
448         }
449         
450         fHandler.OnDarcHeader(*darcHeader, darcScalars, current);
451         
452         // Next, we mark the Global header and check that we do not overrun the buffer.
453         const AliMUONGlobalHeaderStruct* globalHeader =
454                 reinterpret_cast<const AliMUONGlobalHeaderStruct*>(current);
455         current += sizeof(AliMUONGlobalHeaderStruct);
456         if (current > end or current < start)
457         {
458                 // If we overflowed the pointer and already had an error then
459                 // we are clearly lost so just stop decoding before we segfault.
460                 if (current < start and fHadError) return;
461                 
462                 // Indicate we had an error and stop the decoding because we
463                 // hit the end of the buffer already.
464                 fHandler.OnError(EventHandler::kNoGlobalHeader, globalHeader);
465                 fHadError = true;
466                 return;
467         }
468         
469         // Decode the global scalars if this is a scalar event.
470         const AliMUONGlobalScalarsStruct* globalScalars = NULL;
471         if (scalarEvent)
472         {
473                 globalScalars = reinterpret_cast<const AliMUONGlobalScalarsStruct*>(current);
474                 current += sizeof(AliMUONGlobalScalarsStruct);
475                 if (current > end or current < start)
476                 {
477                         // If we overflowed the pointer and already had an error then
478                         // we are clearly lost so just stop decoding before we segfault.
479                         if (current < start and fHadError) return;
480                         
481                         // Indicate we had an error and stop the decoding because we
482                         // hit the end of the buffer already.
483                         fHandler.OnError(EventHandler::kNoGlobalScalars, globalScalars);
484                         fHadError = true;
485                         return;
486                 }
487         }
488         
489         // Now check that the end of global header marker is OK.
490         const UInt_t* endOfGlobal = reinterpret_cast<const UInt_t*>(current);
491         current += sizeof(UInt_t);
492         if (current > end or current < start)
493         {
494                 // If we overflowed the pointer and already had an error then
495                 // we are clearly lost so just stop decoding before we segfault.
496                 if (current < start and fHadError) return;
497                 
498                 // Indicate we had an error and stop the decoding because we
499                 // hit the end of the buffer already.
500                 fHandler.OnError(EventHandler::kNoEndOfGlobal, endOfGlobal);
501                 fHadError = true;
502                 return;
503         }
504         if (*endOfGlobal != fgkEndOfGlobal)
505         {
506                 // Indicate we had an error and stop the decoding if so requested
507                 // by the user.
508                 fHandler.OnError(EventHandler::kBadEndOfGlobal, endOfGlobal);
509                 fHadError = true;
510                 if (fExitOnError) return;
511                 
512                 // If the user requested for us to try and recover from structure
513                 // errors then we need to try locate the key in the data stream
514                 // and continue decoding from there.
515                 if (fTryRecover)
516                 {
517                         const UChar_t* keypos = FindKey(fgkEndOfGlobal,
518                                         reinterpret_cast<const UChar_t*>(globalHeader),
519                                         end
520                                 );
521                         if (keypos != NULL)
522                         {
523                                 // remember to continue decoding just past the key.
524                                 current = keypos + sizeof(UInt_t);
525                         }
526                 }
527         }
528         
529         fHandler.OnGlobalHeader(globalHeader, globalScalars, current);
530         
531         DecodeRegionalStructs(current, end, scalarEvent);
532 }
533
534
535 template <class EventHandler>
536 void AliMUONTriggerDDLDecoder<EventHandler>::DecodeRegionalStructs(
537                 const UChar_t* start, const UChar_t* end, bool scalarEvent
538         )
539 {
540         /// This method decodes the regional structures in the DDL data.
541         /// For each regional header found, the OnNewRegionalStruct method of
542         /// the event handler is called, to signal the start of each
543         /// new regional structure. The DecodeLocalStructs() method is then
544         /// called to decode the local trigger structures. Finally, a symmetrical
545         /// call to OnEndOfRegionalStruct of the event handler is called to
546         /// signal that the regional structure has been decoded.
547         /// \param start  This is the pointer to the start of the buffer.
548         /// \param end  This is the pointer to the first byte just past the
549         ///             end of the buffer.
550         /// \param scalarEvent  Set to true if this DDL contains a scalar event
551         ///     and false if it is a normal physics event.
552         ///
553         /// fHadError is set to true if there were any errors decoding the buffer
554         /// and the OnError method of the callback event handler is called for
555         /// each error.
556         
557         const UChar_t* current = start;
558         
559         for (UInt_t iReg = 0; iReg < fNoRegionals; iReg++)
560         {
561                 const AliMUONRegionalHeaderStruct* regionalHeader =
562                         reinterpret_cast<const AliMUONRegionalHeaderStruct*>(current);
563                 current += sizeof(AliMUONRegionalHeaderStruct);
564                 
565                 if (current > end or current < start)
566                 {
567                         // If we overflowed the pointer and already had an error then
568                         // we are clearly lost so just stop decoding before we segfault.
569                         if (current < start and fHadError) return;
570                         
571                         // So we only got part of a regional header, nothing to do but
572                         // report the error and exit.
573                         fHandler.OnError(EventHandler::kNoRegionalHeader, regionalHeader);
574                         fHadError = true;
575                         return;
576                 }
577                 
578                 // Skip empty regional board (not connected or with error reading).
579                 if (regionalHeader->fDarcWord == fgkErrorWord)
580                 {
581                         //current += sizeof(AliMUONRegionalHeaderStruct);  // already done above
582                         if (scalarEvent)
583                                 current += sizeof(AliMUONRegionalScalarsStruct);
584                         current += sizeof(UInt_t); // skip the end of regional structure key.
585                         
586                         // now also skip the local structure part:
587                         current += fMaxLocals * sizeof(AliMUONLocalInfoStruct);
588                         if (scalarEvent)
589                                 current += fMaxLocals * sizeof(AliMUONLocalScalarsStruct);
590                         current += fMaxLocals * sizeof(UInt_t); // skip all the end of local structure keys.
591                         
592                         continue;
593                 }
594                 
595                 // Decode the regional scalar words if this is a scalar event.
596                 const AliMUONRegionalScalarsStruct* regionalScalars = NULL;
597                 if (scalarEvent)
598                 {
599                         regionalScalars = reinterpret_cast<const AliMUONRegionalScalarsStruct*>(current);
600                         current += sizeof(AliMUONRegionalScalarsStruct);
601                         if (current > end or current < start)
602                         {
603                                 // If we overflowed the pointer and already had an error then
604                                 // we are clearly lost so just stop decoding before we segfault.
605                                 if (current < start and fHadError) return;
606                                 
607                                 // Indicate we had an error and stop the decoding because we
608                                 // hit the end of the buffer already.
609                                 fHandler.OnError(EventHandler::kNoRegionalScalars, regionalScalars);
610                                 fHadError = true;
611                                 return;
612                         }
613                 }
614                 
615                 // Now check that the end of regional header marker is OK.
616                 const UInt_t* endOfRegional = reinterpret_cast<const UInt_t*>(current);
617                 current += sizeof(UInt_t);
618                 if (current > end or current < start)
619                 {
620                         // If we overflowed the pointer and already had an error then
621                         // we are clearly lost so just stop decoding before we segfault.
622                         if (current < start and fHadError) return;
623                         
624                         // Indicate we had an error and stop the decoding because we
625                         // hit the end of the buffer already.
626                         fHandler.OnError(EventHandler::kNoEndOfRegional, endOfRegional);
627                         fHadError = true;
628                         return;
629                 }
630                 if (*endOfRegional != fgkEndOfReg)
631                 {
632                         // Indicate we had an error and stop the decoding if so requested
633                         // by the user.
634                         fHandler.OnError(EventHandler::kBadEndOfRegional, endOfRegional);
635                         fHadError = true;
636                         if (fExitOnError) return;
637                         
638                         // If the user requested for us to try and recover from structure
639                         // errors then we need to try locate the key in the data stream
640                         // and continue decoding from there.
641                         if (fTryRecover)
642                         {
643                                 const UChar_t* keypos = FindKey(fgkEndOfReg,
644                                                 reinterpret_cast<const UChar_t*>(regionalHeader),
645                                                 end
646                                         );
647                                 
648                                 // If the fgkEndOfReg key was found exactly one regional
649                                 // structure later then we should not adjust the current
650                                 // decoding position because it is more likely that the
651                                 // end of regional structure key was just corrupt rather
652                                 // than offset.
653                                 // If we could not find another good key then just continue.
654                                 size_t sizeOfRegional = sizeof(AliMUONRegionalHeaderStruct) + sizeof(UInt_t)
655                                         + fMaxLocals * (sizeof(AliMUONLocalInfoStruct) + sizeof(UInt_t));
656                                 if (scalarEvent)
657                                 {
658                                         sizeOfRegional += sizeof(AliMUONRegionalScalarsStruct)
659                                                 + fMaxLocals * sizeof(AliMUONLocalScalarsStruct);
660                                 }
661                                 
662                                 if (keypos != NULL and keypos != current + sizeOfRegional)
663                                 {
664                                         current = keypos + sizeof(UInt_t);
665                                 }
666                         }
667                 }
668                 
669                 // Tell the handler that we have a new regional block and decode it.
670                 // When done, tell the handler again.
671                 // We call both versions of OnNewRegionalStruct so that user event
672                 // handlers can implement the one they prefer to use.
673                 const UChar_t* startOfLocals = current;
674                 fHandler.OnNewRegionalStruct(regionalHeader, regionalScalars, startOfLocals);
675                 fHandler.OnNewRegionalStructV2(iReg, regionalHeader, regionalScalars, startOfLocals);
676                 current = DecodeLocalStructs(current, end, scalarEvent);
677                 fHandler.OnEndOfRegionalStruct(regionalHeader, regionalScalars, startOfLocals);
678                 fHandler.OnEndOfRegionalStructV2(iReg, regionalHeader, regionalScalars, startOfLocals);
679         }
680         
681         // Now just check that there is no extra rubbish at the end of the DDL.
682         if (current != end)
683         {
684                 fHandler.OnError(EventHandler::kBufferTooBig, current);
685                 fHadError = true;
686         }
687 }
688
689
690 template <class EventHandler>
691 const UChar_t* AliMUONTriggerDDLDecoder<EventHandler>::DecodeLocalStructs(
692                 const UChar_t* start, const UChar_t* end, bool scalarEvent
693         )
694 {
695         /// This method decodes the local structures in the DDL data for a
696         /// single regional structure. For each local trigger structure found,
697         /// the OnLocalStruct method of the event handler is called.
698         /// \param start  This is the pointer to the start of the regional structure
699         ///               payload (The pointer just past the regional header key).
700         /// \param end  This is the pointer to the first byte just past the
701         ///             end of the buffer.
702         /// \param scalarEvent  Set to true if this DDL contains a scalar event
703         ///     and false if it is a normal physics event.
704         /// \returns  The position in the buffer where this method stopped decoding.
705         ///
706         /// fHadError is set to true if there were any errors decoding the buffer
707         /// and the OnError method of the callback event handler is called for
708         /// each error.
709         
710         const UChar_t* current = start;
711         
712         for (UInt_t iLocal = 0; iLocal < fMaxLocals; iLocal++)
713         {
714                 const AliMUONLocalInfoStruct* localStruct =
715                         reinterpret_cast<const AliMUONLocalInfoStruct*>(current);
716                 current += sizeof(AliMUONLocalInfoStruct);
717                 
718                 if (current > end or current < start)
719                 {
720                         // If we overflowed the pointer and already had an error then
721                         // we are clearly lost so just stop decoding before we segfault.
722                         if (current < start and fHadError) return end;
723                         
724                         // So we only got part of a local structure, nothing to do but
725                         // report the error and exit.
726                         fHandler.OnError(EventHandler::kNoLocalStruct, localStruct);
727                         fHadError = true;
728                         return end;
729                 }
730                 
731                 // Skip empty local board if card not notified.
732                 if (localStruct->fX2X1 == fgkDisableWord and
733                     localStruct->fX4X3 == fgkDisableWord and
734                     localStruct->fY2Y1 == fgkDisableWord and
735                     localStruct->fY4Y3 == fgkDisableWord and
736                     localStruct->fTriggerBits == fgkDisableWord
737                    )
738                 {
739                         //current += sizeof(AliMUONLocalInfoStruct); // already done above
740                         if (scalarEvent)
741                                 current += sizeof(AliMUONLocalScalarsStruct);
742                         current += sizeof(UInt_t); // skip the end of local structure key.
743                         continue;
744                 }
745                 
746                 // Decode the regional scalar words if this is a scalar event.
747                 const AliMUONLocalScalarsStruct* localScalars = NULL;
748                 if (scalarEvent)
749                 {
750                         localScalars = reinterpret_cast<const AliMUONLocalScalarsStruct*>(current);
751                         current += sizeof(AliMUONLocalScalarsStruct);
752                         if (current > end or current < start)
753                         {
754                                 // If we overflowed the pointer and already had an error then
755                                 // we are clearly lost so just stop decoding before we segfault.
756                                 if (current < start and fHadError) return end;
757                                 
758                                 // Indicate we had an error and stop the decoding because we
759                                 // hit the end of the buffer already.
760                                 fHandler.OnError(EventHandler::kNoLocalScalars, localScalars);
761                                 fHadError = true;
762                                 return end;
763                         }
764                 }
765                 
766                 // Now check that the end of regional header marker is OK.
767                 const UInt_t* endOfLocal = reinterpret_cast<const UInt_t*>(current);
768                 current += sizeof(UInt_t);
769                 if (current > end or current < start)
770                 {
771                         // If we overflowed the pointer and already had an error then
772                         // we are clearly lost so just stop decoding before we segfault.
773                         if (current < start and fHadError) return end;
774                         
775                         // Indicate we had an error and stop the decoding because we
776                         // hit the end of the buffer already. We can however signal that
777                         // we got a local structure, because the buffer contains enough
778                         // data to potencially contain the real data of the structure.
779                         fHandler.OnError(EventHandler::kNoEndOfLocal, endOfLocal);
780                         if (not fExitOnError)
781                         {
782                                 fHandler.OnLocalStruct(localStruct, localScalars);
783                         }
784                         fHadError = true;
785                         return end;
786                 }
787                 if (*endOfLocal != fgkEndOfLocal)
788                 {
789                         // Indicate we had an error and stop the decoding if so requested
790                         // by the user.
791                         fHandler.OnError(EventHandler::kBadEndOfLocal, endOfLocal);
792                         fHadError = true;
793                         if (fExitOnError) return current;
794                         
795                         // If the user requested for us to try and recover from structure
796                         // errors then we need to try locate the key in the data stream
797                         // and continue decoding from there.
798                         if (fTryRecover)
799                         {
800                                 const UChar_t* searchPos = reinterpret_cast<const UChar_t*>(localStruct);
801                                 const UChar_t* firstLocalKey = FindKey(fgkEndOfLocal, searchPos, end);
802                                 const UChar_t* firstRegionalKey = FindKey(fgkEndOfReg, searchPos, end);
803                                 
804                                 // If a regional key was found first, then give up on
805                                 // anymore local structures from this regional block and
806                                 // continue decoding from the next regional block.
807                                 // Also if the fgkEndOfLocal key was found exactly one
808                                 // local structure later then we should not adjust the
809                                 // current decoding position because it is more likely that
810                                 // the end of local structure key was just corrupt rather
811                                 // than offset.
812                                 if (firstLocalKey != NULL and firstRegionalKey != NULL)
813                                 {
814                                         if (firstLocalKey < firstRegionalKey)
815                                         {
816                                                 size_t sizeOflocalStruct = sizeof(AliMUONLocalInfoStruct) + sizeof(UInt_t);
817                                                 if (scalarEvent)
818                                                         sizeOflocalStruct += sizeof(AliMUONLocalScalarsStruct);
819                                                 
820                                                 if (firstLocalKey != current + sizeOflocalStruct)
821                                                         current = firstLocalKey + sizeof(UInt_t);
822                                         }
823                                         else
824                                         {
825                                                 // Adjust back to the start of the regional header.
826                                                 current = firstRegionalKey - sizeof(AliMUONRegionalHeaderStruct);
827                                                 if (scalarEvent)
828                                                         current -= sizeof(AliMUONRegionalScalarsStruct);
829                                                 break;
830                                         }
831                                 }
832                                 
833                                 // If we could not find another good key then just continue.
834                         }
835                 }
836                 
837                 // Call both handlers for local structures so that the user decoder event
838                 // handler class can implement the one it prefers to use.
839                 fHandler.OnLocalStruct(localStruct, localScalars);
840                 fHandler.OnLocalStructV2(iLocal, localStruct, localScalars);
841         }
842         
843         return current;
844 }
845
846
847 template <class EventHandler>
848 const UChar_t* AliMUONTriggerDDLDecoder<EventHandler>::FindKey(
849                 UInt_t key, const UChar_t* start, const UChar_t* end
850         )
851 {
852         /// Searches for the first occurrence of the key value in the buffer
853         /// marked by 'start' and 'end'. 'start' should point to the start of
854         /// the buffer and 'end' should point to 'start + bufferSize'.
855         /// \param key  The 32 bit word to look for.
856         /// \param start  The start location to begin the search at.
857         /// \param end  The pointer to the first byte just past end of the
858         ///             buffer to check.
859         /// \returns  The location of the first occurance of key in the buffer,
860         ///           otherwise NULL is returned if nothing was found.
861  
862         if (end + sizeof(UInt_t) < start) return NULL;  // check for pointer overflow.
863         const UChar_t* current = start;
864         while (current + sizeof(UInt_t) <= end)
865         {
866                 UInt_t data = * reinterpret_cast<const UInt_t*>(current);
867                 if (data == key) return current;
868                 current++;
869         }
870         return NULL;
871 }
872
873 #endif // ALIMUONTRIGGERDDLDECODER_H