/*************************************************************************** * Generic example of application for unpacking library * * * * Originally created by J.S. Graulich May 2011 * * * ***************************************************************************/ #include #include #include #include #include #include #include "MDprocessManager.h" #include "MDevent.h" #include "MDdateFile.h" #include "MDfileManager.h" #include "MDargumentHandler.h" #include "MDfragmentVLSB_C.h" #include "MDfragmentV830.h" #include "MDfragmentV1290.h" #include "MDfragmentV1724.h" #include "MDpartEventV1290.h" #include "MDpartEventV1724.h" #include "MDpartEventV1731.h" #include "MDfragmentDBB.h" using namespace std; // Create a MDprocessor daughter class for each data structure to be analysed. // In this example, all the classes are declared and defined in the same file // but for real applications, C++ good practice is to have one .h and one .cpp // file per class. class OnStartOfRun : public MDprocessor { public: OnStartOfRun():MDprocessor(){} virtual ~OnStartOfRun(){} virtual int Process(MDdataContainer*); }; int OnStartOfRun::Process(MDdataContainer* aEvtPtr){ cout << "Starting run " << GetRunNumber() << " on " << GetTimeString() << endl; return OK; } /////////////////////////////////////////////////////// class OnStartOfSpill : public MDprocessor { public: OnStartOfSpill():MDprocessor(){} virtual ~OnStartOfSpill(){} virtual int Process(MDdataContainer*); }; int OnStartOfSpill::Process(MDdataContainer* aEvtPtr){ cout << "---> Start of Spill Number " << GetSpillNumber() << " on " << GetTimeString() << endl; return OK; } ///////////////////////////////////////////////////// class OnEndOfSpill : public MDprocessor { public: OnEndOfSpill():MDprocessor(){} virtual ~OnEndOfSpill(){} virtual int Process(MDdataContainer*); }; int OnEndOfSpill::Process(MDdataContainer* aEvtPtr){ cout << "---> End of Spill Number " << GetSpillNumber(); cout << " on " << GetTimeString(); // GetTimeString add an endl cout << " DAQ Physics Event Count : " << GetPhysEventNumber()+1 << endl; return OK; } ///////////////////////////////////////////////////// //********* OnSuperHeader ************** // In this example, the object to fill is meant to be the standard output // and the parameter is meant to be a single int value (given in the main argument list) class OnSuperHeader : public MDprocessor { public: OnSuperHeader(ostream &aStream):MDprocessor(),myObj(&aStream) {} virtual ~OnSuperHeader(){} virtual int Process(MDdataContainer*); ostream* myObj; }; int OnSuperHeader::Process(MDdataContainer* aEvtPtr){ // cast the argument to structure it points to // This process should be called only with MDevent argument corresponding to super event if ( typeid(*aEvtPtr) != typeid(MDevent) ) return CastError; MDevent* theEvent = static_cast(aEvtPtr); if ( *(theEvent->MagicPtr()) != EVENT_MAGIC_NUMBER ) { throw MDexception("ERROR in OnSuperHeader::Process() : The function is called with unvalid argument ***", MDexception::FATAL) ; } if (!theEvent->IsSuperEvent()) { throw MDexception("ERROR in OnSuperHeader::Process() : This function should not be called for non-super event ***", MDexception::FATAL) ; } static unsigned int superEventCount(0); *myObj << "*** Super header count : " << ++superEventCount << " ***" << endl; *myObj << " Run Number : " << theEvent->RunNb() << endl; *myObj << " Event Size : " << theEvent->EventSize() << endl; MDeventType eventType(theEvent->EventTypePtr()); *myObj << " Event Type : " << eventType << endl; uint32_t *xTime = (uint32_t*) theEvent->TimeStampPtr(); // explicit cast required for 64 bit compatibility time_t xMyTime = *xTime; cout << " time:" << ctime( &xMyTime ); // Note: ctime will add endl return OK; } ///////////////////////////////////////////////////////////////////////// // This class is an example to show how to pass information from one // processor to the other, using a user class passed either as object or param. // This is only for illustration. Context data should be taken directly from the Process Manager class ContextData { public: uint32_t _runNumber; uint32_t _ldcId; uint32_t _eventType; uint32_t _physEventCount; uint32_t _equipmentType; uint32_t _boardId; ContextData():_runNumber(0),_ldcId(0),_eventType(0),_physEventCount(0),_equipmentType(0),_boardId(0){} ~ContextData(){} void SetRunNumber(uint32_t aRunNumber){_runNumber = aRunNumber;} void SetLdcId(uint32_t aLdcId){_ldcId = aLdcId;} void SetEventType(uint32_t aEventType){_eventType = aEventType;} void SetPhysEventCount(uint32_t aCount){_physEventCount = aCount;} void SetEquipmentType(uint32_t aEquipmentType){_equipmentType = aEquipmentType;} void SetBoardId(uint32_t aBoardId){_boardId = aBoardId;} uint32_t GetRunNumber(){return _runNumber;} uint32_t GetLdcId(){return _ldcId;} uint32_t GetEventType(){return _eventType;} uint32_t GetPhysEventCount(){return _physEventCount;} uint32_t GetEquipmentType(){return _equipmentType;} uint32_t GetBoardId(){return _boardId;} void Print(){ cout << " *** Context Data ***" << dec << endl; cout << " Run Number : " << GetRunNumber(); cout << " ; LDC Id : " << GetLdcId(); cout << " ; Event Type : " << GetEventType(); cout << " ; Physics Event Count : " << GetPhysEventCount(); cout << " ; Equipment Type : " << GetEquipmentType(); cout << " ; Board Id : " << GetBoardId() << endl; } }; ///////////////////////////////////////////////////////////////////////// //********* OnEventHeader ************** // In this example, the object to fill is meant to be an instance of a user defined // class describing the context, // and the parameter is meant to be the name of an existing file containing a int value // class OnEventHeader : public MDprocessor { public: OnEventHeader(ContextData &aContext):MDprocessor(),myObj(&aContext) {} virtual ~OnEventHeader(){} virtual int Process(MDdataContainer*); ContextData* myObj; }; int OnEventHeader::Process(MDdataContainer* aEvtPtr){ // cast the argument to structure it points to // This process should be called only with MDevent argument corresponding to LDC event if ( typeid(*aEvtPtr) != typeid(MDevent) ) return CastError; MDevent* theEvent = static_cast(aEvtPtr); if ( *(theEvent->MagicPtr()) != EVENT_MAGIC_NUMBER ) { throw MDexception("ERROR in OnEventHeader::Process() : The function is called with unvalid argument ***", MDexception::FATAL) ; } if (theEvent->IsSuperEvent()) { throw MDexception("ERROR in OnEventHeader::Process() : This function should not be called for super event ***", MDexception::FATAL) ; } static vector eventCount(2); static int firstCall(1); if (firstCall) { eventCount[0]=0; eventCount[1]=0; firstCall = 0; } // fill the context data structure with the data available at this level myObj->SetRunNumber(theEvent->RunNb()); myObj->SetLdcId(theEvent->LdcId()); myObj->SetEventType(theEvent->EventType()); myObj->SetPhysEventCount(eventCount[theEvent->LdcId()]); // myObj->Print(); cout << " LDC Id : " << theEvent->LdcId() << endl; cout << " Event Size : " << theEvent->EventSize() << endl; MDeventType eventType(theEvent->EventTypePtr()); cout << " Event Type : " << eventType << endl; cout << " Physics Event Number : " << eventCount[theEvent->LdcId()] << endl; uint32_t *xTime = (uint32_t*) theEvent->TimeStampPtr(); // explicit cast required for 64 bit compatibility time_t xMyTime = *xTime; cout << " Time Stamp:" << ctime( &xMyTime ); // Note: ctime will add endl if (theEvent->EventType() == PHYSICS_EVENT) { eventCount[theEvent->LdcId()]++;} return OK; } //********* OnEquipmentHeader ************** // In this example, the object to fill is meant to be an instance of a user defined // class describing the context and there is no parameter // class OnEquipmentHeader : public MDprocessor { public: OnEquipmentHeader(ContextData &aContext):MDprocessor(),myObj(&aContext){} virtual ~OnEquipmentHeader(){} virtual int Process(MDdataContainer*); ContextData* myObj; }; int OnEquipmentHeader::Process(MDdataContainer* aEquipmentPtr){ // cast the argument to structure it points to // This process should be called only with MDeventFragment argument if ( typeid(*aEquipmentPtr) != typeid(MDeventFragment) ) return CastError; MDeventFragment* theEquipment = static_cast(aEquipmentPtr); // fill the context data structure with the data available at this level myObj->SetEquipmentType(theEquipment->EquipmentType()); myObj->SetBoardId(theEquipment->EquipmentId()); // myObj->Print(); return OK; } //********* OnFragmentVLSB_C ************** // In this example, useful for Tracker cosmic data // the object to fill is meant to be an output stream // and the parameter is meant to be a instance of a user defined class // describing the context // class OnFragmentVLSB_C : public MDprocessor { public: OnFragmentVLSB_C(ostream &aOs, ContextData &aContext):MDprocessor(),myObj(&aOs),myPar(&aContext){} virtual ~OnFragmentVLSB_C(){} virtual int Process(MDdataContainer*); ostream* myObj; ContextData* myPar; }; int OnFragmentVLSB_C::Process(MDdataContainer* aFragPtr){ // cast the argument to structure it points to // This process should be called only with MDfragmentVLSB_C argument if ( typeid(*aFragPtr) != typeid(MDfragmentVLSB_C) ) return CastError; MDfragmentVLSB_C* theFrag = static_cast(aFragPtr); if ( myPar->GetEventType() == PHYSICS_EVENT || myPar->GetEventType() == CALIBRATION_EVENT){ // print context *myObj << " In" << MDequipMap::GetName(myPar->GetEquipmentType()) ; *myObj << " board # " << myPar->GetBoardId() << endl; // print bank lengths *myObj << " Bank Lengths : "; for (int ib=0; ib<4; ib++){ *myObj << theFrag->GetBankLength(ib) << " ; "; } *myObj << endl; // print unpacked channel and adc data MDdataWordVLSB dw; for (unsigned int iw=0; iwGetPayLoadWordCount(); iw++){ dw.SetDataPtr(theFrag->GetDataWordPtr(iw)); *myObj << "channel : " << dw.GetChannel() << " ; adc : " << dw.GetAdc() << endl; } } return OK; } //********* OnFragmentV830 ************** // In this example, the VME scaler data is unpacked and sent to the output stream // the object to fill is meant to be an output stream // and the parameter is meant to be a instance of a user defined class // describing the context // class OnFragmentV830 : public MDprocessor { public: OnFragmentV830(ostream &aOs, ContextData &aContext):MDprocessor(),myObj(&aOs),myPar(&aContext){} virtual ~OnFragmentV830(){} virtual int Process(MDdataContainer*); ostream* myObj; ContextData* myPar; }; int OnFragmentV830::Process(MDdataContainer* aFragPtr){ // cast the argument to structure it points to // This process should be called only with MDfragmentV830 argument if ( typeid(*aFragPtr) != typeid(MDfragmentV830) ) return CastError; MDfragmentV830* theFrag = static_cast(aFragPtr); unsigned int * ptr = theFrag->Get32bWordPtr(0); MDdataWordV830 dw(ptr) ; unsigned int wc(0); // The vme scaler has only valid data for PHYSICS_EVENTs if ( myPar->GetEventType() == PHYSICS_EVENT ){ while (wc < theFrag->GetWordCount() ) { uint32_t dt= dw.GetDataType(); switch ( dt ) { case DWV830_Measurement: { *myObj << " Ch " << setw(2) << dec << dw.GetChannel() ; *myObj << " ; data: " << dec << dw.GetMeasurement() << endl ; break; } case DWV830_Header: { *myObj << " Equipment " << theFrag->GetName() << " ; board " << dw.GetGeo() << endl; if ((uint32_t)dw.GetGeo() != myPar->GetBoardId()) return FormatError; break; } } wc++; dw.SetDataPtr( ++ptr ); } } return OK; } //********* OnFragmentV1290 ************** // Minimal example, no object to fill, no parameter // class OnFragmentV1290 : public MDprocessor { public: OnFragmentV1290():MDprocessor(){} virtual ~OnFragmentV1290(){} virtual int Process(MDdataContainer*); }; int OnFragmentV1290::Process(MDdataContainer* aFragPtr){ // cast the argument to structure it points to MDfragmentV1290* theFrag = static_cast(aFragPtr); cout << " Number of particle Events in " << theFrag->GetName(); cout << " : " << theFrag->GetNPartEvents() << endl; return OK; } //********* OnFragmentDBB ************** // Minimal example, no object to fill, no parameter // class OnFragmentDBB : public MDprocessor { public: OnFragmentDBB():MDprocessor(){} virtual ~OnFragmentDBB(){} virtual int Process(MDdataContainer*); }; int OnFragmentDBB::Process(MDdataContainer* aFragPtr){ // cast the argument to structure it points to // MDfragmentDBB* theFrag = static_cast(aFragPtr); return OK; } //********* OnPartEventV1290 ************** // In this example, the tdc data is unpacked and sent to the output stream // the object to fill is meant to be an output stream // The context data is taken directly from the Process Manager // class OnPartEventV1290 : public MDprocessor { public: OnPartEventV1290(ostream &aOs):MDprocessor(),myObj(&aOs){} virtual ~OnPartEventV1290(){} virtual int Process(MDdataContainer*); ostream* myObj; }; int OnPartEventV1290::Process(MDdataContainer* aPartEventPtr){ // cast the argument to structure it points to if ( typeid(*aPartEventPtr) != typeid(MDpartEventV1290) ) return CastError; MDpartEventV1290* thePart=static_cast(aPartEventPtr); ; static int iPartEvt(0); // print only the first 10 particle events static uint32_t oldBoard(0); if ( GetBoardId() != oldBoard ) { oldBoard=GetBoardId(); iPartEvt=0; } if (iPartEvt++ < 10) { *myObj << "In Equipment " << MDequipMap::GetName(GetEquipmentType()) ; *myObj << " ; Crate # " << GetLdcId() ; *myObj << " ; Board # " << GetBoardId() ; *myObj << " ; Particle Event Number : " << thePart->GetEventCount() << endl; *myObj << " Number of Leading Edge Hits : " << thePart->GetNHits(V1290_NCHANNELS,'l') << endl; *myObj << " Number of Trailing Edge Hits : " << thePart->GetNHits(V1290_NCHANNELS,'t') << endl; *myObj << " Total Number of Hits : " << thePart->GetNHits() << endl; *myObj << " Bunch ID : " << thePart->GetBunchID(0) ; *myObj << " ; Trigger Time Tag : " << thePart->GetTriggerTimeTag() << endl; // loop over channels if (!thePart->GetNHits(0,'l')) { cerr << " Missing hit in particle trigger channel " << endl; return FormatError; } for (int ich =0 ; ichGetNHits(ich,'l')) { *myObj << " Channel : " << ich << " :";} for (unsigned int ih =0 ; ihGetNHits(ich,'l') ; ih++) { *myObj << " " << thePart->GetHitMeasurement(ih,ich,'l'); } if (thePart->GetNHits(ich,'l')) { *myObj << endl; } } } return OK; } //********* OnPartEventV1724 ************** // In this example, the flash adc data is unpacked and sent to the output stream // the object to fill is meant to be an output stream // The context data is taken directly from the Process Manager // class OnPartEventV1724 : public MDprocessor { public: OnPartEventV1724(ostream &aOs):MDprocessor(),myObj(&aOs){} virtual ~OnPartEventV1724(){} virtual int Process(MDdataContainer*); ostream* myObj; }; int OnPartEventV1724::Process(MDdataContainer* aPartEventPtr){ // cast the argument to structure it points to if ( typeid(*aPartEventPtr) != typeid(MDpartEventV1724) ) return CastError; MDpartEventV1724* thePart = static_cast(aPartEventPtr); static int iPartEvt(0); // print only the first 10 particle events per board static uint32_t oldBoard(0); if ( GetBoardId() != oldBoard ) { oldBoard=GetBoardId(); iPartEvt=0; } if (iPartEvt++ < 10) { *myObj << "In Equipment " << MDequipMap::GetName(GetEquipmentType()) ; *myObj << " ; Crate # " << GetLdcId() ; *myObj << " ; Board # " << GetBoardId() ; *myObj << " ; Particle Event Number : " << thePart->GetEventCount() << endl; *myObj << " Trigger Time Tag : " << thePart->GetTriggerTimeTag() << endl; // print data for the last channel for (int ich=0 ; ichGetLength(ich) ) for (unsigned int is =0 ; isGetNSamples(ich) ; is++) { *myObj << " " << thePart->GetSampleData(ich,is); } *myObj << endl; } } return OK; } //********* OnPartEventV1731 ************** // In this example, the flash adc data is unpacked and sent to the output stream // the object to fill is meant to be an output stream // The context data is taken directly from the Process Manager // class OnPartEventV1731 : public MDprocessor { public: OnPartEventV1731(ostream &aOs):MDprocessor(),myObj(&aOs){} virtual ~OnPartEventV1731(){} virtual int Process(MDdataContainer*); ostream* myObj; }; int OnPartEventV1731::Process(MDdataContainer* aPartEventPtr){ // cast the argument to structure it points to if ( typeid(*aPartEventPtr) != typeid(MDpartEventV1731) ) return CastError; MDpartEventV1731* thePart = static_cast(aPartEventPtr); static int iPartEvt(0); // print only the first 10 particle events per board static uint32_t oldBoard(0); if ( GetBoardId() != oldBoard ) { oldBoard=GetBoardId(); iPartEvt=0; } if (iPartEvt++ < 10) { *myObj << "In Equipment " << MDequipMap::GetName(GetEquipmentType()) ; *myObj << " ; Crate # " << GetLdcId() ; *myObj << " ; Board # " << GetBoardId() ; *myObj << " ; Particle Event Number : " << thePart->GetEventCount() << endl; *myObj << " Trigger Time Tag : " << thePart->GetTriggerTimeTag() << endl; // print data for the last channel for (int ich=0 ; ichGetLength(ich) ) for (unsigned int is =0 ; isGetNSamples(ich) ; is++) { *myObj << " " << thePart->GetSampleData(ich,is); } *myObj << endl; } } return OK; } /* Application main */ int main( int argc, char **argv ) { string stringBuf; // int parArg; //char filepath[128]; char runpath[128]; char filename[128]; // The following shows how to use the MDargumentHandler class // to deal with the main arguments // Define the arguments MDargumentHandler argh("Example of unpacking application."); argh.AddArgument("help","print this message","h"); argh.AddArgument("directory","path for the data file","d","","/home/daq/Downloads" ); argh.AddArgument("file","List of data file names or run number (space separated, within double quote)","f","","mandatory"); // Check the user arguments consistancy // All mandatory arguments should be provided and // There should be no extra arguments if ( argh.ProcessArguments(argc,argv) ) { argh.Usage(); return -1; } // Treat arguments, obtain values to be used later if ( argh.GetValue("help") ) { argh.Usage(); return 0; } if ( argh.GetValue("directory",stringBuf) != MDARGUMENT_STATUS_OK ) return -1; strcpy(runpath,stringBuf.c_str()); cout << "Directory : " << runpath << endl; if ( argh.GetValue("file",stringBuf) != MDARGUMENT_STATUS_OK ) return -1; strcpy(filename,stringBuf.c_str()); // Declare the process Manager. This is mandatory ! MDprocessManager thePM; // Used for the example only ContextData theContext; // This is only for illustration. Context data should be taken directly from the Process Manager // Declare and define the processors with their target objects and parameters OnSuperHeader* superHeaderProc = new OnSuperHeader(cout); OnStartOfRun* sorProc = new OnStartOfRun(); OnStartOfSpill* sosProc = new OnStartOfSpill(); OnEndOfSpill* eosProc = new OnEndOfSpill(); OnEventHeader* eventHeaderProc = new OnEventHeader(theContext); OnEquipmentHeader* equipmentHeaderProc = new OnEquipmentHeader(theContext); OnFragmentVLSB_C* vlsb_cProc = new OnFragmentVLSB_C(cout,theContext); OnFragmentV830* v830Proc = new OnFragmentV830(cout,theContext); OnFragmentV1290* v1290Proc = new OnFragmentV1290(); OnFragmentDBB* dbbProc = new OnFragmentDBB(); OnPartEventV1290* v1290PartEventProc = new OnPartEventV1290(cout); OnPartEventV1724* v1724PartEventProc = new OnPartEventV1724(cout); OnPartEventV1731* v1731PartEventProc = new OnPartEventV1731(cout); // Set the user processors thePM.SetStartOfRunProc(sorProc); // The ProcessManager will execute // sorProc->Process(&theEvent) each time a new // start of run event is found in the file thePM.SetStartOfSpillProc(sosProc); thePM.SetEndOfSpillProc(eosProc); thePM.SetSuperHeaderProc(superHeaderProc); // The ProcessManager will execute // superHeaderProc->Process(&theEvent) each time a // super event header is found in the file //thePM.SetEventHeaderProc(eventHeaderProc); // The ProcessManager will execute // eventHeaderProc->Process(&theEvent) each time a // normal LDC event header is found in the file //thePM.SetEquipmentHeaderProc(equipmentHeaderProc); // The ProcessManager will execute // equipmentHeaderProc->Process(&theEquipmentHeader) each // time an equipment header is found in the file //thePM.SetFragmentProc("VLSB_C",vlsb_cProc); // for fragments and particle events, the equipment name must be specified thePM.SetFragmentProc("V830",v830Proc); //thePM.SetFragmentProc("V1290",v1290Proc); thePM.SetFragmentProc("DBB",dbbProc); thePM.SetPartEventProc("V1290",v1290PartEventProc); thePM.SetPartEventProc("V1724",v1724PartEventProc); thePM.SetPartEventProc("V1731",v1731PartEventProc); thePM.DumpProcessors(); // Disable equipments that should not be decoded (in case of internal format error). // If an equipment is disabled, it is skipped at the equipment header level. //thePM.Disable("V1290"); // Declare the DATE data file handler //MDdateFile dFile(filename,filepath); MDfileManager dFileManager(filename,runpath); if ( dFileManager.OpenFile() != DATE_FILE_OK ) return 0; unsigned int nfiles = dFileManager.GetNFiles(); cout<<"nfiles = "<