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