Bug Summary

File:libraries/DAQ/JEventSource_EVIO.cc
Location:line 3246, column 66
Description:Access to field 'P1' results in a dereference of a null pointer (loaded from variable 'f125config')

Annotated Source Code

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