]> git.uio.no Git - u/mrichter/AliRoot.git/blame - MUON/AliMUONTrackerDDLDecoder.h
Take changes in AliDCSSensor class into account (Ionut)
[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
fa9a7065 325template <class EventHandler>
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
8a0dae7c 362template <class EventHandler>
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
726 // decoding from there. Note: to achieve all we have to do
727 // is continue to the next iteration, because the logic
728 // will land up calling the FindKey method within the
729 // TryRecoverStruct method above.
730 if (fTryRecover) continue;
731 }
732
733 // Check if we are padding. If we are, then the bus patch data is
734 // actually 4 bytes smaller and the last word is a padding word.
735 if (dspHeader->fPaddingWord == 1)
736 {
737 dataEnd -= sizeof(UInt_t);
738
739 // Check the pad word is correct.
740 const UInt_t* padWord = reinterpret_cast<const UInt_t*>(dataEnd);
741 if (*padWord != fgkPaddingWord)
742 {
743 fHandler.OnError(EventHandler::kBadPaddingWord, padWord);
744 fHadError = true;
8a0dae7c 745 if (fExitOnError)
746 {
747 fHandler.OnEndOfDSP(dspHeader, dataStart);
748 return false;
749 }
e3a2b9c9 750 }
751 }
752
8a0dae7c 753 if (not DecodeDSPData(dataStart, dataEnd))
754 {
755 // At this point we had a problem decoding the DSP structure's
756 // data, thus we should stop further decoding if so requested by
757 // the user. Note the fHadError flag is already marked inside
758 // DecodeDSPData.
759 if (fExitOnError)
760 {
761 fHandler.OnEndOfDSP(dspHeader, dataStart);
762 return false;
763 }
764 }
765 fHandler.OnEndOfDSP(dspHeader, dataStart);
e3a2b9c9 766 }
767
768 return true;
769}
770
771
772template <class EventHandler>
773bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeDSPData(
774 const UChar_t* start, const UChar_t* end
775 )
776{
777 /// This method decodes a DSP structure's data payload. It finds all the
778 /// bus patches found inside and for each it calls the OnNewBusPatch method
779 /// for the event handler to signal the start of each new bus patch.
780 /// \param start This is the pointer to the start of the DSP structure's data.
781 /// \param end This is the pointer to the first byte just past the
782 /// end of the DSP structure.
783 /// \return If the DSP structure's data was decoded without errors
784 /// or we could recover from the errors, then true is returned.
785 /// False is returned otherwise.
786
787 const UChar_t* current = start;
788
789 UInt_t busPatchCount = 0; // Indicates the number of bus patches decoded.
790 while (current < end)
791 {
792 // Mark the start of the bus patch structure.
793 const UChar_t* busPatchStart = current;
794
795 // Get the bus patch header, move the current pointer just past
796 // the end of the header and check that we have not overflowed
797 // the buffer.
798 const AliMUONBusPatchHeaderStruct* busPatchHeader
799 = reinterpret_cast<const AliMUONBusPatchHeaderStruct*>(busPatchStart);
800 current += sizeof(AliMUONBusPatchHeaderStruct);
009fa22b 801 if (current > end or current < start)
e3a2b9c9 802 {
009fa22b 803 // If we overflowed the pointer and already had an error then
804 // we are clearly lost so just stop decoding before we segfault.
805 if (current < start and fHadError) return false;
806
e3a2b9c9 807 // So we only got part of a bus patch header at the very
808 // end of the DSP structure buffer. Nothing to do but
809 // report the error and exit. Set fHadError in case of
810 // further decoding.
811 fHandler.OnError(EventHandler::kNoBusPatchHeader, busPatchHeader);
812 fHadError = true;
813 return false;
814 }
815
816 // The header fits the buffer so we can mark the data start and
817 // read from the header to find the end of data and bus patch
818 // structure pointers.
819 const UChar_t* dataStart = current;
820 current += busPatchHeader->fLength * sizeof(UInt_t);
821 const UChar_t* dataEnd = current;
822 const UChar_t* busPatchEnd = busPatchStart
823 + busPatchHeader->fTotalLength * sizeof(UInt_t);
824
825 // Now we need to check for the following things:
826 // 1) Is the end of bus patch structure or end of data pointer
827 // outside the buffer boundaries.
828 // 2) Are the values for these pointers the same.
829 // 3) Is the expected data key in the header present.
830 // If any of the above fail then we know there is a problem with
831 // the bus patch header. It must be corrupted somehow.
832 if (busPatchHeader->fDataKey != fgkBusPatchDataKey
009fa22b 833 or dataEnd > end or dataEnd < start
834 or busPatchEnd > end or busPatchEnd < start
835 or dataEnd != busPatchEnd)
e3a2b9c9 836 {
837 // So let us see what exactly is wrong and report this.
838 if (busPatchHeader->fDataKey != fgkBusPatchDataKey)
839 fHandler.OnError(EventHandler::kBadBusPatchKey, &busPatchHeader->fDataKey);
009fa22b 840 if (busPatchEnd > end or busPatchEnd < start)
e3a2b9c9 841 fHandler.OnError(EventHandler::kBadBusPatchLength, &busPatchHeader->fLength);
009fa22b 842 if (dataEnd > end or dataEnd < start)
e3a2b9c9 843 fHandler.OnError(EventHandler::kBadBusPatchTotalLength, &busPatchHeader->fTotalLength);
844 if (dataEnd != busPatchEnd)
845 fHandler.OnError(EventHandler::kBusPatchLengthMismatch, busPatchHeader);
846
847 // Indicate we had and error and stop the decoding if so
848 // requested by the user.
849 fHadError = true;
850 if (fExitOnError) return false;
851
852 // Try to recover from the corrupt header.
853 RecoverResult result = TryRecoverStruct(
854 fgkBusPatchDataKey, sizeof(AliMUONBusPatchHeaderStruct),
855 busPatchHeader->fTotalLength, busPatchHeader->fLength,
856 busPatchStart, end, dataEnd, busPatchEnd, current
857 );
858 if (result == kContinueToNextStruct)
859 continue; // Try the next bus patch at 'current'.
860 if (result == kRecoverFailed) return false;
861 }
862
863 // At this point we certainly have a valid bus patch header, so
864 // we need to check if we have more bus patches than we expected.
865 // If not then we can indicate we have another bus patch and
866 // decode its data.
867 if (++busPatchCount > fMaxBusPatches)
868 {
869 fHandler.OnError(EventHandler::kTooManyBusPatches, current);
870
871 // In this case we stop further decoding of the DSP
872 // structure's data because clearly something is seriously
873 // wrong if we are getting more bus patches than expected.
874 // Indicate that we had an error so the Decode() method
875 // returns false.
876 fHadError = true;
877 return false;
878 }
879
880 fHandler.OnNewBusPatch(busPatchHeader, dataStart);
8a0dae7c 881 if (not DecodeBusPatchData(dataStart, dataEnd))
882 {
883 // At this point we had a problem decoding the bus patch data,
884 // thus we should stop further decoding if so requested by the
885 // user. Note the fHadError flag is already marked inside
886 // DecodeBusPatchData.
887 if (fExitOnError)
888 {
889 fHandler.OnEndOfBusPatch(busPatchHeader, dataStart);
890 return false;
891 }
892 }
893 fHandler.OnEndOfBusPatch(busPatchHeader, dataStart);
e3a2b9c9 894 }
895
896 return true;
897}
898
899
900template <class EventHandler>
901bool AliMUONTrackerDDLDecoder<EventHandler>::DecodeBusPatchData(
902 const UChar_t* start, const UChar_t* end
903 )
904{
905 /// This method decodes a single bus patch's data payload.
906 /// It will check the parity of the raw data words and send them
907 /// to the event handler instance with calls to OnData.
908 /// \param start This is the pointer to the start of the bus patch
909 /// structure's data.
910 /// \param end This is the pointer to the first byte just past the
911 /// end of the bus patch structure.
912 /// \return If the bus patch's data was decoded without errors
913 /// or we could recover from the errors, then true is returned.
914 /// False is returned otherwise.
915
916 // Assert that 'end' is always larger than start by n*sizeof(UInt_t)
917 // where n is a positive integer. This should be the case because we
918 // always add multiples of sizeof(UInt_t) to the 'current' pointer in
919 // all the DecodeXYZ methods.
920 assert( UInt_t(end - start) % 4 == 0 );
921
922 // Now step through all the data words and issue OnData events.
923 // We also need to check parity and signal OnError if it is not valid
924 // for any of the data words.
925 const UInt_t* data = reinterpret_cast<const UInt_t*>(start);
926 const UInt_t* dataEnd = reinterpret_cast<const UInt_t*>(end);
927 for (; data < dataEnd; data++)
928 {
929 if (ParityIsOk(*data))
930 {
8a0dae7c 931 fHandler.OnData(*data, false);
e3a2b9c9 932 }
933 else
934 {
935 // Indicate we had a parity error and exit immediately
936 // if the user so requested.
937 fHandler.OnError(EventHandler::kParityError, data);
938 fHadError = true;
939 if (fExitOnError) return false;
940
941 if (fSendDataOnParityError)
8a0dae7c 942 fHandler.OnData(*data, true);
e3a2b9c9 943 }
944 }
945
946 return true;
947}
948
949
950template <class EventHandler>
951typename AliMUONTrackerDDLDecoder<EventHandler>::RecoverResult
952AliMUONTrackerDDLDecoder<EventHandler>::TryRecoverStruct(
953 UInt_t expectedKey,
954 UInt_t headerSize,
955 UInt_t totalLength,
956 UInt_t length,
957 const UChar_t* structStart,
958 const UChar_t* bufferEnd,
959 const UChar_t*& dataEnd,
960 const UChar_t*& structEnd,
961 const UChar_t*& current
962 )
963{
964 /// This method attempts to recover from a corrupt structure header by
965 /// figuring out which of the structure size indicators is correct.
966 /// This is possible because each header has some redundant information.
967 /// The recovery procedure is only attempted if fTryRecover was set to
968 /// true. If the recovery procedure is successful then this method will
969 /// also update the pointers indicating the start of data, end of structure
970 /// and current parsing position with the correct values.
971 ///
972 /// [in] \param expectedKey This is the expected block key for the header
973 /// currently being processed.
974 /// [in] \param headerSize The expected header size as given by the sizeof
975 /// operator for example.
976 /// [in] \param totalLength The total length as given by the fTotalLength
977 /// field in the current header being handled.
978 /// [in] \param length The data length as given by the fLength field
979 /// in the current header being handled.
980 /// [in] \param structStart A pointer to the start of the structure header.
981 /// [in] \param bufferEnd A pointer to the first byte just past the end
982 /// of the buffer. This could be the pointer to the first byte
983 /// just past the end of the parent structure if we are dealing
984 /// with a DSP structure or bus patch. The parent structure for
985 /// the DSP is a block structure and for a bus patch it is a DSP.
986 /// [out] \param dataEnd This is the pointer to the first byte just past
987 /// the end of the structure being processed. It should be equal to
988 /// structStart + sizeof(structure header) + fLength, where fLength
989 /// is the field found in the structure's header itself. This value
990 /// will be corrected and updated if we could recover from the
991 /// corruption in the header.
992 /// [out] \param structEnd A pointer to the first byte just past the end of
993 /// the structure. This value should be set equal to
994 /// structStart + fTotalLength * sizeof(UInt_t), where fTotalLength
995 /// is the field found in the structure's header itself. This value
996 /// will be corrected and updated if we could recover from the
997 /// corruption in the header.
998 /// [out] \param current This is the pointer to the current location in
999 /// the DDL payload being parsed. It should in principle point
1000 /// to the start of the structures data. This value will be
1001 /// corrected and updated if we could recover from the corruption
1002 /// in the header.
1003 ///
1004 /// \return Returns the result of the recovery attempt, which can be one
1005 /// of the following:
1006 /// kRecoverFailed - The recovery failed completely so the caller
1007 /// cannot continue parsing any more structures. If the failure
1008 /// is within a DSP then one could still continue parsing
1009 /// from the next block. Similarly for bus patches, parsing could
1010 /// continue from the next DSP structure.
1011 /// kStructRecovered - Indicates that we recovered from a corrupt
1012 /// structure header and can continue processing the data of the
1013 /// structure in question.
1014 /// kContinueToNextStruct - Either fTryRecover was set to false or we
1015 /// could not recover from the corrupt header but we did find the
1016 /// start of another header matching the expected key so parsing
1017 /// can continue from the updated current position.
1018
1019 // Check if the user wants us to try and recover from a corrupt header.
1020 if (not fTryRecover) return kContinueToNextStruct;
1021
1022 // If the user wants us to try recover, then try to recover what the
1023 // correct values for dataEnd, structEnd and current were supposed to be.
1024 // The recovery procedure is as follows: We have 4 conditions for a correct
1025 // header:
1026 // 1) The header key is what we expect.
1027 // 2) The totalLength equals length + headerSize.
1028 // 3) The word at dataEnd contains a valid key. (implies length is
1029 // correct.)
1030 // 4) The word at structEnd contains a valid key. (implies totalLength
1031 // is correct.)
1032 // If any 2 of these conditions hold then we know that only one of the
1033 // header fields is corrupt and we have enough information to reconstruct
1034 // the third field. Note that if conditions 3 and 4 are true then this
1035 // implies 2 is also true. (not necessarily the other way around though.)
1036 // The valid key mentioned above at dataEnd and structEnd should be:
1037 // a) A bus patch key, DSP key or end of buffer if expectedKey indicates
1038 // a buspatch.
1039 // b) A DSP key, block structure key or end of buffer if expectedKey
1040 // indicates a DSP.
1041 // c) A block structure key or end of buffer if expectedKey indicates
1042 // a DSP.
1043 const UInt_t* headerKey = reinterpret_cast<const UInt_t*>(structStart);
1044 bool headerKeyOk = (expectedKey == *headerKey);
1045
cc696a72 1046 bool lengthsMatch = (totalLength*4 == length*4 + headerSize);
e3a2b9c9 1047
1048 bool lengthIsCorrect = false;
1049 bool totalLengthIsCorrect = false;
1050 const UInt_t* keyAtDataEnd = reinterpret_cast<const UInt_t*>(dataEnd);
1051 const UInt_t* keyAtStructEnd = reinterpret_cast<const UInt_t*>(structEnd);
1052
a0fea27d 1053
1054 if ( expectedKey == fgkBlockDataKey )
1055 {
e3a2b9c9 1056 if (dataEnd == bufferEnd)
1057 {
1058 // Are we at the end of the buffer?
1059 lengthIsCorrect = true;
1060 }
1061 else
1062 {
1063 // Must check that we can read another 4 bytes before
1064 // checking the key at dataEnd.
009fa22b 1065 if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
e3a2b9c9 1066 {
1067 if (*keyAtDataEnd == fgkBlockDataKey)
1068 lengthIsCorrect = true;
1069 }
1070 }
1071
1072 if (structEnd == bufferEnd)
1073 {
1074 // Are we at the end of the buffer?
1075 totalLengthIsCorrect = true;
1076 }
1077 else
1078 {
1079 // Must check that we can read another 4 bytes before
1080 // checking the key at structEnd.
009fa22b 1081 if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
e3a2b9c9 1082 {
1083 if (*keyAtStructEnd == fgkBlockDataKey)
1084 totalLengthIsCorrect = true;
1085 }
1086 }
a0fea27d 1087 }
e3a2b9c9 1088
a0fea27d 1089 else if ( expectedKey == fgkDSPDataKey )
1090 {
e3a2b9c9 1091 if (dataEnd == bufferEnd)
1092 {
1093 // Are we at the end of the buffer?
1094 lengthIsCorrect = true;
1095 }
1096 else
1097 {
1098 // Must check that we can read another 4 bytes before
1099 // checking the key at dataEnd.
009fa22b 1100 if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
e3a2b9c9 1101 {
1102 if (*keyAtDataEnd == fgkBlockDataKey
1103 or *keyAtDataEnd == fgkDSPDataKey)
1104 lengthIsCorrect = true;
1105 }
1106 }
1107
1108 if (structEnd == bufferEnd)
1109 {
1110 // Are we at the end of the buffer?
1111 totalLengthIsCorrect = true;
1112 }
1113 else
1114 {
1115 // Must check that we can read another 4 bytes before
1116 // checking the key at structEnd.
009fa22b 1117 if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
e3a2b9c9 1118 {
1119 if (*keyAtStructEnd == fgkBlockDataKey
1120 or *keyAtStructEnd == fgkDSPDataKey)
1121 totalLengthIsCorrect = true;
1122 }
1123 }
a0fea27d 1124 }
1125 else if ( expectedKey == fgkBusPatchDataKey )
1126 {
e3a2b9c9 1127 if (dataEnd == bufferEnd)
1128 {
1129 // Are we at the end of the buffer?
1130 lengthIsCorrect = true;
1131 }
1132 else
1133 {
1134 // Must check that we can read another 4 bytes before
1135 // checking the key at dataEnd.
009fa22b 1136 if (dataEnd + sizeof(UInt_t) <= bufferEnd and dataEnd + sizeof(UInt_t) > structStart)
e3a2b9c9 1137 {
1138 if (*keyAtDataEnd == fgkDSPDataKey
1139 or *keyAtDataEnd == fgkBusPatchDataKey)
1140 lengthIsCorrect = true;
1141 }
1142 }
1143
1144 if (structEnd == bufferEnd)
1145 {
1146 // Are we at the end of the buffer?
1147 totalLengthIsCorrect = true;
1148 }
1149 else
1150 {
1151 // Must check that we can read another 4 bytes before
1152 // checking the key at structEnd.
009fa22b 1153 if (structEnd + sizeof(UInt_t) <= bufferEnd and structEnd + sizeof(UInt_t) > structStart)
e3a2b9c9 1154 {
1155 if (*keyAtStructEnd == fgkDSPDataKey
1156 or *keyAtStructEnd == fgkBusPatchDataKey)
1157 totalLengthIsCorrect = true;
1158 }
1159 }
a0fea27d 1160 }
e3a2b9c9 1161
1162 if (headerKeyOk and lengthIsCorrect)
1163 {
1164 // totalLength was wrong, dataEnd is correct.
1165 structEnd = dataEnd;
1166 current = dataEnd;
1167 return kStructRecovered;
1168 }
1169 if (headerKeyOk and totalLengthIsCorrect)
1170 {
1171 // Length was wrong, structEnd is correct.
1172 dataEnd = structEnd;
1173 current = structEnd;
1174 return kStructRecovered;
1175 }
1176 if (lengthsMatch and lengthIsCorrect and totalLengthIsCorrect)
1177 {
1178 // The header's key was wrong but the lengths and pointers are OK.
1179 return kStructRecovered;
1180 }
1181
1182 // Could not recover the header from the available information, so find
1183 // the next key in the stream that is the same as the currently expected
1184 // one and continue decoding from there.
1185 const UChar_t* location = FindKey(
1186 expectedKey, structStart + sizeof(UInt_t), bufferEnd
1187 );
1188 if (location != NULL)
1189 {
1190 current = location;
1191 return kContinueToNextStruct;
1192 }
1193
1194 return kRecoverFailed;
1195}
1196
1197
1198template <class EventHandler>
1199const UChar_t* AliMUONTrackerDDLDecoder<EventHandler>::FindKey(
1200 UInt_t key, const UChar_t* start, const UChar_t* end
1201 )
1202{
1203 /// Searches for the first occurrence of the key value in the buffer marked by
1204 /// 'start' and 'end'. 'start' should point to the start of the buffer and 'end'
1205 /// should point to 'start + bufferSize', i.e. just past the last byte of the
1206 /// buffer. If the key was found then the pointer to that location is returned
1207 /// otherwise NULL is returned.
009fa22b 1208
1209 if (end + sizeof(UInt_t) < start) return NULL; // check for pointer overflow.
e3a2b9c9 1210 const UChar_t* current = start;
1211 while (current + sizeof(UInt_t) <= end)
1212 {
1213 UInt_t data = * reinterpret_cast<const UInt_t*>(current);
1214 if (data == key) return current;
1215 current++;
1216 }
1217 return NULL;
1218}
1219
1220
1221template <class EventHandler>
1222bool AliMUONTrackerDDLDecoder<EventHandler>::ParityIsOk(UInt_t data)
1223{
1224 /// Optimised parity check addapted from:
1225 /// http://graphics.stanford.edu/~seander/bithacks.html#ParityParallel
1226
1227 // parity of the 32 bits must be zero if the last bit is equal
1228 // to the parity of the first 31 bits.
1229 // Reason: the parity bit xor the parity of the first 31 bits must give
1230 // zero, unless there was a bit error.
1231 data ^= data >> 16;
1232 data ^= data >> 8;
1233 data ^= data >> 4;
1234 data &= 0xf;
1235 data = ((0x6996 >> data) & 1);
1236 return data == 0;
1237}
1238
1239#endif // ALIMUONTRACKERDDLDECODER_H