Adding first version of data checking component for TPC.
authoraszostak <aszostak@f7af4fe6-9843-0410-8265-dc069ae4e863>
Wed, 11 Aug 2010 09:16:15 +0000 (09:16 +0000)
committeraszostak <aszostak@f7af4fe6-9843-0410-8265-dc069ae4e863>
Wed, 11 Aug 2010 09:16:15 +0000 (09:16 +0000)
HLT/TPCLib/AliHLTTPCAgent.cxx
HLT/TPCLib/AliHLTTPCDataCheckerComponent.cxx [new file with mode: 0644]
HLT/TPCLib/AliHLTTPCDataCheckerComponent.h [new file with mode: 0644]
HLT/TPCLib/test/Makefile.am
HLT/TPCLib/test/testAliHLTTPCDataCheckerComponent.C [new file with mode: 0644]

index 236e91c..0150a7f 100644 (file)
@@ -78,6 +78,7 @@ AliHLTTPCAgent gAliHLTTPCAgent;
 // #include "AliHLTTPCCalibTimeComponent.h"
 // #include "AliHLTTPCCalibTimeGainComponent.h"
 // #include "AliHLTTPCCalibrationComponent.h"
+#include "AliHLTTPCDataCheckerComponent.h"
 
 /** ROOT macro for the implementation of ROOT specific class methods */
 ClassImp(AliHLTTPCAgent)
@@ -303,6 +304,7 @@ int AliHLTTPCAgent::RegisterComponents(AliHLTComponentHandler* pHandler) const
 //   pHandler->AddComponent(new AliHLTTPCCalibTimeComponent);
 //   pHandler->AddComponent(new AliHLTTPCCalibTimeGainComponent);
 //   pHandler->AddComponent(new AliHLTTPCCalibrationComponent);
+  pHandler->AddComponent(new AliHLTTPCDataCheckerComponent);
 
   return 0;
 }
diff --git a/HLT/TPCLib/AliHLTTPCDataCheckerComponent.cxx b/HLT/TPCLib/AliHLTTPCDataCheckerComponent.cxx
new file mode 100644 (file)
index 0000000..62e01ad
--- /dev/null
@@ -0,0 +1,398 @@
+// $Id: $
+/**************************************************************************
+ * This file is property of and copyright by the ALICE HLT Project        *
+ * ALICE Experiment at CERN, All rights reserved.                         *
+ *                                                                        *
+ * Primary Authors: Artur Szostak <artursz@iafrica.com>                   *
+ *                  for The ALICE HLT Project.                            *
+ *                                                                        *
+ * Permission to use, copy, modify and distribute this software and its   *
+ * documentation strictly for non-commercial purposes is hereby granted   *
+ * without fee, provided that the above copyright notice appears in all   *
+ * copies and that both the copyright notice and this permission notice   *
+ * appear in the supporting documentation. The authors make no claims     *
+ * about the suitability of this software for any purpose. It is          *
+ * provided "as is" without express or implied warranty.                  *
+ **************************************************************************/
+
+/// @file   AliHLTTPCDataCheckerComponent.cxx
+/// @author Artur Szostak <artursz@iafrica.com>
+/// @date   9 Aug 2010
+/// @brief  Implementation of the AliHLTTPCDataCheckerComponent class.
+///
+/// The AliHLTTPCDataCheckerComponent is used to perform data sanity and integrity
+/// checks on the TPC data. This component should be used for testing and debugging.
+
+#include "AliHLTTPCDataCheckerComponent.h"
+#include "AliHLTTPCDefinitions.h"
+#include "AliTPCRawStreamV3.h"
+#include "AliRawReaderMemory.h"
+#include <vector>
+#include <cstring>
+#include <cassert>
+
+ClassImp(AliHLTTPCDataCheckerComponent)
+
+
+AliHLTTPCDataCheckerComponent::AliHLTTPCDataCheckerComponent() :
+       fRawStream(NULL),
+       fRawReader(NULL),
+       fForwardBadBlocks(false),
+       fForwardGoodBlocks(false),
+       fIgnoreType(false),
+       fIgnoreOrigin(false),
+       fIgnoreSpec(false),
+       fHandleAllEvents(false)
+{
+       // Default constructor.
+}
+
+
+AliHLTTPCDataCheckerComponent::~AliHLTTPCDataCheckerComponent()
+{
+       // Default destructor.
+       
+       if (fRawStream != NULL) delete fRawStream;
+       if (fRawReader != NULL) delete fRawReader;
+}
+
+
+const char* AliHLTTPCDataCheckerComponent::GetComponentID()
+{
+       // Returns the component ID.
+       return "TPCDataChecker";
+}
+
+
+void AliHLTTPCDataCheckerComponent::GetInputDataTypes(AliHLTComponentDataTypeList& list)
+{
+       // Returns the list of input data types that are handled.
+       list.push_back(kAliHLTAnyDataType | kAliHLTDataOriginTPC);
+}
+
+
+AliHLTComponentDataType AliHLTTPCDataCheckerComponent::GetOutputDataType()
+{
+       // Returns kAliHLTMultipleDataType.
+       return kAliHLTMultipleDataType;
+}
+
+
+int AliHLTTPCDataCheckerComponent::GetOutputDataTypes(AliHLTComponentDataTypeList& list)
+{
+       // Returns the list of output data block types generated.
+       list.push_back(kAliHLTAnyDataType);
+       return int(list.size());
+}
+
+
+void AliHLTTPCDataCheckerComponent::GetOutputDataSize(unsigned long& constBase, double& inputMultiplier)
+{
+       // Returns the buffer size requirements.
+       constBase = 0;
+       inputMultiplier = 0;
+}
+
+
+AliHLTComponent* AliHLTTPCDataCheckerComponent::Spawn()
+{
+       // Creates a new instance of the component.
+       return new AliHLTTPCDataCheckerComponent;
+}
+
+
+Int_t AliHLTTPCDataCheckerComponent::DoInit(int argc, const char** argv)
+{
+       // Initialises the data checker component from the command line.
+       
+       HLTInfo("Starting TPC data checker component.");
+       
+       fForwardBadBlocks = true;
+       fForwardGoodBlocks = true;
+       fIgnoreType = false;
+       fIgnoreOrigin = false;
+       fIgnoreSpec = false;
+       fHandleAllEvents = false;
+       
+       for (int i = 0; i < argc; ++i)
+       {
+               if (strcmp(argv[i], "-filter") == 0)
+               {
+                       if (i+1 < argc)
+                       {
+                               if (strcmp(argv[i+1], "forwardbad") == 0)
+                               {
+                                       fForwardBadBlocks = true;
+                                       fForwardGoodBlocks = false;
+                                       ++i;
+                               }
+                               else if (strcmp(argv[i+1], "forwardgood") == 0)
+                               {
+                                       fForwardBadBlocks = false;
+                                       fForwardGoodBlocks = true;
+                                       ++i;
+                               }
+                       }
+                       fForwardBadBlocks = true;
+                       fForwardGoodBlocks = false;
+                       continue;
+               }
+               
+               if (strcmp(argv[i], "-ignoretype") == 0)
+               {
+                       fIgnoreType = true;
+                       continue;
+               }
+               
+               if (strcmp(argv[i], "-ignoreorigin") == 0)
+               {
+                       fIgnoreOrigin = true;
+                       continue;
+               }
+               
+               if (strcmp(argv[i], "-ignorespec") == 0)
+               {
+                       fIgnoreSpec = true;
+                       continue;
+               }
+               
+               if (strcmp(argv[i], "-handle-all-events") == 0)
+               {
+                       fHandleAllEvents = true;
+                       continue;
+               }
+               
+               HLTError("Unknown option '%s'.", argv[i]);
+               return -EINVAL;
+       } // for loop
+       
+       if (fRawReader == NULL)
+       {
+               fRawReader = new AliRawReaderMemory();
+               if (fRawReader == NULL)
+               {
+                       HLTError("Could not allocate new AliRawReaderMemory object.");
+                       return -ENOMEM;
+               }
+       }
+       if (fRawStream == NULL)
+       {
+               fRawStream = new AliTPCRawStreamV3(fRawReader);
+               if (fRawStream == NULL)
+               {
+                       HLTError("Could not allocate new AliTPCRawStreamV3 object.");
+                       return -ENOMEM;
+               }
+               fRawStream->SelectRawData("TPC");
+       }
+       
+       return 0;
+}
+
+
+Int_t AliHLTTPCDataCheckerComponent::DoDeinit()
+{
+       // Cleans up the data checker component.
+       HLTInfo("Stopping TPC data checker component.");
+       if (fRawReader != NULL)
+       {
+               fRawReader->ClearBuffers();
+               fRawReader->Reset();
+       }
+       if (fRawStream != NULL)
+       {
+               fRawStream->Reset();
+       }
+       return 0;
+}
+
+
+int AliHLTTPCDataCheckerComponent::DoEvent(
+               const AliHLTComponentEventData& evtData,
+               const AliHLTComponentBlockData* blocks, 
+               AliHLTComponentTriggerData& trigData,
+               AliHLTUInt8_t* outputPtr, 
+               AliHLTUInt32_t& size,
+               AliHLTComponentBlockDataList& outputBlocks
+       )
+{
+       // Check all the input data blocks.
+       
+       if (fRawReader == NULL)
+       {
+               HLTError("The raw reader is not set.");
+               size = 0;
+               return -ENOENT;
+       }
+       if (fRawStream == NULL)
+       {
+               HLTError("The TPC raw stream is not set.");
+               size = 0;
+               return -ENOENT;
+       }
+       
+       if (not IsDataEvent() and not fHandleAllEvents)
+       {
+               // Forward all data blocks if we are not supposed to handle this event.
+               for (AliHLTUInt32_t n = 0; n < evtData.fBlockCnt; ++n)
+               {
+                       Forward(blocks + n);
+               }
+               size = 0;
+               return 0;
+       }
+       
+       AliHLTEventID_t event = evtData.fEventID;
+       
+       // Setup the markers indicating the bad blocks.
+       std::vector<bool> badBlock(evtData.fBlockCnt, false);
+       
+       for (AliHLTUInt32_t n = 0; n < evtData.fBlockCnt; ++n)
+       {
+               char ddltype[kAliHLTComponentDataTypefIDsize] = kAliHLTDDLRawDataTypeID;
+               if (memcmp(&(blocks[n].fDataType.fID), &ddltype, sizeof(ddltype)) == 0)
+               {
+                       badBlock[n] = not CheckRawDataBlock(event, n, blocks + n);
+               }
+               else if (not fIgnoreType)
+               {
+                       HLTError("Received raw data block %d in event %lld that we do not know how to handle."
+                               " The data block has data type '%s' and specification 0x%8.8X.",
+                               n, event, DataType2Text(blocks[n].fDataType).c_str(), blocks[n].fSpecification
+                       );
+               }
+       }
+       
+       // Forward the different blocks.
+       for (AliHLTUInt32_t n = 0; n < evtData.fBlockCnt; ++n)
+       {
+               if (badBlock[n] and fForwardBadBlocks)
+               {
+                       //int result = Forward(blocks + n);
+                       int result = Forward(blocks + n);
+                       if (result != 0)
+                       {
+                               size = 0;
+                               return result;
+                       }
+               }
+               if (not badBlock[n] and fForwardGoodBlocks)
+               {
+                       int result = Forward(blocks + n);
+                       if (result != 0)
+                       {
+                               size = 0;
+                               return result;
+                       }
+               }
+       }
+       
+       size = 0;
+       return 0;
+}
+
+
+bool AliHLTTPCDataCheckerComponent::CheckRawDataBlock(
+               AliHLTEventID_t event, AliHLTUInt32_t index,
+               const AliHLTComponentBlockData* block
+       )
+{
+       // Checks TPC raw DDL data blocks.
+       
+       assert(fRawReader != NULL);
+       assert(fRawStream != NULL);
+       
+       // Check the origin field of the data block.
+       if (not fIgnoreOrigin and
+           memcmp(&(block->fDataType.fOrigin), &kAliHLTDataOriginTPC, sizeof(kAliHLTDataOriginTPC)) != 0
+          )
+       {
+               char origin[kAliHLTComponentDataTypefOriginSize+1];
+               char expectedOrigin[kAliHLTComponentDataTypefOriginSize+1];
+               memcpy(&origin, &(block->fDataType.fOrigin), kAliHLTComponentDataTypefOriginSize);
+               memcpy(&expectedOrigin, &(kAliHLTDataOriginTPC), kAliHLTComponentDataTypefOriginSize);
+               origin[kAliHLTComponentDataTypefOriginSize] = '\0'; // remember the NULL character for the ANSI string.
+               expectedOrigin[kAliHLTComponentDataTypefOriginSize] = '\0';
+               HLTError("Received raw DDL data block %d in event %lld which has an origin '%s', but expected '%s'.",
+                       index, event, origin, expectedOrigin
+               );
+               return false;
+       }
+       
+       // Decode and check the specification bits.
+       AliHLTUInt8_t slice = AliHLTTPCDefinitions::GetMinSliceNr(block->fSpecification);
+       AliHLTUInt8_t patch = AliHLTTPCDefinitions::GetMinPatchNr(block->fSpecification);
+       Int_t ddlid = AliHLTTPCDefinitions::SlicePatchToDDLId(slice, patch);
+       if (slice != AliHLTTPCDefinitions::GetMaxSliceNr(block->fSpecification))
+       {
+               HLTError("Received raw DDL data block %d in event %lld which has a"
+                       " different minimum and maximum slice number (%d verse %d).",
+                       index, event, int(slice), int(AliHLTTPCDefinitions::GetMaxSliceNr(block->fSpecification))
+               );
+               return false;
+       }
+       if (patch != AliHLTTPCDefinitions::GetMaxPatchNr(block->fSpecification))
+       {
+               HLTError("Received raw DDL data block %d in event %lld which has a"
+                       " different minimum and maximum patch number (%d verse %d).",
+                       index, event, int(patch), int(AliHLTTPCDefinitions::GetMaxPatchNr(block->fSpecification))
+               );
+               return false;
+       }
+       if (ddlid == -1)
+       {
+               HLTError("Received raw DDL data block %d in event %lld which has an"
+                       " invalid specification 0x%8.8X. Cannot decode the DDL ID number.",
+                       index, event, block->fSpecification
+               );
+               return false;
+       }
+       
+       // Now try decode the DDL data. Do it in a try catch block in case
+       // the decoder segfaults. We want to know about this and log it.
+       bool result = false;
+       try
+       {
+               fRawReader->ClearBuffers();
+               fRawReader->Reset();
+               fRawStream->Reset();
+               fRawReader->AddBuffer(reinterpret_cast<UChar_t*>(block->fPtr), block->fSize, ddlid);
+               if (fRawStream->NextDDL())
+               {
+                       while (fRawStream->NextChannel())
+                       {
+                               while (fRawStream->NextBunch())
+                               {
+                                       UInt_t startTimeBin = fRawStream->GetStartTimeBin();
+                                       UInt_t endTimeBin = fRawStream->GetEndTimeBin();
+                                       Int_t bunchLength = fRawStream->GetBunchLength();
+                                       const UShort_t* bunchData = fRawStream->GetSignals();
+                                       cout << "startTimeBin = " << startTimeBin << endl;
+                                       cout << "endTimeBin = " << endTimeBin << endl;
+                                       cout << "bunchLength = " << bunchLength << endl;
+                                       for (Int_t i = 0; i < bunchLength; ++i)
+                                       {
+                                               cout << "bunchData[" << i << "] = " << bunchData[i] << endl;
+                                       }
+                               }
+                       }
+                       result = true;
+               }
+               else
+               {
+                       HLTError("Cannot decode the raw DDL data (DDL ID = %d) from"
+                               " data block %d in event %lld.",
+                               ddlid, index, event
+                       );
+               }
+       }
+       catch (...)
+       {
+               HLTError("Caught an exception when processing raw DDL data (DDL ID = %d)"
+                       " from data block %d in event %lld.",
+                       ddlid, index, event
+               );
+       }
+       return result;
+}
+
diff --git a/HLT/TPCLib/AliHLTTPCDataCheckerComponent.h b/HLT/TPCLib/AliHLTTPCDataCheckerComponent.h
new file mode 100644 (file)
index 0000000..ed833c8
--- /dev/null
@@ -0,0 +1,128 @@
+//-*- Mode: C++ -*-
+// $Id: $
+#ifndef ALIHLTTPCDATACHECKERCOMPONENT_H
+#define ALIHLTTPCDATACHECKERCOMPONENT_H
+/* This file is property of and copyright by the ALICE HLT Project        *
+ * ALICE Experiment at CERN, All rights reserved.                         *
+ * See cxx source for full Copyright notice                               */
+
+/// \file   AliHLTTPCDataCheckerComponent.h
+/// \author Artur Szostak <artursz@iafrica.com>
+/// \date   9 Aug 2010
+/// \brief  Declaration of the AliHLTTPCDataCheckerComponent component class.
+
+#include "AliHLTProcessor.h"
+
+class AliTPCRawStreamV3;
+class AliRawReaderMemory;
+
+/**
+ * \class AliHLTTPCDataCheckerComponent
+ * The TPC data checker component is used to validate the raw data entering the HLT
+ * from the TPC detector. Basic sanity and data integrity checks are performed.
+ * Any problems are logged with explanatory error messages. By default all data blocks
+ * are forwarded, but one can also optionally filter on the bad data blocks.
+ *
+ * <h2>General properties:</h2>
+ *
+ * Component ID: \b TPCDataChecker <br>
+ * Library: \b libAliHLTTPC.so   <br>
+ * Input Data Types:  ::kAliHLTAnyDataType | ::kAliHLTDataOriginTPC <br>
+ * Output Data Types: ::kAliHLTAnyDataType | ::kAliHLTDataOriginTPC <br>
+ *
+ * <h2>Mandatory arguments:</h2>
+ * None.
+ *
+ * <h2>Optional arguments:</h2>
+ * \li -filter <i>flag</i> <br>
+ *      If specified then all data blocks for which a problem was found are forwarded
+ *      and all others are dropped. If the optional <i>flag</i> is specified then it
+ *      can be one of:
+ *        forwardbad  - only the bad data blocks are forwarded (default option).
+ *        forwardgood - only the good data blocks are forwarded.
+ * \li -ignoretype <br>
+ *      If set then the check of the data type is not performed.
+ * \li -ignoreorigin <br>
+ *      If set then the check of the origin is not performed.
+ * \li -ignorespec <br>
+ *      If set then the check of the block specification is not performed.
+ * \li -handle-all-events <br>
+ *      If set then all events are handled and not just data events.
+ *
+ * <h2>Configuration:</h2>
+ * Can only be configured with the command line arguments.
+ *
+ * <h2>Default CDB entries:</h2>
+ * None.
+ *
+ * <h2>Performance:</h2>
+ * TODO
+ *
+ * <h2>Memory consumption:</h2>
+ * Negligible.
+ *
+ * <h2>Output size:</h2>
+ * The same as the input data size.
+ *
+ * \ingroup alihlt_tpc_components
+ */
+class AliHLTTPCDataCheckerComponent : public AliHLTProcessor
+{
+public:
+       
+       AliHLTTPCDataCheckerComponent();
+       virtual ~AliHLTTPCDataCheckerComponent();
+       
+       // Methods inherited from AliHLTComponent:
+       virtual const char* GetComponentID();
+       virtual void GetInputDataTypes(AliHLTComponentDataTypeList& list);
+       virtual AliHLTComponentDataType GetOutputDataType();
+       virtual int GetOutputDataTypes(AliHLTComponentDataTypeList& list);
+       virtual void GetOutputDataSize(unsigned long& constBase, double& inputMultiplier);
+       virtual AliHLTComponent* Spawn();
+       virtual Int_t DoInit(int argc, const char** argv);
+       virtual Int_t DoDeinit();
+       
+protected:
+       
+       // Method inherited from AliHLTProcessor:
+       virtual int DoEvent(
+                       const AliHLTComponentEventData& evtData,
+                       const AliHLTComponentBlockData* blocks, 
+                       AliHLTComponentTriggerData& trigData,
+                       AliHLTUInt8_t* outputPtr, 
+                       AliHLTUInt32_t& size,
+                       AliHLTComponentBlockDataList& outputBlocks
+               );
+       
+       using AliHLTProcessor::DoEvent;
+       
+private:
+       
+       // Do not allow copying of this class.
+       AliHLTTPCDataCheckerComponent(const AliHLTTPCDataCheckerComponent& obj);
+       AliHLTTPCDataCheckerComponent& operator = (const AliHLTTPCDataCheckerComponent& obj);
+       
+       /**
+        * Checks the structure of a TPC raw DDL data block.
+        * \param event  The event this data block was found in.
+        * \param index  The index number of the data block as found in the
+        *               DoEvent::blocks parameter.
+        * \param block  The data block to check. Must correspond to 'index'.
+        * \returns true if the raw data is OK and false otherwise.
+        */
+       bool CheckRawDataBlock(AliHLTEventID_t event, AliHLTUInt32_t index, const AliHLTComponentBlockData* block);
+       
+       AliTPCRawStreamV3* fRawStream;  /// Raw stream to read TPC data.
+       AliRawReaderMemory* fRawReader;  /// Raw reader object for the TPC stream.
+       bool fForwardBadBlocks;  /// Flag indicating if the bad blocks should be forwarded.
+       bool fForwardGoodBlocks;  /// Flag indicating if the good blocks should be forwarded.
+       bool fIgnoreType;     /// Indicates if the data block type should not be checked.
+       bool fIgnoreOrigin;   /// Indicates if the data block origin should not be checked.
+       bool fIgnoreSpec;     /// Indicates if the data block specification bits should not be checked.
+       bool fHandleAllEvents; /// Indicates if all event types are processed and not just data events.
+       
+       ClassDef(AliHLTTPCDataCheckerComponent, 0)  // Data sanity and integrity checker component for TPC data.
+};
+
+#endif // ALIHLTTPCDATACHECKERCOMPONENT_H
index 3aeea73..8f528e6 100644 (file)
@@ -12,12 +12,14 @@ EXTRA_DIST                  =
 check_PROGRAMS                 = testAliHLTTPCDigitReaderDecoder \
                                  testAliHLTTPCDigitReaderPacked \
                                  testAliHLTTPCMapping \
-                                 testAliHLTTPCDefinitions
+                                 testAliHLTTPCDefinitions \
+                                 testAliHLTTPCDataCheckerComponent
 
 testAliHLTTPCDigitReaderDecoder_SOURCES = testAliHLTTPCDigitReaderDecoder.C
 testAliHLTTPCDigitReaderPacked_SOURCES = testAliHLTTPCDigitReaderPacked.C
 testAliHLTTPCMapping_SOURCES           = testAliHLTTPCMapping.C
 testAliHLTTPCDefinitions_SOURCES       = testAliHLTTPCDefinitions.C
+testAliHLTTPCDataCheckerComponent_SOURCES      = testAliHLTTPCDataCheckerComponent.C
 
 
 # linker flags
@@ -32,13 +34,16 @@ testAliHLTTPCDigitReaderDecoder_LDADD       = $(LDADD_COMMON)
 testAliHLTTPCDigitReaderPacked_LDADD   = $(LDADD_COMMON)
 testAliHLTTPCMapping_LDADD             = $(LDADD_COMMON)
 testAliHLTTPCDefinitions_LDADD         = $(LDADD_COMMON)
+testAliHLTTPCDataCheckerComponent_LDADD        = $(LDADD_COMMON)
 testAliHLTTPCDigitReaderDecoder_LDFLAGS        = $(LDFLAGS_COMMON)
 testAliHLTTPCDigitReaderPacked_LDFLAGS = $(LDFLAGS_COMMON)
 testAliHLTTPCMapping_LDFLAGS           = $(LDFLAGS_COMMON)
 testAliHLTTPCDefinitions_LDFLAGS       = $(LDFLAGS_COMMON)
+testAliHLTTPCDataCheckerComponent_LDFLAGS      = $(LDFLAGS_COMMON)
 
 # set back to all as sson as DigitReaderPacked is fixed
 #TESTS                         = $(check_PROGRAMS)
 TESTS                          = testAliHLTTPCDigitReaderDecoder \
                                  testAliHLTTPCMapping \
-                                 testAliHLTTPCDefinitions
+                                 testAliHLTTPCDefinitions \
+                                 testAliHLTTPCDataCheckerComponent
diff --git a/HLT/TPCLib/test/testAliHLTTPCDataCheckerComponent.C b/HLT/TPCLib/test/testAliHLTTPCDataCheckerComponent.C
new file mode 100644 (file)
index 0000000..db10fac
--- /dev/null
@@ -0,0 +1,168 @@
+/**************************************************************************
+ * This file is property of and copyright by the ALICE HLT Project        *
+ * ALICE Experiment at CERN, All rights reserved.                         *
+ *                                                                        *
+ * Primary Authors: Artur Szostak <artursz@iafrica.com>                   *
+ *                  for The ALICE HLT Project.                            *
+ *                                                                        *
+ * Permission to use, copy, modify and distribute this software and its   *
+ * documentation strictly for non-commercial purposes is hereby granted   *
+ * without fee, provided that the above copyright notice appears in all   *
+ * copies and that both the copyright notice and this permission notice   *
+ * appear in the supporting documentation. The authors make no claims     *
+ * about the suitability of this software for any purpose. It is          *
+ * provided "as is" without express or implied warranty.                  *
+ **************************************************************************/
+
+/**
+ * @file   testAliHLTTPCDataCheckerComponent.C
+ * @author Artur Szostak <artursz@iafrica.com>
+ * @date   9 Aug 2010
+ *
+ * This macro is used to test the basic functionality of the
+ * AliHLTTPCDataCheckerComponent class.
+ */
+
+#if !defined(__CINT__) || defined(__MAKECINT__)
+#include "Riostream.h"
+#include "TSystem.h"
+#include "TClassTable.h"
+#include "AliLog.h"
+#include "AliHLTSystem.h"
+#include "AliHLTConfiguration.h"
+#include <fstream>
+#include <cstdlib>
+#endif
+
+/**
+ * Creates the input data for the test.
+ * It is just a file of 256 bytes with all zeros.
+ */
+void GenerateInputData(bool debug = false)
+{
+       using namespace std;
+       const char* filename = "dataCheckerInputTestFile.dat";
+       fstream file(filename, ios::trunc | ios::out | ios::binary);
+       if (! file)
+       {
+               if (debug) cerr << "ERROR: Could not create file " << filename << endl;
+               return;
+       }
+       
+       char buffer[256];
+       memset(buffer, 0x0, sizeof(buffer));
+       AliHLTUInt32_t* words = reinterpret_cast<AliHLTUInt32_t*>(buffer);
+       words[0] = 0xFFFFFFFF;
+       words[3] = 0x03000000;  // RCU version 3 in CDH block attributes field.
+       
+       file.write(buffer, sizeof(buffer));
+       if (! file)
+       {
+               if (debug) cerr << "ERROR: I/O error when writing to file " << filename << endl;
+               return;
+       }
+       file.close();
+}
+
+/**
+ * Routine to run a HLT chain with the data checker component to generate output
+ * which we can later check. The chain will only test basic functionality of the
+ * component.
+ */
+void RunChainToCheckComponent(bool debug = false)
+{
+       // Done before to prevent output from AliHLTSystem.
+       if (debug)
+       {
+               AliLog::SetGlobalLogLevel(AliLog::kMaxType);
+       }
+       else
+       {
+               AliLog::SetGlobalLogLevel(AliLog::kFatal);
+       }
+       AliHLTSystem sys;
+       sys.LoadComponentLibraries("libAliHLTUtil.so");
+       sys.LoadComponentLibraries("libAliHLTTPC.so");
+       if (debug)
+       {
+               sys.SetGlobalLoggingLevel(kHLTLogAll);
+       }
+       else
+       {
+               sys.SetGlobalLoggingLevel(kHLTLogNone);
+       }
+       
+       AliHLTConfiguration src(
+               "source",
+               "FilePublisher",
+               "",
+               "-datatype 'DDL_RAW ' 'TPC ' -dataspec 0x01010202 -datafile dataCheckerInputTestFile.dat"
+       );
+       AliHLTConfiguration prc(
+               "processor",
+               "TPCDataChecker",
+               "source",
+               "-filter forwardbad -ignoretype"
+       );
+       AliHLTConfiguration snk(
+               "sink",
+               "FileWriter",
+               "processor",
+               "-specfmt -datafile dataCheckerOutputTestFile.dat"
+       );
+       
+       sys.BuildTaskList("sink");
+       sys.Run(1); // Run for 1 event.
+}
+
+/**
+ * Checks the output data generated by the chain.
+ * There should be one data block corresponding to the invalid input data block.
+ */
+bool CheckOutput()
+{
+       if (gSystem->Exec("test -f dataCheckerOutputTestFile_0x00000000_0x00_TPC:DDL_RAW_0x01010202.dat") != 0)
+       {
+               cerr << "ERROR: The AliHLTTPCDataCheckerComponent did not generate the expected"
+                       " output data block when given a corrupt input data block." << endl;
+               return false;
+       }
+       if (gSystem->Exec("diff dataCheckerInputTestFile.dat dataCheckerOutputTestFile_0x00000000_0x00_TPC:DDL_RAW_0x01010202.dat") != 0)
+       {
+               cerr << "ERROR: The AliHLTTPCDataCheckerComponent forwarded the"
+                       " wrong data block when checking for errors." << endl;
+               return false;
+       }
+       return true;
+}
+
+/**
+ * This is the top level testing method which calls individual tests.
+ * \returns true if all tests succeeded and false otherwise.
+ */
+bool testAliHLTTPCDataCheckerComponent(bool debug = false)
+{
+       if (gClassTable->GetID("AliHLTTPCDataCheckerComponent") < 0)
+       {
+               gSystem->Load("libAliHLTUtil.so");
+       }
+       GenerateInputData(debug);
+       RunChainToCheckComponent(debug);
+       if (! CheckOutput()) return false;
+       
+       // Cleanup all temporary files generated.
+       gSystem->Exec("rm -f dataCheckerInputTestFile.dat dataCheckerOutputTestFile*.dat");
+       return true;
+}
+
+#ifndef __MAKECINT__
+
+int main(int /*argc*/, const char** /*argv*/)
+{
+       bool resultOk = testAliHLTTPCDataCheckerComponent();
+       if (not resultOk) return 1;
+       return 0;
+}
+
+#endif // __MAKECINT__
+