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