#include #include #include #include #include using namespace std; #include #include "BORroc.h" #include #include // from rcm/monitor // These were copied from evio.c in the EVIO library #define EV_VERSION 0x4 #define EV_LASTBLOCK_MASK 0x200 #define EV_FIRSTEVENT_MASK 0x4000 #define ET_USER_EVENT 0x5000 string OUTPUT_EVIO_FILENAME = ""; string ETsystem = "ET:/tmp/et_sys_davidl:MON:gluonraid1"; int VERBOSE=0; // Routines void Usage(bool longform=false, string mess=""); void ParseCommandLineArguments(int narg, char *argv[]); void ConnectToET(const char* source_name); void InsertEventIntoET(uint32_t *buff); // Globals et_sys_id sys_id; et_att_id att_id; et_stat_id sta_id; ofstream *evio_ofs = NULL; uint32_t BUFFER_SIZE = 20000000; // in bytes bool WRITE_TO_ET=false; bool WRITE_TO_EVIOFILE=false; bool ADD_EVIO_BLOCK_HEADER_ET = true; bool ADD_EVIO_BLOCK_HEADER_EVIOFILE = true; //-------------------- // Usage //-------------------- void Usage(bool longform, string mess) { cout << endl; cout << "Usage:" << endl; cout << " hdBOR [options]" << endl; cout << "" << endl; cout << "Create a Beginning Of Run (BOR) record and write it to." << endl; cout << "ET system or single event EVIO file." << endl; cout << "" << endl; if(longform){ cout << "Events can be written to an ET system, or EVIO file, or both." << endl; cout << "Writing to an ET system can be used to insert" << endl; cout << "the events into a CODA-produced data file. The event will" << endl; cout << "have the proper flag set so that the Event Recorder (ER)" << endl; cout << "will maintain a copy of the event so that it can be written" << endl; cout << "to the front of every file." << endl; cout << "" << endl; cout << "The ETsystem string is normally of the format:" << endl; cout << "" << endl; cout << "ET:etfilename:station:host:port" << endl; cout << "" << endl; cout << "for example:" << endl; cout << "" << endl; cout << "ET:/tmp/et_sys_hdops:MON:gluonraid1:23914" << endl; cout << "" << endl; cout << "This format matches that used by other Hall-D online utilities. Note " << endl; cout << "that because this program (unlike monitoring programs) is a producer," << endl; cout << "it will always attach to the GRAND CENTRAL station, thereby" << endl; cout << "ignoring the 'station' field. Also, if the port number is not given" << endl; cout << "then the default ET port number of 11111 is used. Finally, if the" << endl; cout << "source does not start with the string 'ET:', then the source is " << endl; cout << "assumed to be an ET system file on the local file system." << endl; cout << "" << endl; cout << "At least one of the -et, or -evio options must be given." << endl; cout << "" << endl; } cout << "options:" << endl; cout << " -h Print the short form Usage statement" << endl; cout << " --help Print the long form Usage statement" << endl; cout << " -v turn on verbose mode" << endl; cout << " -et ETsystem Write events to ET system with given name" << endl; cout << " -evio filename Write events to EVIO file with given name" << endl; cout << " -BHevio Do NOT write out EVIO Block Header to EVIO file" << endl; cout << " " << (longform ? "(see below)":"(see long form help)") << endl; cout << " +BHevio Do write out EVIO Block Header to EVIO file" << endl; cout << " " << (longform ? "(see below)":"(see long form help)") << endl; cout << " -BHet Do NOT write out EVIO Block Header to ET event" << endl; cout << " " << (longform ? "(see below)":"(see long form help)") << endl; cout << " +BHet Do write out EVIO Block Header to ET event" << endl; cout << " " << (longform ? "(see below)":"(see long form help)") << endl; cout << "" <0) cout << mess << endl << endl; exit(0); } //-------------------- // ParseCommandLineArguments //-------------------- void ParseCommandLineArguments(int narg, char *argv[]) { // Loop over al lcommand line arguments for(int i=1; i BORrocs; BORrocs.push_back(new BORroc("rocTAGM1")); BORrocs.push_back(new BORroc("rocTAGH1")); BORrocs.push_back(new BORroc("rocTAGMH")); BORrocs.push_back(new BORroc("rocST")); BORrocs.push_back(new BORroc("rocPS1")); BORrocs.push_back(new BORroc("rocPS2")); BORrocs.push_back(new BORroc("rocSTPSC1")); BORrocs.push_back(new BORroc("rocBCAL1")); BORrocs.push_back(new BORroc("rocBCAL2")); BORrocs.push_back(new BORroc("rocBCAL3")); BORrocs.push_back(new BORroc("rocBCAL4")); BORrocs.push_back(new BORroc("rocBCAL5")); BORrocs.push_back(new BORroc("rocBCAL6")); BORrocs.push_back(new BORroc("rocBCAL7")); BORrocs.push_back(new BORroc("rocBCAL8")); BORrocs.push_back(new BORroc("rocBCAL9")); BORrocs.push_back(new BORroc("rocBCAL10")); BORrocs.push_back(new BORroc("rocBCAL11")); BORrocs.push_back(new BORroc("rocBCAL12")); BORrocs.push_back(new BORroc("rocFMWPC1")); BORrocs.push_back(new BORroc("rocCDC1")); BORrocs.push_back(new BORroc("rocCDC2")); BORrocs.push_back(new BORroc("rocCDC3")); BORrocs.push_back(new BORroc("rocCDC4")); BORrocs.push_back(new BORroc("rocFDC1")); BORrocs.push_back(new BORroc("rocFDC2")); BORrocs.push_back(new BORroc("rocFDC3")); BORrocs.push_back(new BORroc("rocFDC4")); BORrocs.push_back(new BORroc("rocFDC5")); BORrocs.push_back(new BORroc("rocFDC6")); BORrocs.push_back(new BORroc("rocFDC7")); BORrocs.push_back(new BORroc("rocFDC8")); BORrocs.push_back(new BORroc("rocFDC9")); BORrocs.push_back(new BORroc("rocFDC10")); BORrocs.push_back(new BORroc("rocFDC11")); BORrocs.push_back(new BORroc("rocFDC12")); BORrocs.push_back(new BORroc("rocFDC13")); BORrocs.push_back(new BORroc("rocFDC14")); BORrocs.push_back(new BORroc("rocTOF1")); BORrocs.push_back(new BORroc("rocTOF2")); BORrocs.push_back(new BORroc("rocFCAL1")); BORrocs.push_back(new BORroc("rocFCAL2")); BORrocs.push_back(new BORroc("rocFCAL3")); BORrocs.push_back(new BORroc("rocFCAL4")); BORrocs.push_back(new BORroc("rocFCAL5")); BORrocs.push_back(new BORroc("rocFCAL6")); BORrocs.push_back(new BORroc("rocFCAL7")); BORrocs.push_back(new BORroc("rocFCAL8")); BORrocs.push_back(new BORroc("rocFCAL9")); BORrocs.push_back(new BORroc("rocFCAL10")); BORrocs.push_back(new BORroc("rocFCAL11")); BORrocs.push_back(new BORroc("rocFCAL12")); // Launch thread fro every ROC, making connection and reading shmem vector threads; for(uint32_t i=0; i goodBORrocs; cout << "sizeof(roc_shmem) = " << sizeof(roc_shmem) << endl; for(uint32_t i=0; iRUN_Number; cout << B.hostname << " : " << (B.data_valid ? " good":"ERROR") << " -- " << B.N << " bytes -- run: " << run_number << endl; if(B.data_valid && (B.N==sizeof(roc_shmem))){ // Only interested in crates that report module data ModulesConfigBOR *BOR = &shmem->BOR; uint32_t Nmodules_tot = BOR->Nf250 + BOR->Nf125 + BOR->NF1TDC + BOR->Ncaen1190; if(Nmodules_tot==0) { cout << " *Nmodules_tot=0 ! No relevant BOR dat to write for " << B.hostname << endl; continue; } // Only keep records from ROCs reporting the highest // run number. This should effectively filter out // ROCs not used for the current run. if(run_number>max_run_number){ goodBORrocs.clear(); max_run_number = run_number; } if(run_number==max_run_number) goodBORrocs.push_back(&B); } } cout << " Num. of ROCs: " << BORrocs.size() << endl; cout << "Num. reporting good data: " << goodBORrocs.size() << endl; cout << "(\"good\" = data was read and is of same size as roc_shmem" << endl; cout <<" struct and run number is highest one reported.)" << endl; cout << endl; // Create BOR EVIO event uint32_t *buff = new uint32_t[BUFFER_SIZE]; uint32_t *iptr = &buff[8]; uint32_t *evLen = iptr; *iptr++ = 0; // will be updated after all data is written to buffer *iptr++ = (0x70<<16) + (0x0E<<8) + (0x1<<0); // 0x70=BOR event 0x0E=bank of banks 0x1=num for(uint32_t j=0; jDATA; ModulesConfigBOR *BOR = &shmem->BOR; // Look for rocid for this crate so we can write the crate bank // header just once. uint32_t rocid = 0; if(BOR->Nf250 ) rocid = BOR->f250[0].rocid; if(BOR->Nf125 ) rocid = BOR->f125[0].rocid; if(BOR->NF1TDC ) rocid = BOR->F1TDC[0].rocid; if(BOR->Ncaen1190) rocid = BOR->caen1190[0].rocid; if(rocid==0) continue; // ignore this if there is not module data // Create crate config header uint32_t *cratelen = iptr++; // for updating length later *iptr++ = (0x71<<16) + (0x0C<<8) + (rocid); // 0x71=crate config, 0x0c=tag segment, num=rocid // F250 for(uint32_t i=0; iNf250; i++){ uint32_t slot = BOR->f250[i].slot; uint32_t tag = (slot<<5) + (0x1); // 0x1=FADC250 (see DModuleType.h) uint32_t Nwords = sizeof(f250config)/sizeof(uint32_t); *iptr++ = (tag<<20) + (0x01<<16) + (Nwords); // 0x1=uint32 uint32_t *d = (uint32_t*)&BOR->f250[i]; for(uint32_t j=0; jNf125; i++){ uint32_t slot = BOR->f125[i].slot; uint32_t tag = (slot<<5) + (0x2); // 0x2=FADC125 (see DModuleType.h) uint32_t Nwords = sizeof(f125config)/sizeof(uint32_t); *iptr++ = (tag<<20) + (0x01<<16) + (Nwords); // 0x1=uint32 uint32_t *d = (uint32_t*)&BOR->f125[i]; for(uint32_t j=0; jNF1TDC; i++){ uint32_t slot = BOR->F1TDC[i].slot; uint32_t modtype = BOR->F1TDC[i].nchips==8 ? 0x3:0x4; // 0x3=F1TDC32, 0x4=F1TDC48 (see DModuleType.h) uint32_t tag = (slot<<5) + (modtype); uint32_t Nwords = sizeof(F1TDCconfig)/sizeof(uint32_t); *iptr++ = (tag<<20) + (0x01<<16) + (Nwords); // 0x1=uint32 uint32_t *d = (uint32_t*)&BOR->F1TDC[i]; for(uint32_t j=0; jNcaen1190; i++){ uint32_t slot = BOR->caen1190[i].slot; uint32_t tag = (slot<<5) + (0x13); // 0x13=CAEN1290 (see DModuleType.h) uint32_t Nwords = sizeof(caen1190config)/sizeof(uint32_t); *iptr++ = (tag<<20) + (0x01<<16) + (Nwords); // 0x1=uint32 uint32_t *d = (uint32_t*)&BOR->caen1190[i]; for(uint32_t j=0; jhostname << " evio bank size: " << *cratelen << " words RunNumber: " << shmem->RUN_Number << endl; } *evLen = (iptr - evLen) - 1; int nwords = *evLen + 1; // +1 is for length word uint32_t nwords_tot = nwords + 8; cout << "EVIO event length: " << nwords << " words" << endl; // The following contains the special magic needed to flag this // as the last event in the block as well as the first event // to be written to each file by the ER AND that it is EVIO // version 4 (even though I think the first event feature // was not implemented until version 5). This was lifted from // the evCreateFirstEventBlock routine in evio.c in the EVIO // library. uint32_t bitinfo = (EV_VERSION & 0xff) | EV_LASTBLOCK_MASK | EV_FIRSTEVENT_MASK | ET_USER_EVENT; buff[0] = nwords_tot; // Block Length (inclusive) buff[1] = 1; // Block Number buff[2] = 8; // Header Length buff[3] = 1; // Event count buff[4] = 0; // Reserved 1 buff[5] = bitinfo; // (see comments above) buff[6] = 0; // Reserved 2 buff[7] = 0xc0da0100; // Magic number // Optionally open EVIO file for output. if(WRITE_TO_EVIOFILE){ evio_ofs = new ofstream(OUTPUT_EVIO_FILENAME.c_str()); if(evio_ofs->is_open()){ cout << "Writing BOR event to EVIO file: " << OUTPUT_EVIO_FILENAME << endl; uint32_t *my_buff = ADD_EVIO_BLOCK_HEADER_EVIOFILE ? buff:&buff[8]; uint32_t my_nwords_tot = ADD_EVIO_BLOCK_HEADER_EVIOFILE ? nwords_tot:(nwords_tot-8); evio_ofs->write((const char*)my_buff, my_nwords_tot*sizeof(uint32_t)); evio_ofs->close(); }else{ cerr << "ERROR opening EVIO file for output: " << OUTPUT_EVIO_FILENAME << endl; } delete evio_ofs; } // Optionally connect to ET system. (This will exit the program if it fails) if(WRITE_TO_ET){ ConnectToET(ETsystem.c_str()); InsertEventIntoET(buff); } return 0; } //---------------- // ConnectToET //---------------- void 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); // Override station name with "GRAND CENTRAL" for display purposes // We are a producer so we always connect to that. We allow station // to be passed so we can accept same format as consumers. station = "GRAND CENTRAL"; // Report to user what we're doing cout << " Opening ET system:" << endl; if(session!=fname) cout << " session: " << session << endl; cout << " station: " << station << endl; cout << " system file: " << fname << endl; cout << " host: " << host << endl; if(port !=0) cout << " 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){ cout<<" Events in ET system are larger than currently set buffer size:"< "<