Line data Source code
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 32 : class AliMUONTriggerDDLDecoder
90 : {
91 : public:
92 :
93 : /// Default contructor.
94 : AliMUONTriggerDDLDecoder() :
95 24 : fExitOnError(true), fTryRecover(false),
96 12 : fAutoDetectScalars(false), fHadError(false),
97 12 : fNoRegionals(0), fMaxRegionals(8), fMaxLocals(16),
98 12 : fHandler()
99 36 : {}
100 :
101 : /// Constant method to return the event handler instance.
102 160 : const EventHandler& GetHandler() const { return fHandler; }
103 :
104 : /// Returns the event handler instance.
105 116 : 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 12 : 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 0 : 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 3 : 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 3 : void AutoDetectScalars(bool value) { fAutoDetectScalars = value; }
133 :
134 : /// Returns the maximum regional structure count expected in the DDL payload.
135 18 : UInt_t MaxRegionals() const { return fMaxRegionals; }
136 :
137 : /// Sets the maximum regional structure count expected in the DDL payload.
138 0 : 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 1954 : 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 0 : 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 0 : static UInt_t EndOfDarcWord() { return fgkEndOfDarc; }
156 :
157 : /// Returns the end of global header marker key.
158 0 : static UInt_t EndOfGlobalWord() { return fgkEndOfGlobal; }
159 :
160 : /// Returns the end of regional structure marker key.
161 0 : static UInt_t EndOfRegionalWord() { return fgkEndOfReg; }
162 :
163 : /// Returns the regional error word.
164 18 : static UInt_t RegionalErrorWord() { return fgkErrorWord; }
165 :
166 : /// Returns the end of local structure marker key.
167 0 : 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 0 : static UInt_t DarcDefaultType() { return fgkDarcDefaultType; }
174 :
175 : /// Returns value of Vadorh DARC type.
176 0 : 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 8 : assert( buffer != NULL );
269 :
270 8 : 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 8 : const UChar_t* end = start + bufferSize;
276 :
277 8 : fHandler.OnNewBuffer(buffer, bufferSize);
278 8 : DecodeBuffer(start, end, scalarEvent);
279 8 : fHandler.OnEndOfBuffer(buffer, bufferSize);
280 8 : 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 8 : const UInt_t* darcHeader = reinterpret_cast<const UInt_t*>(current);
308 8 : current += sizeof(UInt_t);
309 16 : if (current > end or current < start)
310 : {
311 : // Indicate we had an error and stop the decoding because we
312 : // hit the end of the buffer already.
313 0 : fHandler.OnError(EventHandler::kNoDarcHeader, darcHeader);
314 0 : fHadError = true;
315 0 : 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 8 : if (fAutoDetectScalars)
323 : {
324 0 : const UInt_t* expectedEndOfDarc = reinterpret_cast<const UInt_t*>(
325 0 : 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 0 : if (reinterpret_cast<const UChar_t*>(expectedEndOfDarc+1) <= end and
334 0 : reinterpret_cast<const UChar_t*>(expectedEndOfDarc+1) > start and
335 0 : EventHandler::GetDarcEventType(*darcHeader) != 0x1
336 0 : and *expectedEndOfDarc == fgkEndOfDarc
337 : )
338 : {
339 : scalarEvent = true;
340 0 : }
341 : else
342 : {
343 : scalarEvent = false;
344 : }
345 0 : }
346 :
347 : // Detect how many regional blocks we expect. If we have no idea then
348 : // just use what the maximum setting is.
349 8 : UInt_t darkType = EventHandler::GetDarcType(*darcHeader);
350 8 : if (darkType == fgkDarcVadorhType)
351 : {
352 0 : fNoRegionals = 1;
353 0 : }
354 8 : else if (darkType == fgkDarcDefaultType)
355 : {
356 0 : fNoRegionals = 8;
357 0 : }
358 : else
359 : {
360 8 : fNoRegionals = fMaxRegionals;
361 : }
362 :
363 : // Check if the DARC header indicates we expect more regionals than we
364 : // are allowed to decode according to our max regional structures count.
365 : // If we do then this is an error and we should indicate it and exit
366 : // if so requested by the user. Also we can fix the number of regionals
367 : // to expect if we are trying to recover from errors.
368 8 : if (fNoRegionals > fMaxRegionals)
369 : {
370 0 : fHandler.OnError(EventHandler::kTooManyRegionals, darcHeader);
371 0 : fHadError = true;
372 0 : if (fExitOnError) return;
373 0 : if (fTryRecover)
374 : {
375 0 : fNoRegionals = fMaxRegionals;
376 0 : }
377 : }
378 :
379 : // Check that the DARC header indicates correctly if we are a scalar event or not.
380 8 : bool darcShowsScalar = (EventHandler::GetDarcEventType(*darcHeader) != 0x1);
381 8 : if (darcShowsScalar != scalarEvent)
382 : {
383 : // Indicate we had an error and stop the decoding if so requested
384 : // by the user.
385 0 : fHandler.OnError(EventHandler::kWrongEventType, darcHeader);
386 0 : fHadError = true;
387 0 : if (fExitOnError) return;
388 : }
389 :
390 : // Decode the DARC scalars if this is a scalar event.
391 : const AliMUONDarcScalarsStruct* darcScalars = NULL;
392 8 : if (scalarEvent)
393 : {
394 0 : darcScalars = reinterpret_cast<const AliMUONDarcScalarsStruct*>(current);
395 0 : current += sizeof(AliMUONDarcScalarsStruct);
396 0 : if (current > end or current < start)
397 : {
398 : // If we overflowed the pointer and already had an error then
399 : // we are clearly lost so just stop decoding before we segfault.
400 0 : if (current < start and fHadError) return;
401 :
402 : // Indicate we had an error and stop the decoding because we
403 : // hit the end of the buffer already.
404 0 : fHandler.OnError(EventHandler::kNoDarcScalars, darcScalars);
405 0 : fHadError = true;
406 0 : return;
407 : }
408 : }
409 :
410 : // Now check that the end of DARC header marker is OK.
411 8 : const UInt_t* endOfDarc = reinterpret_cast<const UInt_t*>(current);
412 8 : current += sizeof(UInt_t);
413 16 : if (current > end or current < start)
414 : {
415 : // If we overflowed the pointer and already had an error then
416 : // we are clearly lost so just stop decoding before we segfault.
417 0 : if (current < start and fHadError) return;
418 :
419 : // Indicate we had an error and stop the decoding because we
420 : // hit the end of the buffer already.
421 0 : fHandler.OnError(EventHandler::kNoEndOfDarc, endOfDarc);
422 0 : fHadError = true;
423 0 : return;
424 : }
425 8 : if (*endOfDarc != fgkEndOfDarc)
426 : {
427 : // Indicate we had an error and stop the decoding if so requested
428 : // by the user.
429 0 : fHandler.OnError(EventHandler::kBadEndOfDarc, endOfDarc);
430 0 : fHadError = true;
431 0 : 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 0 : if (fTryRecover)
437 : {
438 0 : const UChar_t* keypos = FindKey(fgkEndOfDarc,
439 0 : reinterpret_cast<const UChar_t*>(darcHeader),
440 : end
441 : );
442 0 : if (keypos != NULL)
443 : {
444 : // remember to continue decoding just past the key.
445 0 : current = keypos + sizeof(UInt_t);
446 0 : }
447 0 : }
448 : }
449 :
450 8 : 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 8 : reinterpret_cast<const AliMUONGlobalHeaderStruct*>(current);
455 8 : current += sizeof(AliMUONGlobalHeaderStruct);
456 16 : if (current > end or current < start)
457 : {
458 : // If we overflowed the pointer and already had an error then
459 : // we are clearly lost so just stop decoding before we segfault.
460 0 : if (current < start and fHadError) return;
461 :
462 : // Indicate we had an error and stop the decoding because we
463 : // hit the end of the buffer already.
464 0 : fHandler.OnError(EventHandler::kNoGlobalHeader, globalHeader);
465 0 : fHadError = true;
466 0 : return;
467 : }
468 :
469 : // Decode the global scalars if this is a scalar event.
470 : const AliMUONGlobalScalarsStruct* globalScalars = NULL;
471 8 : if (scalarEvent)
472 : {
473 0 : globalScalars = reinterpret_cast<const AliMUONGlobalScalarsStruct*>(current);
474 0 : current += sizeof(AliMUONGlobalScalarsStruct);
475 0 : if (current > end or current < start)
476 : {
477 : // If we overflowed the pointer and already had an error then
478 : // we are clearly lost so just stop decoding before we segfault.
479 0 : if (current < start and fHadError) return;
480 :
481 : // Indicate we had an error and stop the decoding because we
482 : // hit the end of the buffer already.
483 0 : fHandler.OnError(EventHandler::kNoGlobalScalars, globalScalars);
484 0 : fHadError = true;
485 0 : return;
486 : }
487 : }
488 :
489 : // Now check that the end of global header marker is OK.
490 8 : const UInt_t* endOfGlobal = reinterpret_cast<const UInt_t*>(current);
491 8 : current += sizeof(UInt_t);
492 16 : if (current > end or current < start)
493 : {
494 : // If we overflowed the pointer and already had an error then
495 : // we are clearly lost so just stop decoding before we segfault.
496 0 : if (current < start and fHadError) return;
497 :
498 : // Indicate we had an error and stop the decoding because we
499 : // hit the end of the buffer already.
500 0 : fHandler.OnError(EventHandler::kNoEndOfGlobal, endOfGlobal);
501 0 : fHadError = true;
502 0 : return;
503 : }
504 8 : if (*endOfGlobal != fgkEndOfGlobal)
505 : {
506 : // Indicate we had an error and stop the decoding if so requested
507 : // by the user.
508 0 : fHandler.OnError(EventHandler::kBadEndOfGlobal, endOfGlobal);
509 0 : fHadError = true;
510 0 : 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 0 : if (fTryRecover)
516 : {
517 0 : const UChar_t* keypos = FindKey(fgkEndOfGlobal,
518 0 : reinterpret_cast<const UChar_t*>(globalHeader),
519 : end
520 : );
521 0 : if (keypos != NULL)
522 : {
523 : // remember to continue decoding just past the key.
524 0 : current = keypos + sizeof(UInt_t);
525 0 : }
526 0 : }
527 : }
528 :
529 8 : fHandler.OnGlobalHeader(globalHeader, globalScalars, current);
530 :
531 8 : DecodeRegionalStructs(current, end, scalarEvent);
532 16 : }
533 :
534 :
535 : template <class EventHandler>
536 : void AliMUONTriggerDDLDecoder<EventHandler>::DecodeRegionalStructs(
537 : const UChar_t* start, const UChar_t* end, bool scalarEvent
538 : )
539 : {
540 : /// This method decodes the regional structures in the DDL data.
541 : /// For each regional header found, the OnNewRegionalStruct method of
542 : /// the event handler is called, to signal the start of each
543 : /// new regional structure. The DecodeLocalStructs() method is then
544 : /// called to decode the local trigger structures. Finally, a symmetrical
545 : /// call to OnEndOfRegionalStruct of the event handler is called to
546 : /// signal that the regional structure has been decoded.
547 : /// \param start This is the pointer to the start of the buffer.
548 : /// \param end This is the pointer to the first byte just past the
549 : /// end of the buffer.
550 : /// \param scalarEvent Set to true if this DDL contains a scalar event
551 : /// and false if it is a normal physics event.
552 : ///
553 : /// fHadError is set to true if there were any errors decoding the buffer
554 : /// and the OnError method of the callback event handler is called for
555 : /// each error.
556 :
557 : const UChar_t* current = start;
558 :
559 152 : for (UInt_t iReg = 0; iReg < fNoRegionals; iReg++)
560 : {
561 : const AliMUONRegionalHeaderStruct* regionalHeader =
562 64 : reinterpret_cast<const AliMUONRegionalHeaderStruct*>(current);
563 64 : current += sizeof(AliMUONRegionalHeaderStruct);
564 :
565 128 : if (current > end or current < start)
566 : {
567 : // If we overflowed the pointer and already had an error then
568 : // we are clearly lost so just stop decoding before we segfault.
569 0 : if (current < start and fHadError) return;
570 :
571 : // So we only got part of a regional header, nothing to do but
572 : // report the error and exit.
573 0 : fHandler.OnError(EventHandler::kNoRegionalHeader, regionalHeader);
574 0 : fHadError = true;
575 0 : return;
576 : }
577 :
578 : // Skip empty regional board (not connected or with error reading).
579 64 : if (regionalHeader->fDarcWord == fgkErrorWord)
580 : {
581 : //current += sizeof(AliMUONRegionalHeaderStruct); // already done above
582 0 : if (scalarEvent)
583 0 : current += sizeof(AliMUONRegionalScalarsStruct);
584 0 : current += sizeof(UInt_t); // skip the end of regional structure key.
585 :
586 : // now also skip the local structure part:
587 0 : current += fMaxLocals * sizeof(AliMUONLocalInfoStruct);
588 0 : if (scalarEvent)
589 0 : current += fMaxLocals * sizeof(AliMUONLocalScalarsStruct);
590 0 : current += fMaxLocals * sizeof(UInt_t); // skip all the end of local structure keys.
591 :
592 0 : continue;
593 : }
594 :
595 : // Decode the regional scalar words if this is a scalar event.
596 : const AliMUONRegionalScalarsStruct* regionalScalars = NULL;
597 64 : if (scalarEvent)
598 : {
599 0 : regionalScalars = reinterpret_cast<const AliMUONRegionalScalarsStruct*>(current);
600 0 : current += sizeof(AliMUONRegionalScalarsStruct);
601 0 : if (current > end or current < start)
602 : {
603 : // If we overflowed the pointer and already had an error then
604 : // we are clearly lost so just stop decoding before we segfault.
605 0 : if (current < start and fHadError) return;
606 :
607 : // Indicate we had an error and stop the decoding because we
608 : // hit the end of the buffer already.
609 0 : fHandler.OnError(EventHandler::kNoRegionalScalars, regionalScalars);
610 0 : fHadError = true;
611 0 : return;
612 : }
613 : }
614 :
615 : // Now check that the end of regional header marker is OK.
616 64 : const UInt_t* endOfRegional = reinterpret_cast<const UInt_t*>(current);
617 64 : current += sizeof(UInt_t);
618 128 : if (current > end or current < start)
619 : {
620 : // If we overflowed the pointer and already had an error then
621 : // we are clearly lost so just stop decoding before we segfault.
622 0 : if (current < start and fHadError) return;
623 :
624 : // Indicate we had an error and stop the decoding because we
625 : // hit the end of the buffer already.
626 0 : fHandler.OnError(EventHandler::kNoEndOfRegional, endOfRegional);
627 0 : fHadError = true;
628 0 : return;
629 : }
630 64 : if (*endOfRegional != fgkEndOfReg)
631 : {
632 : // Indicate we had an error and stop the decoding if so requested
633 : // by the user.
634 0 : fHandler.OnError(EventHandler::kBadEndOfRegional, endOfRegional);
635 0 : fHadError = true;
636 0 : 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 0 : if (fTryRecover)
642 : {
643 0 : const UChar_t* keypos = FindKey(fgkEndOfReg,
644 0 : 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 0 : + fMaxLocals * (sizeof(AliMUONLocalInfoStruct) + sizeof(UInt_t));
656 0 : if (scalarEvent)
657 : {
658 0 : sizeOfRegional += sizeof(AliMUONRegionalScalarsStruct)
659 0 : + fMaxLocals * sizeof(AliMUONLocalScalarsStruct);
660 0 : }
661 :
662 0 : if (keypos != NULL and keypos != current + sizeOfRegional)
663 : {
664 0 : current = keypos + sizeof(UInt_t);
665 0 : }
666 0 : }
667 : }
668 :
669 : // Tell the handler that we have a new regional block and decode it.
670 : // When done, tell the handler again.
671 : // We call both versions of OnNewRegionalStruct so that user event
672 : // handlers can implement the one they prefer to use.
673 : const UChar_t* startOfLocals = current;
674 64 : fHandler.OnNewRegionalStruct(regionalHeader, regionalScalars, startOfLocals);
675 64 : fHandler.OnNewRegionalStructV2(iReg, regionalHeader, regionalScalars, startOfLocals);
676 64 : current = DecodeLocalStructs(current, end, scalarEvent);
677 64 : fHandler.OnEndOfRegionalStruct(regionalHeader, regionalScalars, startOfLocals);
678 64 : fHandler.OnEndOfRegionalStructV2(iReg, regionalHeader, regionalScalars, startOfLocals);
679 64 : }
680 :
681 : // Now just check that there is no extra rubbish at the end of the DDL.
682 8 : if (current != end)
683 : {
684 0 : fHandler.OnError(EventHandler::kBufferTooBig, current);
685 0 : fHadError = true;
686 0 : }
687 16 : }
688 :
689 :
690 : template <class EventHandler>
691 : const UChar_t* AliMUONTriggerDDLDecoder<EventHandler>::DecodeLocalStructs(
692 : const UChar_t* start, const UChar_t* end, bool scalarEvent
693 : )
694 : {
695 : /// This method decodes the local structures in the DDL data for a
696 : /// single regional structure. For each local trigger structure found,
697 : /// the OnLocalStruct method of the event handler is called.
698 : /// \param start This is the pointer to the start of the regional structure
699 : /// payload (The pointer just past the regional header key).
700 : /// \param end This is the pointer to the first byte just past the
701 : /// end of the buffer.
702 : /// \param scalarEvent Set to true if this DDL contains a scalar event
703 : /// and false if it is a normal physics event.
704 : /// \returns The position in the buffer where this method stopped decoding.
705 : ///
706 : /// fHadError is set to true if there were any errors decoding the buffer
707 : /// and the OnError method of the callback event handler is called for
708 : /// each error.
709 :
710 : const UChar_t* current = start;
711 :
712 2240 : for (UInt_t iLocal = 0; iLocal < fMaxLocals; iLocal++)
713 : {
714 : const AliMUONLocalInfoStruct* localStruct =
715 1024 : reinterpret_cast<const AliMUONLocalInfoStruct*>(current);
716 1024 : current += sizeof(AliMUONLocalInfoStruct);
717 :
718 2048 : if (current > end or current < start)
719 : {
720 : // If we overflowed the pointer and already had an error then
721 : // we are clearly lost so just stop decoding before we segfault.
722 0 : if (current < start and fHadError) return end;
723 :
724 : // So we only got part of a local structure, nothing to do but
725 : // report the error and exit.
726 0 : fHandler.OnError(EventHandler::kNoLocalStruct, localStruct);
727 0 : fHadError = true;
728 0 : return end;
729 : }
730 :
731 : // Skip empty local board if card not notified.
732 1080 : if (localStruct->fX2X1 == fgkDisableWord and
733 56 : localStruct->fX4X3 == fgkDisableWord and
734 56 : localStruct->fY2Y1 == fgkDisableWord and
735 56 : localStruct->fY4Y3 == fgkDisableWord and
736 56 : localStruct->fTriggerBits == fgkDisableWord
737 : )
738 : {
739 : //current += sizeof(AliMUONLocalInfoStruct); // already done above
740 56 : if (scalarEvent)
741 0 : current += sizeof(AliMUONLocalScalarsStruct);
742 56 : current += sizeof(UInt_t); // skip the end of local structure key.
743 56 : continue;
744 : }
745 :
746 : // Decode the regional scalar words if this is a scalar event.
747 : const AliMUONLocalScalarsStruct* localScalars = NULL;
748 968 : if (scalarEvent)
749 : {
750 0 : localScalars = reinterpret_cast<const AliMUONLocalScalarsStruct*>(current);
751 0 : current += sizeof(AliMUONLocalScalarsStruct);
752 0 : if (current > end or current < start)
753 : {
754 : // If we overflowed the pointer and already had an error then
755 : // we are clearly lost so just stop decoding before we segfault.
756 0 : if (current < start and fHadError) return end;
757 :
758 : // Indicate we had an error and stop the decoding because we
759 : // hit the end of the buffer already.
760 0 : fHandler.OnError(EventHandler::kNoLocalScalars, localScalars);
761 0 : fHadError = true;
762 0 : return end;
763 : }
764 : }
765 :
766 : // Now check that the end of regional header marker is OK.
767 968 : const UInt_t* endOfLocal = reinterpret_cast<const UInt_t*>(current);
768 968 : current += sizeof(UInt_t);
769 1936 : if (current > end or current < start)
770 : {
771 : // If we overflowed the pointer and already had an error then
772 : // we are clearly lost so just stop decoding before we segfault.
773 0 : if (current < start and fHadError) return end;
774 :
775 : // Indicate we had an error and stop the decoding because we
776 : // hit the end of the buffer already. We can however signal that
777 : // we got a local structure, because the buffer contains enough
778 : // data to potencially contain the real data of the structure.
779 0 : fHandler.OnError(EventHandler::kNoEndOfLocal, endOfLocal);
780 0 : if (not fExitOnError)
781 : {
782 0 : fHandler.OnLocalStruct(localStruct, localScalars);
783 0 : }
784 0 : fHadError = true;
785 0 : return end;
786 : }
787 968 : if (*endOfLocal != fgkEndOfLocal)
788 : {
789 : // Indicate we had an error and stop the decoding if so requested
790 : // by the user.
791 0 : fHandler.OnError(EventHandler::kBadEndOfLocal, endOfLocal);
792 0 : fHadError = true;
793 0 : 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 0 : if (fTryRecover)
799 : {
800 0 : const UChar_t* searchPos = reinterpret_cast<const UChar_t*>(localStruct);
801 0 : const UChar_t* firstLocalKey = FindKey(fgkEndOfLocal, searchPos, end);
802 0 : 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 0 : if (firstLocalKey != NULL and firstRegionalKey != NULL)
813 : {
814 0 : if (firstLocalKey < firstRegionalKey)
815 : {
816 : size_t sizeOflocalStruct = sizeof(AliMUONLocalInfoStruct) + sizeof(UInt_t);
817 0 : if (scalarEvent)
818 0 : sizeOflocalStruct += sizeof(AliMUONLocalScalarsStruct);
819 :
820 0 : if (firstLocalKey != current + sizeOflocalStruct)
821 0 : current = firstLocalKey + sizeof(UInt_t);
822 : }
823 : else
824 : {
825 : // Adjust back to the start of the regional header.
826 0 : current = firstRegionalKey - sizeof(AliMUONRegionalHeaderStruct);
827 0 : if (scalarEvent)
828 0 : current -= sizeof(AliMUONRegionalScalarsStruct);
829 0 : break;
830 : }
831 0 : }
832 :
833 : // If we could not find another good key then just continue.
834 0 : }
835 : }
836 :
837 : // Call both handlers for local structures so that the user decoder event
838 : // handler class can implement the one it prefers to use.
839 968 : fHandler.OnLocalStruct(localStruct, localScalars);
840 968 : fHandler.OnLocalStructV2(iLocal, localStruct, localScalars);
841 968 : }
842 :
843 64 : return current;
844 64 : }
845 :
846 :
847 : template <class EventHandler>
848 : const UChar_t* AliMUONTriggerDDLDecoder<EventHandler>::FindKey(
849 : UInt_t key, const UChar_t* start, const UChar_t* end
850 : )
851 : {
852 : /// Searches for the first occurrence of the key value in the buffer
853 : /// marked by 'start' and 'end'. 'start' should point to the start of
854 : /// the buffer and 'end' should point to 'start + bufferSize'.
855 : /// \param key The 32 bit word to look for.
856 : /// \param start The start location to begin the search at.
857 : /// \param end The pointer to the first byte just past end of the
858 : /// buffer to check.
859 : /// \returns The location of the first occurance of key in the buffer,
860 : /// otherwise NULL is returned if nothing was found.
861 :
862 0 : if (end + sizeof(UInt_t) < start) return NULL; // check for pointer overflow.
863 : const UChar_t* current = start;
864 0 : while (current + sizeof(UInt_t) <= end)
865 : {
866 0 : UInt_t data = * reinterpret_cast<const UInt_t*>(current);
867 0 : if (data == key) return current;
868 0 : current++;
869 0 : }
870 0 : return NULL;
871 0 : }
872 :
873 : #endif // ALIMUONTRIGGERDDLDECODER_H
|