Line data Source code
1 : #ifndef ALIMUONTRACKERDDLDECODER_H
2 : #define ALIMUONTRACKERDDLDECODER_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 AliMUONTrackerDDLDecoder.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 tracking stations.
26 : ///
27 : /// This file implementes the AliMUONTrackerDDLDecoder class, which contains
28 : /// the core logic for decoding the payload in DDL streams coming from the muon
29 : /// spectrometer's tracking chambers in a very efficient manner.
30 : ///
31 : /// This implementation is derived from work done by Christian Finck for the
32 : /// AliMUONPayloadTracker.
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 <string.h>
41 : #include "AliMUONTrackerDDLDecoderEventHandler.h"
42 :
43 : /// \ingroup raw
44 : /// \class AliMUONTrackerDDLDecoder
45 : /// \brief A high performance decoder class for MUON tracking DDL data.
46 : ///
47 : /// This class implements a high performance decoder for decoding DDL payload
48 : /// data coming from the muon spectrometers tracking chambers.
49 : /// It has been implemented using the event driven paradigm with templates,
50 : /// which allows us to minimise the number of method calls made in the inner
51 : /// loops of the algorithm and minimise the memory footprint. At least for
52 : /// optimised production compilations.
53 : /// The decoder class only contains the basic decoding and error checking logic.
54 : /// It calls methods such as OnNewBlock, OnNewBusPatch, OnData etc in
55 : /// the event handler during the decoding to return the decoded data.
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 AliMUONTrackerDDLDecoderEventHandler
60 : /// and overriding the callback methods like so:
61 : /// \code
62 : /// class MyCustomHandler : public AliMUONTrackerDDLDecoderEventHandler
63 : /// {
64 : /// public:
65 : /// void OnData(UInt_t data, bool parityError)
66 : /// {
67 : /// // I can do something with 'data' here and check if there was
68 : /// // a parity error with 'parityError'.
69 : /// }
70 : /// };
71 : /// \endcode
72 : ///
73 : /// Once the custom handler is written then the decoder is instantiated as
74 : /// shown below, to use your new custom handler. Also to start decoding one needs
75 : /// to call the Decode() method of the decoder.
76 : /// \code
77 : /// AliMUONTrackerDDLDecoder<MyCustomHandler> myDecoder;
78 : /// muDecoder.Decoder(buffer, bufferSize);
79 : /// \endcode
80 : ///
81 : /// Note that this class was written as a template on purpose. To maximise the
82 : /// compilers chance to make optimisations and inline the code we must use a template.
83 : /// Depending on exactly what you do inside your handler, the decoder could be
84 : /// significantly slower if run time polymorphism was used, i.e. making the class
85 : /// AliMUONTrackerDDLDecoderEventHandler abstract and using virtual methods.
86 : ///
87 : /// There has been a change to the data format that the real detector generates.
88 : /// Two trailer words are added to the end of the DDL payload which indicated
89 : /// the end of data. The decoder is initialised by default to automatically
90 : /// check for these and deal with it correctly, if they exist or not.
91 : /// However, if you want to override this behaviour then set the flag
92 : /// fAutoDetectTrailer to false with AutoDetectTrailer(false). Then if you have
93 : /// data with the old data format you should set fCheckForTrailer to false with
94 : /// CheckForTrailer(false), otherwise for real data it should be
95 : /// fCheckForTrailer = true. Only when fAutoDetectTrailer is true will the
96 : /// fCheckForTrailer flag be ignored and no warnings will be generated for an
97 : /// incorrect data format.
98 : ///
99 : /// \author Artur Szostak <artursz@iafrica.com>
100 :
101 : template <class EventHandler>
102 32 : class AliMUONTrackerDDLDecoder
103 : {
104 : public:
105 :
106 : /// Default contructor.
107 : AliMUONTrackerDDLDecoder() :
108 24 : fExitOnError(true), fTryRecover(false),
109 12 : fSendDataOnParityError(false), fHadError(false),
110 12 : fAutoDetectTrailer(true), fCheckForTrailer(true),
111 12 : fMaxBlocks(2), fMaxDSPs(5), fMaxBusPatches(5), fHandler()
112 36 : {}
113 :
114 : /// Constant method to return the event handler instance.
115 0 : const EventHandler& GetHandler() const { return fHandler; }
116 :
117 : /// Returns the event handler instance.
118 15204 : EventHandler& GetHandler() { return fHandler; }
119 :
120 : /// Returns the "exit on error" flag.
121 : /// i.e. should the decoder stop on the very first error found.
122 : bool ExitOnError() const { return fExitOnError; }
123 :
124 : /// Sets the "exit on error" flag.
125 : /// i.e. should the decoder stop on the very first error found.
126 12 : void ExitOnError(bool value) { fExitOnError = value; }
127 :
128 : /// Returns the "try to recover from errors" flag.
129 : /// i.e. should the decoder try to recover from errors found in the
130 : /// payload headers or trailers.
131 0 : bool TryRecover() const { return fTryRecover; }
132 :
133 : /// Sets the "try to recover from errors" flag.
134 : /// i.e. should the decoder try to recover from errors found in the
135 : /// payload headers or trailers.
136 4 : void TryRecover(bool value) { fTryRecover = value; }
137 :
138 : /// Returns the flag indicating if the raw data words in the bus patches
139 : /// that failed their parity tests (i.e. parity error / bit flip in the
140 : /// raw data word) will be sent to the event handler anyway through OnData.
141 : bool SendDataOnParityError() const { return fSendDataOnParityError; }
142 :
143 : /// Sets the flag indicating if the raw data words in the bus patches
144 : /// that failed their parity tests (i.e. parity error / bit flip in the
145 : /// raw data word) will be sent to the event handler anyway through OnData.
146 12 : void SendDataOnParityError(bool value) { fSendDataOnParityError = value; }
147 :
148 : /// Returns the maximum block count expected in the DDL payload.
149 18 : UInt_t MaxBlocks() const { return fMaxBlocks; }
150 :
151 : /// Sets the maximum block count expected in the DDL payload.
152 0 : void MaxBlocks(UInt_t n) { fMaxBlocks = n; }
153 :
154 : /// Returns the maximum DSP header count expected in any given block
155 : /// structure within the DDL payload.
156 18 : UInt_t MaxDSPs() const { return fMaxDSPs; }
157 :
158 : /// Sets the maximum DSP header count expected in any given block structure
159 : /// within the DDL payload.
160 0 : void MaxDSPs(UInt_t n) { fMaxDSPs = n; }
161 :
162 : /// Returns the maximum number of bus patches expected in any given DSP
163 : /// structure within the DDL payload.
164 18 : UInt_t MaxBusPatches() const { return fMaxBusPatches; }
165 :
166 : /// Sets the maximum number of bus patches expected in any given DSP
167 : /// structure within the DDL payload.
168 0 : void MaxBusPatches(UInt_t n) { fMaxBusPatches = n; }
169 :
170 : /// Returns the value of the auto-detect trailer flag.
171 0 : bool AutoDetectTrailer() const { return fAutoDetectTrailer; }
172 :
173 : /// Sets the value of the auto-detect trailer flag.
174 3 : void AutoDetectTrailer(bool value) { fAutoDetectTrailer = value; }
175 :
176 : /// Returns the value of the flag to check for the end of DDL trailer.
177 0 : bool CheckForTrailer() const { return fCheckForTrailer; }
178 :
179 : /// Sets the value of the flag to check for the end of DDL trailer.
180 3 : void CheckForTrailer(bool value) { fCheckForTrailer = value; }
181 :
182 : /// This method decodes the DDL payload contained in the buffer.
183 : bool Decode(const void* buffer, UInt_t bufferSize);
184 :
185 : /// First try fix data corruption and then decode the DDL payload.
186 : bool Decode(void* buffer, UInt_t bufferSize);
187 :
188 : /// Returns the block marker key.
189 : static UInt_t BlockDataKeyWord() { return fgkBlockDataKey; }
190 :
191 : /// Returns the DSP marker key.
192 : static UInt_t DspDataKeyWord() { return fgkDSPDataKey; }
193 :
194 : /// Returns the bus patch marker key.
195 : static UInt_t BusPatchDataKeyWord() { return fgkBusPatchDataKey; }
196 :
197 : /// Returns the expected padding word value.
198 : static UInt_t PaddingWord() { return fgkPaddingWord; }
199 :
200 : /// Returns the expected end of DDL marker.
201 : static UInt_t EndOfDDLWord() { return fgkEndOfDDL; }
202 :
203 : private:
204 :
205 : bool fExitOnError; ///< Indicates if we should exit on the very first error.
206 : bool fTryRecover; ///< Indicates if we should try recover from a corrupt structure header or DDL trailer.
207 : bool fSendDataOnParityError; ///< If set to true then we issue a OnData() event even if the data word had a parity error.
208 : bool fHadError; ///< Indicates if we had an error decoding the data.
209 : bool fAutoDetectTrailer; ///< Indicates if we should automatically check for the end of DDL trailer (Default = true).
210 : bool fCheckForTrailer; ///< Indicates if we should check for the end of DDL trailer (Default = true). This flag is ignored if fAutoDetectTrailer is true.
211 : UInt_t fMaxBlocks; ///< Maximum number of block structures allowed in a DDL stream.
212 : UInt_t fMaxDSPs; ///< Maximum number of DSP structures allowed in a DDL stream.
213 : UInt_t fMaxBusPatches; ///< Maximum number of bus patch structures allowed in a DDL stream.
214 : EventHandler fHandler; ///< The event handler which deals with parsing events.
215 :
216 : void DecodeBuffer(const UChar_t* start, const UChar_t* end);
217 :
218 : bool DecodeBlockData(
219 : const AliMUONBlockHeaderStruct* blockHeader,
220 : const UChar_t* start, const UChar_t* end
221 : );
222 :
223 : bool DecodeDSPData(const UChar_t* start, const UChar_t* end);
224 :
225 : bool DecodeBusPatchData(const UChar_t* start, const UChar_t* end);
226 :
227 : /// Possible results that can be returned by the TryRecoverStruct method.
228 : enum RecoverResult
229 : {
230 : kRecoverFailed, ///< The recovery failed. Cannot continue parsing.
231 : kStructRecovered, ///< Indicates that we recovered from a corrupt structure header and can continue processing the given structure.
232 : kContinueToNextStruct ///< Must continue parsing the next structure and ignore the current one.
233 : };
234 :
235 : RecoverResult TryRecoverStruct(
236 : UInt_t expectedKey,
237 : UInt_t headerSize,
238 : UInt_t totalLength,
239 : UInt_t length,
240 : const UChar_t* structStart,
241 : const UChar_t* bufferEnd,
242 : const UChar_t*& dataEnd,
243 : const UChar_t*& structEnd,
244 : const UChar_t*& current
245 : );
246 :
247 : const UChar_t* FindKey(
248 : UInt_t key, const UChar_t* start, const UChar_t* end
249 : );
250 :
251 : bool ParityIsOk(UInt_t data);
252 :
253 : static const UInt_t fgkBlockDataKey; ///< The key word expected to identify block structure headers.
254 : static const UInt_t fgkDSPDataKey; ///< The key word expected to identify DSP structure headers.
255 : static const UInt_t fgkBusPatchDataKey; ///< The key word expected to identify bus patch headers.
256 : static const UInt_t fgkPaddingWord; ///< The expected format of the padding word in the DDL payload.
257 : static const UInt_t fgkEndOfDDL; ///< The end of DDL trailer word.
258 : };
259 :
260 : //_____________________________________________________________________________
261 :
262 : // The following are the structure header keys which are used to identify the kind
263 : // of structure header we are dealing with: block, DSP or bus patch header.
264 : template <class EventHandler>
265 : const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkBlockDataKey = 0xFC0000FC;
266 : template <class EventHandler>
267 : const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkDSPDataKey = 0xF000000F;
268 : template <class EventHandler>
269 : const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkBusPatchDataKey = 0xB000000B;
270 : template <class EventHandler>
271 : const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkPaddingWord = 0xBEEFFACE;
272 : template <class EventHandler>
273 : const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkEndOfDDL = 0xD000000D;
274 :
275 :
276 : template <class EventHandler>
277 : bool AliMUONTrackerDDLDecoder<EventHandler>::Decode(const void* buffer, UInt_t bufferSize)
278 : {
279 : /// This method should be called to actually decode the DDL payload
280 : /// contained in a memory buffer. The payload should be for a muon tracking
281 : /// chamber DDL stream.
282 : /// As the decoder progresses it will make method calls to the event handler
283 : /// instance (which can be accessed with the GetHandler() method) to indicate
284 : /// the start of the new block, DSP and bus patch headers. For every raw
285 : /// data word the OnData method of the event handler is called.
286 : ///
287 : /// If an error occurs during the parse because the data is corrupt then
288 : /// the OnError method is called indicating what the problem was.
289 : /// Decoding will stop at this point unless the fExitOnError flag is set
290 : /// to false. Also raw data words which contain a parity error are only
291 : /// sent to the event handler with OnData if the fSendDataOnParityError
292 : /// flag is set to true. There is also an optional flag fTryRecover which
293 : /// can enable logic which will attempt to recover the header structures found
294 : /// in the DDL payload if they are found to be inconsistent (assumed corrupt).
295 : /// fTryRecover set to true will also enable recovery from a corrupt
296 : /// DDL trailer marking the end of DDL payload.
297 : ///
298 : /// \param buffer This is the pointer to the start of the memory buffer
299 : /// containing the DDL payload. Remember that this must be the start of
300 : /// the payload and not the DDL stream. That is, this pointer should be
301 : /// equal to: DDL start pointer + 8 * sizeof(UInt_t).
302 : /// \param bufferSize This is the pointer to the first byte just past the
303 : /// end of the block structure.
304 : /// \return Returns false if there was any problem with decoding the data,
305 : /// and true otherwise. Note: the data may have been partially decoded
306 : /// even if false was returned, which would be indicated by at least one
307 : /// call to the event handlers OnData method.
308 :
309 160 : assert( buffer != NULL );
310 :
311 80 : fHadError = false;
312 :
313 : // We are basically implementing something like a recursive decent parser.
314 : // So start by marking the start of buffer position and end of buffer.
315 : const UChar_t* start = reinterpret_cast<const UChar_t*>(buffer);
316 80 : const UChar_t* end = start + bufferSize;
317 :
318 80 : fHandler.OnNewBuffer(buffer, bufferSize);
319 80 : DecodeBuffer(start, end);
320 80 : fHandler.OnEndOfBuffer(buffer, bufferSize);
321 80 : return not fHadError;
322 : }
323 :
324 :
325 : template <class EventHandler>
326 : bool AliMUONTrackerDDLDecoder<EventHandler>::Decode(void* buffer, UInt_t bufferSize)
327 : {
328 : /// This decoding method performs a special checks to see if the DDL
329 : /// corruption is fixable and then fixes the buffer by modifying it directly.
330 : /// The fixes only apply if the fTryRecover flag is enabled.
331 : /// \note buffer might be modified.
332 :
333 160 : assert( buffer != NULL );
334 80 : if (fTryRecover)
335 : {
336 : ///////////////////////////////////////////////////////
337 : // Trick to recover B off data Runs : 119041, 119047, 119055, 119057
338 : // A. Baldisseri May 2010
339 : // Check if 16 32-bit words from a buspatch have been inserted
340 : // incorrectly immediately at the beginning of the DDL payload.
341 : UChar_t* bufferChar = reinterpret_cast<UChar_t*>(buffer);
342 0 : UInt_t* bufferInt = reinterpret_cast<UInt_t*>(buffer);
343 0 : if (bufferSize > 18*4 // is the buffer large enough to check the header.
344 0 : and bufferInt[0] != fgkBlockDataKey and bufferInt[16] == fgkBlockDataKey // was the header incorrectly moved.
345 0 : and bufferSize > bufferInt[17]*4 + sizeof(AliMUONBlockHeaderStruct) // is the buffer large enough for the second block header.
346 0 : and bufferInt[bufferInt[17]] == fgkBlockDataKey // Check that the second header is in the correct location.
347 0 : and bufferInt[17] == bufferInt[18] + 8 // Make sure that both lengths are correct.
348 0 : and (bufferInt[17] + bufferInt[bufferInt[17]+1]+2)*4 == bufferSize // Check that both blocks will have the correct size if we make the fix.
349 : )
350 : {
351 0 : UChar_t tmpbuf[16*4];
352 0 : memcpy(tmpbuf, bufferChar, 16*4);
353 0 : size_t sizeToMove = bufferInt[17]*4-16*4;
354 0 : memmove(bufferChar, bufferChar+16*4, sizeToMove);
355 0 : memcpy(bufferChar + sizeToMove, tmpbuf, 16*4);
356 0 : }
357 0 : }
358 80 : return Decode(reinterpret_cast<const void*>(buffer), bufferSize);
359 : }
360 :
361 :
362 : template <class EventHandler>
363 : void AliMUONTrackerDDLDecoder<EventHandler>::DecodeBuffer(
364 : const UChar_t* start, const UChar_t* end
365 : )
366 : {
367 : /// This method decodes the buffer's payload data. It unpacks the block
368 : /// structures contained inside and then for each block it calls the
369 : /// OnNewBlock method for the event handler to signal the start of each new
370 : /// block structure. OnEndOfBlock is called once each block is processed.
371 : /// \param start This is the pointer to the start of the buffer.
372 : /// \param end This is the pointer to the first byte just past the
373 : /// end of the buffer.
374 : /// fHadError is set to true if there were any errors decoding the buffer
375 : /// and the OnError method of the callback event handler is called for
376 : /// each error.
377 :
378 160 : const UChar_t* current = start;
379 80 : const UInt_t* bufferStart = reinterpret_cast<const UInt_t*>(start);
380 80 : const UInt_t* bufferEnd = reinterpret_cast<const UInt_t*>(end);
381 : bool problemWithTrailer = false;
382 :
383 : // The DDL payload normally has a 2 word trailer which contains the end of
384 : // DDL markers 0xD000000D. But this is not the case for older simulated
385 : // data so if we are auto-detecting the trailer then we need to carefully
386 : // check if these words are there or not.
387 : const UChar_t* endOfBlocks = end;
388 80 : const UInt_t* trailerWords = reinterpret_cast<const UInt_t*>(end) - 2;
389 80 : if (fAutoDetectTrailer)
390 : {
391 160 : if (trailerWords >= bufferStart and trailerWords < bufferEnd
392 240 : and *trailerWords == fgkEndOfDDL and *(trailerWords+1) == fgkEndOfDDL
393 : )
394 : {
395 : // Found the trailer so reposition the end of blocks marker.
396 80 : endOfBlocks = reinterpret_cast<const UChar_t*>(trailerWords);
397 80 : }
398 : // else assume we are dealing with the older data format.
399 : }
400 0 : else if (fCheckForTrailer)
401 : {
402 0 : if (trailerWords >= bufferStart and trailerWords < bufferEnd
403 0 : and *trailerWords == fgkEndOfDDL and *(trailerWords+1) == fgkEndOfDDL
404 : )
405 : {
406 : // Found the trailer so reposition the end of blocks marker.
407 0 : endOfBlocks = reinterpret_cast<const UChar_t*>(trailerWords);
408 0 : }
409 : else
410 : {
411 0 : if (trailerWords+1 >= bufferStart and trailerWords+1 < bufferEnd and *(trailerWords+1) == fgkEndOfDDL)
412 0 : fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords+1);
413 0 : else if (trailerWords >= bufferStart and trailerWords < bufferEnd and *(trailerWords) == fgkEndOfDDL)
414 0 : fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords);
415 : else
416 0 : fHandler.OnError(EventHandler::kNoDDLTrailerWords, end);
417 :
418 : // Stop the decoding if so requested by the user, otherwise
419 : // remember about the error so that we return false from the
420 : // Decode() method and continue decoding.
421 0 : fHadError = true;
422 0 : if (fExitOnError) return;
423 :
424 : // Mark that there was a problem with the trailer so that
425 : // for subsequent errors we try to deal with this better.
426 : problemWithTrailer = true;
427 :
428 : // We can also try figure out how many trailer words there
429 : // actually are and move the end of blocks marker back.
430 :
431 0 : if (fTryRecover)
432 : {
433 : trailerWords = bufferEnd;
434 : // There should only be a max of 2 trailer words.
435 0 : if (trailerWords-2 >= bufferStart and trailerWords-2 < bufferEnd and *(trailerWords-2) == fgkEndOfDDL)
436 0 : trailerWords -= 2;
437 0 : else if (trailerWords-1 >= bufferStart and trailerWords-1 < bufferEnd and *(trailerWords-1) == fgkEndOfDDL)
438 0 : trailerWords -= 1;
439 0 : endOfBlocks = reinterpret_cast<const UChar_t*>(trailerWords);
440 0 : }
441 : }
442 : }
443 :
444 : UInt_t blockCount = 0; // Indicates the number of blocks decoded.
445 320 : while (current < endOfBlocks)
446 : {
447 : // Mark the start of the block structure.
448 : const UChar_t* blockStart = current;
449 :
450 : // Get the block header, move the current pointer just past the end
451 : // of the header and check that we have not overflowed the buffer.
452 : const AliMUONBlockHeaderStruct* blockHeader
453 160 : = reinterpret_cast<const AliMUONBlockHeaderStruct*>(blockStart);
454 160 : current += sizeof(AliMUONBlockHeaderStruct);
455 320 : if (current > endOfBlocks or current < start)
456 : {
457 : // If we overflowed the pointer and already had an error then
458 : // we are clearly lost so just stop decoding before we segfault.
459 0 : if (current < start and fHadError) return;
460 :
461 : // We first check if we actually hit the end of DDL markers
462 : // If we did then either we did not/could not recover from
463 : // a corrupt trailer or we did not detect a correct trailer
464 : // in auto-detect mode.
465 0 : trailerWords = reinterpret_cast<const UInt_t*>(blockHeader);
466 : // The "trailerWords+1 <= bufferEnd" checks that we are
467 : // not reading beyond the end of the buffer.
468 0 : if (trailerWords+1 <= bufferEnd and *trailerWords == fgkEndOfDDL)
469 : {
470 : // If we aready knew the trailer was corrupt then just
471 : // return because the error was already announced.
472 0 : if (problemWithTrailer) return;
473 :
474 0 : if (fAutoDetectTrailer)
475 : {
476 : // If we got here then there is at least one correct trailer
477 : // word, but since we did not detect a correct trailer then
478 : // there must be only one. Announce the error and exit.
479 0 : fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords);
480 0 : fHadError = true;
481 0 : return;
482 : }
483 : }
484 :
485 : // So we only got part of a block header at the very end
486 : // of the buffer. Nothing to do but report the error and exit.
487 0 : if (blockCount == fMaxBlocks)
488 : // Special case where we got all the blocks we
489 : // expected, so the remaining data must be rubbish.
490 0 : fHandler.OnError(EventHandler::kBufferTooBig, blockHeader);
491 : else
492 0 : fHandler.OnError(EventHandler::kNoBlockHeader, blockHeader);
493 0 : fHadError = true;
494 0 : return;
495 : }
496 :
497 : // The header fits the buffer so we can mark the data start and
498 : // read from the header to find the end of data and block pointers.
499 : const UChar_t* dataStart = current;
500 160 : current += blockHeader->fLength * sizeof(UInt_t);
501 160 : const UChar_t* dataEnd = current;
502 320 : const UChar_t* blockEnd = blockStart
503 160 : + blockHeader->fTotalLength * sizeof(UInt_t);
504 :
505 : // Now we need to check for the following things:
506 : // 1) Is the end of block or end of data pointer outside the buffer
507 : // boundaries.
508 : // 2) Are the values for these pointers the same.
509 : // 3) Is the expected data key in the header present.
510 : // If any of the above fail then we know there is a problem with
511 : // the block header. It must be corrupted somehow.
512 320 : if (blockHeader->fDataKey != fgkBlockDataKey
513 480 : or dataEnd > endOfBlocks or dataEnd < start
514 480 : or blockEnd > endOfBlocks or blockEnd < start
515 320 : or dataEnd != blockEnd)
516 : {
517 : // So let us see what exactly is wrong and report this.
518 0 : if (blockCount == fMaxBlocks)
519 : {
520 : // Special case where we got all the blocks we
521 : // expected, so the remaining data must be rubbish.
522 : // Don't even bother trying to recover the data.
523 0 : fHandler.OnError(EventHandler::kBufferTooBig, blockHeader);
524 0 : fHadError = true;
525 0 : return;
526 : }
527 0 : if (blockHeader->fDataKey != fgkBlockDataKey)
528 0 : fHandler.OnError(EventHandler::kBadBlockKey, &blockHeader->fDataKey);
529 0 : if (blockEnd > endOfBlocks or blockEnd < start)
530 0 : fHandler.OnError(EventHandler::kBadBlockLength, &blockHeader->fLength);
531 0 : if (dataEnd > endOfBlocks or dataEnd < start)
532 0 : fHandler.OnError(EventHandler::kBadBlockTotalLength, &blockHeader->fTotalLength);
533 0 : if (dataEnd != blockEnd)
534 0 : fHandler.OnError(EventHandler::kBlockLengthMismatch, blockHeader);
535 :
536 : // Stop the decoding if so requested by the user, otherwise
537 : // remember about the error so that we return false from the
538 : // Decode() method and continue decoding.
539 0 : fHadError = true;
540 0 : if (fExitOnError) return;
541 :
542 : // Try to recover from the corrupt header.
543 0 : RecoverResult result = TryRecoverStruct(
544 : fgkBlockDataKey, sizeof(AliMUONBlockHeaderStruct),
545 0 : blockHeader->fTotalLength, blockHeader->fLength,
546 : blockStart, endOfBlocks, dataEnd, blockEnd, current
547 : );
548 0 : if (result == kContinueToNextStruct)
549 0 : continue; // Try the next block at 'current'.
550 0 : if (result == kRecoverFailed) return;
551 0 : }
552 :
553 : // At this point we certainly have a valid block header, so we
554 : // need to check if we have more blocks than we expected. If not
555 : // then we can indicate we have another block and decode its data.
556 320 : if (++blockCount > fMaxBlocks)
557 : {
558 160 : fHandler.OnError(EventHandler::kTooManyBlocks, current);
559 :
560 : // In this case we stop the decoding because clearly
561 : // something is seriously wrong with the data if we are
562 : // getting more blocks than expected.
563 0 : fHadError = true;
564 0 : return;
565 : }
566 :
567 160 : fHandler.OnNewBlock(blockHeader, dataStart);
568 160 : if (not DecodeBlockData(blockHeader, dataStart, dataEnd))
569 : {
570 : // At this point we had a problem decoding the block structure's
571 : // data. Thus we should stop further decoding if so requested by
572 : // the user. Note the fHadError flag is already marked inside
573 : // DecodeBlockData.
574 0 : if (fExitOnError)
575 : {
576 0 : fHandler.OnEndOfBlock(blockHeader, dataStart);
577 0 : return;
578 : }
579 : }
580 160 : fHandler.OnEndOfBlock(blockHeader, dataStart);
581 320 : }
582 160 : }
583 :
584 :
585 : template <class EventHandler>
586 : bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeBlockData(
587 : const AliMUONBlockHeaderStruct* blockHeader,
588 : const UChar_t* start, const UChar_t* end
589 : )
590 : {
591 : /// This method decodes a block structure's data payload. It unpacks the
592 : /// DSP structures contained inside and then for each DSP it calls the
593 : /// OnNewDSP method for the event handler to signal the start of each new
594 : /// DSP structure.
595 : /// \param blockHeader
596 : /// \param start This is the pointer to the start of the block
597 : /// structure's data.
598 : /// \param end This is the pointer to the first byte just past the
599 : /// end of the block structure.
600 : /// \return If the block structure's data was decoded without errors
601 : /// or we could recover from the errors, then true is returned.
602 : /// False is returned otherwise.
603 :
604 320 : const UChar_t* current = start;
605 :
606 : UInt_t dspCount = 0; // Indicates the number of DSPs decoded.
607 1056 : while (current < end)
608 : {
609 : // Mark the start of the DSP structure.
610 : const UChar_t* dspStart = current;
611 :
612 : // Get the DSP header, move the current pointer just past the end
613 : // of the header and check that we have not overflowed the buffer.
614 : const AliMUONDSPHeaderStruct* dspHeader
615 736 : = reinterpret_cast<const AliMUONDSPHeaderStruct*>(dspStart);
616 736 : current += sizeof(AliMUONDSPHeaderStruct);
617 1472 : if (current > end or current < start)
618 : {
619 : // If we overflowed the pointer and already had an error then
620 : // we are clearly lost so just stop decoding before we segfault.
621 0 : if (current < start and fHadError) return false;
622 :
623 : // So we only got part of a DSP header at the very end of
624 : // the block structure buffer. Nothing to do but report the
625 : // error and exit. Set fHadError in case of further decoding.
626 0 : fHandler.OnError(EventHandler::kNoDSPHeader, dspHeader);
627 0 : fHadError = true;
628 0 : return false;
629 : }
630 :
631 : // The header fits the buffer so we can mark the data start and
632 : // read from the header to find the end of data and DSP pointers.
633 : const UChar_t* dataStart = current;
634 736 : current += dspHeader->fLength * sizeof(UInt_t);
635 736 : const UChar_t* dataEnd = current;
636 736 : const UChar_t* dspEnd = dspStart + dspHeader->fTotalLength * sizeof(UInt_t);
637 :
638 : // Now we need to check for the following things:
639 : // 1) Is the end of DSP or end of data pointer outside the buffer
640 : // boundaries.
641 : // 2) Are the values for these pointers the same.
642 : // 3) Is the expected data key in the header present.
643 : // If any of the above fail then we know there is a problem with
644 : // the DSP header. It must be corrupted somehow.
645 1472 : if (dspHeader->fDataKey != fgkDSPDataKey
646 2208 : or dataEnd > end or dataEnd < start
647 2208 : or dspEnd > end or dspEnd < start
648 1472 : or dataEnd != dspEnd)
649 : {
650 : // So let us see what exactly is wrong and report this.
651 0 : if (dspHeader->fDataKey != fgkDSPDataKey)
652 0 : fHandler.OnError(EventHandler::kBadDSPKey, &dspHeader->fDataKey);
653 0 : if (dspEnd > end or dspEnd < start)
654 0 : fHandler.OnError(EventHandler::kBadDSPLength, &dspHeader->fLength);
655 0 : if (dataEnd > end or dataEnd < start)
656 0 : fHandler.OnError(EventHandler::kBadDSPTotalLength, &dspHeader->fTotalLength);
657 0 : if (dataEnd != dspEnd)
658 0 : fHandler.OnError(EventHandler::kDSPLengthMismatch, dspHeader);
659 :
660 : // Indicate we had and error and stop the decoding if so
661 : // requested by the user.
662 0 : fHadError = true;
663 0 : if (fExitOnError) return false;
664 :
665 : // Try to recover from the corrupt header.
666 0 : RecoverResult result = TryRecoverStruct(
667 : fgkDSPDataKey, sizeof(AliMUONDSPHeaderStruct),
668 0 : dspHeader->fTotalLength, dspHeader->fLength,
669 : dspStart, end, dataEnd, dspEnd, current
670 : );
671 0 : if (result == kContinueToNextStruct)
672 0 : continue; // Try the next DSP at 'current'.
673 0 : if (result == kRecoverFailed) return false;
674 0 : }
675 :
676 : // At this point we certainly have a valid DSP header, so we
677 : // need to check if we have more DSPs than we expected. If not
678 : // then we can indicate we have another DSP and decode its data.
679 1472 : if (++dspCount > fMaxDSPs)
680 : {
681 736 : fHandler.OnError(EventHandler::kTooManyDSPs, current);
682 :
683 : // In this case we stop further decoding of the block
684 : // structure data because clearly something is seriously
685 : // wrong if we are getting more DSPs than expected.
686 : // Indicate that we had an error so the Decode() method
687 : // returns false.
688 0 : fHadError = true;
689 0 : return false;
690 : }
691 :
692 736 : fHandler.OnNewDSP(dspHeader, dataStart);
693 :
694 : // Check the error word in the header.
695 736 : if (dspHeader->fErrorWord != 0x0)
696 : {
697 0 : if (dspHeader->fErrorWord == (0x000000B1 | blockHeader->fDSPId)
698 0 : or dspHeader->fErrorWord == (0x00000091 | blockHeader->fDSPId)
699 : )
700 : {
701 : // An event with a glitch in the readout has been detected.
702 : // It means that somewhere a 1 byte word has been randomly
703 : // inserted and all the readout sequence is shifted until
704 : // the next event.
705 0 : fHandler.OnError(EventHandler::kGlitchFound, &dspHeader->fErrorWord);
706 0 : }
707 0 : else if ((dspHeader->fErrorWord & 0x0000FFF0) == 0x220)
708 : {
709 : // Detected a TOKEN_LOST error which can affect the dead time in the DAQ.
710 0 : fHandler.OnError(EventHandler::kTokenLost, &dspHeader->fErrorWord);
711 0 : }
712 : else
713 : {
714 : // The DSP error code is non-zero but has an unknown code.
715 0 : fHandler.OnError(EventHandler::kUnknownDspError, &dspHeader->fErrorWord);
716 : }
717 :
718 0 : fHadError = true;
719 0 : if (fExitOnError)
720 : {
721 0 : fHandler.OnEndOfDSP(dspHeader, dataStart);
722 0 : return false;
723 : }
724 :
725 : // Try recover by finding the very next DSP and continue
726 : // decoding from there. Note: to achieve this all we have to
727 : // do is continue to the next iteration, because the logic
728 : // will land up calling the FindKey method within the
729 : // TryRecoverStruct method above.
730 0 : if (fTryRecover)
731 : {
732 0 : fHandler.OnEndOfDSP(dspHeader, dataStart);
733 0 : continue;
734 : }
735 : }
736 :
737 : // Check if we are padding. If we are, then the bus patch data is
738 : // actually 4 bytes smaller and the last word is a padding word.
739 736 : if (dspHeader->fPaddingWord == 1)
740 : {
741 50 : dataEnd -= sizeof(UInt_t);
742 :
743 : // Check the pad word is correct.
744 50 : const UInt_t* padWord = reinterpret_cast<const UInt_t*>(dataEnd);
745 50 : if (*padWord != fgkPaddingWord)
746 : {
747 0 : fHandler.OnError(EventHandler::kBadPaddingWord, padWord);
748 0 : fHadError = true;
749 0 : if (fExitOnError)
750 : {
751 0 : fHandler.OnEndOfDSP(dspHeader, dataStart);
752 0 : return false;
753 : }
754 : }
755 50 : }
756 :
757 736 : if (not DecodeDSPData(dataStart, dataEnd))
758 : {
759 : // At this point we had a problem decoding the DSP structure's
760 : // data, thus we should stop further decoding if so requested by
761 : // the user. Note the fHadError flag is already marked inside
762 : // DecodeDSPData.
763 0 : if (fExitOnError)
764 : {
765 0 : fHandler.OnEndOfDSP(dspHeader, dataStart);
766 0 : return false;
767 : }
768 : }
769 736 : fHandler.OnEndOfDSP(dspHeader, dataStart);
770 1472 : }
771 :
772 160 : return true;
773 160 : }
774 :
775 :
776 : template <class EventHandler>
777 : bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeDSPData(
778 : const UChar_t* start, const UChar_t* end
779 : )
780 : {
781 : /// This method decodes a DSP structure's data payload. It finds all the
782 : /// bus patches found inside and for each it calls the OnNewBusPatch method
783 : /// for the event handler to signal the start of each new bus patch.
784 : /// \param start This is the pointer to the start of the DSP structure's data.
785 : /// \param end This is the pointer to the first byte just past the
786 : /// end of the DSP structure.
787 : /// \return If the DSP structure's data was decoded without errors
788 : /// or we could recover from the errors, then true is returned.
789 : /// False is returned otherwise.
790 :
791 1472 : const UChar_t* current = start;
792 :
793 : UInt_t busPatchCount = 0; // Indicates the number of bus patches decoded.
794 5024 : while (current < end)
795 : {
796 : // Mark the start of the bus patch structure.
797 : const UChar_t* busPatchStart = current;
798 :
799 : // Get the bus patch header, move the current pointer just past
800 : // the end of the header and check that we have not overflowed
801 : // the buffer.
802 : const AliMUONBusPatchHeaderStruct* busPatchHeader
803 3552 : = reinterpret_cast<const AliMUONBusPatchHeaderStruct*>(busPatchStart);
804 3552 : current += sizeof(AliMUONBusPatchHeaderStruct);
805 7104 : if (current > end or current < start)
806 : {
807 : // If we overflowed the pointer and already had an error then
808 : // we are clearly lost so just stop decoding before we segfault.
809 0 : if (current < start and fHadError) return false;
810 :
811 : // So we only got part of a bus patch header at the very
812 : // end of the DSP structure buffer. Nothing to do but
813 : // report the error and exit. Set fHadError in case of
814 : // further decoding.
815 0 : fHandler.OnError(EventHandler::kNoBusPatchHeader, busPatchHeader);
816 0 : fHadError = true;
817 0 : return false;
818 : }
819 :
820 : // The header fits the buffer so we can mark the data start and
821 : // read from the header to find the end of data and bus patch
822 : // structure pointers.
823 : const UChar_t* dataStart = current;
824 3552 : current += busPatchHeader->fLength * sizeof(UInt_t);
825 3552 : const UChar_t* dataEnd = current;
826 7104 : const UChar_t* busPatchEnd = busPatchStart
827 3552 : + busPatchHeader->fTotalLength * sizeof(UInt_t);
828 :
829 : // Now we need to check for the following things:
830 : // 1) Is the end of bus patch structure or end of data pointer
831 : // outside the buffer boundaries.
832 : // 2) Are the values for these pointers the same.
833 : // 3) Is the expected data key in the header present.
834 : // If any of the above fail then we know there is a problem with
835 : // the bus patch header. It must be corrupted somehow.
836 7104 : if (busPatchHeader->fDataKey != fgkBusPatchDataKey
837 10656 : or dataEnd > end or dataEnd < start
838 10656 : or busPatchEnd > end or busPatchEnd < start
839 7104 : or dataEnd != busPatchEnd)
840 : {
841 : // So let us see what exactly is wrong and report this.
842 0 : if (busPatchHeader->fDataKey != fgkBusPatchDataKey)
843 0 : fHandler.OnError(EventHandler::kBadBusPatchKey, &busPatchHeader->fDataKey);
844 0 : if (busPatchEnd > end or busPatchEnd < start)
845 0 : fHandler.OnError(EventHandler::kBadBusPatchLength, &busPatchHeader->fLength);
846 0 : if (dataEnd > end or dataEnd < start)
847 0 : fHandler.OnError(EventHandler::kBadBusPatchTotalLength, &busPatchHeader->fTotalLength);
848 0 : if (dataEnd != busPatchEnd)
849 0 : fHandler.OnError(EventHandler::kBusPatchLengthMismatch, busPatchHeader);
850 :
851 : // Indicate we had and error and stop the decoding if so
852 : // requested by the user.
853 0 : fHadError = true;
854 0 : if (fExitOnError) return false;
855 :
856 : // Try to recover from the corrupt header.
857 0 : RecoverResult result = TryRecoverStruct(
858 : fgkBusPatchDataKey, sizeof(AliMUONBusPatchHeaderStruct),
859 0 : busPatchHeader->fTotalLength, busPatchHeader->fLength,
860 : busPatchStart, end, dataEnd, busPatchEnd, current
861 : );
862 0 : if (result == kContinueToNextStruct)
863 0 : continue; // Try the next bus patch at 'current'.
864 0 : if (result == kRecoverFailed) return false;
865 0 : }
866 :
867 : // At this point we certainly have a valid bus patch header, so
868 : // we need to check if we have more bus patches than we expected.
869 : // If not then we can indicate we have another bus patch and
870 : // decode its data.
871 7104 : if (++busPatchCount > fMaxBusPatches)
872 : {
873 3552 : fHandler.OnError(EventHandler::kTooManyBusPatches, current);
874 :
875 : // In this case we stop further decoding of the DSP
876 : // structure's data because clearly something is seriously
877 : // wrong if we are getting more bus patches than expected.
878 : // Indicate that we had an error so the Decode() method
879 : // returns false.
880 0 : fHadError = true;
881 0 : return false;
882 : }
883 :
884 3552 : fHandler.OnNewBusPatch(busPatchHeader, dataStart);
885 3552 : if (not DecodeBusPatchData(dataStart, dataEnd))
886 : {
887 : // At this point we had a problem decoding the bus patch data,
888 : // thus we should stop further decoding if so requested by the
889 : // user. Note the fHadError flag is already marked inside
890 : // DecodeBusPatchData.
891 0 : if (fExitOnError)
892 : {
893 0 : fHandler.OnEndOfBusPatch(busPatchHeader, dataStart);
894 0 : return false;
895 : }
896 : }
897 3552 : fHandler.OnEndOfBusPatch(busPatchHeader, dataStart);
898 7104 : }
899 :
900 736 : return true;
901 736 : }
902 :
903 :
904 : template <class EventHandler>
905 : bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeBusPatchData(
906 : const UChar_t* start, const UChar_t* end
907 : )
908 : {
909 : /// This method decodes a single bus patch's data payload.
910 : /// It will check the parity of the raw data words and send them
911 : /// to the event handler instance with calls to OnData.
912 : /// \param start This is the pointer to the start of the bus patch
913 : /// structure's data.
914 : /// \param end This is the pointer to the first byte just past the
915 : /// end of the bus patch structure.
916 : /// \return If the bus patch's data was decoded without errors
917 : /// or we could recover from the errors, then true is returned.
918 : /// False is returned otherwise.
919 :
920 : // Assert that 'end' is always larger than start by n*sizeof(UInt_t)
921 : // where n is a positive integer. This should be the case because we
922 : // always add multiples of sizeof(UInt_t) to the 'current' pointer in
923 : // all the DecodeXYZ methods.
924 7104 : assert( UInt_t(end - start) % 4 == 0 );
925 :
926 : // Now step through all the data words and issue OnData events.
927 : // We also need to check parity and signal OnError if it is not valid
928 : // for any of the data words.
929 3552 : const UInt_t* data = reinterpret_cast<const UInt_t*>(start);
930 3552 : const UInt_t* dataEnd = reinterpret_cast<const UInt_t*>(end);
931 8520 : for (; data < dataEnd; data++)
932 : {
933 1416 : if (ParityIsOk(*data))
934 : {
935 1416 : fHandler.OnData(*data, false);
936 708 : }
937 : else
938 : {
939 : // Indicate we had a parity error and exit immediately
940 : // if the user so requested.
941 0 : fHandler.OnError(EventHandler::kParityError, data);
942 0 : fHadError = true;
943 0 : if (fExitOnError) return false;
944 :
945 0 : if (fSendDataOnParityError)
946 0 : fHandler.OnData(*data, true);
947 : }
948 : }
949 :
950 3552 : return true;
951 3552 : }
952 :
953 :
954 : template <class EventHandler>
955 : typename AliMUONTrackerDDLDecoder<EventHandler>::RecoverResult
956 : AliMUONTrackerDDLDecoder<EventHandler>::TryRecoverStruct(
957 : UInt_t expectedKey,
958 : UInt_t headerSize,
959 : UInt_t totalLength,
960 : UInt_t length,
961 : const UChar_t* structStart,
962 : const UChar_t* bufferEnd,
963 : const UChar_t*& dataEnd,
964 : const UChar_t*& structEnd,
965 : const UChar_t*& current
966 : )
967 : {
968 : /// This method attempts to recover from a corrupt structure header by
969 : /// figuring out which of the structure size indicators is correct.
970 : /// This is possible because each header has some redundant information.
971 : /// The recovery procedure is only attempted if fTryRecover was set to
972 : /// true. If the recovery procedure is successful then this method will
973 : /// also update the pointers indicating the start of data, end of structure
974 : /// and current parsing position with the correct values.
975 : ///
976 : /// [in] \param expectedKey This is the expected block key for the header
977 : /// currently being processed.
978 : /// [in] \param headerSize The expected header size as given by the sizeof
979 : /// operator for example.
980 : /// [in] \param totalLength The total length as given by the fTotalLength
981 : /// field in the current header being handled.
982 : /// [in] \param length The data length as given by the fLength field
983 : /// in the current header being handled.
984 : /// [in] \param structStart A pointer to the start of the structure header.
985 : /// [in] \param bufferEnd A pointer to the first byte just past the end
986 : /// of the buffer. This could be the pointer to the first byte
987 : /// just past the end of the parent structure if we are dealing
988 : /// with a DSP structure or bus patch. The parent structure for
989 : /// the DSP is a block structure and for a bus patch it is a DSP.
990 : /// [out] \param dataEnd This is the pointer to the first byte just past
991 : /// the end of the structure being processed. It should be equal to
992 : /// structStart + sizeof(structure header) + fLength, where fLength
993 : /// is the field found in the structure's header itself. This value
994 : /// will be corrected and updated if we could recover from the
995 : /// corruption in the header.
996 : /// [out] \param structEnd A pointer to the first byte just past the end of
997 : /// the structure. This value should be set equal to
998 : /// structStart + fTotalLength * sizeof(UInt_t), where fTotalLength
999 : /// is the field found in the structure's header itself. This value
1000 : /// will be corrected and updated if we could recover from the
1001 : /// corruption in the header.
1002 : /// [out] \param current This is the pointer to the current location in
1003 : /// the DDL payload being parsed. It should in principle point
1004 : /// to the start of the structures data. This value will be
1005 : /// corrected and updated if we could recover from the corruption
1006 : /// in the header.
1007 : ///
1008 : /// \return Returns the result of the recovery attempt, which can be one
1009 : /// of the following:
1010 : /// kRecoverFailed - The recovery failed completely so the caller
1011 : /// cannot continue parsing any more structures. If the failure
1012 : /// is within a DSP then one could still continue parsing
1013 : /// from the next block. Similarly for bus patches, parsing could
1014 : /// continue from the next DSP structure.
1015 : /// kStructRecovered - Indicates that we recovered from a corrupt
1016 : /// structure header and can continue processing the data of the
1017 : /// structure in question.
1018 : /// kContinueToNextStruct - Either fTryRecover was set to false or we
1019 : /// could not recover from the corrupt header but we did find the
1020 : /// start of another header matching the expected key so parsing
1021 : /// can continue from the updated current position.
1022 :
1023 : // Check if the user wants us to try and recover from a corrupt header.
1024 0 : if (not fTryRecover) return kContinueToNextStruct;
1025 :
1026 : // If the user wants us to try recover, then try to recover what the
1027 : // correct values for dataEnd, structEnd and current were supposed to be.
1028 : // The recovery procedure is as follows: We have 4 conditions for a correct
1029 : // header:
1030 : // 1) The header key is what we expect.
1031 : // 2) The totalLength equals length + headerSize.
1032 : // 3) The word at dataEnd contains a valid key. (implies length is
1033 : // correct.)
1034 : // 4) The word at structEnd contains a valid key. (implies totalLength
1035 : // is correct.)
1036 : // If any 2 of these conditions hold then we know that only one of the
1037 : // header fields is corrupt and we have enough information to reconstruct
1038 : // the third field. Note that if conditions 3 and 4 are true then this
1039 : // implies 2 is also true. (not necessarily the other way around though.)
1040 : // The valid key mentioned above at dataEnd and structEnd should be:
1041 : // a) A bus patch key, DSP key or end of buffer if expectedKey indicates
1042 : // a buspatch.
1043 : // b) A DSP key, block structure key or end of buffer if expectedKey
1044 : // indicates a DSP.
1045 : // c) A block structure key or end of buffer if expectedKey indicates
1046 : // a DSP.
1047 0 : const UInt_t* headerKey = reinterpret_cast<const UInt_t*>(structStart);
1048 0 : bool headerKeyOk = (expectedKey == *headerKey);
1049 :
1050 0 : bool lengthsMatch = (totalLength*4 == length*4 + headerSize);
1051 :
1052 : bool lengthIsCorrect = false;
1053 : bool totalLengthIsCorrect = false;
1054 0 : const UInt_t* keyAtDataEnd = reinterpret_cast<const UInt_t*>(dataEnd);
1055 0 : const UInt_t* keyAtStructEnd = reinterpret_cast<const UInt_t*>(structEnd);
1056 :
1057 :
1058 0 : if ( expectedKey == fgkBlockDataKey )
1059 : {
1060 0 : if (dataEnd == bufferEnd)
1061 : {
1062 : // Are we at the end of the buffer?
1063 : lengthIsCorrect = true;
1064 0 : }
1065 : else
1066 : {
1067 : // Must check that we can read another 4 bytes before
1068 : // checking the key at dataEnd.
1069 0 : if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
1070 : {
1071 0 : if (*keyAtDataEnd == fgkBlockDataKey)
1072 0 : lengthIsCorrect = true;
1073 : }
1074 : }
1075 :
1076 0 : if (structEnd == bufferEnd)
1077 : {
1078 : // Are we at the end of the buffer?
1079 : totalLengthIsCorrect = true;
1080 0 : }
1081 : else
1082 : {
1083 : // Must check that we can read another 4 bytes before
1084 : // checking the key at structEnd.
1085 0 : if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
1086 : {
1087 0 : if (*keyAtStructEnd == fgkBlockDataKey)
1088 0 : totalLengthIsCorrect = true;
1089 : }
1090 : }
1091 : }
1092 :
1093 0 : else if ( expectedKey == fgkDSPDataKey )
1094 : {
1095 0 : if (dataEnd == bufferEnd)
1096 : {
1097 : // Are we at the end of the buffer?
1098 : lengthIsCorrect = true;
1099 0 : }
1100 : else
1101 : {
1102 : // Must check that we can read another 4 bytes before
1103 : // checking the key at dataEnd.
1104 0 : if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
1105 : {
1106 0 : if (*keyAtDataEnd == fgkBlockDataKey
1107 0 : or *keyAtDataEnd == fgkDSPDataKey)
1108 0 : lengthIsCorrect = true;
1109 : }
1110 : }
1111 :
1112 0 : if (structEnd == bufferEnd)
1113 : {
1114 : // Are we at the end of the buffer?
1115 : totalLengthIsCorrect = true;
1116 0 : }
1117 : else
1118 : {
1119 : // Must check that we can read another 4 bytes before
1120 : // checking the key at structEnd.
1121 0 : if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
1122 : {
1123 0 : if (*keyAtStructEnd == fgkBlockDataKey
1124 0 : or *keyAtStructEnd == fgkDSPDataKey)
1125 0 : totalLengthIsCorrect = true;
1126 : }
1127 : }
1128 : }
1129 0 : else if ( expectedKey == fgkBusPatchDataKey )
1130 : {
1131 0 : if (dataEnd == bufferEnd)
1132 : {
1133 : // Are we at the end of the buffer?
1134 : lengthIsCorrect = true;
1135 0 : }
1136 : else
1137 : {
1138 : // Must check that we can read another 4 bytes before
1139 : // checking the key at dataEnd.
1140 0 : if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
1141 : {
1142 0 : if (*keyAtDataEnd == fgkDSPDataKey
1143 0 : or *keyAtDataEnd == fgkBusPatchDataKey)
1144 0 : lengthIsCorrect = true;
1145 : }
1146 : }
1147 :
1148 0 : if (structEnd == bufferEnd)
1149 : {
1150 : // Are we at the end of the buffer?
1151 : totalLengthIsCorrect = true;
1152 0 : }
1153 : else
1154 : {
1155 : // Must check that we can read another 4 bytes before
1156 : // checking the key at structEnd.
1157 0 : if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
1158 : {
1159 0 : if (*keyAtStructEnd == fgkDSPDataKey
1160 0 : or *keyAtStructEnd == fgkBusPatchDataKey)
1161 0 : totalLengthIsCorrect = true;
1162 : }
1163 : }
1164 : }
1165 :
1166 0 : if (headerKeyOk and lengthIsCorrect)
1167 : {
1168 : // totalLength was wrong, dataEnd is correct.
1169 0 : structEnd = dataEnd;
1170 0 : current = dataEnd;
1171 0 : return kStructRecovered;
1172 : }
1173 0 : if (headerKeyOk and totalLengthIsCorrect)
1174 : {
1175 : // Length was wrong, structEnd is correct.
1176 0 : dataEnd = structEnd;
1177 0 : current = structEnd;
1178 0 : return kStructRecovered;
1179 : }
1180 0 : if (lengthsMatch and lengthIsCorrect and totalLengthIsCorrect)
1181 : {
1182 : // The header's key was wrong but the lengths and pointers are OK.
1183 0 : return kStructRecovered;
1184 : }
1185 :
1186 : // Could not recover the header from the available information, so find
1187 : // the next key in the stream that is the same as the currently expected
1188 : // one and continue decoding from there.
1189 0 : const UChar_t* location = FindKey(
1190 0 : expectedKey, structStart + sizeof(UInt_t), bufferEnd
1191 : );
1192 0 : if (location != NULL)
1193 : {
1194 0 : current = location;
1195 0 : return kContinueToNextStruct;
1196 : }
1197 :
1198 0 : return kRecoverFailed;
1199 0 : }
1200 :
1201 :
1202 : template <class EventHandler>
1203 : const UChar_t* AliMUONTrackerDDLDecoder<EventHandler>::FindKey(
1204 : UInt_t key, const UChar_t* start, const UChar_t* end
1205 : )
1206 : {
1207 : /// Searches for the first occurrence of the key value in the buffer marked by
1208 : /// 'start' and 'end'. 'start' should point to the start of the buffer and 'end'
1209 : /// should point to 'start + bufferSize', i.e. just past the last byte of the
1210 : /// buffer. If the key was found then the pointer to that location is returned
1211 : /// otherwise NULL is returned.
1212 :
1213 0 : if (end + sizeof(UInt_t) < start) return NULL; // check for pointer overflow.
1214 : const UChar_t* current = start;
1215 0 : while (current + sizeof(UInt_t) <= end)
1216 : {
1217 0 : UInt_t data = * reinterpret_cast<const UInt_t*>(current);
1218 0 : if (data == key) return current;
1219 0 : current++;
1220 0 : }
1221 0 : return NULL;
1222 0 : }
1223 :
1224 :
1225 : template <class EventHandler>
1226 : bool AliMUONTrackerDDLDecoder<EventHandler>::ParityIsOk(UInt_t data)
1227 : {
1228 : /// Optimised parity check addapted from:
1229 : /// http://graphics.stanford.edu/~seander/bithacks.html#ParityParallel
1230 :
1231 : // parity of the 32 bits must be zero if the last bit is equal
1232 : // to the parity of the first 31 bits.
1233 : // Reason: the parity bit xor the parity of the first 31 bits must give
1234 : // zero, unless there was a bit error.
1235 1416 : data ^= data >> 16;
1236 708 : data ^= data >> 8;
1237 708 : data ^= data >> 4;
1238 708 : data &= 0xf;
1239 708 : data = ((0x6996 >> data) & 1);
1240 708 : return data == 0;
1241 : }
1242 :
1243 : #endif // ALIMUONTRACKERDDLDECODER_H
|