bug fixed
[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
fd2624ba 40#include <string.h>
e3a2b9c9 41#include "AliMUONTrackerDDLDecoderEventHandler.h"
42
e3a2b9c9 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.
24a0fe9f 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.
e3a2b9c9 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.
24a0fe9f 58/// To actually do something with the data, one needs to implement a custom
e3a2b9c9 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:
24a0fe9f 65/// void OnData(UInt_t data, bool parityError)
e3a2b9c9 66/// {
24a0fe9f 67/// // I can do something with 'data' here and check if there was
68/// // a parity error with 'parityError'.
e3a2b9c9 69/// }
70/// };
71/// \endcode
72///
24a0fe9f 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
e3a2b9c9 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
24a0fe9f 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
e3a2b9c9 85/// AliMUONTrackerDDLDecoderEventHandler abstract and using virtual methods.
86///
29b6be6a 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///
e3a2b9c9 99/// \author Artur Szostak <artursz@iafrica.com>
100
101template <class EventHandler>
102class AliMUONTrackerDDLDecoder
103{
104public:
105
106 /// Default contructor.
107 AliMUONTrackerDDLDecoder() :
108 fExitOnError(true), fTryRecover(false),
109 fSendDataOnParityError(false), fHadError(false),
29b6be6a 110 fAutoDetectTrailer(true), fCheckForTrailer(true),
e3a2b9c9 111 fMaxBlocks(2), fMaxDSPs(5), fMaxBusPatches(5), fHandler()
112 {}
113
114 /// Constant method to return the event handler instance.
115 const EventHandler& GetHandler() const { return fHandler; }
116
117 /// Returns the event handler instance.
118 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 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
29b6be6a 130 /// payload headers or trailers.
e3a2b9c9 131 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
29b6be6a 135 /// payload headers or trailers.
e3a2b9c9 136 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 void SendDataOnParityError(bool value) { fSendDataOnParityError = value; }
147
148 /// Returns the maximum block count expected in the DDL payload.
149 UInt_t MaxBlocks() const { return fMaxBlocks; }
150
151 /// Sets the maximum block count expected in the DDL payload.
152 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 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 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 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 void MaxBusPatches(UInt_t n) { fMaxBusPatches = n; }
169
29b6be6a 170 /// Returns the value of the auto-detect trailer flag.
171 bool AutoDetectTrailer() const { return fAutoDetectTrailer; }
172
173 /// Sets the value of the auto-detect trailer flag.
174 void AutoDetectTrailer(bool value) { fAutoDetectTrailer = value; }
175
176 /// Returns the value of the flag to check for the end of DDL trailer.
177 bool CheckForTrailer() const { return fCheckForTrailer; }
178
179 /// Sets the value of the flag to check for the end of DDL trailer.
180 void CheckForTrailer(bool value) { fCheckForTrailer = value; }
181
e3a2b9c9 182 /// This method decodes the DDL payload contained in the buffer.
183 bool Decode(const void* buffer, UInt_t bufferSize);
184
fa9a7065 185 /// First try fix data corruption and then decode the DDL payload.
186 bool Decode(void* buffer, UInt_t bufferSize);
187
1788245f 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
e3a2b9c9 203private:
204
205 bool fExitOnError; ///< Indicates if we should exit on the very first error.
29b6be6a 206 bool fTryRecover; ///< Indicates if we should try recover from a corrupt structure header or DDL trailer.
e3a2b9c9 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.
29b6be6a 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.
e3a2b9c9 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
8a0dae7c 216 void DecodeBuffer(const UChar_t* start, const UChar_t* end);
217
e3a2b9c9 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.
29b6be6a 257 static const UInt_t fgkEndOfDDL; ///< The end of DDL trailer word.
e3a2b9c9 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.
264template <class EventHandler>
265const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkBlockDataKey = 0xFC0000FC;
266template <class EventHandler>
267const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkDSPDataKey = 0xF000000F;
268template <class EventHandler>
269const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkBusPatchDataKey = 0xB000000B;
270template <class EventHandler>
271const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkPaddingWord = 0xBEEFFACE;
29b6be6a 272template <class EventHandler>
273const UInt_t AliMUONTrackerDDLDecoder<EventHandler>::fgkEndOfDDL = 0xD000000D;
e3a2b9c9 274
275
e3a2b9c9 276template <class EventHandler>
277bool 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).
29b6be6a 295 /// fTryRecover set to true will also enable recovery from a corrupt
296 /// DDL trailer marking the end of DDL payload.
e3a2b9c9 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 assert( buffer != NULL );
310
311 fHadError = false;
312
313 // We are basically implementing something like a recursive decent parser.
8a0dae7c 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 const UChar_t* end = start + bufferSize;
e3a2b9c9 317
e3a2b9c9 318 fHandler.OnNewBuffer(buffer, bufferSize);
8a0dae7c 319 DecodeBuffer(start, end);
320 fHandler.OnEndOfBuffer(buffer, bufferSize);
321 return not fHadError;
322}
323
324
325template <class EventHandler>
fa9a7065 326bool 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 assert( buffer != NULL );
334 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 UInt_t* bufferInt = reinterpret_cast<UInt_t*>(buffer);
343 if (bufferSize > 18*4 // is the buffer large enough to check the header.
344 and bufferInt[0] != fgkBlockDataKey and bufferInt[16] == fgkBlockDataKey // was the header incorrectly moved.
345 and bufferSize > bufferInt[17]*4 + sizeof(AliMUONBlockHeaderStruct) // is the buffer large enough for the second block header.
346 and bufferInt[bufferInt[17]] == fgkBlockDataKey // Check that the second header is in the correct location.
347 and bufferInt[17] == bufferInt[18] + 8 // Make sure that both lengths are correct.
348 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 UChar_t tmpbuf[16*4];
352 memcpy(tmpbuf, bufferChar, 16*4);
353 size_t sizeToMove = bufferInt[17]*4-16*4;
354 memmove(bufferChar, bufferChar+16*4, sizeToMove);
355 memcpy(bufferChar + sizeToMove, tmpbuf, 16*4);
356 }
357 }
358 return Decode(reinterpret_cast<const void*>(buffer), bufferSize);
359}
360
361
362template <class EventHandler>
8a0dae7c 363void 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.
7795d339 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.
8a0dae7c 377
378 const UChar_t* current = start;
29b6be6a 379 const UInt_t* bufferStart = reinterpret_cast<const UInt_t*>(start);
380 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
24a0fe9f 385 // data so if we are auto-detecting the trailer then we need to carefully
29b6be6a 386 // check if these words are there or not.
387 const UChar_t* endOfBlocks = end;
388 const UInt_t* trailerWords = reinterpret_cast<const UInt_t*>(end) - 2;
389 if (fAutoDetectTrailer)
390 {
009fa22b 391 if (trailerWords >= bufferStart and trailerWords < bufferEnd
392 and *trailerWords == fgkEndOfDDL and *(trailerWords+1) == fgkEndOfDDL
29b6be6a 393 )
394 {
395 // Found the trailer so reposition the end of blocks marker.
396 endOfBlocks = reinterpret_cast<const UChar_t*>(trailerWords);
397 }
398 // else assume we are dealing with the older data format.
399 }
400 else if (fCheckForTrailer)
401 {
009fa22b 402 if (trailerWords >= bufferStart and trailerWords < bufferEnd
403 and *trailerWords == fgkEndOfDDL and *(trailerWords+1) == fgkEndOfDDL
29b6be6a 404 )
405 {
406 // Found the trailer so reposition the end of blocks marker.
407 endOfBlocks = reinterpret_cast<const UChar_t*>(trailerWords);
408 }
409 else
410 {
009fa22b 411 if (trailerWords+1 >= bufferStart and trailerWords+1 < bufferEnd and *(trailerWords+1) == fgkEndOfDDL)
29b6be6a 412 fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords+1);
009fa22b 413 else if (trailerWords >= bufferStart and trailerWords < bufferEnd and *(trailerWords) == fgkEndOfDDL)
29b6be6a 414 fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords);
415 else
416 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 fHadError = true;
422 if (fExitOnError) return;
423
424 // Mark that there was a problem with the trailer so that
24a0fe9f 425 // for subsequent errors we try to deal with this better.
29b6be6a 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 if (fTryRecover)
432 {
433 trailerWords = bufferEnd;
434 // There should only be a max of 2 trailer words.
009fa22b 435 if (trailerWords-2 >= bufferStart and trailerWords-2 < bufferEnd and *(trailerWords-2) == fgkEndOfDDL)
436 trailerWords -= 2;
437 else if (trailerWords-1 >= bufferStart and trailerWords-1 < bufferEnd and *(trailerWords-1) == fgkEndOfDDL)
438 trailerWords -= 1;
29b6be6a 439 endOfBlocks = reinterpret_cast<const UChar_t*>(trailerWords);
440 }
441 }
442 }
e3a2b9c9 443
444 UInt_t blockCount = 0; // Indicates the number of blocks decoded.
29b6be6a 445 while (current < endOfBlocks)
e3a2b9c9 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 = reinterpret_cast<const AliMUONBlockHeaderStruct*>(blockStart);
454 current += sizeof(AliMUONBlockHeaderStruct);
009fa22b 455 if (current > endOfBlocks or current < start)
e3a2b9c9 456 {
009fa22b 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 if (current < start and fHadError) return;
460
29b6be6a 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 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 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 if (problemWithTrailer) return;
473
474 if (fAutoDetectTrailer)
475 {
476 // If we got here then there is at least one correct trailer
24a0fe9f 477 // word, but since we did not detect a correct trailer then
29b6be6a 478 // there must be only one. Announce the error and exit.
479 fHandler.OnError(EventHandler::kTooFewDDLTrailerWords, trailerWords);
480 fHadError = true;
481 return;
482 }
483 }
484
e3a2b9c9 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 if (blockCount == fMaxBlocks)
488 // Special case where we got all the blocks we
489 // expected, so the remaining data must be rubbish.
490 fHandler.OnError(EventHandler::kBufferTooBig, blockHeader);
491 else
492 fHandler.OnError(EventHandler::kNoBlockHeader, blockHeader);
8a0dae7c 493 fHadError = true;
494 return;
e3a2b9c9 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 current += blockHeader->fLength * sizeof(UInt_t);
501 const UChar_t* dataEnd = current;
502 const UChar_t* blockEnd = blockStart
503 + 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 if (blockHeader->fDataKey != fgkBlockDataKey
009fa22b 513 or dataEnd > endOfBlocks or dataEnd < start
514 or blockEnd > endOfBlocks or blockEnd < start
515 or dataEnd != blockEnd)
e3a2b9c9 516 {
517 // So let us see what exactly is wrong and report this.
518 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 fHandler.OnError(EventHandler::kBufferTooBig, blockHeader);
8a0dae7c 524 fHadError = true;
525 return;
e3a2b9c9 526 }
527 if (blockHeader->fDataKey != fgkBlockDataKey)
528 fHandler.OnError(EventHandler::kBadBlockKey, &blockHeader->fDataKey);
009fa22b 529 if (blockEnd > endOfBlocks or blockEnd < start)
e3a2b9c9 530 fHandler.OnError(EventHandler::kBadBlockLength, &blockHeader->fLength);
009fa22b 531 if (dataEnd > endOfBlocks or dataEnd < start)
e3a2b9c9 532 fHandler.OnError(EventHandler::kBadBlockTotalLength, &blockHeader->fTotalLength);
533 if (dataEnd != blockEnd)
534 fHandler.OnError(EventHandler::kBlockLengthMismatch, blockHeader);
535
536 // Stop the decoding if so requested by the user, otherwise
8a0dae7c 537 // remember about the error so that we return false from the
538 // Decode() method and continue decoding.
539 fHadError = true;
540 if (fExitOnError) return;
e3a2b9c9 541
542 // Try to recover from the corrupt header.
543 RecoverResult result = TryRecoverStruct(
544 fgkBlockDataKey, sizeof(AliMUONBlockHeaderStruct),
545 blockHeader->fTotalLength, blockHeader->fLength,
29b6be6a 546 blockStart, endOfBlocks, dataEnd, blockEnd, current
e3a2b9c9 547 );
548 if (result == kContinueToNextStruct)
549 continue; // Try the next block at 'current'.
8a0dae7c 550 if (result == kRecoverFailed) return;
e3a2b9c9 551 }
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 if (++blockCount > fMaxBlocks)
557 {
558 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.
8a0dae7c 563 fHadError = true;
564 return;
e3a2b9c9 565 }
566
567 fHandler.OnNewBlock(blockHeader, dataStart);
8a0dae7c 568 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 if (fExitOnError)
575 {
576 fHandler.OnEndOfBlock(blockHeader, dataStart);
577 return;
578 }
579 }
580 fHandler.OnEndOfBlock(blockHeader, dataStart);
e3a2b9c9 581 }
e3a2b9c9 582}
583
584
585template <class EventHandler>
586bool 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 const UChar_t* current = start;
605
606 UInt_t dspCount = 0; // Indicates the number of DSPs decoded.
607 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 = reinterpret_cast<const AliMUONDSPHeaderStruct*>(dspStart);
616 current += sizeof(AliMUONDSPHeaderStruct);
009fa22b 617 if (current > end or current < start)
e3a2b9c9 618 {
009fa22b 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 if (current < start and fHadError) return false;
622
e3a2b9c9 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 fHandler.OnError(EventHandler::kNoDSPHeader, dspHeader);
627 fHadError = true;
628 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 current += dspHeader->fLength * sizeof(UInt_t);
635 const UChar_t* dataEnd = current;
636 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 if (dspHeader->fDataKey != fgkDSPDataKey
009fa22b 646 or dataEnd > end or dataEnd < start
647 or dspEnd > end or dspEnd < start
648 or dataEnd != dspEnd)
e3a2b9c9 649 {
650 // So let us see what exactly is wrong and report this.
651 if (dspHeader->fDataKey != fgkDSPDataKey)
652 fHandler.OnError(EventHandler::kBadDSPKey, &dspHeader->fDataKey);
009fa22b 653 if (dspEnd > end or dspEnd < start)
e3a2b9c9 654 fHandler.OnError(EventHandler::kBadDSPLength, &dspHeader->fLength);
009fa22b 655 if (dataEnd > end or dataEnd < start)
e3a2b9c9 656 fHandler.OnError(EventHandler::kBadDSPTotalLength, &dspHeader->fTotalLength);
657 if (dataEnd != dspEnd)
658 fHandler.OnError(EventHandler::kDSPLengthMismatch, dspHeader);
659
660 // Indicate we had and error and stop the decoding if so
661 // requested by the user.
662 fHadError = true;
663 if (fExitOnError) return false;
664
665 // Try to recover from the corrupt header.
666 RecoverResult result = TryRecoverStruct(
667 fgkDSPDataKey, sizeof(AliMUONDSPHeaderStruct),
668 dspHeader->fTotalLength, dspHeader->fLength,
669 dspStart, end, dataEnd, dspEnd, current
670 );
671 if (result == kContinueToNextStruct)
672 continue; // Try the next DSP at 'current'.
673 if (result == kRecoverFailed) return false;
674 }
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 if (++dspCount > fMaxDSPs)
680 {
681 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 fHadError = true;
689 return false;
690 }
691
692 fHandler.OnNewDSP(dspHeader, dataStart);
693
694 // Check the error word in the header.
74585128 695 if (dspHeader->fErrorWord != 0x0)
e3a2b9c9 696 {
74585128 697 if (dspHeader->fErrorWord == (0x000000B1 | blockHeader->fDSPId)
698 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 fHandler.OnError(EventHandler::kGlitchFound, &dspHeader->fErrorWord);
706 }
707 else if ((dspHeader->fErrorWord & 0x0000FFF0) == 0x220)
708 {
709 // Detected a TOKEN_LOST error which can affect the dead time in the DAQ.
710 fHandler.OnError(EventHandler::kTokenLost, &dspHeader->fErrorWord);
711 }
712 else
713 {
714 // The DSP error code is non-zero but has an unknown code.
715 fHandler.OnError(EventHandler::kUnknownDspError, &dspHeader->fErrorWord);
716 }
717
e3a2b9c9 718 fHadError = true;
8a0dae7c 719 if (fExitOnError)
720 {
721 fHandler.OnEndOfDSP(dspHeader, dataStart);
722 return false;
723 }
e3a2b9c9 724
725 // Try recover by finding the very next DSP and continue
6d8d716c 726 // decoding from there. Note: to achieve this all we have to
727 // do is continue to the next iteration, because the logic
e3a2b9c9 728 // will land up calling the FindKey method within the
729 // TryRecoverStruct method above.
6d8d716c 730 if (fTryRecover)
731 {
732 fHandler.OnEndOfDSP(dspHeader, dataStart);
733 continue;
734 }
e3a2b9c9 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 if (dspHeader->fPaddingWord == 1)
740 {
741 dataEnd -= sizeof(UInt_t);
742
743 // Check the pad word is correct.
744 const UInt_t* padWord = reinterpret_cast<const UInt_t*>(dataEnd);
745 if (*padWord != fgkPaddingWord)
746 {
747 fHandler.OnError(EventHandler::kBadPaddingWord, padWord);
748 fHadError = true;
8a0dae7c 749 if (fExitOnError)
750 {
751 fHandler.OnEndOfDSP(dspHeader, dataStart);
752 return false;
753 }
e3a2b9c9 754 }
755 }
756
8a0dae7c 757 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 if (fExitOnError)
764 {
765 fHandler.OnEndOfDSP(dspHeader, dataStart);
766 return false;
767 }
768 }
769 fHandler.OnEndOfDSP(dspHeader, dataStart);
e3a2b9c9 770 }
771
772 return true;
773}
774
775
776template <class EventHandler>
777bool 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 const UChar_t* current = start;
792
793 UInt_t busPatchCount = 0; // Indicates the number of bus patches decoded.
794 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 = reinterpret_cast<const AliMUONBusPatchHeaderStruct*>(busPatchStart);
804 current += sizeof(AliMUONBusPatchHeaderStruct);
009fa22b 805 if (current > end or current < start)
e3a2b9c9 806 {
009fa22b 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 if (current < start and fHadError) return false;
810
e3a2b9c9 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 fHandler.OnError(EventHandler::kNoBusPatchHeader, busPatchHeader);
816 fHadError = true;
817 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 current += busPatchHeader->fLength * sizeof(UInt_t);
825 const UChar_t* dataEnd = current;
826 const UChar_t* busPatchEnd = busPatchStart
827 + 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 if (busPatchHeader->fDataKey != fgkBusPatchDataKey
009fa22b 837 or dataEnd > end or dataEnd < start
838 or busPatchEnd > end or busPatchEnd < start
839 or dataEnd != busPatchEnd)
e3a2b9c9 840 {
841 // So let us see what exactly is wrong and report this.
842 if (busPatchHeader->fDataKey != fgkBusPatchDataKey)
843 fHandler.OnError(EventHandler::kBadBusPatchKey, &busPatchHeader->fDataKey);
009fa22b 844 if (busPatchEnd > end or busPatchEnd < start)
e3a2b9c9 845 fHandler.OnError(EventHandler::kBadBusPatchLength, &busPatchHeader->fLength);
009fa22b 846 if (dataEnd > end or dataEnd < start)
e3a2b9c9 847 fHandler.OnError(EventHandler::kBadBusPatchTotalLength, &busPatchHeader->fTotalLength);
848 if (dataEnd != busPatchEnd)
849 fHandler.OnError(EventHandler::kBusPatchLengthMismatch, busPatchHeader);
850
851 // Indicate we had and error and stop the decoding if so
852 // requested by the user.
853 fHadError = true;
854 if (fExitOnError) return false;
855
856 // Try to recover from the corrupt header.
857 RecoverResult result = TryRecoverStruct(
858 fgkBusPatchDataKey, sizeof(AliMUONBusPatchHeaderStruct),
859 busPatchHeader->fTotalLength, busPatchHeader->fLength,
860 busPatchStart, end, dataEnd, busPatchEnd, current
861 );
862 if (result == kContinueToNextStruct)
863 continue; // Try the next bus patch at 'current'.
864 if (result == kRecoverFailed) return false;
865 }
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 if (++busPatchCount > fMaxBusPatches)
872 {
873 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 fHadError = true;
881 return false;
882 }
883
884 fHandler.OnNewBusPatch(busPatchHeader, dataStart);
8a0dae7c 885 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 if (fExitOnError)
892 {
893 fHandler.OnEndOfBusPatch(busPatchHeader, dataStart);
894 return false;
895 }
896 }
897 fHandler.OnEndOfBusPatch(busPatchHeader, dataStart);
e3a2b9c9 898 }
899
900 return true;
901}
902
903
904template <class EventHandler>
905bool 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 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 const UInt_t* data = reinterpret_cast<const UInt_t*>(start);
930 const UInt_t* dataEnd = reinterpret_cast<const UInt_t*>(end);
931 for (; data < dataEnd; data++)
932 {
933 if (ParityIsOk(*data))
934 {
8a0dae7c 935 fHandler.OnData(*data, false);
e3a2b9c9 936 }
937 else
938 {
939 // Indicate we had a parity error and exit immediately
940 // if the user so requested.
941 fHandler.OnError(EventHandler::kParityError, data);
942 fHadError = true;
943 if (fExitOnError) return false;
944
945 if (fSendDataOnParityError)
8a0dae7c 946 fHandler.OnData(*data, true);
e3a2b9c9 947 }
948 }
949
950 return true;
951}
952
953
954template <class EventHandler>
955typename AliMUONTrackerDDLDecoder<EventHandler>::RecoverResult
956AliMUONTrackerDDLDecoder<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 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 const UInt_t* headerKey = reinterpret_cast<const UInt_t*>(structStart);
1048 bool headerKeyOk = (expectedKey == *headerKey);
1049
cc696a72 1050 bool lengthsMatch = (totalLength*4 == length*4 + headerSize);
e3a2b9c9 1051
1052 bool lengthIsCorrect = false;
1053 bool totalLengthIsCorrect = false;
1054 const UInt_t* keyAtDataEnd = reinterpret_cast<const UInt_t*>(dataEnd);
1055 const UInt_t* keyAtStructEnd = reinterpret_cast<const UInt_t*>(structEnd);
1056
a0fea27d 1057
1058 if ( expectedKey == fgkBlockDataKey )
1059 {
e3a2b9c9 1060 if (dataEnd == bufferEnd)
1061 {
1062 // Are we at the end of the buffer?
1063 lengthIsCorrect = true;
1064 }
1065 else
1066 {
1067 // Must check that we can read another 4 bytes before
1068 // checking the key at dataEnd.
009fa22b 1069 if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
e3a2b9c9 1070 {
1071 if (*keyAtDataEnd == fgkBlockDataKey)
1072 lengthIsCorrect = true;
1073 }
1074 }
1075
1076 if (structEnd == bufferEnd)
1077 {
1078 // Are we at the end of the buffer?
1079 totalLengthIsCorrect = true;
1080 }
1081 else
1082 {
1083 // Must check that we can read another 4 bytes before
1084 // checking the key at structEnd.
009fa22b 1085 if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
e3a2b9c9 1086 {
1087 if (*keyAtStructEnd == fgkBlockDataKey)
1088 totalLengthIsCorrect = true;
1089 }
1090 }
a0fea27d 1091 }
e3a2b9c9 1092
a0fea27d 1093 else if ( expectedKey == fgkDSPDataKey )
1094 {
e3a2b9c9 1095 if (dataEnd == bufferEnd)
1096 {
1097 // Are we at the end of the buffer?
1098 lengthIsCorrect = true;
1099 }
1100 else
1101 {
1102 // Must check that we can read another 4 bytes before
1103 // checking the key at dataEnd.
009fa22b 1104 if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
e3a2b9c9 1105 {
1106 if (*keyAtDataEnd == fgkBlockDataKey
1107 or *keyAtDataEnd == fgkDSPDataKey)
1108 lengthIsCorrect = true;
1109 }
1110 }
1111
1112 if (structEnd == bufferEnd)
1113 {
1114 // Are we at the end of the buffer?
1115 totalLengthIsCorrect = true;
1116 }
1117 else
1118 {
1119 // Must check that we can read another 4 bytes before
1120 // checking the key at structEnd.
009fa22b 1121 if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
e3a2b9c9 1122 {
1123 if (*keyAtStructEnd == fgkBlockDataKey
1124 or *keyAtStructEnd == fgkDSPDataKey)
1125 totalLengthIsCorrect = true;
1126 }
1127 }
a0fea27d 1128 }
1129 else if ( expectedKey == fgkBusPatchDataKey )
1130 {
e3a2b9c9 1131 if (dataEnd == bufferEnd)
1132 {
1133 // Are we at the end of the buffer?
1134 lengthIsCorrect = true;
1135 }
1136 else
1137 {
1138 // Must check that we can read another 4 bytes before
1139 // checking the key at dataEnd.
009fa22b 1140 if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
e3a2b9c9 1141 {
1142 if (*keyAtDataEnd == fgkDSPDataKey
1143 or *keyAtDataEnd == fgkBusPatchDataKey)
1144 lengthIsCorrect = true;
1145 }
1146 }
1147
1148 if (structEnd == bufferEnd)
1149 {
1150 // Are we at the end of the buffer?
1151 totalLengthIsCorrect = true;
1152 }
1153 else
1154 {
1155 // Must check that we can read another 4 bytes before
1156 // checking the key at structEnd.
009fa22b 1157 if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
e3a2b9c9 1158 {
1159 if (*keyAtStructEnd == fgkDSPDataKey
1160 or *keyAtStructEnd == fgkBusPatchDataKey)
1161 totalLengthIsCorrect = true;
1162 }
1163 }
a0fea27d 1164 }
e3a2b9c9 1165
1166 if (headerKeyOk and lengthIsCorrect)
1167 {
1168 // totalLength was wrong, dataEnd is correct.
1169 structEnd = dataEnd;
1170 current = dataEnd;
1171 return kStructRecovered;
1172 }
1173 if (headerKeyOk and totalLengthIsCorrect)
1174 {
1175 // Length was wrong, structEnd is correct.
1176 dataEnd = structEnd;
1177 current = structEnd;
1178 return kStructRecovered;
1179 }
1180 if (lengthsMatch and lengthIsCorrect and totalLengthIsCorrect)
1181 {
1182 // The header's key was wrong but the lengths and pointers are OK.
1183 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 const UChar_t* location = FindKey(
1190 expectedKey, structStart + sizeof(UInt_t), bufferEnd
1191 );
1192 if (location != NULL)
1193 {
1194 current = location;
1195 return kContinueToNextStruct;
1196 }
1197
1198 return kRecoverFailed;
1199}
1200
1201
1202template <class EventHandler>
1203const 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.
009fa22b 1212
1213 if (end + sizeof(UInt_t) < start) return NULL; // check for pointer overflow.
e3a2b9c9 1214 const UChar_t* current = start;
1215 while (current + sizeof(UInt_t) <= end)
1216 {
1217 UInt_t data = * reinterpret_cast<const UInt_t*>(current);
1218 if (data == key) return current;
1219 current++;
1220 }
1221 return NULL;
1222}
1223
1224
1225template <class EventHandler>
1226bool 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 data ^= data >> 16;
1236 data ^= data >> 8;
1237 data ^= data >> 4;
1238 data &= 0xf;
1239 data = ((0x6996 >> data) & 1);
1240 return data == 0;
1241}
1242
1243#endif // ALIMUONTRACKERDDLDECODER_H