Update in HP decoders:
[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  = 0x010CDEAD;
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)
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                     EventHandler::GetDarcEventType(*darcHeader) != 0x1
335                     and *expectedEndOfDarc == fgkEndOfDarc
336                    )
337                 {
338                         scalarEvent = true;
339                 }
340                 else
341                 {
342                         scalarEvent = false;
343                 }
344         }
345         
346         // Detect how many regional blocks we expect. If we have no idea then
347         // just use what the maximum setting is.
348         switch (EventHandler::GetDarcType(*darcHeader))
349         {
350         case fgkDarcVadorhType:  fNoRegionals = 1; break;
351         case fgkDarcDefaultType: fNoRegionals = 8; break;
352         default: fNoRegionals = fMaxRegionals; break;
353         }
354         
355         // Check if the DARC header indicates we expect more regionals than we
356         // are allowed to decode according to our max regional structures count.
357         // If we do then this is an error and we should indicate it and exit
358         // if so requested by the user. Also we can fix the number of regionals
359         // to expect if we are trying to recover from errors.
360         if (fNoRegionals > fMaxRegionals)
361         {
362                 fHandler.OnError(EventHandler::kTooManyRegionals, darcHeader);
363                 fHadError = true;
364                 if (fExitOnError) return;
365                 if (fTryRecover)
366                 {
367                         fNoRegionals = fMaxRegionals;
368                 }
369         }
370         
371         // Check that the DARC header indicates correctly if we are a scalar event or not.
372         bool darcShowsScalar = (EventHandler::GetDarcEventType(*darcHeader) != 0x1);
373         if (darcShowsScalar != scalarEvent)
374         {
375                 // Indicate we had an error and stop the decoding if so requested
376                 // by the user.
377                 fHandler.OnError(EventHandler::kWrongEventType, darcHeader);
378                 fHadError = true;
379                 if (fExitOnError) return;
380         }
381         
382         // Decode the DARC scalars if this is a scalar event.
383         const AliMUONDarcScalarsStruct* darcScalars = NULL;
384         if (scalarEvent)
385         {
386                 darcScalars = reinterpret_cast<const AliMUONDarcScalarsStruct*>(current);
387                 current += sizeof(AliMUONDarcScalarsStruct);
388                 if (current > end)
389                 {
390                         // Indicate we had an error and stop the decoding because we
391                         // hit the end of the buffer already.
392                         fHandler.OnError(EventHandler::kNoDarcScalars, darcScalars);
393                         fHadError = true;
394                         return;
395                 }
396         }
397         
398         // Now check that the end of DARC header marker is OK.
399         const UInt_t* endOfDarc = reinterpret_cast<const UInt_t*>(current);
400         current += sizeof(UInt_t);
401         if (current > end)
402         {
403                 // Indicate we had an error and stop the decoding because we
404                 // hit the end of the buffer already.
405                 fHandler.OnError(EventHandler::kNoEndOfDarc, endOfDarc);
406                 fHadError = true;
407                 return;
408         }
409         if (*endOfDarc != fgkEndOfDarc)
410         {
411                 // Indicate we had an error and stop the decoding if so requested
412                 // by the user.
413                 fHandler.OnError(EventHandler::kBadEndOfDarc, endOfDarc);
414                 fHadError = true;
415                 if (fExitOnError) return;
416                 
417                 // If the user requested for us to try and recover from structure
418                 // errors then we need to try locate the key in the data stream
419                 // and continue decoding from there.
420                 if (fTryRecover)
421                 {
422                         const UChar_t* keypos = FindKey(fgkEndOfDarc,
423                                         reinterpret_cast<const UChar_t*>(darcHeader),
424                                         end
425                                 );
426                         if (keypos != NULL)
427                         {
428                                 // remember to continue decoding just past the key.
429                                 current = keypos + sizeof(UInt_t);
430                         }
431                 }
432         }
433         
434         fHandler.OnDarcHeader(*darcHeader, darcScalars, current);
435         
436         // Next, we mark the Global header and check that we do not overrun the buffer.
437         const AliMUONGlobalHeaderStruct* globalHeader =
438                 reinterpret_cast<const AliMUONGlobalHeaderStruct*>(current);
439         current += sizeof(AliMUONGlobalHeaderStruct);
440         if (current > end)
441         {
442                 // Indicate we had an error and stop the decoding because we
443                 // hit the end of the buffer already.
444                 fHandler.OnError(EventHandler::kNoGlobalHeader, globalHeader);
445                 fHadError = true;
446                 return;
447         }
448         
449         // Decode the global scalars if this is a scalar event.
450         const AliMUONGlobalScalarsStruct* globalScalars = NULL;
451         if (scalarEvent)
452         {
453                 globalScalars = reinterpret_cast<const AliMUONGlobalScalarsStruct*>(current);
454                 current += sizeof(AliMUONGlobalScalarsStruct);
455                 if (current > end)
456                 {
457                         // Indicate we had an error and stop the decoding because we
458                         // hit the end of the buffer already.
459                         fHandler.OnError(EventHandler::kNoGlobalScalars, globalScalars);
460                         fHadError = true;
461                         return;
462                 }
463         }
464         
465         // Now check that the end of global header marker is OK.
466         const UInt_t* endOfGlobal = reinterpret_cast<const UInt_t*>(current);
467         current += sizeof(UInt_t);
468         if (current > end)
469         {
470                 // Indicate we had an error and stop the decoding because we
471                 // hit the end of the buffer already.
472                 fHandler.OnError(EventHandler::kNoEndOfGlobal, endOfGlobal);
473                 fHadError = true;
474                 return;
475         }
476         if (*endOfGlobal != fgkEndOfGlobal)
477         {
478                 // Indicate we had an error and stop the decoding if so requested
479                 // by the user.
480                 fHandler.OnError(EventHandler::kBadEndOfGlobal, endOfGlobal);
481                 fHadError = true;
482                 if (fExitOnError) return;
483                 
484                 // If the user requested for us to try and recover from structure
485                 // errors then we need to try locate the key in the data stream
486                 // and continue decoding from there.
487                 if (fTryRecover)
488                 {
489                         const UChar_t* keypos = FindKey(fgkEndOfGlobal,
490                                         reinterpret_cast<const UChar_t*>(globalHeader),
491                                         end
492                                 );
493                         if (keypos != NULL)
494                         {
495                                 // remember to continue decoding just past the key.
496                                 current = keypos + sizeof(UInt_t);
497                         }
498                 }
499         }
500         
501         fHandler.OnGlobalHeader(globalHeader, globalScalars, current);
502         
503         DecodeRegionalStructs(current, end, scalarEvent);
504 }
505
506
507 template <class EventHandler>
508 void AliMUONTriggerDDLDecoder<EventHandler>::DecodeRegionalStructs(
509                 const UChar_t* start, const UChar_t* end, bool scalarEvent
510         )
511 {
512         /// This method decodes the regional structures in the DDL data.
513         /// For each regional header found, the OnNewRegionalStruct method of
514         /// the event handler is called, to signal the start of each
515         /// new regional structure. The DecodeLocalStructs() method is then
516         /// called to decode the local trigger structures. Finally, a symmetrical
517         /// call to OnEndOfRegionalStruct of the event handler is called to
518         /// signal that the regional structure has been decoded.
519         /// \param start  This is the pointer to the start of the buffer.
520         /// \param end  This is the pointer to the first byte just past the
521         ///             end of the buffer.
522         /// \param scalarEvent  Set to true if this DDL contains a scalar event
523         ///     and false if it is a normal physics event.
524         ///
525         /// fHadError is set to true if there were any errors decoding the buffer
526         /// and the OnError method of the callback event handler is called for
527         /// each error.
528         
529         const UChar_t* current = start;
530         
531         for (UInt_t iReg = 0; iReg < fNoRegionals; iReg++)
532         {
533                 const AliMUONRegionalHeaderStruct* regionalHeader =
534                         reinterpret_cast<const AliMUONRegionalHeaderStruct*>(current);
535                 current += sizeof(AliMUONRegionalHeaderStruct);
536                 
537                 if (current > end)
538                 {
539                         // So we only got part of a regional header, nothing to do but
540                         // report the error and exit.
541                         fHandler.OnError(EventHandler::kNoRegionalHeader, regionalHeader);
542                         fHadError = true;
543                         return;
544                 }
545                 
546                 // Skip empty regional board (not connected or with error reading).
547                 if (regionalHeader->fDarcWord == fgkErrorWord)
548                 {
549                         //current += sizeof(AliMUONRegionalHeaderStruct);  // already done above
550                         if (scalarEvent)
551                                 current += sizeof(AliMUONRegionalScalarsStruct);
552                         current += sizeof(UInt_t); // skip the end of regional structure key.
553                         
554                         // now also skip the local structure part:
555                         current += fMaxLocals * sizeof(AliMUONLocalInfoStruct);
556                         if (scalarEvent)
557                                 current += fMaxLocals * sizeof(AliMUONLocalScalarsStruct);
558                         current += fMaxLocals * sizeof(UInt_t); // skip all the end of local structure keys.
559                         
560                         continue;
561                 }
562                 
563                 // Decode the regional scalar words if this is a scalar event.
564                 const AliMUONRegionalScalarsStruct* regionalScalars = NULL;
565                 if (scalarEvent)
566                 {
567                         regionalScalars = reinterpret_cast<const AliMUONRegionalScalarsStruct*>(current);
568                         current += sizeof(AliMUONRegionalScalarsStruct);
569                         if (current > end)
570                         {
571                                 // Indicate we had an error and stop the decoding because we
572                                 // hit the end of the buffer already.
573                                 fHandler.OnError(EventHandler::kNoRegionalScalars, regionalScalars);
574                                 fHadError = true;
575                                 return;
576                         }
577                 }
578                 
579                 // Now check that the end of regional header marker is OK.
580                 const UInt_t* endOfRegional = reinterpret_cast<const UInt_t*>(current);
581                 current += sizeof(UInt_t);
582                 if (current > end)
583                 {
584                         // Indicate we had an error and stop the decoding because we
585                         // hit the end of the buffer already.
586                         fHandler.OnError(EventHandler::kNoEndOfRegional, endOfRegional);
587                         fHadError = true;
588                         return;
589                 }
590                 if (*endOfRegional != fgkEndOfReg)
591                 {
592                         // Indicate we had an error and stop the decoding if so requested
593                         // by the user.
594                         fHandler.OnError(EventHandler::kBadEndOfRegional, endOfRegional);
595                         fHadError = true;
596                         if (fExitOnError) return;
597                         
598                         // If the user requested for us to try and recover from structure
599                         // errors then we need to try locate the key in the data stream
600                         // and continue decoding from there.
601                         if (fTryRecover)
602                         {
603                                 const UChar_t* keypos = FindKey(fgkEndOfReg,
604                                                 reinterpret_cast<const UChar_t*>(regionalHeader),
605                                                 end
606                                         );
607                                 
608                                 // If the fgkEndOfReg key was found exactly one regional
609                                 // structure later then we should not adjust the current
610                                 // decoding position because it is more likely that the
611                                 // end of regional structure key was just corrupt rather
612                                 // than offset.
613                                 // If we could not find another good key then just continue.
614                                 size_t sizeOfRegional = sizeof(AliMUONRegionalHeaderStruct) + sizeof(UInt_t)
615                                         + fMaxLocals * (sizeof(AliMUONLocalInfoStruct) + sizeof(UInt_t));
616                                 if (scalarEvent)
617                                 {
618                                         sizeOfRegional += sizeof(AliMUONRegionalScalarsStruct)
619                                                 + fMaxLocals * sizeof(AliMUONLocalScalarsStruct);
620                                 }
621                                 
622                                 if (keypos != NULL and keypos != current + sizeOfRegional)
623                                 {
624                                         current = keypos + sizeof(UInt_t);
625                                 }
626                         }
627                 }
628                 
629                 // Tell the handler that we have a new regional block and decode it.
630                 // When done, tell the handler again.
631                 const UChar_t* startOfLocals = current;
632                 fHandler.OnNewRegionalStruct(regionalHeader, regionalScalars, startOfLocals);
633                 current = DecodeLocalStructs(current, end, scalarEvent);
634                 fHandler.OnEndOfRegionalStruct(regionalHeader, regionalScalars, startOfLocals);
635         }
636         
637         // Now just check that there is no extra rubbish at the end of the DDL.
638         if (current != end)
639         {
640                 fHandler.OnError(EventHandler::kBufferTooBig, current);
641                 fHadError = true;
642         }
643 }
644
645
646 template <class EventHandler>
647 const UChar_t* AliMUONTriggerDDLDecoder<EventHandler>::DecodeLocalStructs(
648                 const UChar_t* start, const UChar_t* end, bool scalarEvent
649         )
650 {
651         /// This method decodes the local structures in the DDL data for a
652         /// single regional structure. For each local trigger structure found,
653         /// the OnLocalStruct method of the event handler is called.
654         /// \param start  This is the pointer to the start of the regional structure
655         ///               payload (The pointer just past the regional header key).
656         /// \param end  This is the pointer to the first byte just past the
657         ///             end of the buffer.
658         /// \param scalarEvent  Set to true if this DDL contains a scalar event
659         ///     and false if it is a normal physics event.
660         /// \returns  The position in the buffer where this method stopped decoding.
661         ///
662         /// fHadError is set to true if there were any errors decoding the buffer
663         /// and the OnError method of the callback event handler is called for
664         /// each error.
665         
666         const UChar_t* current = start;
667         
668         for (UInt_t iLocal = 0; iLocal < fMaxLocals; iLocal++)
669         {
670                 const AliMUONLocalInfoStruct* localStruct =
671                         reinterpret_cast<const AliMUONLocalInfoStruct*>(current);
672                 current += sizeof(AliMUONLocalInfoStruct);
673                 
674                 if (current > end)
675                 {
676                         // So we only got part of a local structure, nothing to do but
677                         // report the error and exit.
678                         fHandler.OnError(EventHandler::kNoLocalStruct, localStruct);
679                         fHadError = true;
680                         return end;
681                 }
682                 
683                 // Skip empty local board if card not notified.
684                 if (localStruct->fX2X1 == fgkDisableWord and
685                     localStruct->fX4X3 == fgkDisableWord and
686                     localStruct->fY2Y1 == fgkDisableWord and
687                     localStruct->fY4Y3 == fgkDisableWord and
688                     localStruct->fTriggerBits == fgkDisableWord
689                    )
690                 {
691                         //current += sizeof(AliMUONLocalInfoStruct); // already done above
692                         if (scalarEvent)
693                                 current += sizeof(AliMUONLocalScalarsStruct);
694                         current += sizeof(UInt_t); // skip the end of local structure key.
695                         continue;
696                 }
697                 
698                 // Decode the regional scalar words if this is a scalar event.
699                 const AliMUONLocalScalarsStruct* localScalars = NULL;
700                 if (scalarEvent)
701                 {
702                         localScalars = reinterpret_cast<const AliMUONLocalScalarsStruct*>(current);
703                         current += sizeof(AliMUONLocalScalarsStruct);
704                         if (current > end)
705                         {
706                                 // Indicate we had an error and stop the decoding because we
707                                 // hit the end of the buffer already.
708                                 fHandler.OnError(EventHandler::kNoLocalScalars, localScalars);
709                                 fHadError = true;
710                                 return end;
711                         }
712                 }
713                 
714                 // Now check that the end of regional header marker is OK.
715                 const UInt_t* endOfLocal = reinterpret_cast<const UInt_t*>(current);
716                 current += sizeof(UInt_t);
717                 if (current > end)
718                 {
719                         // Indicate we had an error and stop the decoding because we
720                         // hit the end of the buffer already. We can however signal that
721                         // we got a local structure, because the buffer contains enough
722                         // data to potencially contain the real data of the structure.
723                         fHandler.OnError(EventHandler::kNoEndOfLocal, endOfLocal);
724                         if (not fExitOnError)
725                         {
726                                 fHandler.OnLocalStruct(localStruct, localScalars);
727                         }
728                         fHadError = true;
729                         return end;
730                 }
731                 if (*endOfLocal != fgkEndOfLocal)
732                 {
733                         // Indicate we had an error and stop the decoding if so requested
734                         // by the user.
735                         fHandler.OnError(EventHandler::kBadEndOfLocal, endOfLocal);
736                         fHadError = true;
737                         if (fExitOnError) return current;
738                         
739                         // If the user requested for us to try and recover from structure
740                         // errors then we need to try locate the key in the data stream
741                         // and continue decoding from there.
742                         if (fTryRecover)
743                         {
744                                 const UChar_t* searchPos = reinterpret_cast<const UChar_t*>(localStruct);
745                                 const UChar_t* firstLocalKey = FindKey(fgkEndOfLocal, searchPos, end);
746                                 const UChar_t* firstRegionalKey = FindKey(fgkEndOfReg, searchPos, end);
747                                 
748                                 // If a regional key was found first, then give up on
749                                 // anymore local structures from this regional block and
750                                 // continue decoding from the next regional block.
751                                 // Also if the fgkEndOfLocal key was found exactly one
752                                 // local structure later then we should not adjust the
753                                 // current decoding position because it is more likely that
754                                 // the end of local structure key was just corrupt rather
755                                 // than offset.
756                                 if (firstLocalKey != NULL and firstRegionalKey != NULL)
757                                 {
758                                         if (firstLocalKey < firstRegionalKey)
759                                         {
760                                                 size_t sizeOflocalStruct = sizeof(AliMUONLocalInfoStruct) + sizeof(UInt_t);
761                                                 if (scalarEvent)
762                                                         sizeOflocalStruct += sizeof(AliMUONLocalScalarsStruct);
763                                                 
764                                                 if (firstLocalKey != current + sizeOflocalStruct)
765                                                         current = firstLocalKey + sizeof(UInt_t);
766                                         }
767                                         else
768                                         {
769                                                 // Adjust back to the start of the regional header.
770                                                 current = firstRegionalKey - sizeof(AliMUONRegionalHeaderStruct);
771                                                 if (scalarEvent)
772                                                         current -= sizeof(AliMUONRegionalScalarsStruct);
773                                                 break;
774                                         }
775                                 }
776                                 
777                                 // If we could not find another good key then just continue.
778                         }
779                 }
780                 
781                 fHandler.OnLocalStruct(localStruct, localScalars);
782         }
783         
784         return current;
785 }
786
787
788 template <class EventHandler>
789 const UChar_t* AliMUONTriggerDDLDecoder<EventHandler>::FindKey(
790                 UInt_t key, const UChar_t* start, const UChar_t* end
791         )
792 {
793         /// Searches for the first occurrence of the key value in the buffer
794         /// marked by 'start' and 'end'. 'start' should point to the start of
795         /// the buffer and 'end' should point to 'start + bufferSize'.
796         /// \param key  The 32 bit word to look for.
797         /// \param start  The start location to begin the search at.
798         /// \param end  The pointer to the first byte just past end of the
799         ///             buffer to check.
800         /// \returns  The location of the first occurance of key in the buffer,
801         ///           otherwise NULL is returned if nothing was found.
802  
803         const UChar_t* current = start;
804         while (current + sizeof(UInt_t) <= end)
805         {
806                 UInt_t data = * reinterpret_cast<const UInt_t*>(current);
807                 if (data == key) return current;
808                 current++;
809         }
810         return NULL;
811 }
812
813 #endif // ALIMUONTRIGGERDDLDECODER_H