// $Id$ // $HeadURL$ // // File: JEventSource_EVIO.cc // Created: Tue Aug 7 15:22:29 EDT 2012 // Creator: davidl (on Darwin harriet.jlab.org 11.4.0 i386) // // See comments in JEventSource_EVIO.h for overview description #include #include #include #include using namespace std; // This flag allows us to switch back and forth from using HDEVIO and // the CODA-supplied EVIO #define USE_HDEVIO 1 //#define ENABLE_UPSAMPLING #ifdef HAVE_EVIO #include extern "C" uint32_t *swap_int32_t(uint32_t *data, unsigned int length, uint32_t *dest); #endif // HAVE_EVIO // Require codachannels to use ET here #ifndef HAVE_CODACHANNELS #undef HAVE_ET #endif // HAVE_CODACHANNELS #ifdef HAVE_ET #include #include #endif // HAVE_ET #include "JEventSourceGenerator_EVIO.h" //#include "JFactoryGenerator_DAQ.h" #include "JEventSource_EVIO.h" using namespace jana; #include #include #define _DBG_DAQ(A) cerr<<__FILE__<<":"<<__LINE__<<" 0x"<>22)&0x1F)< //extern "C"{ // void InitPlugin(JApplication *app){ // InitJANAPlugin(app); // app->AddEventSourceGenerator(new JEventSourceGenerator_EVIO()); // app->AddFactoryGenerator(new JFactoryGenerator_DAQ()); // } //} // "C" set ROCIDS_TO_PARSE; // Naomi's CDC timing algortihm #include //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: // If EVIO support is not available, define dummy methods #ifndef HAVE_EVIO JEventSource_EVIO::JEventSource_EVIO(const char* source_name):JEventSource(source_name){ cerr << endl; cerr << "You are trying to use code requiring EVIO when support" << endl; cerr << "for EVIO was not built into this binary. Set your" << endl; cerr << "EVIOROOT *and* your ETROOT environment variables to" << endl; cerr << "point to your EVIO installation and recompile." << endl; cerr << endl; exit(-1); } JEventSource_EVIO::~JEventSource_EVIO(){} jerror_t JEventSource_EVIO::GetEvent(jana::JEvent &event){return NOERROR;} void JEventSource_EVIO::FreeEvent(jana::JEvent &event){} jerror_t JEventSource_EVIO::GetObjects(jana::JEvent &event, jana::JFactory_base *factory){return NOERROR;} //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: #else // HAVE_EVIO //---------------- // Constructor //---------------- JEventSource_EVIO::JEventSource_EVIO(const char* source_name):JEventSource(source_name) { // Initialize EVIO channel pointer to NULL (subclass will instantiate and open) chan = NULL; hdevio = NULL; source_type = kNoSource; quit_on_next_ET_timeout = false; // Initialize dedicated JStreamLog used for debugging messages evioout.SetTag("--- EVIO ---: "); evioout.SetTimestampFlag(); evioout.SetThreadstampFlag(); // Get configuration parameters AUTODETECT_MODULE_TYPES = true; DUMP_MODULE_MAP = false; MAKE_DOM_TREE = true; PARSE_EVIO_EVENTS = true; PARSE_F250 = true; PARSE_F125 = true; PARSE_F1TDC = true; PARSE_CAEN1290TDC = true; BUFFER_SIZE = 20000000; // in bytes ET_STATION_NEVENTS = 10; ET_STATION_CREATE_BLOCKING = false; ET_DEBUG_WORDS_TO_DUMP = 0; LOOP_FOREVER = false; VERBOSE = 0; TIMEOUT = 2.0; EMULATE_PULSE_INTEGRAL_MODE = true; EMULATE_SPARSIFICATION_THRESHOLD = 0; // =0 is equivalent to no threshold EMULATE_FADC250_TIME_THRESHOLD = 10; EMULATE_FADC125_TIME_THRESHOLD = 80; MODTYPE_MAP_FILENAME = "modtype.map"; ENABLE_DISENTANGLING = true; F250_IGNORE_PULSETIME = false; F125_IGNORE_PULSETIME = false; F250_THRESHOLD = 120; F125_THRESHOLD = 80; F250_NSA = 50; F250_NSB = 5; F250_NSPED = 4; F250_EMULATION_THRESHOLD = 20; F125_NSA = 40; F125_NSB = 3; F125_NSA_CDC = 80; F125_NSB_CDC = 5; F125_NSPED = 16; F125_EMULATION_THRESHOLD = 20; EMULATE_FADC125_TIME_UPSAMPLE = true; USER_RUN_NUMBER = 0; F125PULSE_NUMBER_FILTER = 1000; F250PULSE_NUMBER_FILTER = 1000; if(gPARMS){ gPARMS->SetDefaultParameter("EVIO:AUTODETECT_MODULE_TYPES", AUTODETECT_MODULE_TYPES, "Try and guess the module type tag,num values for which there is no module map entry."); gPARMS->SetDefaultParameter("EVIO:DUMP_MODULE_MAP", DUMP_MODULE_MAP, "Write module map used to file when source is destroyed. n.b. If more than one input file is used, the map file will be overwritten!"); gPARMS->SetDefaultParameter("EVIO:MAKE_DOM_TREE", MAKE_DOM_TREE, "Set this to 0 to disable generation of EVIO DOM Tree and parsing of event. (for benchmarking/debugging)"); gPARMS->SetDefaultParameter("EVIO:PARSE_EVIO_EVENTS", PARSE_EVIO_EVENTS, "Set this to 0 to disable parsing of event but still make the DOM tree, so long as MAKE_DOM_TREE isn't set to 0. (for benchmarking/debugging)"); gPARMS->SetDefaultParameter("EVIO:PARSE_F250", PARSE_F250, "Set this to 0 to disable parsing of data from F250 ADC modules (for benchmarking/debugging)"); gPARMS->SetDefaultParameter("EVIO:PARSE_F125", PARSE_F125, "Set this to 0 to disable parsing of data from F125 ADC modules (for benchmarking/debugging)"); gPARMS->SetDefaultParameter("EVIO:PARSE_F1TDC", PARSE_F1TDC, "Set this to 0 to disable parsing of data from F1TDC modules (for benchmarking/debugging)"); gPARMS->SetDefaultParameter("EVIO:PARSE_CAEN1290TDC", PARSE_CAEN1290TDC, "Set this to 0 to disable parsing of data from CAEN 1290 TDC modules (for benchmarking/debugging)"); gPARMS->SetDefaultParameter("EVIO:BUFFER_SIZE", BUFFER_SIZE, "Size in bytes to allocate for holding a single EVIO event."); gPARMS->SetDefaultParameter("EVIO:ET_STATION_NEVENTS", ET_STATION_NEVENTS, "Number of events to use if we have to create the ET station. Ignored if station already exists."); gPARMS->SetDefaultParameter("EVIO:ET_STATION_CREATE_BLOCKING", ET_STATION_CREATE_BLOCKING, "Set this to 0 to create station in non-blocking mode (default is to create it in blocking mode). Ignored if station already exists."); gPARMS->SetDefaultParameter("EVIO:ET_DEBUG_WORDS_TO_DUMP", ET_DEBUG_WORDS_TO_DUMP, "Number of words to dump to screen from ET buffer (useful for debugging only)."); gPARMS->SetDefaultParameter("EVIO:LOOP_FOREVER", LOOP_FOREVER, "If reading from EVIO file, keep re-opening file and re-reading events forever (only useful for debugging) If reading from ET, this is ignored."); gPARMS->SetDefaultParameter("EVIO:VERBOSE", VERBOSE, "Set verbosity level for processing and debugging statements while parsing. 0=no debugging messages. 10=all messages"); gPARMS->SetDefaultParameter("EVIO:EMULATE_PULSE_INTEGRAL_MODE", EMULATE_PULSE_INTEGRAL_MODE, "If non-zero, and Df250WindowRawData objects exist in the event AND no Df250PulseIntegral objects exist, then use the waveform data to generate Df250PulseIntegral objects. Default is for this feature to be on. Set this to zero to disable it."); gPARMS->SetDefaultParameter("EVIO:EMULATE_SPARSIFICATION_THRESHOLD", EMULATE_SPARSIFICATION_THRESHOLD, "If EVIO:EMULATE_PULSE_INTEGRAL_MODE is on, then this is used to apply a cut on the non-pedestal-subtracted integral to determine if a Df250PulseIntegral is produced or not."); gPARMS->SetDefaultParameter("EVIO:EMULATE_FADC250_TIME_THRESHOLD", EMULATE_FADC250_TIME_THRESHOLD, "If EVIO:EMULATE_PULSE_INTEGRAL_MODE is on, then DF250PulseTime objects will be emulated as well. This sets the sample threshold above pedestal from which the time will be determined."); gPARMS->SetDefaultParameter("EVIO:EMULATE_FADC125_TIME_THRESHOLD", EMULATE_FADC125_TIME_THRESHOLD, "If EVIO:EMULATE_PULSE_INTEGRAL_MODE is on, then DF125PulseTime objects will be emulated as well. This sets the sample threshold above pedestal from which the time will be determined."); gPARMS->SetDefaultParameter("EVIO:EMULATE_FADC125_TIME_UPSAMPLE", EMULATE_FADC125_TIME_UPSAMPLE, "If true, then use the CMU upsampling algorithm to determine times for the DF125PulseTime objects when using emulaton. Set to zero to use the f250 algorithm that was in f125 firmware for 2014 commissioning data."); gPARMS->SetDefaultParameter("ET:TIMEOUT", TIMEOUT, "Set the timeout in seconds for each attempt at reading from ET system (repeated attempts will still be made indefinitely until program quits or the quit_on_et_timeout flag is set."); gPARMS->SetDefaultParameter("EVIO:MODTYPE_MAP_FILENAME", MODTYPE_MAP_FILENAME, "Optional module type conversion map for use with files generated with the non-standard module types"); gPARMS->SetDefaultParameter("EVIO:ENABLE_DISENTANGLING", ENABLE_DISENTANGLING, "Enable/disable disentangling of multi-block events. Enabled by default. Set to 0 to disable."); gPARMS->SetDefaultParameter("EVIO:F250_IGNORE_PULSETIME", F250_IGNORE_PULSETIME, "Set this to non-zero to inhibit creation of Df250PulseTime and Df250PulsePedestal objects directly from data stream. If Window Raw Data exists, these objects may still be created from it."); gPARMS->SetDefaultParameter("EVIO:F125_IGNORE_PULSETIME", F125_IGNORE_PULSETIME, "Set this to non-zero to inhibit creation of Df125PulseTime and Df125PulsePedestal objects directly from data stream. If Window Raw Data exists, these objects may still be created from it."); gPARMS->SetDefaultParameter("EVIO:F250_THRESHOLD", F250_THRESHOLD, "For F250 window raw data. Threshold to emulate a PulseIntegral and PulseTime objects."); gPARMS->SetDefaultParameter("EVIO:F250_NSA", F250_NSA, "For f250PulseIntegral object. NSA value for emulation from window raw data and for pulse integral pedestal normalization."); gPARMS->SetDefaultParameter("EVIO:F250_NSB", F250_NSB, "For f250PulseIntegral object. NSB value for emulation from window raw data and for pulse integral pedestal normalization."); gPARMS->SetDefaultParameter("EVIO:F250_NSPED", F250_NSPED, "For f250PulseIntegral object. Number of pedestal samples value for emulation from window raw data and for pulse integral normalization."); gPARMS->SetDefaultParameter("EVIO:F125_NSA", F125_NSA, "For f125PulseIntegral object. NSA value for emulation from window raw data and for pulse integral pedestal normalization."); gPARMS->SetDefaultParameter("EVIO:F125_NSB", F125_NSB, "For f125PulseIntegral object. NSB value for emulation from window raw data and for pulse integral pedestal normalization."); gPARMS->SetDefaultParameter("EVIO:F125_NSA_CDC", F125_NSA_CDC, "For f125PulseIntegral object. NSA value for emulation from window raw data and for pulse integral pedestal normalization. This is applied to rocid 24-28 only!"); gPARMS->SetDefaultParameter("EVIO:F125_NSB_CDC", F125_NSB_CDC, "For f125PulseIntegral object. NSB value for emulation from window raw data and for pulse integral pedestal normalization. This is applied to rocid 24-28 only!"); gPARMS->SetDefaultParameter("EVIO:F125_NSPED", F125_NSPED, "For f125PulseIntegral object. Number of pedestal samples value for emulation from window raw data and for pulse integral normalization."); gPARMS->SetDefaultParameter("EVIO:RUN_NUMBER", USER_RUN_NUMBER, "User-supplied run number. Override run number from other sources with this.(will be ignored if set to zero)"); gPARMS->SetDefaultParameter("EVIO:F125PULSE_NUMBER_FILTER", F125PULSE_NUMBER_FILTER, "Ignore data for DF125XXX objects with a pulse number equal or greater than this."); gPARMS->SetDefaultParameter("EVIO:F250PULSE_NUMBER_FILTER", F250PULSE_NUMBER_FILTER, "Ignore data for DF250XXX objects with a pulse number equal or greater than this."); } // Try to open the file. try { if(VERBOSE>0) evioout << "Attempting to open \""<source_name<<"\" as EVIO file..." <source_name); if( ! hdevio->is_open ) throw std::exception(); // throw exception if unable to open #else // USE_HDEVIO //-------- CODA EVIO ----------- chan = new evioFileChannel(this->source_name, "r", BUFFER_SIZE); chan->open(); // open the file. Throws exception if not successful #endif // USE_HDEVIO source_type = kFileSource; } catch (std::exception &e) { #ifdef HAVE_ET // Could not open file. Check if name starts with "ET:" chan = NULL; if(this->source_name.substr(0,3) == "ET:"){ if(VERBOSE>0) evioout << "Attempting to open \""<source_name<<"\" as ET (network) source..." <source_name); // open the channel. Throws exception if not successful chan->open(); source_type = kETSource; #else // HAVE_ET // No ET and the file didn't work so re-throw the exception if(this->source_name.substr(0,3) == "ET:"){ cerr << endl; cerr << "=== ERROR: ET source specified and this was compiled without ===" << endl; cerr << "=== ET support. You need to install ET and CODAchannels ===" << endl; cerr << "=== and set your ETROOT and CODA environment variables ===" << endl; cerr << "=== appropriately before recompiling. ===" << endl; cerr << endl; } throw e; #endif // HAVE_ET } if(VERBOSE>0) evioout << "Success opening event source \"" << this->source_name << "\"!" <source_name.find_last_of('_'); if(pos2 != string::npos){ size_t pos1 = this->source_name.find_last_of('_', pos2-1); if(pos1 != string::npos){ pos1++; string runstr = this->source_name.substr(pos1, pos2-pos1); if(runstr.length()>0) filename_run_number = atoi(runstr.c_str()); } } pthread_mutex_init(&evio_buffer_pool_mutex, NULL); pthread_mutex_init(&stored_events_mutex, NULL); pthread_mutex_init(¤t_event_count_mutex, NULL); } //---------------- // Destructor //---------------- JEventSource_EVIO::~JEventSource_EVIO() { // close event source here if(chan){ if(VERBOSE>0) evioout << "Closing event source \"" << this->source_name << "\"" <close(); delete chan; } if(hdevio){ if(VERBOSE>0) evioout << "Closing hdevio event source \"" << this->source_name << "\"" <PrintStats(); delete hdevio; } // Release memory used for the event buffer pool while(!evio_buffer_pool.empty()){ free(evio_buffer_pool.front()); evio_buffer_pool.pop_front(); } // Optionally dump the module map if(DUMP_MODULE_MAP)DumpModuleMap(); } //--------------------------------- // ReadOptionalModuleTypeTranslation //--------------------------------- void JEventSource_EVIO::ReadOptionalModuleTypeTranslation(void) { // Some data may be taken with bad ROLs or drivers that // write module type values that are non-standard. This // allows the user to specify a simple text file that // can be read in to translate the types found in the // file to another type so that they can be properly parsed. ifstream ifs(MODTYPE_MAP_FILENAME.c_str()); if(!ifs.is_open()) return; cout << "Opened JLab module type translation map: " << endl; cout << " " << MODTYPE_MAP_FILENAME << endl; while(ifs.good()){ char line[256]; ifs.getline(line, 256); if(ifs.gcount() < 1) break; if(line[0] == '#') continue; stringstream ss(line); uint32_t from=10000, to=10000; ss >> from >> to; // from=evio to=TT if( to==10000 ){ if( from!=10000){ cout << "unable to convert line:" << endl; cout << " " << line; } }else{ modtype_translate[(MODULE_TYPE)from] = (MODULE_TYPE)to; } } ifs.close(); cout << " Read " << modtype_translate.size() << " entries" << endl; map::iterator iter; for(iter=modtype_translate.begin(); iter != modtype_translate.end(); iter++){ cout << " type " << iter->first << " -> type " << iter->second << endl; } } //---------------- // ConnectToET //---------------- void JEventSource_EVIO::ConnectToET(const char* source_name) { #ifdef HAVE_ET /// Format for ET source strings is: /// /// ET:session:station:host:port /// /// The session is used to form the filename of the ET /// system. For example, if an session of "eb" is specified, /// then a file named "/tmp/et_sys_eb" is assumed to be /// what should be opened. If no session is specified (or /// an empty session name) then "none" is used as the session. /// /// If the station name specified does not exist, it will /// be created. If it does exist, the existing station will /// be used. If no station is specified, then the station /// name "DANA" will be used. Any station created will be /// set to "blocking" *unless* the configuration paramter /// EVIO:ET_STATION_CREATE_BLOCKING is set to "0" /// in which case it will be set to non-blocking. /// /// If the host is specified, then an attempt will be made /// to open that system. If it is not specified, then /// it will attempt to open an ET system on the local machine. /// /// If port is specified, it is used as the TCP port number /// on the remote host to attach to. If the host is not /// specified (i.e. by having two colons and therefore /// an empty string) then the port is ignored. If the /// port is omitted or specified as "0", then the default /// port is used. /// // Split source name into session, station, etc... vector fields; string str = source_name; size_t startpos=0, endpos=0; while((endpos = str.find(":", startpos)) != str.npos){ size_t len = endpos-startpos; fields.push_back(len==0 ? "":str.substr(startpos, len)); startpos = endpos+1; } if(startpos1 ? fields[1]:""; string station = fields.size()>2 ? fields[2]:""; string host = fields.size()>3 ? fields[3]:"localhost"; int port = fields.size()>4 ? atoi(fields[4].c_str()):ET_SERVER_PORT; if(session == "") session = "none"; if(station == "") station = "DANA"; if(host == "") host = "localhost"; string fname = session.at(0)=='/' ? session:(string("/tmp/et_sys_") + session); // Report to user what we're doing jout << " Opening ET system:" << endl; if(session!=fname) jout << " session: " << session << endl; jout << " station: " << station << endl; jout << " system file: " << fname << endl; jout << " host: " << host << endl; if(port !=0) jout << " port: " << port << endl; // connect to the ET system et_openconfig openconfig; et_open_config_init(&openconfig); if(host != ""){ et_open_config_setcast(openconfig, ET_DIRECT); et_open_config_setmode(openconfig, ET_HOST_AS_LOCAL); // ET_HOST_AS_LOCAL or ET_HOST_AS_REMOTE et_open_config_sethost(openconfig, host.c_str()); et_open_config_setport(openconfig, ET_BROADCAST_PORT); et_open_config_setserverport(openconfig, port); } int err = et_open(&sys_id,fname.c_str(),openconfig); if(err != ET_OK){ cerr << __FILE__<<":"<<__LINE__<<" Problem opening ET system"< BUFFER_SIZE){ jout<<" Events in ET system are larger than currently set buffer size:"< "<