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