Updates to AddTask macro from Chris
[u/mrichter/AliRoot.git] / MUON / AliMUONTriggerDDLDecoder.h
CommitLineData
1788245f 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///
88template <class EventHandler>
89class AliMUONTriggerDDLDecoder
90{
91public:
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
178private:
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.
211template <class EventHandler>
212const UInt_t AliMUONTriggerDDLDecoder<EventHandler>::fgkEndOfDarc = 0xDEADFACE;
213template <class EventHandler>
214const UInt_t AliMUONTriggerDDLDecoder<EventHandler>::fgkEndOfGlobal = 0xDEADBEEF;
215template <class EventHandler>
216const UInt_t AliMUONTriggerDDLDecoder<EventHandler>::fgkEndOfReg = 0xBEEFFACE;
217template <class EventHandler>
218const UInt_t AliMUONTriggerDDLDecoder<EventHandler>::fgkErrorWord = 0xCAFEDEAD;
219template <class EventHandler>
220const UInt_t AliMUONTriggerDDLDecoder<EventHandler>::fgkEndOfLocal = 0xCAFEFADE;
221template <class EventHandler>
3f9d7600 222const UInt_t AliMUONTriggerDDLDecoder<EventHandler>::fgkDisableWord = 0x10CADEAD;
1788245f 223template <class EventHandler>
224const UInt_t AliMUONTriggerDDLDecoder<EventHandler>::fgkDarcDefaultType = 0x6;
225template <class EventHandler>
226const UInt_t AliMUONTriggerDDLDecoder<EventHandler>::fgkDarcVadorhType = 0x4;
227
228
229template <class EventHandler>
230bool 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
284template <class EventHandler>
285void 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);
009fa22b 309 if (current > end or current < start)
1788245f 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
009fa22b 334 reinterpret_cast<const UChar_t*>(expectedEndOfDarc+1) > start and
1788245f 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.
6b4a77b9 349 UInt_t darkType = EventHandler::GetDarcType(*darcHeader);
350 if (darkType == fgkDarcVadorhType)
1788245f 351 {
6b4a77b9 352 fNoRegionals = 1;
353 }
354 else if (darkType == fgkDarcDefaultType)
355 {
356 fNoRegionals = 8;
357 }
358 else
359 {
360 fNoRegionals = fMaxRegionals;
1788245f 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);
009fa22b 396 if (current > end or current < start)
1788245f 397 {
009fa22b 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
1788245f 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);
009fa22b 413 if (current > end or current < start)
1788245f 414 {
009fa22b 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
1788245f 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);
009fa22b 456 if (current > end or current < start)
1788245f 457 {
009fa22b 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
1788245f 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);
009fa22b 475 if (current > end or current < start)
1788245f 476 {
009fa22b 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
1788245f 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);
009fa22b 492 if (current > end or current < start)
1788245f 493 {
009fa22b 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
1788245f 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
535template <class EventHandler>
536void 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
009fa22b 565 if (current > end or current < start)
1788245f 566 {
009fa22b 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
1788245f 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);
009fa22b 601 if (current > end or current < start)
1788245f 602 {
009fa22b 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
1788245f 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);
009fa22b 618 if (current > end or current < start)
1788245f 619 {
009fa22b 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
1788245f 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.
2235e482 671 // We call both versions of OnNewRegionalStruct so that user event
672 // handlers can implement the one they prefer to use.
1788245f 673 const UChar_t* startOfLocals = current;
674 fHandler.OnNewRegionalStruct(regionalHeader, regionalScalars, startOfLocals);
2235e482 675 fHandler.OnNewRegionalStructV2(iReg, regionalHeader, regionalScalars, startOfLocals);
1788245f 676 current = DecodeLocalStructs(current, end, scalarEvent);
677 fHandler.OnEndOfRegionalStruct(regionalHeader, regionalScalars, startOfLocals);
2235e482 678 fHandler.OnEndOfRegionalStructV2(iReg, regionalHeader, regionalScalars, startOfLocals);
1788245f 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
690template <class EventHandler>
691const 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
009fa22b 718 if (current > end or current < start)
1788245f 719 {
009fa22b 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
1788245f 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);
009fa22b 752 if (current > end or current < start)
1788245f 753 {
009fa22b 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
1788245f 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);
009fa22b 769 if (current > end or current < start)
1788245f 770 {
009fa22b 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
1788245f 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
2235e482 837 // Call both handlers for local structures so that the user decoder event
838 // handler class can implement the one it prefers to use.
1788245f 839 fHandler.OnLocalStruct(localStruct, localScalars);
2235e482 840 fHandler.OnLocalStructV2(iLocal, localStruct, localScalars);
1788245f 841 }
842
843 return current;
844}
845
846
847template <class EventHandler>
848const 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
009fa22b 862 if (end + sizeof(UInt_t) < start) return NULL; // check for pointer overflow.
1788245f 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