]>
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> | |
3f9d7600 | 222 | const UInt_t AliMUONTriggerDDLDecoder<EventHandler>::fgkDisableWord = 0x10CADEAD; |
1788245f | 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); | |
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 | ||
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 | 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 | ||
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 | 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 | ||
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 | ||
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 |