Adding a utility program to perform a logical dump of internal dHLT data block struct...
[u/mrichter/AliRoot.git] / HLT / MUON / utils / dHLTdumpraw.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-2007, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author:                                                                *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 /* $Id$ */
17
18 /**
19  * @file   dHLTdumpraw.cxx
20  * @author Artur Szostak <artursz@iafrica.com>,
21  *         Seforo Mohlalisi <seforomohlalisi@yahoo.co.uk>
22  * @date   
23  * @brief  Command line utility to dump dHLT's internal raw data blocks.
24  */
25
26 // We define NDEBUG for the AliHLTMUONDataBlockReader.h header file since this
27 // program by definition handles corrupt data. So we do not need the assertions
28 // in the AliHLTMUONDataBlockReader class to be checked.
29 #define NDEBUG
30 #include "AliHLTMUONDataBlockReader.h"
31 #undef NDEBUG
32 #include "AliHLTMUONUtils.h"
33
34 #include <endian.h>
35 #ifndef LITTLE_ENDIAN
36 #error Handling of internal data for non little endian machines not yet implemented.
37 #endif
38
39 #include <stdlib.h>
40 #include <cassert>
41 #include <new>
42 #include <fstream>
43
44 #include <iostream>
45 using std::cout;
46 using std::cerr;
47 using std::endl;
48 using std::showbase;
49 using std::noshowbase;
50 using std::hex;
51 using std::dec;
52
53 #include <iomanip>
54 using std::setw;
55 using std::left;
56 using std::internal;
57
58
59 #define CMDLINE_ERROR 1
60 #define PARSE_ERROR 2
61 #define SYSTEM_ERROR 3
62 #define FATAL_ERROR 4
63
64
65 void PrintRubbishData(AliHLTUInt32_t offset, const char* padByte, AliHLTUInt32_t padCount)
66 {
67         if (padCount == 0) return;
68         
69         cerr << "ERROR: Found the following unexpected rubbish data at the"
70                 " end of the data block:" << endl;
71         cerr << "Byte #\tValue\tCharacter" << endl;
72         for (AliHLTUInt32_t i = 0; i < padCount; i++)
73         {
74                 short value = short(padByte[i]) & 0xFF;
75                 char character = padByte[i];
76                 cerr << offset + i + 1 << "\t"
77                         << noshowbase << hex << "0x" << value << dec << "\t"
78                         << character << endl;
79         }
80 }
81
82
83 template <typename FieldType>
84 int CheckHeaderField(
85                 FieldType& field, const char* buffer, unsigned long bufferSize,
86                 bool continueParse
87         )
88 {
89         const char* fieldptr = reinterpret_cast<const char*>(&field);
90         const char* endptr = buffer + bufferSize;
91         AliHLTUInt32_t bufferRemaining = endptr > fieldptr ? endptr - fieldptr : 0;
92         
93         if (bufferRemaining < sizeof(field))
94         {
95                 cout << "..." << endl; // We may be half way through printing a line so end it.
96                 cerr << "ERROR: The data block is too short. The header is corrupt." << endl;
97                 if (continueParse)
98                 {
99                         AliHLTUInt32_t offset = fieldptr - buffer;
100                         PrintRubbishData(offset, fieldptr, bufferRemaining);
101                 }
102                 return PARSE_ERROR;
103         }
104         return EXIT_SUCCESS;
105 }
106
107
108 template <typename FieldType>
109 int CheckField(
110                 FieldType& field, const char* buffer, unsigned long bufferSize,
111                 bool continueParse
112         )
113 {
114         const char* fieldptr = reinterpret_cast<const char*>(&field);
115         const char* endptr = buffer + bufferSize;
116         AliHLTUInt32_t bufferRemaining = endptr > fieldptr ? endptr - fieldptr : 0;
117         
118         if (bufferRemaining < sizeof(field))
119         {
120                 cout << "..." << endl; // We may be half way through printing a line so end it.
121                 cerr << "ERROR: The data block is too short. The data is corrupt." << endl;
122                 if (continueParse)
123                 {
124                         AliHLTUInt32_t offset = fieldptr - buffer;
125                         PrintRubbishData(offset, fieldptr, bufferRemaining);
126                 }
127                 return PARSE_ERROR;
128         }
129         return EXIT_SUCCESS;
130 }
131
132
133 template <typename BlockType>
134 int CheckCommonHeader(
135                 BlockType& block, const char* buffer, unsigned long bufferSize,
136                 bool continueParse
137         )
138 {
139         int result = EXIT_SUCCESS;
140
141         // Check the fRecordWidth field in the common header.
142         if (block.CommonBlockHeader().fRecordWidth !=
143                 sizeof(typename BlockType::ElementType))
144         {
145                 cerr << "ERROR: The record width found in the header is incorrect."
146                         " Found a record width of "
147                         << block.CommonBlockHeader().fRecordWidth << " bytes, but expected"
148                         " a value of " << sizeof(typename BlockType::ElementType)
149                         << " bytes." << endl;
150                 result = PARSE_ERROR;
151                 if (not continueParse) return result;
152         }
153         
154         if (not block.BufferSizeOk())
155         {
156                 cerr << "ERROR: The size of the file is incorrect. It is "
157                         << bufferSize << " bytes big, but according"
158                         " to the data block header it should be " << block.BytesUsed()
159                         << " bytes." << endl;
160                 result = PARSE_ERROR;
161                 if (not continueParse) return result;
162         }
163         
164         return result;
165 }
166
167
168 template <typename BlockType>
169 AliHLTUInt32_t CalculateNEntries(BlockType& block, unsigned long bufferSize)
170 {
171         // Calculate how many entries we can display. If the buffer size is correct
172         // we just use the number of entries the block specifies. Otherwise we need
173         // to calculate it from the buffer size.
174         AliHLTUInt32_t nentries;
175         if (block.BytesUsed() == bufferSize)
176         {
177                 nentries = block.Nentries();
178         }
179         else
180         {
181                 AliHLTInt32_t dataSize = bufferSize
182                         - sizeof(typename BlockType::HeaderType);
183                 nentries = dataSize / sizeof(typename BlockType::ElementType);
184                 if (dataSize % sizeof(typename BlockType::ElementType) > 0)
185                         nentries++;
186         }
187         return nentries;
188 }
189
190
191 int DumpTriggerRecordsBlock(
192                 const char* buffer, unsigned long bufferSize,
193                 bool continueParse
194         )
195 {
196         AliHLTMUONTriggerRecordsBlockReader block(buffer, bufferSize);
197         // TODO
198         return EXIT_SUCCESS;
199 }
200
201
202 int DumpTrigRecsDebugBlock(
203                 const char* buffer, unsigned long bufferSize,
204                 bool continueParse
205         )
206 {
207         AliHLTMUONTrigRecsDebugBlockReader block(buffer, bufferSize);
208         // TODO
209         return EXIT_SUCCESS;
210 }
211
212
213 int DumpTriggerChannelsBlock(
214                 const char* buffer, unsigned long bufferSize,
215                 bool continueParse
216         )
217 {
218         AliHLTMUONTriggerChannelsBlockReader block(buffer, bufferSize);
219         // TODO
220         return EXIT_SUCCESS;
221 }
222
223
224 int DumpRecHitStruct(
225                 const char* buffer, unsigned long bufferSize,
226                 const AliHLTMUONRecHitStruct* hit,
227                 bool continueParse
228         )
229 {
230         // Step through the fields trying to print them.
231         // At each step check if we have not overflowed the buffer. If we have
232         // not, then we can print the field, otherwise we print the left over
233         // bytes assumed to be corrupted rubbish.
234         int result = CheckField(hit->fX, buffer, bufferSize, continueParse);
235         if (result != EXIT_SUCCESS) return result;
236         cout << setw(13) << left << hit->fX << setw(0);
237
238         result = CheckField(hit->fY, buffer, bufferSize, continueParse);
239         if (result != EXIT_SUCCESS) return result;
240         cout << setw(13) << left << hit->fY << setw(0);
241
242         result = CheckField(hit->fZ, buffer, bufferSize, continueParse);
243         if (result != EXIT_SUCCESS) return result;
244         cout << hit->fZ << setw(0) << endl;
245
246         return result;
247 }
248
249
250 int DumpRecHitsBlock(
251                 const char* buffer, unsigned long bufferSize,
252                 bool continueParse
253         )
254 {
255         int result = EXIT_SUCCESS;
256         AliHLTMUONRecHitsBlockReader block(buffer, bufferSize);
257         
258         result = CheckCommonHeader(block, buffer, bufferSize, continueParse);
259         if (result != EXIT_SUCCESS and not continueParse) return result;
260         
261         AliHLTUInt32_t nentries = CalculateNEntries(block, bufferSize);
262         
263         // Print the data block record entries.
264         cout << " X (cm)     | Y (cm)     | Z (cm)" << endl;
265         cout << "---------------------------------------" << endl;
266         const AliHLTMUONRecHitStruct* entry = block.GetArray();
267         for(AliHLTUInt32_t i = 0; i < nentries; i++)
268         {
269                 int subResult = DumpRecHitStruct(buffer, bufferSize, entry++, continueParse);
270                 if (subResult != EXIT_SUCCESS) return subResult;
271         }
272         
273         return result;
274 }
275
276
277 int DumpClustersBlock(
278                 const char* buffer, unsigned long bufferSize,
279                 bool continueParse
280         )
281 {
282         AliHLTMUONClustersBlockReader block(buffer, bufferSize);
283         // TODO
284         return EXIT_SUCCESS;
285 }
286
287
288 int DumpChannelsBlock(
289                 const char* buffer, unsigned long bufferSize,
290                 bool continueParse
291         )
292 {
293         AliHLTMUONChannelsBlockReader block(buffer, bufferSize);
294         // TODO
295         return EXIT_SUCCESS;
296 }
297
298
299 int DumpMansoTrackStruct(
300                 const char* buffer, unsigned long bufferSize,
301                 const AliHLTMUONMansoTrackStruct* track,
302                 bool continueParse
303         )
304 {
305         // Step through the fields trying to print them.
306         // At each step check if we have not overflowed the buffer. If we have
307         // not, then we can print the field, otherwise we print the left over
308         // bytes assumed to be corrupted rubbish.
309         int result = CheckField(track->fId, buffer, bufferSize, continueParse);
310         if (result != EXIT_SUCCESS) return result;
311         cout << "Track ID: " << track->fId << "\t";
312
313         result = CheckField(track->fTrigRec, buffer, bufferSize, continueParse);
314         if (result != EXIT_SUCCESS) return result;
315         cout << "Trigger Record ID: " << track->fTrigRec << endl;
316         
317         result = CheckField(track->fFlags, buffer, bufferSize, continueParse);
318         if (result != EXIT_SUCCESS) return result;
319         cout << "Flags: " << showbase << hex << track->fFlags << dec;
320                 
321         // Print the individual trigger bits.
322         AliHLTMUONParticleSign sign;
323         bool hitset[4];
324         AliHLTMUONUtils::UnpackMansoTrackFlags(track->fFlags, sign, hitset);
325         cout << " [Sign: " << sign << ", Hits set on chambers: ";
326         bool first = true;
327         for (AliHLTUInt32_t i = 0; i < 4; i++)
328         {
329                 if (hitset[i])
330                 {
331                         cout << (first ? "" : ", ") << i+7;
332                         first = false;
333                 }
334         }
335         cout << (first ? "none]" : "]") << endl;
336
337         result = CheckField(track->fPx, buffer, bufferSize, continueParse);
338         if (result != EXIT_SUCCESS) return result;
339         cout << "Momentum: (px = " << track->fPx << ", ";
340
341         result = CheckField(track->fPy, buffer, bufferSize, continueParse);
342         if (result != EXIT_SUCCESS) return result;
343         cout << "py = " << track->fPy << ", ";
344
345         result = CheckField(track->fPz, buffer, bufferSize, continueParse);
346         if (result != EXIT_SUCCESS) return result;
347         cout << "pz = " << track->fPz << ") GeV/c\t";
348
349         result = CheckField(track->fChi2, buffer, bufferSize, continueParse);
350         if (result != EXIT_SUCCESS) return result;
351         cout << "Chi squared fit: " << track->fChi2 << endl;
352         
353         cout << "Track hits:" << endl;
354         cout << "Chamber | X (cm)     | Y (cm)     | Z (cm)" << endl;
355         cout << "------------------------------------------------" << endl;
356         const AliHLTMUONRecHitStruct* hit = &track->fHit[0];
357         for(AliHLTUInt32_t ch = 0; ch < 4; ch++)
358         {
359                 cout << setw(10) << ch + 7;
360                 result = DumpRecHitStruct(buffer, bufferSize, hit++, continueParse);
361                 if (result != EXIT_SUCCESS) return result;
362         }
363
364         return result;
365 }
366
367
368 int DumpMansoTracksBlock(
369                 const char* buffer, unsigned long bufferSize,
370                 bool continueParse
371         )
372 {
373         int result = EXIT_SUCCESS;
374         AliHLTMUONMansoTracksBlockReader block(buffer, bufferSize);
375         
376         result = CheckCommonHeader(block, buffer, bufferSize, continueParse);
377         if (result != EXIT_SUCCESS and not continueParse) return result;
378         
379         AliHLTUInt32_t nentries = CalculateNEntries(block, bufferSize);
380         
381         // Print the data block record entries.
382         const AliHLTMUONMansoTrackStruct* entry = block.GetArray();
383         for(AliHLTUInt32_t i = 0; i < nentries; i++)
384         {
385                 cout << "============================== Manso track number " << i+1
386                         << " of " << nentries << " ==============================" << endl;
387                 int subResult = DumpMansoTrackStruct(buffer, bufferSize, entry++, continueParse);
388                 if (subResult != EXIT_SUCCESS) return subResult;
389         }
390         
391         return result;
392 }
393
394
395 int DumpMansoRoIStruct(
396                 const char* buffer, unsigned long bufferSize,
397                 const AliHLTMUONMansoRoIStruct* roi,
398                 bool continueParse
399         )
400 {
401         // Step through the fields trying to print them.
402         // At each step check if we have not overflowed the buffer. If we have
403         // not, then we can print the field, otherwise we print the left over
404         // bytes assumed to be corrupted rubbish.
405         int result = CheckField(roi->fX, buffer, bufferSize, continueParse);
406         if (result != EXIT_SUCCESS) return result;
407         cout << setw(13) << left << roi->fX << setw(0);
408
409         result = CheckField(roi->fY, buffer, bufferSize, continueParse);
410         if (result != EXIT_SUCCESS) return result;
411         cout << setw(13) << left << roi->fY << setw(0);
412
413         result = CheckField(roi->fZ, buffer, bufferSize, continueParse);
414         if (result != EXIT_SUCCESS) return result;
415         cout << setw(13) << left << roi->fZ << setw(0);
416
417         result = CheckField(roi->fRadius, buffer, bufferSize, continueParse);
418         if (result != EXIT_SUCCESS) return result;
419         cout << roi->fRadius << setw(0) << endl;
420
421         return result;
422 }
423
424
425 int DumpMansoCandidateStruct(
426                 const char* buffer, unsigned long bufferSize,
427                 const AliHLTMUONMansoCandidateStruct* candidate,
428                 bool continueParse
429         )
430 {
431         int result = DumpMansoTrackStruct(buffer, bufferSize, &candidate->fTrack, continueParse);
432         if (result != EXIT_SUCCESS) return result;
433         
434         cout << "Regions of interest:" << endl;
435         cout << "Chamber | X (cm)     | Y (cm)     | Z (cm)     | Radius (cm)" << endl;
436         cout << "-------------------------------------------------------------" << endl;
437         const AliHLTMUONMansoRoIStruct* roi = &candidate->fRoI[0];
438         for(AliHLTUInt32_t ch = 0; ch < 4; ch++)
439         {
440                 cout << setw(10) << ch + 7;
441                 result = DumpMansoRoIStruct(buffer, bufferSize, roi++, continueParse);
442                 if (result != EXIT_SUCCESS) return result;
443         }
444         return result;
445 }
446
447
448 int DumpMansoCandidatesBlock(
449                 const char* buffer, unsigned long bufferSize,
450                 bool continueParse
451         )
452 {
453         int result = EXIT_SUCCESS;
454         AliHLTMUONMansoCandidatesBlockReader block(buffer, bufferSize);
455         
456         result = CheckCommonHeader(block, buffer, bufferSize, continueParse);
457         if (result != EXIT_SUCCESS and not continueParse) return result;
458         
459         AliHLTUInt32_t nentries = CalculateNEntries(block, bufferSize);
460         
461         // Print the data block record entries.
462         const AliHLTMUONMansoCandidateStruct* entry = block.GetArray();
463         for(AliHLTUInt32_t i = 0; i < nentries; i++)
464         {
465                 cout << "=========================== Manso track candidate number " << i+1
466                         << " of " << nentries << " ===========================" << endl;
467                 int subResult = DumpMansoCandidateStruct(buffer, bufferSize, entry++, continueParse);
468                 if (subResult != EXIT_SUCCESS) return subResult;
469         }
470         
471         return result;
472 }
473
474
475 int DumpSinglesDecisionBlockHeader(
476                 const char* buffer, unsigned long bufferSize,
477                 const AliHLTMUONSinglesDecisionBlockStruct* header,
478                 bool continueParse
479         )
480 {
481         // Step through the header fields trying to print them.
482         // At each step check if we have not overflowed the buffer, if we have
483         // not then we can print the field, otherwise we print the left over
484         // bytes assumed to be corrupted rubbish.
485         int result = CheckHeaderField(header->fNlowPt, buffer, bufferSize, continueParse);
486         if (result != EXIT_SUCCESS) return result;
487         cout << " Number of low pt triggers: " << header->fNlowPt << endl;
488         
489         result = CheckHeaderField(header->fNhighPt, buffer, bufferSize, continueParse);
490         if (result != EXIT_SUCCESS) return result;
491         cout << "Number of high pt triggers: " << header->fNhighPt << endl;
492
493         return result;
494 }
495
496
497 int DumpTrackDecisionStruct(
498                 const char* buffer, unsigned long bufferSize,
499                 const AliHLTMUONTrackDecisionStruct* decision,
500                 bool continueParse
501         )
502 {
503         // Step through the fields trying to print them.
504         // At each step check if we have not overflowed the buffer. If we have
505         // not, then we can print the field, otherwise we print the left over
506         // bytes assumed to be corrupted rubbish.
507         int result = CheckField(decision->fTrackId, buffer, bufferSize, continueParse);
508         if (result != EXIT_SUCCESS) return result;
509         cout << setw(13) << left << decision->fTrackId << setw(0);
510         
511         result = CheckField(decision->fTriggerBits, buffer, bufferSize, continueParse);
512         if (result != EXIT_SUCCESS) return result;
513         cout << setw(12) << left << showbase << hex << decision->fTriggerBits
514                 << setw(0) << dec;
515                 
516         // Print the individual trigger bits.
517         bool highPt, lowPt;
518         AliHLTMUONUtils::UnpackTrackDecisionBits(decision->fTriggerBits, highPt, lowPt);
519         cout << setw(7) << left << (highPt ? "yes" : "no");
520         cout << setw(8) << left << (lowPt ? "yes" : "no");
521         cout << setw(0) << endl;
522
523         return result;
524 }
525
526
527 int DumpSinglesDecisionBlock(
528                 const char* buffer, unsigned long bufferSize,
529                 bool continueParse
530         )
531 {
532         int result = EXIT_SUCCESS;
533         AliHLTMUONSinglesDecisionBlockReader block(buffer, bufferSize);
534         
535         result = CheckCommonHeader(block, buffer, bufferSize, continueParse);
536         if (result != EXIT_SUCCESS and not continueParse) return result;
537         
538         // Dump the rest of the block header.
539         const AliHLTMUONSinglesDecisionBlockStruct* header = &block.BlockHeader();
540         int subResult = DumpSinglesDecisionBlockHeader(buffer, bufferSize, header, continueParse);
541         if (subResult != EXIT_SUCCESS) return subResult;
542         
543         AliHLTUInt32_t nentries = CalculateNEntries(block, bufferSize);
544         
545         // Print the data block record entries.
546         cout << "           |        Trigger Bits" << endl;
547         cout << "Track ID   | Raw         HighPt LowPt" << endl;
548         cout << "--------------------------------------" << endl;
549         const AliHLTMUONTrackDecisionStruct* entry = block.GetArray();
550         for(AliHLTUInt32_t i = 0; i < nentries; i++)
551         {
552                 subResult = DumpTrackDecisionStruct(buffer, bufferSize, entry++, continueParse);
553                 if (subResult != EXIT_SUCCESS) return subResult;
554         }
555         
556         return result;
557 }
558
559
560 int DumpPairsDecisionBlockHeader(
561                 const char* buffer, unsigned long bufferSize,
562                 const AliHLTMUONPairsDecisionBlockStruct* header,
563                 bool continueParse
564         )
565 {
566         // Step through the header fields trying to print them.
567         // At each step check if we have not overflowed the buffer, if we have
568         // not then we can print the field, otherwise we print the left over
569         // bytes assumed to be corrupted rubbish.
570         int result = CheckHeaderField(header->fNunlikeAnyPt, buffer, bufferSize, continueParse);
571         if (result != EXIT_SUCCESS) return result;
572         cout << "      Number of unlike all pt triggers: " << header->fNunlikeAnyPt << endl;
573         
574         result = CheckHeaderField(header->fNunlikeLowPt, buffer, bufferSize, continueParse);
575         if (result != EXIT_SUCCESS) return result;
576         cout << "      Number of unlike low pt triggers: " << header->fNunlikeLowPt << endl;
577         
578         result = CheckHeaderField(header->fNunlikeHighPt, buffer, bufferSize, continueParse);
579         if (result != EXIT_SUCCESS) return result;
580         cout << "     Number of unlike high pt triggers: " << header->fNunlikeHighPt << endl;
581         
582         result = CheckHeaderField(header->fNlikeAnyPt, buffer, bufferSize, continueParse);
583         if (result != EXIT_SUCCESS) return result;
584         cout << "        Number of like any pt triggers: " << header->fNlikeAnyPt << endl;
585         
586         result = CheckHeaderField(header->fNlikeLowPt, buffer, bufferSize, continueParse);
587         if (result != EXIT_SUCCESS) return result;
588         cout << "        Number of like low pt triggers: " << header->fNlikeLowPt << endl;
589         
590         result = CheckHeaderField(header->fNlikeHighPt, buffer, bufferSize, continueParse);
591         if (result != EXIT_SUCCESS) return result;
592         cout << "       Number of like high pt triggers: " << header->fNlikeHighPt << endl;
593         
594         result = CheckHeaderField(header->fNmassAny, buffer, bufferSize, continueParse);
595         if (result != EXIT_SUCCESS) return result;
596         cout << " Number of all invariant mass triggers: " << header->fNmassAny << endl;
597         
598         result = CheckHeaderField(header->fNmassLow, buffer, bufferSize, continueParse);
599         if (result != EXIT_SUCCESS) return result;
600         cout << " Number of low invariant mass triggers: " << header->fNmassLow << endl;
601         
602         result = CheckHeaderField(header->fNmassHigh, buffer, bufferSize, continueParse);
603         if (result != EXIT_SUCCESS) return result;
604         cout << "Number of high invariant mass triggers: " << header->fNmassHigh << endl;
605         
606         return result;
607 }
608
609
610 int DumpPairDecisionStruct(
611                 const char* buffer, unsigned long bufferSize,
612                 const AliHLTMUONPairDecisionStruct* decision,
613                 bool continueParse
614         )
615 {
616         // Step through the fields trying to print them.
617         // At each step check if we have not overflowed the buffer. If we have
618         // not, then we can print the field, otherwise we print the left over
619         // bytes assumed to be corrupted rubbish.
620         int result = CheckField(decision->fTrackAId, buffer, bufferSize, continueParse);
621         if (result != EXIT_SUCCESS) return result;
622         cout << setw(13) << left << decision->fTrackAId << setw(0);
623         
624         result = CheckField(decision->fTrackBId, buffer, bufferSize, continueParse);
625         if (result != EXIT_SUCCESS) return result;
626         cout << setw(13) << left << decision->fTrackBId << setw(0);
627         
628         result = CheckField(decision->fTriggerBits, buffer, bufferSize, continueParse);
629         if (result != EXIT_SUCCESS) return result;
630         cout << setw(12) << left << showbase << hex << decision->fTriggerBits
631                 << setw(0) << dec;
632                 
633         // Print the individual trigger bits.
634         bool highMass, lowMass, unlike;
635         AliHLTUInt8_t highPtCount, lowPtCount;
636         AliHLTMUONUtils::UnpackPairDecisionBits(
637                         decision->fTriggerBits,
638                         highMass, lowMass, unlike, highPtCount, lowPtCount
639                 );
640         cout << setw(7) << left << (highMass ? "yes" : "no");
641         cout << setw(7) << left << (lowMass ? "yes" : "no");
642         cout << setw(7) << left << (unlike ? "yes" : "no");
643         cout << setw(6) << left << AliHLTUInt16_t(highPtCount);
644         cout << setw(8) << left << AliHLTUInt16_t(lowPtCount);
645         cout << setw(0);
646         
647         result = CheckField(decision->fInvMass, buffer, bufferSize, continueParse);
648         if (result != EXIT_SUCCESS) return result;
649         cout << decision->fInvMass << endl;
650         
651         return EXIT_SUCCESS;
652 }
653
654
655 int DumpPairsDecisionBlock(
656                 const char* buffer, unsigned long bufferSize,
657                 bool continueParse
658         )
659 {
660         int result = EXIT_SUCCESS;
661         AliHLTMUONPairsDecisionBlockReader block(buffer, bufferSize);
662         
663         result = CheckCommonHeader(block, buffer, bufferSize, continueParse);
664         if (result != EXIT_SUCCESS and not continueParse) return result;
665         
666         // Dump the rest of the block header.
667         const AliHLTMUONPairsDecisionBlockStruct* header = &block.BlockHeader();
668         int subResult = DumpPairsDecisionBlockHeader(buffer, bufferSize, header, continueParse);
669         if (subResult != EXIT_SUCCESS) return subResult;
670         
671         AliHLTUInt32_t nentries = CalculateNEntries(block, bufferSize);
672         
673         // Print the data block record entries.
674         cout << "           |            |                Trigger Bits                  |" << endl;
675         cout << "Track A ID | Track B ID | Raw         HiMass LoMass Unlike HiPt# LoPt# | Invariant mass" << endl;
676         cout << "----------------------------------------------------------------------------------------" << endl;
677         const AliHLTMUONPairDecisionStruct* entry = block.GetArray();
678         for(AliHLTUInt32_t i = 0; i < nentries; i++)
679         {
680                 subResult = DumpPairDecisionStruct(buffer, bufferSize, entry++, continueParse);
681                 if (subResult != EXIT_SUCCESS) return subResult;
682         }
683         
684         return result;
685 }
686
687
688 int DumpCommonHeader(
689                 const char* buffer, unsigned long bufferSize,
690                 const AliHLTMUONDataBlockHeader* header, bool continueParse
691         )
692 {
693         // Step through the header fields trying to print them.
694         // At each step check if we have not overflowed the buffer, if we have
695         // not then we can print the field, otherwise we print the left over
696         // bytes assumed to be corrupted rubbish.
697         int result = CheckHeaderField(header->fType, buffer, bufferSize, continueParse);
698         if (result != EXIT_SUCCESS) return result;
699         AliHLTMUONDataBlockType type = AliHLTMUONDataBlockType(header->fType);
700         cout << "       Block type: " << type << endl;
701         
702         result = CheckHeaderField(header->fRecordWidth, buffer, bufferSize, continueParse);
703         if (result != EXIT_SUCCESS) return result;
704         cout << "     Record width: " << header->fRecordWidth << endl;
705         
706         result = CheckHeaderField(header->fNrecords, buffer, bufferSize, continueParse);
707         if (result != EXIT_SUCCESS) return result;
708         cout << "Number of entries: " << header->fNrecords << endl;
709         
710         return result;
711 }
712
713
714 int ParseBuffer(
715                 const char* buffer, unsigned long bufferSize,
716                 bool continueParse, AliHLTMUONDataBlockType type
717         )
718 {
719         assert( buffer != NULL );
720         int result = EXIT_SUCCESS;
721         
722         if (bufferSize < sizeof(AliHLTMUONDataBlockHeader))
723         {
724                 cerr << "ERROR: The size of the file is too small to contain a"
725                         " valid data block." << endl;
726                 result = PARSE_ERROR;
727                 if (not continueParse) return result;
728         }
729         const AliHLTMUONDataBlockHeader* header =
730                 reinterpret_cast<const AliHLTMUONDataBlockHeader*>(buffer);
731
732         int subResult = DumpCommonHeader(buffer, bufferSize, header, continueParse);
733         if (subResult != EXIT_SUCCESS) return subResult;
734
735         
736         // Check if the block type in the header corresponds to the type given
737         // by the '-type' command line parameter. If they do not then print an
738         // error or big fat warning message and force interpretation of the data
739         // block with the type given by '-type'.
740         AliHLTMUONDataBlockType headerType = AliHLTMUONDataBlockType(header->fType);
741         
742         if (type == kUnknownDataBlock)
743         {
744                 // -type not used in the command line so just use what is given
745                 // by the data block header.
746                 type = headerType;
747         }
748         else if (type != headerType)
749         {
750                 cerr << "WARNING: The data block header indicates a type"
751                         " different from what was specified on the command line."
752                         " The data could be corrupt."
753                         << endl;
754                 cerr << "WARNING: The type value in the file is "
755                         << showbase << hex << header->fType
756                         << " (" << headerType << "), but on the command line it is "
757                         << showbase << hex << int(type) << dec
758                         << " (" << type << ")."
759                         << endl;
760                 cerr << "WARNING: Will force the interpretation of the data block"
761                         " with a type of " << type << "." << endl;
762         }
763         
764         // Now we know what type the data block is supposed to be so we can
765         // dump it to screen with the appropriate dump routine.
766         switch (type)
767         {
768         case kTriggerRecordsDataBlock:
769                 subResult = DumpTriggerRecordsBlock(buffer, bufferSize, continueParse);
770                 if (subResult != EXIT_SUCCESS) result = subResult;
771                 break;
772         case kTrigRecsDebugDataBlock:
773                 subResult = DumpTrigRecsDebugBlock(buffer, bufferSize, continueParse);
774                 if (subResult != EXIT_SUCCESS) result = subResult;
775                 break;
776         case kTriggerChannelsDataBlock:
777                 subResult = DumpTriggerChannelsBlock(buffer, bufferSize, continueParse);
778                 if (subResult != EXIT_SUCCESS) result = subResult;
779                 break;
780         case kRecHitsDataBlock:
781                 subResult = DumpRecHitsBlock(buffer, bufferSize, continueParse);
782                 if (subResult != EXIT_SUCCESS) result = subResult;
783                 break;
784         case kClustersDataBlock:
785                 subResult = DumpClustersBlock(buffer, bufferSize, continueParse);
786                 if (subResult != EXIT_SUCCESS) result = subResult;
787                 break;
788         case kChannelsDataBlock:
789                 return DumpChannelsBlock(buffer, bufferSize, continueParse);
790                 if (subResult != EXIT_SUCCESS) result = subResult;
791                 break;
792         case kMansoTracksDataBlock:
793                 subResult = DumpMansoTracksBlock(buffer, bufferSize, continueParse);
794                 if (subResult != EXIT_SUCCESS) result = subResult;
795                 break;
796         case kMansoCandidatesDataBlock:
797                 subResult = DumpMansoCandidatesBlock(buffer, bufferSize, continueParse);
798                 if (subResult != EXIT_SUCCESS) result = subResult;
799                 break;
800         case kSinglesDecisionDataBlock:
801                 subResult = DumpSinglesDecisionBlock(buffer, bufferSize, continueParse);
802                 if (subResult != EXIT_SUCCESS) result = subResult;
803                 break;
804         case kPairsDecisionDataBlock:
805                 return DumpPairsDecisionBlock(buffer, bufferSize, continueParse);
806                 if (subResult != EXIT_SUCCESS) result = subResult;
807                 break;
808         default :
809                 cout << "ERROR: Unknown data block type. Found a type number of "
810                         << showbase << hex << int(type) << dec
811                         << " (" << int(type) << ")." << endl;
812                 result = PARSE_ERROR;
813         }
814         
815         return result;
816 }
817
818
819 /**
820  * The caller is responsible for freeing memory allocated for buffer with a call
821  * to delete [] buffer.
822  */
823 int ReadFile(const char* filename, char*& buffer, unsigned long& bufferSize)
824 {
825         assert( filename != NULL );
826         
827         // Open the file and find its size.
828         fstream file;
829         file.open(filename, ios::in);
830         if (not file)
831         {
832                 cerr << "ERROR: Could not open the file: " << filename << endl;
833                 return SYSTEM_ERROR;
834         }
835         file.seekg(0, ios::end);
836         if (not file)
837         {
838                 cerr << "ERROR: Could not seek in the file: " << filename << endl;
839                 return SYSTEM_ERROR;
840         }
841         bufferSize = file.tellg();
842         if (not file)
843         {
844                 cerr << "ERROR: Could not get file size for the file: " <<
845                         filename << endl;
846                 return SYSTEM_ERROR;
847         }
848         file.seekg(0, ios::beg);
849         if (not file)
850         {
851                 cerr << "ERROR: Could not seek in the file: " << filename << endl;
852                 return SYSTEM_ERROR;
853         }
854         
855         // Allocate the memory for the file.
856         try
857         {
858                 buffer = new char[bufferSize];
859         }
860         catch (const std::bad_alloc&)
861         {
862                 cerr << "ERROR: Out of memory. Tried to allocate " << bufferSize
863                         << " bytes." << endl;
864                 return SYSTEM_ERROR;
865         }
866         
867         file.read(buffer, bufferSize);
868         if (not file)
869         {
870                 delete [] buffer;
871                 buffer = NULL;
872                 bufferSize = 0;
873                 cerr << "ERROR: Could not read from file: " << filename << endl;
874                 return SYSTEM_ERROR;
875         }
876         
877         file.close();
878         if (not file)
879         {
880                 delete [] buffer;
881                 buffer = NULL;
882                 bufferSize = 0;
883                 cerr << "ERROR: Could not close the file: " << filename << endl;
884                 return SYSTEM_ERROR;
885         }
886         
887         return EXIT_SUCCESS;
888 }
889
890 /**
891  * Prints the command line usage of this program to standard error.
892  */
893 void PrintUsage()
894 {
895         cerr << "Usage: dHLTdumpraw [-help|-h] [-continue] [-type <typename>] <filename>" << endl;
896         cerr << "Where <filename> is the name of a file containing a raw data block." << endl;
897         cerr << "Options:" << endl;
898         cerr << " -help | -h" << endl;
899         cerr << "       Displays this message." << endl;
900         cerr << " -continue" << endl;
901         cerr << "       If specified, the program will try to continue parsing the data block" << endl;
902         cerr << "       as much as possible rather than stopping at the first error." << endl;
903         cerr << " -type <typename>" << endl;
904         cerr << "       Forces the contents of the file to be interpreted as a specific" << endl;
905         cerr << "       type of data block. Where <typename> can be one of:" << endl;
906         cerr << "         trigrecs - trigger records data." << endl;
907         cerr << "         trigrecsdebug - debugging information about trigger records." << endl;
908         cerr << "         trigchannels - channel debugging in." << endl;
909         cerr << "         rechits - reconstructed hits data." << endl;
910         cerr << "         channels - channel debugging information from hit reconstruction." << endl;
911         cerr << "         clusters - cluster debugging information from hit reconstruction." << endl;
912         cerr << "         mansotracks - partial tracks from Manso algorithm." << endl;
913         cerr << "         mansocandidates - track candidates considered in the Manso algorithm." << endl;
914         cerr << "         singlesdecision - trigger decisions for single tracks." << endl;
915         cerr << "         pairsdecision - trigger decisions for track pairs." << endl;
916 }
917
918 /**
919  * Parse the string passed as the type of the block and return the corresponding
920  * AliHLTMUONDataBlockType value.
921  */
922 AliHLTMUONDataBlockType ParseCommandLineType(const char* type)
923 {
924         if (strcmp(type, "trigrecs") == 0)
925         {
926                 return kTriggerRecordsDataBlock;
927         }
928         else if (strcmp(type, "trigrecsdebug") == 0)
929         {
930                 return kTrigRecsDebugDataBlock;
931         }
932         else if (strcmp(type, "trigchannels") == 0)
933         {
934                 return kTriggerChannelsDataBlock;
935         }
936         else if (strcmp(type, "rechits") == 0)
937         {      
938                 return kRecHitsDataBlock;
939         }
940         else if (strcmp(type,"channels") == 0)
941         {
942                 return kChannelsDataBlock;
943         }
944         else if (strcmp(type,"clusters") == 0)
945         {
946                 return kClustersDataBlock;
947         }
948         else if (strcmp(type, "mansotracks") == 0)
949         {
950                 return kMansoTracksDataBlock;
951         }
952         else if (strcmp(type, "mansocandidates") == 0)
953         {
954                 return kMansoCandidatesDataBlock;
955         }
956         else if (strcmp(type, "singlesdecision") == 0)
957         {
958                 return kSinglesDecisionDataBlock;
959         }
960         else if (strcmp(type, "pairsdecision") == 0)
961         {
962                 return kPairsDecisionDataBlock;
963         }
964         
965         cerr << "ERROR: Invalid type name '" << type << "' specified for argument -type."
966                 << endl << endl;
967         PrintUsage();
968         return kUnknownDataBlock;
969 }
970
971 /**
972  * Parses the command line.
973  * @param argc  Number of arguments as given in main().
974  * @param argv  Array of arguments as given in main().
975  * @param filename  Receives the pointer to the file name string.
976  * @param type      Receives the type of the data block expected, i.e. the
977  *                  value of the -type flag.
978  * @return  A status flag suitable for returning from main(), containing either
979  *          EXIT_SUCCESS or CMDLINE_ERROR.
980  */
981 int ParseCommandLine(
982                 int argc, const char** argv,
983                 const char*& filename, bool& continueParse,
984                 AliHLTMUONDataBlockType& type
985         )
986 {
987         filename = NULL;
988         continueParse = false;
989
990         // Parse the command line.
991         for (int i = 1; i < argc; i++)
992         {
993                 if (strcmp(argv[i], "-help") == 0 || strcmp(argv[i], "-h") == 0)
994                 {
995                         PrintUsage();
996                         return EXIT_SUCCESS;
997                 }
998                 else if (strcmp(argv[i], "-continue") == 0)
999                 {
1000                         continueParse = true;
1001                 }
1002                 else if (strcmp(argv[i], "-type") == 0)
1003                 {
1004                         // Now we need to parse the typename in the command line.
1005                         type = ParseCommandLineType(argv[++i]);
1006                         if (type == kUnknownDataBlock) return CMDLINE_ERROR;
1007                 }
1008                 else
1009                 {
1010                         if (filename != NULL)
1011                         {
1012                                 cerr << "ERROR: Only one file can be specified, but got '"
1013                                         << argv[i] << "', with '" << filename
1014                                         << "' specified earlier." << endl << endl;
1015                                 PrintUsage();
1016                                 return CMDLINE_ERROR;
1017                         }
1018                         else
1019                                 filename = argv[i];
1020                 }
1021         }
1022         
1023         // Now check that we have the filename and all the flags we need.
1024         if (filename == NULL)
1025         {
1026                 cerr << "ERROR: Missing a file name. You must specify a file to process."
1027                         << endl << endl;
1028                 PrintUsage();
1029                 return CMDLINE_ERROR;
1030         }
1031         
1032         return EXIT_SUCCESS;
1033 }
1034
1035
1036 int main(int argc, const char** argv)
1037 {
1038         const char* filename = NULL;
1039         bool continueParse = false;
1040         int returnCode = EXIT_SUCCESS;
1041         AliHLTMUONDataBlockType type = kUnknownDataBlock;
1042         char* buffer = NULL;
1043
1044         try
1045         {
1046                 returnCode = ParseCommandLine(argc, argv, filename, continueParse, type);
1047
1048                 if (returnCode == EXIT_SUCCESS)
1049                 {
1050                         unsigned long bufferSize = 0;
1051                         returnCode = ReadFile(filename, buffer, bufferSize);
1052                         if (returnCode == EXIT_SUCCESS)
1053                                 returnCode = ParseBuffer(buffer, bufferSize, continueParse, type);
1054                         if (buffer != NULL) delete [] buffer;
1055                 }
1056                 
1057         }
1058         catch (...)
1059         {
1060                 cerr << "FATAL ERROR: An unknown exception occurred!" << endl << endl;
1061                 returnCode = FATAL_ERROR;
1062                 if (buffer != NULL) delete [] buffer;
1063         }
1064
1065         return returnCode;
1066 }