File: | libraries/DAQ/JEventSource_EVIO.cc |
Location: | line 1942, column 9 |
Description: | Called C++ object pointer is null |
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 |