File: | libraries/DAQ/JEventSource_EVIO.cc |
Location: | line 935, column 4 |
Description: | Potential leak of memory pointed to by 'c' |
1 | // $Id$ | |||||
2 | // $HeadURL$ | |||||
3 | // | |||||
4 | // File: JEventSource_EVIO.cc | |||||
5 | // Created: Tue Aug 7 15:22:29 EDT 2012 | |||||
6 | // Creator: davidl (on Darwin harriet.jlab.org 11.4.0 i386) | |||||
7 | // | |||||
8 | ||||||
9 | // See comments in JEventSource_EVIO.h for overview description | |||||
10 | ||||||
11 | #include <unistd.h> | |||||
12 | #include <stdint.h> | |||||
13 | ||||||
14 | #include <string> | |||||
15 | #include <cmath> | |||||
16 | #include <iomanip> | |||||
17 | using namespace std; | |||||
18 | ||||||
19 | ||||||
20 | // This flag allows us to switch back and forth from using HDEVIO and | |||||
21 | // the CODA-supplied EVIO | |||||
22 | #define USE_HDEVIO1 1 | |||||
23 | ||||||
24 | //#define ENABLE_UPSAMPLING | |||||
25 | ||||||
26 | #ifdef HAVE_EVIO1 | |||||
27 | ||||||
28 | #if USE_HDEVIO1 == 0 | |||||
29 | #include <evioFileChannel.hxx> | |||||
30 | #endif | |||||
31 | ||||||
32 | extern "C" uint32_t *swap_int32_t(uint32_t *data, unsigned int length, uint32_t *dest); | |||||
33 | #endif // HAVE_EVIO | |||||
34 | ||||||
35 | #ifdef HAVE_ET | |||||
36 | //#include <evioETChannel.hxx> | |||||
37 | #include <et.h> | |||||
38 | #endif // HAVE_ET | |||||
39 | ||||||
40 | #include "JEventSourceGenerator_EVIO.h" | |||||
41 | //#include "JFactoryGenerator_DAQ.h" | |||||
42 | #include "JEventSource_EVIO.h" | |||||
43 | ||||||
44 | using namespace jana; | |||||
45 | ||||||
46 | #include <DANA/DStatusBits.h> | |||||
47 | #include <TTAB/DTranslationTable.h> | |||||
48 | #include <TTAB/DTranslationTable_factory.h> | |||||
49 | #include <DAQ/Df125EmulatorAlgorithm_factory.h> | |||||
50 | #include <DAQ/Df250EmulatorAlgorithm_factory.h> | |||||
51 | ||||||
52 | #define _DBG_DAQ(A)cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<<":"<< 52<<" 0x"<<hex<<A<<" cntrl:0x"<< (A&0xF0000000)<<dec<<" slot:"<<((A>> 22)&0x1F)<<endl cerr<<__FILE__"libraries/DAQ/JEventSource_EVIO.cc"<<":"<<__LINE__52<<" 0x"<<hex<<A<<" cntrl:0x"<<(A&0xF0000000)<<dec<<" slot:"<<((A>>22)&0x1F)<<endl | |||||
53 | ||||||
54 | // Make us a plugin | |||||
55 | #include <JANA/JApplication.h> | |||||
56 | //extern "C"{ | |||||
57 | // void InitPlugin(JApplication *app){ | |||||
58 | // InitJANAPlugin(app); | |||||
59 | // app->AddEventSourceGenerator(new JEventSourceGenerator_EVIO()); | |||||
60 | // app->AddFactoryGenerator(new JFactoryGenerator_DAQ()); | |||||
61 | // } | |||||
62 | //} // "C" | |||||
63 | ||||||
64 | // if we don't find a run number in the file, then it's nice to let the user know | |||||
65 | static bool WARN_USER_RUN_FILENAME = false; | |||||
66 | ||||||
67 | set<uint32_t> ROCIDS_TO_PARSE; | |||||
68 | ||||||
69 | //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | |||||
70 | // If EVIO support is not available, define dummy methods | |||||
71 | #ifndef HAVE_EVIO1 | |||||
72 | JEventSource_EVIO::JEventSource_EVIO(const char* source_name):JEventSource(source_name){ | |||||
73 | cerr << endl; | |||||
74 | cerr << "You are trying to use code requiring EVIO when support" << endl; | |||||
75 | cerr << "for EVIO was not built into this binary. Set your" << endl; | |||||
76 | cerr << "EVIOROOT *and* your ETROOT environment variables to" << endl; | |||||
77 | cerr << "point to your EVIO installation and recompile." << endl; | |||||
78 | cerr << endl; | |||||
79 | exit(-1); | |||||
80 | } | |||||
81 | JEventSource_EVIO::~JEventSource_EVIO(){} | |||||
82 | jerror_t JEventSource_EVIO::GetEvent(jana::JEvent &event){return NOERROR;} | |||||
83 | void JEventSource_EVIO::FreeEvent(jana::JEvent &event){} | |||||
84 | jerror_t JEventSource_EVIO::GetObjects(jana::JEvent &event, jana::JFactory_base *factory){return NOERROR;} | |||||
85 | jerror_t JEventSource_EVIO::ReadEVIOEvent(uint32_t* &buf){return NOERROR;} | |||||
86 | //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | |||||
87 | ||||||
88 | #else // HAVE_EVIO | |||||
89 | ||||||
90 | //---------------- | |||||
91 | // Constructor | |||||
92 | //---------------- | |||||
93 | JEventSource_EVIO::JEventSource_EVIO(const char* source_name):JEventSource(source_name) | |||||
94 | { | |||||
95 | // Initialize connection objects and flags to NULL | |||||
96 | et_connected = false; | |||||
97 | //chan = NULL; | |||||
98 | hdevio = NULL__null; | |||||
99 | source_type = kNoSource; | |||||
100 | quit_on_next_ET_timeout = false; | |||||
101 | ||||||
102 | // Initialize dedicated JStreamLog used for debugging messages | |||||
103 | evioout.SetTag("--- EVIO ---: "); | |||||
104 | evioout.SetTimestampFlag(); | |||||
105 | evioout.SetThreadstampFlag(); | |||||
106 | ||||||
107 | // Define base set of status bits | |||||
108 | if(japp) DStatusBits::SetStatusBitDescriptions(japp); | |||||
109 | ||||||
110 | // Get configuration parameters | |||||
111 | AUTODETECT_MODULE_TYPES = true; | |||||
112 | DUMP_MODULE_MAP = false; | |||||
113 | MAKE_DOM_TREE = true; | |||||
114 | PARSE_EVIO_EVENTS = true; | |||||
115 | PARSE_F250 = true; | |||||
116 | PARSE_F125 = true; | |||||
117 | PARSE_F1TDC = true; | |||||
118 | PARSE_CAEN1290TDC = true; | |||||
119 | PARSE_CONFIG = true; | |||||
120 | PARSE_BOR = true; | |||||
121 | PARSE_EPICS = true; | |||||
122 | PARSE_EVENTTAG = true; | |||||
123 | PARSE_TRIGGER = true; | |||||
124 | BUFFER_SIZE = 20000000; // in bytes | |||||
125 | ET_STATION_NEVENTS = 10; | |||||
126 | ET_STATION_CREATE_BLOCKING = false; | |||||
127 | ET_DEBUG_WORDS_TO_DUMP = 0; | |||||
128 | LOOP_FOREVER = false; | |||||
129 | VERBOSE = 0; | |||||
130 | TIMEOUT = 2.0; | |||||
131 | MODTYPE_MAP_FILENAME = "modtype.map"; | |||||
132 | ENABLE_DISENTANGLING = true; | |||||
133 | ||||||
134 | F125_EMULATION_MODE = kEmulationAuto; | |||||
135 | F250_EMULATION_MODE = kEmulationAuto; | |||||
136 | ||||||
137 | USER_RUN_NUMBER = 0; | |||||
138 | F125PULSE_NUMBER_FILTER = 1000; | |||||
139 | F250PULSE_NUMBER_FILTER = 1000; | |||||
140 | ||||||
141 | if(gPARMS){ | |||||
142 | // JANA doesn't know about EmulationModeType so we use temporary variables | |||||
143 | uint32_t f250_emulation_mode = F250_EMULATION_MODE; | |||||
144 | uint32_t f125_emulation_mode = F125_EMULATION_MODE; | |||||
145 | ||||||
146 | 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."); | |||||
147 | 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!"); | |||||
148 | 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)"); | |||||
149 | 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)"); | |||||
150 | gPARMS->SetDefaultParameter("EVIO:PARSE_F250", PARSE_F250, "Set this to 0 to disable parsing of data from F250 ADC modules (for benchmarking/debugging)"); | |||||
151 | gPARMS->SetDefaultParameter("EVIO:PARSE_F125", PARSE_F125, "Set this to 0 to disable parsing of data from F125 ADC modules (for benchmarking/debugging)"); | |||||
152 | gPARMS->SetDefaultParameter("EVIO:PARSE_F1TDC", PARSE_F1TDC, "Set this to 0 to disable parsing of data from F1TDC modules (for benchmarking/debugging)"); | |||||
153 | gPARMS->SetDefaultParameter("EVIO:PARSE_CAEN1290TDC", PARSE_CAEN1290TDC, "Set this to 0 to disable parsing of data from CAEN 1290 TDC modules (for benchmarking/debugging)"); | |||||
154 | gPARMS->SetDefaultParameter("EVIO:PARSE_CONFIG", PARSE_CONFIG, "Set this to 0 to disable parsing of ROC configuration data in the data stream (for benchmarking/debugging)"); | |||||
155 | gPARMS->SetDefaultParameter("EVIO:PARSE_BOR", PARSE_BOR, "Set this to 0 to disable parsing of BOR events from the data stream (for benchmarking/debugging)"); | |||||
156 | gPARMS->SetDefaultParameter("EVIO:PARSE_EPICS", PARSE_EPICS, "Set this to 0 to disable parsing of EPICS events from the data stream (for benchmarking/debugging)"); | |||||
157 | gPARMS->SetDefaultParameter("EVIO:PARSE_EVENTTAG", PARSE_EVENTTAG, "Set this to 0 to disable parsing of event tag data in the data stream (for benchmarking/debugging)"); | |||||
158 | gPARMS->SetDefaultParameter("EVIO:PARSE_TRIGGER", PARSE_TRIGGER, "Set this to 0 to disable parsing of the built trigger bank from CODA (for benchmarking/debugging)"); | |||||
159 | ||||||
160 | gPARMS->SetDefaultParameter("EVIO:BUFFER_SIZE", BUFFER_SIZE, "Size in bytes to allocate for holding a single EVIO event."); | |||||
161 | 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."); | |||||
162 | 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."); | |||||
163 | 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)."); | |||||
164 | 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."); | |||||
165 | gPARMS->SetDefaultParameter("EVIO:VERBOSE", VERBOSE, "Set verbosity level for processing and debugging statements while parsing. 0=no debugging messages. 10=all messages"); | |||||
166 | 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."); | |||||
167 | 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"); | |||||
168 | gPARMS->SetDefaultParameter("EVIO:ENABLE_DISENTANGLING", ENABLE_DISENTANGLING, "Enable/disable disentangling of multi-block events. Enabled by default. Set to 0 to disable."); | |||||
169 | ||||||
170 | gPARMS->SetDefaultParameter("EVIO:F250_EMULATION_MODE", f250_emulation_mode, "Set f250 emulation mode. 0=no emulation, 1=always, 2=auto. Default is 2 (auto)."); | |||||
171 | gPARMS->SetDefaultParameter("EVIO:F125_EMULATION_MODE", f125_emulation_mode, "Set f125 emulation mode. 0=no emulation, 1=always, 2=auto. Default is 2 (auto)."); | |||||
172 | ||||||
173 | 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)"); | |||||
174 | gPARMS->SetDefaultParameter("EVIO:F125PULSE_NUMBER_FILTER", F125PULSE_NUMBER_FILTER, "Ignore data for DF125XXX objects with a pulse number equal or greater than this."); | |||||
175 | gPARMS->SetDefaultParameter("EVIO:F250PULSE_NUMBER_FILTER", F250PULSE_NUMBER_FILTER, "Ignore data for DF250XXX objects with a pulse number equal or greater than this."); | |||||
176 | ||||||
177 | F250_EMULATION_MODE = (EmulationModeType)f250_emulation_mode; | |||||
178 | F125_EMULATION_MODE = (EmulationModeType)f125_emulation_mode; | |||||
179 | } | |||||
180 | ||||||
181 | // Try to open the file. | |||||
182 | try { | |||||
183 | ||||||
184 | if(VERBOSE>0) evioout << "Attempting to open \""<<this->source_name<<"\" as EVIO file..." <<endl; | |||||
185 | ||||||
186 | #if USE_HDEVIO1 | |||||
187 | //---------- HDEVIO ------------ | |||||
188 | hdevio = new HDEVIO(this->source_name); | |||||
189 | if( ! hdevio->is_open ) throw std::exception(); // throw exception if unable to open | |||||
190 | #else // USE_HDEVIO | |||||
191 | //-------- CODA EVIO ----------- | |||||
192 | jerr << "You are attempting to use the CODA Channels library for reading" << endl; | |||||
193 | jerr << "and EVIO file and this mechanism has been disabled from in the" << endl; | |||||
194 | jerr << "DAQ library. Contact davidl@jlab.org if you need this to be" << endl; | |||||
195 | jerr << "reinstated." << endl; | |||||
196 | quit(0); | |||||
197 | //chan = new evioFileChannel(this->source_name, "r", BUFFER_SIZE); | |||||
198 | //chan->open(); // open the file. Throws exception if not successful | |||||
199 | ||||||
200 | #endif // USE_HDEVIO | |||||
201 | ||||||
202 | source_type = kFileSource; | |||||
203 | ||||||
204 | } catch (std::exception &e) { | |||||
205 | ||||||
206 | #ifdef HAVE_ET | |||||
207 | // Could not open file. Check if name starts with "ET:" | |||||
208 | //chan = NULL; | |||||
209 | if(this->source_name.substr(0,3) == "ET:"){ | |||||
210 | if(VERBOSE>0) evioout << "Attempting to open \""<<this->source_name<<"\" as ET (network) source..." <<endl; | |||||
211 | ConnectToET(source_name); | |||||
212 | } | |||||
213 | ||||||
214 | if(!et_connected) throw JException("Failed to open ET system: " + this->source_name); | |||||
215 | ||||||
216 | // open the channel. Throws exception if not successful | |||||
217 | // chan->open(); // evioETchannel no longer used | |||||
218 | source_type = kETSource; | |||||
219 | ||||||
220 | #else // HAVE_ET | |||||
221 | ||||||
222 | // No ET and the file didn't work so re-throw the exception | |||||
223 | if(this->source_name.substr(0,3) == "ET:"){ | |||||
224 | cerr << endl; | |||||
225 | cerr << "=== ERROR: ET source specified and this was compiled without ===" << endl; | |||||
226 | cerr << "=== ET support. You need to install ET and set your ===" << endl; | |||||
227 | cerr << "=== ETROOT environment variable appropriately before ===" << endl; | |||||
228 | cerr << "=== recompiling. ===" << endl; | |||||
229 | cerr << endl; | |||||
230 | } | |||||
231 | throw e; | |||||
232 | ||||||
233 | #endif // HAVE_ET | |||||
234 | } | |||||
235 | if(VERBOSE>0) evioout << "Success opening event source \"" << this->source_name << "\"!" <<endl; | |||||
236 | ||||||
237 | ||||||
238 | // Create list of data types this event source can provide | |||||
239 | // (must match what is returned by JObject::className() ) | |||||
240 | // n.b. there is an ugly hack down in GetObjects that will | |||||
241 | // probably also need a line added for each data type added | |||||
242 | // here. | |||||
243 | event_source_data_types.insert("Df250Config"); | |||||
244 | event_source_data_types.insert("Df250PulseIntegral"); | |||||
245 | event_source_data_types.insert("Df250StreamingRawData"); | |||||
246 | event_source_data_types.insert("Df250WindowSum"); | |||||
247 | event_source_data_types.insert("Df250PulseRawData"); | |||||
248 | event_source_data_types.insert("Df250TriggerTime"); | |||||
249 | event_source_data_types.insert("Df250PulseTime"); | |||||
250 | event_source_data_types.insert("Df250PulsePedestal"); | |||||
251 | event_source_data_types.insert("Df250WindowRawData"); | |||||
252 | event_source_data_types.insert("Df125Config"); | |||||
253 | event_source_data_types.insert("Df125PulseIntegral"); | |||||
254 | event_source_data_types.insert("Df125TriggerTime"); | |||||
255 | event_source_data_types.insert("Df125PulseTime"); | |||||
256 | event_source_data_types.insert("Df125PulsePedestal"); | |||||
257 | event_source_data_types.insert("Df125WindowRawData"); | |||||
258 | event_source_data_types.insert("Df125CDCPulse"); | |||||
259 | event_source_data_types.insert("Df125FDCPulse"); | |||||
260 | event_source_data_types.insert("DF1TDCConfig"); | |||||
261 | event_source_data_types.insert("DF1TDCHit"); | |||||
262 | event_source_data_types.insert("DF1TDCTriggerTime"); | |||||
263 | event_source_data_types.insert("DCAEN1290TDCConfig"); | |||||
264 | event_source_data_types.insert("DCAEN1290TDCHit"); | |||||
265 | event_source_data_types.insert("DCODAEventInfo"); | |||||
266 | event_source_data_types.insert("DCODAROCInfo"); | |||||
267 | event_source_data_types.insert("DTSscalers"); | |||||
268 | event_source_data_types.insert("DEPICSvalue"); | |||||
269 | event_source_data_types.insert("DEventTag"); | |||||
270 | event_source_data_types.insert("DL1Info"); | |||||
271 | ||||||
272 | // Read in optional module type translation map if it exists | |||||
273 | ReadOptionalModuleTypeTranslation(); | |||||
274 | ||||||
275 | last_run_number = 0; | |||||
276 | filename_run_number = 0; | |||||
277 | current_event_count = 0; | |||||
278 | ||||||
279 | // Try extracting the run number from the filename. (This is | |||||
280 | // only used if the run number is not found in the EVIO data.) | |||||
281 | size_t pos2 = this->source_name.find_last_of('_'); | |||||
282 | if(pos2 != string::npos){ | |||||
283 | size_t pos1 = this->source_name.find_last_of('_', pos2-1); | |||||
284 | if(pos1 != string::npos){ | |||||
285 | pos1++; | |||||
286 | string runstr = this->source_name.substr(pos1, pos2-pos1); | |||||
287 | if(runstr.length()>0) filename_run_number = atoi(runstr.c_str()); | |||||
288 | } | |||||
289 | } | |||||
290 | ||||||
291 | pthread_mutex_init(&evio_buffer_pool_mutex, NULL__null); | |||||
292 | pthread_mutex_init(&stored_events_mutex, NULL__null); | |||||
293 | pthread_mutex_init(¤t_event_count_mutex, NULL__null); | |||||
294 | pthread_rwlock_init(&BOR_lock, NULL__null); | |||||
295 | } | |||||
296 | ||||||
297 | //---------------- | |||||
298 | // Destructor | |||||
299 | //---------------- | |||||
300 | JEventSource_EVIO::~JEventSource_EVIO() | |||||
301 | { | |||||
302 | // close event source here | |||||
303 | // if(chan){ | |||||
304 | // if(VERBOSE>0) evioout << "Closing event source \"" << this->source_name << "\"" <<endl; | |||||
305 | // chan->close(); | |||||
306 | // delete chan; | |||||
307 | // } | |||||
308 | ||||||
309 | #ifdef HAVE_ET | |||||
310 | if(et_connected){ | |||||
311 | if(VERBOSE>0) evioout << "Closing ET connection \"" << this->source_name << "\"" <<endl; | |||||
312 | et_close(sys_id); | |||||
313 | et_connected = false; | |||||
314 | } | |||||
315 | #endif | |||||
316 | ||||||
317 | if(hdevio){ | |||||
318 | if(VERBOSE>0) evioout << "Closing hdevio event source \"" << this->source_name << "\"" <<endl; | |||||
319 | hdevio->PrintStats(); | |||||
320 | delete hdevio; | |||||
321 | } | |||||
322 | ||||||
323 | // Release memory used for the event buffer pool | |||||
324 | while(!evio_buffer_pool.empty()){ | |||||
325 | free(evio_buffer_pool.front()); | |||||
326 | evio_buffer_pool.pop_front(); | |||||
327 | } | |||||
328 | ||||||
329 | // Delete any BOR config objects | |||||
330 | for(uint32_t i=0; i<BORobjs.size(); i++) delete BORobjs[i]; | |||||
331 | BORobjs.clear(); | |||||
332 | ||||||
333 | // Optionally dump the module map | |||||
334 | if(DUMP_MODULE_MAP)DumpModuleMap(); | |||||
335 | } | |||||
336 | ||||||
337 | //--------------------------------- | |||||
338 | // ReadOptionalModuleTypeTranslation | |||||
339 | //--------------------------------- | |||||
340 | void JEventSource_EVIO::ReadOptionalModuleTypeTranslation(void) | |||||
341 | { | |||||
342 | // Some data may be taken with bad ROLs or drivers that | |||||
343 | // write module type values that are non-standard. This | |||||
344 | // allows the user to specify a simple text file that | |||||
345 | // can be read in to translate the types found in the | |||||
346 | // file to another type so that they can be properly parsed. | |||||
347 | ifstream ifs(MODTYPE_MAP_FILENAME.c_str()); | |||||
348 | if(!ifs.is_open()) return; | |||||
349 | ||||||
350 | cout << "Opened JLab module type translation map: " << endl; | |||||
351 | cout << " " << MODTYPE_MAP_FILENAME << endl; | |||||
352 | while(ifs.good()){ | |||||
353 | char line[256]; | |||||
354 | ifs.getline(line, 256); | |||||
355 | if(ifs.gcount() < 1) break; | |||||
356 | if(line[0] == '#') continue; | |||||
357 | ||||||
358 | stringstream ss(line); | |||||
359 | uint32_t from=10000, to=10000; | |||||
360 | ss >> from >> to; // from=evio to=TT | |||||
361 | if( to==10000 ){ | |||||
362 | if( from!=10000){ | |||||
363 | cout << "unable to convert line:" << endl; | |||||
364 | cout << " " << line; | |||||
365 | } | |||||
366 | }else{ | |||||
367 | modtype_translate[(MODULE_TYPE)from] = (MODULE_TYPE)to; | |||||
368 | } | |||||
369 | } | |||||
370 | ifs.close(); | |||||
371 | ||||||
372 | cout << " Read " << modtype_translate.size() << " entries" << endl; | |||||
373 | map<MODULE_TYPE,MODULE_TYPE>::iterator iter; | |||||
374 | for(iter=modtype_translate.begin(); iter != modtype_translate.end(); iter++){ | |||||
375 | cout << " type " << iter->first << " -> type " << iter->second << endl; | |||||
376 | } | |||||
377 | } | |||||
378 | ||||||
379 | //---------------- | |||||
380 | // ConnectToET | |||||
381 | //---------------- | |||||
382 | void JEventSource_EVIO::ConnectToET(const char* source_name) | |||||
383 | { | |||||
384 | #ifdef HAVE_ET | |||||
385 | ||||||
386 | /// Format for ET source strings is: | |||||
387 | /// | |||||
388 | /// ET:session:station:host:port | |||||
389 | /// | |||||
390 | /// The session is used to form the filename of the ET | |||||
391 | /// system. For example, if an session of "eb" is specified, | |||||
392 | /// then a file named "/tmp/et_sys_eb" is assumed to be | |||||
393 | /// what should be opened. If no session is specified (or | |||||
394 | /// an empty session name) then "none" is used as the session. | |||||
395 | /// | |||||
396 | /// If the station name specified does not exist, it will | |||||
397 | /// be created. If it does exist, the existing station will | |||||
398 | /// be used. If no station is specified, then the station | |||||
399 | /// name "DANA" will be used. Any station created will be | |||||
400 | /// set to "blocking" *unless* the configuration paramter | |||||
401 | /// EVIO:ET_STATION_CREATE_BLOCKING is set to "0" | |||||
402 | /// in which case it will be set to non-blocking. | |||||
403 | /// | |||||
404 | /// If the host is specified, then an attempt will be made | |||||
405 | /// to open that system. If it is not specified, then | |||||
406 | /// it will attempt to open an ET system on the local machine. | |||||
407 | /// | |||||
408 | /// If port is specified, it is used as the TCP port number | |||||
409 | /// on the remote host to attach to. If the host is not | |||||
410 | /// specified (i.e. by having two colons and therefore | |||||
411 | /// an empty string) then the port is ignored. If the | |||||
412 | /// port is omitted or specified as "0", then the default | |||||
413 | /// port is used. | |||||
414 | /// | |||||
415 | ||||||
416 | // Split source name into session, station, etc... | |||||
417 | vector<string> fields; | |||||
418 | string str = source_name; | |||||
419 | size_t startpos=0, endpos=0; | |||||
420 | while((endpos = str.find(":", startpos)) != str.npos){ | |||||
421 | size_t len = endpos-startpos; | |||||
422 | fields.push_back(len==0 ? "":str.substr(startpos, len)); | |||||
423 | startpos = endpos+1; | |||||
424 | } | |||||
425 | if(startpos<str.length()) fields.push_back(str.substr(startpos, str.npos)); | |||||
426 | ||||||
427 | string session = fields.size()>1 ? fields[1]:""; | |||||
428 | string station = fields.size()>2 ? fields[2]:""; | |||||
429 | string host = fields.size()>3 ? fields[3]:"localhost"; | |||||
430 | int port = fields.size()>4 ? atoi(fields[4].c_str()):ET_SERVER_PORT; | |||||
431 | ||||||
432 | if(session == "") session = "none"; | |||||
433 | if(station == "") station = "DANA"; | |||||
434 | if(host == "") host = "localhost"; | |||||
435 | string fname = session.at(0)=='/' ? session:(string("/tmp/et_sys_") + session); | |||||
436 | ||||||
437 | // Report to user what we're doing | |||||
438 | jout << " Opening ET system:" << endl; | |||||
439 | if(session!=fname) jout << " session: " << session << endl; | |||||
440 | jout << " station: " << station << endl; | |||||
441 | jout << " system file: " << fname << endl; | |||||
442 | jout << " host: " << host << endl; | |||||
443 | if(port !=0) jout << " port: " << port << endl; | |||||
444 | ||||||
445 | // connect to the ET system | |||||
446 | et_openconfig openconfig; | |||||
447 | et_open_config_init(&openconfig); | |||||
448 | if(host != ""){ | |||||
449 | if(host.find("239.")==0){ | |||||
450 | cout<<__FILE__"libraries/DAQ/JEventSource_EVIO.cc"<<":"<<__LINE__450<<" Configuring input ET for multicast" << endl; | |||||
451 | et_open_config_setcast(openconfig, ET_MULTICAST); | |||||
452 | et_open_config_addmulticast(openconfig, host.c_str()); | |||||
453 | et_open_config_sethost(openconfig, ET_HOST_ANYWHERE); | |||||
454 | et_open_config_setport(openconfig, port); | |||||
455 | struct timespec tspec={5,5}; | |||||
456 | et_open_config_settimeout(openconfig, tspec); | |||||
457 | et_open_config_setwait(openconfig, ET_OPEN_WAIT); | |||||
458 | }else{ | |||||
459 | cout<<__FILE__"libraries/DAQ/JEventSource_EVIO.cc"<<":"<<__LINE__459<<" Configuring input ET for direct connection" << endl; | |||||
460 | et_open_config_setcast(openconfig, ET_DIRECT); | |||||
461 | et_open_config_setmode(openconfig, ET_HOST_AS_LOCAL); // ET_HOST_AS_LOCAL or ET_HOST_AS_REMOTE | |||||
462 | et_open_config_sethost(openconfig, host.c_str()); | |||||
463 | et_open_config_setport(openconfig, ET_BROADCAST_PORT); | |||||
464 | if(port != 0)et_open_config_setserverport(openconfig, port); | |||||
465 | } | |||||
466 | } | |||||
467 | int err = et_open(&sys_id,fname.c_str(),openconfig); | |||||
468 | if(err != ET_OK){ | |||||
469 | cerr << __FILE__"libraries/DAQ/JEventSource_EVIO.cc"<<":"<<__LINE__469<<" Problem opening ET system"<<endl; | |||||
470 | cerr << et_perror(err); | |||||
471 | return; | |||||
472 | } | |||||
473 | ||||||
474 | // create station config in case no station exists | |||||
475 | et_statconfig et_station_config; | |||||
476 | et_station_config_init(&et_station_config); | |||||
477 | et_station_config_setblock(et_station_config, ET_STATION_CREATE_BLOCKING ? ET_STATION_BLOCKING:ET_STATION_NONBLOCKING); | |||||
478 | et_station_config_setselect(et_station_config,ET_STATION_SELECT_ALL); | |||||
479 | et_station_config_setuser(et_station_config,ET_STATION_USER_MULTI); | |||||
480 | et_station_config_setrestore(et_station_config,ET_STATION_RESTORE_OUT); | |||||
481 | et_station_config_setcue(et_station_config,ET_STATION_NEVENTS); | |||||
482 | et_station_config_setprescale(et_station_config,1); | |||||
483 | cout<<"ET station configured\n"; | |||||
484 | ||||||
485 | // create station if not already created | |||||
486 | int status=et_station_create(sys_id,&sta_id,station.c_str(),et_station_config); | |||||
487 | if((status!=ET_OK)&&(status!=ET_ERROR_EXISTS)) { | |||||
488 | et_close(sys_id); | |||||
489 | cerr << "Unable to create station " << station << endl; | |||||
490 | cerr << et_perror(status); | |||||
491 | ||||||
492 | // Check that the number of events in the ET system is not | |||||
493 | // less than the number of events we specified for the station CUE. | |||||
494 | int Nevents = 0; | |||||
495 | et_system_getnumevents(sys_id, &Nevents); | |||||
496 | if(Nevents <= ET_STATION_NEVENTS){ | |||||
497 | jerr << "NOTE: The number of events specified for the station cue is equal to" << endl; | |||||
498 | jerr << "or greater than the number of events in the entire ET system:" << endl; | |||||
499 | jerr << endl; | |||||
500 | jerr << " " << ET_STATION_NEVENTS << " >= " << Nevents << endl; | |||||
501 | jerr << endl; | |||||
502 | jerr << "Try re-running with: " << endl; | |||||
503 | jerr << endl; | |||||
504 | jerr << " -PEVIO:ET_STATION_NEVENTS=" << (Nevents+1)/2 << endl; | |||||
505 | jerr << endl; | |||||
506 | } | |||||
507 | return; | |||||
508 | } | |||||
509 | if(status==ET_ERROR_EXISTS){ | |||||
510 | jout << " Using existing ET station " << station << endl; | |||||
511 | }else{ | |||||
512 | jout << " ET station " << station << " created\n"; | |||||
513 | } | |||||
514 | ||||||
515 | // Attach to the ET station | |||||
516 | status=et_station_attach(sys_id,sta_id,&att_id); | |||||
517 | if(status!=ET_OK) { | |||||
518 | et_close(sys_id); | |||||
519 | jerr << "Unable to attach to station " << station << endl; | |||||
520 | return; | |||||
521 | } | |||||
522 | ||||||
523 | jout << "...now connected to ET system: " << fname | |||||
524 | << ", station: " << station << " (station id=" << sta_id << ", attach id=" << att_id <<")" << endl; | |||||
525 | ||||||
526 | et_connected = true; | |||||
527 | // chan = new evioETChannel(sys_id, att_id); | |||||
528 | ||||||
529 | // Make sure the size of event buffers we will allocate are at least as big | |||||
530 | // as the event size used in the ET system | |||||
531 | size_t eventsize; | |||||
532 | et_system_geteventsize(sys_id, &eventsize); | |||||
533 | if((uint32_t)eventsize > BUFFER_SIZE){ | |||||
534 | jout<<" Events in ET system are larger than currently set buffer size:"<<endl; | |||||
535 | jout<<" "<<eventsize<<" > "<<BUFFER_SIZE<<endl; | |||||
536 | jout<<" Setting BUFFER_SIZE to "<<eventsize<<endl; | |||||
537 | BUFFER_SIZE = (uint32_t)eventsize; | |||||
538 | }else{ | |||||
539 | jout<<" ET system event size:"<<eventsize<<" JEventSource_EVIO.BUFFER_SIZE:"<<BUFFER_SIZE<<endl; | |||||
540 | } | |||||
541 | ||||||
542 | #else | |||||
543 | jerr << endl; | |||||
544 | jerr << "You are attempting to connect to an ET system using a binary that" <<endl; | |||||
545 | jerr << "was compiled without ET support. Please reconfigure and recompile" <<endl; | |||||
546 | jerr << "To get ET support." << endl; | |||||
547 | jerr << endl; | |||||
548 | throw exception(); | |||||
549 | #endif // HAVE_ET | |||||
550 | } | |||||
551 | ||||||
552 | //---------------- | |||||
553 | // Cleanup | |||||
554 | //---------------- | |||||
555 | void JEventSource_EVIO::Cleanup(void) | |||||
556 | { | |||||
557 | /// This is called internally by the JEventSource_EVIO class | |||||
558 | /// once all events have been read in. Its purpose is to | |||||
559 | /// free the hidden memory in all of the container class | |||||
560 | /// members of the JEventSource_EVIO class. This is needed | |||||
561 | /// for jobs that process a lot of input files and therefore | |||||
562 | /// create a lot JEventSource_EVIO objects. JANA does not delete | |||||
563 | /// these objects until the end of the job so this tends to | |||||
564 | /// act like a memory leak. The data used can be substantial | |||||
565 | /// (nearly 1GB per JEventSource_EVIO object). | |||||
566 | if(hdevio) delete hdevio; | |||||
567 | hdevio = NULL__null; | |||||
568 | //if(chan) delete chan; | |||||
569 | //chan = NULL; | |||||
570 | #ifdef HAVE_ET | |||||
571 | if(et_connected) et_close(sys_id); | |||||
572 | et_connected = false; | |||||
573 | #endif // HAVE_ET | |||||
574 | ||||||
575 | module_type.clear(); | |||||
576 | modtype_translate.clear(); | |||||
577 | ||||||
578 | for(uint32_t i=0; i<hit_objs.size(); i++) hit_objs[i].resize(0); | |||||
579 | hit_objs.resize(0); | |||||
580 | ||||||
581 | while(!stored_events.empty()){ | |||||
582 | delete stored_events.front(); | |||||
583 | stored_events.pop(); | |||||
584 | } | |||||
585 | while(!evio_buffer_pool.empty()) { | |||||
586 | delete evio_buffer_pool.back(); | |||||
587 | evio_buffer_pool.pop_back(); | |||||
588 | } | |||||
589 | while(!event_source_data_types.empty()){ | |||||
590 | event_source_data_types.erase(event_source_data_types.begin()); | |||||
591 | } | |||||
592 | } | |||||
593 | ||||||
594 | //---------------- | |||||
595 | // GetEvent | |||||
596 | //---------------- | |||||
597 | jerror_t JEventSource_EVIO::GetEvent(JEvent &event) | |||||
598 | { | |||||
599 | if(VERBOSE>1) evioout << "GetEvent called for &event = " << hex << &event << dec << endl; | |||||
600 | ||||||
601 | // If we couldn't even open the source, then there's nothing to do | |||||
602 | bool no_source = true; | |||||
603 | #if USE_HDEVIO1 | |||||
604 | if(source_type==kFileSource && hdevio->is_open) no_source = false; | |||||
605 | #endif | |||||
606 | if(source_type==kETSource && et_connected) no_source = false; | |||||
607 | if(no_source)throw JException(string("Unable to open EVIO channel for \"") + source_name + "\""); | |||||
608 | ||||||
609 | ||||||
610 | // This may not be a long term solution, but here goes: | |||||
611 | // We need to write single events out in EVIO format, possibly | |||||
612 | // with new information attached. The easiest way to do this | |||||
613 | // is to keep the DOM tree when the event is read in and modify | |||||
614 | // it if needed before writing it out. The complication comes | |||||
615 | // in that entangled events will not have a dedicated DOM tree | |||||
616 | // for every event. This is only an issue if disentangling is | |||||
617 | // not done upstream. How this is handled now is that the DOM | |||||
618 | // tree pointer is copied into the ObjList object for the first | |||||
619 | // physics event found in the DAQ event. The DOM tree is freed | |||||
620 | // in FreeEvent (if the pointer is non-NULL). Note that for | |||||
621 | // single event blocks (i.e. already disentangled events) the | |||||
622 | // stored_events list will always be empty so "evt" is always | |||||
623 | // set. | |||||
624 | ||||||
625 | // Check for event stored from parsing a previously read in | |||||
626 | // DAQ event | |||||
627 | ObjList *objs_ptr = NULL__null; | |||||
628 | pthread_mutex_lock(&stored_events_mutex); | |||||
629 | if(!stored_events.empty()){ | |||||
630 | objs_ptr = stored_events.front(); | |||||
631 | stored_events.pop(); | |||||
632 | ||||||
633 | // If this is a stored event then it almost certainly | |||||
634 | // came from a multi-event block of physics events. | |||||
635 | // Set the physics event status bit. | |||||
636 | event.SetStatusBit(kSTATUS_PHYSICS_EVENT); | |||||
637 | } | |||||
638 | pthread_mutex_unlock(&stored_events_mutex); | |||||
639 | ||||||
640 | // If no events are currently stored in the buffer, then | |||||
641 | // read in another event block. | |||||
642 | if(objs_ptr == NULL__null){ | |||||
643 | uint32_t *buff = NULL__null; // ReadEVIOEvent will allocate memory from pool for this | |||||
644 | double t1 = GetTime(); | |||||
645 | jerror_t err = ReadEVIOEvent(buff); | |||||
646 | double t2 = GetTime(); | |||||
647 | if(err != NOERROR) return err; | |||||
648 | if(buff == NULL__null) return MEMORY_ALLOCATION_ERROR; | |||||
649 | uint32_t buff_size = ((*buff) + 1)*4; // first word in EVIO buffer is total bank size in words | |||||
650 | ||||||
651 | objs_ptr = new ObjList(); | |||||
652 | objs_ptr->time_evio_read = t2 - t1; | |||||
653 | objs_ptr->eviobuff = buff; | |||||
654 | objs_ptr->eviobuff_size = buff_size; | |||||
655 | objs_ptr->run_number = FindRunNumber(buff); | |||||
656 | objs_ptr->event_number = FindEventNumber(buff); | |||||
657 | ||||||
658 | // Increment counter that keeps track of how many events | |||||
659 | // are currently being processed. | |||||
660 | pthread_mutex_lock(¤t_event_count_mutex); | |||||
661 | current_event_count++; | |||||
662 | pthread_mutex_unlock(¤t_event_count_mutex); | |||||
663 | } | |||||
664 | ||||||
665 | // Store a pointer to the ObjList object for this event in the | |||||
666 | // JEvent as the Reference value. Parsing will be done later | |||||
667 | // in GetObjects() -> ParseEvents() using the eviobuff pointer. | |||||
668 | event.SetJEventSource(this); | |||||
669 | event.SetEventNumber((uint64_t)objs_ptr->event_number); | |||||
670 | event.SetRunNumber(objs_ptr->run_number); | |||||
671 | event.SetRef(objs_ptr); | |||||
672 | event.SetStatusBit(kSTATUS_EVIO); | |||||
673 | if( source_type == kFileSource ) event.SetStatusBit(kSTATUS_FROM_FILE); | |||||
674 | if( source_type == kETSource ) event.SetStatusBit(kSTATUS_FROM_ET); | |||||
675 | if(objs_ptr) | |||||
676 | if(objs_ptr->eviobuff) FindEventType(objs_ptr->eviobuff, event); | |||||
677 | ||||||
678 | // EPICS and BOR events are barrier events | |||||
679 | if(event.GetStatusBit(kSTATUS_EPICS_EVENT) || event.GetStatusBit(kSTATUS_BOR_EVENT) ){ | |||||
680 | event.SetSequential(); | |||||
681 | } | |||||
682 | ||||||
683 | Nevents_read++; | |||||
684 | ||||||
685 | return NOERROR; | |||||
686 | } | |||||
687 | ||||||
688 | //---------------- | |||||
689 | // FreeEvent | |||||
690 | //---------------- | |||||
691 | void JEventSource_EVIO::FreeEvent(JEvent &event) | |||||
692 | { | |||||
693 | if(VERBOSE>1) evioout << "FreeEvent called for event: " << event.GetEventNumber() << endl; | |||||
694 | ||||||
695 | ObjList *objs_ptr = (ObjList*)event.GetRef(); | |||||
696 | if(objs_ptr){ | |||||
697 | ||||||
698 | // If a DAQ event was read in but GetObjects never called | |||||
699 | // then the buffer will never have been parsed. Since the | |||||
700 | // DAQ event could hold multiple Physics events, we parse | |||||
701 | // it now to ensure all physics events are presented by | |||||
702 | // the event source. The ParseEvents call will copy the | |||||
703 | // first event's parameters into our objs_ptr object, but | |||||
704 | // any additional ones will be placed in stored_events. | |||||
705 | if(!objs_ptr->eviobuff_parsed) ParseEvents(objs_ptr); | |||||
706 | ||||||
707 | if(objs_ptr->own_objects){ | |||||
708 | ||||||
709 | for(unsigned int i=0; i<objs_ptr->hit_objs.size(); i++){ | |||||
710 | delete objs_ptr->hit_objs[i]; | |||||
711 | } | |||||
712 | ||||||
713 | for(unsigned int i=0; i<objs_ptr->config_objs.size(); i++){ | |||||
714 | delete objs_ptr->config_objs[i]; | |||||
715 | } | |||||
716 | ||||||
717 | for(unsigned int i=0; i<objs_ptr->misc_objs.size(); i++){ | |||||
718 | delete objs_ptr->misc_objs[i]; | |||||
719 | } | |||||
720 | } | |||||
721 | ||||||
722 | if(objs_ptr->DOMTree != NULL__null) delete objs_ptr->DOMTree; | |||||
723 | if(objs_ptr->eviobuff){ | |||||
724 | ||||||
725 | // If we have not already stopped reading events from | |||||
726 | // the source then return this buffer to the pool. Otherwise, | |||||
727 | // delete the buffer. | |||||
728 | if(hdevio){ | |||||
729 | // Return EVIO buffer to pool for recycling | |||||
730 | pthread_mutex_lock(&evio_buffer_pool_mutex); | |||||
731 | evio_buffer_pool.push_front(objs_ptr->eviobuff); | |||||
732 | pthread_mutex_unlock(&evio_buffer_pool_mutex); | |||||
733 | }else{ | |||||
734 | free(objs_ptr->eviobuff); | |||||
735 | } | |||||
736 | } | |||||
737 | ||||||
738 | delete objs_ptr; | |||||
739 | ||||||
740 | // Decrement counter that keeps track of how many events | |||||
741 | // are currently being processed. | |||||
742 | pthread_mutex_lock(¤t_event_count_mutex); | |||||
743 | current_event_count--; | |||||
744 | bool last_event = (hdevio==NULL__null) && (current_event_count==0); | |||||
745 | pthread_mutex_unlock(¤t_event_count_mutex); | |||||
746 | ||||||
747 | // If we are the last event, then clean up as much memory as | |||||
748 | // possible. | |||||
749 | if(last_event) Cleanup(); | |||||
750 | } | |||||
751 | } | |||||
752 | ||||||
753 | //---------------- | |||||
754 | // ParseEvents | |||||
755 | //---------------- | |||||
756 | jerror_t JEventSource_EVIO::ParseEvents(ObjList *objs_ptr) | |||||
757 | { | |||||
758 | /// This is the high-level entry point for parsing the | |||||
759 | /// DAQ event in order to create one or more Physics | |||||
760 | /// events. It will be called from either GetObjects | |||||
761 | /// or FreeEvent, the latter being done only if needed | |||||
762 | /// to ensure the event does eventually get parsed. | |||||
763 | /// The grunt work of actually parsing the data starts | |||||
764 | /// in ParseEVIOEvent(). | |||||
765 | /// | |||||
766 | /// This method is here so that the DOM Tree creation | |||||
767 | /// and data parsing can be deferred from the EventBuffer | |||||
768 | /// thread (of which there is only one) to an event | |||||
769 | /// processor thread (or which there may be many). Since | |||||
770 | /// the DOM tree creating and data parsing represent the | |||||
771 | /// larger time cost of getting the event into memory, | |||||
772 | /// a siginificant performance increase can be gained | |||||
773 | /// using this slightly more complicated method. | |||||
774 | ||||||
775 | if(VERBOSE>2) evioout << " Entering ParseEvents() with objs_ptr=" << hex << objs_ptr << dec << endl; | |||||
| ||||||
776 | ||||||
777 | // Double check that we're not re-parsing an event | |||||
778 | if(objs_ptr->eviobuff_parsed){ | |||||
779 | jerr << " DAQ event already parsed!! Bug in code. Contact davidl@jlab.org" << endl; | |||||
780 | return UNKNOWN_ERROR; | |||||
781 | } | |||||
782 | ||||||
783 | // Bomb-proof against getting a NULL buffer | |||||
784 | uint32_t *buff = objs_ptr->eviobuff; | |||||
785 | if(buff == NULL__null){ | |||||
786 | jerr << " Bad buffer pointer passed to JEventSource_EVIO::ParseEvent()!!" << endl; | |||||
787 | return RESOURCE_UNAVAILABLE; | |||||
788 | } | |||||
789 | ||||||
790 | // This container will be used to hold all of the individual | |||||
791 | // Physics (L1 triggered) events for this DAQ event. This includes | |||||
792 | // both dientangling multi-event blocks and separating multi-event | |||||
793 | // ET events. | |||||
794 | list<ObjList*> full_events; | |||||
795 | ||||||
796 | // Setup up iptr and iend to point to the start of the first event | |||||
797 | // and the word just after the end of the last event respectively. | |||||
798 | // Initialize them for the case of reading from a file and not a | |||||
799 | // CODA-produced ET event | |||||
800 | uint32_t *iptr = &buff[0]; | |||||
801 | uint32_t *iend = &buff[buff[0]+1]; // EVIO length word is exclusive so +1 | |||||
802 | ||||||
803 | // If the "event" was read from ET, then it may (and likely | |||||
804 | // will) contain several DAQ events. (Each DAQ event may itself | |||||
805 | // contain many L1 trigger events.) In addition, the ET event | |||||
806 | // will have a Network Transport Header (NTH) that must be skipped | |||||
807 | // but only if read from CODA. Events put into the ET system | |||||
808 | // by other means will not include the NTH. To decide whether | |||||
809 | // there is an NTH, we look at the magic word and the header length. | |||||
810 | // Note that byteswapping should already have occured. | |||||
811 | if(source_type==kETSource && buff[7]==0xc0da0100 && buff[2]==8){ | |||||
812 | // This buffer read from ET. Redefine iptr and iend | |||||
813 | iptr = &buff[8]; | |||||
814 | iend = &buff[buff[0]]; // EVIO length word in NTH is inclusive so don't add 1 | |||||
815 | } | |||||
816 | ||||||
817 | if(VERBOSE>5) evioout << " Looping event stack with " << *iptr << " words" << endl; | |||||
818 | ||||||
819 | // Loop over events in buffer until entire buffer is parsed. | |||||
820 | // When reading from a file, this loop should only get executed once. | |||||
821 | int Nevents_in_stack=0; | |||||
822 | while(iptr < iend){ | |||||
823 | ||||||
824 | double time_dom_tree = 0; | |||||
825 | double time_evio_parse = 0; | |||||
826 | ||||||
827 | // Make a evioDOMTree for this DAQ event | |||||
828 | evioDOMTree *evt = NULL__null; | |||||
829 | if(MAKE_DOM_TREE){ | |||||
830 | try{ | |||||
831 | double tstart = GetTime(); | |||||
832 | evt = new evioDOMTree(iptr); | |||||
833 | time_dom_tree = GetTime() - tstart; | |||||
834 | }catch(evioException &e){ | |||||
835 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<835<<" " << "Problem creating EVIO DOM Tree!!" << endl; | |||||
836 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<836<<" " << e.what() << endl; | |||||
837 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<837<<" " << "Binary dump of first 160 words follows:" << endl; | |||||
838 | DumpBinary(iptr, iend, 160); | |||||
839 | exit(-1); | |||||
840 | } | |||||
841 | } | |||||
842 | ||||||
843 | if(evt){ | |||||
844 | // Parse event, making other ObjList objects | |||||
845 | list<ObjList*> my_full_events; | |||||
846 | //bool skipped_parsing = true; | |||||
847 | if(PARSE_EVIO_EVENTS){ | |||||
848 | try{ | |||||
849 | double tstart = GetTime(); | |||||
850 | ParseEVIOEvent(evt, my_full_events); | |||||
851 | time_evio_parse = GetTime() - tstart; | |||||
852 | }catch(JException &jexception){ | |||||
853 | jerr << "Exception thrown from ParseEVIOEvent!" << endl; | |||||
854 | jerr << jexception.toString() << endl; | |||||
855 | } | |||||
856 | } | |||||
857 | ||||||
858 | // Append physics events found for this DAQ event to the list of all physics events | |||||
859 | if(!my_full_events.empty()) { | |||||
860 | my_full_events.front()->DOMTree = evt; // keep DOMTree pointer with first event from this DAQ event | |||||
861 | my_full_events.front()->time_dom_tree = time_dom_tree; | |||||
862 | my_full_events.front()->time_evio_parse = time_evio_parse; | |||||
863 | full_events.insert( full_events.end(), my_full_events.begin(), my_full_events.end() ); | |||||
864 | }else{ | |||||
865 | delete evt; | |||||
866 | } | |||||
867 | }else{ | |||||
868 | // No DOM tree made for this buffer. Insert an empty event into | |||||
869 | // the list so we can keep track of the number of events seen | |||||
870 | // even when DOMTree creation is turned off. | |||||
871 | ObjList *objs = new ObjList; | |||||
872 | full_events.push_back(objs); | |||||
873 | } | |||||
874 | ||||||
875 | // Advance pointer to next event in buffer | |||||
876 | iptr += iptr[0]+1; | |||||
877 | Nevents_in_stack++; // number of events processed in this buffer (for debugging) | |||||
878 | } | |||||
879 | ||||||
880 | if(VERBOSE>5) evioout << " Loop finished. " << full_events.size() << " events total found (" << Nevents_in_stack << " events in stack)" << endl; | |||||
881 | ||||||
882 | // At this point, we have parsed the DAQ event and extracted all physics | |||||
883 | // events into the full_events list. In the case of a prestart or go event | |||||
884 | // read from an EVIO file, the full_events list may actually be empty at | |||||
885 | // this point. For these cases, we need to add an empty event for the | |||||
886 | // current thread to "process". | |||||
887 | bool empty_event = full_events.empty(); | |||||
888 | if(empty_event) full_events.push_back(new ObjList()); | |||||
889 | ||||||
890 | // Whether we actually parsed the events or not, we mark them as being | |||||
891 | // parsed since it is really just used as a flag to tell whether this | |||||
892 | // method should be called or not. | |||||
893 | list<ObjList*>::iterator iter = full_events.begin(); | |||||
894 | for( ; iter != full_events.end(); iter++ ) (*iter)->eviobuff_parsed = true; | |||||
895 | ||||||
896 | // Copy the first event's objects obtained from parsing into this event's ObjList | |||||
897 | ObjList *objs = full_events.front(); | |||||
898 | full_events.pop_front(); | |||||
899 | //objs_ptr->run_number = empty_event ? objs_ptr->run_number:objs->run_number; | |||||
900 | objs_ptr->own_objects = objs->own_objects; | |||||
901 | objs_ptr->hit_objs = objs->hit_objs; | |||||
902 | objs_ptr->config_objs = objs->config_objs; | |||||
903 | objs_ptr->misc_objs = objs->misc_objs; | |||||
904 | objs_ptr->eviobuff_parsed = objs->eviobuff_parsed; | |||||
905 | objs_ptr->time_dom_tree = objs->time_dom_tree; | |||||
906 | objs_ptr->time_evio_parse = objs->time_evio_parse; | |||||
907 | //objs_ptr->eviobuff = objs->eviobuff; // Don't copy this! (it causes memory leak) | |||||
908 | //objs_ptr->eviobuff_size = objs->eviobuff_size; | |||||
909 | objs_ptr->DOMTree = objs->DOMTree; | |||||
910 | delete objs; | |||||
911 | ||||||
912 | // Config objects come from banks that are created when a block | |||||
913 | // of events is read out. Thus, a single set of config. objects | |||||
914 | // will be created when parsing a multi-event block. Here, we duplicate | |||||
915 | // all config objects for the first event for every other event in the | |||||
916 | // block. To make this a little more compact and maintainable, we use a | |||||
917 | // #define. This allows us to write the class type once and guarantee | |||||
918 | // that it shows up the same in all places. For example, using | |||||
919 | // CloneConfigObject(Df125Config) will expand to something like: | |||||
920 | // | |||||
921 | // if(confobj->className() == string("Df125Config")){ | |||||
922 | // c = new Df125Config(confobj->rocid,confobj->slot_mask); | |||||
923 | // *((Df125Config*)c) = *((Df125Config*)confobj); | |||||
924 | // } | |||||
925 | #define CloneConfigObject(T){ if(confobj->className() == string("T")){ c = new T(confobj ->rocid,confobj->slot_mask); *((T*)c) = *((T*)confobj); } }{ if(confobj->className() == string(#T)){ c = new T(confobj->rocid,confobj->slot_mask); *((T*)c) = *((T*)confobj);} } | |||||
926 | list<ObjList*>::iterator feiter = full_events.begin(); | |||||
927 | for(; feiter!=full_events.end(); feiter++){ | |||||
928 | ObjList *objs = *feiter; | |||||
929 | for(uint32_t j=0; j<objs_ptr->config_objs.size(); j++){ | |||||
930 | DDAQConfig *confobj = objs_ptr->config_objs[j]; | |||||
931 | DDAQConfig *c = NULL__null; | |||||
932 | CloneConfigObject(Df250Config){ if(confobj->className() == string("Df250Config")){ c = new Df250Config(confobj->rocid,confobj->slot_mask); *((Df250Config *)c) = *((Df250Config*)confobj);} }; | |||||
933 | CloneConfigObject(Df125Config){ if(confobj->className() == string("Df125Config")){ c = new Df125Config(confobj->rocid,confobj->slot_mask); *((Df125Config *)c) = *((Df125Config*)confobj);} }; | |||||
934 | CloneConfigObject(DF1TDCConfig){ if(confobj->className() == string("DF1TDCConfig")){ c = new DF1TDCConfig(confobj->rocid,confobj->slot_mask); *((DF1TDCConfig *)c) = *((DF1TDCConfig*)confobj);} }; | |||||
935 | CloneConfigObject(DCAEN1290TDCConfig){ if(confobj->className() == string("DCAEN1290TDCConfig")) { c = new DCAEN1290TDCConfig(confobj->rocid,confobj->slot_mask ); *((DCAEN1290TDCConfig*)c) = *((DCAEN1290TDCConfig*)confobj );} }; | |||||
| ||||||
936 | if(c)objs->config_objs.push_back(c); | |||||
937 | } | |||||
938 | } | |||||
939 | ||||||
940 | // Copy remaining events into the stored_events container | |||||
941 | pthread_mutex_lock(&stored_events_mutex); | |||||
942 | while(!full_events.empty()){ | |||||
943 | objs = full_events.front(); | |||||
944 | full_events.pop_front(); | |||||
945 | stored_events.push(objs); | |||||
946 | ||||||
947 | // Copy run number from first event | |||||
948 | objs->run_number = objs_ptr->run_number; | |||||
949 | } | |||||
950 | pthread_mutex_unlock(&stored_events_mutex); | |||||
951 | ||||||
952 | if(VERBOSE>2) evioout << " Leaving ParseEvents()" << endl; | |||||
953 | ||||||
954 | return NOERROR; | |||||
955 | } | |||||
956 | ||||||
957 | //---------------- | |||||
958 | // GetPoolBuffer | |||||
959 | //---------------- | |||||
960 | uint32_t* JEventSource_EVIO::GetPoolBuffer(void) | |||||
961 | { | |||||
962 | // Get buffer from pool or allocate new one if needed | |||||
963 | uint32_t *buff = NULL__null; | |||||
964 | pthread_mutex_lock(&evio_buffer_pool_mutex); | |||||
965 | if(evio_buffer_pool.empty()){ | |||||
966 | // Allocate new block of memory | |||||
967 | if(VERBOSE>5) evioout << " evio_buffer_pool empty. Allocating new buffer of size: " << BUFFER_SIZE << " bytes" << endl; | |||||
968 | buff = (uint32_t*)malloc(BUFFER_SIZE); | |||||
969 | }else{ | |||||
970 | if(VERBOSE>5) evioout << " evio_buffer_pool not empty(size=" << evio_buffer_pool.size() << "). using buffer from pool" << endl; | |||||
971 | buff = evio_buffer_pool.front(); | |||||
972 | evio_buffer_pool.pop_front(); | |||||
973 | } | |||||
974 | pthread_mutex_unlock(&evio_buffer_pool_mutex); | |||||
975 | ||||||
976 | return buff; | |||||
977 | } | |||||
978 | ||||||
979 | //---------------- | |||||
980 | // ReadEVIOEvent | |||||
981 | //---------------- | |||||
982 | jerror_t JEventSource_EVIO::ReadEVIOEvent(uint32_t* &buff) | |||||
983 | { | |||||
984 | /// This method will read an event from the source (file or ET system) | |||||
985 | /// copying the data into "buff". No parsing of the data is done at | |||||
986 | /// this level except that if the event comes from ET and needs to be | |||||
987 | /// byte-swapped, the byte swapping is done during the copy. | |||||
988 | /// | |||||
989 | /// This is called from the GetEvent method and therefore run in | |||||
990 | /// the event reader thread. Events read from ET may contain several DAQ | |||||
991 | /// events in a single buffer (and each of those may contain several | |||||
992 | /// physics events if read in multi-event blocks). Separating the multiple | |||||
993 | /// DAQ events is left to the ParseEvents method which gets called later | |||||
994 | /// from the event processing threads to improve efficiency. | |||||
995 | ||||||
996 | if(VERBOSE>1) evioout << " ReadEVIOEvent() called with &buff=" << hex << &buff << dec << endl; | |||||
997 | ||||||
998 | try{ | |||||
999 | if(source_type==kFileSource){ | |||||
1000 | if(VERBOSE>3) evioout << " attempting read from EVIO file source ..." << endl; | |||||
1001 | ||||||
1002 | #if USE_HDEVIO1 | |||||
1003 | ||||||
1004 | bool done = false; | |||||
1005 | buff = GetPoolBuffer(); // Get (or allocate) a new buffer from the pool | |||||
1006 | uint32_t buff_size = BUFFER_SIZE; | |||||
1007 | while(!done){ | |||||
1008 | if(hdevio->read(buff, buff_size)){ | |||||
1009 | done = true; | |||||
1010 | }else{ | |||||
1011 | string mess = hdevio->err_mess.str(); | |||||
1012 | ||||||
1013 | switch(hdevio->err_code){ | |||||
1014 | case HDEVIO::HDEVIO_OK: | |||||
1015 | done = true; | |||||
1016 | break; | |||||
1017 | case HDEVIO::HDEVIO_USER_BUFFER_TOO_SMALL: | |||||
1018 | if(VERBOSE>0) evioout << "EVIO buffer too small (" << buff_size << " bytes) . Reallocating to " << hdevio->last_event_len<< endl; | |||||
1019 | if(buff) delete[] buff; | |||||
1020 | buff_size = hdevio->last_event_len; | |||||
1021 | buff = new uint32_t[buff_size]; | |||||
1022 | continue; | |||||
1023 | break; | |||||
1024 | case HDEVIO::HDEVIO_EVENT_BIGGER_THAN_BLOCK: | |||||
1025 | case HDEVIO::HDEVIO_BANK_TRUNCATED: | |||||
1026 | case HDEVIO::HDEVIO_UNKNOWN_BANK_TYPE: | |||||
1027 | if(VERBOSE>0) cout << endl << mess << endl; | |||||
1028 | continue; | |||||
1029 | break; | |||||
1030 | case HDEVIO::HDEVIO_EOF: | |||||
1031 | if(hdevio) delete hdevio; | |||||
1032 | hdevio = NULL__null; | |||||
1033 | if(LOOP_FOREVER && Nevents_read>=1){ | |||||
1034 | cout << "LOOP_FOREVER: reopening " << this->source_name <<endl; | |||||
1035 | hdevio = new HDEVIO(this->source_name); | |||||
1036 | if( hdevio->is_open ) continue; | |||||
1037 | } | |||||
1038 | return NO_MORE_EVENTS_IN_SOURCE; | |||||
1039 | break; | |||||
1040 | default: | |||||
1041 | cout << endl << "err_code=" << hdevio->err_code << endl; | |||||
1042 | cout << endl << mess << endl; | |||||
1043 | if(hdevio) delete hdevio; | |||||
1044 | hdevio = NULL__null; | |||||
1045 | return NO_MORE_EVENTS_IN_SOURCE; | |||||
1046 | break; | |||||
1047 | } | |||||
1048 | } | |||||
1049 | } // while(!done) | |||||
1050 | ||||||
1051 | #else | |||||
1052 | // ( removed old evio library code ) | |||||
1053 | #endif // USE_HDEVIO | |||||
1054 | ||||||
1055 | }else if(source_type==kETSource){ | |||||
1056 | ||||||
1057 | #ifdef HAVE_ET | |||||
1058 | ||||||
1059 | if(VERBOSE>3) evioout << " attempting read from EVIO ET source ..." << endl; | |||||
1060 | ||||||
1061 | ||||||
1062 | // Loop until we get an event or are told to stop | |||||
1063 | struct timespec timeout; | |||||
1064 | timeout.tv_sec = (unsigned int)floor(TIMEOUT); // set ET timeout | |||||
1065 | timeout.tv_nsec = (unsigned int)floor(1.0E9*(TIMEOUT-(float)timeout.tv_sec)); | |||||
1066 | et_event *pe=NULL__null; | |||||
1067 | while(! japp->GetQuittingStatus() ){ | |||||
1068 | int err = et_event_get(sys_id, att_id, &pe, ET_TIMED , &timeout); | |||||
1069 | ||||||
1070 | if( err == ET_OK && pe!=NULL__null) break; // got an event. break out of while loop | |||||
1071 | ||||||
1072 | if( err == ET_OK && pe==NULL__null){ | |||||
1073 | evioout << " !!! ET returned no error, but event pointer is NULL!!!" << endl; | |||||
1074 | return NO_MORE_EVENTS_IN_SOURCE; | |||||
1075 | } | |||||
1076 | ||||||
1077 | if( err==ET_ERROR_TIMEOUT ){ | |||||
1078 | if(quit_on_next_ET_timeout)return NO_MORE_EVENTS_IN_SOURCE; | |||||
1079 | }else if( err!=ET_OK){ | |||||
1080 | evioout << " Error reading from ET. This probably means the ET" << endl; | |||||
1081 | evioout << "system has gone away (possibly due to run ending or" << endl; | |||||
1082 | evioout << "DAQ crashing). At any rate, we are quitting now as this" << endl; | |||||
1083 | evioout << "error is currently unrecoverable." << endl; | |||||
1084 | return NO_MORE_EVENTS_IN_SOURCE; | |||||
1085 | } | |||||
1086 | ||||||
1087 | usleep(10); | |||||
1088 | } | |||||
1089 | ||||||
1090 | if(japp->GetQuittingStatus() && pe==NULL__null) return NO_MORE_EVENTS_IN_SOURCE; | |||||
1091 | ||||||
1092 | // Get pointer to event buffer in the ET-owned memory | |||||
1093 | uint32_t *et_buff=NULL__null; | |||||
1094 | et_event_getdata(pe, (void**)&et_buff); | |||||
1095 | if(et_buff == NULL__null){ | |||||
1096 | jerr << " Got event from ET, but pointer to data is NULL!" << endl; | |||||
1097 | return NO_MORE_EVENTS_IN_SOURCE; | |||||
1098 | } | |||||
1099 | ||||||
1100 | // If user specified to dump words from ET event, do it right away | |||||
1101 | if(ET_DEBUG_WORDS_TO_DUMP) DumpBinary(et_buff, &et_buff[ET_DEBUG_WORDS_TO_DUMP], ET_DEBUG_WORDS_TO_DUMP, NULL__null); | |||||
1102 | ||||||
1103 | // A single ET event may have multiple EVIO blocks in it | |||||
1104 | // Each block may have several EVIO events in it. | |||||
1105 | // | |||||
1106 | // (note that "block" here is not the same as the CODA | |||||
1107 | // "block number". That one determines the number of | |||||
1108 | // entangled events within the EVIO event and is dealt | |||||
1109 | // with later while parsing the EVIO event itself.) | |||||
1110 | // | |||||
1111 | // We need to loop over EVIO blocks in this ET event | |||||
1112 | // and then loop over EVIO events within the block. | |||||
1113 | ||||||
1114 | // Get total size of ET event | |||||
1115 | size_t et_len=0; | |||||
1116 | size_t et_idx=0; | |||||
1117 | et_event_getlength(pe, &et_len); | |||||
1118 | if(VERBOSE>3)evioout << " ET event length: " << et_len << " (=" << et_len/4 << " words)"<<endl; | |||||
1119 | ||||||
1120 | // Loop over EVIO blocks in ET event | |||||
1121 | vector<uint32_t*> buffs; | |||||
1122 | while(et_idx < et_len/4){ | |||||
1123 | ||||||
1124 | // Pointer to start of EVIO block header | |||||
1125 | if(VERBOSE>3)evioout << " Looking for EVIO block header at et_idx=" << et_idx << endl; | |||||
1126 | uint32_t *evio_block = &et_buff[et_idx]; | |||||
1127 | ||||||
1128 | // Check byte order of event by looking at magic # | |||||
1129 | bool swap_needed = false; | |||||
1130 | uint32_t magic = evio_block[7]; | |||||
1131 | switch(magic){ | |||||
1132 | case 0xc0da0100: swap_needed = false; break; | |||||
1133 | case 0x0001dac0: swap_needed = true; break; | |||||
1134 | default: | |||||
1135 | evioout << "EVIO magic word not present!" << endl; | |||||
1136 | return NO_MORE_EVENTS_IN_SOURCE; | |||||
1137 | } | |||||
1138 | uint32_t len = evio_block[0]; | |||||
1139 | if(swap_needed) len = EVIO_SWAP32(len)( (((len) >> 24) & 0x000000FF) | (((len) >> 8 ) & 0x0000FF00) | (((len) << 8) & 0x00FF0000) | (((len) << 24) & 0xFF000000) ); | |||||
1140 | if(VERBOSE>3){ | |||||
1141 | evioout << "Swapping is " << (swap_needed ? "":"not ") << "needed" << endl; | |||||
1142 | evioout << " Num. words in EVIO buffer: "<<len<<endl; | |||||
1143 | } | |||||
1144 | ||||||
1145 | bool is_last_evio_block = (evio_block[5]>>(9+8))&0x1; | |||||
1146 | if(VERBOSE>3)evioout << " Is last EVIO block?: " << is_last_evio_block << endl; | |||||
1147 | ||||||
1148 | // Loop over all evio events in ET event | |||||
1149 | uint32_t idx = 8; // point to first EVIO event | |||||
1150 | while(idx<len){ | |||||
1151 | ||||||
1152 | // Size of events in bytes | |||||
1153 | uint32_t mylen = swap_needed ? EVIO_SWAP32(evio_block[idx])( (((evio_block[idx]) >> 24) & 0x000000FF) | (((evio_block [idx]) >> 8) & 0x0000FF00) | (((evio_block[idx]) << 8) & 0x00FF0000) | (((evio_block[idx]) << 24) & 0xFF000000) ):evio_block[idx]; | |||||
1154 | uint32_t bufsize_bytes = (mylen+1)*sizeof(uint32_t); // +1 is for buffer length word | |||||
1155 | if(bufsize_bytes > BUFFER_SIZE){ | |||||
1156 | jerr<<" ET event larger than our BUFFER_SIZE!!!"<<endl; | |||||
1157 | jerr<<" " << bufsize_bytes << " > " << BUFFER_SIZE << endl; | |||||
1158 | jerr<<" Will stop reading from this source now. Try restarting"<<endl; | |||||
1159 | jerr<<" with -PEVIO:BUFFER_SIZE=X where X is greater than "<<bufsize_bytes<<endl; | |||||
1160 | if(VERBOSE>3){ | |||||
1161 | evioout << "First few words in case you are trying to debug:" << endl; | |||||
1162 | for(unsigned int j=0; j<3; j++){ | |||||
1163 | char str[512]; | |||||
1164 | for(unsigned int i=0; i<5; i++){ | |||||
1165 | sprintf(str, " %08x", evio_block[i+j*5]); | |||||
1166 | evioout << str; | |||||
1167 | } | |||||
1168 | evioout << endl; | |||||
1169 | } | |||||
1170 | } | |||||
1171 | return NO_MORE_EVENTS_IN_SOURCE; | |||||
1172 | } | |||||
1173 | ||||||
1174 | // Check that EVIO event length doesn't claim to | |||||
1175 | // extend past ET buffer. | |||||
1176 | if( (idx+mylen) > len ){ | |||||
1177 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<1177<<" " << "Bad word count while swapping events in ET event stack!" << endl; | |||||
1178 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<1178<<" " << "idx="<<idx<<" mylen="<<mylen<<" len="<<len<<endl; | |||||
1179 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<1179<<" " << "This indicates a problem either with the DAQ system"<<endl; | |||||
1180 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<1180<<" " << "or this parser code! Contact davidl@jlab.org x5567 " <<endl; | |||||
1181 | break; | |||||
1182 | } | |||||
1183 | ||||||
1184 | // Get new buffer for this EVIO event | |||||
1185 | buff = GetPoolBuffer(); | |||||
1186 | ||||||
1187 | // Copy event into "buff", byte swapping if needed. | |||||
1188 | // If no swapping is needed, we just copy it all over | |||||
1189 | // in one go. | |||||
1190 | if(!swap_needed){ | |||||
1191 | memcpy(buff, &evio_block[idx], bufsize_bytes); | |||||
1192 | }else{ | |||||
1193 | swap_int32_t(&evio_block[idx], mylen+1, buff); | |||||
1194 | } | |||||
1195 | ||||||
1196 | // Update pointer to next EVIO event in stack (if any) | |||||
1197 | idx += mylen+1; | |||||
1198 | buffs.push_back(buff); | |||||
1199 | } | |||||
1200 | ||||||
1201 | // bump index to next EVIO block | |||||
1202 | et_idx += idx; | |||||
1203 | if(VERBOSE>3)evioout << " EVIO events found so far: " << buffs.size() << endl; | |||||
1204 | if(is_last_evio_block){ | |||||
1205 | if(VERBOSE>3) evioout << " Block flagged as last in ET event. Ignoring last " << (et_len/4 - et_idx) << " words" <<endl; | |||||
1206 | break; | |||||
1207 | } | |||||
1208 | } | |||||
1209 | ||||||
1210 | // Put ET event back since we're done with it | |||||
1211 | et_event_put(sys_id, att_id, pe); | |||||
1212 | ||||||
1213 | if(VERBOSE>3) evioout << " Found " << buffs.size() << " events in the ET event stack." << endl; | |||||
1214 | ||||||
1215 | // The first EVIO event should be returned via "buff". | |||||
1216 | buff = buffs.empty() ? NULL__null:buffs[0]; | |||||
1217 | ||||||
1218 | // Additional EVIO events need to be placed in | |||||
1219 | // the "stored_events" deque so they can be | |||||
1220 | // used in subsequent calls to GetEvent() | |||||
1221 | pthread_mutex_lock(&stored_events_mutex); | |||||
1222 | for(uint32_t i=1; i<buffs.size(); i++){ | |||||
1223 | ObjList *objs = new ObjList(); | |||||
1224 | objs->eviobuff = buffs[i]; | |||||
1225 | objs->eviobuff_size = BUFFER_SIZE; | |||||
1226 | objs->run_number = FindRunNumber(buffs[i]); | |||||
1227 | objs->event_number = FindEventNumber(buffs[i]); | |||||
1228 | stored_events.push(objs); | |||||
1229 | } | |||||
1230 | pthread_mutex_unlock(&stored_events_mutex); | |||||
1231 | ||||||
1232 | #else // HAVE_ET | |||||
1233 | ||||||
1234 | japp->Quit(); | |||||
1235 | evioout << "Attempting to read from ET system using binary that" << endl; | |||||
1236 | evioout << "does not have ET support built in! Try recompiling" << endl; | |||||
1237 | evioout << "programs/Utilities/plugins/DAQ with ETROOT defined" << endl; | |||||
1238 | evioout << "and pointing to an ET installation." << endl; | |||||
1239 | ||||||
1240 | #endif //HAVE_ET | |||||
1241 | ||||||
1242 | } | |||||
1243 | } catch (evioException &e) { | |||||
1244 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<1244<<" "<<e.what()<<endl; | |||||
1245 | if(e.type == S_EVFILE_TRUNC0x40730001){ | |||||
1246 | jerr << "-- Event buffer truncated --" <<endl; | |||||
1247 | jerr << "---- this could be because the events are too large " << endl; | |||||
1248 | jerr << "---- for the buffer provided (" << BUFFER_SIZE << " bytes)" <<endl; | |||||
1249 | jerr << "---- you can try giving a larger buffer size by setting" << endl; | |||||
1250 | jerr << "---- the EVIO:BUFFER_SIZE configuration parameter by " << endl; | |||||
1251 | jerr << "---- adding this argument to your command line:" << endl; | |||||
1252 | jerr << "---- -PEVIO:BUFFER_SIZE=X (where X is in bytes)" << endl; | |||||
1253 | } | |||||
1254 | } | |||||
1255 | ||||||
1256 | if(VERBOSE>2) evioout << " Leaving ReadEVIOEvent()" << endl; | |||||
1257 | ||||||
1258 | return NOERROR; | |||||
1259 | } | |||||
1260 | ||||||
1261 | //---------------- | |||||
1262 | // GetObjects | |||||
1263 | //---------------- | |||||
1264 | jerror_t JEventSource_EVIO::GetObjects(JEvent &event, JFactory_base *factory) | |||||
1265 | { | |||||
1266 | if(VERBOSE>2) evioout << " GetObjects() called for &event = " << hex << &event << dec << endl; | |||||
1267 | ||||||
1268 | // This will get called when the first object of the event is | |||||
1269 | // requested (regardless of the type of object). Instead of | |||||
1270 | // pulling out objects only of the type requested, we instead | |||||
1271 | // take the data for all objects and copy them into the respective | |||||
1272 | // factories. Subsequent requests for objects for this same | |||||
1273 | // event will get them from the factories. Thus, this should | |||||
1274 | // only get called once per event. | |||||
1275 | // O.K. that is not actually true. If objects of a type we don't | |||||
1276 | // supply are requested, then the corresponding factory's evnt_called | |||||
1277 | // flag will not have been set and it will come here first to see | |||||
1278 | // if the source can supply those objects. In those cases, we should | |||||
1279 | // just return OBJECT_NOT_AVAILABLE so it can revert to the factory | |||||
1280 | // algorithm. We use the "own_objects" flag here to test if we have | |||||
1281 | // already copied the low-level objects to the factories and so | |||||
1282 | // should return right away. | |||||
1283 | ObjList *objs_ptr = (ObjList*)event.GetRef(); | |||||
1284 | if(!objs_ptr)return RESOURCE_UNAVAILABLE; | |||||
1285 | if(!objs_ptr->own_objects) return OBJECT_NOT_AVAILABLE; // if objects were already copied ... | |||||
1286 | ||||||
1287 | // If any translation tables exist, we will use them at the end of this | |||||
1288 | // method. However, the TTab plugin has an option to specify parsing of | |||||
1289 | // only certain detector systems. It does this by copying values into | |||||
1290 | // this JEventSource_EVIO object via the AddROCIDtoParseList method | |||||
1291 | // while in the brun method. The brun method won't get called until | |||||
1292 | // we ask for the DTranslationTable objects, thus, we must ask for them | |||||
1293 | // here, prior to calling ParseEvents. | |||||
1294 | // Note that we have to use the GetFromFactory() method here since | |||||
1295 | // if we just use Get() or GetSingle(), it will call us (the event | |||||
1296 | // source) again in an infinite loop! | |||||
1297 | // Also note that we use static_cast here instead of dynamic_cast | |||||
1298 | // since the latter requires that the type_info structure for | |||||
1299 | // the DTranslationTable_factory be present. It is not in this | |||||
1300 | // plugin (it is in the TTab plugin). Thus, with dynamic_cast there | |||||
1301 | // is an unresolved symbol error if the TTab plugin is not also | |||||
1302 | // present. (Make sense?) | |||||
1303 | vector<const DTranslationTable*> translationTables; | |||||
1304 | JEventLoop *loop = event.GetJEventLoop(); | |||||
1305 | DTranslationTable_factory *ttfac = static_cast<DTranslationTable_factory*>(loop->GetFactory("DTranslationTable")); | |||||
1306 | if(ttfac) ttfac->Get(translationTables); | |||||
1307 | ||||||
1308 | // We use a deferred parsing scheme for efficiency. If the event | |||||
1309 | // is not flagged as having already been parsed, then parse it | |||||
1310 | // now, creating objects for one or more events. The first event's | |||||
1311 | // parameters will be copied into our ObjList object and any additional | |||||
1312 | // ones stored in the stored_events queue. | |||||
1313 | if(!objs_ptr->eviobuff_parsed) ParseEvents(objs_ptr); | |||||
1314 | ||||||
1315 | // Get name of class which is actually being requested by caller | |||||
1316 | string dataClassName = (factory==NULL__null ? "N/A":factory->GetDataClassName()); | |||||
1317 | ||||||
1318 | // Make list of data(hit) types we have. Keep list of | |||||
1319 | // pointers to hit objects of each type | |||||
1320 | map<string, vector<JObject*> > hit_objs_by_type; | |||||
1321 | vector<DDAQAddress*> &hit_objs = objs_ptr->hit_objs; | |||||
1322 | for(unsigned int i=0; i<hit_objs.size(); i++){ | |||||
1323 | JObject *hit_obj = hit_objs[i]; | |||||
1324 | hit_objs_by_type[hit_obj->className()].push_back(hit_obj); | |||||
1325 | } | |||||
1326 | ||||||
1327 | // Make list of config objects of each type | |||||
1328 | map<string, vector<JObject*> > config_objs_by_type; | |||||
1329 | vector<DDAQConfig*> &config_objs = objs_ptr->config_objs; | |||||
1330 | for(unsigned int i=0; i<config_objs.size(); i++){ | |||||
1331 | JObject *config_obj = config_objs[i]; | |||||
1332 | config_objs_by_type[config_obj->className()].push_back(config_obj); | |||||
1333 | } | |||||
1334 | ||||||
1335 | // Make list of misc objects of each type | |||||
1336 | map<string, vector<JObject*> > misc_objs_by_type; | |||||
1337 | vector<JObject*> &misc_objs = objs_ptr->misc_objs; | |||||
1338 | for(unsigned int i=0; i<misc_objs.size(); i++){ | |||||
1339 | JObject *jobj = misc_objs[i]; | |||||
1340 | misc_objs_by_type[jobj->className()].push_back(jobj); | |||||
1341 | } | |||||
1342 | ||||||
1343 | // Associate any DDAQConfig objects with hit objects to which they should apply. | |||||
1344 | // If the objects are emulated, we will add this association later. | |||||
1345 | for(unsigned int j=0; j<config_objs.size(); j++){ | |||||
1346 | DDAQConfig *config = config_objs[j]; | |||||
1347 | for(unsigned int i=0; i<hit_objs.size(); i++){ | |||||
1348 | DDAQAddress *hit = hit_objs[i]; | |||||
1349 | if(hit->rocid != config->rocid) continue; | |||||
1350 | if( (1<<hit->slot) & config->slot_mask){ | |||||
1351 | hit->AddAssociatedObject(config); | |||||
1352 | } | |||||
1353 | } | |||||
1354 | } | |||||
1355 | ||||||
1356 | // Copy pointers to BOR objects | |||||
1357 | CopyBOR(loop, hit_objs_by_type); | |||||
1358 | ||||||
1359 | // In order for the janadot plugin to properly display the callgraph, we need to | |||||
1360 | // make entries for each of the object types that we generated from data in the file. | |||||
1361 | // Actually, we need to do it for all of the data objects we supply, but if any objects | |||||
1362 | // are emulated (e.g. Df250PulseIntegral) they need to be added differently so the correct | |||||
1363 | // dependence is shown. The first step is to add entries for all of the hit objects we | |||||
1364 | // actually did find in the file. Do that here. | |||||
1365 | map<string, vector<JObject*> >::iterator hoiter; | |||||
1366 | for(hoiter=hit_objs_by_type.begin(); hoiter!=hit_objs_by_type.end(); hoiter++){ | |||||
1367 | AddSourceObjectsToCallStack(loop, hoiter->first); | |||||
1368 | } | |||||
1369 | ||||||
1370 | // Get references to various objects | |||||
1371 | vector<JObject*> &f250_wrd_objs = hit_objs_by_type["Df250WindowRawData"]; | |||||
1372 | vector<JObject*> &f250_pt_objs = hit_objs_by_type["Df250PulseTime"]; | |||||
1373 | vector<JObject*> &f250_pp_objs = hit_objs_by_type["Df250PulsePedestal"]; | |||||
1374 | vector<JObject*> &f250_pi_objs = hit_objs_by_type["Df250PulseIntegral"]; | |||||
1375 | ||||||
1376 | vector<JObject*> &f125_wrd_objs = hit_objs_by_type["Df125WindowRawData"]; | |||||
1377 | vector<JObject*> &f125_pt_objs = hit_objs_by_type["Df125PulseTime"]; | |||||
1378 | vector<JObject*> &f125_pp_objs = hit_objs_by_type["Df125PulsePedestal"]; | |||||
1379 | vector<JObject*> &f125_pi_objs = hit_objs_by_type["Df125PulseIntegral"]; | |||||
1380 | vector<JObject*> &f125_cp_objs = hit_objs_by_type["Df125CDCPulse"]; | |||||
1381 | vector<JObject*> &f125_fp_objs = hit_objs_by_type["Df125FDCPulse"]; | |||||
1382 | ||||||
1383 | // Firmware Emulation | |||||
1384 | ||||||
1385 | if( F250_EMULATION_MODE != kEmulationNone ){ | |||||
1386 | EmulateDf250Firmware(event, f250_wrd_objs, f250_pt_objs, f250_pp_objs, f250_pi_objs); | |||||
1387 | } | |||||
1388 | // Repeat for f125 | |||||
1389 | if( F125_EMULATION_MODE != kEmulationNone ){ | |||||
1390 | EmulateDf125Firmware(event, f125_wrd_objs, f125_cp_objs, f125_fp_objs); | |||||
1391 | } | |||||
1392 | ||||||
1393 | // Make PulseTime, PulsePedstal, and PulseIntegral objects associated objects of one another | |||||
1394 | vector<Df250PulseIntegral*> f250_ppi_objs; | |||||
1395 | vector<Df250PulseTime*> f250_ppt_objs; | |||||
1396 | vector<Df250PulsePedestal*> f250_ppp_objs; | |||||
1397 | CopyContainerElementsWithCast(f250_pi_objs, f250_ppi_objs); | |||||
1398 | CopyContainerElementsWithCast(f250_pt_objs, f250_ppt_objs); | |||||
1399 | CopyContainerElementsWithCast(f250_pp_objs, f250_ppp_objs); | |||||
1400 | LinkAssociationsWithPulseNumber(f250_ppt_objs, f250_ppi_objs); | |||||
1401 | LinkAssociationsWithPulseNumber(f250_ppp_objs, f250_ppi_objs); | |||||
1402 | LinkAssociationsWithPulseNumber(f250_ppp_objs, f250_ppt_objs); | |||||
1403 | ||||||
1404 | vector<Df125WindowRawData*> f125_pwrd_objs; | |||||
1405 | vector<Df125PulseIntegral*> f125_ppi_objs; | |||||
1406 | vector<Df125PulseTime*> f125_ppt_objs; | |||||
1407 | vector<Df125PulsePedestal*> f125_ppp_objs; | |||||
1408 | vector<Df125CDCPulse*> f125_pcp_objs; | |||||
1409 | vector<Df125FDCPulse*> f125_pfp_objs; | |||||
1410 | CopyContainerElementsWithCast(f125_wrd_objs, f125_pwrd_objs); | |||||
1411 | CopyContainerElementsWithCast(f125_pi_objs, f125_ppi_objs); | |||||
1412 | CopyContainerElementsWithCast(f125_pt_objs, f125_ppt_objs); | |||||
1413 | CopyContainerElementsWithCast(f125_pp_objs, f125_ppp_objs); | |||||
1414 | CopyContainerElementsWithCast(f125_cp_objs, f125_pcp_objs); | |||||
1415 | CopyContainerElementsWithCast(f125_fp_objs, f125_pfp_objs); | |||||
1416 | LinkAssociationsWithPulseNumber(f125_ppt_objs, f125_ppi_objs); | |||||
1417 | LinkAssociationsWithPulseNumber(f125_ppp_objs, f125_ppi_objs); | |||||
1418 | LinkAssociationsWithPulseNumber(f125_ppp_objs, f125_ppt_objs); | |||||
1419 | LinkAssociations(f125_pcp_objs, f125_pwrd_objs); | |||||
1420 | LinkAssociations(f125_pfp_objs, f125_pwrd_objs); | |||||
1421 | ||||||
1422 | // Add data objects to call stack for the classes we can provide, but for which | |||||
1423 | // there are no objects for this event. Again, this is so janadot will display things | |||||
1424 | // properly. | |||||
1425 | set<string>::iterator siter; | |||||
1426 | for(siter=event_source_data_types.begin(); siter!=event_source_data_types.end(); siter++){ | |||||
1427 | if(hit_objs_by_type.find(*siter) == hit_objs_by_type.end()){ | |||||
1428 | AddSourceObjectsToCallStack(loop, *siter); | |||||
1429 | } | |||||
1430 | } | |||||
1431 | ||||||
1432 | // The f125 firmware used for the 2014 and Spring 2015 commissioning | |||||
1433 | // data was hardwired to report pedestals that were an average of | |||||
1434 | // 4 samples. Since only the average was reported, the number of | |||||
1435 | // samples used for this data was always "1". For the firmware | |||||
1436 | // implemented in late 2015, configuration parameters were introduced | |||||
1437 | // to allow a different number of samples to be used for the pedestal | |||||
1438 | // and a different divisor as well. Here, we need to replace the | |||||
1439 | // nsamples field of the PulsePedestal objects (which should be set to | |||||
1440 | // a default value of "1") with values determined by the config. | |||||
1441 | // parameters. We use the value NPED which should be calculated in | |||||
1442 | // the coda_config code on the ROCs when the data was taken. | |||||
1443 | vector<JObject*> &vpp125 = hit_objs_by_type["Df125PulsePedestal"]; | |||||
1444 | for(unsigned int i=0; i<vpp125.size(); i++){ | |||||
1445 | Df125PulsePedestal *pp = (Df125PulsePedestal*)vpp125[i]; | |||||
1446 | if(!pp->emulated){ | |||||
1447 | const Df125Config*conf = NULL__null; | |||||
1448 | pp->GetSingle(conf); | |||||
1449 | if(conf!=NULL__null){ | |||||
1450 | if(conf->NPED != 0xFFFF){ | |||||
1451 | pp->nsamples = conf->NPED; | |||||
1452 | } | |||||
1453 | } | |||||
1454 | } | |||||
1455 | } | |||||
1456 | ||||||
1457 | // Initially, the F250, F125 firmware does not include the | |||||
1458 | // pedestal measurement in the pulse integral data | |||||
1459 | // (it is an add-on Pulse Pedestal word) We want the | |||||
1460 | // pedestal field of the Df250PulseIntegral objects | |||||
1461 | // to contain the measured pedestals in both cases. | |||||
1462 | // Check all Df250PulseIntegral objects for an associated | |||||
1463 | // Df250PulsePedestal object. If it has one, copy the | |||||
1464 | // pedestal from it into the Df250PulseIntegral. | |||||
1465 | vector<JObject*> &vpi250 = hit_objs_by_type["Df250PulseIntegral"]; | |||||
1466 | for(unsigned int i=0; i<vpi250.size(); i++){ | |||||
1467 | ||||||
1468 | Df250PulseIntegral *pi = (Df250PulseIntegral*)vpi250[i]; | |||||
1469 | const Df250Config*conf = NULL__null; | |||||
1470 | const Df250BORConfig*BORconf = NULL__null; | |||||
1471 | const Df250PulsePedestal*pp = NULL__null; | |||||
1472 | pi->GetSingle(conf); | |||||
1473 | pi->GetSingle(BORconf); | |||||
1474 | pi->GetSingle(pp); | |||||
1475 | ||||||
1476 | // If a Df250PulsePedestal object is associated with this | |||||
1477 | // then copy its pedestal into the pedestal member of this | |||||
1478 | // pulse integral object. Furthermore, if the pedestal is | |||||
1479 | // *not* emulated and we have a configuration parameter from | |||||
1480 | // the datastream for the number of samples the pedestal | |||||
1481 | // represents, then copy this into the nsamples_pedestal. | |||||
1482 | if(pp){ | |||||
1483 | pi->pedestal = pp->pedestal; | |||||
1484 | if(!pp->emulated){ | |||||
1485 | if(conf!=NULL__null){ | |||||
1486 | if(conf->NPED != 0xFFFF){ | |||||
1487 | pi->nsamples_pedestal = conf->NPED; | |||||
1488 | } | |||||
1489 | } | |||||
1490 | } | |||||
1491 | } | |||||
1492 | ||||||
1493 | // If this pulse integral is *not* emulated AND there is | |||||
1494 | // a configuration object from the data stream associated, | |||||
1495 | // then copy the number of samples for the integral from it. | |||||
1496 | if(!pi->emulated){ | |||||
1497 | if (BORconf!=NULL__null){ | |||||
1498 | uint16_t NSB = BORconf->adc_nsb & 0x7F; | |||||
1499 | uint16_t NSA = BORconf->adc_nsa & 0x7F; | |||||
1500 | pi->nsamples_integral = NSB + NSA; | |||||
1501 | } | |||||
1502 | else if(conf){ | |||||
1503 | pi->nsamples_integral = conf->NSA_NSB; | |||||
1504 | } | |||||
1505 | } | |||||
1506 | } | |||||
1507 | vector<JObject*> &vpi125 = hit_objs_by_type["Df125PulseIntegral"]; | |||||
1508 | for(unsigned int i=0; i<vpi125.size(); i++){ | |||||
1509 | ||||||
1510 | Df125PulseIntegral *pi = (Df125PulseIntegral*)vpi125[i]; | |||||
1511 | const Df125Config*conf = NULL__null; | |||||
1512 | const Df125PulsePedestal*pp = NULL__null; | |||||
1513 | pi->GetSingle(conf); | |||||
1514 | pi->GetSingle(pp); | |||||
1515 | ||||||
1516 | // If a Df125PulsePedestal object is associated with this | |||||
1517 | // then copy its pedestal into the pedestal member of this | |||||
1518 | // pulse integral object. Furthermore, if the pedestal is | |||||
1519 | // *not* emulated then copy the number of pedestal samples. | |||||
1520 | // (n.b. the value of nsamples should have been set based | |||||
1521 | // on the configuration parameter in a separate loop over | |||||
1522 | // Df125PulsePedestal objects above.) | |||||
1523 | if(pp){ | |||||
1524 | pi->pedestal = pp->pedestal; | |||||
1525 | if(!pp->emulated) pi->nsamples_pedestal = pp->nsamples; | |||||
1526 | } | |||||
1527 | ||||||
1528 | // If this pulse integral is *not* emulated AND there is | |||||
1529 | // a configuration object from the data stream associated, | |||||
1530 | // then copy the number of samples for the integral from it. | |||||
1531 | if(!pi->emulated){ | |||||
1532 | if(conf){ | |||||
1533 | pi->nsamples_integral = conf->NSA_NSB; | |||||
1534 | } | |||||
1535 | } | |||||
1536 | } | |||||
1537 | vector<JObject*> &vcdcp125 = hit_objs_by_type["Df125CDCPulse"]; | |||||
1538 | for(unsigned int i=0; i<vcdcp125.size(); i++){ | |||||
1539 | ||||||
1540 | Df125CDCPulse *cdcp = (Df125CDCPulse*)vcdcp125[i]; | |||||
1541 | const Df125Config*conf = NULL__null; | |||||
1542 | cdcp->GetSingle(conf); | |||||
1543 | ||||||
1544 | // If this CDCpulse is *not* emulated AND there is | |||||
1545 | // a configuration object from the data stream associated, | |||||
1546 | // then copy the number of samples for the integral from it. | |||||
1547 | if(!cdcp->emulated){ | |||||
1548 | if(conf){ | |||||
1549 | //cdcp->nsamples_integral = conf->NSA_NSB; | |||||
1550 | int TC = (int)cdcp->le_time/10+1; | |||||
1551 | //int PG = conf->PG; does not yet work | |||||
1552 | int PG = 4; | |||||
1553 | int END = ( (TC-PG+conf->IE) > (conf->NW - 20) ) ? (conf->NW - 20) : (TC-PG + conf->IE) ; | |||||
1554 | int nsamp = END - (TC-PG); | |||||
1555 | if (nsamp>0){ | |||||
1556 | cdcp->nsamples_integral = nsamp; | |||||
1557 | } else { | |||||
1558 | cdcp->nsamples_integral = 1; | |||||
1559 | } | |||||
1560 | } | |||||
1561 | } | |||||
1562 | } | |||||
1563 | ||||||
1564 | vector<JObject*> &vfdcp125 = hit_objs_by_type["Df125FDCPulse"]; | |||||
1565 | for(unsigned int i=0; i<vfdcp125.size(); i++){ | |||||
1566 | ||||||
1567 | Df125FDCPulse *fdcp = (Df125FDCPulse*)vfdcp125[i]; | |||||
1568 | const Df125Config*conf = NULL__null; | |||||
1569 | fdcp->GetSingle(conf); | |||||
1570 | ||||||
1571 | // If this FDCpulse is *not* emulated AND there is | |||||
1572 | // a configuration object from the data stream associated, | |||||
1573 | // then copy the number of samples for the integral from it. | |||||
1574 | if(!fdcp->emulated){ | |||||
1575 | if(conf){ | |||||
1576 | //fdcp->nsamples_integral = conf->NSA_NSB; | |||||
1577 | int TC = (int)fdcp->le_time/10+1; | |||||
1578 | //int PG = conf->PG; does not yet work | |||||
1579 | int PG = 4; | |||||
1580 | int END = ( (TC-PG+conf->IE) > (conf->NW - 20) ) ? (conf->NW - 20) : (TC-PG + conf->IE) ; | |||||
1581 | int nsamp = END - (TC-PG); | |||||
1582 | if (nsamp>0){ | |||||
1583 | fdcp->nsamples_integral = nsamp; | |||||
1584 | } else { | |||||
1585 | fdcp->nsamples_integral = 1; | |||||
1586 | } | |||||
1587 | } | |||||
1588 | } | |||||
1589 | } | |||||
1590 | ||||||
1591 | // Loop over types of config objects, copying to appropriate factory | |||||
1592 | map<string, vector<JObject*> >::iterator config_iter = config_objs_by_type.begin(); | |||||
1593 | for(; config_iter!=config_objs_by_type.end(); config_iter++){ | |||||
1594 | JFactory_base *fac = loop->GetFactory(config_iter->first, "", false); // false= don't allow default tag replacement | |||||
1595 | if(fac) fac->CopyTo(config_iter->second); | |||||
1596 | } | |||||
1597 | ||||||
1598 | // Loop over types of hit objects, copying to appropriate factory | |||||
1599 | map<string, vector<JObject*> >::iterator iter = hit_objs_by_type.begin(); | |||||
1600 | for(; iter!=hit_objs_by_type.end(); iter++){ | |||||
1601 | JFactory_base *fac = loop->GetFactory(iter->first, "", false); // false= don't allow default tag replacement | |||||
1602 | fac->CopyTo(iter->second); | |||||
1603 | } | |||||
1604 | ||||||
1605 | // Loop over types of misc objects, copying to appropriate factory | |||||
1606 | map<string, vector<JObject*> >::iterator misc_iter = misc_objs_by_type.begin(); | |||||
1607 | for(; misc_iter!=misc_objs_by_type.end(); misc_iter++){ | |||||
1608 | JFactory_base *fac = loop->GetFactory(misc_iter->first, "", false); // false= don't allow default tag replacement | |||||
1609 | fac->CopyTo(misc_iter->second); | |||||
1610 | } | |||||
1611 | objs_ptr->own_objects = false; | |||||
1612 | ||||||
1613 | // Copy pointers to BOR objects | |||||
1614 | //CopyBOR(loop, hit_objs_by_type); | |||||
1615 | ||||||
1616 | // Returning OBJECT_NOT_AVAILABLE tells JANA that this source cannot | |||||
1617 | // provide the type of object requested and it should try and generate | |||||
1618 | // it via a factory algorithm. Returning NOERROR on the other hand | |||||
1619 | // tells JANA that we can provide this type of object and any that | |||||
1620 | // are present have already been copied into the appropriate factory. | |||||
1621 | jerror_t err = OBJECT_NOT_AVAILABLE; | |||||
1622 | if(strlen(factory->Tag()) == 0){ // We do not supply any tagged factory data here | |||||
1623 | if(event_source_data_types.find(dataClassName) != event_source_data_types.end()) err = NOERROR; | |||||
1624 | } | |||||
1625 | ||||||
1626 | // If it turns out there are no objects of one of the types we supply | |||||
1627 | // then the CopyTo method for that factory never gets called and subsequent | |||||
1628 | // requests for that object type will end up calling this method again. | |||||
1629 | // (For the case when this is done from the ApplyTranslationTable call | |||||
1630 | // below, it results in an infinite loop!). To prevent this, we need to | |||||
1631 | // mark all factories of the data types we supply as having had their | |||||
1632 | // evnt method called. | |||||
1633 | set<string>::iterator dtiter = event_source_data_types.begin(); | |||||
1634 | for(; dtiter!=event_source_data_types.end(); dtiter++){ | |||||
1635 | JFactory_base *fac = loop->GetFactory(*dtiter); | |||||
1636 | if(fac) { | |||||
1637 | // The DAQ_WRD2PI plugin wants to generate some objects from | |||||
1638 | // the waveform data, overiding anything found in the file. | |||||
1639 | // It this case, the factory's use_factory flag is set and | |||||
1640 | // we should NOT mark the factory as having it's event method | |||||
1641 | // called. Furthermore, we should delete any objects in the | |||||
1642 | // factory. | |||||
1643 | // Now, another complication is that the only way to check | |||||
1644 | // the use_factory flag is to have a pointer to the JFactory | |||||
1645 | // not the JFactory_base. This means we have to check the data | |||||
1646 | // type of the factory and make the appropriate cast | |||||
1647 | string dataClassName = fac->GetDataClassName(); | |||||
1648 | int checkSourceFirst = 1; | |||||
1649 | if( dataClassName == "Df250Config") checkSourceFirst = ((JFactory<Df250Config >*)fac)->GetCheckSourceFirst(); | |||||
1650 | else if(dataClassName == "Df250PulseIntegral") checkSourceFirst = ((JFactory<Df250PulseIntegral >*)fac)->GetCheckSourceFirst(); | |||||
1651 | else if(dataClassName == "Df250StreamingRawData") checkSourceFirst = ((JFactory<Df250StreamingRawData>*)fac)->GetCheckSourceFirst(); | |||||
1652 | else if(dataClassName == "Df250WindowSum") checkSourceFirst = ((JFactory<Df250WindowSum >*)fac)->GetCheckSourceFirst(); | |||||
1653 | else if(dataClassName == "Df250PulseRawData") checkSourceFirst = ((JFactory<Df250PulseRawData >*)fac)->GetCheckSourceFirst(); | |||||
1654 | else if(dataClassName == "Df250TriggerTime") checkSourceFirst = ((JFactory<Df250TriggerTime >*)fac)->GetCheckSourceFirst(); | |||||
1655 | else if(dataClassName == "Df250PulseTime") checkSourceFirst = ((JFactory<Df250PulseTime >*)fac)->GetCheckSourceFirst(); | |||||
1656 | else if(dataClassName == "Df250PulsePedestal") checkSourceFirst = ((JFactory<Df250PulsePedestal >*)fac)->GetCheckSourceFirst(); | |||||
1657 | else if(dataClassName == "Df250WindowRawData") checkSourceFirst = ((JFactory<Df250WindowRawData >*)fac)->GetCheckSourceFirst(); | |||||
1658 | else if(dataClassName == "Df125Config") checkSourceFirst = ((JFactory<Df125Config >*)fac)->GetCheckSourceFirst(); | |||||
1659 | else if(dataClassName == "Df125PulseIntegral") checkSourceFirst = ((JFactory<Df125PulseIntegral >*)fac)->GetCheckSourceFirst(); | |||||
1660 | else if(dataClassName == "Df125TriggerTime") checkSourceFirst = ((JFactory<Df125TriggerTime >*)fac)->GetCheckSourceFirst(); | |||||
1661 | else if(dataClassName == "Df125PulseTime") checkSourceFirst = ((JFactory<Df125PulseTime >*)fac)->GetCheckSourceFirst(); | |||||
1662 | else if(dataClassName == "Df125PulsePedestal") checkSourceFirst = ((JFactory<Df125PulsePedestal >*)fac)->GetCheckSourceFirst(); | |||||
1663 | else if(dataClassName == "Df125WindowRawData") checkSourceFirst = ((JFactory<Df125WindowRawData >*)fac)->GetCheckSourceFirst(); | |||||
1664 | else if(dataClassName == "Df125CDCPulse") checkSourceFirst = ((JFactory<Df125CDCPulse >*)fac)->GetCheckSourceFirst(); | |||||
1665 | else if(dataClassName == "Df125FDCPulse") checkSourceFirst = ((JFactory<Df125FDCPulse >*)fac)->GetCheckSourceFirst(); | |||||
1666 | else if(dataClassName == "DF1TDCConfig") checkSourceFirst = ((JFactory<DF1TDCConfig >*)fac)->GetCheckSourceFirst(); | |||||
1667 | else if(dataClassName == "DF1TDCHit") checkSourceFirst = ((JFactory<DF1TDCHit >*)fac)->GetCheckSourceFirst(); | |||||
1668 | else if(dataClassName == "DF1TDCTriggerTime") checkSourceFirst = ((JFactory<DF1TDCTriggerTime >*)fac)->GetCheckSourceFirst(); | |||||
1669 | else if(dataClassName == "DCAEN1290TDCConfig") checkSourceFirst = ((JFactory<DCAEN1290TDCConfig >*)fac)->GetCheckSourceFirst(); | |||||
1670 | else if(dataClassName == "DCAEN1290TDCHit") checkSourceFirst = ((JFactory<DCAEN1290TDCHit >*)fac)->GetCheckSourceFirst(); | |||||
1671 | else if(dataClassName == "DCODAEventInfo") checkSourceFirst = ((JFactory<DCODAEventInfo >*)fac)->GetCheckSourceFirst(); | |||||
1672 | else if(dataClassName == "DCODAROCInfo") checkSourceFirst = ((JFactory<DCODAROCInfo >*)fac)->GetCheckSourceFirst(); | |||||
1673 | else if(dataClassName == "DTSscalers") checkSourceFirst = ((JFactory<DTSscalers >*)fac)->GetCheckSourceFirst(); | |||||
1674 | else if(dataClassName == "Df250BORConfig") checkSourceFirst = ((JFactory<Df250BORConfig >*)fac)->GetCheckSourceFirst(); | |||||
1675 | else if(dataClassName == "Df125BORConfig") checkSourceFirst = ((JFactory<Df125BORConfig >*)fac)->GetCheckSourceFirst(); | |||||
1676 | else if(dataClassName == "DF1TDCBORConfig") checkSourceFirst = ((JFactory<DF1TDCBORConfig >*)fac)->GetCheckSourceFirst(); | |||||
1677 | else if(dataClassName == "DCAEN1290TDCBORConfig") checkSourceFirst = ((JFactory<DCAEN1290TDCBORConfig>*)fac)->GetCheckSourceFirst(); | |||||
1678 | ||||||
1679 | if(checkSourceFirst) { | |||||
1680 | fac->Set_evnt_called(); | |||||
1681 | }else{ | |||||
1682 | // Factory wants to generate these so delete any read | |||||
1683 | // from source. | |||||
1684 | fac->Reset(); | |||||
1685 | } | |||||
1686 | } | |||||
1687 | } | |||||
1688 | ||||||
1689 | // If a translation table object is available, use it to create | |||||
1690 | // detector hits from the low-level DAQ objects we just created. | |||||
1691 | for(unsigned int i=0; i<translationTables.size(); i++){ | |||||
1692 | translationTables[i]->ApplyTranslationTable(loop); | |||||
1693 | if(translationTables[i]->IsSuppliedType(dataClassName)) | |||||
1694 | if(strlen(factory->Tag()) == 0)err = NOERROR; // Don't allow tagged factories from Translation table | |||||
1695 | } | |||||
1696 | ||||||
1697 | if(VERBOSE>2) evioout << " Leaving GetObjects()" << endl; | |||||
1698 | ||||||
1699 | return err; | |||||
1700 | } | |||||
1701 | ||||||
1702 | //---------------- | |||||
1703 | // CopyBOR | |||||
1704 | //---------------- | |||||
1705 | void JEventSource_EVIO::CopyBOR(JEventLoop *loop, map<string, vector<JObject*> > &hit_objs_by_type) | |||||
1706 | { | |||||
1707 | /// Copy pointers to BOR (Beginning Of Run) objects into the | |||||
1708 | /// appropriate factories for this event. The objects are flagged | |||||
1709 | /// so that the factories won't delete them and the objects | |||||
1710 | /// may be reused on subsequent events. | |||||
1711 | ||||||
1712 | pthread_rwlock_rdlock(&BOR_lock); | |||||
1713 | ||||||
1714 | // Make list of BOR objects of each type | |||||
1715 | map<string, vector<JObject*> > bor_objs_by_type; | |||||
1716 | for(unsigned int i=0; i<BORobjs.size(); i++){ | |||||
1717 | JObject *jobj = BORobjs[i]; | |||||
1718 | bor_objs_by_type[jobj->className()].push_back(jobj); | |||||
1719 | } | |||||
1720 | ||||||
1721 | // Loop over types of BOR objects, copying to appropriate factory | |||||
1722 | map<string, vector<JObject*> >::iterator iter = bor_objs_by_type.begin(); | |||||
1723 | for(; iter!=bor_objs_by_type.end(); iter++){ | |||||
1724 | const string &bor_obj_name = iter->first; | |||||
1725 | vector<JObject*> &bors = iter->second; | |||||
1726 | JFactory_base *fac = loop->GetFactory(bor_obj_name, "", false); // false= don't allow default tag replacement | |||||
1727 | if(fac){ | |||||
1728 | fac->CopyTo(bors); | |||||
1729 | fac->SetFactoryFlag(JFactory_base::NOT_OBJECT_OWNER); | |||||
1730 | } | |||||
1731 | ||||||
1732 | // Associate with hit objects from this type of module | |||||
1733 | if(bor_obj_name == "Df250BORConfig"){ | |||||
1734 | LinkAssociationsModuleOnlyWithCast<Df250BORConfig,Df250PulseIntegral>(bors, hit_objs_by_type["Df250PulseIntegral"]); | |||||
1735 | LinkAssociationsModuleOnlyWithCast<Df250BORConfig,Df250PulsePedestal>(bors, hit_objs_by_type["Df250PulsePedestal"]); | |||||
1736 | LinkAssociationsModuleOnlyWithCast<Df250BORConfig,Df250PulseTime>(bors, hit_objs_by_type["Df250PulseTime"]); | |||||
1737 | LinkAssociationsModuleOnlyWithCast<Df250BORConfig,Df250WindowRawData>(bors, hit_objs_by_type["Df250WindowRawData"]); | |||||
1738 | } | |||||
1739 | if(bor_obj_name == "Df125BORConfig"){ | |||||
1740 | LinkAssociationsModuleOnlyWithCast<Df125BORConfig,Df125CDCPulse>(bors, hit_objs_by_type["Df125CDCPulse"]); | |||||
1741 | LinkAssociationsModuleOnlyWithCast<Df125BORConfig,Df125FDCPulse>(bors, hit_objs_by_type["Df125FDCPulse"]); | |||||
1742 | LinkAssociationsModuleOnlyWithCast<Df125BORConfig,Df125PulseIntegral>(bors, hit_objs_by_type["Df125PulseIntegral"]); | |||||
1743 | LinkAssociationsModuleOnlyWithCast<Df125BORConfig,Df125PulsePedestal>(bors, hit_objs_by_type["Df125PulsePedestal"]); | |||||
1744 | LinkAssociationsModuleOnlyWithCast<Df125BORConfig,Df125PulseTime>(bors, hit_objs_by_type["Df125PulseTime"]); | |||||
1745 | LinkAssociationsModuleOnlyWithCast<Df125BORConfig,Df125WindowRawData>(bors, hit_objs_by_type["Df125WindowRawData"]); | |||||
1746 | } | |||||
1747 | if(bor_obj_name == "DF1TDCBORConfig"){ | |||||
1748 | LinkAssociationsModuleOnlyWithCast<DF1TDCBORConfig,Df250PulseIntegral>(bors, hit_objs_by_type["DF1TDCHit"]); | |||||
1749 | } | |||||
1750 | if(bor_obj_name == "DCAEN1290TDCBORConfig"){ | |||||
1751 | LinkAssociationsModuleOnlyWithCast<DCAEN1290TDCBORConfig,Df250PulseIntegral>(bors, hit_objs_by_type["DCAEN1290TDCHit"]); | |||||
1752 | } | |||||
1753 | } | |||||
1754 | ||||||
1755 | pthread_rwlock_unlock(&BOR_lock); | |||||
1756 | } | |||||
1757 | ||||||
1758 | //---------------- | |||||
1759 | // AddSourceObjectsToCallStack | |||||
1760 | //---------------- | |||||
1761 | void JEventSource_EVIO::AddSourceObjectsToCallStack(JEventLoop *loop, string className) | |||||
1762 | { | |||||
1763 | /// This is used to give information to JANA regarding the origin of objects | |||||
1764 | /// that *should* come from the source. We add them in explicitly because | |||||
1765 | /// the file may not have any, but factories may ask for them. We want those | |||||
1766 | /// links to indicate that the "0" objects in the factory came from the source | |||||
1767 | /// so that janadot draws these objects correctly. | |||||
1768 | ||||||
1769 | JEventLoop::call_stack_t cs; | |||||
1770 | cs.caller_name = "<ignore>"; // tells janadot this object wasn't actually requested by anybody | |||||
1771 | cs.caller_tag = ""; | |||||
1772 | cs.callee_name = className; | |||||
1773 | cs.callee_tag = ""; | |||||
1774 | cs.start_time = 0.0; | |||||
1775 | cs.end_time = 0.0; | |||||
1776 | cs.data_source = JEventLoop::DATA_FROM_SOURCE; | |||||
1777 | loop->AddToCallStack(cs); | |||||
1778 | } | |||||
1779 | ||||||
1780 | //---------------- | |||||
1781 | // AddEmulatedObjectsToCallStack | |||||
1782 | //---------------- | |||||
1783 | void JEventSource_EVIO::AddEmulatedObjectsToCallStack(JEventLoop *loop, string caller, string callee) | |||||
1784 | { | |||||
1785 | /// This is used to give information to JANA regarding the relationship and | |||||
1786 | /// origin of some of these data objects. This is really just needed so that | |||||
1787 | /// the janadot program can be used to produce the correct callgraph. Because | |||||
1788 | /// of how this plugin works, JANA can't record the correct call stack (at | |||||
1789 | /// least not easily!) Therefore, we have to give it a little help here. | |||||
1790 | ||||||
1791 | JEventLoop::call_stack_t cs; | |||||
1792 | cs.caller_name = caller; | |||||
1793 | cs.callee_name = callee; | |||||
1794 | cs.data_source = JEventLoop::DATA_FROM_SOURCE; | |||||
1795 | loop->AddToCallStack(cs); | |||||
1796 | cs.callee_name = cs.caller_name; | |||||
1797 | cs.caller_name = "<ignore>"; | |||||
1798 | cs.data_source = JEventLoop::DATA_FROM_FACTORY; | |||||
1799 | loop->AddToCallStack(cs); | |||||
1800 | } | |||||
1801 | ||||||
1802 | //---------------- | |||||
1803 | // EmulateDf250Firmware | |||||
1804 | //---------------- | |||||
1805 | void JEventSource_EVIO::EmulateDf250Firmware(JEvent &event, vector<JObject*> &wrd_objs, vector<JObject*> &pt_objs, vector<JObject*> &pp_objs, vector<JObject*> &pi_objs) | |||||
1806 | { | |||||
1807 | // Cant emulate without the raw data | |||||
1808 | if(wrd_objs.size() == 0) return; | |||||
1809 | if(VERBOSE>3) evioout << " Entering EmulateDf250Firmware ..." <<endl; | |||||
1810 | ||||||
1811 | vector <const Df250EmulatorAlgorithm*> f250Emulator_const; | |||||
1812 | Df250EmulatorAlgorithm *f250Emulator = NULL__null; | |||||
1813 | JEventLoop *loop = event.GetJEventLoop(); | |||||
1814 | Df250EmulatorAlgorithm_factory *f250EmFac = static_cast<Df250EmulatorAlgorithm_factory*>(loop->GetFactory("Df250EmulatorAlgorithm")); | |||||
1815 | if (f250EmFac) { | |||||
1816 | f250EmFac->Get(f250Emulator_const); | |||||
1817 | // Drop const | |||||
1818 | if (f250Emulator_const.size() != 0) f250Emulator = const_cast<Df250EmulatorAlgorithm*>(f250Emulator_const[0]); | |||||
1819 | } | |||||
1820 | ||||||
1821 | if(VERBOSE>3) evioout << " Looping over raw data ..." <<endl; | |||||
1822 | // Loop over all window raw data objects | |||||
1823 | for(unsigned int i=0; i<wrd_objs.size(); i++){ | |||||
1824 | const Df250WindowRawData *f250WindowRawData = (Df250WindowRawData*)wrd_objs[i]; | |||||
1825 | Df250PulseTime *f250PulseTime = NULL__null; | |||||
1826 | Df250PulsePedestal *f250PulsePedestal = NULL__null; | |||||
1827 | Df250PulseIntegral *f250PulseIntegral = NULL__null; | |||||
1828 | ||||||
1829 | // When raw data exists, we will always do the emulation | |||||
1830 | // Grab the existing Pulse data | |||||
1831 | // This will grab the first pulse. This will need to be adapted later for multiple hits. | |||||
1832 | for(uint32_t j=0; j<pt_objs.size(); j++){ | |||||
1833 | Df250PulseTime *pt = (Df250PulseTime*)pt_objs[j]; | |||||
1834 | if(pt->rocid == f250WindowRawData->rocid){ | |||||
1835 | if(pt->slot == f250WindowRawData->slot){ | |||||
1836 | if(pt->channel == f250WindowRawData->channel){ | |||||
1837 | f250PulseTime = pt; | |||||
1838 | f250PulseTime->AddAssociatedObject(f250WindowRawData); | |||||
1839 | if(pt->emulated){ | |||||
1840 | jerr << "Emulating channel that already has emulated objects!" << endl; | |||||
1841 | jerr << "This likely means there is a bug in JEventSource_EVIO.cc" <<endl; | |||||
1842 | jerr << "PulseTime: rocid="<<pt->rocid<<" slot="<<pt->slot<<" channel="<<pt->channel<<endl; | |||||
1843 | jerr << "please report error to davidl@jlab.org" << endl; | |||||
1844 | exit(-1); | |||||
1845 | } | |||||
1846 | break; | |||||
1847 | } | |||||
1848 | } | |||||
1849 | } | |||||
1850 | } | |||||
1851 | ||||||
1852 | // Ditto for pulse pedestal objects | |||||
1853 | for(uint32_t j=0; j<pp_objs.size(); j++){ | |||||
1854 | Df250PulsePedestal *pp = (Df250PulsePedestal*)pp_objs[j]; | |||||
1855 | if(pp->rocid == f250WindowRawData->rocid){ | |||||
1856 | if(pp->slot == f250WindowRawData->slot){ | |||||
1857 | if(pp->channel == f250WindowRawData->channel){ | |||||
1858 | f250PulsePedestal = pp; | |||||
1859 | f250PulsePedestal->AddAssociatedObject(f250WindowRawData); | |||||
1860 | if(pp->emulated){ | |||||
1861 | jerr << "Emulating channel that already has emulated objects!" << endl; | |||||
1862 | jerr << "This likely means there is a bug in JEventSource_EVIO.cc" <<endl; | |||||
1863 | jerr << "PulsePedestal: rocid="<<pp->rocid<<" slot="<<pp->slot<<" channel="<<pp->channel<<endl; | |||||
1864 | jerr << "please report error to davidl@jlab.org" << endl; | |||||
1865 | exit(-1); | |||||
1866 | } | |||||
1867 | break; | |||||
1868 | } | |||||
1869 | } | |||||
1870 | } | |||||
1871 | } | |||||
1872 | ||||||
1873 | // Ditto for pulse integral objects | |||||
1874 | for(uint32_t j=0; j<pi_objs.size(); j++){ | |||||
1875 | Df250PulseIntegral *pi = (Df250PulseIntegral*)pi_objs[j]; | |||||
1876 | if(pi->rocid == f250WindowRawData->rocid){ | |||||
1877 | if(pi->slot == f250WindowRawData->slot){ | |||||
1878 | if(pi->channel == f250WindowRawData->channel){ | |||||
1879 | f250PulseIntegral = pi; | |||||
1880 | f250PulseIntegral->AddAssociatedObject(f250WindowRawData); | |||||
1881 | if(pi->emulated){ | |||||
1882 | jerr << "Emulating channel that already has emulated objects!" << endl; | |||||
1883 | jerr << "This likely means there is a bug in JEventSource_EVIO.cc" <<endl; | |||||
1884 | jerr << "PulseIntegral: rocid="<<pi->rocid<<" slot="<<pi->slot<<" channel="<<pi->channel<<endl; | |||||
1885 | jerr << "please report error to davidl@jlab.org" << endl; | |||||
1886 | exit(-1); | |||||
1887 | } | |||||
1888 | break; | |||||
1889 | } | |||||
1890 | } | |||||
1891 | } | |||||
1892 | } | |||||
1893 | ||||||
1894 | // create new Df250PulseTime object if one does not exist | |||||
1895 | if(f250PulseTime == NULL__null){ | |||||
1896 | f250PulseTime = new Df250PulseTime; | |||||
1897 | f250PulseTime->rocid =f250WindowRawData->rocid; | |||||
1898 | f250PulseTime->slot = f250WindowRawData->slot; | |||||
1899 | f250PulseTime->channel = f250WindowRawData->channel; | |||||
1900 | f250PulseTime->itrigger = f250WindowRawData->itrigger; | |||||
1901 | f250PulseTime->pulse_number = 0; | |||||
1902 | f250PulseTime->emulated = true; | |||||
1903 | f250PulseTime->AddAssociatedObject(f250WindowRawData); | |||||
1904 | pt_objs.push_back(f250PulseTime); | |||||
1905 | } | |||||
1906 | ||||||
1907 | // create new Df250PulsePedestal object if one does not exist | |||||
1908 | if(f250PulsePedestal == NULL__null){ | |||||
1909 | f250PulsePedestal = new Df250PulsePedestal; | |||||
1910 | f250PulsePedestal->rocid =f250WindowRawData->rocid; | |||||
1911 | f250PulsePedestal->slot = f250WindowRawData->slot; | |||||
1912 | f250PulsePedestal->channel = f250WindowRawData->channel; | |||||
1913 | f250PulsePedestal->itrigger = f250WindowRawData->itrigger; | |||||
1914 | f250PulsePedestal->pulse_number = 0; | |||||
1915 | f250PulsePedestal->emulated = true; | |||||
1916 | f250PulsePedestal->AddAssociatedObject(f250WindowRawData); | |||||
1917 | pp_objs.push_back(f250PulsePedestal); | |||||
1918 | } | |||||
1919 | ||||||
1920 | // create new Df250PulseIntegral object if one does not exist | |||||
1921 | if(f250PulseIntegral == NULL__null){ | |||||
1922 | f250PulseIntegral = new Df250PulseIntegral; | |||||
1923 | f250PulseIntegral->rocid =f250WindowRawData->rocid; | |||||
1924 | f250PulseIntegral->slot = f250WindowRawData->slot; | |||||
1925 | f250PulseIntegral->channel = f250WindowRawData->channel; | |||||
1926 | f250PulseIntegral->itrigger = f250WindowRawData->itrigger; | |||||
1927 | f250PulseIntegral->pulse_number = 0; | |||||
1928 | f250PulseIntegral->emulated = true; | |||||
1929 | f250PulseIntegral->AddAssociatedObject(f250WindowRawData); | |||||
1930 | pi_objs.push_back(f250PulseIntegral); | |||||
1931 | } | |||||
1932 | ||||||
1933 | // Flag all objects as emulated and their values will be replaced with emulated quantities | |||||
1934 | if (F250_EMULATION_MODE == kEmulationAlways){ | |||||
1935 | f250PulseTime->emulated = 1; | |||||
1936 | f250PulsePedestal->emulated = 1; | |||||
1937 | f250PulseIntegral->emulated = 1; | |||||
1938 | } | |||||
1939 | ||||||
1940 | // Emulate firmware | |||||
1941 | if(VERBOSE>3) evioout << " Calling EmulateFirmware ..." << endl; | |||||
1942 | f250Emulator->EmulateFirmware(f250WindowRawData, f250PulseTime, f250PulsePedestal, f250PulseIntegral); | |||||
1943 | } | |||||
1944 | ||||||
1945 | // PulseTime, PulsePedestal, PulseIntegral objects are associated to one another in GetObjects | |||||
1946 | if(VERBOSE>3) evioout << " Leaving EmulateDf250Firmware" <<endl; | |||||
1947 | } | |||||
1948 | ||||||
1949 | //---------------- | |||||
1950 | // EmulateDf125Firmware | |||||
1951 | //---------------- | |||||
1952 | void JEventSource_EVIO::EmulateDf125Firmware( JEvent &event, vector<JObject*> &wrd_objs, vector<JObject*> &cp_objs, vector<JObject*> &fp_objs) | |||||
1953 | { | |||||
1954 | /// This code implements an upsampling technique developed by Naomi Jarvis at | |||||
1955 | /// CMU. This was not implemented in the firmware for the 2014-2015 commissioning | |||||
1956 | /// run, but was implemented for later runs. | |||||
1957 | /// | |||||
1958 | /// Removed f250 style emulation of f125 firmware. Keep in mind if for some reason old | |||||
1959 | /// mode 8 data is processed, it will return the new style words with 1/10 | |||||
1960 | /// sample resolution. It is doubtful anyone will be using these in the future so nbd. 3/18/2016 MS | |||||
1961 | ||||||
1962 | if(wrd_objs.size() == 0) return; // Can't do anything without the raw data | |||||
1963 | if(VERBOSE>3) evioout << " Entering EmulateDf125Firmware ..." <<endl; | |||||
1964 | ||||||
1965 | vector <const Df125EmulatorAlgorithm*> f125Emulator_const; | |||||
1966 | Df125EmulatorAlgorithm *f125Emulator = NULL__null; | |||||
1967 | JEventLoop *loop = event.GetJEventLoop(); | |||||
1968 | Df125EmulatorAlgorithm_factory *f125EmFac = static_cast<Df125EmulatorAlgorithm_factory*>(loop->GetFactory("Df125EmulatorAlgorithm")); | |||||
1969 | if (f125EmFac) { | |||||
1970 | f125EmFac->Get(f125Emulator_const); | |||||
1971 | // Drop const | |||||
1972 | if (f125Emulator_const.size() != 0) f125Emulator = const_cast<Df125EmulatorAlgorithm*>(f125Emulator_const[0]); | |||||
1973 | } | |||||
1974 | ||||||
1975 | // Loop over all window raw data objects | |||||
1976 | for(unsigned int i=0; i<wrd_objs.size(); i++){ | |||||
1977 | const Df125WindowRawData *f125WindowRawData = (Df125WindowRawData*)wrd_objs[i]; | |||||
1978 | Df125CDCPulse *f125CDCPulse = NULL__null; | |||||
1979 | Df125FDCPulse *f125FDCPulse = NULL__null; | |||||
1980 | ||||||
1981 | //search for existing CDCPulse | |||||
1982 | for(uint32_t j=0; j<cp_objs.size(); j++){ | |||||
1983 | Df125CDCPulse *cp = (Df125CDCPulse*)cp_objs[j]; | |||||
1984 | if(cp->rocid == f125WindowRawData->rocid){ | |||||
1985 | if(cp->slot == f125WindowRawData->slot){ | |||||
1986 | if(cp->channel == f125WindowRawData->channel){ | |||||
1987 | f125CDCPulse = cp; | |||||
1988 | f125CDCPulse->AddAssociatedObject(f125WindowRawData); | |||||
1989 | break; | |||||
1990 | } | |||||
1991 | } | |||||
1992 | } | |||||
1993 | } | |||||
1994 | ||||||
1995 | // search for existing FDCPulse | |||||
1996 | for(uint32_t j=0; j<fp_objs.size(); j++){ | |||||
1997 | Df125FDCPulse *fp = (Df125FDCPulse*)fp_objs[j]; | |||||
1998 | if(fp->rocid == f125WindowRawData->rocid){ | |||||
1999 | if(fp->slot == f125WindowRawData->slot){ | |||||
2000 | if(fp->channel == f125WindowRawData->channel){ | |||||
2001 | f125FDCPulse = fp; | |||||
2002 | f125FDCPulse->AddAssociatedObject(f125WindowRawData); | |||||
2003 | break; | |||||
2004 | } | |||||
2005 | } | |||||
2006 | } | |||||
2007 | } | |||||
2008 | ||||||
2009 | // If the the pulse objects do not exist, create new ones to go with our raw data | |||||
2010 | // This should rarely happen since CDC_long and FDC_long have the raw data | |||||
2011 | // along with the calculated quantities in a pulse word. Pure raw mode would be the only time | |||||
2012 | // when this would not be the case. Since this is so infrequently used (if ever), | |||||
2013 | // the ROCID check for CDC/FDC determination is hard coded... | |||||
2014 | // ROCID CDC: 25-28 | |||||
2015 | // ROCID FDC Cathode: 52,53,55-62 | |||||
2016 | ||||||
2017 | if(f125CDCPulse == NULL__null && ( f125WindowRawData->rocid < 30 ) ){ | |||||
2018 | f125CDCPulse = new Df125CDCPulse; | |||||
2019 | f125CDCPulse->rocid = f125WindowRawData->rocid; | |||||
2020 | f125CDCPulse->slot = f125WindowRawData->slot; | |||||
2021 | f125CDCPulse->channel = f125WindowRawData->channel; | |||||
2022 | f125CDCPulse->emulated = true; | |||||
2023 | f125CDCPulse->AddAssociatedObject(f125WindowRawData); | |||||
2024 | cp_objs.push_back(f125CDCPulse); | |||||
2025 | } | |||||
2026 | ||||||
2027 | else if(f125FDCPulse == NULL__null && ( f125WindowRawData->rocid > 30 ) ){ | |||||
2028 | f125FDCPulse = new Df125FDCPulse; | |||||
2029 | f125FDCPulse->rocid = f125WindowRawData->rocid; | |||||
2030 | f125FDCPulse->slot = f125WindowRawData->slot; | |||||
2031 | f125FDCPulse->channel = f125WindowRawData->channel; | |||||
2032 | f125FDCPulse->emulated = true; | |||||
2033 | f125FDCPulse->AddAssociatedObject(f125WindowRawData); | |||||
2034 | cp_objs.push_back(f125FDCPulse); | |||||
2035 | } | |||||
2036 | ||||||
2037 | // Flag all objects as emulated and their values will be replaced with emulated quantities | |||||
2038 | if (F125_EMULATION_MODE == kEmulationAlways){ | |||||
2039 | if(f125CDCPulse!=NULL__null) f125CDCPulse->emulated = 1; | |||||
2040 | if(f125FDCPulse!=NULL__null) f125FDCPulse->emulated = 1; | |||||
2041 | } | |||||
2042 | ||||||
2043 | // Perform the emulation | |||||
2044 | f125Emulator->EmulateFirmware(f125WindowRawData, f125CDCPulse, f125FDCPulse); | |||||
2045 | } | |||||
2046 | ||||||
2047 | if(VERBOSE>3) evioout << " Leaving EmulateDf125Firmware" <<endl; | |||||
2048 | } | |||||
2049 | ||||||
2050 | //---------------- | |||||
2051 | // GetRunNumber | |||||
2052 | //---------------- | |||||
2053 | int32_t JEventSource_EVIO::GetRunNumber(evioDOMTree *evt) | |||||
2054 | { | |||||
2055 | // Note: This is currently not used. Preference is | |||||
2056 | // now given to the run number found in FindRunNumber | |||||
2057 | // which is called from GetEvent. This makes things | |||||
2058 | // a little simpler and ensures the run number originally | |||||
2059 | // presented to the processor/factory does not change. | |||||
2060 | // 2/15/2016 DL | |||||
2061 | ||||||
2062 | // This is called during event parsing to get the | |||||
2063 | // run number for the event. | |||||
2064 | // Look through event to try and extract the run number. | |||||
2065 | // We do this by looking for all uint64_t nodes. Then | |||||
2066 | // check for a parent with one of the magic values for | |||||
2067 | // the tag indicating it has run number information. | |||||
2068 | if(USER_RUN_NUMBER>0) return USER_RUN_NUMBER; | |||||
2069 | if(!evt) return last_run_number; | |||||
2070 | ||||||
2071 | evioDOMNodeListP bankList = evt->getNodeList(typeIs<uint64_t>()); | |||||
2072 | evioDOMNodeList::iterator iter = bankList->begin(); | |||||
2073 | const uint64_t *run_number_and_type = NULL__null; | |||||
2074 | for(; iter!=bankList->end(); iter++){ | |||||
2075 | evioDOMNodeP bankPtr = *iter; | |||||
2076 | evioDOMNodeP physics_event_built_trigger_bank = bankPtr->getParent(); | |||||
2077 | if(physics_event_built_trigger_bank == NULL__null) continue; | |||||
2078 | uint32_t tag = physics_event_built_trigger_bank->tag; | |||||
2079 | const vector<uint64_t> *vec; | |||||
2080 | switch(tag){ | |||||
2081 | case 0xFF22: | |||||
2082 | case 0xFF23: | |||||
2083 | case 0xFF26: | |||||
2084 | case 0xFF27: | |||||
2085 | vec = bankPtr->getVector<uint64_t>(); | |||||
2086 | if(!vec) continue; | |||||
2087 | if(vec->size()<1) continue; | |||||
2088 | run_number_and_type = &((*vec)[vec->size()-1]); | |||||
2089 | break; | |||||
2090 | } | |||||
2091 | if(run_number_and_type != NULL__null) break; | |||||
2092 | } | |||||
2093 | ||||||
2094 | if(run_number_and_type != NULL__null) last_run_number = (*run_number_and_type)>>32; | |||||
2095 | ||||||
2096 | return last_run_number; | |||||
2097 | } | |||||
2098 | ||||||
2099 | //---------------- | |||||
2100 | // FindRunNumber | |||||
2101 | //---------------- | |||||
2102 | int32_t JEventSource_EVIO::FindRunNumber(uint32_t *iptr) | |||||
2103 | { | |||||
2104 | /// This is called from GetEvent() to quickly look for the run number | |||||
2105 | /// at the time the event is read in so it can be passed into | |||||
2106 | /// JEvent. It is what will be used for accessing the CCDB. | |||||
2107 | /// from this event. If a bank containing the run number is found, | |||||
2108 | /// use it to provide the run number. Otherwise, return whatever run | |||||
2109 | /// number we were able to extract from the file name. | |||||
2110 | ||||||
2111 | if(VERBOSE>1) evioout << " .. Searching for run number ..." <<endl; | |||||
2112 | if(USER_RUN_NUMBER>0){ | |||||
2113 | if(VERBOSE>1) evioout << " returning user-supplied run number: " << USER_RUN_NUMBER << endl; | |||||
2114 | return last_run_number=USER_RUN_NUMBER; | |||||
2115 | } | |||||
2116 | ||||||
2117 | // Assume first word is number of words in bank | |||||
2118 | uint32_t *iend = &iptr[*iptr - 1]; | |||||
2119 | if(*iptr > 2048) iend = &iptr[2048]; | |||||
2120 | bool has_timestamps = false; | |||||
2121 | while(iptr<iend){ | |||||
2122 | iptr++; | |||||
2123 | ||||||
2124 | // EPICS event | |||||
2125 | if( (*iptr & 0xff000f) == 0x600001){ | |||||
2126 | if(VERBOSE>2) evioout << " Found EPICS header. Looking for HD:coda:daq:run_number ..." << endl; | |||||
2127 | const char *cptr = (const char*)&iptr[1]; | |||||
2128 | const char *cend = (const char*)iend; | |||||
2129 | const char *needle = "HD:coda:daq:run_number="; | |||||
2130 | while(cptr<cend){ | |||||
2131 | if(VERBOSE>4) evioout << " \""<<cptr<<"\"" << endl; | |||||
2132 | if(!strncmp(cptr, needle, strlen(needle))){ | |||||
2133 | if(VERBOSE>2) evioout << " Found it!" << endl; | |||||
2134 | return last_run_number = atoi(&cptr[strlen(needle)]); | |||||
2135 | } | |||||
2136 | cptr+=4; // should only start on 4-byte boundary! | |||||
2137 | } | |||||
2138 | } | |||||
2139 | ||||||
2140 | // BOR event | |||||
2141 | if( (*iptr & 0xffffffff) == 0x00700E01){ | |||||
2142 | // OK, this looks like a BOR event which does not include the | |||||
2143 | // run number. In this case, we have a couple of options: | |||||
2144 | // | |||||
2145 | // 1. If we are reading from a file then look further into | |||||
2146 | // the file to see if we can find another event with the | |||||
2147 | // run number in it. | |||||
2148 | // | |||||
2149 | // 2. Return the run number found from the filename. | |||||
2150 | // | |||||
2151 | if(source_type==kFileSource){ | |||||
2152 | int32_t run_number = EpicQuestForRunNumber(); | |||||
2153 | if(run_number != 0){ | |||||
2154 | if(VERBOSE>1) evioout << " Found run number " << run_number << " from Epic Quest." <<endl; | |||||
2155 | return last_run_number = run_number; | |||||
2156 | } | |||||
2157 | } | |||||
2158 | break; // return filename_run_number with warning message | |||||
2159 | } | |||||
2160 | ||||||
2161 | // PHYSICS event | |||||
2162 | switch((*iptr)>>16){ | |||||
2163 | case 0xFF10: | |||||
2164 | case 0xFF11: | |||||
2165 | case 0xFF20: | |||||
2166 | case 0xFF21: | |||||
2167 | case 0xFF24: | |||||
2168 | case 0xFF25: | |||||
2169 | case 0xFF30: | |||||
2170 | // These Trigger Bank Tag values have no run number info in them | |||||
2171 | if(VERBOSE>2) evioout << " ... Trigger bank tag (0x" << hex << ((*iptr)>>16) << dec << ") does not contain run number" <<endl; | |||||
2172 | if(!WARN_USER_RUN_FILENAME) { | |||||
2173 | jout << "WARNING: setting run number " << filename_run_number << " based on file name" << endl; | |||||
2174 | WARN_USER_RUN_FILENAME = true; | |||||
2175 | } | |||||
2176 | return last_run_number = filename_run_number; | |||||
2177 | case 0xFF23: | |||||
2178 | case 0xFF27: | |||||
2179 | has_timestamps = true; | |||||
2180 | case 0xFF22: | |||||
2181 | case 0xFF26: | |||||
2182 | if(VERBOSE>2) evioout << " ... Trigger bank tag (0x" << hex << ((*iptr)>>16) << dec << ") does contain run number" <<endl; | |||||
2183 | // Nrocs = (*iptr) & 0x0F; | |||||
2184 | break; | |||||
2185 | default: | |||||
2186 | continue; | |||||
2187 | } | |||||
2188 | iptr++; | |||||
2189 | if( ((*iptr)&0x00FF0000) != 0x000A0000) { iptr--; continue; } | |||||
2190 | uint32_t M = iptr[-3] & 0x000000FF; // Number of events from Physics Event header | |||||
2191 | if(VERBOSE>2) evioout << " ... Trigger bank " << (has_timestamps ? "does":"doesn't") << " have timestamps. Nevents in block M=" << M <<endl; | |||||
2192 | iptr++; | |||||
2193 | uint64_t *iptr64 = (uint64_t*)iptr; | |||||
2194 | ||||||
2195 | uint64_t event_num = *iptr64; | |||||
2196 | if(source_type==kETSource) event_num = ((*iptr64)>>32) | ((*iptr64)<<32); | |||||
2197 | if(VERBOSE>3) evioout << " .... Event num: " << event_num <<endl; | |||||
2198 | iptr64++; | |||||
2199 | if(has_timestamps) iptr64 = &iptr64[M]; // advance past timestamps | |||||
2200 | ||||||
2201 | // I'm not sure I fully understand this, but if we read from | |||||
2202 | // ET, then the run number is in the low 32 bits of *iptr64. | |||||
2203 | // If we are reading from a file, it is in the high 32 bits. | |||||
2204 | // No byte swapping is needed (it has already been done, though | |||||
2205 | // perhaps incorrectly). We handle this here by checking if | |||||
2206 | // this is an ET source or not. | |||||
2207 | uint64_t run64 = (*iptr64)>>32; | |||||
2208 | if(source_type==kETSource){ | |||||
2209 | run64 = (*iptr64)&0xffffffff; | |||||
2210 | } | |||||
2211 | int32_t run = (int32_t)run64; | |||||
2212 | if(VERBOSE>1) evioout << " .. Found run number: " << run <<endl; | |||||
2213 | ||||||
2214 | return last_run_number = run; | |||||
2215 | } | |||||
2216 | ||||||
2217 | // if we're not sure what else to do, try a more comprehensive search | |||||
2218 | if(source_type==kFileSource){ | |||||
2219 | int32_t run_number = EpicQuestForRunNumber(); | |||||
2220 | if(run_number != 0){ | |||||
2221 | if(VERBOSE>1) evioout << " Found run number " << run_number << " from Epic Quest." <<endl; | |||||
2222 | return last_run_number = run_number; | |||||
2223 | } | |||||
2224 | } | |||||
2225 | ||||||
2226 | if(!WARN_USER_RUN_FILENAME) { | |||||
2227 | jout << "WARNING: setting run number " << filename_run_number << " based on file name" << endl; | |||||
2228 | WARN_USER_RUN_FILENAME = true; | |||||
2229 | } | |||||
2230 | ||||||
2231 | return last_run_number = filename_run_number; | |||||
2232 | } | |||||
2233 | ||||||
2234 | //---------------- | |||||
2235 | // EpicQuestForRunNumber | |||||
2236 | //---------------- | |||||
2237 | int32_t JEventSource_EVIO::EpicQuestForRunNumber(void) | |||||
2238 | { | |||||
2239 | /// This is called when an event is encountered that does | |||||
2240 | /// not have a run number in it. (e.g. a BOR event encountered | |||||
2241 | /// in FindRunNumber() ). This is a last hope of finding the | |||||
2242 | /// run number in the file by looking for other events that | |||||
2243 | /// may contain it. Specifically, EPICS or PHYSICS events. | |||||
2244 | /// This only works if it is a file source so that it can open | |||||
2245 | /// the file and read in past the first event. | |||||
2246 | /// | |||||
2247 | /// Note that this is extremely inefficient so should not be | |||||
2248 | /// called very often. As a precaution, this will look to see | |||||
2249 | /// if last_run_number is not set to 0 first and will just | |||||
2250 | /// return it if it is. Only if it is not will the epic quest | |||||
2251 | /// commence. | |||||
2252 | ||||||
2253 | if(source_type!=kFileSource) return 0; | |||||
2254 | if(last_run_number != 0) return last_run_number; | |||||
2255 | ||||||
2256 | uint32_t buff_len = 4000000; | |||||
2257 | uint32_t *buff = new uint32_t[buff_len]; | |||||
2258 | HDEVIO *hdevio = new HDEVIO(source_name); | |||||
2259 | while(hdevio->read(buff, buff_len)){ | |||||
2260 | ||||||
2261 | // Assume first word is number of words in bank | |||||
2262 | uint32_t *iptr = buff; | |||||
2263 | uint32_t *iend = &iptr[*iptr - 1]; | |||||
2264 | if(*iptr > 2048) iend = &iptr[2048]; | |||||
2265 | bool has_timestamps = false; | |||||
2266 | while(iptr<iend){ | |||||
2267 | iptr++; | |||||
2268 | ||||||
2269 | // EPICS event | |||||
2270 | if( (*iptr & 0xff000f) == 0x600001){ | |||||
2271 | if(VERBOSE>2) evioout << " Found EPICS header. Looking for HD:coda:daq:run_number ..." << endl; | |||||
2272 | const char *cptr = (const char*)&iptr[1]; | |||||
2273 | const char *cend = (const char*)iend; | |||||
2274 | const char *needle = "HD:coda:daq:run_number="; | |||||
2275 | while(cptr<cend){ | |||||
2276 | if(VERBOSE>4) evioout << " \""<<cptr<<"\"" << endl; | |||||
2277 | if(!strncmp(cptr, needle, strlen(needle))){ | |||||
2278 | if(VERBOSE>2) evioout << " Found it!" << endl; | |||||
2279 | int32_t run_number = atoi(&cptr[strlen(needle)]); | |||||
2280 | if(hdevio) delete hdevio; | |||||
2281 | if(buff) delete[] buff; | |||||
2282 | return run_number; | |||||
2283 | } | |||||
2284 | cptr+=4; // should only start on 4-byte boundary! | |||||
2285 | } | |||||
2286 | } | |||||
2287 | ||||||
2288 | // BOR event | |||||
2289 | if( (*iptr & 0xffffffff) == 0x00700E01) continue; | |||||
2290 | ||||||
2291 | // PHYSICS event | |||||
2292 | bool not_in_this_buffer = false; | |||||
2293 | switch((*iptr)>>16){ | |||||
2294 | case 0xFF10: | |||||
2295 | case 0xFF11: | |||||
2296 | case 0xFF20: | |||||
2297 | case 0xFF21: | |||||
2298 | case 0xFF24: | |||||
2299 | case 0xFF25: | |||||
2300 | case 0xFF30: | |||||
2301 | not_in_this_buffer = true; | |||||
2302 | break; | |||||
2303 | case 0xFF23: | |||||
2304 | case 0xFF27: | |||||
2305 | has_timestamps = true; | |||||
2306 | case 0xFF22: | |||||
2307 | case 0xFF26: | |||||
2308 | break; | |||||
2309 | default: | |||||
2310 | continue; | |||||
2311 | } | |||||
2312 | ||||||
2313 | if(not_in_this_buffer) break; // go to next EVIO buffer | |||||
2314 | ||||||
2315 | iptr++; | |||||
2316 | if( ((*iptr)&0x00FF0000) != 0x000A0000) { iptr--; continue; } | |||||
2317 | uint32_t M = iptr[-3] & 0x000000FF; // Number of events from Physics Event header | |||||
2318 | if(VERBOSE>2) evioout << " ...(epic quest) Trigger bank " << (has_timestamps ? "does":"doesn't") << " have timestamps. Nevents in block M=" << M <<endl; | |||||
2319 | iptr++; | |||||
2320 | uint64_t *iptr64 = (uint64_t*)iptr; | |||||
2321 | ||||||
2322 | uint64_t event_num = *iptr64; | |||||
2323 | if(source_type==kETSource) event_num = ((*iptr64)>>32) | ((*iptr64)<<32); | |||||
2324 | if(VERBOSE>3) evioout << " ....(epic quest) Event num: " << event_num <<endl; | |||||
2325 | iptr64++; | |||||
2326 | if(has_timestamps) iptr64 = &iptr64[M]; // advance past timestamps | |||||
2327 | ||||||
2328 | // I'm not sure I fully understand this, but if we read from | |||||
2329 | // ET, then the run number is in the low 32 bits of *iptr64. | |||||
2330 | // If we are reading from a file, it is in the high 32 bits. | |||||
2331 | // No byte swapping is needed (it has already been done, though | |||||
2332 | // perhaps incorrectly). We handle this here by checking if | |||||
2333 | // this is an ET source or not. | |||||
2334 | uint64_t run64 = (*iptr64)>>32; | |||||
2335 | if(source_type==kETSource){ | |||||
2336 | run64 = (*iptr64)&0xffffffff; | |||||
2337 | } | |||||
2338 | int32_t run = (int32_t)run64; | |||||
2339 | if(VERBOSE>1) evioout << " .. (epic quest) Found run number: " << run <<endl; | |||||
2340 | ||||||
2341 | if(hdevio) delete hdevio; | |||||
2342 | if(buff) delete[] buff; | |||||
2343 | return run; | |||||
2344 | ||||||
2345 | } // while(iptr<iend) | |||||
2346 | ||||||
2347 | if(hdevio->Nevents > 500) break; | |||||
2348 | } // while(hdevio->read(buff, buff_len)) | |||||
2349 | ||||||
2350 | if(hdevio) delete hdevio; | |||||
2351 | if(buff) delete[] buff; | |||||
2352 | ||||||
2353 | return 0; | |||||
2354 | } | |||||
2355 | ||||||
2356 | //---------------- | |||||
2357 | // FindEventNumber | |||||
2358 | //---------------- | |||||
2359 | uint64_t JEventSource_EVIO::FindEventNumber(uint32_t *iptr) | |||||
2360 | { | |||||
2361 | /// This is called from GetEvent() to quickly look for the event number | |||||
2362 | /// at the time the event is read in so it can be passed into JEvent. | |||||
2363 | /// (See comments for FindRunNumber above.) | |||||
2364 | if(VERBOSE>1) evioout << " .. Searching for event number ..." <<endl; | |||||
2365 | ||||||
2366 | if(*iptr < 6){ | |||||
2367 | if(VERBOSE>1) evioout << " Word count(="<<*iptr<<")<6. Returning Nevents_read+1(=" << Nevents_read+1 << ") as event number" <<endl; | |||||
2368 | return Nevents_read+1; | |||||
2369 | } | |||||
2370 | ||||||
2371 | // Check header of Trigger bank | |||||
2372 | uint32_t mask = 0xFF202000; | |||||
2373 | if( (iptr[3]&mask) != mask ){ | |||||
2374 | if(VERBOSE>1){ | |||||
2375 | evioout << " iptr[3]=" << hex << iptr[3] << " does not look like trigger bank tag (" << (iptr[3]&mask) << " != " << mask << ")" << dec <<endl; | |||||
2376 | evioout << " Returning Nevents_read+1(=" << Nevents_read+1 << ") as event number" <<endl; | |||||
2377 | } | |||||
2378 | return Nevents_read+1; | |||||
2379 | } | |||||
2380 | ||||||
2381 | uint64_t loevent_num = iptr[5]; | |||||
2382 | uint64_t hievent_num = iptr[6]; | |||||
2383 | if(source_type==kETSource) { | |||||
2384 | loevent_num = iptr[6]; | |||||
2385 | hievent_num = iptr[5]; | |||||
2386 | } | |||||
2387 | uint64_t event_num = loevent_num + (hievent_num<<32); | |||||
2388 | if(VERBOSE>1) evioout << " .. Found event number: " << event_num <<endl; | |||||
2389 | ||||||
2390 | return event_num; | |||||
2391 | } | |||||
2392 | ||||||
2393 | //---------------- | |||||
2394 | // FindEventType | |||||
2395 | //---------------- | |||||
2396 | void JEventSource_EVIO::FindEventType(uint32_t *iptr, JEvent &event) | |||||
2397 | { | |||||
2398 | /// This is called from GetEvent to quickly determine the type of | |||||
2399 | /// event this is (Physics, EPICS, SYNC, BOR, ...) | |||||
2400 | uint32_t head = iptr[1]; | |||||
2401 | if( (head & 0xff000f) == 0x600001){ | |||||
2402 | event.SetStatusBit(kSTATUS_EPICS_EVENT); | |||||
2403 | }else if( (head & 0xffffffff) == 0x00700E01){ | |||||
2404 | event.SetStatusBit(kSTATUS_BOR_EVENT); | |||||
2405 | }else if( (head & 0xffffff00) == 0xff501000){ | |||||
2406 | event.SetStatusBit(kSTATUS_PHYSICS_EVENT); | |||||
2407 | }else if( (head & 0xffffff00) == 0xff701000){ | |||||
2408 | event.SetStatusBit(kSTATUS_PHYSICS_EVENT); | |||||
2409 | }else if( (head & 0xfff000ff) == 0xffd00000){ | |||||
2410 | event.SetStatusBit(kSTATUS_CONTROL_EVENT); | |||||
2411 | if( (head>>16) == 0xffd0 ) event.SetStatusBit(kSTATUS_SYNC_EVENT); | |||||
2412 | }else{ | |||||
2413 | DumpBinary(iptr, &iptr[16]); | |||||
2414 | } | |||||
2415 | } | |||||
2416 | ||||||
2417 | //---------------- | |||||
2418 | // MergeObjLists | |||||
2419 | //---------------- | |||||
2420 | void JEventSource_EVIO::MergeObjLists(list<ObjList*> &events1, list<ObjList*> &events2) | |||||
2421 | { | |||||
2422 | if(VERBOSE>5) evioout << " Entering MergeObjLists(). " | |||||
2423 | << " &events1=" << hex << &events1 << dec << "(" << events1.size() << " events) " | |||||
2424 | << " &events2=" << hex << &events2 << dec << "(" << events2.size() << " events) " << endl; | |||||
2425 | ||||||
2426 | /// Merge the events referenced in events2 into the events1 list. | |||||
2427 | /// | |||||
2428 | /// This will append the object lists for each type of data object | |||||
2429 | /// stored in events2 onto the appropriate list in events1. It does this | |||||
2430 | /// event-by-event. The idea being that each entry in the queue represents a | |||||
2431 | /// partial list of the objects for the event. The two queues are most likely | |||||
2432 | /// filled from different EVIO banks orginiating from different ROCs. | |||||
2433 | /// | |||||
2434 | /// Before the merging is done, it is checked that both lists either have the | |||||
2435 | /// same number of events, or one list is empty. One list is allowed to be | |||||
2436 | /// empty since it is possible it was "filled" from a bank that contains no | |||||
2437 | /// data at all which may not neccessarily be an error. If both queues have | |||||
2438 | /// at least one event, but they do not contain an equal number of events, | |||||
2439 | /// then an exception is thrown. | |||||
2440 | /// | |||||
2441 | /// The contents of event2 will be erased before returning. Ownership of all | |||||
2442 | /// ObjList objects pointed to by event2 upon entry should be considered | |||||
2443 | /// owned by event1 upon return. | |||||
2444 | ||||||
2445 | // Allow a list of 1 event with only config objects in test below | |||||
2446 | bool justconfig = false; | |||||
2447 | if(events1.size()==1){ | |||||
2448 | ObjList *objs1 = events1.front(); | |||||
2449 | justconfig = objs1->hit_objs.size()==0 && objs1->misc_objs.size()==0 && objs1->config_objs.size()!=0; | |||||
2450 | }else if(events2.size()==1){ | |||||
2451 | ObjList *objs2 = events2.front(); | |||||
2452 | justconfig = objs2->hit_objs.size()==0 && objs2->misc_objs.size()==0 && objs2->config_objs.size()!=0; | |||||
2453 | } | |||||
2454 | ||||||
2455 | // Check number of events and throw exception if appropriate | |||||
2456 | unsigned int Nevents1 = events1.size(); | |||||
2457 | unsigned int Nevents2 = events2.size(); | |||||
2458 | if(Nevents1>0 && Nevents2>0 && !justconfig){ | |||||
2459 | if(Nevents1 != Nevents2){ | |||||
2460 | evioout << "Mismatch of number of events passed to MergeObjLists. Throwing exception." << endl; | |||||
2461 | evioout << "Nevents1="<<Nevents1<<" Nevents2="<<Nevents2<<endl; | |||||
2462 | throw JException("Number of events in JEventSource_EVIO::MergeObjLists do not match!"); | |||||
2463 | } | |||||
2464 | } | |||||
2465 | ||||||
2466 | // Handle cases when one or both lists are empty | |||||
2467 | if(Nevents1==0 && Nevents2==0)return; | |||||
2468 | if(Nevents1==0){ | |||||
2469 | events1 = events2; | |||||
2470 | events2.clear(); // clear queue | |||||
2471 | return; | |||||
2472 | } | |||||
2473 | if(Nevents2==0)return; | |||||
2474 | ||||||
2475 | // If we get here it means both events1 and events2 have events | |||||
2476 | list<ObjList*>::iterator iter = events1.begin(); | |||||
2477 | for(; iter!=events1.end(); iter++){ | |||||
2478 | if(events2.empty()) break; // in case one has just config objects in a single event | |||||
2479 | ObjList *objs1 = *iter; | |||||
2480 | ObjList *objs2 = events2.front(); | |||||
2481 | events2.pop_front(); | |||||
2482 | ||||||
2483 | objs1->hit_objs.insert(objs1->hit_objs.end(), objs2->hit_objs.begin(), objs2->hit_objs.end()); | |||||
2484 | objs1->config_objs.insert(objs1->config_objs.end(), objs2->config_objs.begin(), objs2->config_objs.end()); | |||||
2485 | objs1->misc_objs.insert(objs1->misc_objs.end(), objs2->misc_objs.begin(), objs2->misc_objs.end()); | |||||
2486 | ||||||
2487 | // Delete the objs2 container | |||||
2488 | delete objs2; | |||||
2489 | } | |||||
2490 | ||||||
2491 | // Clear out any references to objects in event2 (this should be redundant) | |||||
2492 | events2.clear(); // clear queue | |||||
2493 | ||||||
2494 | if(VERBOSE>5) evioout << " Leaving MergeObjLists(). &events1=" << hex << &events1 << " &events2=" << &events2 << dec << endl; | |||||
2495 | } | |||||
2496 | ||||||
2497 | //---------------- | |||||
2498 | // ParseEVIOEvent | |||||
2499 | //---------------- | |||||
2500 | void JEventSource_EVIO::ParseEVIOEvent(evioDOMTree *evt, list<ObjList*> &full_events) | |||||
2501 | { | |||||
2502 | if(VERBOSE>5) evioout << " Entering ParseEVIOEvent() with evt=" << hex << evt << dec << endl; | |||||
2503 | ||||||
2504 | if(!evt)throw RESOURCE_UNAVAILABLE; | |||||
2505 | ||||||
2506 | // Since each bank contains parts of many events, have them fill in | |||||
2507 | // the "tmp_events" list and then merge those into the "full_events". | |||||
2508 | // It is done this way so each bank can grow tmp_events to the appropriate | |||||
2509 | // size to hold the number of events it discovers in the bank. A check | |||||
2510 | // can then be made that this is consistent with the number of event | |||||
2511 | // fragments found in the other banks. | |||||
2512 | //list<ObjList*> full_events; | |||||
2513 | list<ObjList*> tmp_events; | |||||
2514 | ||||||
2515 | // The Physics Event bank is the outermost bank of the event and | |||||
2516 | // it is a bank of banks. One of those banks is the | |||||
2517 | // "Built Trigger Bank" which is a bank of segments. The others | |||||
2518 | // are the "Data Bank" banks which in turn contain the | |||||
2519 | // "Data Block Bank" banks which hold the actual data. For the | |||||
2520 | // mc2coda generated data files (and presumably the real data) | |||||
2521 | // these Data Block Banks are banks of ints. More specifically, | |||||
2522 | // uint32_t. | |||||
2523 | // | |||||
2524 | // The "Physics Event's Built Trigger Bank" is a bank of segments. | |||||
2525 | // This contains 3 segments, one each of type uint64, uint16, and | |||||
2526 | // unit32. The first two are "common data" which contains information | |||||
2527 | // common to all rocs. The last (uint32) has information specific to each | |||||
2528 | // event and for each ROC. | |||||
2529 | // | |||||
2530 | // For now, we skip parseing the Built Trigger Bank and just | |||||
2531 | // look for Data Block Banks. We do this by getting a list of | |||||
2532 | // all uint32_t banks in the enitries DOM Tree (at all levels | |||||
2533 | // of the heirachy) and checking the parent banks for depth | |||||
2534 | // and additional info. | |||||
2535 | ||||||
2536 | // Loop over list of all EVIO banks at all levels of the tree and parse | |||||
2537 | // them, creating data objects and adding them to the overall list. | |||||
2538 | evioDOMNodeListP bankList = evt->getNodeList(); | |||||
2539 | evioDOMNodeList::iterator iter = bankList->begin(); | |||||
2540 | if(VERBOSE>7) evioout << " Looping over " << bankList->size() << " banks in EVIO event" << endl; | |||||
2541 | for(int ibank=1; iter!=bankList->end(); iter++, ibank++){ // ibank only used for debugging messages | |||||
2542 | ||||||
2543 | if(VERBOSE>7) evioout << " -------- bank " << ibank << "/" << bankList->size() << " --------" << endl; | |||||
2544 | ||||||
2545 | // The data banks we want should have exactly two parents: | |||||
2546 | // - Data Bank bank <-- parent | |||||
2547 | // - Physics Event bank <-- grandparent | |||||
2548 | // | |||||
2549 | // other types of events may be inserted in the datastream though so we | |||||
2550 | // check for those first. | |||||
2551 | ||||||
2552 | // BOR event | |||||
2553 | // BOR events will have an outermost | |||||
2554 | // bank with tag=0x70 and num=1. If this is the outermost bank of | |||||
2555 | // a BOR event, then parse it. If it is a inner BOR bank then ignore it. | |||||
2556 | evioDOMNodeP outermostBankPtr = *iter; | |||||
2557 | while(outermostBankPtr->getParent()) outermostBankPtr = outermostBankPtr->getParent(); | |||||
2558 | if(outermostBankPtr->tag==0x70 && outermostBankPtr->num==1){ | |||||
2559 | // This is a BOR bank | |||||
2560 | if(VERBOSE>9) evioout << " bank is part of BOR event ... " << endl; | |||||
2561 | if(outermostBankPtr == *iter){ | |||||
2562 | if(VERBOSE>9) evioout << " bank is outermost EVIO bank. Parsing BOR event ..." << endl; | |||||
2563 | ParseBORevent(outermostBankPtr); | |||||
2564 | }else{ | |||||
2565 | if(VERBOSE>9) evioout << " bank is not outermost EVIO bankin BOR event skipping ..." << endl; | |||||
2566 | } | |||||
2567 | continue; // no further processing of this bank is needed | |||||
2568 | } | |||||
2569 | ||||||
2570 | // EPICS event | |||||
2571 | evioDOMNodeP bankPtr = *iter; | |||||
2572 | evioDOMNodeP data_bank = bankPtr->getParent(); | |||||
2573 | if( data_bank==NULL__null ) { | |||||
2574 | ||||||
2575 | if(VERBOSE>9) evioout << " bank has no parent. Checking if it's an EPICS event ... " << endl; | |||||
2576 | if(bankPtr->tag==96 && bankPtr->num==1){ | |||||
2577 | // This looks like an EPICS event. Hand it over to EPICS parser | |||||
2578 | ParseEPICSevent(bankPtr, full_events); | |||||
2579 | }else{ | |||||
2580 | if(VERBOSE>9) evioout << " Not an EPICS event bank. skipping ... " << endl; | |||||
2581 | } | |||||
2582 | ||||||
2583 | continue; | |||||
2584 | } | |||||
2585 | ||||||
2586 | // Trigger Bank | |||||
2587 | evioDOMNodeP physics_event_bank = data_bank->getParent(); | |||||
2588 | ||||||
2589 | // TS scalers for SYNC events. Currently us phys event tag | |||||
2590 | // Don't use the parent tag in the future, to be checked | |||||
2591 | if((physics_event_bank != NULL__null) && (bankPtr != NULL__null)){ | |||||
2592 | if( (physics_event_bank->tag == 0xff70) && (bankPtr->tag == 0xEE02)){ | |||||
2593 | const vector<uint32_t> *vec = bankPtr->getVector<uint32_t>(); | |||||
2594 | if(vec->size() < 102){ | |||||
2595 | evioout << " TS record for SYNC event is inconsistent. Don't parse " << endl; | |||||
2596 | } else { | |||||
2597 | ParseTSSync(bankPtr, full_events); | |||||
2598 | // MergeObjLists(full_events, tmp_events); | |||||
2599 | } | |||||
2600 | } | |||||
2601 | } | |||||
2602 | ||||||
2603 | ||||||
2604 | if( physics_event_bank==NULL__null ){ | |||||
2605 | if(VERBOSE>6) evioout << " bank has no grandparent. Checking if this is a trigger bank ... " << endl; | |||||
2606 | ||||||
2607 | // Check if this is a CODA Reserved Bank Tag. If it is, then | |||||
2608 | // this probably is part of the built trigger bank and not | |||||
2609 | // the ROC data we're looking to parse here. | |||||
2610 | if((bankPtr->tag & 0xFF00) == 0xFF00){ | |||||
2611 | if(VERBOSE>6) evioout << " Bank tag="<<hex<<data_bank->tag<<dec<<" is in reserved CODA range and has correct lineage. Assuming it's a built trigger bank."<< endl; | |||||
2612 | ParseBuiltTriggerBank(bankPtr, tmp_events); | |||||
2613 | if(VERBOSE>5) evioout << " Merging objects in ParseEVIOEvent" << endl; | |||||
2614 | MergeObjLists(full_events, tmp_events); | |||||
2615 | ||||||
2616 | // Check if this is a DEventTag bank | |||||
2617 | }else if(bankPtr->tag == 0x0056){ | |||||
2618 | const vector<uint32_t> *vec = bankPtr->getVector<uint32_t>(); | |||||
2619 | if(vec){ | |||||
2620 | const uint32_t *iptr = &(*vec)[0]; | |||||
2621 | const uint32_t *iend = &(*vec)[vec->size()]; | |||||
2622 | ParseEventTag(iptr, iend, tmp_events); | |||||
2623 | if(VERBOSE>5) evioout << " Merging DEventTag objects in ParseEVIOEvent" << endl; | |||||
2624 | MergeObjLists(full_events, tmp_events); | |||||
2625 | } | |||||
2626 | } | |||||
2627 | ||||||
2628 | continue; // if this wasn't a trigger bank, then it has the wrong lineage to be a data bank | |||||
2629 | } | |||||
2630 | if( physics_event_bank->getParent() != NULL__null ){ | |||||
2631 | if(VERBOSE>9) evioout << " bank DOES have great-grandparent. skipping ... " << endl; | |||||
2632 | continue; // physics event bank should have no parent! | |||||
2633 | } | |||||
2634 | if(VERBOSE>9){ | |||||
2635 | evioout << " Physics Event Bank: tag=" << hex << physics_event_bank->tag << " num=" << (int)physics_event_bank->num << dec << endl; | |||||
2636 | evioout << " Data Bank: tag=" << hex << data_bank->tag << " num=" << (int)data_bank->num << dec << endl; | |||||
2637 | } | |||||
2638 | ||||||
2639 | if(VERBOSE>9) evioout << " bank lineage check OK. Continuing with parsing ... " << endl; | |||||
2640 | ||||||
2641 | // Extract ROC id (crate number) from bank's parent | |||||
2642 | uint32_t rocid = data_bank->tag & 0x0FFF; | |||||
2643 | ||||||
2644 | // Get data from bank in the form of a vector of uint32_t | |||||
2645 | const vector<uint32_t> *vec = bankPtr->getVector<uint32_t>(); | |||||
2646 | if(!vec){ | |||||
2647 | if(VERBOSE>6) evioout << " bank is not uint32_t. Skipping..." << endl; | |||||
2648 | continue; | |||||
2649 | } | |||||
2650 | const uint32_t *iptr = &(*vec)[0]; | |||||
2651 | const uint32_t *iend = &(*vec)[vec->size()]; | |||||
2652 | if(VERBOSE>6) evioout << " uint32_t bank has " << vec->size() << " words" << endl; | |||||
2653 | ||||||
2654 | // If there are rocid's specified that we wish to parse, make sure this one | |||||
2655 | // is in the list. Otherwise, skip it. | |||||
2656 | if(!ROCIDS_TO_PARSE.empty()){ | |||||
2657 | if(VERBOSE>4) evioout << " Skipping parsing of rocid="<<rocid<<" due to it being in ROCIDS_TO_PARSE set." << endl; | |||||
2658 | if(ROCIDS_TO_PARSE.find(rocid) == ROCIDS_TO_PARSE.end()) continue; | |||||
2659 | } | |||||
2660 | ||||||
2661 | // Check if this is a CODA Reserved Bank Tag. | |||||
2662 | if((data_bank->tag & 0xFF00) == 0xFF00){ | |||||
2663 | if(VERBOSE>6) evioout << " Data Bank tag="<<hex<<data_bank->tag<<dec<<" is in reserved CODA range. This is probably not ROC data"<< endl; | |||||
2664 | continue; | |||||
2665 | } | |||||
2666 | ||||||
2667 | // Check if this is a TS Bank. | |||||
2668 | if(bankPtr->tag == 0xEE02){ | |||||
2669 | if(VERBOSE>4) evioout << " TS bank tag="<<hex<<bankPtr->tag<<dec<< endl; | |||||
2670 | ParseTSBank(rocid, iptr, iend, full_events); | |||||
2671 | continue; | |||||
2672 | } | |||||
2673 | ||||||
2674 | // Check if this is a f250 Pedestal Bank. | |||||
2675 | if(bankPtr->tag == 0xEE05){ | |||||
2676 | if(VERBOSE>6) evioout << " SYNC event - f250 pedestals not currently handled"<< endl; | |||||
2677 | continue; | |||||
2678 | } | |||||
2679 | ||||||
2680 | // The number of events in block is stored in lower 8 bits | |||||
2681 | // of header word (aka the "num") of Data Bank. This should | |||||
2682 | // be at least 1. | |||||
2683 | uint32_t NumEvents = data_bank->num & 0xFF; | |||||
2684 | if( NumEvents<1 ){ | |||||
2685 | if(VERBOSE>9) evioout << " bank has less than 1 event (Data Bank num or \"M\" = 0) skipping ... " << endl; | |||||
2686 | continue; | |||||
2687 | } | |||||
2688 | ||||||
2689 | // At this point iptr and iend indicate the data that came | |||||
2690 | // from the ROC itself (all CODA headers have been stripped | |||||
2691 | // away). Here, we need to decide what type of data this | |||||
2692 | // bank contains. All JLab modules have a common block | |||||
2693 | // header format and so are handled in a common way. Other | |||||
2694 | // modules (e.g. CAEN) will have to appear in their own | |||||
2695 | // EVIO bank and should be identified by their own det_id | |||||
2696 | // value in the Data Block Bank. | |||||
2697 | // | |||||
2698 | // Current, preliminary thinking includes writing the type | |||||
2699 | // of data into the 12-bit detector id contained in the | |||||
2700 | // Data Block Bank of the DAQ group's "Event Building EVIO | |||||
2701 | // Scheme". (This is the lower 12 bits of the "tag"). We | |||||
2702 | // use this to decide if it is JLab module data or somehting | |||||
2703 | // else. | |||||
2704 | uint32_t det_id = bankPtr->tag & 0x0FFF; | |||||
2705 | // Call appropriate parsing method | |||||
2706 | bool bank_parsed = true; // will be set to false if default case is entered | |||||
2707 | switch(det_id){ | |||||
2708 | case 0: | |||||
2709 | case 1: | |||||
2710 | case 3: | |||||
2711 | case 6: // flash 250 module, MMD 2014/2/4 | |||||
2712 | case 16: // flash 125 module (CDC), DL 2014/6/19 | |||||
2713 | case 26: // F1 TDC module (BCAL), MMD 2014-07-31 | |||||
2714 | ParseJLabModuleData(rocid, iptr, iend, tmp_events); | |||||
2715 | break; | |||||
2716 | ||||||
2717 | case 20: | |||||
2718 | ParseCAEN1190(rocid, iptr, iend, tmp_events); | |||||
2719 | break; | |||||
2720 | ||||||
2721 | case 0x55: | |||||
2722 | ParseModuleConfiguration(rocid, iptr, iend, tmp_events); | |||||
2723 | break; | |||||
2724 | ||||||
2725 | case 5: | |||||
2726 | // Beni's original CDC ROL used for the stand-alone CDC DAQ | |||||
2727 | // had the following for the TS readout list (used in the TI): | |||||
2728 | // *dma_dabufp++ = 0xcebaf111; | |||||
2729 | // *dma_dabufp++ = tsGetIntCount(); | |||||
2730 | // *dma_dabufp++ = 0xdead; | |||||
2731 | // *dma_dabufp++ = 0xcebaf222; | |||||
2732 | // We skip this here, but put in the case so that we avoid errors | |||||
2733 | break; | |||||
2734 | ||||||
2735 | ||||||
2736 | default: | |||||
2737 | jerr<<"Unknown module type ("<<det_id<<") encountered for tag="<<bankPtr->tag<<" num="<< (int)bankPtr->num << endl; | |||||
2738 | bank_parsed = false; | |||||
2739 | if(VERBOSE>5){ | |||||
2740 | cerr << endl; | |||||
2741 | cout << "----- First few words to help with debugging -----" << endl; | |||||
2742 | cout.flush(); cerr.flush(); | |||||
2743 | int i=0; | |||||
2744 | for(const uint32_t *iiptr = iptr; iiptr<iend; iiptr++, i++){ | |||||
2745 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<2745<<" " << "0x" << hex << *iiptr << dec << endl; | |||||
2746 | if(i>=8) break; | |||||
2747 | } | |||||
2748 | ||||||
2749 | } | |||||
2750 | } | |||||
2751 | ||||||
2752 | // Merge this bank's partial events into the full events | |||||
2753 | if(bank_parsed){ | |||||
2754 | if(VERBOSE>5) evioout << " Merging objects in ParseEVIOEvent" << endl; | |||||
2755 | MergeObjLists(full_events, tmp_events); | |||||
2756 | } | |||||
2757 | } | |||||
2758 | ||||||
2759 | // The following disabled in preference for keeping the | |||||
2760 | // run number found by FindRunNumber called from | |||||
2761 | // GetEvent() 2/15/2016 | |||||
2762 | ||||||
2763 | // // Set the run number for all events | |||||
2764 | // uint32_t run_number = GetRunNumber(evt); | |||||
2765 | // list<ObjList*>::iterator evt_iter = full_events.begin(); | |||||
2766 | // for(; evt_iter!=full_events.end(); evt_iter++){ | |||||
2767 | // ObjList *objs = *evt_iter; | |||||
2768 | // objs->run_number = run_number; | |||||
2769 | // } | |||||
2770 | ||||||
2771 | if(VERBOSE>5) evioout << " Leaving ParseEVIOEvent()" << endl; | |||||
2772 | } | |||||
2773 | ||||||
2774 | //---------------- | |||||
2775 | // ParseBuiltTriggerBank | |||||
2776 | //---------------- | |||||
2777 | void JEventSource_EVIO::ParseBuiltTriggerBank(evioDOMNodeP trigbank, list<ObjList*> &events) | |||||
2778 | { | |||||
2779 | if(!PARSE_TRIGGER) return; | |||||
2780 | ||||||
2781 | if(VERBOSE>5) evioout << " Entering ParseBuiltTriggerBank()" << endl; | |||||
2782 | ||||||
2783 | uint32_t Mevents = 1; // number of events in block (will be overwritten below) | |||||
2784 | uint32_t Nrocs = (uint32_t)trigbank->num; // number of rocs providing data in this bank | |||||
2785 | evioDOMNodeP physics_event_bank = trigbank->getParent(); | |||||
2786 | if(physics_event_bank) Mevents = (uint32_t)physics_event_bank->num; | |||||
2787 | ||||||
2788 | if(VERBOSE>6) evioout << " Mevents=" << Mevents << " Nrocs=" << Nrocs << endl; | |||||
2789 | ||||||
2790 | // Some values to fill in while parsing the banks that will be used later to create objects | |||||
2791 | vector<uint64_t> avg_timestamps; | |||||
2792 | uint32_t run_number = 0; | |||||
2793 | uint32_t run_type = 0; | |||||
2794 | uint64_t first_event_num = 1; | |||||
2795 | vector<uint16_t> event_types; | |||||
2796 | map<uint32_t, vector<DCODAROCInfo*> > rocinfos; // key=event (from 0 to Mevents-1) | |||||
2797 | //vector<map<uint32_t, DCODAROCInfo*> > rocinfos; // key=rocid | |||||
2798 | ||||||
2799 | // Loop over children of built trigger bank | |||||
2800 | evioDOMNodeListP bankList = trigbank->getChildren(); | |||||
2801 | evioDOMNodeList::iterator iter = bankList->begin(); | |||||
2802 | for(int ibank=1; iter!=bankList->end(); iter++, ibank++){ | |||||
2803 | ||||||
2804 | if(VERBOSE>7) evioout << " Looking for data in child banks ..." << endl; | |||||
2805 | ||||||
2806 | evioDOMNodeP bankPtr = *iter; | |||||
2807 | ||||||
2808 | // The "Physics Event's Built Trigger Bank" is a bank of segments that | |||||
2809 | // may contain banks of 3 data types: uint64_t, uint32_t, and uint16_t | |||||
2810 | // The uint64_t contains the first event number, average timestamps, and | |||||
2811 | // run number & types. The uint16_t contains the event type(s). The | |||||
2812 | // uint32_t contains the optional ROC specific meta data starting with | |||||
2813 | // the specific timestamp for each event. All of these have some options | |||||
2814 | // on exactly what info is contained in the bank. The first check here is | |||||
2815 | // on the data type the bank contains. At most, one of the following pointers | |||||
2816 | // should be non-zero. | |||||
2817 | vector<uint64_t> *vec64 = bankPtr->getVector<uint64_t>(); | |||||
2818 | vector<uint32_t> *vec32 = bankPtr->getVector<uint32_t>(); | |||||
2819 | vector<uint16_t> *vec16 = bankPtr->getVector<uint16_t>(); | |||||
2820 | ||||||
2821 | // unit64_t = common data (1st part) | |||||
2822 | if(vec64){ | |||||
2823 | ||||||
2824 | if(VERBOSE>9) evioout << " found uint64_t data" << endl; | |||||
2825 | ||||||
2826 | // In addition to the first event number (1st word) there are three | |||||
2827 | // additional pieces of information that may be present: | |||||
2828 | // t = average timestamp | |||||
2829 | // r = run number and type | |||||
2830 | // d = run specific data | |||||
2831 | // | |||||
2832 | // The last one ("d") comes in the form of multiple uint32_t banks | |||||
2833 | // so is not included in vec64. The other two have their presence | |||||
2834 | // signaled by bit 0(=t) and bit 1(=r) in the trigbank tag. (We can | |||||
2835 | // also deduce this from the bank length.) | |||||
2836 | ||||||
2837 | if(vec64->size() == 0) continue; // need debug message here! | |||||
2838 | ||||||
2839 | first_event_num = (*vec64)[0]; | |||||
2840 | ||||||
2841 | // Hi and lo 32bit words in 64bit numbers seem to be | |||||
2842 | // switched for events read from ET, but not read from | |||||
2843 | // file. Not sure if this is in the swapping routine | |||||
2844 | if(source_type==kETSource) first_event_num = (first_event_num>>32) | (first_event_num<<32); | |||||
2845 | ||||||
2846 | uint32_t Ntimestamps = vec64->size()-1; | |||||
2847 | if(Ntimestamps==0) continue; // no more words of interest | |||||
2848 | if(trigbank->tag & 0x2) Ntimestamps--; // subtract 1 for run number/type word if present | |||||
2849 | for(uint32_t i=0; i<Ntimestamps; i++) avg_timestamps.push_back((*vec64)[i+1]); | |||||
2850 | ||||||
2851 | // run number and run type | |||||
2852 | if(trigbank->tag & 0x02){ | |||||
2853 | run_number = (*vec64)[vec64->size()-1] >> 32; | |||||
2854 | run_type = (*vec64)[vec64->size()-1] & 0xFFFFFFFF; | |||||
2855 | } | |||||
2856 | } | |||||
2857 | ||||||
2858 | // uint16_t = common data (2nd part) | |||||
2859 | if(vec16){ | |||||
2860 | ||||||
2861 | if(VERBOSE>9) evioout << " found uint16_t data" << endl; | |||||
2862 | ||||||
2863 | for(uint32_t i=0; i<Mevents; i++){ | |||||
2864 | if(i>=vec16->size()) break; | |||||
2865 | event_types.push_back((*vec16)[i]); | |||||
2866 | } | |||||
2867 | } | |||||
2868 | ||||||
2869 | // uint32_t = inidivdual ROC timestamps and misc. roc-specfic data | |||||
2870 | if(vec32){ | |||||
2871 | ||||||
2872 | if(VERBOSE>9) evioout << " found uint32_t data" << endl; | |||||
2873 | ||||||
2874 | // Get pointer to DCODAROCInfo object for this rocid/event, instantiating it if necessary | |||||
2875 | uint32_t rocid = (uint32_t)bankPtr->tag; | |||||
2876 | uint32_t Nwords_per_event = vec32->size()/Mevents; | |||||
2877 | if(vec32->size() != Mevents*Nwords_per_event){ | |||||
2878 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<2878<<" " << "Number of ROC data words in Trigger Bank inconsistent with header" << endl; | |||||
2879 | exit(-1); | |||||
2880 | } | |||||
2881 | ||||||
2882 | uint32_t *iptr = &(*vec32)[0]; | |||||
2883 | for(uint32_t ievent=0; ievent<Mevents; ievent++){ | |||||
2884 | ||||||
2885 | DCODAROCInfo *codarocinfo = new DCODAROCInfo; | |||||
2886 | codarocinfo->rocid = rocid; | |||||
2887 | ||||||
2888 | uint64_t ts_low = *iptr++; | |||||
2889 | uint64_t ts_high = *iptr++; | |||||
2890 | codarocinfo->timestamp = (ts_high<<32) + ts_low; | |||||
2891 | for(uint32_t i=2; i<Nwords_per_event; i++) codarocinfo->misc.push_back(*iptr++); | |||||
2892 | ||||||
2893 | if(VERBOSE>7) evioout << " Adding DCODAROCInfo for rocid="<<rocid<< " with timestamp " << codarocinfo->timestamp << endl; | |||||
2894 | rocinfos[ievent].push_back(codarocinfo); | |||||
2895 | } | |||||
2896 | } | |||||
2897 | } | |||||
2898 | ||||||
2899 | // Check that we have agreement on the number of events this data represents | |||||
2900 | bool Nevent_mismatch = false; | |||||
2901 | if(!avg_timestamps.empty()) Nevent_mismatch |= (avg_timestamps.size() != Mevents); | |||||
2902 | if(!event_types.empty() ) Nevent_mismatch |= (event_types.size() != Mevents); | |||||
2903 | if(!rocinfos.empty() ) Nevent_mismatch |= (rocinfos.size() != Mevents); | |||||
2904 | if(Nevent_mismatch){ | |||||
2905 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<2905<<" "<<"Mismatch in number of events in Trigger Bank!"<<endl; | |||||
2906 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<2906<<" "<<" Mevents="<<Mevents<<endl; | |||||
2907 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<2907<<" "<<" avg_timestamps.size()="<<avg_timestamps.size()<<endl; | |||||
2908 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<2908<<" "<<" event_types.size()="<<event_types.size()<<endl; | |||||
2909 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<2909<<" "<<" rocinfos.size()="<<rocinfos.size()<<endl; | |||||
2910 | exit(-1); | |||||
2911 | } | |||||
2912 | ||||||
2913 | // Copy all objects into events | |||||
2914 | for(uint32_t i=0; i<Mevents; i++){ | |||||
2915 | while(events.size()<=i){ | |||||
2916 | if(!ENABLE_DISENTANGLING && !events.empty()) break; | |||||
2917 | events.push_back(new ObjList); | |||||
2918 | } | |||||
2919 | ObjList *objs = events.back(); | |||||
2920 | ||||||
2921 | DCODAEventInfo *codaeventinfo = new DCODAEventInfo; | |||||
2922 | codaeventinfo->run_number = run_number; | |||||
2923 | codaeventinfo->run_type = run_type; | |||||
2924 | codaeventinfo->event_number = first_event_num + i; | |||||
2925 | codaeventinfo->event_type = event_types.empty() ? 0:event_types[i]; | |||||
2926 | codaeventinfo->avg_timestamp = avg_timestamps.empty() ? 0:avg_timestamps[i]; | |||||
2927 | objs->misc_objs.push_back(codaeventinfo); | |||||
2928 | objs->event_number = codaeventinfo->event_number; | |||||
2929 | ||||||
2930 | vector<DCODAROCInfo*> &codarocinfos = rocinfos[i]; | |||||
2931 | for(uint32_t i=0; i<codarocinfos.size(); i++) objs->misc_objs.push_back(codarocinfos[i]); | |||||
2932 | } | |||||
2933 | ||||||
2934 | if(VERBOSE>6) evioout << " Found "<<events.size()<<" events in Built Trigger Bank"<< endl; | |||||
2935 | if(VERBOSE>5) evioout << " Leaving ParseBuiltTriggerBank()" << endl; | |||||
2936 | } | |||||
2937 | ||||||
2938 | //---------------- | |||||
2939 | // ParseModuleConfiguration | |||||
2940 | //---------------- | |||||
2941 | void JEventSource_EVIO::ParseModuleConfiguration(int32_t rocid, const uint32_t* &iptr, const uint32_t *iend, list<ObjList*> &events) | |||||
2942 | { | |||||
2943 | if(!PARSE_CONFIG){ iptr = iend; return; } | |||||
2944 | ||||||
2945 | if(VERBOSE>5) evioout << " Entering ParseModuleConfiguration() (events.size()="<<events.size()<<")" << endl; | |||||
2946 | ||||||
2947 | /// Parse a bank of module configuration data. These are configuration values | |||||
2948 | /// programmed into the module at the beginning of the run that may be needed | |||||
2949 | /// in the offline. For example, the number of samples to sum in a FADC pulse | |||||
2950 | /// integral. | |||||
2951 | /// | |||||
2952 | /// The bank has one or more sections, each describing parameters applicable | |||||
2953 | /// to a number of modules as indicated by a 24bit slot mask. | |||||
2954 | /// | |||||
2955 | /// This bank should appear only once per DAQ event which, if in multi-event | |||||
2956 | /// block mode, may have multiple L1 events. The parameters here will apply | |||||
2957 | /// to all L1 events in the block. This method will put the config objects | |||||
2958 | /// in the first event of "events", creating it if needed. The config objects | |||||
2959 | /// are duplicated for all other events in the block later, after all event | |||||
2960 | /// parsing is finished and the total number of events is known. | |||||
2961 | /// (See the end of ParseEvents() .) | |||||
2962 | ||||||
2963 | while(iptr < iend){ | |||||
2964 | uint32_t slot_mask = (*iptr) & 0xFFFFFF; | |||||
2965 | uint32_t Nvals = ((*iptr) >> 24) & 0xFF; | |||||
2966 | iptr++; | |||||
2967 | ||||||
2968 | Df250Config *f250config = NULL__null; | |||||
2969 | Df125Config *f125config = NULL__null; | |||||
2970 | DF1TDCConfig *f1tdcconfig = NULL__null; | |||||
2971 | DCAEN1290TDCConfig *caen1290tdcconfig = NULL__null; | |||||
2972 | ||||||
2973 | // Loop over all parameters in this section | |||||
2974 | for(uint32_t i=0; i< Nvals; i++){ | |||||
2975 | if( iptr >= iend){ | |||||
2976 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<2976<<" " << "DAQ Configuration bank corrupt! slot_mask=0x" << hex << slot_mask << dec << " Nvals="<< Nvals << endl; | |||||
2977 | exit(-1); | |||||
2978 | } | |||||
2979 | ||||||
2980 | daq_param_type ptype = (daq_param_type)((*iptr)>>16); | |||||
2981 | uint16_t val = (*iptr) & 0xFFFF; | |||||
2982 | ||||||
2983 | if(VERBOSE>6) evioout << " DAQ parameter of type: 0x" << hex << ptype << dec << " found with value: " << val << endl; | |||||
2984 | ||||||
2985 | // Create config object of correct type if needed and copy | |||||
2986 | // parameter value into it. | |||||
2987 | switch(ptype>>8){ | |||||
2988 | ||||||
2989 | // f250 | |||||
2990 | case 0x05: | |||||
2991 | if( !f250config ) f250config = new Df250Config(rocid, slot_mask); | |||||
2992 | switch(ptype){ | |||||
2993 | case kPARAM250_NSA : f250config->NSA = val; break; | |||||
2994 | case kPARAM250_NSB : f250config->NSB = val; break; | |||||
2995 | case kPARAM250_NSA_NSB : f250config->NSA_NSB = val; break; | |||||
2996 | case kPARAM250_NPED : f250config->NPED = val; break; | |||||
2997 | default: _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<2997<<" " << "UNKNOWN DAQ Config Parameter type: 0x" << hex << ptype << dec << endl; | |||||
2998 | } | |||||
2999 | break; | |||||
3000 | ||||||
3001 | // f125 | |||||
3002 | case 0x0F: | |||||
3003 | if( !f125config ) f125config = new Df125Config(rocid, slot_mask); | |||||
3004 | switch(ptype){ | |||||
3005 | case kPARAM125_NSA : f125config->NSA = val; break; | |||||
3006 | case kPARAM125_NSB : f125config->NSB = val; break; | |||||
3007 | case kPARAM125_NSA_NSB : f125config->NSA_NSB = val; break; | |||||
3008 | case kPARAM125_NPED : f125config->NPED = val; break; | |||||
3009 | case kPARAM125_WINWIDTH : f125config->WINWIDTH = val; break; | |||||
3010 | case kPARAM125_PL : f125config->PL = val; break; | |||||
3011 | case kPARAM125_NW : f125config->NW = val; break; | |||||
3012 | case kPARAM125_NPK : f125config->NPK = val; break; | |||||
3013 | case kPARAM125_P1 : f125config->P1 = val; break; | |||||
3014 | case kPARAM125_P2 : f125config->P2 = val; break; | |||||
3015 | case kPARAM125_PG : f125config->PG = val; break; | |||||
3016 | case kPARAM125_IE : f125config->IE = val; break; | |||||
3017 | case kPARAM125_H : f125config->H = val; break; | |||||
3018 | case kPARAM125_TH : f125config->TH = val; break; | |||||
3019 | case kPARAM125_TL : f125config->TL = val; break; | |||||
3020 | case kPARAM125_IBIT : f125config->IBIT = val; break; | |||||
3021 | case kPARAM125_ABIT : f125config->ABIT = val; break; | |||||
3022 | case kPARAM125_PBIT : f125config->PBIT = val; break; | |||||
3023 | default: _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<3023<<" " << "UNKNOWN DAQ Config Parameter type: 0x" << hex << ptype << dec << endl; | |||||
3024 | } | |||||
3025 | break; | |||||
3026 | ||||||
3027 | // F1TDC | |||||
3028 | case 0x06: | |||||
3029 | if( !f1tdcconfig ) f1tdcconfig = new DF1TDCConfig(rocid, slot_mask); | |||||
3030 | switch(ptype){ | |||||
3031 | case kPARAMF1_REFCNT : f1tdcconfig->REFCNT = val; break; | |||||
3032 | case kPARAMF1_TRIGWIN : f1tdcconfig->TRIGWIN = val; break; | |||||
3033 | case kPARAMF1_TRIGLAT : f1tdcconfig->TRIGLAT = val; break; | |||||
3034 | case kPARAMF1_HSDIV : f1tdcconfig->HSDIV = val; break; | |||||
3035 | case kPARAMF1_BINSIZE : f1tdcconfig->BINSIZE = val; break; | |||||
3036 | case kPARAMF1_REFCLKDIV : f1tdcconfig->REFCLKDIV = val; break; | |||||
3037 | default: _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<3037<<" " << "UNKNOWN DAQ Config Parameter type: 0x" << hex << ptype << dec << endl; | |||||
3038 | } | |||||
3039 | break; | |||||
3040 | ||||||
3041 | // caen1290 | |||||
3042 | case 0x10: | |||||
3043 | if( !caen1290tdcconfig ) caen1290tdcconfig = new DCAEN1290TDCConfig(rocid, slot_mask); | |||||
3044 | switch(ptype){ | |||||
3045 | case kPARAMCAEN1290_WINWIDTH : caen1290tdcconfig->WINWIDTH = val; break; | |||||
3046 | case kPARAMCAEN1290_WINOFFSET : caen1290tdcconfig->WINOFFSET = val; break; | |||||
3047 | default: _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<3047<<" " << "UNKNOWN DAQ Config Parameter type: 0x" << hex << ptype << dec << endl; | |||||
3048 | } | |||||
3049 | break; | |||||
3050 | ||||||
3051 | default: | |||||
3052 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<3052<<" " << "Unknown module type: 0x" << hex << (ptype>>8) << endl; | |||||
3053 | exit(-1); | |||||
3054 | } | |||||
3055 | ||||||
3056 | #if 0 | |||||
3057 | // Create config object of correct type if needed. (Only one type | |||||
3058 | // should be created per section!) | |||||
3059 | switch(ptype>>8){ | |||||
3060 | case 0x05: if(!f250config ) f250config = new Df250Config(rocid, slot_mask); break; | |||||
3061 | case 0x0F: if(!f125config ) f125config = new Df125Config(rocid, slot_mask); break; | |||||
3062 | case 0x06: if(!f1tdcconfig ) f1tdcconfig = new DF1TDCConfig(rocid, slot_mask); break; | |||||
3063 | case 0x10: if(!caen1290tdcconfig) caen1290tdcconfig = new DCAEN1290TDCConfig(rocid, slot_mask); break; | |||||
3064 | default: | |||||
3065 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<3065<<" " << "Unknown module type: 0x" << hex << (ptype>>8) << endl; | |||||
3066 | exit(-1); | |||||
3067 | } | |||||
3068 | ||||||
3069 | // Copy parameter into config. object | |||||
3070 | switch(ptype){ | |||||
3071 | case kPARAM250_NSA : f250config->NSA = val; break; | |||||
3072 | case kPARAM250_NSB : f250config->NSB = val; break; | |||||
3073 | case kPARAM250_NSA_NSB : f250config->NSA_NSB = val; break; | |||||
3074 | case kPARAM250_NPED : f250config->NPED = val; break; | |||||
3075 | ||||||
3076 | case kPARAM125_NSA : f125config->NSA = val; break; | |||||
3077 | case kPARAM125_NSB : f125config->NSB = val; break; | |||||
3078 | case kPARAM125_NSA_NSB : f125config->NSA_NSB = val; break; | |||||
3079 | case kPARAM125_NPED : f125config->NPED = val; break; | |||||
3080 | case kPARAM125_WINWIDTH : f125config->WINWIDTH = val; break; | |||||
3081 | case kPARAM125_PL : f125config->PL = val; break; | |||||
3082 | case kPARAM125_NW : f125config->NW = val; break; | |||||
3083 | case kPARAM125_NPK : f125config->NPK = val; break; | |||||
3084 | case kPARAM125_P1 : f125config->P1 = val; break; | |||||
3085 | case kPARAM125_P2 : f125config->P2 = val; break; | |||||
3086 | case kPARAM125_PG : f125config->PG = val; break; | |||||
3087 | case kPARAM125_IE : f125config->IE = val; break; | |||||
3088 | case kPARAM125_H : f125config->H = val; break; | |||||
3089 | case kPARAM125_TH : f125config->TH = val; break; | |||||
3090 | case kPARAM125_TL : f125config->TL = val; break; | |||||
3091 | case kPARAM125_IBIT : f125config->IBIT = val; break; | |||||
3092 | case kPARAM125_ABIT : f125config->ABIT = val; break; | |||||
3093 | case kPARAM125_PBIT : f125config->PBIT = val; break; | |||||
3094 | ||||||
3095 | case kPARAMF1_REFCNT : f1tdcconfig->REFCNT = val; break; | |||||
3096 | case kPARAMF1_TRIGWIN : f1tdcconfig->TRIGWIN = val; break; | |||||
3097 | case kPARAMF1_TRIGLAT : f1tdcconfig->TRIGLAT = val; break; | |||||
3098 | case kPARAMF1_HSDIV : f1tdcconfig->HSDIV = val; break; | |||||
3099 | case kPARAMF1_BINSIZE : f1tdcconfig->BINSIZE = val; break; | |||||
3100 | case kPARAMF1_REFCLKDIV : f1tdcconfig->REFCLKDIV = val; break; | |||||
3101 | ||||||
3102 | case kPARAMCAEN1290_WINWIDTH : caen1290tdcconfig->WINWIDTH = val; break; | |||||
3103 | case kPARAMCAEN1290_WINOFFSET : caen1290tdcconfig->WINOFFSET = val; break; | |||||
3104 | ||||||
3105 | default: | |||||
3106 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<3106<<" " << "UNKNOWN DAQ Config Parameter type: 0x" << hex << ptype << dec << endl; | |||||
3107 | } | |||||
3108 | #endif | |||||
3109 | ||||||
3110 | iptr++; | |||||
3111 | } | |||||
3112 | ||||||
3113 | // If we get here it means we didn't exit in the switch(ptype>>16) statement above | |||||
3114 | // so there is at least one DDAQConfig object we need to store. Get pointer to | |||||
3115 | // first event's ObjList, creating it if needed. | |||||
3116 | if(events.empty()) events.push_back(new ObjList()); | |||||
3117 | ObjList *objs = *(events.begin()); | |||||
3118 | ||||||
3119 | if(f250config ) objs->config_objs.push_back(f250config ); | |||||
3120 | if(f125config ) objs->config_objs.push_back(f125config ); | |||||
3121 | if(f1tdcconfig ) objs->config_objs.push_back(f1tdcconfig ); | |||||
3122 | if(caen1290tdcconfig) objs->config_objs.push_back(caen1290tdcconfig); | |||||
3123 | } | |||||
3124 | ||||||
3125 | if(VERBOSE>5) evioout << " Leaving ParseModuleConfiguration()" << endl; | |||||
3126 | } | |||||
3127 | ||||||
3128 | //---------------- | |||||
3129 | // ParseEventTag | |||||
3130 | //---------------- | |||||
3131 | void JEventSource_EVIO::ParseEventTag(const uint32_t* &iptr, const uint32_t *iend, list<ObjList*> &events) | |||||
3132 | { | |||||
3133 | if(!PARSE_EVENTTAG){ iptr = iend; return; } | |||||
3134 | ||||||
3135 | if(VERBOSE>5) evioout << " Entering ParseEventTag() (events.size()="<<events.size()<<")" << endl; | |||||
3136 | ||||||
3137 | // Make sure there is one event in the event container | |||||
3138 | // and get pointer to it. | |||||
3139 | if(events.empty()) events.push_back(new ObjList()); | |||||
3140 | ObjList *objs = *(events.begin()); | |||||
3141 | ||||||
3142 | ||||||
3143 | DEventTag *etag = new DEventTag; | |||||
3144 | ||||||
3145 | // event_status | |||||
3146 | uint64_t lo = *iptr++; | |||||
3147 | uint64_t hi = *iptr++; | |||||
3148 | etag->event_status = (hi<<32) + lo; | |||||
3149 | ||||||
3150 | // L3_status | |||||
3151 | lo = *iptr++; | |||||
3152 | hi = *iptr++; | |||||
3153 | etag->L3_status = (hi<<32) + lo; | |||||
3154 | ||||||
3155 | // L3_decision | |||||
3156 | etag->L3_decision = (DL3Trigger::L3_decision_t)*iptr++; | |||||
3157 | ||||||
3158 | // L3_algorithm | |||||
3159 | etag->L3_algorithm = *iptr++; | |||||
3160 | ||||||
3161 | objs->misc_objs.push_back(etag); | |||||
3162 | ||||||
3163 | ||||||
3164 | if(VERBOSE>5) evioout << " Leaving ParseEventTag()" << endl; | |||||
3165 | } | |||||
3166 | ||||||
3167 | //---------------- | |||||
3168 | // ParseJLabModuleData | |||||
3169 | //---------------- | |||||
3170 | void JEventSource_EVIO::ParseJLabModuleData(int32_t rocid, const uint32_t* &iptr, const uint32_t *iend, list<ObjList*> &events) | |||||
3171 | { | |||||
3172 | if(VERBOSE>5) evioout << " Entering ParseJLabModuleData()" << endl; | |||||
3173 | ||||||
3174 | /// Parse a bank of data coming from one or more JLab modules. | |||||
3175 | /// The data are assumed to follow the standard JLab format for | |||||
3176 | /// block headers. If multiple modules are read out in a single | |||||
3177 | /// chain block transfer, then the data will all be placed in | |||||
3178 | /// a single EVIO bank and this will loop over the modules. | |||||
3179 | while(iptr < iend){ | |||||
3180 | ||||||
3181 | if(VERBOSE>9) evioout << "Parsing word: " << hex << *iptr << dec << endl; | |||||
3182 | ||||||
3183 | // This was observed in some CDC data. Not sure where it came from ... | |||||
3184 | if(*iptr == 0xF800FAFA){ | |||||
3185 | if(VERBOSE>9) evioout << " 0xf800fafa is a known extra word. Skipping it ..." << endl; | |||||
3186 | iptr++; | |||||
3187 | continue; | |||||
3188 | } | |||||
3189 | ||||||
3190 | // Get module type from next word (bits 18-21) | |||||
3191 | uint32_t mod_id = ((*iptr) >> 18) & 0x000F; | |||||
3192 | ||||||
3193 | // The enum defined in DModuleType.h MUST be kept in alignment | |||||
3194 | // with the DAQ group's definitions for modules types! | |||||
3195 | MODULE_TYPE type = (MODULE_TYPE)mod_id; | |||||
3196 | if(VERBOSE>5) evioout << " Encountered module type: " << type << " (=" << DModuleType::GetModule(type).GetName() << ")" << endl; | |||||
3197 | ||||||
3198 | if(modtype_translate.find(type) != modtype_translate.end()){ | |||||
3199 | type = modtype_translate[type]; | |||||
3200 | if(VERBOSE>5) evioout << " switched module type to: " << type << " (=" << DModuleType::GetModule(type).GetName() << ")" << endl; | |||||
3201 | } | |||||
3202 | ||||||
3203 | // Parse buffer depending on module type | |||||
3204 | // (Note that each of the ParseXXX routines called below will | |||||
3205 | // update the "iptr" variable to point to the next word | |||||
3206 | // after the block it parsed.) | |||||
3207 | list<ObjList*> tmp_events; | |||||
3208 | const uint32_t *istart=iptr; // just for UNKNOWN case below | |||||
3209 | bool module_parsed = true; | |||||
3210 | switch(type){ | |||||
3211 | case DModuleType::FADC250: | |||||
3212 | Parsef250Bank(rocid, iptr, iend, tmp_events); | |||||
3213 | break; | |||||
3214 | ||||||
3215 | case DModuleType::FADC125: | |||||
3216 | Parsef125Bank(rocid, iptr, iend, tmp_events); | |||||
3217 | break; | |||||
3218 | ||||||
3219 | case DModuleType::F1TDC32: | |||||
3220 | ParseF1TDCBank(rocid, iptr, iend, tmp_events); | |||||
3221 | break; | |||||
3222 | ||||||
3223 | case DModuleType::F1TDC48: | |||||
3224 | ParseF1TDCBank(rocid, iptr, iend, tmp_events); | |||||
3225 | break; | |||||
3226 | ||||||
3227 | case DModuleType::JLAB_TS: | |||||
3228 | //ParseTSBank(rocid, iptr, iend, tmp_events); // This is not used | |||||
3229 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<3229<<" " << "What the ? ! This data type isn't supposed to be here!!" << endl; | |||||
3230 | break; | |||||
3231 | ||||||
3232 | case DModuleType::TID: | |||||
3233 | ParseTIBank(rocid, iptr, iend, tmp_events); | |||||
3234 | break; | |||||
3235 | ||||||
3236 | case DModuleType::UNKNOWN: | |||||
3237 | default: | |||||
3238 | jerr<<"Unknown module type ("<<mod_id<<") iptr=0x" << hex << iptr << dec << endl; | |||||
3239 | ||||||
3240 | while(iptr<iend && ((*iptr) & 0xF8000000) != 0x88000000) iptr++; // Skip to JLab block trailer | |||||
3241 | iptr++; // advance past JLab block trailer | |||||
3242 | while(iptr<iend && *iptr == 0xF8000000) iptr++; // skip filler words after block trailer | |||||
3243 | module_parsed = false; | |||||
3244 | jerr<<"...skipping to 0x" << hex << iptr << dec << " (discarding " << (((uint64_t)iptr-(uint64_t)istart)/4) << " words)" << endl; | |||||
3245 | break; | |||||
3246 | } | |||||
3247 | ||||||
3248 | if(VERBOSE>9) evioout << "Finished parsing (last word: " << hex << iptr[-1] << dec << ")" << endl; | |||||
3249 | ||||||
3250 | if(module_parsed){ | |||||
3251 | if(VERBOSE>5) evioout << " Merging objects in ParseJLabModuleData" << endl; | |||||
3252 | MergeObjLists(events, tmp_events); | |||||
3253 | } | |||||
3254 | } | |||||
3255 | ||||||
3256 | if(VERBOSE>5) evioout << " Leaving ParseJLabModuleData()" << endl; | |||||
3257 | } | |||||
3258 | ||||||
3259 | //---------------- | |||||
3260 | // Parsef250Bank | |||||
3261 | //---------------- | |||||
3262 | void JEventSource_EVIO::Parsef250Bank(int32_t rocid, const uint32_t* &iptr, const uint32_t *iend, list<ObjList*> &events) | |||||
3263 | { | |||||
3264 | /// Parse data from a single FADC250 module. | |||||
3265 | ||||||
3266 | if(!PARSE_F250){ iptr = iend; return; } | |||||
3267 | ||||||
3268 | // This will get updated to point to a newly allocated object when an | |||||
3269 | // event header is encountered. The existing value (if non-NULL) is | |||||
3270 | // added to the events queue first though so all events are kept. | |||||
3271 | ObjList *objs = NULL__null; | |||||
3272 | ||||||
3273 | // From the Block Header | |||||
3274 | uint32_t slot=0; | |||||
3275 | //uint32_t Nblock_events; | |||||
3276 | //uint32_t iblock; | |||||
3277 | ||||||
3278 | // From the Block Trailer | |||||
3279 | //uint32_t slot_trailer; | |||||
3280 | //uint32_t Nwords_in_block; | |||||
3281 | ||||||
3282 | // From Event header | |||||
3283 | //uint32_t slot_event_header; | |||||
3284 | uint32_t itrigger = -1; | |||||
3285 | uint32_t last_itrigger = -2; | |||||
3286 | ||||||
3287 | // Loop over data words | |||||
3288 | for(; iptr<iend; iptr++){ | |||||
3289 | ||||||
3290 | // Skip all non-data-type-defining words at this | |||||
3291 | // level. When we do encounter one, the appropriate | |||||
3292 | // case block below should handle parsing all of | |||||
3293 | // the data continuation words and advance the iptr. | |||||
3294 | if(((*iptr>>31) & 0x1) == 0)continue; | |||||
3295 | ||||||
3296 | // Variables used inside of switch, but cannot be declared inside | |||||
3297 | uint64_t t = 0L; | |||||
3298 | uint32_t channel = 0; | |||||
3299 | uint32_t sum = 0; | |||||
3300 | uint32_t pulse_number = 0; | |||||
3301 | uint32_t quality_factor = 0; | |||||
3302 | uint32_t pulse_time = 0; | |||||
3303 | uint32_t pedestal = 0; | |||||
3304 | uint32_t pulse_peak = 0; | |||||
3305 | uint32_t nsamples_integral = 0; | |||||
3306 | uint32_t nsamples_pedestal = 0; | |||||
3307 | bool overflow = false; | |||||
3308 | ||||||
3309 | bool found_block_trailer = false; | |||||
3310 | uint32_t data_type = (*iptr>>27) & 0x0F; | |||||
3311 | switch(data_type){ | |||||
3312 | case 0: // Block Header | |||||
3313 | slot = (*iptr>>22) & 0x1F; | |||||
3314 | if(VERBOSE>7) evioout << " FADC250 Block Header: slot="<<slot<<" ("<<hex<<*iptr<<dec<<")"<<endl; | |||||
3315 | //iblock= (*iptr>>8) & 0x03FF; | |||||
3316 | //Nblock_events= (*iptr>>0) & 0xFF; | |||||
3317 | break; | |||||
3318 | case 1: // Block Trailer | |||||
3319 | //slot_trailer = (*iptr>>22) & 0x1F; | |||||
3320 | //Nwords_in_block = (*iptr>>0) & 0x3FFFFF; | |||||
3321 | if(VERBOSE>7) evioout << " FADC250 Block Trailer"<<" ("<<hex<<*iptr<<dec<<")"<<endl; | |||||
3322 | found_block_trailer = true; | |||||
3323 | break; | |||||
3324 | case 2: // Event Header | |||||
3325 | //slot_event_header = (*iptr>>22) & 0x1F; | |||||
3326 | itrigger = (*iptr>>0) & 0x3FFFFF; | |||||
3327 | if(VERBOSE>7) evioout << " FADC250 Event Header: itrigger="<<itrigger<<" (objs=0x"<<hex<<objs<<dec<<", last_itrigger="<<last_itrigger<<", rocid="<<rocid<<", slot="<<slot<<")" <<" ("<<hex<<*iptr<<dec<<")" <<endl; | |||||
3328 | if( (itrigger!=last_itrigger) || (objs==NULL__null) ){ | |||||
3329 | if(ENABLE_DISENTANGLING){ | |||||
3330 | if(objs){ | |||||
3331 | events.push_back(objs); | |||||
3332 | objs = NULL__null; | |||||
3333 | } | |||||
3334 | } | |||||
3335 | if(!objs) objs = new ObjList; | |||||
3336 | last_itrigger = itrigger; | |||||
3337 | } | |||||
3338 | break; | |||||
3339 | case 3: // Trigger Time | |||||
3340 | t = ((*iptr)&0xFFFFFF)<<0; | |||||
3341 | if(VERBOSE>7) evioout << " FADC250 Trigger Time: t="<<t<<" ("<<hex<<*iptr<<dec<<")"<<endl; | |||||
3342 | iptr++; | |||||
3343 | if(((*iptr>>31) & 0x1) == 0){ | |||||
3344 | t += ((*iptr)&0xFFFFFF)<<24; // from word on the street: second trigger time word is optional!!?? | |||||
3345 | if(VERBOSE>7) evioout << " Trigger time high word="<<(((*iptr)&0xFFFFFF))<<" ("<<hex<<*iptr<<dec<<")"<<endl; | |||||
3346 | }else{ | |||||
3347 | iptr--; | |||||
3348 | } | |||||
3349 | if(objs) objs->hit_objs.push_back(new Df250TriggerTime(rocid, slot, itrigger, t)); | |||||
3350 | break; | |||||
3351 | case 4: // Window Raw Data | |||||
3352 | // iptr passed by reference and so will be updated automatically | |||||
3353 | if(VERBOSE>7) evioout << " FADC250 Window Raw Data"<<" ("<<hex<<*iptr<<dec<<")"<<endl; | |||||
3354 | MakeDf250WindowRawData(objs, rocid, slot, itrigger, iptr); | |||||
3355 | break; | |||||
3356 | case 5: // Window Sum | |||||
3357 | channel = (*iptr>>23) & 0x0F; | |||||
3358 | sum = (*iptr>>0) & 0x3FFFFF; | |||||
3359 | overflow = (*iptr>>22) & 0x1; | |||||
3360 | if(VERBOSE>7) evioout << " FADC250 Window Sum"<<" ("<<hex<<*iptr<<dec<<")"<<endl; | |||||
3361 | if(objs) objs->hit_objs.push_back(new Df250WindowSum(rocid, slot, channel, itrigger, sum, overflow)); | |||||
3362 | break; | |||||
3363 | case 6: // Pulse Raw Data | |||||
3364 | // iptr passed by reference and so will be updated automatically | |||||
3365 | if(VERBOSE>7) evioout << " FADC250 Pulse Raw Data"<<" ("<<hex<<*iptr<<dec<<")"<<endl; | |||||
3366 | MakeDf250PulseRawData(objs, rocid, slot, itrigger, iptr); | |||||
3367 | break; | |||||
3368 | case 7: // Pulse Integral | |||||
3369 | channel = (*iptr>>23) & 0x0F; | |||||
3370 | pulse_number = (*iptr>>21) & 0x03; | |||||
3371 | quality_factor = (*iptr>>19) & 0x03; | |||||
3372 | sum = (*iptr>>0) & 0x7FFFF; | |||||
3373 | nsamples_integral = 0; // must be overwritten later in GetObjects with value from Df125Config value | |||||
3374 | nsamples_pedestal = 1; // The firmware returns an already divided pedestal | |||||
3375 | pedestal = 0; // This will be replaced by the one from Df250PulsePedestal in GetObjects | |||||
3376 | if(VERBOSE>7) evioout << " FADC250 Pulse Integral: chan="<<channel<<" pulse_number="<<pulse_number<<" sum="<<sum<<" ("<<hex<<*iptr<<dec<<")"<<endl; | |||||
3377 | if( (objs!=NULL__null) && (pulse_number<F250PULSE_NUMBER_FILTER) ) { | |||||
3378 | objs->hit_objs.push_back(new Df250PulseIntegral(rocid, slot, channel, itrigger, pulse_number, | |||||
3379 | quality_factor, sum, pedestal, nsamples_integral, nsamples_pedestal)); | |||||
3380 | } | |||||
3381 | break; | |||||
3382 | case 8: // Pulse Time | |||||
3383 | channel = (*iptr>>23) & 0x0F; | |||||
3384 | pulse_number = (*iptr>>21) & 0x03; | |||||
3385 | quality_factor = (*iptr>>19) & 0x03; | |||||
3386 | pulse_time = (*iptr>>0) & 0x7FFFF; | |||||
3387 | if(VERBOSE>7) evioout << " FADC250 Pulse Time: chan="<<channel<<" pulse_number="<<pulse_number<<" pulse_time="<<pulse_time<<" ("<<hex<<*iptr<<dec<<")"<<endl; | |||||
3388 | if( (objs!=NULL__null) && (pulse_number<F250PULSE_NUMBER_FILTER) ) { | |||||
3389 | objs->hit_objs.push_back(new Df250PulseTime(rocid, slot, channel, itrigger, pulse_number, quality_factor, pulse_time)); | |||||
3390 | } | |||||
3391 | break; | |||||
3392 | case 9: // Streaming Raw Data | |||||
3393 | // This is marked "reserved for future implementation" in the current manual (v2). | |||||
3394 | // As such, we don't try handling it here just yet. | |||||
3395 | if(VERBOSE>7) evioout << " FADC250 Streaming Raw Data (unsupported)"<<" ("<<hex<<*iptr<<dec<<")"<<endl; | |||||
3396 | break; | |||||
3397 | case 10: // Pulse Pedestal | |||||
3398 | channel = (*iptr>>23) & 0x0F; | |||||
3399 | pulse_number = (*iptr>>21) & 0x03; | |||||
3400 | pedestal = (*iptr>>12) & 0x1FF; | |||||
3401 | pulse_peak = (*iptr>>0) & 0xFFF; | |||||
3402 | if(VERBOSE>7) evioout << " FADC250 Pulse Pedestal chan="<<channel<<" pulse_number="<<pulse_number<<" pedestal="<<pedestal<<" pulse_peak="<<pulse_peak<<" ("<<hex<<*iptr<<dec<<")"<<endl; | |||||
3403 | if( (objs!=NULL__null) && (pulse_number<F250PULSE_NUMBER_FILTER) ) { | |||||
3404 | objs->hit_objs.push_back(new Df250PulsePedestal(rocid, slot, channel, itrigger, pulse_number, pedestal, pulse_peak)); | |||||
3405 | } | |||||
3406 | break; | |||||
3407 | case 13: // Event Trailer | |||||
3408 | // This is marked "suppressed for normal readout – debug mode only" in the | |||||
3409 | // current manual (v2). It does not contain any data so the most we could do here | |||||
3410 | // is return early. I'm hesitant to do that though since it would mean | |||||
3411 | // different behavior for debug mode data as regular data. | |||||
3412 | case 14: // Data not valid (empty module) | |||||
3413 | case 15: // Filler (non-data) word | |||||
3414 | if(VERBOSE>7) evioout << " FADC250 Event Trailer, Data not Valid, or Filler word ("<<data_type<<")"<<" ("<<hex<<*iptr<<dec<<")"<<endl; | |||||
3415 | break; | |||||
3416 | } | |||||
3417 | ||||||
3418 | // Once we find a block trailer, assume that is it for this module. | |||||
3419 | if(found_block_trailer){ | |||||
3420 | iptr++; // iptr is still pointing to block trailer. Jump to next word. | |||||
3421 | break; | |||||
3422 | } | |||||
3423 | } | |||||
3424 | ||||||
3425 | // Chop off filler words | |||||
3426 | for(; iptr<iend; iptr++){ | |||||
3427 | if(((*iptr)&0xf8000000) != 0xf8000000) break; | |||||
3428 | } | |||||
3429 | ||||||
3430 | // Add last event in block to list | |||||
3431 | if(objs)events.push_back(objs); | |||||
3432 | ||||||
3433 | // Here, we make object associations to link PulseIntegral, PulseTime, PulseRawData, etc | |||||
3434 | // objects to each other so it is easier to get to these downstream without having to | |||||
3435 | // make nested loops. This is the most efficient place to do it since the ObjList objects | |||||
3436 | // in "event" contain only the objects from this EVIO block (i.e. at most one crate's | |||||
3437 | // worth.) | |||||
3438 | list<ObjList*>::iterator iter = events.begin(); | |||||
3439 | for(; iter!=events.end(); iter++){ | |||||
3440 | ||||||
3441 | // Sort list of objects into type-specific lists | |||||
3442 | vector<DDAQAddress*> &hit_objs = (*iter)->hit_objs; | |||||
3443 | vector<Df250TriggerTime*> vtrigt; | |||||
3444 | vector<Df250WindowRawData*> vwrd; | |||||
3445 | vector<Df250WindowSum*> vws; | |||||
3446 | vector<Df250PulseRawData*> vprd; | |||||
3447 | vector<Df250PulseIntegral*> vpi; | |||||
3448 | vector<Df250PulseTime*> vpt; | |||||
3449 | vector<Df250PulsePedestal*> vpp; | |||||
3450 | for(unsigned int i=0; i<hit_objs.size(); i++){ | |||||
3451 | AddIfAppropriate(hit_objs[i], vtrigt); | |||||
3452 | AddIfAppropriate(hit_objs[i], vwrd); | |||||
3453 | AddIfAppropriate(hit_objs[i], vws); | |||||
3454 | AddIfAppropriate(hit_objs[i], vprd); | |||||
3455 | AddIfAppropriate(hit_objs[i], vpi); | |||||
3456 | AddIfAppropriate(hit_objs[i], vpt); | |||||
3457 | AddIfAppropriate(hit_objs[i], vpp); | |||||
3458 | } | |||||
3459 | ||||||
3460 | // Connect Df250PulseIntegral, Df250PulseTime, and | |||||
3461 | // Df250PulsePedestal with Df250PulseRawData | |||||
3462 | // (n.b. the associations between pi, pt, and pp are | |||||
3463 | // done in GetObjects where emulated objects are | |||||
3464 | // also available.) | |||||
3465 | LinkAssociationsWithPulseNumber(vprd, vpi); | |||||
3466 | LinkAssociationsWithPulseNumber(vprd, vpt); | |||||
3467 | LinkAssociationsWithPulseNumber(vprd, vpp); | |||||
3468 | ||||||
3469 | // Connect Df250WindowSum and Df250WindowRawData | |||||
3470 | LinkAssociations(vwrd, vws); | |||||
3471 | ||||||
3472 | // Connect Df250TriggerTime to everything | |||||
3473 | LinkAssociationsModuleOnly(vtrigt, vwrd); | |||||
3474 | LinkAssociationsModuleOnly(vtrigt, vws); | |||||
3475 | LinkAssociationsModuleOnly(vtrigt, vprd); | |||||
3476 | LinkAssociationsModuleOnly(vtrigt, vpi); | |||||
3477 | LinkAssociationsModuleOnly(vtrigt, vpt); | |||||
3478 | LinkAssociationsModuleOnly(vtrigt, vpp); | |||||
3479 | } | |||||
3480 | } | |||||
3481 | ||||||
3482 | //---------------- | |||||
3483 | // MakeDf250WindowRawData | |||||
3484 | //---------------- | |||||
3485 | void JEventSource_EVIO::MakeDf250WindowRawData(ObjList *objs, uint32_t rocid, uint32_t slot, uint32_t itrigger, const uint32_t* &iptr) | |||||
3486 | { | |||||
3487 | uint32_t channel = (*iptr>>23) & 0x0F; | |||||
3488 | uint32_t window_width = (*iptr>>0) & 0x0FFF; | |||||
3489 | ||||||
3490 | Df250WindowRawData *wrd = new Df250WindowRawData(rocid, slot, channel, itrigger); | |||||
3491 | ||||||
3492 | for(uint32_t isample=0; isample<window_width; isample +=2){ | |||||
3493 | ||||||
3494 | // Advance to next word | |||||
3495 | iptr++; | |||||
3496 | ||||||
3497 | // Make sure this is a data continuation word, if not, stop here | |||||
3498 | if(((*iptr>>31) & 0x1) != 0x0){ | |||||
3499 | iptr--; // calling method expects us to point to last word in block | |||||
3500 | break; | |||||
3501 | } | |||||
3502 | ||||||
3503 | bool invalid_1 = (*iptr>>29) & 0x1; | |||||
3504 | bool invalid_2 = (*iptr>>13) & 0x1; | |||||
3505 | uint16_t sample_1 = 0; | |||||
3506 | uint16_t sample_2 = 0; | |||||
3507 | if(!invalid_1)sample_1 = (*iptr>>16) & 0x1FFF; | |||||
3508 | if(!invalid_2)sample_2 = (*iptr>>0) & 0x1FFF; | |||||
3509 | ||||||
3510 | // Sample 1 | |||||
3511 | wrd->samples.push_back(sample_1); | |||||
3512 | wrd->invalid_samples |= invalid_1; | |||||
3513 | wrd->overflow |= (sample_1>>12) & 0x1; | |||||
3514 | ||||||
3515 | if((isample+2) == window_width && invalid_2)break; // skip last sample if flagged as invalid | |||||
3516 | ||||||
3517 | // Sample 2 | |||||
3518 | wrd->samples.push_back(sample_2); | |||||
3519 | wrd->invalid_samples |= invalid_2; | |||||
3520 | wrd->overflow |= (sample_2>>12) & 0x1; | |||||
3521 | } | |||||
3522 | ||||||
3523 | // Due to how the calling function works, the value of "objs" passed to us may be NULL. | |||||
3524 | // This will happen if a Window Raw Data block is encountered before an event header. | |||||
3525 | // For these cases, we still want to try parsing the data so that the iptr is updated | |||||
3526 | // but don't have an event to assign it to. If "objs" is non-NULL, add this object to | |||||
3527 | // the list. Otherwise, delete it now. | |||||
3528 | if(objs){ | |||||
3529 | objs->hit_objs.push_back(wrd); | |||||
3530 | }else{ | |||||
3531 | delete wrd; | |||||
3532 | } | |||||
3533 | } | |||||
3534 | ||||||
3535 | //---------------- | |||||
3536 | // MakeDf250PulseRawData | |||||
3537 | //---------------- | |||||
3538 | void JEventSource_EVIO::MakeDf250PulseRawData(ObjList *objs, uint32_t rocid, uint32_t slot, uint32_t itrigger, const uint32_t* &iptr) | |||||
3539 | { | |||||
3540 | const uint32_t *istart = iptr; | |||||
3541 | uint32_t channel = (*iptr>>23) & 0x0F; | |||||
3542 | uint32_t pulse_number = (*iptr>>21) & 0x0003; | |||||
3543 | uint32_t first_sample_number = (*iptr>>0) & 0x03FF; | |||||
3544 | ||||||
3545 | if(VERBOSE>9) evioout << " DF250PulseRawData: iptr=0x" << hex << iptr << dec << " channel=" << channel << " pulse_number=" << pulse_number << " first_sample=" << first_sample_number << endl; | |||||
3546 | ||||||
3547 | Df250PulseRawData *prd = new Df250PulseRawData(rocid, slot, channel, itrigger, pulse_number, first_sample_number); | |||||
3548 | ||||||
3549 | // This loop needs to break when it hits a non-continuation word | |||||
3550 | for(uint32_t isample=0; isample<1000; isample +=2){ | |||||
3551 | ||||||
3552 | // Advance to next word | |||||
3553 | iptr++; | |||||
3554 | ||||||
3555 | // Make sure this is a data continuation word, if not, stop here | |||||
3556 | if(((*iptr>>31) & 0x1) != 0x0)break; | |||||
3557 | ||||||
3558 | bool invalid_1 = (*iptr>>29) & 0x1; | |||||
3559 | bool invalid_2 = (*iptr>>13) & 0x1; | |||||
3560 | uint16_t sample_1 = 0; | |||||
3561 | uint16_t sample_2 = 0; | |||||
3562 | if(!invalid_1)sample_1 = (*iptr>>16) & 0x1FFF; | |||||
3563 | if(!invalid_2)sample_2 = (*iptr>>0) & 0x1FFF; | |||||
3564 | ||||||
3565 | // Sample 1 | |||||
3566 | prd->samples.push_back(sample_1); | |||||
3567 | prd->invalid_samples |= invalid_1; | |||||
3568 | prd->overflow |= (sample_1>>12) & 0x1; | |||||
3569 | ||||||
3570 | bool last_word = (iptr[1]>>31) & 0x1; | |||||
3571 | if(last_word && invalid_2)break; // skip last sample if flagged as invalid | |||||
3572 | ||||||
3573 | // Sample 2 | |||||
3574 | prd->samples.push_back(sample_2); | |||||
3575 | prd->invalid_samples |= invalid_2; | |||||
3576 | prd->overflow |= (sample_2>>12) & 0x1; | |||||
3577 | } | |||||
3578 | ||||||
3579 | if(VERBOSE>9) evioout << " number of samples: " << prd->samples.size() << " words processed: " << iptr-istart << endl; | |||||
3580 | ||||||
3581 | // When should get here because the loop above stopped when it found | |||||
3582 | // a data defining word (bit 31=1). The method calling this one will | |||||
3583 | // assume iptr is pointing to the last word of this block and it will | |||||
3584 | // advance to the first word of the next block. We need to back up one | |||||
3585 | // word so that it is pointing to the last word of this block. | |||||
3586 | iptr--; | |||||
3587 | ||||||
3588 | // Due to how the calling function works, the value of "objs" passed to us may be NULL. | |||||
3589 | // This will happen if a Window Raw Data block is encountered before an event header. | |||||
3590 | // For these cases, we still want to try parsing the data so that the iptr is updated | |||||
3591 | // but don't have an event to assign it to. If "objs" is non-NULL, add this object to | |||||
3592 | // the list. Otherwise, delete it now. | |||||
3593 | if(objs){ | |||||
3594 | objs->hit_objs.push_back(prd); | |||||
3595 | }else{ | |||||
3596 | delete prd; | |||||
3597 | } | |||||
3598 | } | |||||
3599 | ||||||
3600 | //---------------- | |||||
3601 | // Parsef125Bank | |||||
3602 | //---------------- | |||||
3603 | void JEventSource_EVIO::Parsef125Bank(int32_t rocid, const uint32_t* &iptr, const uint32_t* iend, list<ObjList*> &events) | |||||
3604 | { | |||||
3605 | /// Parse data from a single FADC125 module. | |||||
3606 | /// This is currently written assuming that the Pulse Integral, Pulse Time, and Pulse Pedestal | |||||
3607 | /// data formats follow what is in the file: | |||||
3608 | /// https://halldweb1.jlab.org/wiki/index.php/File:FADC125_dataformat_250_modes.docx | |||||
3609 | ||||||
3610 | if(!PARSE_F125){ iptr = iend; return; } | |||||
3611 | ||||||
3612 | if(VERBOSE>6) evioout << " Entering Parsef125Bank for rocid=" << rocid << "..."<<endl; | |||||
3613 | ||||||
3614 | // This will get updated to point to a newly allocated object when an | |||||
3615 | // event header is encountered. The existing value (if non-NULL) is | |||||
3616 | // added to the events queue first though so all events are kept. | |||||
3617 | ObjList *objs = NULL__null; | |||||
3618 | ||||||
3619 | // From the Block Header | |||||
3620 | uint32_t slot=0; | |||||
3621 | //uint32_t Nblock_events; | |||||
3622 | //uint32_t iblock; | |||||
3623 | ||||||
3624 | // From the Block Trailer | |||||
3625 | //uint32_t slot_trailer; | |||||
3626 | //uint32_t Nwords_in_block; | |||||
3627 | ||||||
3628 | // From Event header | |||||
3629 | //uint32_t slot_event_header; | |||||
3630 | uint32_t itrigger = -1; | |||||
3631 | uint32_t last_itrigger = -2; | |||||
3632 | uint32_t last_pulse_time_channel=0; | |||||
3633 | uint32_t last_slot = -1; | |||||
3634 | uint32_t last_channel = -1; | |||||
3635 | ||||||
3636 | // Loop over data words | |||||
3637 | for(; iptr<iend; iptr++){ | |||||
3638 | ||||||
3639 | // Skip all non-data-type-defining words at this | |||||
3640 | // level. When we do encounter one, the appropriate | |||||
3641 | // case block below should handle parsing all of | |||||
3642 | // the data continuation words and advance the iptr. | |||||
3643 | if(((*iptr>>31) & 0x1) == 0)continue; | |||||
3644 | ||||||
3645 | // Variables used inside of switch, but cannot be declared inside | |||||
3646 | uint64_t t = 0L; | |||||
3647 | uint32_t channel = 0; | |||||
3648 | uint32_t sum = 0; | |||||
3649 | uint32_t pulse_number = 0; | |||||
3650 | uint32_t pulse_time = 0; | |||||
3651 | uint32_t quality_factor = 0; | |||||
3652 | uint32_t overflow_count = 0; | |||||
3653 | uint32_t pedestal = 0; | |||||
3654 | uint32_t pulse_peak = 0; | |||||
3655 | uint32_t peak_time = 0; | |||||
3656 | uint32_t nsamples_integral = 0; | |||||
3657 | uint32_t nsamples_pedestal = 0; | |||||
3658 | uint32_t word1=0; | |||||
3659 | uint32_t word2=0; | |||||
3660 | ||||||
3661 | bool found_block_trailer = false; | |||||
3662 | uint32_t data_type = (*iptr>>27) & 0x0F; | |||||
3663 | switch(data_type){ | |||||
3664 | case 0: // Block Header | |||||
3665 | slot = (*iptr>>22) & 0x1F; | |||||
3666 | if(VERBOSE>7) evioout << " FADC125 Block Header: slot="<<slot<<endl; | |||||
3667 | //iblock= (*iptr>>8) & 0x03FF; | |||||
3668 | //Nblock_events= (*iptr>>0) & 0xFF; | |||||
3669 | break; | |||||
3670 | case 1: // Block Trailer | |||||
3671 | //slot_trailer = (*iptr>>22) & 0x1F; | |||||
3672 | //Nwords_in_block = (*iptr>>0) & 0x3FFFFF; | |||||
3673 | found_block_trailer = true; | |||||
3674 | break; | |||||
3675 | case 2: // Event Header | |||||
3676 | //slot_event_header = (*iptr>>22) & 0x1F; | |||||
3677 | itrigger = (*iptr>>0) & 0x3FFFFFF; | |||||
3678 | if(VERBOSE>7) evioout << " FADC125 Event Header: itrigger="<<itrigger<<" (objs=0x"<<hex<<objs<<dec<<", last_itrigger="<<last_itrigger<<", rocid="<<rocid<<", slot="<<slot<<")" <<endl; | |||||
3679 | if( (itrigger!=last_itrigger) || (objs==NULL__null) ){ | |||||
3680 | if(ENABLE_DISENTANGLING){ | |||||
3681 | if(objs){ | |||||
3682 | events.push_back(objs); | |||||
3683 | objs = NULL__null; | |||||
3684 | } | |||||
3685 | } | |||||
3686 | if(!objs) objs = new ObjList; | |||||
3687 | last_itrigger = itrigger; | |||||
3688 | } | |||||
3689 | break; | |||||
3690 | case 3: // Trigger Time | |||||
3691 | t = ((*iptr)&0xFFFFFF)<<0; | |||||
3692 | iptr++; | |||||
3693 | if(((*iptr>>31) & 0x1) == 0){ | |||||
3694 | t += ((*iptr)&0xFFFFFF)<<24; // from word on the street: second trigger time word is optional!!?? | |||||
3695 | }else{ | |||||
3696 | iptr--; | |||||
3697 | } | |||||
3698 | if(VERBOSE>7) evioout << " FADC125 Trigger Time (t="<<t<<")"<<endl; | |||||
3699 | if(objs) objs->hit_objs.push_back(new Df125TriggerTime(rocid, slot, itrigger, t)); | |||||
3700 | break; | |||||
3701 | case 4: // Window Raw Data | |||||
3702 | // iptr passed by reference and so will be updated automatically | |||||
3703 | if(VERBOSE>7) evioout << " FADC125 Window Raw Data"<<endl; | |||||
3704 | MakeDf125WindowRawData(objs, rocid, slot, itrigger, iptr); | |||||
3705 | break; | |||||
3706 | ||||||
3707 | case 5: // CDC pulse data (new) (GlueX-doc-2274-v8) | |||||
3708 | ||||||
3709 | // Word 1: | |||||
3710 | word1 = *iptr; | |||||
3711 | channel = (*iptr>>20) & 0x7F; | |||||
3712 | pulse_number = (*iptr>>15) & 0x1F; | |||||
3713 | pulse_time = (*iptr>>4 ) & 0x7FF; | |||||
3714 | quality_factor = (*iptr>>3 ) & 0x1; //time QF bit | |||||
3715 | overflow_count = (*iptr>>0 ) & 0x7; | |||||
3716 | if(VERBOSE>8) evioout << " FADC125 CDC Pulse Data word1: " << hex << (*iptr) << dec << endl; | |||||
3717 | if(VERBOSE>7) evioout << " FADC125 CDC Pulse Data (chan="<<channel<<" pulse="<<pulse_number<<" time="<<pulse_time<<" QF="<<quality_factor<<" OC="<<overflow_count<<")"<<endl; | |||||
3718 | ||||||
3719 | // Word 2: | |||||
3720 | ++iptr; | |||||
3721 | if(iptr>=iend){ | |||||
3722 | jerr << " Truncated f125 CDC hit (block ends before continuation word!)" << endl; | |||||
3723 | continue; | |||||
3724 | } | |||||
3725 | if( ((*iptr>>31) & 0x1) != 0 ){ | |||||
3726 | jerr << " Truncated f125 CDC hit (missing continuation word!)" << endl; | |||||
3727 | continue; | |||||
3728 | } | |||||
3729 | word2 = *iptr; | |||||
3730 | pedestal = (*iptr>>23) & 0xFF; | |||||
3731 | sum = (*iptr>>9 ) & 0x3FFF; | |||||
3732 | pulse_peak = (*iptr>>0 ) & 0x1FF; | |||||
3733 | if(VERBOSE>8) evioout << " FADC125 CDC Pulse Data word2: " << hex << (*iptr) << dec << endl; | |||||
3734 | if(VERBOSE>7) evioout << " FADC125 CDC Pulse Data (pedestal="<<pedestal<<" sum="<<sum<<" peak="<<pulse_peak<<")"<<endl; | |||||
3735 | ||||||
3736 | // Create hit objects | |||||
3737 | nsamples_integral = 0; // must be overwritten later in GetObjects with value from Df125Config value | |||||
3738 | nsamples_pedestal = 1; // The firmware pedestal divided by 2^PBIT where PBIT is a config. parameter | |||||
3739 | ||||||
3740 | if( (objs!=NULL__null) && (pulse_number<F125PULSE_NUMBER_FILTER) ) { | |||||
3741 | // n.b. This is were we might apply a check on whether we are | |||||
3742 | // only producing emulated objects. If so, then we shouldn't | |||||
3743 | // create the Df125CDCPulse. At this point in time though, | |||||
3744 | // there are 3 config. parameters that control this because | |||||
3745 | // the original firmware produced 3 separate data types as | |||||
3746 | // opposed to the new firmware that puts the same infomation | |||||
3747 | // into a single data type. The emulation framework is also | |||||
3748 | // being revamped. | |||||
3749 | objs->hit_objs.push_back( new Df125CDCPulse(rocid, slot, channel, itrigger | |||||
3750 | , pulse_number // NPK | |||||
3751 | , pulse_time // le_time | |||||
3752 | , quality_factor // time_quality_bit | |||||
3753 | , overflow_count // overflow_count | |||||
3754 | , pedestal // pedestal | |||||
3755 | , sum // integral | |||||
3756 | , pulse_peak // first_max_amp | |||||
3757 | , word1 // word1 | |||||
3758 | , word2 // word2 | |||||
3759 | , nsamples_pedestal // nsamples_pedestal | |||||
3760 | , nsamples_integral // nsamples_integral | |||||
3761 | , false) // emulated | |||||
3762 | ); | |||||
3763 | } | |||||
3764 | ||||||
3765 | // n.b. We don't record last_slot, last_channel, etc... here since those | |||||
3766 | // are only used by data types corresponding to older firmware that did | |||||
3767 | // not write out data type 5. | |||||
3768 | break; | |||||
3769 | ||||||
3770 | case 6: // FDC pulse data-integral (new) (GlueX-doc-2274-v8) | |||||
3771 | ||||||
3772 | // Word 1: | |||||
3773 | word1 = *iptr; | |||||
3774 | channel = (*iptr>>20) & 0x7F; | |||||
3775 | pulse_number = (*iptr>>15) & 0x1F; | |||||
3776 | pulse_time = (*iptr>>4 ) & 0x7FF; | |||||
3777 | quality_factor = (*iptr>>3 ) & 0x1; //time QF bit | |||||
3778 | overflow_count = (*iptr>>0 ) & 0x7; | |||||
3779 | if(VERBOSE>8) evioout << " FADC125 FDC Pulse Data(integral) word1: " << hex << (*iptr) << dec << endl; | |||||
3780 | if(VERBOSE>7) evioout << " FADC125 FDC Pulse Data (chan="<<channel<<" pulse="<<pulse_number<<" time="<<pulse_time<<" QF="<<quality_factor<<" OC="<<overflow_count<<")"<<endl; | |||||
3781 | ||||||
3782 | // Word 2: | |||||
3783 | ++iptr; | |||||
3784 | if(iptr>=iend){ | |||||
3785 | jerr << " Truncated f125 FDC hit (block ends before continuation word!)" << endl; | |||||
3786 | continue; | |||||
3787 | } | |||||
3788 | if( ((*iptr>>31) & 0x1) != 0 ){ | |||||
3789 | jerr << " Truncated f125 FDC hit (missing continuation word!)" << endl; | |||||
3790 | continue; | |||||
3791 | } | |||||
3792 | word2 = *iptr; | |||||
3793 | pulse_peak = 0; | |||||
3794 | sum = (*iptr>>19) & 0xFFF; | |||||
3795 | peak_time = (*iptr>>11) & 0xFF; | |||||
3796 | pedestal = (*iptr>>0 ) & 0x7FF; | |||||
3797 | if(VERBOSE>8) evioout << " FADC125 FDC Pulse Data(integral) word2: " << hex << (*iptr) << dec << endl; | |||||
3798 | if(VERBOSE>7) evioout << " FADC125 FDC Pulse Data (integral="<<sum<<" time="<<peak_time<<" pedestal="<<pedestal<<")"<<endl; | |||||
3799 | ||||||
3800 | // Create hit objects | |||||
3801 | nsamples_integral = 0; // must be overwritten later in GetObjects with value from Df125Config value | |||||
3802 | nsamples_pedestal = 1; // The firmware pedestal divided by 2^PBIT where PBIT is a config. parameter | |||||
3803 | ||||||
3804 | if( (objs!=NULL__null) && (pulse_number<F125PULSE_NUMBER_FILTER) ) { | |||||
3805 | // n.b. This is were we might apply a check on whether we are | |||||
3806 | // only producing emulated objects. If so, then we shouldn't | |||||
3807 | // create the Df125FDCPulse. At this point in time though, | |||||
3808 | // there are 3 config. parameters that control this because | |||||
3809 | // the original firmware produced 3 separate data types as | |||||
3810 | // opposed to the new firmware that puts the same infomation | |||||
3811 | // into a single data type. The emulation framework is also | |||||
3812 | // being revamped. | |||||
3813 | objs->hit_objs.push_back( new Df125FDCPulse(rocid, slot, channel, itrigger | |||||
3814 | , pulse_number // NPK | |||||
3815 | , pulse_time // le_time | |||||
3816 | , quality_factor // time_quality_bit | |||||
3817 | , overflow_count // overflow_count | |||||
3818 | , pedestal // pedestal | |||||
3819 | , sum // integral | |||||
3820 | , pulse_peak // peak_amp | |||||
3821 | , peak_time // peak_time | |||||
3822 | , word1 // word1 | |||||
3823 | , word2 // word2 | |||||
3824 | , nsamples_pedestal // nsamples_pedestal | |||||
3825 | , nsamples_integral // nsamples_integral | |||||
3826 | , false) // emulated | |||||
3827 | ); | |||||
3828 | } | |||||
3829 | ||||||
3830 | // n.b. We don't record last_slot, last_channel, etc... here since those | |||||
3831 | // are only used by data types corresponding to older firmware that did | |||||
3832 | // not write out data type 6. | |||||
3833 | break; | |||||
3834 | ||||||
3835 | case 7: // Pulse Integral | |||||
3836 | if(VERBOSE>7) evioout << " FADC125 Pulse Integral"<<endl; | |||||
3837 | channel = (*iptr>>20) & 0x7F; | |||||
3838 | sum = (*iptr>>0) & 0xFFFFF; | |||||
3839 | nsamples_integral = 0; // must be overwritten later in GetObjects with value from Df125Config value | |||||
3840 | nsamples_pedestal = 1; // The firmware returns an already divided pedestal | |||||
3841 | pedestal = 0; // This will be replaced by the one from Df250PulsePedestal in GetObjects | |||||
3842 | if (last_slot == slot && last_channel == channel) pulse_number = 1; | |||||
3843 | last_slot = slot; | |||||
3844 | last_channel = channel; | |||||
3845 | if( (objs!=NULL__null) && (pulse_number<F125PULSE_NUMBER_FILTER) ) { | |||||
3846 | objs->hit_objs.push_back(new Df125PulseIntegral(rocid, slot, channel, itrigger, pulse_number, | |||||
3847 | quality_factor, sum, pedestal, nsamples_integral, nsamples_pedestal)); | |||||
3848 | } | |||||
3849 | break; | |||||
3850 | case 8: // Pulse Time | |||||
3851 | if(VERBOSE>7) evioout << " FADC125 Pulse Time"<<endl; | |||||
3852 | channel = (*iptr>>20) & 0x7F; | |||||
3853 | pulse_number = (*iptr>>18) & 0x03; | |||||
3854 | pulse_time = (*iptr>>0) & 0xFFFF; | |||||
3855 | if( (objs!=NULL__null) && (pulse_number<F125PULSE_NUMBER_FILTER) ) { | |||||
3856 | objs->hit_objs.push_back(new Df125PulseTime(rocid, slot, channel, itrigger, pulse_number, quality_factor, pulse_time)); | |||||
3857 | } | |||||
3858 | last_pulse_time_channel = channel; | |||||
3859 | break; | |||||
3860 | ||||||
3861 | case 9: // FDC pulse data-peak (new) (GlueX-doc-2274-v8) | |||||
3862 | ||||||
3863 | // Word 1: | |||||
3864 | word1 = *iptr; | |||||
3865 | channel = (*iptr>>20) & 0x7F; | |||||
3866 | pulse_number = (*iptr>>15) & 0x1F; | |||||
3867 | pulse_time = (*iptr>>4 ) & 0x7FF; | |||||
3868 | quality_factor = (*iptr>>3 ) & 0x1; //time QF bit | |||||
3869 | overflow_count = (*iptr>>0 ) & 0x7; | |||||
3870 | if(VERBOSE>8) evioout << " FADC125 FDC Pulse Data(peak) word1: " << hex << (*iptr) << dec << endl; | |||||
3871 | if(VERBOSE>7) evioout << " FADC125 FDC Pulse Data (chan="<<channel<<" pulse="<<pulse_number<<" time="<<pulse_time<<" QF="<<quality_factor<<" OC="<<overflow_count<<")"<<endl; | |||||
3872 | ||||||
3873 | // Word 2: | |||||
3874 | ++iptr; | |||||
3875 | if(iptr>=iend){ | |||||
3876 | jerr << " Truncated f125 FDC hit (block ends before continuation word!)" << endl; | |||||
3877 | continue; | |||||
3878 | } | |||||
3879 | if( ((*iptr>>31) & 0x1) != 0 ){ | |||||
3880 | jerr << " Truncated f125 FDC hit (missing continuation word!)" << endl; | |||||
3881 | continue; | |||||
3882 | } | |||||
3883 | word2 = *iptr; | |||||
3884 | pulse_peak = (*iptr>>19) & 0xFFF; | |||||
3885 | sum = 0; | |||||
3886 | peak_time = (*iptr>>11) & 0xFF; | |||||
3887 | pedestal = (*iptr>>0 ) & 0x7FF; | |||||
3888 | if(VERBOSE>8) evioout << " FADC125 FDC Pulse Data(peak) word2: " << hex << (*iptr) << dec << endl; | |||||
3889 | if(VERBOSE>7) evioout << " FADC125 FDC Pulse Data (integral="<<sum<<" time="<<peak_time<<" pedestal="<<pedestal<<")"<<endl; | |||||
3890 | ||||||
3891 | // Create hit objects | |||||
3892 | nsamples_integral = 0; // must be overwritten later in GetObjects with value from Df125Config value | |||||
3893 | nsamples_pedestal = 1; // The firmware pedestal divided by 2^PBIT where PBIT is a config. parameter | |||||
3894 | ||||||
3895 | if( (objs!=NULL__null) && (pulse_number<F125PULSE_NUMBER_FILTER) ) { | |||||
3896 | // n.b. This is were we might apply a check on whether we are | |||||
3897 | // only producing emulated objects. If so, then we shouldn't | |||||
3898 | // create the Df125FDCPulse. At this point in time though, | |||||
3899 | // there are 3 config. parameters that control this because | |||||
3900 | // the original firmware produced 3 separate data types as | |||||
3901 | // opposed to the new firmware that puts the same infomation | |||||
3902 | // into a single data type. The emulation framework is also | |||||
3903 | // being revamped. | |||||
3904 | objs->hit_objs.push_back( new Df125FDCPulse(rocid, slot, channel, itrigger | |||||
3905 | , pulse_number // NPK | |||||
3906 | , pulse_time // le_time | |||||
3907 | , quality_factor // time_quality_bit | |||||
3908 | , overflow_count // overflow_count | |||||
3909 | , pedestal // pedestal | |||||
3910 | , sum // integral | |||||
3911 | , pulse_peak // peak_amp | |||||
3912 | , peak_time // peak_time | |||||
3913 | , word1 // word1 | |||||
3914 | , word2 // word2 | |||||
3915 | , nsamples_pedestal // nsamples_pedestal | |||||
3916 | , nsamples_integral // nsamples_integral | |||||
3917 | , false) // emulated | |||||
3918 | ); | |||||
3919 | } | |||||
3920 | ||||||
3921 | // n.b. We don't record last_slot, last_channel, etc... here since those | |||||
3922 | // are only used by data types corresponding to older firmware that did | |||||
3923 | // not write out data type 6. | |||||
3924 | break; | |||||
3925 | ||||||
3926 | case 10: // Pulse Pedestal (consistent with Beni's hand-edited version of Cody's document) | |||||
3927 | if(VERBOSE>7) evioout << " FADC125 Pulse Pedestal"<<endl; | |||||
3928 | //channel = (*iptr>>20) & 0x7F; | |||||
3929 | channel = last_pulse_time_channel; // not enough bits to hold channel number so rely on proximity to Pulse Time in data stream (see "FADC125 dataformat 250 modes.docx") | |||||
3930 | pulse_number = (*iptr>>21) & 0x03; | |||||
3931 | pedestal = (*iptr>>12) & 0x1FF; | |||||
3932 | pulse_peak = (*iptr>>0) & 0xFFF; | |||||
3933 | nsamples_pedestal = 1; // The firmware returns an already divided pedestal | |||||
3934 | if( (objs!=NULL__null) && (pulse_number<F125PULSE_NUMBER_FILTER) ) { | |||||
3935 | objs->hit_objs.push_back(new Df125PulsePedestal(rocid, slot, channel, itrigger, pulse_number, pedestal, pulse_peak, nsamples_pedestal)); | |||||
3936 | } | |||||
3937 | break; | |||||
3938 | ||||||
3939 | case 13: // Event Trailer | |||||
3940 | case 14: // Data not valid (empty module) | |||||
3941 | case 15: // Filler (non-data) word | |||||
3942 | if(VERBOSE>7) evioout << " FADC125 ignored data type: " << data_type <<endl; | |||||
3943 | break; | |||||
3944 | } | |||||
3945 | ||||||
3946 | // Once we find a block trailer, assume that is it for this module. | |||||
3947 | if(found_block_trailer){ | |||||
3948 | iptr++; // iptr is still pointing to block trailer. Jump to next word. | |||||
3949 | break; | |||||
3950 | } | |||||
3951 | } | |||||
3952 | ||||||
3953 | // Chop off filler words | |||||
3954 | for(; iptr<iend; iptr++){ | |||||
3955 | if(((*iptr)&0xf8000000) != 0xf8000000) break; | |||||
3956 | } | |||||
3957 | ||||||
3958 | // Add last event in block to list | |||||
3959 | if(objs)events.push_back(objs); | |||||
3960 | ||||||
3961 | // Here, we make object associations to link PulseIntegral, PulseTime, PulseRawData, etc | |||||
3962 | // objects to each other so it is easier to get to these downstream without having to | |||||
3963 | // make nested loops. This is the most efficient place to do it since the ObjList objects | |||||
3964 | // in "event" contain only the objects from this EVIO block (i.e. at most one crate's | |||||
3965 | // worth.) | |||||
3966 | list<ObjList*>::iterator iter = events.begin(); | |||||
3967 | for(; iter!=events.end(); iter++){ | |||||
3968 | ||||||
3969 | // Sort list of objects into type-specific lists | |||||
3970 | vector<DDAQAddress*> &hit_objs = (*iter)->hit_objs; | |||||
3971 | vector<Df125TriggerTime*> vtrigt; | |||||
3972 | vector<Df125WindowRawData*> vwrd; | |||||
3973 | vector<Df125PulseRawData*> vprd; | |||||
3974 | vector<Df125PulseIntegral*> vpi; | |||||
3975 | vector<Df125PulseTime*> vpt; | |||||
3976 | vector<Df125PulsePedestal*> vpp; | |||||
3977 | for(unsigned int i=0; i<hit_objs.size(); i++){ | |||||
3978 | AddIfAppropriate(hit_objs[i], vtrigt); | |||||
3979 | AddIfAppropriate(hit_objs[i], vwrd); | |||||
3980 | AddIfAppropriate(hit_objs[i], vprd); | |||||
3981 | AddIfAppropriate(hit_objs[i], vpi); | |||||
3982 | AddIfAppropriate(hit_objs[i], vpt); | |||||
3983 | AddIfAppropriate(hit_objs[i], vpp); | |||||
3984 | } | |||||
3985 | ||||||
3986 | // Connect Df125PulseIntegral with Df125PulseTime | |||||
3987 | LinkAssociationsWithPulseNumber(vprd, vpi); | |||||
3988 | LinkAssociationsWithPulseNumber(vprd, vpt); | |||||
3989 | LinkAssociationsWithPulseNumber(vprd, vpp); | |||||
3990 | LinkAssociationsWithPulseNumber(vpi, vpt); | |||||
3991 | LinkAssociationsWithPulseNumber(vpi, vpp); | |||||
3992 | LinkAssociationsWithPulseNumber(vpt, vpp); | |||||
3993 | ||||||
3994 | // Connect Df125TriggerTime to everything | |||||
3995 | LinkAssociationsModuleOnly(vtrigt, vwrd); | |||||
3996 | LinkAssociationsModuleOnly(vtrigt, vprd); | |||||
3997 | LinkAssociationsModuleOnly(vtrigt, vpi); | |||||
3998 | LinkAssociationsModuleOnly(vtrigt, vpt); | |||||
3999 | LinkAssociationsModuleOnly(vtrigt, vpp); | |||||
4000 | } | |||||
4001 | ||||||
4002 | if(VERBOSE>6) evioout << " Leaving Parsef125Bank"<<endl; | |||||
4003 | } | |||||
4004 | ||||||
4005 | //---------------- | |||||
4006 | // MakeDf125WindowRawData | |||||
4007 | //---------------- | |||||
4008 | void JEventSource_EVIO::MakeDf125WindowRawData(ObjList *objs, uint32_t rocid, uint32_t slot, uint32_t itrigger, const uint32_t* &iptr) | |||||
4009 | { | |||||
4010 | uint32_t channel = (*iptr>>20) & 0x7F; | |||||
4011 | uint32_t window_width = (*iptr>>0) & 0x0FFF; | |||||
4012 | ||||||
4013 | Df125WindowRawData *wrd = new Df125WindowRawData(rocid, slot, channel, itrigger); | |||||
4014 | ||||||
4015 | for(uint32_t isample=0; isample<window_width; isample +=2){ | |||||
4016 | ||||||
4017 | // Advance to next word | |||||
4018 | iptr++; | |||||
4019 | ||||||
4020 | // Make sure this is a data continuation word, if not, stop here | |||||
4021 | if(((*iptr>>31) & 0x1) != 0x0)break; | |||||
4022 | ||||||
4023 | bool invalid_1 = (*iptr>>29) & 0x1; | |||||
4024 | bool invalid_2 = (*iptr>>13) & 0x1; | |||||
4025 | uint16_t sample_1 = 0; | |||||
4026 | uint16_t sample_2 = 0; | |||||
4027 | if(!invalid_1)sample_1 = (*iptr>>16) & 0x1FFF; | |||||
4028 | if(!invalid_2)sample_2 = (*iptr>>0) & 0x1FFF; | |||||
4029 | ||||||
4030 | // Sample 1 | |||||
4031 | wrd->samples.push_back(sample_1); | |||||
4032 | wrd->invalid_samples |= invalid_1; | |||||
4033 | wrd->overflow |= (sample_1>>12) & 0x1; | |||||
4034 | ||||||
4035 | if((isample+2) == window_width && invalid_2)break; // skip last sample if flagged as invalid | |||||
4036 | ||||||
4037 | // Sample 2 | |||||
4038 | wrd->samples.push_back(sample_2); | |||||
4039 | wrd->invalid_samples |= invalid_2; | |||||
4040 | wrd->overflow |= (sample_2>>12) & 0x1; | |||||
4041 | } | |||||
4042 | ||||||
4043 | if(VERBOSE>7) evioout << " FADC125 - " << wrd->samples.size() << " samples" << endl; | |||||
4044 | ||||||
4045 | // Due to how the calling function works, the value of "objs" passed to us may be NULL. | |||||
4046 | // This will happen if a Window Raw Data block is encountered before an event header. | |||||
4047 | // For these cases, we still want to try parsing the data so that the iptr is updated | |||||
4048 | // but don't have an event to assign it to. If "objs" is non-NULL, add this object to | |||||
4049 | // the list. Otherwise, delete it now. | |||||
4050 | if(objs){ | |||||
4051 | objs->hit_objs.push_back(wrd); | |||||
4052 | }else{ | |||||
4053 | delete wrd; | |||||
4054 | } | |||||
4055 | } | |||||
4056 | ||||||
4057 | //---------------- | |||||
4058 | // MakeDf125PulseRawData | |||||
4059 | //---------------- | |||||
4060 | void JEventSource_EVIO::MakeDf125PulseRawData(ObjList *objs, uint32_t rocid, uint32_t slot, uint32_t itrigger, const uint32_t* &iptr) | |||||
4061 | { | |||||
4062 | uint32_t channel = (*iptr>>23) & 0x0F; | |||||
4063 | uint32_t pulse_number = (*iptr>>21) & 0x000F; | |||||
4064 | uint32_t first_sample_number = (*iptr>>0) & 0x03FF; | |||||
4065 | ||||||
4066 | Df125PulseRawData *prd = new Df125PulseRawData(rocid, slot, channel, itrigger, pulse_number, first_sample_number); | |||||
4067 | ||||||
4068 | // This loop needs to break when it hits a non-continuation word | |||||
4069 | for(uint32_t isample=0; isample<1000; isample +=2){ | |||||
4070 | ||||||
4071 | // Advance to next word | |||||
4072 | iptr++; | |||||
4073 | ||||||
4074 | // Make sure this is a data continuation word, if not, stop here | |||||
4075 | if(((*iptr>>31) & 0x1) != 0x0)break; | |||||
4076 | ||||||
4077 | bool invalid_1 = (*iptr>>29) & 0x1; | |||||
4078 | bool invalid_2 = (*iptr>>13) & 0x1; | |||||
4079 | uint16_t sample_1 = 0; | |||||
4080 | uint16_t sample_2 = 0; | |||||
4081 | if(!invalid_1)sample_1 = (*iptr>>16) & 0x1FFF; | |||||
4082 | if(!invalid_2)sample_2 = (*iptr>>0) & 0x1FFF; | |||||
4083 | ||||||
4084 | // Sample 1 | |||||
4085 | prd->samples.push_back(sample_1); | |||||
4086 | prd->invalid_samples |= invalid_1; | |||||
4087 | prd->overflow |= (sample_1>>12) & 0x1; | |||||
4088 | ||||||
4089 | bool last_word = (iptr[1]>>31) & 0x1; | |||||
4090 | if(last_word && invalid_2)break; // skip last sample if flagged as invalid | |||||
4091 | ||||||
4092 | // Sample 2 | |||||
4093 | prd->samples.push_back(sample_2); | |||||
4094 | prd->invalid_samples |= invalid_2; | |||||
4095 | prd->overflow |= (sample_2>>12) & 0x1; | |||||
4096 | } | |||||
4097 | ||||||
4098 | ||||||
4099 | // Due to how the calling function works, the value of "objs" passed to us may be NULL. | |||||
4100 | // This will happen if a Window Raw Data block is encountered before an event header. | |||||
4101 | // For these cases, we still want to try parsing the data so that the iptr is updated | |||||
4102 | // but don't have an event to assign it to. If "objs" is non-NULL, add this object to | |||||
4103 | // the list. Otherwise, delete it now. | |||||
4104 | if(objs){ | |||||
4105 | objs->hit_objs.push_back(prd); | |||||
4106 | }else{ | |||||
4107 | delete prd; | |||||
4108 | } | |||||
4109 | } | |||||
4110 | ||||||
4111 | //---------------- | |||||
4112 | // ParseF1TDCBank | |||||
4113 | //---------------- | |||||
4114 | void JEventSource_EVIO::ParseF1TDCBank(int32_t rocid, const uint32_t* &iptr, const uint32_t* iend, list<ObjList*> &events) | |||||
4115 | { | |||||
4116 | /// Parse data from a single F1TDCv2 (32 ch) or F1TDCv3 (48 ch) module. | |||||
4117 | /// This code is based on the document F1TDC_V2_V3_4_29_14.pdf obtained from: | |||||
4118 | /// https://coda.jlab.org/wiki/index.php/JLab_Module_Manuals | |||||
4119 | ||||||
4120 | if(!PARSE_F1TDC){ iptr = iend; return; } | |||||
4121 | ||||||
4122 | if(VERBOSE>6) evioout << " Entering ParseF1TDCBank (rocid=" << rocid << ")" << endl; | |||||
4123 | ||||||
4124 | const uint32_t *istart = iptr; | |||||
4125 | ||||||
4126 | // Some early data had a marker word at just before the actual F1 data | |||||
4127 | if(*iptr == 0xf1daffff) iptr++; | |||||
4128 | ||||||
4129 | // Block header word | |||||
4130 | // Double check that block header is set | |||||
4131 | if( ((*iptr) & 0xF8000000) != 0x80000000 ){ | |||||
4132 | throw JException("F1TDC Block header corrupt! (high 5 bits not set to 0x80000000!)"); | |||||
4133 | } | |||||
4134 | ||||||
4135 | uint32_t slot_block_header = (*iptr)>>22 & 0x001F; | |||||
4136 | uint32_t block_num = (*iptr)>> 8 & 0x03FF; | |||||
4137 | uint32_t Nevents_block_header = (*iptr)>> 0 & 0x00FF; | |||||
4138 | int modtype = (*iptr)>>18 & 0x000F; // should match a DModuleType::type_id_t | |||||
4139 | if(VERBOSE>5) evioout << " F1 Block Header: slot=" << slot_block_header << " block_num=" << block_num << " Nevents=" << Nevents_block_header << endl; | |||||
4140 | ||||||
4141 | // Advance to next word | |||||
4142 | iptr++; | |||||
4143 | ||||||
4144 | // Loop over events | |||||
4145 | ObjList *objs = NULL__null; | |||||
4146 | while(iptr<iend){ | |||||
4147 | ||||||
4148 | // Event header | |||||
4149 | // Double check that event header is set | |||||
4150 | if( ((*iptr) & 0xF8000000) != 0x90000000 ){ | |||||
4151 | if(VERBOSE>10){ | |||||
4152 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<4152<<" "<<"Corrupt F1TDC Event header! Data dump follows (\"*\" indicates bad header word):" <<endl; | |||||
4153 | DumpBinary(istart, iend, 0, iptr); | |||||
4154 | } | |||||
4155 | throw JException("F1TDC Event header corrupt! (high 5 bits not set to 0x90000000!)"); | |||||
4156 | } | |||||
4157 | ||||||
4158 | uint32_t slot_event_header = (*iptr)>>22 & 0x00000001F; | |||||
4159 | uint32_t itrigger = (*iptr)>>0 & 0x0003FFFFF; | |||||
4160 | if(VERBOSE>5) evioout << " F1 Event Header: slot=" << slot_block_header << " itrigger=" << itrigger << endl; | |||||
4161 | ||||||
4162 | // Make sure slot number from event header matches block header | |||||
4163 | if(slot_event_header != slot_block_header){ | |||||
4164 | char str[256]; | |||||
4165 | sprintf(str, "F1TDC slot from event header(%d) doesn't match block header(%d)", slot_event_header, slot_block_header); | |||||
4166 | throw JException(str); | |||||
4167 | } | |||||
4168 | ||||||
4169 | // Advance to timestamp word | |||||
4170 | iptr++; | |||||
4171 | if(iptr>=iend) throw JException("F1TDC data corrupt! Block truncated before timestamp word!"); | |||||
4172 | ||||||
4173 | // The most recent documentation says that the first time stamp | |||||
4174 | // word holds the low 24 bits and the second the high 16 bits. According to Dave A., | |||||
4175 | // the second word is optional. | |||||
4176 | uint32_t trig_time = ((*iptr)&0xFFFFFF); | |||||
4177 | if(VERBOSE>6) evioout << " F1 Trigger time: low 24 bits=" << trig_time << endl; | |||||
4178 | iptr++; | |||||
4179 | if(iptr>=iend) throw JException("F1TDC data corrupt! Block truncated before trailer word!"); | |||||
4180 | if(((*iptr>>31) & 0x1) == 0){ | |||||
4181 | trig_time += ((*iptr)&0xFFFF)<<24; // from word on the street: second trigger time word is optional!!?? | |||||
4182 | if(VERBOSE>6) evioout << " F1 Trigger time: high 16 bits=" << ((*iptr)&0xFFFF) << " total trig_time=" << trig_time << endl; | |||||
4183 | }else{ | |||||
4184 | iptr--; // second time word not present, back up pointer | |||||
4185 | } | |||||
4186 | ||||||
4187 | // Create a new object list (i.e. new event) | |||||
4188 | if(objs!=NULL__null && ENABLE_DISENTANGLING){ | |||||
4189 | events.push_back(objs); | |||||
4190 | objs = NULL__null; | |||||
4191 | } | |||||
4192 | if(!objs) objs = new ObjList; | |||||
4193 | ||||||
4194 | if(objs) objs->hit_objs.push_back(new DF1TDCTriggerTime(rocid, slot_block_header, itrigger, trig_time)); | |||||
4195 | ||||||
4196 | // Advance past last timestamp word to first data word (or rather, F1 chip header) | |||||
4197 | iptr++; | |||||
4198 | ||||||
4199 | // Loop over F1 data words | |||||
4200 | uint32_t chip_f1header=0, chan_on_chip_f1header=0, itrigger_f1header=0, trig_time_f1header=0; | |||||
4201 | while( iptr<iend && ((*iptr)>>31)==0x1 ){ | |||||
4202 | ||||||
4203 | bool done = false; | |||||
4204 | ||||||
4205 | uint32_t chip, chan_on_chip, time; | |||||
4206 | uint32_t channel; | |||||
4207 | DF1TDCHit *hit=NULL__null; | |||||
4208 | switch( (*iptr) & 0xF8000000 ){ | |||||
4209 | case 0xC0000000: // F1 Header | |||||
4210 | chip_f1header = ((*iptr)>> 3) & 0x07; | |||||
4211 | chan_on_chip_f1header = ((*iptr)>> 0) & 0x07; // this is always 7 in real data! | |||||
4212 | itrigger_f1header = ((*iptr)>>16) & 0x3F; | |||||
4213 | trig_time_f1header = ((*iptr)>> 7) & 0x1FF; | |||||
4214 | if(VERBOSE>5) evioout << " Found F1 header: chip=" << chip_f1header << " chan=" << chan_on_chip_f1header << " itrig=" << itrigger_f1header << " trig_time=" << trig_time_f1header << endl; | |||||
4215 | //if( itrigger_f1header != (itrigger & 0x3F)) throw JException("Trigger number in F1 header word does not match Event header word!"); | |||||
4216 | break; | |||||
4217 | case 0xB8000000: // F1 Data | |||||
4218 | chip = (*iptr>>19) & 0x07; | |||||
4219 | chan_on_chip = (*iptr>>16) & 0x07; | |||||
4220 | time = (*iptr>> 0) & 0xFFFF; | |||||
4221 | if(VERBOSE>5) evioout << " Found F1 data : chip=" << chip << " chan=" << chan_on_chip << " time=" << time << " (header: chip=" << chip_f1header << ")" << endl; | |||||
4222 | //if(chip!=chip_f1header) throw JException("F1 chip number in data does not match header!"); | |||||
4223 | channel = F1TDC_channel(chip, chan_on_chip, modtype); | |||||
4224 | hit = new DF1TDCHit(rocid, slot_block_header, channel, itrigger, trig_time_f1header, time, *iptr, MODULE_TYPE(modtype)); | |||||
4225 | if(objs)objs->hit_objs.push_back(hit); | |||||
4226 | break; | |||||
4227 | case 0xF8000000: // Filler word | |||||
4228 | if(VERBOSE>7) evioout << " Found F1 filler word" << endl; | |||||
4229 | break; | |||||
4230 | case 0x80000000: // JLab block header (handled in outer loop) | |||||
4231 | case 0x88000000: // JLab block trailer (handled in outer loop) | |||||
4232 | case 0x90000000: // JLab event header (handled in outer loop) | |||||
4233 | case 0x98000000: // Trigger time (handled in outer loop) | |||||
4234 | case 0xF0000000: // module has no valid data available for read out (how to handle this?) | |||||
4235 | if(VERBOSE>5) evioout << " Found F1 break word: 0x" << hex << *iptr << dec << endl; | |||||
4236 | done = true; | |||||
4237 | break; | |||||
4238 | default: | |||||
4239 | cerr<<endl; | |||||
4240 | cout.flush(); cerr.flush(); | |||||
4241 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<4241<<" "<<"Unknown data word in F1TDC block. Dumping for debugging:" << endl; | |||||
4242 | for(const uint32_t *iiptr = istart; iiptr<iend; iiptr++){ | |||||
4243 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<4243<<" "<<"0x"<<hex<<*iiptr<<dec; | |||||
4244 | if(iiptr == iptr)cerr<<" <----"; | |||||
4245 | switch( (*iiptr) & 0xF8000000 ){ | |||||
4246 | case 0x80000000: cerr << " F1 Block Header"; break; | |||||
4247 | case 0x90000000: cerr << " F1 Event Header"; break; | |||||
4248 | case 0x98000000: cerr << " F1 Trigger time"; break; | |||||
4249 | case 0xC0000000: cerr << " F1 Header"; break; | |||||
4250 | case 0xB8000000: cerr << " F1 Data"; break; | |||||
4251 | case 0x88000000: cerr << " F1 Block Trailer"; break; | |||||
4252 | case 0xF8000000: cerr << " Filler word"; break; | |||||
4253 | case 0xF0000000: cerr << " <module has no valid data>"; break; | |||||
4254 | default: break; | |||||
4255 | } | |||||
4256 | cerr<<endl; | |||||
4257 | if(iiptr > (iptr+4)) break; | |||||
4258 | } | |||||
4259 | ||||||
4260 | throw JException("Unexpected word type in F1TDC block!"); | |||||
4261 | } | |||||
4262 | ||||||
4263 | if(done)break; | |||||
4264 | ||||||
4265 | // Advance to next data word | |||||
4266 | iptr++; | |||||
4267 | ||||||
4268 | } // end loop over data words in this event | |||||
4269 | ||||||
4270 | // If the current word is a JLab block trailer, then we are done | |||||
4271 | if( ((*iptr) & 0xF8000000) == 0x88000000) break; | |||||
4272 | ||||||
4273 | } // end loop over events | |||||
4274 | ||||||
4275 | // Add hits for last event to list of events. | |||||
4276 | if(objs)events.push_back(objs); | |||||
4277 | ||||||
4278 | if( ((*iptr) & 0xF8000000) != 0x88000000 ){ | |||||
4279 | throw JException("F1TDC Block Trailer corrupt! (high 5 bits not set to 0x88000000!)"); | |||||
4280 | } | |||||
4281 | ||||||
4282 | // Advance past JLab block trailer | |||||
4283 | iptr++; | |||||
4284 | ||||||
4285 | // Skip filler words | |||||
4286 | while(iptr<iend && (*iptr&0xF8000000)==0xF8000000)iptr++; | |||||
4287 | ||||||
4288 | // Double check that we found all of the events we were supposed to | |||||
4289 | if(!ENABLE_DISENTANGLING) Nevents_block_header=1; | |||||
4290 | if(events.size() != Nevents_block_header){ | |||||
4291 | stringstream ss; | |||||
4292 | ss << "F1TDC missing events in block! (found "<< events.size() <<" but should have found "<<Nevents_block_header<<")"; | |||||
4293 | DumpBinary(istart, iend, 128); | |||||
4294 | throw JException(ss.str()); | |||||
4295 | } | |||||
4296 | ||||||
4297 | if(VERBOSE>6) evioout << " Leaving ParseF1TDCBank (rocid=" << rocid << ")" << endl; | |||||
4298 | ||||||
4299 | } | |||||
4300 | ||||||
4301 | //---------------- | |||||
4302 | // F1TDC_channel | |||||
4303 | //---------------- | |||||
4304 | uint32_t JEventSource_EVIO::F1TDC_channel(uint32_t chip, uint32_t chan_on_chip, int modtype) | |||||
4305 | { | |||||
4306 | /// Convert a F1TDC chip number and channel on the chip to the | |||||
4307 | /// front panel channel number. This is based on "Input Channel Mapping" | |||||
4308 | /// section at the very bottom of the document F1TDC_V2_V3_4_29_14.pdf | |||||
4309 | ||||||
4310 | uint32_t channel_map[8] = {0, 0, 1, 1, 2, 2, 3, 3}; | |||||
4311 | switch(modtype){ | |||||
4312 | case DModuleType::F1TDC32: | |||||
4313 | return (4 * chip) + channel_map[ chan_on_chip&0x7 ]; | |||||
4314 | case DModuleType::F1TDC48: | |||||
4315 | return (chip <<3) | chan_on_chip; | |||||
4316 | default: | |||||
4317 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<4317<<" " << "Calling F1TDC_channel for module type: " << DModuleType::GetName((DModuleType::type_id_t)modtype) << endl; | |||||
4318 | throw JException("F1TDC_channel called for non-F1TDC module type"); | |||||
4319 | } | |||||
4320 | return 1000000; // (should never get here) | |||||
4321 | } | |||||
4322 | ||||||
4323 | //---------------- | |||||
4324 | // ParseTSBank | |||||
4325 | //---------------- | |||||
4326 | void JEventSource_EVIO::ParseTSBank(int32_t rocid, const uint32_t* &iptr, const uint32_t* iend, list<ObjList*> &events) | |||||
4327 | { | |||||
4328 | /// Parse data written to the TS roc data during sync events. | |||||
4329 | /// This is written by the ts_scalers routine in the conf_utils.c | |||||
4330 | /// file and called from ts_list.c | |||||
4331 | ||||||
4332 | uint32_t Nwords = ((uint64_t)iend - (uint64_t)iptr)/sizeof(uint32_t); | |||||
4333 | uint32_t Nwords_expected = (6+32+16+32+16); | |||||
4334 | if(Nwords != Nwords_expected){ | |||||
4335 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<4335<<" " << "TS bank size does not match expected!!" << endl; | |||||
4336 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<4336<<" " << "Found " << Nwords << " words. Expected " << Nwords_expected << endl; | |||||
4337 | ||||||
4338 | }else{ | |||||
4339 | DTSscalers *s = new DTSscalers; | |||||
4340 | s->nsync_event = *iptr++; | |||||
4341 | s->int_count = *iptr++; | |||||
4342 | s->live_time = *iptr++; | |||||
4343 | s->busy_time = *iptr++; | |||||
4344 | s->inst_livetime = *iptr++; | |||||
4345 | s->time = *iptr++; | |||||
4346 | for(uint32_t i=0; i<32; i++) s->gtp_scalers[i] = *iptr++; | |||||
4347 | for(uint32_t i=0; i<16; i++) s->fp_scalers[i] = *iptr++; | |||||
4348 | for(uint32_t i=0; i<32; i++) s->gtp_rate[i] = *iptr++; | |||||
4349 | for(uint32_t i=0; i<16; i++) s->fp_rate[i] = *iptr++; | |||||
4350 | ||||||
4351 | if(events.empty()) events.push_back(new ObjList); | |||||
4352 | ObjList *objs = *(events.begin()); | |||||
4353 | objs->misc_objs.push_back(s); | |||||
4354 | } | |||||
4355 | ||||||
4356 | iptr = iend; | |||||
4357 | } | |||||
4358 | ||||||
4359 | //---------------- | |||||
4360 | // ParseTIBank | |||||
4361 | //---------------- | |||||
4362 | void JEventSource_EVIO::ParseTIBank(int32_t rocid, const uint32_t* &iptr, const uint32_t* iend, list<ObjList*> &events) | |||||
4363 | { | |||||
4364 | while(iptr<iend && ((*iptr) & 0xF8000000) != 0x88000000) iptr++; // Skip to JLab block trailer | |||||
4365 | iptr++; // advance past JLab block trailer | |||||
4366 | while(iptr<iend && *iptr == 0xF8000000) iptr++; // skip filler words after block trailer | |||||
4367 | //iptr = iend; | |||||
4368 | } | |||||
4369 | ||||||
4370 | //---------------- | |||||
4371 | // ParseCAEN1190 | |||||
4372 | //---------------- | |||||
4373 | void JEventSource_EVIO::ParseCAEN1190(int32_t rocid, const uint32_t* &iptr, const uint32_t *iend, list<ObjList*> &events) | |||||
4374 | { | |||||
4375 | /// Parse data from a CAEN 1190 or 1290 module | |||||
4376 | /// (See ppg. 72-74 of V1290_REV15.pdf manual) | |||||
4377 | ||||||
4378 | if(!PARSE_CAEN1290TDC){ iptr = iend; return; } | |||||
4379 | ||||||
4380 | uint32_t slot = 0; | |||||
4381 | uint32_t event_count = 0; | |||||
4382 | uint32_t word_count = 0; | |||||
4383 | uint32_t trigger_time_tag = 0; | |||||
4384 | uint32_t tdc_num = 0; | |||||
4385 | uint32_t event_id = 0; | |||||
4386 | uint32_t bunch_id = 0; | |||||
4387 | ||||||
4388 | // We need to accomodate multi-event blocks where | |||||
4389 | // events are entangled (i.e. hits from event 1 | |||||
4390 | // are mixed inbetween those of event 2,3,4, | |||||
4391 | // etc... With CAEN modules, we only know which | |||||
4392 | // event a hit came from by looking at the event_id | |||||
4393 | // in the TDC header. This value is only 12 bits | |||||
4394 | // and could roll over within an event block. This | |||||
4395 | // means we need to keep track of the order we | |||||
4396 | // encounter them in so it is maintained in the | |||||
4397 | // "events" container. The event_id order is kept | |||||
4398 | // in the "event_id_order" vector. | |||||
4399 | map<uint32_t, vector<DCAEN1290TDCHit*> > hits_by_event_id; | |||||
4400 | vector<uint32_t> event_id_order; | |||||
4401 | ||||||
4402 | while(iptr<iend){ | |||||
4403 | ||||||
4404 | // This word appears to be appended to the data. | |||||
4405 | // Probably in the ROL. Ignore it if found. | |||||
4406 | if(*iptr == 0xd00dd00d) { | |||||
4407 | if(VERBOSE>7) evioout << " CAEN skipping 0xd00dd00d word" << endl; | |||||
4408 | iptr++; | |||||
4409 | continue; | |||||
4410 | } | |||||
4411 | ||||||
4412 | uint32_t type = (*iptr) >> 27; | |||||
4413 | uint32_t edge = 0; // 1=trailing, 0=leading | |||||
4414 | uint32_t channel = 0; | |||||
4415 | uint32_t tdc = 0; | |||||
4416 | uint32_t error_flags = 0; | |||||
4417 | DCAEN1290TDCHit *caen1290tdchit = NULL__null; | |||||
4418 | map<uint32_t, ObjList*>::iterator iter; | |||||
4419 | switch(type){ | |||||
4420 | case 0b01000: // Global Header | |||||
4421 | slot = (*iptr) & 0x1f; | |||||
4422 | event_count = ((*iptr)>>5) & 0xffffff; | |||||
4423 | if(VERBOSE>7) evioout << " CAEN TDC Global Header (slot=" << slot << " , event count=" << event_count << ")" << endl; | |||||
4424 | break; | |||||
4425 | case 0b10000: // Global Trailer | |||||
4426 | slot = (*iptr) & 0x1f; | |||||
4427 | word_count = ((*iptr)>>5) & 0x7ffff; | |||||
4428 | if(VERBOSE>7) evioout << " CAEN TDC Global Trailer (slot=" << slot << " , word count=" << word_count << ")" << endl; | |||||
4429 | slot = event_count = word_count = trigger_time_tag = tdc_num = event_id = bunch_id = 0; | |||||
4430 | break; | |||||
4431 | case 0b10001: // Global Trigger Time Tag | |||||
4432 | trigger_time_tag = ((*iptr)>>5) & 0x7ffffff; | |||||
4433 | if(VERBOSE>7) evioout << " CAEN TDC Global Trigger Time Tag (tag=" << trigger_time_tag << ")" << endl; | |||||
4434 | break; | |||||
4435 | case 0b00001: // TDC Header | |||||
4436 | tdc_num = ((*iptr)>>24) & 0x03; | |||||
4437 | event_id = ((*iptr)>>12) & 0x0fff; | |||||
4438 | bunch_id = (*iptr) & 0x0fff; | |||||
4439 | if( find(event_id_order.begin(), event_id_order.end(), event_id) == event_id_order.end()){ | |||||
4440 | event_id_order.push_back(event_id); | |||||
4441 | } | |||||
4442 | if(VERBOSE>7) evioout << " CAEN TDC TDC Header (tdc=" << tdc_num <<" , event id=" << event_id <<" , bunch id=" << bunch_id << ")" << endl; | |||||
4443 | break; | |||||
4444 | case 0b00000: // TDC Measurement | |||||
4445 | edge = ((*iptr)>>26) & 0x01; | |||||
4446 | channel = ((*iptr)>>21) & 0x1f; | |||||
4447 | tdc = ((*iptr)>>0) & 0x1fffff; | |||||
4448 | if(VERBOSE>7) evioout << " CAEN TDC TDC Measurement (" << (edge ? "trailing":"leading") << " , channel=" << channel << " , tdc=" << tdc << ")" << endl; | |||||
4449 | ||||||
4450 | // Create DCAEN1290TDCHit object | |||||
4451 | caen1290tdchit = new DCAEN1290TDCHit(rocid, slot, channel, 0, edge, tdc_num, event_id, bunch_id, tdc); | |||||
4452 | hits_by_event_id[event_id].push_back(caen1290tdchit); | |||||
4453 | break; | |||||
4454 | case 0b00100: // TDC Error | |||||
4455 | error_flags = (*iptr) & 0x7fff; | |||||
4456 | if(VERBOSE>7) evioout << " CAEN TDC TDC Error (err flags=0x" << hex << error_flags << dec << ")" << endl; | |||||
4457 | break; | |||||
4458 | case 0b00011: // TDC Trailer | |||||
4459 | tdc_num = ((*iptr)>>24) & 0x03; | |||||
4460 | event_id = ((*iptr)>>12) & 0x0fff; | |||||
4461 | word_count = ((*iptr)>>0) & 0x0fff; | |||||
4462 | if(VERBOSE>7) evioout << " CAEN TDC TDC Trailer (tdc=" << tdc_num <<" , event id=" << event_id <<" , word count=" << word_count << ")" << endl; | |||||
4463 | tdc_num = event_id = bunch_id = 0; | |||||
4464 | break; | |||||
4465 | case 0b11000: // Filler Word | |||||
4466 | if(VERBOSE>7) evioout << " CAEN TDC Filler Word" << endl; | |||||
4467 | break; | |||||
4468 | default: | |||||
4469 | evioout << "Unknown datatype: 0x" << hex << type << " full word: "<< *iptr << dec << endl; | |||||
4470 | } | |||||
4471 | ||||||
4472 | iptr++; | |||||
4473 | } | |||||
4474 | ||||||
4475 | // If disentagling is disabled, then lump all hits into single event | |||||
4476 | if( (!ENABLE_DISENTANGLING) && (event_id_order.size()>1) ){ | |||||
4477 | if(VERBOSE>2) evioout << " Disentangling disabled. Merging all hits into single event" << endl; | |||||
4478 | vector<DCAEN1290TDCHit*> &hits1 = hits_by_event_id[event_id_order[0]]; | |||||
4479 | for(uint32_t i=1; i<event_id_order.size(); i++){ | |||||
4480 | vector<DCAEN1290TDCHit*> &hits2 = hits_by_event_id[event_id_order[i]]; | |||||
4481 | hits1.insert(hits1.end(), hits2.begin(), hits2.end()); // copy hits into first event | |||||
4482 | hits_by_event_id.erase(event_id_order[i]); // remove hits list for this event_id | |||||
4483 | } | |||||
4484 | } | |||||
4485 | ||||||
4486 | // Add hits for each event to the events container, creating ObjList's as needed | |||||
4487 | for(uint32_t i=0; i<event_id_order.size(); i++){ | |||||
4488 | ||||||
4489 | // Make sure there are enough event containers to hold this event | |||||
4490 | while(events.size() <= i) events.push_back(new ObjList); | |||||
4491 | list<ObjList*>::iterator it = events.begin(); | |||||
4492 | advance(it, i); | |||||
4493 | ObjList *objs = *it; | |||||
4494 | ||||||
4495 | vector<DCAEN1290TDCHit*> &hits = hits_by_event_id[event_id_order[i]]; | |||||
4496 | objs->hit_objs.insert(objs->hit_objs.end(), hits.begin(), hits.end()); | |||||
4497 | ||||||
4498 | if(VERBOSE>7) evioout << " Added " << hits.size() << " hits with event_id=" << event_id_order[i] << " to event " << i << endl; | |||||
4499 | } | |||||
4500 | ||||||
4501 | } | |||||
4502 | ||||||
4503 | //---------------- | |||||
4504 | // ParseBORevent | |||||
4505 | //---------------- | |||||
4506 | void JEventSource_EVIO::ParseBORevent(evioDOMNodeP bankPtr) | |||||
4507 | { | |||||
4508 | if(!PARSE_BOR) return; | |||||
4509 | ||||||
4510 | // This really shouldn't be needed | |||||
4511 | pthread_rwlock_wrlock(&BOR_lock); | |||||
4512 | ||||||
4513 | // Delete any existing BOR config objects. BOR events should | |||||
4514 | // be flagged as sequential (or barrier) events so all threads | |||||
4515 | // that were using these should be done with them now. | |||||
4516 | for(uint32_t i=0; i<BORobjs.size(); i++) delete BORobjs[i]; | |||||
4517 | BORobjs.clear(); | |||||
4518 | ||||||
4519 | evioDOMNodeListP bankList = bankPtr->getChildren(); | |||||
4520 | evioDOMNodeList::iterator iter = bankList->begin(); | |||||
4521 | if(VERBOSE>7) evioout << " Looping over " << bankList->size() << " banks in BOR event" << endl; | |||||
4522 | for(int ibank=1; iter!=bankList->end(); iter++, ibank++){ // ibank only used for debugging messages | |||||
4523 | evioDOMNodeP childBank = *iter; | |||||
4524 | ||||||
4525 | if(childBank->tag==0x71){ | |||||
4526 | // uint32_t rocid = childBank->num; | |||||
4527 | evioDOMNodeListP bankList = childBank->getChildren(); | |||||
4528 | evioDOMNodeList::iterator iter = bankList->begin(); | |||||
4529 | for(; iter!=bankList->end(); iter++){ | |||||
4530 | evioDOMNodeP dataBank = *iter; | |||||
4531 | // uint32_t slot = dataBank->tag>>5; | |||||
4532 | uint32_t modType = dataBank->tag&0x1f; | |||||
4533 | ||||||
4534 | const vector<uint32_t> *vec = dataBank->getVector<uint32_t>(); | |||||
4535 | ||||||
4536 | const uint32_t *src = &(*vec)[0]; | |||||
4537 | uint32_t *dest = NULL__null; | |||||
4538 | uint32_t sizeof_dest = 0; | |||||
4539 | ||||||
4540 | Df250BORConfig *f250conf = NULL__null; | |||||
4541 | Df125BORConfig *f125conf = NULL__null; | |||||
4542 | DF1TDCBORConfig *F1TDCconf = NULL__null; | |||||
4543 | DCAEN1290TDCBORConfig *caen1190conf = NULL__null; | |||||
4544 | ||||||
4545 | switch(modType){ | |||||
4546 | case DModuleType::FADC250: // f250 | |||||
4547 | f250conf = new Df250BORConfig; | |||||
4548 | dest = (uint32_t*)&f250conf->rocid; | |||||
4549 | sizeof_dest = sizeof(f250config); | |||||
4550 | break; | |||||
4551 | case DModuleType::FADC125: // f125 | |||||
4552 | f125conf = new Df125BORConfig; | |||||
4553 | dest = (uint32_t*)&f125conf->rocid; | |||||
4554 | sizeof_dest = sizeof(f125config); | |||||
4555 | break; | |||||
4556 | ||||||
4557 | case DModuleType::F1TDC32: // F1TDCv2 | |||||
4558 | case DModuleType::F1TDC48: // F1TDCv3 | |||||
4559 | F1TDCconf = new DF1TDCBORConfig; | |||||
4560 | dest = (uint32_t*)&F1TDCconf->rocid; | |||||
4561 | sizeof_dest = sizeof(F1TDCconfig); | |||||
4562 | break; | |||||
4563 | ||||||
4564 | case DModuleType::CAEN1190: // CAEN 1190 TDC | |||||
4565 | case DModuleType::CAEN1290: // CAEN 1290 TDC | |||||
4566 | caen1190conf = new DCAEN1290TDCBORConfig; | |||||
4567 | dest = (uint32_t*)&caen1190conf->rocid; | |||||
4568 | sizeof_dest = sizeof(caen1190config); | |||||
4569 | break; | |||||
4570 | } | |||||
4571 | ||||||
4572 | // Check that the bank size and data structure size match. | |||||
4573 | // If they do, then copy the data and add the object to | |||||
4574 | // the event. If not, then delete the object and print | |||||
4575 | // a warning message. | |||||
4576 | if( vec->size() == (sizeof_dest/sizeof(uint32_t)) ){ | |||||
4577 | ||||||
4578 | // Copy bank data, assuming format is the same | |||||
4579 | for(uint32_t i=0; i<vec->size(); i++) *dest++ = *src++; | |||||
4580 | ||||||
4581 | // Store object for use in this and subsequent events | |||||
4582 | if(f250conf) BORobjs.push_back(f250conf); | |||||
4583 | if(f125conf) BORobjs.push_back(f125conf); | |||||
4584 | if(F1TDCconf) BORobjs.push_back(F1TDCconf); | |||||
4585 | if(caen1190conf) BORobjs.push_back(caen1190conf); | |||||
4586 | ||||||
4587 | }else if(sizeof_dest>0){ | |||||
4588 | if(f250conf) delete f250conf; | |||||
4589 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<4589<<" " << "BOR bank size does not match structure! " << vec->size() <<" != " << (sizeof_dest/sizeof(uint32_t)) << endl; | |||||
4590 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<4590<<" " << "sizeof(f250config)="<<sizeof(f250config)<<endl; | |||||
4591 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<4591<<" " << "sizeof(f125config)="<<sizeof(f125config)<<endl; | |||||
4592 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<4592<<" " << "sizeof(F1TDCconfig)="<<sizeof(F1TDCconfig)<<endl; | |||||
4593 | _DBG_std::cerr<<"libraries/DAQ/JEventSource_EVIO.cc"<< ":"<<4593<<" " << "sizeof(caen1190config)="<<sizeof(caen1190config)<<endl; | |||||
4594 | } | |||||
4595 | } | |||||
4596 | } | |||||
4597 | } | |||||
4598 | ||||||
4599 | pthread_rwlock_unlock(&BOR_lock); | |||||
4600 | ||||||
4601 | } | |||||
4602 | ||||||
4603 | ||||||
4604 | //---------------- | |||||
4605 | // ParseTSSyncevent | |||||
4606 | //---------------- | |||||
4607 | void JEventSource_EVIO::ParseTSSync(evioDOMNodeP bankPtr, list<ObjList*> &events) | |||||
4608 | { | |||||
4609 | ||||||
4610 | DL1Info *trig_info = new DL1Info; | |||||
4611 | ||||||
4612 | // cout << " INSIDE ParseTSSync " << endl; | |||||
4613 | ||||||
4614 | if((bankPtr->tag & 0xFFFF) == 0xEE02){ | |||||
4615 | const vector<uint32_t> *vec = bankPtr->getVector<uint32_t>(); | |||||
4616 | ||||||
4617 | trig_info->nsync = (*vec)[0]; | |||||
4618 | trig_info->trig_number = (*vec)[1]; | |||||
4619 | trig_info->live_time = (*vec)[2]; | |||||
4620 | trig_info->busy_time = (*vec)[3]; | |||||
4621 | trig_info->live_inst = (*vec)[4]; | |||||
4622 | trig_info->unix_time = (*vec)[5]; | |||||
4623 | ||||||
4624 | ||||||
4625 | ||||||
4626 | // GTP scalers | |||||
4627 | for(uint32_t ii = 6; ii < 38; ii++){ | |||||
4628 | trig_info->gtp_sc.push_back((*vec)[ii]); | |||||
4629 | } | |||||
4630 | ||||||
4631 | // FP scalers | |||||
4632 | for(uint32_t ii = 38; ii < 54; ii++){ | |||||
4633 | trig_info->fp_sc.push_back((*vec)[ii]); | |||||
4634 | } | |||||
4635 | ||||||
4636 | // GTP rate | |||||
4637 | for(uint32_t ii = 54; ii < 86; ii++){ | |||||
4638 | trig_info->gtp_rate.push_back((*vec)[ii]); | |||||
4639 | } | |||||
4640 | ||||||
4641 | // FP rate | |||||
4642 | for(uint32_t ii = 86; ii < 102; ii++){ | |||||
4643 | trig_info->fp_rate.push_back((*vec)[ii]); | |||||
4644 | } | |||||
4645 | } | |||||
4646 | ||||||
4647 | ||||||
4648 | if(events.empty()){ | |||||
4649 | events.push_back(new ObjList()); | |||||
4650 | // cout << " TSSync: Empty event " << endl; | |||||
4651 | } | |||||
4652 | ||||||
4653 | ObjList *objs = *(events.begin()); | |||||
4654 | ||||||
4655 | objs->misc_objs.push_back(trig_info); | |||||
4656 | ||||||
4657 | ||||||
4658 | } | |||||
4659 | ||||||
4660 | ||||||
4661 | //---------------- | |||||
4662 | // ParseEPICSevent | |||||
4663 | //---------------- | |||||
4664 | void JEventSource_EVIO::ParseEPICSevent(evioDOMNodeP bankPtr, list<ObjList*> &events) | |||||
4665 | { | |||||
4666 | if(!PARSE_EPICS) return; | |||||
4667 | ||||||
4668 | time_t timestamp=0; | |||||
4669 | ||||||
4670 | ObjList *objs = NULL__null; | |||||
4671 | ||||||
4672 | evioDOMNodeListP bankList = bankPtr->getChildren(); | |||||
4673 | evioDOMNodeList::iterator iter = bankList->begin(); | |||||
4674 | if(VERBOSE>7) evioout << " Looping over " << bankList->size() << " banks in EPICS event" << endl; | |||||
4675 | for(int ibank=1; iter!=bankList->end(); iter++, ibank++){ // ibank only used for debugging messages | |||||
4676 | evioDOMNodeP childBank = *iter; | |||||
4677 | ||||||
4678 | if(childBank->tag == 97){ | |||||
4679 | // timestamp bank | |||||
4680 | const vector<uint32_t> *vec = childBank->getVector<uint32_t>(); | |||||
4681 | if(vec) { | |||||
4682 | timestamp = (time_t)(*vec)[0]; | |||||
4683 | if(VERBOSE>7) evioout << " timestamp: " << ctime(×tamp); | |||||
4684 | } | |||||
4685 | }else if(childBank->tag==98){ | |||||
4686 | const vector<uint8_t> *vec = childBank->getVector<uint8_t>(); | |||||
4687 | if(vec){ | |||||
4688 | string nameval = (const char*)&((*vec)[0]); | |||||
4689 | DEPICSvalue *epicsval = new DEPICSvalue(timestamp, nameval); | |||||
4690 | if(VERBOSE>7) evioout << " " << nameval << endl; | |||||
4691 | ||||||
4692 | if(!objs){ | |||||
4693 | if(events.empty()) events.push_back(new ObjList); | |||||
4694 | objs = *(events.begin()); | |||||
4695 | } | |||||
4696 | objs->misc_objs.push_back(epicsval); | |||||
4697 | } | |||||
4698 | } | |||||
4699 | } | |||||
4700 | } | |||||
4701 | ||||||
4702 | //---------------- | |||||
4703 | // DumpBinary | |||||
4704 | //---------------- | |||||
4705 | void JEventSource_EVIO::DumpBinary(const uint32_t *iptr, const uint32_t *iend, uint32_t MaxWords, const uint32_t *imark) | |||||
4706 | { | |||||
4707 | /// This is used for debugging. It will print to the screen the words | |||||
4708 | /// starting at the address given by iptr and ending just before iend | |||||
4709 | /// or for MaxWords words, whichever comes first. If iend is NULL, | |||||
4710 | /// then MaxWords will be printed. If MaxWords is zero then it is ignored | |||||
4711 | /// and only iend is checked. If both iend==NULL and MaxWords==0, then | |||||
4712 | /// only the word at iptr is printed. | |||||
4713 | ||||||
4714 | cout << "Dumping binary: istart=" << hex << iptr << " iend=" << iend << " MaxWords=" << dec << MaxWords << endl; | |||||
4715 | ||||||
4716 | if(iend==NULL__null && MaxWords==0) MaxWords=1; | |||||
4717 | if(MaxWords==0) MaxWords = (uint32_t)0xffffffff; | |||||
4718 | ||||||
4719 | uint32_t Nwords=0; | |||||
4720 | while(iptr!=iend && Nwords<MaxWords){ | |||||
4721 | ||||||
4722 | // line1 is hex and line2 is decimal | |||||
4723 | stringstream line1, line2; | |||||
4724 | ||||||
4725 | // print words in columns 8 words wide. First part is | |||||
4726 | // reserved for word number | |||||
4727 | uint32_t Ncols = 8; | |||||
4728 | line1 << setw(5) << Nwords; | |||||
4729 | line2 << string(5, ' '); | |||||
4730 | ||||||
4731 | // Loop over columns | |||||
4732 | for(uint32_t i=0; i<Ncols; i++, iptr++, Nwords++){ | |||||
4733 | ||||||
4734 | if(iptr == iend) break; | |||||
4735 | if(Nwords>=MaxWords) break; | |||||
4736 | ||||||
4737 | stringstream iptr_hex; | |||||
4738 | iptr_hex << hex << "0x" << *iptr; | |||||
4739 | ||||||
4740 | string mark = (iptr==imark ? "*":" "); | |||||
4741 | ||||||
4742 | line1 << setw(12) << iptr_hex.str() << mark; | |||||
4743 | line2 << setw(12) << *iptr << mark; | |||||
4744 | } | |||||
4745 | ||||||
4746 | cout << line1.str() << endl; | |||||
4747 | cout << line2.str() << endl; | |||||
4748 | cout << endl; | |||||
4749 | } | |||||
4750 | } | |||||
4751 | ||||||
4752 | #endif // HAVE_EVIO | |||||
4753 | ||||||
4754 | #if 0 | |||||
4755 | //---------------- | |||||
4756 | // GuessModuleType | |||||
4757 | //---------------- | |||||
4758 | MODULE_TYPE JEventSource_EVIO::GuessModuleType(const uint32_t* istart, const uint32_t* iend, evioDOMNodeP bankPtr) | |||||
4759 | { | |||||
4760 | /// Try parsing through the information in the given data buffer | |||||
4761 | /// to determine which type of module produced the data. | |||||
4762 | ||||||
4763 | if(IsFADC250(istart, iend)) return DModuleType::FADC250; | |||||
4764 | if(IsF125ADC(istart, iend)) return DModuleType::F125ADC; | |||||
4765 | if(IsF1TDC(istart, iend)) return DModuleType::F1TDC; | |||||
4766 | if(IsTS(istart, iend)) return DModuleType::JLAB_TS; | |||||
4767 | if(IsTI(istart, iend)) return DModuleType::JLAB_TID; | |||||
4768 | ||||||
4769 | ||||||
4770 | // Couldn't figure it out... | |||||
4771 | return DModuleType::UNKNOWN; | |||||
4772 | } | |||||
4773 | ||||||
4774 | //---------------- | |||||
4775 | // IsFADC250 | |||||
4776 | //---------------- | |||||
4777 | bool JEventSource_EVIO::IsFADC250(const uint32_t *istart, const uint32_t *iend) | |||||
4778 | { | |||||
4779 | //---- Check for f250 | |||||
4780 | // This will check if the first word appears to be a block header. | |||||
4781 | // If so, it loops over all words looking for a block trailer. | |||||
4782 | // If the slot number in the block trailer matches that in the | |||||
4783 | // block header AND the number of words in the block matches that | |||||
4784 | // specified in the block trailer, then it is assumed to be a f250. | |||||
4785 | if(((*istart>>31) & 0x1) == 1){ | |||||
4786 | uint32_t data_type = (*istart>>27) & 0x0F; | |||||
4787 | if(data_type == 0){ // Block Header | |||||
4788 | uint32_t slot_header = (*istart>>22) & 0x1F; | |||||
4789 | uint32_t Nwords = 1; | |||||
4790 | for(const uint32_t *iptr=istart; iptr<iend; iptr++, Nwords++){ | |||||
4791 | if(((*iptr>>31) & 0x1) == 1){ | |||||
4792 | uint32_t data_type = (*iptr>>27) & 0x0F; | |||||
4793 | if(data_type == 1){ // Block Trailer | |||||
4794 | uint32_t slot_trailer = (*iptr>>22) & 0x1F; | |||||
4795 | uint32_t Nwords_trailer = (*iptr>>0) & 0x3FFFFF; | |||||
4796 | ||||||
4797 | if( slot_header == slot_trailer && Nwords == Nwords_trailer ){ | |||||
4798 | return true; | |||||
4799 | }else{ | |||||
4800 | return false; | |||||
4801 | } | |||||
4802 | } | |||||
4803 | } | |||||
4804 | } | |||||
4805 | } | |||||
4806 | } | |||||
4807 | ||||||
4808 | // either first word was not a block header or no block trailer was found | |||||
4809 | return false; | |||||
4810 | } | |||||
4811 | ||||||
4812 | //---------------- | |||||
4813 | // IsF1TDC | |||||
4814 | //---------------- | |||||
4815 | bool JEventSource_EVIO::IsF1TDC(const uint32_t *istart, const uint32_t *iend) | |||||
4816 | { | |||||
4817 | //---- Check for F1TDC | |||||
4818 | // This will check for consistency in the slot numbers for all words | |||||
4819 | // in the buffer. The slot number of data words are checked against | |||||
4820 | // the slot number of the most recently encountered header word. | |||||
4821 | uint32_t slot_header = 1000; | |||||
4822 | uint32_t slot_trailer = 1000; | |||||
4823 | ||||||
4824 | const uint32_t *iptr=istart; | |||||
4825 | ||||||
4826 | // skip first word which appears to be ROL marker for F1TDC data | |||||
4827 | if(*istart == 0xf1daffff)iptr++ | |||||
4828 | ||||||
4829 | // There is no distinction between header and trailer | |||||
4830 | // words other than the order that they appear. We keep | |||||
4831 | // track by flipping this value | |||||
4832 | bool looking_for_header = true; | |||||
4833 | ||||||
4834 | // Keep track of the number of valid blocks of F1TDC data we find | |||||
4835 | // (i.e. ones where the header and trailer words were found | |||||
4836 | int Nvalid = 0; | |||||
4837 | ||||||
4838 | for(; iptr<iend; iptr++){ | |||||
4839 | ||||||
4840 | // ROL end of data marker (only in test setup data) | |||||
4841 | if(*iptr == 0xda0000ff)break; | |||||
4842 | ||||||
4843 | uint32_t slot = (*iptr>>27) & 0x1F; | |||||
4844 | ||||||
4845 | // if slot is 0 or 30, we are supposed to ignore the data. | |||||
4846 | if(slot == 30 || slot ==0)continue; | |||||
4847 | ||||||
4848 | if(((*iptr>>23) & 0x1) == 0){ | |||||
4849 | // header/trailer word | |||||
4850 | if(looking_for_header){ | |||||
4851 | slot_header = slot; | |||||
4852 | looking_for_header = false; | |||||
4853 | }else{ | |||||
4854 | slot_trailer = slot; | |||||
4855 | if(slot_trailer != slot_header)return false; | |||||
4856 | looking_for_header = true; | |||||
4857 | Nvalid++; | |||||
4858 | } | |||||
4859 | }else{ | |||||
4860 | // data word | |||||
4861 | ||||||
4862 | // if we encounter a data word when we are expecting | |||||
4863 | // a header word, then the current word is not from | |||||
4864 | // an F1TDC. However, if we did find at least one valid | |||||
4865 | // block at the begining, of the buffer, claim the buffer | |||||
4866 | // points to F1TDC data. We check for as many valid F1TDC | |||||
4867 | // blocks as possible to help ensure that is what the data | |||||
4868 | // is. | |||||
4869 | if(looking_for_header)return Nvalid>0; | |||||
4870 | ||||||
4871 | // If the slot number does not match, then this is | |||||
4872 | // not valid F1TDC data | |||||
4873 | if(slot != slot_header)return false; | |||||
4874 | } | |||||
4875 | } | |||||
4876 | ||||||
4877 | return Nvalid>0; | |||||
4878 | } | |||||
4879 | ||||||
4880 | //---------------- | |||||
4881 | // DumpModuleMap | |||||
4882 | //---------------- | |||||
4883 | void JEventSource_EVIO::DumpModuleMap(void) | |||||
4884 | { | |||||
4885 | // Open output file | |||||
4886 | string fname = "module_map.txt"; | |||||
4887 | ofstream ofs(fname.c_str()); | |||||
4888 | if(!ofs.is_open()){ | |||||
4889 | jerr<<"Unable to open file \""<<fname<<"\" for writing!"<<endl; | |||||
4890 | return; | |||||
4891 | } | |||||
4892 | ||||||
4893 | jout<<"Writing module map to file \""<<fname<<"\""<<endl; | |||||
4894 | ||||||
4895 | // Write header | |||||
4896 | time_t now = time(NULL__null); | |||||
4897 | ofs<<"# Autogenerated module map"<<endl; | |||||
4898 | ofs<<"# Created: "<<ctime(&now); | |||||
4899 | ofs<<"#"<<endl; | |||||
4900 | ||||||
4901 | // Write known module types in header | |||||
4902 | vector<DModuleType> modules; | |||||
4903 | DModuleType::GetModuleList(modules); | |||||
4904 | ofs<<"# Known module types:"<<endl; | |||||
4905 | ofs<<"# ----------------------"<<endl; | |||||
4906 | for(unsigned int i=0; i<modules.size(); i++){ | |||||
4907 | string name = modules[i].GetName(); | |||||
4908 | string space(12-name.size(), ' '); | |||||
4909 | ofs << "# " << name << space << " - " << modules[i].GetDescription() <<endl; | |||||
4910 | } | |||||
4911 | ofs<<"#"<<endl; | |||||
4912 | ofs<<"#"<<endl; | |||||
4913 | ||||||
4914 | // Write module map | |||||
4915 | ofs<<"# Format is:"<<endl; | |||||
4916 | ofs<<"# tag num type"<<endl; | |||||
4917 | ofs<<"#"<<endl; | |||||
4918 | ||||||
4919 | map<tagNum, MODULE_TYPE>::iterator iter = module_type.begin(); | |||||
4920 | for(; iter!=module_type.end(); iter++){ | |||||
4921 | ||||||
4922 | tagNum tag_num = iter->first; | |||||
4923 | MODULE_TYPE type = iter->second; | |||||
4924 | ofs<<tag_num.first<<" "<<(int)tag_num.second<<" "<<DModuleType::GetName(type)<<endl; | |||||
4925 | } | |||||
4926 | ofs<<endl; | |||||
4927 | ||||||
4928 | // Close output file | |||||
4929 | ofs.close(); | |||||
4930 | } | |||||
4931 | #endif |