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