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