File: | /home/sdobbs/work/clang/halld_recon/src/libraries/DAQ/DEVIOWorkerThread.cc |
Warning: | line 1142, column 51 Although the value stored to 'trigger_time_tag' is used in the enclosing expression, the value is never actually read from 'trigger_time_tag' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /// $Id$ |
2 | // |
3 | // File: DEVIOWorkerThread.cc |
4 | // Created: Mon Mar 28 07:40:07 EDT 2016 |
5 | // Creator: davidl (on Darwin harriet.jlab.org 13.4.0 i386) |
6 | // |
7 | |
8 | #include <unistd.h> |
9 | |
10 | #include "DEVIOWorkerThread.h" |
11 | #include "JEventSource_EVIOpp.h" |
12 | #include "LinkAssociations.h" |
13 | |
14 | #include <swap_bank.h> |
15 | #include <DANA/JExceptionDataFormat.h> |
16 | |
17 | using namespace std; |
18 | using namespace std::chrono; |
19 | |
20 | |
21 | |
22 | //--------------------------------- |
23 | // DEVIOWorkerThread (Constructor) |
24 | //--------------------------------- |
25 | DEVIOWorkerThread::DEVIOWorkerThread( |
26 | JEventSource_EVIOpp *event_source |
27 | ,list<DParsedEvent*> &parsed_events |
28 | ,uint32_t &MAX_PARSED_EVENTS |
29 | ,mutex &PARSED_EVENTS_MUTEX |
30 | ,condition_variable &PARSED_EVENTS_CV |
31 | ,set<uint32_t> &ROCIDS_TO_PARSE |
32 | ): |
33 | event_source(event_source) |
34 | ,parsed_events(parsed_events) |
35 | ,MAX_PARSED_EVENTS(MAX_PARSED_EVENTS) |
36 | ,PARSED_EVENTS_MUTEX(PARSED_EVENTS_MUTEX) |
37 | ,PARSED_EVENTS_CV(PARSED_EVENTS_CV) |
38 | ,ROCIDS_TO_PARSE(ROCIDS_TO_PARSE) |
39 | ,done(false) |
40 | ,thd(&DEVIOWorkerThread::Run,this) |
41 | { |
42 | // n.b. in principal, the worker thread is started when the |
43 | // above constructor is hit and so may already be in Run() |
44 | // before executing anything below. The "done" variable is |
45 | // therefore initialized first to guarantee that if that |
46 | // happens, it gets to the cv.wait() call where it will wait |
47 | // for someone to notify it. That won't happen before this |
48 | // constructor completes so we do the remaining initializations |
49 | // below. |
50 | |
51 | VERBOSE = 0; |
52 | Nrecycled = 0; // Incremented in JEventSource_EVIOpp::Dispatcher() |
53 | MAX_EVENT_RECYCLES = 1000; // In EVIO events (not L1 trigger events!) overwritten in JEventSource_EVIOpp constructor |
54 | MAX_OBJECT_RECYCLES = 1000; // overwritten in JEventSource_EVIOpp constructor |
55 | run_number_seed = 0; // Set in JEventSource_EVIOpp constructor |
56 | |
57 | in_use = false; |
58 | jobtype = JOB_NONE; |
59 | |
60 | buff_len = 100; // this will grow as needed |
61 | buff = new uint32_t[buff_len]; |
62 | |
63 | PARSE_F250 = true; |
64 | PARSE_F125 = true; |
65 | PARSE_F1TDC = true; |
66 | PARSE_CAEN1290TDC = true; |
67 | PARSE_CONFIG = true; |
68 | PARSE_BOR = true; |
69 | PARSE_EPICS = true; |
70 | PARSE_EVENTTAG = true; |
71 | PARSE_TRIGGER = true; |
72 | PARSE_SSP = true; |
73 | PARSE_GEMSRS = true; |
74 | NSAMPLES_GEMSRS = 9; |
75 | |
76 | LINK_TRIGGERTIME = true; |
77 | } |
78 | |
79 | //--------------------------------- |
80 | // ~DEVIOWorkerThread (Destructor) |
81 | //--------------------------------- |
82 | DEVIOWorkerThread::~DEVIOWorkerThread() |
83 | { |
84 | if(buff) delete[] buff; |
85 | for(auto pe : parsed_event_pool) delete pe; |
86 | } |
87 | |
88 | //--------------------------------- |
89 | // Run |
90 | //--------------------------------- |
91 | void DEVIOWorkerThread::Run(void) |
92 | { |
93 | unique_lock<std::mutex> lck(mtx); |
94 | |
95 | // Loop waiting for jobs or until told to quit |
96 | while(!done){ |
97 | |
98 | cv.wait_for(lck, std::chrono::milliseconds(1)); |
99 | |
100 | // In principle, in_use should never be false with a jobtype!=JOB_NONE |
101 | // In practice, this has happened, possibly due to compiler optimization |
102 | // reordering things in JEventSource_EVIOpp::Dispatcher. That led to |
103 | // attempting to process a buffer that was being written to. Avoid that |
104 | // condition by checking the in_use flag is really set. |
105 | if( !in_use ) continue; |
106 | |
107 | try { |
108 | |
109 | if( jobtype & JOB_SWAP ) swap_bank(buff, buff, swap32(buff[0])( (((buff[0]) >> 24) & 0x000000FF) | (((buff[0]) >> 8) & 0x0000FF00) | (((buff[0]) << 8) & 0x00FF0000 ) | (((buff[0]) << 24) & 0xFF000000) )+1 ); |
110 | |
111 | if( jobtype & JOB_FULL_PARSE ) MakeEvents(); |
112 | |
113 | if( jobtype & JOB_ASSOCIATE ) LinkAllAssociations(); |
114 | |
115 | if( !current_parsed_events.empty() ) PublishEvents(); |
116 | |
117 | } catch( JExceptionDataFormat &e ){ |
118 | for(auto pe : parsed_event_pool) delete pe; // delete all parsed events any any objects they hold |
119 | parsed_event_pool.clear(); |
120 | current_parsed_events.clear(); // (these are also in parsed_event_pool so were already deleted) |
121 | jerr << "Data format error exception caught" << endl; |
122 | jerr << "Stack trace follows:" << endl; |
123 | jerr << e.getStackTrace() << endl; |
124 | jerr << e.what() << endl; |
125 | japp->Quit(10); |
126 | } catch (exception &e) { |
127 | jerr << e.what() << endl; |
128 | for(auto pe : parsed_event_pool) delete pe; // delete all parsed events any any objects they hold |
129 | parsed_event_pool.clear(); |
130 | current_parsed_events.clear(); // (these are also in parsed_event_pool so were already deleted) |
131 | japp->Quit(-1); |
132 | } |
133 | |
134 | // Reset and mark us as available for use |
135 | jobtype = JOB_NONE; |
136 | in_use = false; |
137 | |
138 | if( jobtype & JOB_QUIT ) break; |
139 | } |
140 | |
141 | in_use = false; |
142 | } |
143 | |
144 | //--------------------------------- |
145 | // Finish |
146 | //--------------------------------- |
147 | void DEVIOWorkerThread::Finish(bool wait_to_complete) |
148 | { |
149 | /// Set the done flag so that the worker thread |
150 | /// will exit once it is done processing its current |
151 | /// job. The thread is notified to wake up in case |
152 | /// it is currently idle. If the wait_to_complete |
153 | /// flag is set (default), then the worker thread is |
154 | /// joined to guarantee the current job's processing |
155 | /// is completed before returning. |
156 | done = true; |
157 | cv.notify_all(); |
158 | if(wait_to_complete) { |
159 | thd.join(); |
160 | } else { |
161 | thd.detach(); |
162 | } |
163 | } |
164 | |
165 | //--------------------------------- |
166 | // Prune |
167 | //--------------------------------- |
168 | void DEVIOWorkerThread::Prune(void) |
169 | { |
170 | /// Delete any DParsedEvent objects not currently in use. |
171 | /// If the DParsedEvent object pool and their internal |
172 | /// hit object pools are allowed to continuously grow, it |
173 | /// will appear as a though there is a memory leak. Occasional |
174 | /// pruning will reduce the average memory footprint. |
175 | /// This is called from MakeEvents() every MAX_EVENT_RECYCLES |
176 | /// EVIO events processed by this worker thread. |
177 | /// Note that this is in EVIO events (i.e. possibly a block |
178 | /// of events) not in L1 trigger events. |
179 | /// |
180 | /// NOTE: We currently do NOT reduce the size of buff |
181 | /// here if it is too big. We may wish to do that at some point! |
182 | |
183 | // Delete extra parsed events |
184 | vector<DParsedEvent*> tmp_events = parsed_event_pool; |
185 | parsed_event_pool.clear(); |
186 | for(auto pe : tmp_events) { |
187 | if(pe->in_use) |
188 | parsed_event_pool.push_back(pe); |
189 | else |
190 | delete pe; |
191 | |
192 | } |
193 | } |
194 | |
195 | //--------------------------------- |
196 | // MakeEvents |
197 | //--------------------------------- |
198 | void DEVIOWorkerThread::MakeEvents(void) |
199 | { |
200 | |
201 | /// Make DParsedEvent objects from data currently in buff. |
202 | /// This will look at the begining of the EVIO event to see |
203 | /// how many L1 events are in it. It will then grab that many |
204 | /// DParsedEvent objects from this threads pool , or create |
205 | /// new ones and add them all to the current_parsed_events |
206 | /// vector. These are then filled out later as the data is |
207 | /// parsed. |
208 | |
209 | if(!current_parsed_events.empty()) throw JException("Attempting call to DEVIOWorkerThread::MakeEvents when current_parsed_events not empty!!", __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__209); |
210 | |
211 | uint32_t *iptr = buff; |
212 | |
213 | uint32_t M = 1; |
214 | uint64_t event_num = 0; |
215 | |
216 | iptr++; |
217 | uint32_t mask = 0xFF001000; |
218 | if( (*iptr)>>16 == 0xFF32){ |
219 | |
220 | // CDAQ BOR. Leave M=1 |
221 | |
222 | }else if( (*iptr)>>16 == 0xFF33){ |
223 | |
224 | // CDAQ Physics event |
225 | M = iptr[2]&0xFF; |
226 | |
227 | // Event number taken from first ROC's trigger bank |
228 | uint64_t eventnum_lo = iptr[6]; |
229 | uint64_t eventnum_hi = 0; // Only lower 32bits in ROC trigger info. |
230 | event_num = (eventnum_hi<<32) + (eventnum_lo); |
231 | }else if( ((*iptr)&mask) == mask ){ |
232 | // CODA Physics event |
233 | M = *(iptr)&0xFF; |
234 | uint64_t eventnum_lo = iptr[4]; |
235 | uint64_t eventnum_hi = iptr[5]; |
236 | event_num = (eventnum_hi<<32) + (eventnum_lo); |
237 | } |
238 | |
239 | // Try and get M DParsedEvent objects from this thread's pool. |
240 | for(auto pe : parsed_event_pool){ |
241 | if(pe->in_use) continue; |
242 | current_parsed_events.push_back(pe); |
243 | if( current_parsed_events.size() >= M ) break; |
244 | } |
245 | |
246 | // Create new DParsedEvent objects if needed |
247 | while( current_parsed_events.size() < M ){ |
248 | DParsedEvent *pe = new DParsedEvent(MAX_OBJECT_RECYCLES); |
249 | current_parsed_events.push_back(pe); |
250 | parsed_event_pool.push_back(pe); |
251 | } |
252 | |
253 | // Set indexes for the parsed event objects |
254 | // and flag them as being in use. |
255 | if( VERBOSE>3 ) cout << " Creating " << current_parsed_events.size() << " parsed events ..." << endl; |
256 | for(auto pe : current_parsed_events){ |
257 | |
258 | pe->Clear(); // return previous event's objects to pools and clear vectors |
259 | pe->buff_len = buff_len; |
260 | pe->istreamorder = istreamorder; |
261 | pe->run_number = run_number_seed; |
262 | pe->event_number = event_num++; |
263 | pe->sync_flag = false; |
264 | pe->in_use = true; |
265 | pe->copied_to_factories = false; |
266 | pe->event_status_bits = 0; |
267 | pe->borptrs = NULL__null; // may be set by either ParseBORbank or JEventSource_EVIOpp::GetEvent |
268 | } |
269 | |
270 | // Parse data in buffer to create data objects |
271 | ParseBank(); |
272 | |
273 | // Occasionally prune extra DParsedEvent objects as well as objects |
274 | // from the existing pools to reduce average memory usage. We do |
275 | // this after parsing so that not everything is deleted (objects |
276 | // being used this event will be returned to the pools later.) |
277 | if(++Nrecycled%MAX_EVENT_RECYCLES == 0) Prune(); |
278 | for(auto pe : current_parsed_events){ |
279 | if( ++pe->Nrecycled%pe->MAX_RECYCLES == 0) pe->Prune(); |
280 | } |
281 | } |
282 | |
283 | //--------------------------------- |
284 | // PublishEvents |
285 | //--------------------------------- |
286 | void DEVIOWorkerThread::PublishEvents(void) |
287 | { |
288 | /// Copy our "current_parsed_events" pointers into the global "parsed_events" |
289 | /// list making them available for consumption. |
290 | |
291 | // Lock mutex so other threads can't modify parsed_events |
292 | unique_lock<mutex> lck(PARSED_EVENTS_MUTEX); |
293 | |
294 | // Make sure we don't exceed the maximum number of simultaneous |
295 | // parsed events. If the done flag is set, go ahead and add |
296 | // this regardless |
297 | while( ((current_parsed_events.size()+parsed_events.size())>=MAX_PARSED_EVENTS) && !done ){ |
298 | event_source->NPARSER_STALLED++; |
299 | PARSED_EVENTS_CV.wait_for(lck, std::chrono::milliseconds(1)); |
300 | } |
301 | |
302 | // Loop over all elements of parsed_events and insert |
303 | // these based on istreamorder so that the front element |
304 | // is the most recent. |
305 | bool inserted = false; |
306 | for(auto it = parsed_events.begin(); it!=parsed_events.end(); it++){ |
307 | if( istreamorder < (*it)->istreamorder ){ |
308 | parsed_events.insert(it, current_parsed_events.begin(), current_parsed_events.end()); |
309 | inserted = true; |
310 | break; |
311 | } |
312 | } |
313 | |
314 | // In case this should go at end of list |
315 | if(!inserted) parsed_events.insert(parsed_events.end(), current_parsed_events.begin(), current_parsed_events.end()); |
316 | |
317 | lck.unlock(); |
318 | PARSED_EVENTS_CV.notify_all(); |
319 | |
320 | // Any events should now be published |
321 | current_parsed_events.clear(); |
322 | } |
323 | |
324 | //--------------------------------- |
325 | // ParseBank |
326 | //--------------------------------- |
327 | void DEVIOWorkerThread::ParseBank(void) |
328 | { |
329 | uint32_t *iptr = buff; |
330 | uint32_t *iend = &buff[buff[0]+1]; |
331 | |
332 | while(iptr < iend){ |
333 | uint32_t event_len = iptr[0]; |
334 | uint32_t event_head = iptr[1]; |
335 | uint32_t tag = (event_head >> 16) & 0xFFFF; |
336 | |
337 | //_DBG_ << "0x" << hex << (uint64_t)iptr << dec << ": event_len=" << event_len << "tag=" << hex << tag << dec << endl; |
338 | |
339 | switch(tag){ |
340 | case 0x0060: ParseEPICSbank(iptr, iend); break; |
341 | case 0x0070: ParseBORbank(iptr, iend); break; |
342 | |
343 | case 0xFFD0: |
344 | case 0xFFD1: |
345 | case 0xFFD2: |
346 | case 0xFFD3: |
347 | case 0xFFD4: ParseControlEvent(iptr, iend); break; |
348 | |
349 | case 0xFF58: |
350 | case 0xFF78: current_parsed_events.back()->sync_flag = true; |
351 | case 0xFF50: |
352 | case 0xFF70: ParsePhysicsBank(iptr, iend); break; |
353 | case 0xFF32: |
354 | case 0xFF33: ParseCDAQBank(iptr, iend); break; |
355 | |
356 | default: |
357 | _DBG_std::cerr<<"libraries/DAQ/DEVIOWorkerThread.cc"<< ":"<<357<<" " << "Unknown outer EVIO bank tag: " << hex << tag << dec << endl; |
358 | iptr = &iptr[event_len+1]; |
359 | if(event_len<1) iptr = iend; |
360 | } |
361 | } |
362 | } |
363 | |
364 | //--------------------------------- |
365 | // ParseEventTagBank |
366 | //--------------------------------- |
367 | void DEVIOWorkerThread::ParseEventTagBank(uint32_t* &iptr, uint32_t *iend) |
368 | { |
369 | // skip the bank header |
370 | // EventTag is stored in a bank of banks with only 1 data bank |
371 | // so just skip the data bank header for now. |
372 | |
373 | iptr++; // data bank length |
374 | iptr++; // data bank header |
375 | |
376 | uint64_t evt_status_lo = *iptr++; |
377 | uint64_t evt_status_hi = *iptr++; |
378 | uint64_t l3_status_lo = *iptr++; |
379 | uint64_t l3_status_hi = *iptr++; |
380 | auto l3_decision = (DL3Trigger::L3_decision_t)*iptr++; |
381 | uint32_t l3_algorithm = *iptr++; |
382 | uint32_t mva_encoded = *iptr++; |
383 | |
384 | uint64_t evt_status = evt_status_lo + (evt_status_hi<<32); |
385 | uint64_t l3_status = l3_status_lo + ( l3_status_hi<<32); |
386 | |
387 | DParsedEvent *pe = current_parsed_events.front(); |
388 | pe->NEW_DEventTag(evt_status, l3_decision, l3_status, l3_algorithm, mva_encoded); |
389 | |
390 | iptr = iend; |
391 | } |
392 | |
393 | //--------------------------------- |
394 | // ParseEPICSbank |
395 | //--------------------------------- |
396 | void DEVIOWorkerThread::ParseEPICSbank(uint32_t* &iptr, uint32_t *iend) |
397 | { |
398 | if(!PARSE_EPICS){ iptr = iend; return; } |
399 | |
400 | time_t timestamp=0; |
401 | |
402 | // Outer bank |
403 | uint32_t *istart = iptr; |
404 | uint32_t epics_bank_len = *iptr++; |
405 | if(epics_bank_len < 1){ |
406 | _DBG_std::cerr<<"libraries/DAQ/DEVIOWorkerThread.cc"<< ":"<<406<<" " << "bank_len<1 in EPICS event!" << endl; |
407 | iptr = iend; |
408 | return; |
409 | } |
410 | |
411 | uint32_t *iend_epics = &iptr[epics_bank_len]; |
412 | |
413 | // Advance to first daughter bank |
414 | iptr++; |
415 | |
416 | // Get pointer to first DParsedEvent |
417 | DParsedEvent *pe = current_parsed_events.front(); |
418 | pe->event_status_bits |= (1<<kSTATUS_EPICS_EVENT); |
419 | |
420 | // Loop over daughter banks |
421 | while( iptr < iend_epics ){ |
422 | |
423 | uint32_t bank_len = (*iptr)&0xFFFF; |
424 | uint32_t tag = ((*iptr)>>24)&0xFF; |
425 | iptr++; |
426 | |
427 | if(tag == 0x61){ |
428 | // timestamp bank |
429 | timestamp = *iptr; |
430 | }else if(tag == 0x62){ |
431 | // EPICS data value |
432 | string nameval = (const char*)iptr; |
433 | pe->NEW_DEPICSvalue(timestamp, nameval); |
434 | }else{ |
435 | // Unknown tag. Bail |
436 | _DBG_std::cerr<<"libraries/DAQ/DEVIOWorkerThread.cc"<< ":"<<436<<" " << "Unknown tag 0x" << hex << tag << dec << " in EPICS event!" <<endl; |
437 | DumpBinary(istart, iend_epics, 32, &iptr[-1]); |
438 | throw JExceptionDataFormat("Unknown tag in EPICS bank", __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__438); |
439 | } |
440 | |
441 | iptr = &iptr[bank_len]; |
442 | } |
443 | |
444 | iptr = iend_epics; |
445 | } |
446 | |
447 | //--------------------------------- |
448 | // ParseBORbank |
449 | //--------------------------------- |
450 | void DEVIOWorkerThread::ParseBORbank(uint32_t* &iptr, uint32_t *iend) |
451 | { |
452 | /// Create BOR config objects from the EVIO bank and store them in |
453 | /// the event (should only be one since BOR events are not entangled). |
454 | /// These objects will eventually be inherited by the JEventSource_EVIOpp |
455 | /// object and passed to all subsequent events. |
456 | |
457 | // Upon entry, iptr should point to length word of a bank of banks with tag=0x70 |
458 | // indicating BOR event. Each bank contained within will represent one crate and |
459 | // will be a bank with tag=0x71 and num the rocid, containing tagsegments. Each tagsegment |
460 | // represents a single module with the tag containing the module type (bits 0-4) and |
461 | // slot (bits 5-10). The data in the tagsegments is uint32_t and maps to a data |
462 | // structure in bor_roc.h depending on the module type. Below is a summary of |
463 | // how this looks in memory: |
464 | // |
465 | // BOR event length |
466 | // BOR header |
467 | // crate bank length |
468 | // crate header |
469 | // module bank len/header |
470 | // module data ... |
471 | // module bank len/header |
472 | // module data ... |
473 | // ... |
474 | // crate bank length |
475 | // crate header |
476 | // ... |
477 | |
478 | if(!PARSE_BOR){ iptr = &iptr[(*iptr) + 1]; return; } |
479 | if(VERBOSE>1) jout << "--- Parsing BOR Bank" << endl; |
480 | |
481 | // Make sure there is exactly 1 event in current_parsed_events |
482 | if(current_parsed_events.size() != 1){ |
483 | stringstream ss; |
484 | ss << "DEVIOWorkerThread::ParseBORbank called for EVIO event with " << current_parsed_events.size() << " events in it. (Should be exactly 1!)"; |
485 | jerr << ss.str() << endl; |
486 | jerr << "EVIO length=" << hex << iptr[0] << " header=" << iptr[1] << endl; |
487 | throw JExceptionDataFormat(ss.str(), __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__487); |
488 | } |
489 | |
490 | // Create new DBORptrs object and set pointer to it in DParsedEvent |
491 | // (see JEventSource_EVIOpp::GetEvent) |
492 | DParsedEvent *pe = current_parsed_events.front(); |
493 | pe->event_status_bits |= (1<<kSTATUS_BOR_EVENT); |
494 | pe->borptrs = new DBORptrs(); |
495 | DBORptrs* &borptrs = pe->borptrs; |
496 | |
497 | // Make sure we have full event |
498 | uint32_t borevent_len = *iptr++; |
499 | uint32_t bank_len = (uint32_t)((uint64_t)iend - (uint64_t)iptr)/sizeof(uint32_t); |
500 | if(borevent_len > bank_len){ |
501 | stringstream ss; |
502 | ss << "BOR: Size of bank doesn't match amount of data given (" << borevent_len << " > " << bank_len << ")"; |
503 | throw JExceptionDataFormat(ss.str(), __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__503); |
504 | } |
505 | iend = &iptr[borevent_len]; // in case they give us too much data! |
506 | |
507 | // Make sure BOR header word is right |
508 | // n.b. CODA writes bor_header = 0x700e01 |
509 | // CDAQ replaces the last "01" with the number of crates. |
510 | // Prior to Fall 2019 this was 0x700e34 and then 2 more crates |
511 | // were added to make it 0x700e36. Now we just ignore those |
512 | // lower 8 bits so this doesn't break in the future. |
513 | uint32_t bor_header = *iptr++; |
514 | // if( (bor_header!=0x700e01) && (bor_header!=0x700e34) ){ |
515 | if( (bor_header>>8) != 0x700e ){ |
516 | stringstream ss; |
517 | ss << "Bad BOR header: 0x" << hex << bor_header; |
518 | _DBG_std::cerr<<"libraries/DAQ/DEVIOWorkerThread.cc"<< ":"<<518<<" "<< ss.str() << endl; |
519 | DumpBinary(&iptr[-4], iend, 32, iptr); |
520 | throw JExceptionDataFormat(ss.str(), __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__520); |
521 | } |
522 | |
523 | // Loop over crates |
524 | while(iptr<iend){ |
525 | uint32_t crate_len = *iptr++; |
526 | uint32_t *iend_crate = &iptr[crate_len]; // points to first word after this crate |
527 | uint32_t crate_header = *iptr++; |
528 | // uint32_t rocid = crate_header&0xFF; |
529 | |
530 | // Make sure crate tag is right |
531 | if( (crate_header>>16) != 0x71 ){ |
532 | stringstream ss; |
533 | ss << "Bad BOR crate header: 0x" << hex << (crate_header>>16); |
534 | _DBG_std::cerr<<"libraries/DAQ/DEVIOWorkerThread.cc"<< ":"<<534<<" "<< ss.str() << endl; |
535 | throw JExceptionDataFormat(ss.str(), __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__535); |
536 | } |
537 | |
538 | // Loop over modules |
539 | while(iptr<iend_crate){ |
540 | uint32_t module_header = *iptr++; |
541 | uint32_t module_len = module_header&0xFFFF; |
542 | uint32_t modType = (module_header>>20)&0x1f; |
543 | // uint32_t slot = (module_header>>25); |
544 | // uint32_t *iend_module = &iptr[module_len]; // points to first word after this module |
545 | |
546 | uint32_t *src = iptr; |
547 | uint32_t *dest = NULL__null; |
548 | uint32_t sizeof_dest = 0; |
549 | |
550 | Df250BORConfig *f250conf = NULL__null; |
551 | Df125BORConfig *f125conf = NULL__null; |
552 | DF1TDCBORConfig *F1TDCconf = NULL__null; |
553 | DCAEN1290TDCBORConfig *caen1190conf = NULL__null; |
554 | DTSGBORConfig *tsgconf = NULL__null; |
555 | |
556 | switch(modType){ |
557 | case DModuleType::FADC250: // f250 |
558 | f250conf = new Df250BORConfig; |
559 | dest = (uint32_t*)&f250conf->rocid; |
560 | sizeof_dest = sizeof(f250config)/sizeof(uint32_t); |
561 | break; |
562 | case DModuleType::FADC125: // f125 |
563 | f125conf = new Df125BORConfig; |
564 | dest = (uint32_t*)&f125conf->rocid; |
565 | sizeof_dest = sizeof(f125config)/sizeof(uint32_t); |
566 | break; |
567 | |
568 | case DModuleType::F1TDC32: // F1TDCv2 |
569 | case DModuleType::F1TDC48: // F1TDCv3 |
570 | F1TDCconf = new DF1TDCBORConfig; |
571 | dest = (uint32_t*)&F1TDCconf->rocid; |
572 | sizeof_dest = sizeof(F1TDCconfig)/sizeof(uint32_t); |
573 | break; |
574 | |
575 | case DModuleType::CAEN1190: // CAEN 1190 TDC |
576 | case DModuleType::CAEN1290: // CAEN 1290 TDC |
577 | caen1190conf = new DCAEN1290TDCBORConfig; |
578 | dest = (uint32_t*)&caen1190conf->rocid; |
579 | sizeof_dest = sizeof(caen1190config)/sizeof(uint32_t); |
580 | break; |
581 | case DModuleType::CDAQTSG: // TSG (from CDAQ) |
582 | tsgconf = new DTSGBORConfig; |
583 | // Accomodate variable number of words by copying here |
584 | tsgconf->rocid = 81; // rocid member must exist for LinkAssociations.h::SortByModule |
585 | tsgconf->slot = 1; // " " " |
586 | tsgconf->run_number = src[0]; |
587 | tsgconf->unix_time = src[1]; |
588 | for(uint32_t i=0; i<module_len; i++) tsgconf->misc_words.push_back(src[i]); |
589 | |
590 | sizeof_dest = module_len; // prevent error from being thrown below |
591 | dest = src; // make copy benign. This allows us to keep mechansim used by other modules |
592 | break; |
593 | |
594 | default: |
595 | { |
596 | stringstream ss; |
597 | ss << "Unknown BOR module type: " << modType << " (module_header=0x"<<hex<<module_header<<")"; |
598 | jerr << ss.str() << endl; |
599 | throw JExceptionDataFormat(ss.str(), __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__599); |
600 | } |
601 | } |
602 | |
603 | // Check that the bank size and data structure size match. |
604 | if( module_len > sizeof_dest ){ |
605 | stringstream ss; |
606 | ss << "BOR module bank size does not match structure! " << module_len << " > " << sizeof_dest << " for modType " << modType; |
607 | _DBG_std::cerr<<"libraries/DAQ/DEVIOWorkerThread.cc"<< ":"<<607<<" "<< ss.str() << endl; |
608 | throw JExceptionDataFormat(ss.str(), __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__608); |
609 | } |
610 | |
611 | // Copy bank data, assuming format is the same |
612 | // Set extra words to "0" at end of structure |
613 | // in case we are processing data from older firmware |
614 | for(uint32_t i=0; i<sizeof_dest; i++) *dest++ = i<module_len ? (*src++):0; |
615 | |
616 | // Extract certain derived values to fill in convenience members |
617 | if(f250conf ) f250conf->FillDerived(); |
618 | |
619 | // Store object for use in this and subsequent events |
620 | if(f250conf ) borptrs->vDf250BORConfig.push_back(f250conf); |
621 | if(f125conf ) borptrs->vDf125BORConfig.push_back(f125conf); |
622 | if(F1TDCconf ) borptrs->vDF1TDCBORConfig.push_back(F1TDCconf); |
623 | if(caen1190conf) borptrs->vDCAEN1290TDCBORConfig.push_back(caen1190conf); |
624 | if(tsgconf ) borptrs->vDTSGBORConfig.push_back(tsgconf); |
625 | |
626 | iptr = &iptr[module_len]; |
627 | } |
628 | |
629 | iptr = iend_crate; // ensure we're pointing past this crate |
630 | } |
631 | |
632 | // Sort the BOR config events now so we don't have to do it for every event |
633 | borptrs->Sort(); |
634 | } |
635 | |
636 | //--------------------------------- |
637 | // ParseTSscalerBank |
638 | //--------------------------------- |
639 | void DEVIOWorkerThread::ParseTSscalerBank(uint32_t* &iptr, uint32_t *iend) |
640 | { |
641 | uint32_t Nwords = ((uint64_t)iend - (uint64_t)iptr)/sizeof(uint32_t); |
642 | uint32_t Nwords_expected = (6+32+16+32+16); |
643 | if(Nwords != Nwords_expected){ |
644 | _DBG_std::cerr<<"libraries/DAQ/DEVIOWorkerThread.cc"<< ":"<<644<<" " << "TS bank size does not match expected!!" << endl; |
645 | _DBG_std::cerr<<"libraries/DAQ/DEVIOWorkerThread.cc"<< ":"<<645<<" " << "Found " << Nwords << " words. Expected " << Nwords_expected << endl; |
646 | throw JExceptionDataFormat("TS bank size does not match expected", __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__646); |
647 | }else{ |
648 | // n.b. Get the last event here since if this is a block |
649 | // of events, the last should be the actual sync event. |
650 | DParsedEvent *pe = current_parsed_events.back(); |
651 | DL1Info *s = pe->NEW_DL1Info(); |
652 | s->nsync = *iptr++; |
653 | s->trig_number = *iptr++; |
654 | s->live_time = *iptr++; |
655 | s->busy_time = *iptr++; |
656 | s->live_inst = *iptr++; |
657 | s->unix_time = *iptr++; |
658 | for(uint32_t i=0; i<32; i++) s->gtp_sc.push_back ( *iptr++ ); |
659 | for(uint32_t i=0; i<16; i++) s->fp_sc.push_back ( *iptr++ ); |
660 | for(uint32_t i=0; i<32; i++) s->gtp_rate.push_back( *iptr++ ); |
661 | for(uint32_t i=0; i<16; i++) s->fp_rate.push_back ( *iptr++ ); |
662 | } |
663 | |
664 | iptr = iend; |
665 | } |
666 | |
667 | //--------------------------------- |
668 | // Parsef250scalerBank |
669 | //--------------------------------- |
670 | void DEVIOWorkerThread::Parsef250scalerBank(uint32_t rocid, uint32_t* &iptr, uint32_t *iend) |
671 | { |
672 | |
673 | uint32_t Nwords = ((uint64_t)iend - (uint64_t)iptr)/sizeof(uint32_t); |
674 | |
675 | if(Nwords < 4){ |
676 | _DBG_std::cerr<<"libraries/DAQ/DEVIOWorkerThread.cc"<< ":"<<676<<" " << "250Scaler bank size does not match expected!!" << endl; |
677 | _DBG_std::cerr<<"libraries/DAQ/DEVIOWorkerThread.cc"<< ":"<<677<<" " << "Found " << Nwords << endl; |
678 | throw JExceptionDataFormat("250scaler bank size does not match expected", __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__678); |
679 | } else { |
680 | |
681 | DParsedEvent *pe = current_parsed_events.back(); |
682 | |
683 | Df250Scaler *sc = pe->NEW_Df250Scaler(); |
684 | |
685 | sc->nsync = *iptr++; |
686 | sc->trig_number = *iptr++; |
687 | sc->version = *iptr++; |
688 | sc->crate = rocid; |
689 | |
690 | while(iptr < iend){ |
691 | // cout << " " << *iptr << endl; |
692 | sc->fa250_sc.push_back(*iptr++); |
693 | } |
694 | |
695 | } |
696 | |
697 | iptr = iend; |
698 | |
699 | } |
700 | |
701 | //--------------------------------- |
702 | // ParseControlEvent |
703 | //--------------------------------- |
704 | void DEVIOWorkerThread::ParseControlEvent(uint32_t* &iptr, uint32_t *iend) |
705 | { |
706 | |
707 | time_t t = (time_t)iptr[2]; |
708 | string tstr = ctime(&t); |
709 | if(tstr.size()>1) tstr.erase(tstr.size()-1); |
710 | |
711 | string type = "Control"; |
712 | switch(iptr[1]>>16){ |
713 | case 0XFFD0: type = "Sync"; break; |
714 | case 0XFFD1: type = "Prestart"; break; |
715 | case 0XFFD2: type = "Go"; break; |
716 | case 0XFFD3: type = "Pause"; break; |
717 | case 0XFFD4: type = "End"; break; |
718 | } |
719 | |
720 | jout << "Control event: " << type << " - " << tstr << endl; |
721 | |
722 | for(auto pe : current_parsed_events) { |
723 | pe->event_status_bits |= (1<<kSTATUS_CONTROL_EVENT); |
724 | auto controlevent = pe->NEW_DCODAControlEvent(); |
725 | controlevent->event_type = iptr[1]>>16; |
726 | controlevent->unix_time = t; |
727 | for(auto p = iptr; p!=iend; p++) controlevent->words.push_back(*p); |
728 | } |
729 | |
730 | iptr = &iptr[(*iptr) + 1]; |
731 | } |
732 | |
733 | //--------------------------------- |
734 | // ParsePhysicsBank |
735 | //--------------------------------- |
736 | void DEVIOWorkerThread::ParsePhysicsBank(uint32_t* &iptr, uint32_t *iend) |
737 | { |
738 | |
739 | for(auto pe : current_parsed_events) pe->event_status_bits |= (1<<kSTATUS_PHYSICS_EVENT) + (1<<kSTATUS_CODA); |
740 | |
741 | uint32_t physics_event_len = *iptr++; |
742 | uint32_t *iend_physics_event = &iptr[physics_event_len]; |
743 | iptr++; |
744 | |
745 | // Built Trigger Bank |
746 | uint32_t built_trigger_bank_len = *iptr; |
747 | uint32_t *iend_built_trigger_bank = &iptr[built_trigger_bank_len+1]; |
748 | ParseBuiltTriggerBank(iptr, iend_built_trigger_bank); |
749 | iptr = iend_built_trigger_bank; |
750 | |
751 | // Loop over Data banks |
752 | while( iptr < iend_physics_event ) { |
753 | |
754 | uint32_t data_bank_len = *iptr; |
755 | uint32_t *iend_data_bank = &iptr[data_bank_len+1]; |
756 | |
757 | ParseDataBank(iptr, iend_data_bank); |
758 | |
759 | iptr = iend_data_bank; |
760 | } |
761 | |
762 | iptr = iend_physics_event; |
763 | } |
764 | |
765 | //--------------------------------- |
766 | // ParseCDAQBank |
767 | //--------------------------------- |
768 | void DEVIOWorkerThread::ParseCDAQBank(uint32_t* &iptr, uint32_t *iend) |
769 | { |
770 | |
771 | if(VERBOSE>1) jout << "-- Parsing CDAQ Event" << endl; |
772 | |
773 | // Check if this is a BOR event |
774 | if( (iptr[1]&0xFFFF0000) == 0xFF320000 ){ |
775 | iptr += 2; |
776 | try{ |
777 | ParseBORbank(iptr, iend); |
778 | }catch(JException &e){ |
779 | cerr << e.what(); |
780 | } |
781 | return; |
782 | } |
783 | |
784 | // Must be physics event(s) |
785 | for(auto pe : current_parsed_events) pe->event_status_bits |= (1<<kSTATUS_PHYSICS_EVENT) + (1<<kSTATUS_CDAQ); |
786 | |
787 | // Set flag in JEventSource_EVIOpp that this is a CDAQ file |
788 | event_source->IS_CDAQ_FILE = true; |
789 | |
790 | uint32_t physics_event_len = *iptr++; |
791 | uint32_t *iend_physics_event = &iptr[physics_event_len]; |
792 | iptr++; |
793 | |
794 | // Loop over Data banks |
795 | while( iptr < iend_physics_event ) { |
796 | |
797 | uint32_t data_bank_len = *iptr; |
798 | uint32_t *iend_data_bank = &iptr[data_bank_len+1]; |
799 | |
800 | ParseDataBank(iptr, iend_data_bank); |
801 | |
802 | iptr = iend_data_bank; |
803 | } |
804 | |
805 | iptr = iend_physics_event; |
806 | } |
807 | |
808 | //--------------------------------- |
809 | // ParseBuiltTriggerBank |
810 | //--------------------------------- |
811 | void DEVIOWorkerThread::ParseBuiltTriggerBank(uint32_t* &iptr, uint32_t *iend) |
812 | { |
813 | if(!PARSE_TRIGGER) return; |
814 | |
815 | iptr++; // advance past length word |
816 | uint32_t mask = 0xFF202000; |
817 | if( ((*iptr) & mask) != mask ){ |
818 | stringstream ss; |
819 | ss << "Bad header word in Built Trigger Bank: " << hex << *iptr; |
820 | throw JExceptionDataFormat(ss.str(), __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__820); |
821 | } |
822 | |
823 | uint32_t tag = (*iptr)>>16; // 0xFF2X |
824 | uint32_t Nrocs = (*iptr++) & 0xFF; |
825 | uint32_t Mevents = current_parsed_events.size(); |
826 | |
827 | // sanity check: |
828 | if(Mevents == 0) { |
829 | stringstream ss; |
830 | ss << "DEVIOWorkerThread::ParseBuiltTriggerBank() called with zero events! "<<endl; |
831 | throw JExceptionDataFormat(ss.str(), __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__831); |
832 | } |
833 | |
834 | |
835 | //-------- Common data (64bit) |
836 | uint32_t common_header64 = *iptr++; |
837 | uint32_t common_header64_len = common_header64 & 0xFFFF; |
838 | uint64_t *iptr64 = (uint64_t*)iptr; |
839 | iptr = &iptr[common_header64_len]; |
840 | |
841 | // First event number |
842 | uint64_t first_event_num = *iptr64++; |
843 | |
844 | // Hi and lo 32bit words in 64bit numbers seem to be |
845 | // switched for events read from ET, but not read from |
846 | // file. Not sure if this is in the swapping routine |
847 | if(event_source->source_type==event_source->kETSource) first_event_num = (first_event_num>>32) | (first_event_num<<32); |
848 | |
849 | // Average timestamps |
850 | uint32_t Ntimestamps = (common_header64_len/2)-1; |
851 | if(tag & 0x2) Ntimestamps--; // subtract 1 for run number/type word if present |
852 | vector<uint64_t> avg_timestamps; |
853 | for(uint32_t i=0; i<Ntimestamps; i++) avg_timestamps.push_back(*iptr64++); |
854 | |
855 | // run number and run type |
856 | uint32_t run_number = 0; |
857 | uint32_t run_type = 0; |
858 | if(tag & 0x02){ |
859 | run_number = (*iptr64) >> 32; |
860 | run_type = (*iptr64) & 0xFFFFFFFF; |
861 | iptr64++; |
862 | } |
863 | |
864 | //-------- Common data (16bit) |
865 | uint32_t common_header16 = *iptr++; |
866 | uint32_t common_header16_len = common_header16 & 0xFFFF; |
867 | uint16_t *iptr16 = (uint16_t*)iptr; |
868 | iptr = &iptr[common_header16_len]; |
869 | |
870 | vector<uint16_t> event_types; |
871 | for(uint32_t i=0; i<Mevents; i++) event_types.push_back(*iptr16++); |
872 | |
873 | //-------- ROC data (32bit) |
874 | for(uint32_t iroc=0; iroc<Nrocs; iroc++){ |
875 | uint32_t common_header32 = *iptr++; |
876 | uint32_t common_header32_len = common_header32 & 0xFFFF; |
877 | uint32_t rocid = common_header32 >> 24; |
878 | |
879 | uint32_t Nwords_per_event = common_header32_len/Mevents; |
880 | for(auto pe : current_parsed_events){ |
881 | |
882 | DCODAROCInfo *codarocinfo = pe->NEW_DCODAROCInfo(); |
883 | codarocinfo->rocid = rocid; |
884 | |
885 | uint64_t ts_low = *iptr++; |
886 | uint64_t ts_high = *iptr++; |
887 | codarocinfo->timestamp = (ts_high<<32) + ts_low; |
888 | codarocinfo->misc.clear(); // could be recycled from previous event |
889 | for(uint32_t i=2; i<Nwords_per_event; i++) codarocinfo->misc.push_back(*iptr++); |
890 | |
891 | if(iptr > iend){ |
892 | throw JExceptionDataFormat("Bad data format in ParseBuiltTriggerBank!", __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__892); |
893 | } |
894 | } |
895 | } |
896 | |
897 | //-------- Make DCODAEventInfo objects |
898 | uint64_t ievent = 0; |
899 | for(auto pe : current_parsed_events){ |
900 | |
901 | pe->run_number = run_number; // may be overwritten in JEventSource_EVIOpp::GetEvent() |
902 | |
903 | DCODAEventInfo *codaeventinfo = pe->NEW_DCODAEventInfo(); |
904 | codaeventinfo->run_number = run_number; |
905 | codaeventinfo->run_type = run_type; |
906 | codaeventinfo->event_number = first_event_num + ievent; |
907 | codaeventinfo->event_type = event_types.empty() ? 0:event_types[ievent]; |
908 | codaeventinfo->avg_timestamp = avg_timestamps.empty() ? 0:avg_timestamps[ievent]; |
909 | ievent++; |
910 | } |
911 | } |
912 | |
913 | //--------------------------------- |
914 | // ParseRawTriggerBank |
915 | //--------------------------------- |
916 | void DEVIOWorkerThread::ParseRawTriggerBank(uint32_t rocid, uint32_t* &iptr, uint32_t *iend) |
917 | { |
918 | // CDAQ records the raw trigger bank rather than the built trigger bank. |
919 | // Create DCODAROCInfo objects for each of these. |
920 | |
921 | if(!PARSE_TRIGGER) return; |
922 | |
923 | // On entry, iptr points to word after the bank header (i.e. word after the one with 0xFF11) |
924 | |
925 | // Loop over events. Should be one segment for each event |
926 | // suppress warning |
927 | // uint32_t ievent = 0; |
928 | for(auto pe : current_parsed_events){ |
929 | |
930 | uint32_t segment_header = *iptr++; |
931 | uint32_t segment_len = segment_header&0xFFFF; |
932 | uint32_t *iend_segment = &iptr[segment_len]; |
933 | |
934 | // suppress warning, remove assignment to unused variable but increment the pointer |
935 | // uint32_t event_number = *iptr++; |
936 | iptr++; |
937 | uint64_t ts_low = *iptr++; |
938 | uint64_t ts_high = *iptr++; |
939 | |
940 | DCODAROCInfo *codarocinfo = pe->NEW_DCODAROCInfo(); |
941 | codarocinfo->rocid = rocid; |
942 | codarocinfo->timestamp = (ts_high<<32) + ts_low; |
943 | codarocinfo->misc.clear(); // could be recycled from previous event |
944 | |
945 | // rocid=1 is TS and produces 2 extra words for the trigger bits |
946 | for(uint32_t i=3; i<segment_len; i++) codarocinfo->misc.push_back(*iptr++); |
947 | |
948 | if( iptr != iend_segment){ |
949 | throw JExceptionDataFormat("Bad raw trigger bank format", __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__949); |
950 | } |
951 | } |
952 | } |
953 | |
954 | //--------------------------------- |
955 | // ParseDataBank |
956 | //--------------------------------- |
957 | void DEVIOWorkerThread::ParseDataBank(uint32_t* &iptr, uint32_t *iend) |
958 | { |
959 | // Physics Event's Data Bank header |
960 | iptr++; // advance past data bank length word |
961 | uint32_t rocid = ((*iptr)>>16) & 0xFFF; |
962 | iptr++; |
963 | |
964 | if(!ROCIDS_TO_PARSE.empty()){ |
965 | if(ROCIDS_TO_PARSE.find(rocid) == ROCIDS_TO_PARSE.end()) return; |
966 | } |
967 | |
968 | // Loop over Data Block Banks |
969 | while(iptr < iend){ |
970 | |
971 | uint32_t data_block_bank_len = *iptr++; |
972 | uint32_t *iend_data_block_bank = &iptr[data_block_bank_len]; |
973 | uint32_t data_block_bank_header = *iptr++; |
974 | |
975 | // Not sure where this comes from, but it needs to be skipped if present |
976 | while( (*iptr==0xF800FAFA) && (iptr<iend) ) iptr++; |
977 | |
978 | uint32_t det_id = (data_block_bank_header>>16) & 0xFFF; |
979 | switch(det_id){ |
980 | |
981 | case 20: |
982 | if(VERBOSE>3) jout << " -- CAEN1190 rocid="<< rocid << endl; |
983 | ParseCAEN1190(rocid, iptr, iend_data_block_bank); |
984 | break; |
985 | |
986 | case 0x55: |
987 | if(VERBOSE>3) jout <<" -- Module Configuration rocid="<< rocid << endl; |
988 | ParseModuleConfiguration(rocid, iptr, iend_data_block_bank); |
989 | break; |
990 | |
991 | case 0x56: |
992 | if(VERBOSE>3) jout <<" -- Event Tag rocid="<< rocid << endl; |
993 | ParseEventTagBank(iptr, iend_data_block_bank); |
994 | break; |
995 | |
996 | case 0: |
997 | case 1: |
998 | case 3: |
999 | case 6: // flash 250 module, MMD 2014/2/4 |
1000 | case 16: // flash 125 module (CDC), DL 2014/6/19 |
1001 | case 26: // F1 TDC module (BCAL), MMD 2014-07-31 |
1002 | if(VERBOSE>3) jout <<" -- JLab Module rocid="<< rocid << endl; |
1003 | ParseJLabModuleData(rocid, iptr, iend_data_block_bank); |
1004 | break; |
1005 | |
1006 | case 0x123: |
1007 | case 0x28: |
1008 | if(VERBOSE>3) jout <<" -- SSP rocid="<< rocid << endl; |
1009 | ParseSSPBank(rocid, iptr, iend_data_block_bank); |
1010 | break; |
1011 | |
1012 | // These were implemented in the ROL for sync events |
1013 | // as 0xEE02 and 0xEE05. However, that violates the |
1014 | // spec. which reserves the top 4 bits as status bits |
1015 | // (the first "E" should really be a "1". We just check |
1016 | // other 12 bits here. |
1017 | case 0xE02: |
1018 | if(VERBOSE>3) jout <<" -- TSscaler rocid="<< rocid << endl; |
1019 | ParseTSscalerBank(iptr, iend); |
1020 | break; |
1021 | case 0xE05: |
1022 | // Parsef250scalerBank(iptr, iend); |
1023 | break; |
1024 | case 0xE10: |
1025 | Parsef250scalerBank(rocid, iptr, iend_data_block_bank); |
1026 | break; |
1027 | |
1028 | // The CDAQ system leave the raw trigger info in the Physics event data |
1029 | // bank. Skip it for now. |
1030 | case 0xF11: |
1031 | if(VERBOSE>3) jout <<"Raw Trigger bank rocid="<< rocid << endl; |
1032 | ParseRawTriggerBank(rocid, iptr, iend_data_block_bank); |
1033 | break; |
1034 | |
1035 | // When we write out single events in the offline, we also can save some |
1036 | // higher level data objects to save disk space and speed up |
1037 | // specialized processing (e.g. pi0 calibration) |
1038 | case 0xD01: |
1039 | ParseDVertexBank(iptr, iend_data_block_bank); |
1040 | break; |
1041 | case 0xD02: |
1042 | ParseDEventRFBunchBank(iptr, iend_data_block_bank); |
1043 | break; |
1044 | |
1045 | case 5: |
1046 | // old ROL Beni used had this but I don't think its |
1047 | // been used for years. Run 10390 seems to have |
1048 | // this though (???) |
1049 | break; |
1050 | |
1051 | case 0x11: |
1052 | // attempt at GEM SRS parsing |
1053 | ParseDGEMSRSBank(rocid, iptr, iend_data_block_bank); |
1054 | break; |
1055 | |
1056 | default: |
1057 | jerr<<"Unknown module type ("<<det_id<<" = 0x" << hex << det_id << dec << " ) encountered" << endl; |
1058 | // if(VERBOSE>5){ |
1059 | cout << "----- First few words to help with debugging -----" << endl; |
1060 | cout.flush(); cerr.flush(); |
1061 | DumpBinary(&iptr[-2], iend, 32, &iptr[-1]); |
1062 | // } |
1063 | throw JExceptionDataFormat("Unknown bank type in EVIO", __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__1063); |
1064 | |
1065 | } |
1066 | |
1067 | iptr = iend_data_block_bank; |
1068 | } |
1069 | |
1070 | } |
1071 | |
1072 | //---------------- |
1073 | // ParseTIBank |
1074 | //---------------- |
1075 | void DEVIOWorkerThread::ParseTIBank(uint32_t rocid, uint32_t* &iptr, uint32_t* iend) |
1076 | { |
1077 | while(iptr<iend && ((*iptr) & 0xF8000000) != 0x88000000) iptr++; // Skip to JLab block trailer |
1078 | iptr++; // advance past JLab block trailer |
1079 | while(iptr<iend && *iptr == 0xF8000000) iptr++; // skip filler words after block trailer |
1080 | //iptr = iend; |
1081 | } |
1082 | |
1083 | //---------------- |
1084 | // ParseCAEN1190 |
1085 | //---------------- |
1086 | void DEVIOWorkerThread::ParseCAEN1190(uint32_t rocid, uint32_t* &iptr, uint32_t *iend) |
1087 | { |
1088 | if(!PARSE_CAEN1290TDC){ iptr = &iptr[(*iptr) + 1]; return; } |
1089 | |
1090 | /// Parse data from a CAEN 1190 or 1290 module |
1091 | /// (See ppg. 72-74 of V1290_REV15.pdf manual) |
1092 | |
1093 | uint32_t slot = 0; |
1094 | uint32_t event_count = 0; |
1095 | uint32_t word_count = 0; |
1096 | uint32_t trigger_time_tag = 0; |
1097 | uint32_t tdc_num = 0; |
1098 | uint32_t event_id = 0; |
1099 | uint32_t bunch_id = 0; |
1100 | |
1101 | // We need to accomodate multi-event blocks where |
1102 | // events are entangled (i.e. hits from event 1 |
1103 | // are mixed in between those of event 2,3,4, |
1104 | // etc... With CAEN modules, we only know which |
1105 | // event a hit came from by looking at the event_id |
1106 | // in the TDC header. This value is only 12 bits |
1107 | // and could roll over within an event block. This |
1108 | // means we need to keep track of the order we |
1109 | // encounter them in so it is maintained in the |
1110 | // "events" container. The event_id order is kept |
1111 | // in the "event_id_order" vector. |
1112 | map<uint32_t, DParsedEvent*> events_by_event_id; |
1113 | |
1114 | auto pe_iter = current_parsed_events.begin(); |
1115 | DParsedEvent *pe = NULL__null; |
1116 | |
1117 | while(iptr<iend){ |
1118 | |
1119 | // This word appears to be appended to the data. |
1120 | // Probably in the ROL. Ignore it if found. |
1121 | if(*iptr == 0xd00dd00d) { |
1122 | if(VERBOSE>7) cout << " CAEN skipping 0xd00dd00d word" << endl; |
1123 | iptr++; |
1124 | continue; |
1125 | } |
1126 | |
1127 | uint32_t type = (*iptr) >> 27; |
1128 | uint32_t edge = 0; // 1=trailing, 0=leading |
1129 | uint32_t channel = 0; |
1130 | uint32_t tdc = 0; |
1131 | uint32_t error_flags = 0; |
1132 | switch(type){ |
1133 | case 0b01000: // Global Header |
1134 | slot = (*iptr) & 0x1f; |
1135 | event_count = ((*iptr)>>5) & 0xffffff; |
1136 | if(VERBOSE>7) cout << " CAEN TDC Global Header (slot=" << slot << " , event count=" << event_count << ")" << endl; |
1137 | break; |
1138 | case 0b10000: // Global Trailer |
1139 | slot = (*iptr) & 0x1f; |
1140 | word_count = ((*iptr)>>5) & 0x7ffff; |
1141 | if(VERBOSE>7) cout << " CAEN TDC Global Trailer (slot=" << slot << " , word count=" << word_count << ")" << endl; |
1142 | slot = event_count = word_count = trigger_time_tag = tdc_num = event_id = bunch_id = 0; |
Although the value stored to 'trigger_time_tag' is used in the enclosing expression, the value is never actually read from 'trigger_time_tag' | |
1143 | break; |
1144 | case 0b10001: // Global Trigger Time Tag |
1145 | trigger_time_tag = ((*iptr)>>5) & 0x7ffffff; |
1146 | if(VERBOSE>7) cout << " CAEN TDC Global Trigger Time Tag (tag=" << trigger_time_tag << ")" << endl; |
1147 | break; |
1148 | case 0b00001: // TDC Header |
1149 | tdc_num = ((*iptr)>>24) & 0x03; |
1150 | event_id = ((*iptr)>>12) & 0x0fff; |
1151 | bunch_id = (*iptr) & 0x0fff; |
1152 | if(events_by_event_id.find(event_id) == events_by_event_id.end()){ |
1153 | if(pe_iter == current_parsed_events.end()){ |
1154 | _DBG_std::cerr<<"libraries/DAQ/DEVIOWorkerThread.cc"<< ":"<<1154<<" " << "CAEN1290TDC parser sees more events than CODA header! (>" << current_parsed_events.size() << ")" << endl; |
1155 | for( auto p : events_by_event_id) cout << "id=" << p.first << endl; |
1156 | iptr = iend; |
1157 | throw JExceptionDataFormat("CAEN1290TDC parser sees more events than CODA header", __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__1157); |
1158 | } |
1159 | pe = *pe_iter++; |
1160 | events_by_event_id[event_id] = pe; |
1161 | }else{ |
1162 | pe = events_by_event_id[event_id]; |
1163 | } |
1164 | if(VERBOSE>7) cout << " CAEN TDC TDC Header (tdc=" << tdc_num <<" , event id=" << event_id <<" , bunch id=" << bunch_id << ")" << endl; |
1165 | break; |
1166 | case 0b00000: // TDC Measurement |
1167 | edge = ((*iptr)>>26) & 0x01; |
1168 | channel = ((*iptr)>>21) & 0x1f; |
1169 | tdc = ((*iptr)>>0) & 0x1fffff; |
1170 | if(VERBOSE>7) cout << " CAEN TDC TDC Measurement (" << (edge ? "trailing":"leading") << " , channel=" << channel << " , tdc=" << tdc << ")" << endl; |
1171 | |
1172 | // Create DCAEN1290TDCHit object |
1173 | if(pe) pe->NEW_DCAEN1290TDCHit(rocid, slot, channel, 0, edge, tdc_num, event_id, bunch_id, tdc); |
1174 | break; |
1175 | case 0b00100: // TDC Error |
1176 | error_flags = (*iptr) & 0x7fff; |
1177 | if(VERBOSE>7) cout << " CAEN TDC TDC Error (err flags=0x" << hex << error_flags << dec << ")" << endl; |
1178 | break; |
1179 | case 0b00011: // TDC Trailer |
1180 | tdc_num = ((*iptr)>>24) & 0x03; |
1181 | event_id = ((*iptr)>>12) & 0x0fff; |
1182 | word_count = ((*iptr)>>0) & 0x0fff; |
1183 | if(VERBOSE>7) cout << " CAEN TDC TDC Trailer (tdc=" << tdc_num <<" , event id=" << event_id <<" , word count=" << word_count << ")" << endl; |
1184 | tdc_num = event_id = bunch_id = 0; |
1185 | break; |
1186 | case 0b11000: // Filler Word |
1187 | if(VERBOSE>7) cout << " CAEN TDC Filler Word" << endl; |
1188 | break; |
1189 | default: |
1190 | cout << "Unknown datatype: 0x" << hex << type << " full word: "<< *iptr << dec << endl; |
1191 | throw JExceptionDataFormat("Unknown data type for CAEN1190", __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__1191); |
1192 | } |
1193 | |
1194 | iptr++; |
1195 | } |
1196 | |
1197 | } |
1198 | |
1199 | //---------------- |
1200 | // ParseModuleConfiguration |
1201 | //---------------- |
1202 | void DEVIOWorkerThread::ParseModuleConfiguration(uint32_t rocid, uint32_t* &iptr, uint32_t *iend) |
1203 | { |
1204 | if(!PARSE_CONFIG){ iptr = &iptr[(*iptr) + 1]; return; } |
1205 | |
1206 | /// Parse a bank of module configuration data. These are configuration values |
1207 | /// programmed into the module at the beginning of the run that may be needed |
1208 | /// in the offline. For example, the number of samples to sum in a FADC pulse |
1209 | /// integral. |
1210 | /// |
1211 | /// The bank has one or more sections, each describing parameters applicable |
1212 | /// to a number of modules as indicated by a 24bit slot mask. |
1213 | /// |
1214 | /// This bank should appear only once per DAQ event which, if in multi-event |
1215 | /// block mode, may have multiple L1 events. The parameters here will apply |
1216 | /// to all L1 events in the block. This method will put the config objects |
1217 | /// into each event in current_parsed_events. The config objects are duplicated |
1218 | /// as needed so each event has its own, indepenent set of config object. |
1219 | |
1220 | while(iptr < iend){ |
1221 | uint32_t slot_mask = (*iptr) & 0xFFFFFF; |
1222 | uint32_t Nvals = ((*iptr) >> 24) & 0xFF; |
1223 | iptr++; |
1224 | |
1225 | // Events will be created in the first event (i.e. using its pool) |
1226 | // but pointers are saved so we can use them to construct identical |
1227 | // objects in all other event later |
1228 | DParsedEvent *pe = current_parsed_events.front(); |
1229 | |
1230 | Df250Config *f250config = NULL__null; |
1231 | Df125Config *f125config = NULL__null; |
1232 | DF1TDCConfig *f1tdcconfig = NULL__null; |
1233 | DCAEN1290TDCConfig *caen1290tdcconfig = NULL__null; |
1234 | |
1235 | // Loop over all parameters in this section |
1236 | for(uint32_t i=0; i< Nvals; i++){ |
1237 | if( iptr >= iend){ |
1238 | _DBG_std::cerr<<"libraries/DAQ/DEVIOWorkerThread.cc"<< ":"<<1238<<" " << "DAQ Configuration bank corrupt! slot_mask=0x" << hex << slot_mask << dec << " Nvals="<< Nvals << endl; |
1239 | throw JExceptionDataFormat("Corrupt DAQ config. bank", __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__1239); |
1240 | } |
1241 | |
1242 | daq_param_type ptype = (daq_param_type)((*iptr)>>16); |
1243 | uint16_t val = (*iptr) & 0xFFFF; |
1244 | |
1245 | if(VERBOSE>6) cout << " DAQ parameter of type: 0x" << hex << ptype << dec << " found with value: " << val << endl; |
1246 | |
1247 | // Create config object of correct type if needed and copy |
1248 | // parameter value into it. |
1249 | switch(ptype>>8){ |
1250 | |
1251 | // f250 |
1252 | case 0x05: |
1253 | if( !f250config ) f250config = pe->NEW_Df250Config(rocid, slot_mask); |
1254 | switch(ptype){ |
1255 | case kPARAM250_NSA : f250config->NSA = val; break; |
1256 | case kPARAM250_NSB : f250config->NSB = val; break; |
1257 | case kPARAM250_NSA_NSB : f250config->NSA_NSB = val; break; |
1258 | case kPARAM250_NPED : f250config->NPED = val; break; |
1259 | default: _DBG_std::cerr<<"libraries/DAQ/DEVIOWorkerThread.cc"<< ":"<<1259<<" " << "UNKNOWN DAQ Config Parameter type: 0x" << hex << ptype << dec << endl; |
1260 | } |
1261 | break; |
1262 | |
1263 | // f125 |
1264 | case 0x0F: |
1265 | if( !f125config ) f125config = pe->NEW_Df125Config(rocid, slot_mask); |
1266 | switch(ptype){ |
1267 | case kPARAM125_NSA : f125config->NSA = val; break; |
1268 | case kPARAM125_NSB : f125config->NSB = val; break; |
1269 | case kPARAM125_NSA_NSB : f125config->NSA_NSB = val; break; |
1270 | case kPARAM125_NPED : f125config->NPED = val; break; |
1271 | case kPARAM125_WINWIDTH : f125config->WINWIDTH = val; break; |
1272 | case kPARAM125_PL : f125config->PL = val; break; |
1273 | case kPARAM125_NW : f125config->NW = val; break; |
1274 | case kPARAM125_NPK : f125config->NPK = val; break; |
1275 | case kPARAM125_P1 : f125config->P1 = val; break; |
1276 | case kPARAM125_P2 : f125config->P2 = val; break; |
1277 | case kPARAM125_PG : f125config->PG = val; break; |
1278 | case kPARAM125_IE : f125config->IE = val; break; |
1279 | case kPARAM125_H : f125config->H = val; break; |
1280 | case kPARAM125_TH : f125config->TH = val; break; |
1281 | case kPARAM125_TL : f125config->TL = val; break; |
1282 | case kPARAM125_IBIT : f125config->IBIT = val; break; |
1283 | case kPARAM125_ABIT : f125config->ABIT = val; break; |
1284 | case kPARAM125_PBIT : f125config->PBIT = val; break; |
1285 | default: _DBG_std::cerr<<"libraries/DAQ/DEVIOWorkerThread.cc"<< ":"<<1285<<" " << "UNKNOWN DAQ Config Parameter type: 0x" << hex << ptype << dec << endl; |
1286 | } |
1287 | break; |
1288 | |
1289 | // F1TDC |
1290 | case 0x06: |
1291 | if( !f1tdcconfig ) f1tdcconfig = pe->NEW_DF1TDCConfig(rocid, slot_mask); |
1292 | switch(ptype){ |
1293 | case kPARAMF1_REFCNT : f1tdcconfig->REFCNT = val; break; |
1294 | case kPARAMF1_TRIGWIN : f1tdcconfig->TRIGWIN = val; break; |
1295 | case kPARAMF1_TRIGLAT : f1tdcconfig->TRIGLAT = val; break; |
1296 | case kPARAMF1_HSDIV : f1tdcconfig->HSDIV = val; break; |
1297 | case kPARAMF1_BINSIZE : f1tdcconfig->BINSIZE = val; break; |
1298 | case kPARAMF1_REFCLKDIV : f1tdcconfig->REFCLKDIV = val; break; |
1299 | default: _DBG_std::cerr<<"libraries/DAQ/DEVIOWorkerThread.cc"<< ":"<<1299<<" " << "UNKNOWN DAQ Config Parameter type: 0x" << hex << ptype << dec << endl; |
1300 | } |
1301 | break; |
1302 | |
1303 | // caen1290 |
1304 | case 0x10: |
1305 | if( !caen1290tdcconfig ) caen1290tdcconfig = pe->NEW_DCAEN1290TDCConfig(rocid, slot_mask); |
1306 | switch(ptype){ |
1307 | case kPARAMCAEN1290_WINWIDTH : caen1290tdcconfig->WINWIDTH = val; break; |
1308 | case kPARAMCAEN1290_WINOFFSET : caen1290tdcconfig->WINOFFSET = val; break; |
1309 | default: _DBG_std::cerr<<"libraries/DAQ/DEVIOWorkerThread.cc"<< ":"<<1309<<" " << "UNKNOWN DAQ Config Parameter type: 0x" << hex << ptype << dec << endl; |
1310 | } |
1311 | break; |
1312 | |
1313 | default: |
1314 | _DBG_std::cerr<<"libraries/DAQ/DEVIOWorkerThread.cc"<< ":"<<1314<<" " << "Unknown module type: 0x" << hex << (ptype>>8) << endl; |
1315 | throw JExceptionDataFormat("Unknown module type in configuration bank", __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__1315); |
1316 | } |
1317 | |
1318 | |
1319 | iptr++; |
1320 | } |
1321 | |
1322 | // Make copies of all config objects for all other events |
1323 | for(auto tpe : current_parsed_events){ |
1324 | |
1325 | if(tpe == pe) continue; // first event already owns objects so skip it |
1326 | |
1327 | if(f250config ) tpe->NEW_Df250Config(f250config); |
1328 | if(f125config ) tpe->NEW_Df125Config(f125config); |
1329 | if(f1tdcconfig ) tpe->NEW_DF1TDCConfig(f1tdcconfig); |
1330 | if(caen1290tdcconfig) tpe->NEW_DCAEN1290TDCConfig(caen1290tdcconfig); |
1331 | } |
1332 | } |
1333 | } |
1334 | |
1335 | //---------------- |
1336 | // ParseJLabModuleData |
1337 | //---------------- |
1338 | void DEVIOWorkerThread::ParseJLabModuleData(uint32_t rocid, uint32_t* &iptr, uint32_t *iend) |
1339 | { |
1340 | |
1341 | while(iptr<iend){ |
1342 | |
1343 | // Get module type from next word (bits 18-21) |
1344 | uint32_t mod_id = ((*iptr) >> 18) & 0x000F; |
1345 | MODULE_TYPE type = (MODULE_TYPE)mod_id; |
1346 | //cout << " rocid=" << rocid << " Encountered module type: " << type << " (=" << DModuleType::GetModule(type).GetName() << ") word=" << hex << (*iptr) << dec << endl; |
1347 | |
1348 | switch(type){ |
1349 | case DModuleType::FADC250: |
1350 | Parsef250Bank(rocid, iptr, iend); |
1351 | break; |
1352 | |
1353 | case DModuleType::FADC125: |
1354 | Parsef125Bank(rocid, iptr, iend); |
1355 | break; |
1356 | |
1357 | case DModuleType::F1TDC32: |
1358 | ParseF1TDCBank(rocid, iptr, iend); |
1359 | break; |
1360 | |
1361 | case DModuleType::F1TDC48: |
1362 | ParseF1TDCBank(rocid, iptr, iend); |
1363 | break; |
1364 | |
1365 | case DModuleType::TID: |
1366 | ParseTIBank(rocid, iptr, iend); |
1367 | /* |
1368 | // Ignore this data and skip over it |
1369 | while(iptr<iend && ((*iptr) & 0xF8000000) != 0x88000000) iptr++; // Skip to JLab block trailer |
1370 | iptr++; // advance past JLab block trailer |
1371 | while(iptr<iend && *iptr == 0xF8000000) iptr++; // skip filler words after block trailer |
1372 | break; |
1373 | */ |
1374 | break; |
1375 | |
1376 | case DModuleType::UNKNOWN: |
1377 | default: |
1378 | jerr<<"Unknown module type ("<<mod_id<<") iptr=0x" << hex << iptr << dec << endl; |
1379 | |
1380 | while(iptr<iend && ((*iptr) & 0xF8000000) != 0x88000000) iptr++; // Skip to JLab block trailer |
1381 | iptr++; // advance past JLab block trailer |
1382 | while(iptr<iend && *iptr == 0xF8000000) iptr++; // skip filler words after block trailer |
1383 | throw JExceptionDataFormat("Unknown JLab module type", __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__1383); |
1384 | break; |
1385 | } |
1386 | } |
1387 | |
1388 | } |
1389 | |
1390 | //---------------- |
1391 | // Parsef250Bank |
1392 | //---------------- |
1393 | void DEVIOWorkerThread::Parsef250Bank(uint32_t rocid, uint32_t* &iptr, uint32_t *iend) |
1394 | { |
1395 | if(!PARSE_F250){ iptr = &iptr[(*iptr) + 1]; return; } |
1396 | |
1397 | int continue_on_format_error = false; |
1398 | |
1399 | auto pe_iter = current_parsed_events.begin(); |
1400 | DParsedEvent *pe = NULL__null; |
1401 | |
1402 | uint32_t slot = 0; |
1403 | uint32_t itrigger = -1; |
1404 | |
1405 | uint32_t *istart_pulse_data = iptr; |
1406 | |
1407 | // Loop over data words |
1408 | for(; iptr<iend; iptr++){ |
1409 | |
1410 | // Skip all non-data-type-defining words at this |
1411 | // level. When we do encounter one, the appropriate |
1412 | // case block below should handle parsing all of |
1413 | // the data continuation words and advance the iptr. |
1414 | if(((*iptr>>31) & 0x1) == 0)continue; |
1415 | |
1416 | uint32_t data_type = (*iptr>>27) & 0x0F; |
1417 | switch(data_type){ |
1418 | case 0: // Block Header |
1419 | slot = (*iptr>>22) & 0x1F; |
1420 | if(VERBOSE>7) cout << " FADC250 Block Header: slot="<<slot<<" (0x"<<hex<<*iptr<<dec<<")"<<endl; |
1421 | break; |
1422 | case 1: // Block Trailer |
1423 | pe_iter = current_parsed_events.begin(); |
1424 | pe = NULL__null; |
1425 | if(VERBOSE>7) cout << " FADC250 Block Trailer"<<" (0x"<<hex<<*iptr<<dec<<") iptr=0x"<<hex<<iptr<<dec<<endl; |
1426 | break; |
1427 | case 2: // Event Header |
1428 | itrigger = (*iptr>>0) & 0x3FFFFF; |
1429 | pe = *pe_iter++; |
1430 | if(VERBOSE>7) cout << " FADC250 Event Header: itrigger="<<itrigger<<", rocid="<<rocid<<", slot="<<slot<<")" <<" (0x"<<hex<<*iptr<<dec<<")" <<endl; |
1431 | break; |
1432 | case 3: // Trigger Time |
1433 | { |
1434 | uint64_t t = ((*iptr)&0xFFFFFF)<<0; |
1435 | if(VERBOSE>7) cout << " FADC250 Trigger time low word="<<(((*iptr)&0xFFFFFF))<<" (0x"<<hex<<*iptr<<dec<<")"<<endl; |
1436 | iptr++; |
1437 | if(((*iptr>>31) & 0x1) == 0){ |
1438 | t += ((*iptr)&0xFFFFFF)<<24; // from word on the street: second trigger time word is optional!!?? |
1439 | if(VERBOSE>7) cout << " FADC250 Trigger time high word="<<(((*iptr)&0xFFFFFF))<<" (0x"<<hex<<*iptr<<dec<<") iptr=0x"<<hex<<iptr<<dec<<endl; |
1440 | }else{ |
1441 | iptr--; |
1442 | } |
1443 | if(VERBOSE>7) cout << " FADC250 Trigger Time: t="<<t<<endl; |
1444 | if(pe) pe->NEW_Df250TriggerTime(rocid, slot, itrigger, t); |
1445 | } |
1446 | break; |
1447 | case 4: // Window Raw Data |
1448 | // iptr passed by reference and so will be updated automatically |
1449 | if(VERBOSE>7) cout << " FADC250 Window Raw Data"<<" (0x"<<hex<<*iptr<<dec<<")"<<endl; |
1450 | if(pe) MakeDf250WindowRawData(pe, rocid, slot, itrigger, iptr); |
1451 | break; |
1452 | case 5: // Window Sum |
1453 | { |
1454 | uint32_t channel = (*iptr>>23) & 0x0F; |
1455 | uint32_t sum = (*iptr>>0) & 0x3FFFFF; |
1456 | uint32_t overflow = (*iptr>>22) & 0x1; |
1457 | if(VERBOSE>7) cout << " FADC250 Window Sum"<<" (0x"<<hex<<*iptr<<dec<<")"<<endl; |
1458 | if(pe) pe->NEW_Df250WindowSum(rocid, slot, channel, itrigger, sum, overflow); |
1459 | } |
1460 | break; |
1461 | case 6: // Pulse Raw Data |
1462 | // MakeDf250PulseRawData(objs, rocid, slot, itrigger, iptr); |
1463 | if(VERBOSE>7) cout << " FADC250 Pulse Raw Data"<<" (0x"<<hex<<*iptr<<dec<<")"<<endl; |
1464 | break; |
1465 | case 7: // Pulse Integral |
1466 | { |
1467 | uint32_t channel = (*iptr>>23) & 0x0F; |
1468 | uint32_t pulse_number = (*iptr>>21) & 0x03; |
1469 | uint32_t quality_factor = (*iptr>>19) & 0x03; |
1470 | uint32_t sum = (*iptr>>0) & 0x7FFFF; |
1471 | uint32_t nsamples_integral = 0; // must be overwritten later in GetObjects with value from Df125Config value |
1472 | uint32_t nsamples_pedestal = 1; // The firmware returns an already divided pedestal |
1473 | uint32_t pedestal = 0; // This will be replaced by the one from Df250PulsePedestal in GetObjects |
1474 | if(VERBOSE>7) cout << " FADC250 Pulse Integral: chan="<<channel<<" pulse_number="<<pulse_number<<" sum="<<sum<<" (0x"<<hex<<*iptr<<dec<<")"<<endl; |
1475 | if(pe) pe->NEW_Df250PulseIntegral(rocid, slot, channel, itrigger, pulse_number, quality_factor, sum, pedestal, nsamples_integral, nsamples_pedestal); |
1476 | } |
1477 | break; |
1478 | case 8: // Pulse Time |
1479 | { |
1480 | uint32_t channel = (*iptr>>23) & 0x0F; |
1481 | uint32_t pulse_number = (*iptr>>21) & 0x03; |
1482 | uint32_t quality_factor = (*iptr>>19) & 0x03; |
1483 | uint32_t pulse_time = (*iptr>>0) & 0x7FFFF; |
1484 | if(VERBOSE>7) cout << " FADC250 Pulse Time: chan="<<channel<<" pulse_number="<<pulse_number<<" pulse_time="<<pulse_time<<" (0x"<<hex<<*iptr<<dec<<")"<<endl; |
1485 | if(pe) pe->NEW_Df250PulseTime(rocid, slot, channel, itrigger, pulse_number, quality_factor, pulse_time); |
1486 | } |
1487 | break; |
1488 | case 9: // Pulse Data (firmware instroduce in Fall 2016) |
1489 | { |
1490 | // from word 1 |
1491 | uint32_t event_number_within_block = (*iptr>>19) & 0xFF; |
1492 | uint32_t channel = (*iptr>>15) & 0x0F; |
1493 | bool QF_pedestal = (*iptr>>14) & 0x01; |
1494 | uint32_t pedestal = (*iptr>>0 ) & 0x3FFF; |
1495 | if(VERBOSE>7) cout << " FADC250 Pulse Data (0x"<<hex<<*iptr<<dec<<") channel=" << channel << " pedestal="<<pedestal << " event within block=" << event_number_within_block <<endl; |
1496 | |
1497 | // event_number_within_block=0 indicates error |
1498 | if(event_number_within_block==0){ |
1499 | _DBG_std::cerr<<"libraries/DAQ/DEVIOWorkerThread.cc"<< ":"<<1499<<" "<<"event_number_within_block==0. This indicates a bug in firmware." << endl; |
1500 | exit(-1); |
1501 | } |
1502 | |
1503 | // Event headers may be supressed so determine event from hit data |
1504 | if( (event_number_within_block > current_parsed_events.size()) ) { jerr << "Bad f250 event number for rocid="<<rocid<<" slot="<<slot<<" channel="<<channel<<endl; throw JException("Bad f250 event number", __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__1504);} |
1505 | pe_iter = current_parsed_events.begin(); |
1506 | advance( pe_iter, event_number_within_block-1 ); |
1507 | pe = *pe_iter++; |
1508 | |
1509 | itrigger = event_number_within_block; // is this right? |
1510 | uint32_t pulse_number = 0; |
1511 | |
1512 | while( (*++iptr>>31) == 0 ){ |
1513 | |
1514 | if( (*iptr>>30) != 0x01) { |
1515 | jerr << "Bad f250 Pulse Data for rocid="<<rocid<<" slot="<<slot<<" channel="<<channel<<endl; |
1516 | DumpBinary(istart_pulse_data, iend, ((uint64_t)&iptr[3]-(uint64_t)istart_pulse_data)/4, iptr); |
1517 | if (continue_on_format_error) { |
1518 | iptr = iend; |
1519 | return; |
1520 | } |
1521 | else |
1522 | throw JException("Bad f250 Pulse Data!", __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__1522); |
1523 | } |
1524 | |
1525 | // from word 2 |
1526 | uint32_t integral = (*iptr>>12) & 0x3FFFF; |
1527 | bool QF_NSA_beyond_PTW = (*iptr>>11) & 0x01; |
1528 | bool QF_overflow = (*iptr>>10) & 0x01; |
1529 | bool QF_underflow = (*iptr>>9 ) & 0x01; |
1530 | uint32_t nsamples_over_threshold = (*iptr>>0 ) & 0x1FF; |
1531 | if(VERBOSE>7) cout << " FADC250 Pulse Data word 2(0x"<<hex<<*iptr<<dec<<") integral="<<integral<<endl; |
1532 | |
1533 | iptr++; |
1534 | if( (*iptr>>30) != 0x00){ |
1535 | DumpBinary(istart_pulse_data, iend, 128, iptr); |
1536 | if (continue_on_format_error) { |
1537 | iptr = iend; |
1538 | return; |
1539 | } |
1540 | else |
1541 | throw JException("Bad f250 Pulse Data!", __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__1541); |
1542 | } |
1543 | |
1544 | // from word 3 |
1545 | uint32_t course_time = (*iptr>>21) & 0x1FF;//< 4 ns/count |
1546 | uint32_t fine_time = (*iptr>>15) & 0x3F;//< 0.0625 ns/count |
1547 | uint32_t pulse_peak = (*iptr>>3 ) & 0xFFF; |
1548 | bool QF_vpeak_beyond_NSA = (*iptr>>2 ) & 0x01; |
1549 | bool QF_vpeak_not_found = (*iptr>>1 ) & 0x01; |
1550 | bool QF_bad_pedestal = (*iptr>>0 ) & 0x01; |
1551 | if(VERBOSE>7) cout << " FADC250 Pulse Data word 3(0x"<<hex<<*iptr<<dec<<") course_time="<<course_time<<" fine_time="<<fine_time<<" pulse_peak="<<pulse_peak<<endl; |
1552 | |
1553 | // FIRMWARE BUG: If pulse integral was zero, this is an invalid bad pulse; |
1554 | // skip over bogus repeated pulse time repeats, and ignore it altogether. |
1555 | // March 18, 2020 -rtj- |
1556 | if (integral == 0 && *iptr == *(iptr + 1)) { |
1557 | while (*(iptr + 1) == *iptr) { |
1558 | ++iptr; |
1559 | } |
1560 | jerr << "Bug #1: bad f250 Pulse Data for rocid="<<rocid<<" slot="<<slot<<" channel="<<channel<<endl; |
1561 | continue_on_format_error = true; |
1562 | break; |
1563 | } |
1564 | |
1565 | if( pe ) { |
1566 | pe->NEW_Df250PulseData(rocid, slot, channel, itrigger |
1567 | , event_number_within_block |
1568 | , QF_pedestal |
1569 | , pedestal |
1570 | , integral |
1571 | , QF_NSA_beyond_PTW |
1572 | , QF_overflow |
1573 | , QF_underflow |
1574 | , nsamples_over_threshold |
1575 | , course_time |
1576 | , fine_time |
1577 | , pulse_peak |
1578 | , QF_vpeak_beyond_NSA |
1579 | , QF_vpeak_not_found |
1580 | , QF_bad_pedestal |
1581 | , pulse_number++); |
1582 | } |
1583 | } |
1584 | iptr--; // backup so when outer loop advances, it points to next data defining word |
1585 | |
1586 | } |
1587 | break; |
1588 | case 10: // Pulse Pedestal |
1589 | { |
1590 | uint32_t channel = (*iptr>>23) & 0x0F; |
1591 | uint32_t pulse_number = (*iptr>>21) & 0x03; |
1592 | uint32_t pedestal = (*iptr>>12) & 0x1FF; |
1593 | uint32_t pulse_peak = (*iptr>>0) & 0xFFF; |
1594 | if(VERBOSE>7) cout << " FADC250 Pulse Pedestal chan="<<channel<<" pulse_number="<<pulse_number<<" pedestal="<<pedestal<<" pulse_peak="<<pulse_peak<<" (0x"<<hex<<*iptr<<dec<<")"<<endl; |
1595 | if(pe) pe->NEW_Df250PulsePedestal(rocid, slot, channel, itrigger, pulse_number, pedestal, pulse_peak); |
1596 | } |
1597 | break; |
1598 | case 13: // Event Trailer |
1599 | // This is marked "suppressed for normal readout – debug mode only" in the |
1600 | // current manual (v2). It does not contain any data so the most we could do here |
1601 | // is return early. I'm hesitant to do that though since it would mean |
1602 | // different behavior for debug mode data as regular data. |
1603 | case 14: // Data not valid (empty module) |
1604 | case 15: // Filler (non-data) word |
1605 | if(VERBOSE>7) cout << " FADC250 Event Trailer, Data not Valid, or Filler word ("<<data_type<<")"<<" (0x"<<hex<<*iptr<<dec<<")"<<endl; |
1606 | break; |
1607 | default: |
1608 | if(VERBOSE>7) cout << " FADC250 unknown data type ("<<data_type<<")"<<" (0x"<<hex<<*iptr<<dec<<")"<<endl; |
1609 | jerr << "FADC250 unknown data type (" << data_type << ") (0x" << hex << *iptr << dec << ")" << endl; |
1610 | // make additional debugging output for special error types |
1611 | if(data_type == 11) { |
1612 | cout << " FADC slot mask = "<<" 0x"<<hex<<*(iptr+1)<<dec<<endl; |
1613 | cout << " Token status = "<<" 0x"<<hex<<*(iptr+2)<<dec<<endl; |
1614 | cout << " Bus error status = "<<" 0x"<<hex<<*(iptr+3)<<dec<<endl; |
1615 | if(pe) { |
1616 | cout << " Associated with event number = "<<pe->event_number<<endl; |
1617 | } |
1618 | } |
1619 | |
1620 | if (continue_on_format_error) { |
1621 | iptr = iend; |
1622 | return; |
1623 | } |
1624 | else |
1625 | throw JExceptionDataFormat("Unexpected word type in fADC250 block!", __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__1625); |
1626 | } |
1627 | } |
1628 | |
1629 | // Chop off filler words |
1630 | for(; iptr<iend; iptr++){ |
1631 | if(((*iptr)&0xf8000000) != 0xf8000000) break; |
1632 | } |
1633 | } |
1634 | |
1635 | //---------------- |
1636 | // MakeDf250WindowRawData |
1637 | //---------------- |
1638 | void DEVIOWorkerThread::MakeDf250WindowRawData(DParsedEvent *pe, uint32_t rocid, uint32_t slot, uint32_t itrigger, uint32_t* &iptr) |
1639 | { |
1640 | uint32_t channel = (*iptr>>23) & 0x0F; |
1641 | uint32_t window_width = (*iptr>>0) & 0x0FFF; |
1642 | |
1643 | Df250WindowRawData *wrd = pe->NEW_Df250WindowRawData(rocid, slot, channel, itrigger); |
1644 | |
1645 | for(uint32_t isample=0; isample<window_width; isample +=2){ |
1646 | |
1647 | // Advance to next word |
1648 | iptr++; |
1649 | |
1650 | // Make sure this is a data continuation word, if not, stop here |
1651 | if(((*iptr>>31) & 0x1) != 0x0){ |
1652 | iptr--; // calling method expects us to point to last word in block |
1653 | break; |
1654 | } |
1655 | |
1656 | bool invalid_1 = (*iptr>>29) & 0x1; |
1657 | bool invalid_2 = (*iptr>>13) & 0x1; |
1658 | uint16_t sample_1 = 0; |
1659 | uint16_t sample_2 = 0; |
1660 | if(!invalid_1)sample_1 = (*iptr>>16) & 0x1FFF; |
1661 | if(!invalid_2)sample_2 = (*iptr>>0) & 0x1FFF; |
1662 | |
1663 | // Sample 1 |
1664 | wrd->samples.push_back(sample_1); |
1665 | wrd->invalid_samples |= invalid_1; |
1666 | wrd->overflow |= (sample_1>>12) & 0x1; |
1667 | |
1668 | if(((isample+2) == window_width) && invalid_2)break; // skip last sample if flagged as invalid |
1669 | |
1670 | // Sample 2 |
1671 | wrd->samples.push_back(sample_2); |
1672 | wrd->invalid_samples |= invalid_2; |
1673 | wrd->overflow |= (sample_2>>12) & 0x1; |
1674 | } |
1675 | |
1676 | if(VERBOSE>7) cout << " FADC250 Window Raw Data: size from header=" << window_width << " Nsamples found=" << wrd->samples.size() << endl; |
1677 | if( window_width != wrd->samples.size() ){ |
1678 | jerr <<" FADC250 Window Raw Data number of samples does not match header! (" <<wrd->samples.size() << " != " << window_width << ") for rocid=" << rocid << " slot=" << slot << " channel=" << channel << endl; |
1679 | } |
1680 | } |
1681 | |
1682 | //---------------- |
1683 | // Parsef125Bank |
1684 | //---------------- |
1685 | void DEVIOWorkerThread::Parsef125Bank(uint32_t rocid, uint32_t* &iptr, uint32_t *iend) |
1686 | { |
1687 | if(!PARSE_F125){ iptr = &iptr[(*iptr) + 1]; return; } |
1688 | |
1689 | auto pe_iter = current_parsed_events.begin(); |
1690 | DParsedEvent *pe = NULL__null; |
1691 | |
1692 | uint32_t slot=0; |
1693 | uint32_t itrigger = -1; |
1694 | uint32_t last_itrigger = -2; |
1695 | uint32_t last_pulse_time_channel=0; |
1696 | uint32_t last_slot = -1; |
1697 | uint32_t last_channel = -1; |
1698 | |
1699 | // Loop over data words |
1700 | for(; iptr<iend; iptr++){ |
1701 | |
1702 | // Skip all non-data-type-defining words at this |
1703 | // level. When we do encounter one, the appropriate |
1704 | // case block below should handle parsing all of |
1705 | // the data continuation words and advance the iptr. |
1706 | if(((*iptr>>31) & 0x1) == 0)continue; |
1707 | |
1708 | uint32_t data_type = (*iptr>>27) & 0x0F; |
1709 | switch(data_type){ |
1710 | case 0: // Block Header |
1711 | slot = (*iptr>>22) & 0x1F; |
1712 | if(VERBOSE>7) cout << " FADC125 Block Header: slot="<<slot<<endl; |
1713 | break; |
1714 | case 1: // Block Trailer |
1715 | pe_iter = current_parsed_events.begin(); |
1716 | pe = NULL__null; |
1717 | break; |
1718 | case 2: // Event Header |
1719 | //slot_event_header = (*iptr>>22) & 0x1F; |
1720 | itrigger = (*iptr>>0) & 0x3FFFFFF; |
1721 | pe = *pe_iter++; |
1722 | if(VERBOSE>7) cout << " FADC125 Event Header: itrigger="<<itrigger<<" last_itrigger="<<last_itrigger<<", rocid="<<rocid<<", slot="<<slot <<endl; |
1723 | break; |
1724 | case 3: // Trigger Time |
1725 | { |
1726 | uint64_t t = ((*iptr)&0xFFFFFF)<<0; |
1727 | iptr++; |
1728 | if(((*iptr>>31) & 0x1) == 0){ |
1729 | t += ((*iptr)&0xFFFFFF)<<24; // from word on the street: second trigger time word is optional!!?? |
1730 | }else{ |
1731 | iptr--; |
1732 | } |
1733 | if(VERBOSE>7) cout << " FADC125 Trigger Time (t="<<t<<")"<<endl; |
1734 | if(pe) pe->NEW_Df125TriggerTime(rocid, slot, itrigger, t); |
1735 | } |
1736 | break; |
1737 | case 4: // Window Raw Data |
1738 | // iptr passed by reference and so will be updated automatically |
1739 | if(VERBOSE>7) cout << " FADC125 Window Raw Data"<<endl; |
1740 | if(pe) MakeDf125WindowRawData(pe, rocid, slot, itrigger, iptr); |
1741 | break; |
1742 | |
1743 | case 5: // CDC pulse data (new) (GlueX-doc-2274-v8) |
1744 | { |
1745 | // Word 1: |
1746 | uint32_t word1 = *iptr; |
1747 | uint32_t channel = (*iptr>>20) & 0x7F; |
1748 | uint32_t pulse_number = (*iptr>>15) & 0x1F; |
1749 | uint32_t pulse_time = (*iptr>>4 ) & 0x7FF; |
1750 | uint32_t quality_factor = (*iptr>>3 ) & 0x1; //time QF bit |
1751 | uint32_t overflow_count = (*iptr>>0 ) & 0x7; |
1752 | if(VERBOSE>7){ |
1753 | cout << " FADC125 CDC Pulse Data word1: " << hex << (*iptr) << dec << endl; |
1754 | cout << " FADC125 CDC Pulse Data (chan="<<channel<<" pulse="<<pulse_number<<" time="<<pulse_time<<" QF="<<quality_factor<<" OC="<<overflow_count<<")"<<endl; |
1755 | } |
1756 | |
1757 | // Word 2: |
1758 | ++iptr; |
1759 | if(iptr>=iend){ |
1760 | jerr << " Truncated f125 CDC hit (block ends before continuation word!)" << endl; |
1761 | continue; |
1762 | } |
1763 | if( ((*iptr>>31) & 0x1) != 0 ){ |
1764 | jerr << " Truncated f125 CDC hit (missing continuation word!)" << endl; |
1765 | continue; |
1766 | } |
1767 | uint32_t word2 = *iptr; |
1768 | uint32_t pedestal = (*iptr>>23) & 0xFF; |
1769 | uint32_t sum = (*iptr>>9 ) & 0x3FFF; |
1770 | uint32_t pulse_peak = (*iptr>>0 ) & 0x1FF; |
1771 | if(VERBOSE>7){ |
1772 | cout << " FADC125 CDC Pulse Data word2: " << hex << (*iptr) << dec << endl; |
1773 | cout << " FADC125 CDC Pulse Data (pedestal="<<pedestal<<" sum="<<sum<<" peak="<<pulse_peak<<")"<<endl; |
1774 | } |
1775 | |
1776 | // Create hit objects |
1777 | uint32_t nsamples_integral = 0; // must be overwritten later in GetObjects with value from Df125Config value |
1778 | uint32_t nsamples_pedestal = 1; // The firmware pedestal divided by 2^PBIT where PBIT is a config. parameter |
1779 | |
1780 | if( pe ) { |
1781 | pe->NEW_Df125CDCPulse(rocid, slot, channel, itrigger |
1782 | , pulse_number // NPK |
1783 | , pulse_time // le_time |
1784 | , quality_factor // time_quality_bit |
1785 | , overflow_count // overflow_count |
1786 | , pedestal // pedestal |
1787 | , sum // integral |
1788 | , pulse_peak // first_max_amp |
1789 | , word1 // word1 |
1790 | , word2 // word2 |
1791 | , nsamples_pedestal // nsamples_pedestal |
1792 | , nsamples_integral // nsamples_integral |
1793 | , false); // emulated |
1794 | } |
1795 | } |
1796 | break; |
1797 | |
1798 | case 6: // FDC pulse data-integral (new) (GlueX-doc-2274-v8) |
1799 | { |
1800 | // Word 1: |
1801 | uint32_t word1 = *iptr; |
1802 | uint32_t channel = (*iptr>>20) & 0x7F; |
1803 | uint32_t pulse_number = (*iptr>>15) & 0x1F; |
1804 | uint32_t pulse_time = (*iptr>>4 ) & 0x7FF; |
1805 | uint32_t quality_factor = (*iptr>>3 ) & 0x1; //time QF bit |
1806 | uint32_t overflow_count = (*iptr>>0 ) & 0x7; |
1807 | if(VERBOSE>7){ |
1808 | cout << " FADC125 FDC Pulse Data(integral) word1: " << hex << (*iptr) << dec << endl; |
1809 | cout << " FADC125 FDC Pulse Data (chan="<<channel<<" pulse="<<pulse_number<<" time="<<pulse_time<<" QF="<<quality_factor<<" OC="<<overflow_count<<")"<<endl; |
1810 | } |
1811 | |
1812 | // Word 2: |
1813 | ++iptr; |
1814 | if(iptr>=iend){ |
1815 | jerr << " Truncated f125 FDC hit (block ends before continuation word!)" << endl; |
1816 | continue; |
1817 | } |
1818 | if( ((*iptr>>31) & 0x1) != 0 ){ |
1819 | jerr << " Truncated f125 FDC hit (missing continuation word!)" << endl; |
1820 | continue; |
1821 | } |
1822 | uint32_t word2 = *iptr; |
1823 | uint32_t pulse_peak = 0; |
1824 | uint32_t sum = (*iptr>>19) & 0xFFF; |
1825 | uint32_t peak_time = (*iptr>>11) & 0xFF; |
1826 | uint32_t pedestal = (*iptr>>0 ) & 0x7FF; |
1827 | if(VERBOSE>7){ |
1828 | cout << " FADC125 FDC Pulse Data(integral) word2: " << hex << (*iptr) << dec << endl; |
1829 | cout << " FADC125 FDC Pulse Data (integral="<<sum<<" time="<<peak_time<<" pedestal="<<pedestal<<")"<<endl; |
1830 | } |
1831 | |
1832 | // Create hit objects |
1833 | uint32_t nsamples_integral = 0; // must be overwritten later in GetObjects with value from Df125Config value |
1834 | uint32_t nsamples_pedestal = 1; // The firmware pedestal divided by 2^PBIT where PBIT is a config. parameter |
1835 | |
1836 | if( pe ) { |
1837 | pe->NEW_Df125FDCPulse(rocid, slot, channel, itrigger |
1838 | , pulse_number // NPK |
1839 | , pulse_time // le_time |
1840 | , quality_factor // time_quality_bit |
1841 | , overflow_count // overflow_count |
1842 | , pedestal // pedestal |
1843 | , sum // integral |
1844 | , pulse_peak // peak_amp |
1845 | , peak_time // peak_time |
1846 | , word1 // word1 |
1847 | , word2 // word2 |
1848 | , nsamples_pedestal // nsamples_pedestal |
1849 | , nsamples_integral // nsamples_integral |
1850 | , false); // emulated |
1851 | } |
1852 | } |
1853 | break; |
1854 | |
1855 | case 7: // Pulse Integral |
1856 | { |
1857 | if(VERBOSE>7) cout << " FADC125 Pulse Integral"<<endl; |
1858 | uint32_t channel = (*iptr>>20) & 0x7F; |
1859 | uint32_t sum = (*iptr>>0) & 0xFFFFF; |
1860 | uint32_t quality_factor = 0; |
1861 | uint32_t nsamples_integral = 0; // must be overwritten later in GetObjects with value from Df125Config value |
1862 | uint32_t nsamples_pedestal = 1; // The firmware returns an already divided pedestal |
1863 | uint32_t pedestal = 0; // This will be replaced by the one from Df250PulsePedestal in GetObjects |
1864 | uint32_t pulse_number = 0; |
1865 | if (last_slot == slot && last_channel == channel) pulse_number = 1; |
1866 | last_slot = slot; |
1867 | last_channel = channel; |
1868 | if( pe ) pe->NEW_Df125PulseIntegral(rocid, slot, channel, itrigger, pulse_number, quality_factor, sum, pedestal, nsamples_integral, nsamples_pedestal); |
1869 | } |
1870 | break; |
1871 | case 8: // Pulse Time |
1872 | { |
1873 | if(VERBOSE>7) cout << " FADC125 Pulse Time"<<endl; |
1874 | uint32_t channel = (*iptr>>20) & 0x7F; |
1875 | uint32_t pulse_number = (*iptr>>18) & 0x03; |
1876 | uint32_t pulse_time = (*iptr>>0) & 0xFFFF; |
1877 | uint32_t quality_factor = 0; |
1878 | if( pe ) pe->NEW_Df125PulseTime(rocid, slot, channel, itrigger, pulse_number, quality_factor, pulse_time); |
1879 | last_pulse_time_channel = channel; |
1880 | } |
1881 | break; |
1882 | |
1883 | case 9: // FDC pulse data-peak (new) (GlueX-doc-2274-v8) |
1884 | { |
1885 | // Word 1: |
1886 | uint32_t word1 = *iptr; |
1887 | uint32_t channel = (*iptr>>20) & 0x7F; |
1888 | uint32_t pulse_number = (*iptr>>15) & 0x1F; |
1889 | uint32_t pulse_time = (*iptr>>4 ) & 0x7FF; |
1890 | uint32_t quality_factor = (*iptr>>3 ) & 0x1; //time QF bit |
1891 | uint32_t overflow_count = (*iptr>>0 ) & 0x7; |
1892 | if(VERBOSE>7){ |
1893 | cout << " FADC125 FDC Pulse Data(peak) word1: " << hex << (*iptr) << dec << endl; |
1894 | cout << " FADC125 FDC Pulse Data (chan="<<channel<<" pulse="<<pulse_number<<" time="<<pulse_time<<" QF="<<quality_factor<<" OC="<<overflow_count<<")"<<endl; |
1895 | } |
1896 | |
1897 | // Word 2: |
1898 | ++iptr; |
1899 | if(iptr>=iend){ |
1900 | jerr << " Truncated f125 FDC hit (block ends before continuation word!)" << endl; |
1901 | continue; |
1902 | } |
1903 | if( ((*iptr>>31) & 0x1) != 0 ){ |
1904 | jerr << " Truncated f125 FDC hit (missing continuation word!)" << endl; |
1905 | continue; |
1906 | } |
1907 | uint32_t word2 = *iptr; |
1908 | uint32_t pulse_peak = (*iptr>>19) & 0xFFF; |
1909 | uint32_t sum = 0; |
1910 | uint32_t peak_time = (*iptr>>11) & 0xFF; |
1911 | uint32_t pedestal = (*iptr>>0 ) & 0x7FF; |
1912 | if(VERBOSE>7){ |
1913 | cout << " FADC125 FDC Pulse Data(peak) word2: " << hex << (*iptr) << dec << endl; |
1914 | cout << " FADC125 FDC Pulse Data (integral="<<sum<<" time="<<peak_time<<" pedestal="<<pedestal<<")"<<endl; |
1915 | } |
1916 | |
1917 | // Create hit objects |
1918 | uint32_t nsamples_integral = 0; // must be overwritten later in GetObjects with value from Df125Config value |
1919 | uint32_t nsamples_pedestal = 1; // The firmware pedestal divided by 2^PBIT where PBIT is a config. parameter |
1920 | |
1921 | if( pe ) { |
1922 | |
1923 | // The following is a temporary fix. In late 2017 the CDC group started |
1924 | // using data type 9 (i.e. FDC pulse peak). This caused many conflicts |
1925 | // with plugins downstream that were built around there being a Df125CDCPulse |
1926 | // object associated with the DCDCDigiHit. In order to quickly solve |
1927 | // the issue as the run was starting, this fix was made to produce Df125CDCPulse |
1928 | // object from this data iff rocid<30 indicating the data came from the |
1929 | // CDC. |
1930 | if( rocid<30 ){ |
1931 | |
1932 | pe->NEW_Df125CDCPulse(rocid, slot, channel, itrigger |
1933 | , pulse_number // NPK |
1934 | , pulse_time // le_time |
1935 | , quality_factor // time_quality_bit |
1936 | , overflow_count // overflow_count |
1937 | , pedestal // pedestal |
1938 | , sum // integral |
1939 | , pulse_peak // peak_amp |
1940 | , word1 // word1 |
1941 | , word2 // word2 |
1942 | , nsamples_pedestal // nsamples_pedestal |
1943 | , nsamples_integral // nsamples_integral |
1944 | , false); // emulated |
1945 | |
1946 | }else{ |
1947 | |
1948 | pe->NEW_Df125FDCPulse(rocid, slot, channel, itrigger |
1949 | , pulse_number // NPK |
1950 | , pulse_time // le_time |
1951 | , quality_factor // time_quality_bit |
1952 | , overflow_count // overflow_count |
1953 | , pedestal // pedestal |
1954 | , sum // integral |
1955 | , pulse_peak // peak_amp |
1956 | , peak_time // peak_time |
1957 | , word1 // word1 |
1958 | , word2 // word2 |
1959 | , nsamples_pedestal // nsamples_pedestal |
1960 | , nsamples_integral // nsamples_integral |
1961 | , false); // emulated |
1962 | } |
1963 | } |
1964 | } |
1965 | break; |
1966 | |
1967 | case 10: // Pulse Pedestal (consistent with Beni's hand-edited version of Cody's document) |
1968 | { |
1969 | if(VERBOSE>7) cout << " FADC125 Pulse Pedestal"<<endl; |
1970 | //channel = (*iptr>>20) & 0x7F; |
1971 | uint32_t 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") |
1972 | uint32_t pulse_number = (*iptr>>21) & 0x03; |
1973 | uint32_t pedestal = (*iptr>>12) & 0x1FF; |
1974 | uint32_t pulse_peak = (*iptr>>0) & 0xFFF; |
1975 | uint32_t nsamples_pedestal = 1; // The firmware returns an already divided pedestal |
1976 | if( pe ) pe->NEW_Df125PulsePedestal(rocid, slot, channel, itrigger, pulse_number, pedestal, pulse_peak, nsamples_pedestal); |
1977 | } |
1978 | break; |
1979 | |
1980 | case 13: // Event Trailer |
1981 | case 14: // Data not valid (empty module) |
1982 | case 15: // Filler (non-data) word |
1983 | if(VERBOSE>7) cout << " FADC125 ignored data type: " << data_type <<endl; |
1984 | break; |
1985 | default: |
1986 | if(VERBOSE>7) cout << " FADC125 unknown data type ("<<data_type<<")"<<" (0x"<<hex<<*iptr<<dec<<")"<<endl; |
1987 | throw JExceptionDataFormat("Unexpected word type in fADC125 block!", __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__1987); |
1988 | |
1989 | } |
1990 | } |
1991 | |
1992 | // Chop off filler words |
1993 | for(; iptr<iend; iptr++){ |
1994 | if(((*iptr)&0xf8000000) != 0xf8000000) break; |
1995 | } |
1996 | } |
1997 | |
1998 | //---------------- |
1999 | // MakeDf125WindowRawData |
2000 | //---------------- |
2001 | void DEVIOWorkerThread::MakeDf125WindowRawData(DParsedEvent *pe, uint32_t rocid, uint32_t slot, uint32_t itrigger, uint32_t* &iptr) |
2002 | { |
2003 | uint32_t channel = (*iptr>>20) & 0x7F; |
2004 | uint32_t window_width = (*iptr>>0) & 0x0FFF; |
2005 | |
2006 | Df125WindowRawData *wrd = pe->NEW_Df125WindowRawData(rocid, slot, channel, itrigger); |
2007 | |
2008 | for(uint32_t isample=0; isample<window_width; isample +=2){ |
2009 | |
2010 | // Advance to next word |
2011 | iptr++; |
2012 | |
2013 | // Make sure this is a data continuation word, if not, stop here |
2014 | if(((*iptr>>31) & 0x1) != 0x0)break; |
2015 | |
2016 | bool invalid_1 = (*iptr>>29) & 0x1; |
2017 | bool invalid_2 = (*iptr>>13) & 0x1; |
2018 | uint16_t sample_1 = 0; |
2019 | uint16_t sample_2 = 0; |
2020 | if(!invalid_1)sample_1 = (*iptr>>16) & 0x1FFF; |
2021 | if(!invalid_2)sample_2 = (*iptr>>0) & 0x1FFF; |
2022 | |
2023 | // Sample 1 |
2024 | wrd->samples.push_back(sample_1); |
2025 | wrd->invalid_samples |= invalid_1; |
2026 | wrd->overflow |= (sample_1>>12) & 0x1; |
2027 | |
2028 | if((isample+2) == window_width && invalid_2)break; // skip last sample if flagged as invalid |
2029 | |
2030 | // Sample 2 |
2031 | wrd->samples.push_back(sample_2); |
2032 | wrd->invalid_samples |= invalid_2; |
2033 | wrd->overflow |= (sample_2>>12) & 0x1; |
2034 | } |
2035 | } |
2036 | |
2037 | //---------------- |
2038 | // ParseF1TDCBank |
2039 | //---------------- |
2040 | void DEVIOWorkerThread::ParseF1TDCBank(uint32_t rocid, uint32_t* &iptr, uint32_t *iend) |
2041 | { |
2042 | if(!PARSE_F1TDC){ iptr = &iptr[(*iptr) + 1]; return; } |
2043 | |
2044 | uint32_t *istart = iptr; |
2045 | |
2046 | auto pe_iter = current_parsed_events.begin(); |
2047 | DParsedEvent *pe = NULL__null; |
2048 | |
2049 | uint32_t slot = 0; |
2050 | uint32_t modtype = 0; |
2051 | uint32_t itrigger = -1; |
2052 | uint32_t trig_time_f1header = 0; |
2053 | |
2054 | // Some early data had a marker word at just before the actual F1 data |
2055 | if(*iptr == 0xf1daffff) iptr++; |
2056 | |
2057 | // Loop over data words |
2058 | for(; iptr<iend; iptr++){ |
2059 | |
2060 | // Skip all non-data-type-defining words at this |
2061 | // level. When we do encounter one, the appropriate |
2062 | // case block below should handle parsing all of |
2063 | // the data continuation words and advance the iptr. |
2064 | if(((*iptr>>31) & 0x1) == 0)continue; |
2065 | |
2066 | uint32_t data_type = (*iptr>>27) & 0x0F; |
2067 | switch(data_type){ |
2068 | case 0: // Block Header |
2069 | slot = (*iptr)>>22 & 0x001F; |
2070 | modtype = (*iptr)>>18 & 0x000F; // should match a DModuleType::type_id_t |
2071 | if(VERBOSE>7) cout << " F1 Block Header: slot=" << slot << " modtype=" << modtype << endl; |
2072 | break; |
2073 | |
2074 | case 1: // Block Trailer |
2075 | pe_iter = current_parsed_events.begin(); |
2076 | pe = NULL__null; |
2077 | if(VERBOSE>7) cout << " F1 Block Trailer" << endl; |
2078 | break; |
2079 | |
2080 | case 2: // Event Header |
2081 | { |
2082 | pe = *pe_iter++; |
2083 | itrigger = (*iptr)>>0 & 0x0003FFFFF; |
2084 | if(VERBOSE>7) { |
2085 | uint32_t slot_event_header = (*iptr)>>22 & 0x00000001F; |
2086 | cout << " F1 Event Header: slot=" << slot_event_header << " itrigger=" << itrigger << endl; |
2087 | } |
2088 | } |
2089 | break; |
2090 | |
2091 | case 3: // Trigger time |
2092 | { |
2093 | uint64_t t = ((*iptr)&0xFFFFFF)<<0; |
2094 | iptr++; |
2095 | if(((*iptr>>31) & 0x1) == 0){ |
2096 | t += ((*iptr)&0xFFFFFF)<<24; // from word on the street: second trigger time word is optional!!?? |
2097 | }else{ |
2098 | iptr--; |
2099 | } |
2100 | if(VERBOSE>7) cout << " F1TDC Trigger Time (t="<<t<<")"<<endl; |
2101 | if(pe) pe->NEW_DF1TDCTriggerTime(rocid, slot, itrigger, t); |
2102 | } |
2103 | break; |
2104 | |
2105 | case 8: // F1 Chip Header |
2106 | trig_time_f1header = ((*iptr)>> 7) & 0x1FF; |
2107 | if(VERBOSE>7) { |
2108 | uint32_t chip_f1header = ((*iptr)>> 3) & 0x07; |
2109 | uint32_t chan_on_chip_f1header = ((*iptr)>> 0) & 0x07; // this is always 7 in real data! |
2110 | uint32_t itrigger_f1header = ((*iptr)>>16) & 0x3F; |
2111 | cout << " Found F1 header: chip=" << chip_f1header << " chan=" << chan_on_chip_f1header << " itrig=" << itrigger_f1header << " trig_time=" << trig_time_f1header << endl; |
2112 | } |
2113 | break; |
2114 | |
2115 | case 7: // F1 Data |
2116 | { |
2117 | uint32_t chip = (*iptr>>19) & 0x07; |
2118 | uint32_t chan_on_chip = (*iptr>>16) & 0x07; |
2119 | uint32_t time = (*iptr>> 0) & 0xFFFF; |
2120 | uint32_t channel = F1TDC_channel(chip, chan_on_chip, modtype); |
2121 | if(VERBOSE>7) cout << " Found F1 data : chip=" << chip << " chan=" << chan_on_chip << " time=" << time << endl; |
2122 | if(pe){ |
2123 | auto hit = pe->NEW_DF1TDCHit(rocid, slot, channel, itrigger, trig_time_f1header, time, *iptr, MODULE_TYPE(modtype)); |
2124 | if(hit->res_status==0){ |
2125 | static uint32_t Nwarnings=0; |
2126 | if(Nwarnings<10) jerr << "ERROR: F1 TDC chip \"unlocked\" flag set!" << ((++Nwarnings == 10) ? " -- last warning":"") << endl; |
2127 | } |
2128 | } |
2129 | } |
2130 | break; |
2131 | |
2132 | case 15: // Filler word |
2133 | if(VERBOSE>7) cout << " F1 filler word" << endl; |
2134 | case 14: // Data not valid (how to handle this?) |
2135 | break; |
2136 | |
2137 | default: |
2138 | cerr<<endl; |
2139 | cout.flush(); cerr.flush(); |
2140 | _DBG_std::cerr<<"libraries/DAQ/DEVIOWorkerThread.cc"<< ":"<<2140<<" "<<"Unknown data word in F1TDC block. Dumping for debugging:" << endl; |
2141 | for(const uint32_t *iiptr = istart; iiptr<iend; iiptr++){ |
2142 | _DBG_std::cerr<<"libraries/DAQ/DEVIOWorkerThread.cc"<< ":"<<2142<<" "<<"0x"<<hex<<*iiptr<<dec; |
2143 | if(iiptr == iptr)cerr<<" <----"; |
2144 | switch( (*iiptr) & 0xF8000000 ){ |
2145 | case 0x80000000: cerr << " F1 Block Header"; break; |
2146 | case 0x90000000: cerr << " F1 Event Header"; break; |
2147 | case 0x98000000: cerr << " F1 Trigger time"; break; |
2148 | case 0xC0000000: cerr << " F1 Header"; break; |
2149 | case 0xB8000000: cerr << " F1 Data"; break; |
2150 | case 0x88000000: cerr << " F1 Block Trailer"; break; |
2151 | case 0xF8000000: cerr << " Filler word"; break; |
2152 | case 0xF0000000: cerr << " <module has no valid data>"; break; |
2153 | default: break; |
2154 | } |
2155 | cerr<<endl; |
2156 | if(iiptr > (iptr+4)) break; |
2157 | } |
2158 | throw JExceptionDataFormat("Unexpected word type in F1TDC block!", __FILE__"libraries/DAQ/DEVIOWorkerThread.cc", __LINE__2158); |
2159 | break; |
2160 | } |
2161 | } |
2162 | |
2163 | // Skip filler words |
2164 | while(iptr<iend && (*iptr&0xF8000000)==0xF8000000)iptr++; |
2165 | } |
2166 | |
2167 | //---------------- |
2168 | // ParseSSPBank |
2169 | //---------------- |
2170 | void DEVIOWorkerThread::ParseSSPBank(uint32_t rocid, uint32_t* &iptr, uint32_t *iend) |
2171 | { |
2172 | if(!PARSE_SSP){ iptr = &iptr[(*iptr) + 1]; return; } |
2173 | |
2174 | auto pe_iter = current_parsed_events.begin(); |
2175 | DParsedEvent *pe = NULL__null; |
2176 | |
2177 | uint32_t slot_bh = 0xFFFFFFFF; //< slot number from block header |
2178 | uint32_t slot = 0xFFFFFFFF; //< slot number from event header |
2179 | uint32_t itrigger = 0xFFFFFFFF; |
2180 | uint32_t dev_id = 0xFFFFFFFF; |
2181 | uint32_t ievent_cnt = 0xFFFFFFFF; |
2182 | //uint32_t last_itrigger = itrigger; |
2183 | for( ; iptr<iend; iptr++){ |
2184 | if(((*iptr>>31) & 0x1) == 0)continue; |
2185 | |
2186 | uint32_t data_type = (*iptr>>27) & 0x0F; |
2187 | switch(data_type){ |
2188 | case 0: // Block Header |
2189 | { |
2190 | slot_bh = ((*iptr)>>22) & 0x1F; |
2191 | uint32_t block_num = ((*iptr)>> 8) & 0x3FF; |
2192 | uint32_t block_size = ((*iptr)>> 0) & 0xFF; |
2193 | if(VERBOSE>7) cout << " SSP/DIRC Block Header: slot=" << slot_bh << " block_num="<<block_num << " block_size=" << block_size << endl; |
2194 | } |
2195 | break; |
2196 | case 1: // Block Trailer |
2197 | pe_iter = current_parsed_events.begin(); |
2198 | pe = NULL__null; |
2199 | if(VERBOSE>7) cout << " SSP/DIRC Block Trailer" << endl; |
2200 | break; |
2201 | case 2: // Event Header |
2202 | slot = ((*iptr)>>22) & 0x1F; |
2203 | itrigger = ((*iptr)>> 0) & 0x3FFFFF; |
2204 | pe = *pe_iter++; |
2205 | //if(itrigger != last_itrigger) pe = *pe_iter++; |
2206 | //last_itrigger = itrigger; |
2207 | if(VERBOSE>7) cout << " SSP/DIRC Event Header: slot=" << slot << " itrigger=" << itrigger << endl; |
2208 | if( slot != slot_bh ){ |
2209 | jerr << "Slot from SSP/DIRC event header does not match slot from last block header (" <<slot<<" != " << slot_bh << ")" <<endl; |
2210 | } |
2211 | break; |
2212 | case 3: // Trigger Time |
2213 | { |
2214 | uint64_t t = ((*iptr)&0xFFFFFF)<<0; |
2215 | if(VERBOSE>7) cout << " SSP Trigger time low word="<<(((*iptr)&0xFFFFFF))<<" (0x"<<hex<<*iptr<<dec<<")"<<endl; |
2216 | iptr++; |
2217 | if(((*iptr>>31) & 0x1) == 0){ // Confirm that continuation word is present |
2218 | t += ((*iptr)&0xFFFFFF)<<24; |
2219 | if(VERBOSE>7) cout << " SSP Trigger time high word="<<(((*iptr)&0xFFFFFF))<<" (0x"<<hex<<*iptr<<dec<<") iptr=0x"<<hex<<iptr<<dec<<endl; |
2220 | }else{ |
2221 | iptr--; |
2222 | } |
2223 | if(VERBOSE>7) cout << " SSP Trigger Time: t="<<t<<endl; |
2224 | if(pe) pe->NEW_DDIRCTriggerTime(rocid, slot, itrigger, t); |
2225 | } |
2226 | break; |
2227 | case 4: // Reserved |
2228 | case 5: // Reserved |
2229 | case 6: // Reserved |
2230 | case 10: // Reserved |
2231 | case 11: // Reserved |
2232 | case 12: // Reserved |
2233 | case 13: // Reserved |
2234 | if(VERBOSE>7) cout << " SSP/DIRC Reserved Word" << endl; |
2235 | break; |
2236 | case 7: // Device ID |
2237 | dev_id = ((*iptr)>>22) & 0x1F; |
2238 | ievent_cnt = ((*iptr)>>0 ) & 0x3FFFFF; |
2239 | if(VERBOSE>7) cout << " SSP/DIRC Device ID: dev_id=" << dev_id << " ievent_cnt=" << ievent_cnt << endl; |
2240 | break; |
2241 | case 8: // TDC Hit (single channel) |
2242 | { |
2243 | uint32_t edge = (*iptr>>26) & 0x01; |
2244 | uint32_t channel_fpga = (*iptr>>16) & 0xFF; |
2245 | uint32_t time = (*iptr>>0 ) & 0xFFFF; |
2246 | uint32_t channel = (dev_id<<8) + channel_fpga; |
2247 | if(VERBOSE>7) cout << " SSP/DIRC TDC Hit: edge=" << edge << "channel_fpga=" << channel_fpga << "time=" << time << " channel=" << channel << endl; |
2248 | if( pe ) pe->NEW_DDIRCTDCHit(rocid, slot, channel, itrigger, dev_id, ievent_cnt, channel_fpga, edge, time); |
2249 | } |
2250 | break; |
2251 | case 9: // ADC (64 channels, currently only used for bench testing and may not be supported by all firmware versions) |
2252 | { |
2253 | if(VERBOSE>7) cout << " SSP/DIRC ADC data"<<endl; |
2254 | uint32_t adc_hold2 = (*iptr>>16) & 0xFF; |
2255 | uint32_t adc_hold1 = (*iptr>>8 ) & 0xFF; |
2256 | uint32_t adc_max_bits = (*iptr>>4 ) & 0x0F; |
2257 | uint32_t maroc_id = (*iptr>>0 ) & 0x03; |
2258 | for(uint32_t i=0; i<32; i++){ |
2259 | if(((*++iptr>>31) & 0x1) != 0){ iptr--; break;} |
2260 | uint32_t channel_lower = (dev_id<<8) + (maroc_id<<6) + (i*2 + 0); // ADC_LOWER |
2261 | uint32_t channel_upper = (dev_id<<8) + (maroc_id<<6) + (i*2 + 1); // ADC_UPPER |
2262 | uint32_t adc_lower = (*iptr>>0 ) & 0xFFF; |
2263 | uint32_t adc_upper = (*iptr>>16 ) & 0xFFF; |
2264 | switch(adc_max_bits){ |
2265 | case 11: |
2266 | break; |
2267 | case 9: |
2268 | adc_lower >>= 2; |
2269 | adc_upper >>= 2; |
2270 | break; |
2271 | case 7: |
2272 | adc_lower >>= 4; |
2273 | adc_upper >>= 4; |
2274 | break; |
2275 | default: |
2276 | jerr << "Bad value for adc_max_bits (" << adc_max_bits << ") from SSP/DIRC with rocid=" << rocid << " slot=" << slot << "channel=" << channel_lower << "," << channel_upper << endl; |
2277 | break; |
2278 | } |
2279 | if( pe ) { |
2280 | pe->NEW_DDIRCADCHit(rocid, slot, channel_lower, itrigger, dev_id, ievent_cnt, adc_hold1, adc_hold2, adc_max_bits, maroc_id, adc_lower); |
2281 | pe->NEW_DDIRCADCHit(rocid, slot, channel_upper, itrigger, dev_id, ievent_cnt, adc_hold1, adc_hold2, adc_max_bits, maroc_id, adc_upper); |
2282 | } |
2283 | } |
2284 | } |
2285 | break; |
2286 | case 14: // Data not Valid |
2287 | if(VERBOSE>7) cout << " SSP/DIRC Data not Valid" << endl; |
2288 | break; |
2289 | case 15: // Filler Word |
2290 | if(VERBOSE>7) cout << " SSP/DIRC Filler Word" << endl; |
2291 | break; |
2292 | } |
2293 | } |
2294 | |
2295 | iptr =iend; |
2296 | } |
2297 | |
2298 | //---------------- |
2299 | // ParseGEMSRSBank |
2300 | //---------------- |
2301 | void DEVIOWorkerThread::ParseDGEMSRSBank(uint32_t rocid, uint32_t* &iptr, uint32_t *iend) |
2302 | { |
2303 | if(!PARSE_GEMSRS){ iptr = &iptr[(*iptr) + 1]; return; } |
2304 | if(VERBOSE>7) cout << "GEMSRS ROC " << rocid <<endl; |
2305 | |
2306 | auto pe_iter = current_parsed_events.begin(); |
2307 | DParsedEvent *pe = NULL__null; |
2308 | |
2309 | // fictitious slot for TT, since SRS is a separate crate but read through ROC 76 |
2310 | uint32_t slot = 24; |
2311 | uint32_t apv_id = 0xFFFFFFFF; |
2312 | uint32_t fec_id = 0xFFFFFFFF; |
2313 | uint32_t itrigger = 0xFFFFFFFF; |
2314 | //uint32_t ievent_cnt = 0xFFFFFFFF; |
2315 | //uint32_t last_itrigger = itrigger; |
2316 | |
2317 | vector<int> rawData16bits; |
2318 | |
2319 | iptr++; //skip first word? (no idata=0) used in GEMRawDecoder::Decode |
2320 | |
2321 | while(true) { // while haven't reached event trailer |
2322 | |
2323 | if(((*iptr>>8) & 0xffffff) == 0x414443) { // magic key for "Data Header" in ADC format |
2324 | |
2325 | if(rawData16bits.size() > 0) { |
2326 | if(VERBOSE>7) cout<<"Previous channel: apv_id = "<<apv_id<<" fec_id = "<<fec_id<<" had "<<rawData16bits.size()<<" 16 bit words"<<endl; |
2327 | |
2328 | if( pe ) MakeDGEMSRSWindowRawData(pe, rocid, slot, itrigger, apv_id, rawData16bits); |
2329 | } |
2330 | else { // for first APV in event initialize DParsedEvent |
2331 | pe = *pe_iter++; |
2332 | } |
2333 | |
2334 | // initial word is "Data Header" |
2335 | apv_id = (*iptr) & 0xff; // equivalent to nadcCh in GEMRawDecoder::Decode |
2336 | iptr++; // next word is "Header Info" (reserved) |
2337 | fec_id = (*iptr>>16) & 0xff; // equivalent to nfecID in GEMRawDecoder::Decode |
2338 | |
2339 | if(VERBOSE>7) cout<<"Data Header for APV = "<<apv_id<<" FEC = "<<fec_id<<endl; |
2340 | |
2341 | // clear vector for raw data from this APV |
2342 | rawData16bits.clear(); |
2343 | } |
2344 | else { |
2345 | unsigned int word32bit = *iptr; |
2346 | unsigned int word16bit1 = 0; |
2347 | unsigned int word16bit2 = 0; |
2348 | |
2349 | unsigned int data1 = ( (word32bit)>>24 ) & 0xff; |
2350 | unsigned int data2 = ( (word32bit)>>16 ) & 0xff; |
2351 | unsigned int data3 = ( (word32bit)>>8 ) & 0xff; |
2352 | unsigned int data4 = (word32bit) & 0xff; |
2353 | |
2354 | (word16bit1) = (data2 << 8) | data1; |
2355 | (word16bit2) = (data4 << 8) | data3; |
2356 | rawData16bits.push_back(word16bit1); |
2357 | rawData16bits.push_back(word16bit2); |
2358 | } |
2359 | |
2360 | // trailer word (cleanup data from last APV?) |
2361 | if(*iptr == 0xfafafafa) { |
2362 | |
2363 | // write last ADC channel out from rawData16bits vector |
2364 | if(rawData16bits.size() > 0) { |
2365 | if(VERBOSE>7) cout<<"Previous channel: apv_id = "<<apv_id<<" fec_id = "<<fec_id<<" had "<<rawData16bits.size()<<" 16 bit words"<<endl; |
2366 | |
2367 | if( pe ) MakeDGEMSRSWindowRawData(pe, rocid, slot, itrigger, apv_id, rawData16bits); |
2368 | } |
2369 | |
2370 | // reset DParsedEvent with event trailer? |
2371 | pe_iter = current_parsed_events.begin(); |
2372 | pe = NULL__null; |
2373 | break; |
2374 | } |
2375 | |
2376 | iptr++; |
2377 | } |
2378 | |
2379 | iptr =iend; |
2380 | } |
2381 | |
2382 | //------------------------- |
2383 | // MakeDGEMSRSWindowRawData |
2384 | //------------------------- |
2385 | void DEVIOWorkerThread::MakeDGEMSRSWindowRawData(DParsedEvent *pe, uint32_t rocid, uint32_t slot, uint32_t itrigger, uint32_t apv_id, vector<int>rawData16bits) |
2386 | { |
2387 | Int_t idata = 0, firstdata = 0, lastdata = 0; |
2388 | Int_t size = rawData16bits.size() ; |
2389 | vector<Float_t> rawDataTS, rawDataZS; |
2390 | rawDataTS.clear(); |
2391 | |
2392 | Int_t fAPVHeaderLevel = 1500; |
2393 | Int_t fNbOfTimeSamples = NSAMPLES_GEMSRS; // hard coded maximum number of time samples |
2394 | |
2395 | uint8_t NCH = 128; |
2396 | |
2397 | Int_t fStartData = 0; |
2398 | for(idata = 0; idata < size; idata++) { |
2399 | if (rawData16bits[idata] < fAPVHeaderLevel) { |
2400 | idata++ ; |
2401 | if (rawData16bits[idata] < fAPVHeaderLevel) { |
2402 | idata++ ; |
2403 | if (rawData16bits[idata] < fAPVHeaderLevel) { |
2404 | idata += 10; |
2405 | fStartData = idata ; |
2406 | idata = size ; |
2407 | } |
2408 | } |
2409 | } |
2410 | } |
2411 | |
2412 | // set range for data |
2413 | firstdata = fStartData ; |
2414 | lastdata = firstdata + NCH; |
2415 | |
2416 | /////////////////////////////////////////////////////////////////////// |
2417 | // loop over time bins and store samples in map for all APV channels // |
2418 | /////////////////////////////////////////////////////////////////////// |
2419 | //vector<uint16_t> windowDataAPV[NCH]; |
2420 | std::shared_ptr< vector<uint16_t> > sptr_windowDataAPV( new vector<uint16_t>[NCH] ); |
2421 | vector<uint16_t>* windowDataAPV = sptr_windowDataAPV.get(); |
2422 | //for(int i=0; i<NCH; i++) windowDataAPV[i].resize(fNbOfTimeSamples); |
2423 | |
2424 | for(Int_t timebin = 0; timebin < fNbOfTimeSamples; timebin++) { |
2425 | // EXTRACT APV25 DATA FOR A GIVEN TIME BIN |
2426 | rawDataTS.insert(rawDataTS.end(), &rawData16bits[firstdata], &rawData16bits[lastdata]); |
2427 | assert( rawDataTS.size() == 128 )((rawDataTS.size() == 128) ? static_cast<void> (0) : __assert_fail ("rawDataTS.size() == 128", "libraries/DAQ/DEVIOWorkerThread.cc" , 2427, __PRETTY_FUNCTION__)); |
2428 | for(Int_t chNo = 0; chNo < NCH; chNo++) { |
2429 | //windowDataAPV[chNo].at(timebin) = rawDataTS[chNo]; |
2430 | windowDataAPV[chNo].push_back(rawDataTS[chNo]); |
2431 | } |
2432 | |
2433 | firstdata = lastdata + 12 ; |
2434 | lastdata = firstdata + NCH; |
2435 | rawDataTS.clear() ; |
2436 | |
2437 | // if next time sample beyond last word, break from loop |
2438 | if(lastdata > size) break; |
2439 | } |
2440 | |
2441 | // write sample data to GEMSRS object |
2442 | for(int ichan=0; ichan<NCH; ichan++) { |
2443 | uint32_t channel = apv_id * 128 + ichan; |
2444 | DGEMSRSWindowRawData *windowRawData = pe->NEW_DGEMSRSWindowRawData(rocid, slot, channel, itrigger, apv_id, ichan); |
2445 | windowRawData->samples = windowDataAPV[ichan]; |
2446 | } |
2447 | } |
2448 | |
2449 | //---------------- |
2450 | // ParseDEventRFBunchBank |
2451 | //---------------- |
2452 | void DEVIOWorkerThread::ParseDEventRFBunchBank(uint32_t* &iptr, uint32_t *iend) |
2453 | { |
2454 | uint32_t Nwords = ((uint64_t)iend - (uint64_t)iptr)/sizeof(uint32_t); |
2455 | uint32_t Nwords_expected = 6; |
2456 | if(Nwords != Nwords_expected){ |
2457 | _DBG_std::cerr<<"libraries/DAQ/DEVIOWorkerThread.cc"<< ":"<<2457<<" " << "RFTime size does not match expected!!" << endl; |
2458 | _DBG_std::cerr<<"libraries/DAQ/DEVIOWorkerThread.cc"<< ":"<<2458<<" " << "Found " << Nwords << " words. Expected " << Nwords_expected << endl; |
2459 | }else{ |
2460 | DParsedEvent *pe = current_parsed_events.back(); |
2461 | DEventRFBunch *the_rftime = pe->NEW_DEventRFBunch(); |
2462 | |
2463 | the_rftime->dTimeSource = static_cast<DetectorSystem_t>(*iptr++); |
2464 | the_rftime->dNumParticleVotes = *iptr++; |
2465 | |
2466 | uint64_t in_word = *iptr++; // 1st word, lo word; 2nd word, hi word |
2467 | uint64_t in_word_hi = *iptr++; |
2468 | in_word |= in_word_hi<<32; |
2469 | double rftime; |
2470 | memcpy(&rftime, &in_word, sizeof(double)); |
2471 | in_word = *iptr++; in_word_hi = *iptr++; |
2472 | in_word |= in_word_hi<<32; |
2473 | double rftime_var; |
2474 | memcpy(&rftime_var, &in_word, sizeof(double)); |
2475 | |
2476 | the_rftime->dTime = rftime; |
2477 | the_rftime->dTimeVariance = rftime_var; |
2478 | } |
2479 | } |
2480 | |
2481 | |
2482 | //---------------- |
2483 | // ParseDVertexBank |
2484 | //---------------- |
2485 | void DEVIOWorkerThread::ParseDVertexBank(uint32_t* &iptr, uint32_t *iend) |
2486 | { |
2487 | uint32_t Nwords = ((uint64_t)iend - (uint64_t)iptr)/sizeof(uint32_t); |
2488 | uint32_t Nwords_expected = 11; |
2489 | if(Nwords != Nwords_expected){ |
2490 | _DBG_std::cerr<<"libraries/DAQ/DEVIOWorkerThread.cc"<< ":"<<2490<<" " << "DVertex size does not match expected!!" << endl; |
2491 | _DBG_std::cerr<<"libraries/DAQ/DEVIOWorkerThread.cc"<< ":"<<2491<<" " << "Found " << Nwords << " words. Expected " << Nwords_expected << endl; |
2492 | }else{ |
2493 | DParsedEvent *pe = current_parsed_events.back(); |
2494 | DVertex *the_vertex = pe->NEW_DVertex(); |
2495 | |
2496 | uint64_t in_word = *iptr++; // 1st word, lo word; 2nd word, hi word |
2497 | uint64_t in_word_hi = *iptr++; |
2498 | in_word |= in_word_hi<<32; |
2499 | //uint64_t hi_word = *iptr++; |
2500 | double vertex_x_pos; |
2501 | memcpy(&vertex_x_pos, &in_word, sizeof(double)); |
2502 | in_word = *iptr++; in_word_hi = *iptr++; |
2503 | in_word |= in_word_hi<<32; |
2504 | double vertex_y_pos; |
2505 | memcpy(&vertex_y_pos, &in_word, sizeof(double)); |
2506 | in_word = *iptr++; in_word_hi = *iptr++; |
2507 | in_word |= in_word_hi<<32; |
2508 | double vertex_z_pos; |
2509 | memcpy(&vertex_z_pos, &in_word, sizeof(double)); |
2510 | in_word = *iptr++; in_word_hi = *iptr++; |
2511 | in_word |= in_word_hi<<32; |
2512 | double vertex_t; |
2513 | memcpy(&vertex_t, &in_word, sizeof(double)); |
2514 | |
2515 | DVector3 vertex_position(vertex_x_pos, vertex_y_pos, vertex_z_pos); |
2516 | the_vertex->dSpacetimeVertex = DLorentzVector(vertex_position, vertex_t); |
2517 | the_vertex->dKinFitNDF = *iptr++; |
2518 | |
2519 | in_word = *iptr++; in_word_hi = *iptr++; |
2520 | in_word |= in_word_hi<<32; |
2521 | memcpy(&(the_vertex->dKinFitChiSq), &in_word, sizeof(double)); |
2522 | } |
2523 | } |
2524 | |
2525 | |
2526 | //---------------- |
2527 | // LinkAllAssociations |
2528 | //---------------- |
2529 | void DEVIOWorkerThread::LinkAllAssociations(void) |
2530 | { |
2531 | |
2532 | /// Find objects that should be linked as "associated objects" |
2533 | /// of one another and add to each other's list. |
2534 | for( auto pe : current_parsed_events){ |
2535 | |
2536 | //----------------- Sort hit objects |
2537 | |
2538 | // fADC250 (n.b. Df250PulseData values overwritten in JEventSource_EVIOpp::LinkBORassociations) |
2539 | if(pe->vDf250PulseData.size()>1 ) sort(pe->vDf250PulseData.begin(), pe->vDf250PulseData.end(), SortByPulseNumber<Df250PulseData> ); |
2540 | if(pe->vDf250PulseIntegral.size()>1) sort(pe->vDf250PulseIntegral.begin(), pe->vDf250PulseIntegral.end(), SortByPulseNumber<Df250PulseIntegral> ); |
2541 | if(pe->vDf250PulseTime.size()>1 ) sort(pe->vDf250PulseTime.begin(), pe->vDf250PulseTime.end(), SortByPulseNumber<Df250PulseTime> ); |
2542 | if(pe->vDf250PulsePedestal.size()>1) sort(pe->vDf250PulsePedestal.begin(), pe->vDf250PulsePedestal.end(), SortByPulseNumber<Df250PulsePedestal> ); |
2543 | if(pe->vDf250WindowRawData.size()>1) sort(pe->vDf250WindowRawData.begin(), pe->vDf250WindowRawData.end(), SortByChannel<Df250WindowRawData> ); |
2544 | |
2545 | // fADC125 |
2546 | if(pe->vDf125PulseIntegral.size()>1) sort(pe->vDf125PulseIntegral.begin(), pe->vDf125PulseIntegral.end(), SortByPulseNumber<Df125PulseIntegral> ); |
2547 | if(pe->vDf125CDCPulse.size()>1 ) sort(pe->vDf125CDCPulse.begin(), pe->vDf125CDCPulse.end(), SortByChannel<Df125CDCPulse> ); |
2548 | if(pe->vDf125FDCPulse.size()>1 ) sort(pe->vDf125FDCPulse.begin(), pe->vDf125FDCPulse.end(), SortByChannel<Df125FDCPulse> ); |
2549 | if(pe->vDf125PulseTime.size()>1 ) sort(pe->vDf125PulseTime.begin(), pe->vDf125PulseTime.end(), SortByPulseNumber<Df125PulseTime> ); |
2550 | if(pe->vDf125PulsePedestal.size()>1) sort(pe->vDf125PulsePedestal.begin(), pe->vDf125PulsePedestal.end(), SortByPulseNumber<Df125PulsePedestal> ); |
2551 | if(pe->vDf125WindowRawData.size()>1) sort(pe->vDf125WindowRawData.begin(), pe->vDf125WindowRawData.end(), SortByChannel<Df125WindowRawData> ); |
2552 | |
2553 | // F1TDC |
2554 | if(pe->vDF1TDCHit.size()>1 ) sort(pe->vDF1TDCHit.begin(), pe->vDF1TDCHit.end(), SortByModule<DF1TDCHit> ); |
2555 | |
2556 | // CAEN1290TDC |
2557 | if(pe->vDCAEN1290TDCHit.size()>1 ) sort(pe->vDCAEN1290TDCHit.begin(), pe->vDCAEN1290TDCHit.end(), SortByModule<DCAEN1290TDCHit> ); |
2558 | |
2559 | |
2560 | //----------------- Link hit objects |
2561 | |
2562 | // Connect Df250 pulse objects |
2563 | LinkPulse(pe->vDf250PulseTime, pe->vDf250PulseIntegral); |
2564 | LinkPulsePedCopy(pe->vDf250PulsePedestal, pe->vDf250PulseIntegral); |
2565 | |
2566 | // Connect Df125 pulse objects |
2567 | LinkPulse(pe->vDf125PulseTime, pe->vDf125PulseIntegral); |
2568 | LinkPulsePedCopy(pe->vDf125PulsePedestal, pe->vDf125PulseIntegral); |
2569 | |
2570 | // Connect Df250 window raw data objects |
2571 | if(!pe->vDf250WindowRawData.empty()){ |
2572 | LinkConfig(pe->vDf250Config, pe->vDf250WindowRawData); |
2573 | LinkModule(pe->vDf250TriggerTime, pe->vDf250WindowRawData); |
2574 | LinkChannel(pe->vDf250WindowRawData, pe->vDf250PulseIntegral); |
2575 | LinkChannel(pe->vDf250WindowRawData, pe->vDf250PulseTime); |
2576 | LinkChannel(pe->vDf250WindowRawData, pe->vDf250PulsePedestal); |
2577 | LinkChannel(pe->vDf250WindowRawData, pe->vDf250PulseData); |
2578 | } |
2579 | |
2580 | // Connect Df125 window raw data objects |
2581 | if(!pe->vDf125WindowRawData.empty()){ |
2582 | LinkConfig(pe->vDf125Config, pe->vDf125WindowRawData); |
2583 | LinkModule(pe->vDf125TriggerTime, pe->vDf125WindowRawData); |
2584 | LinkChannel(pe->vDf125WindowRawData, pe->vDf125PulseIntegral); |
2585 | LinkChannel(pe->vDf125WindowRawData, pe->vDf125PulseTime); |
2586 | LinkChannel(pe->vDf125WindowRawData, pe->vDf125PulsePedestal); |
2587 | LinkChannel(pe->vDf125WindowRawData, pe->vDf125CDCPulse); |
2588 | LinkChannel(pe->vDf125WindowRawData, pe->vDf125FDCPulse); |
2589 | } |
2590 | |
2591 | //----------------- Optionally link config objects (on by default) |
2592 | if(LINK_CONFIG){ |
2593 | if(pe->vDf250Config.size()>1 ) sort(pe->vDf250Config.begin(), pe->vDf250Config.end(), SortByROCID<Df250Config> ); |
2594 | if(pe->vDf125Config.size()>1 ) sort(pe->vDf125Config.begin(), pe->vDf125Config.end(), SortByROCID<Df125Config> ); |
2595 | if(pe->vDF1TDCConfig.size()>1 ) sort(pe->vDF1TDCConfig.begin(), pe->vDF1TDCConfig.end(), SortByROCID<DF1TDCConfig> ); |
2596 | if(pe->vDCAEN1290TDCConfig.size()>1) sort(pe->vDCAEN1290TDCConfig.begin(), pe->vDCAEN1290TDCConfig.end(), SortByROCID<DCAEN1290TDCConfig> ); |
2597 | |
2598 | LinkConfigSamplesCopy(pe->vDf250Config, pe->vDf250PulseIntegral); |
2599 | LinkConfigSamplesCopy(pe->vDf250Config, pe->vDf250PulseData); |
2600 | LinkConfigSamplesCopy(pe->vDf125Config, pe->vDf125PulseIntegral); |
2601 | LinkConfigSamplesCopy(pe->vDf125Config, pe->vDf125CDCPulse); |
2602 | LinkConfigSamplesCopy(pe->vDf125Config, pe->vDf125FDCPulse); |
2603 | LinkConfig(pe->vDF1TDCConfig, pe->vDF1TDCHit); |
2604 | LinkConfig(pe->vDCAEN1290TDCConfig, pe->vDCAEN1290TDCHit); |
2605 | } |
2606 | |
2607 | //----------------- Optionally link trigger time objects (off by default) |
2608 | if(LINK_TRIGGERTIME){ |
2609 | if(pe->vDf250TriggerTime.size()>1 ) sort(pe->vDf250TriggerTime.begin(), pe->vDf250TriggerTime.end(), SortByModule<Df250TriggerTime> ); |
2610 | if(pe->vDf125TriggerTime.size()>1 ) sort(pe->vDf125TriggerTime.begin(), pe->vDf125TriggerTime.end(), SortByModule<Df125TriggerTime> ); |
2611 | if(pe->vDF1TDCTriggerTime.size()>1 ) sort(pe->vDF1TDCTriggerTime.begin(), pe->vDF1TDCTriggerTime.end(), SortByModule<DF1TDCTriggerTime> ); |
2612 | |
2613 | LinkModule(pe->vDf250TriggerTime, pe->vDf250PulseIntegral); |
2614 | LinkModule(pe->vDf125TriggerTime, pe->vDf125PulseIntegral); |
2615 | LinkModule(pe->vDf125TriggerTime, pe->vDf125CDCPulse); |
2616 | LinkModule(pe->vDf125TriggerTime, pe->vDf125FDCPulse); |
2617 | LinkModule(pe->vDF1TDCTriggerTime, pe->vDF1TDCHit); |
2618 | } |
2619 | } |
2620 | |
2621 | } |
2622 | |
2623 | //---------------- |
2624 | // DumpBinary |
2625 | //---------------- |
2626 | void DEVIOWorkerThread::DumpBinary(const uint32_t *iptr, const uint32_t *iend, uint32_t MaxWords, const uint32_t *imark) |
2627 | { |
2628 | /// This is used for debugging. It will print to the screen the words |
2629 | /// starting at the address given by iptr and ending just before iend |
2630 | /// or for MaxWords words, whichever comes first. If iend is NULL, |
2631 | /// then MaxWords will be printed. If MaxWords is zero then it is ignored |
2632 | /// and only iend is checked. If both iend==NULL and MaxWords==0, then |
2633 | /// only the word at iptr is printed. |
2634 | |
2635 | cout << "Dumping binary: istart=" << hex << iptr << " iend=" << iend << " MaxWords=" << dec << MaxWords << endl; |
2636 | |
2637 | if(iend==NULL__null && MaxWords==0) MaxWords=1; |
2638 | if(MaxWords==0) MaxWords = (uint32_t)0xffffffff; |
2639 | |
2640 | uint32_t Nwords=0; |
2641 | while(iptr!=iend && Nwords<MaxWords){ |
2642 | |
2643 | // line1 is hex and line2 is decimal |
2644 | stringstream line1, line2; |
2645 | |
2646 | // print words in columns 8 words wide. First part is |
2647 | // reserved for word number |
2648 | uint32_t Ncols = 8; |
2649 | line1 << setw(5) << Nwords; |
2650 | line2 << string(5, ' '); |
2651 | |
2652 | // Loop over columns |
2653 | for(uint32_t i=0; i<Ncols; i++, iptr++, Nwords++){ |
2654 | |
2655 | if(iptr == iend) break; |
2656 | if(Nwords>=MaxWords) break; |
2657 | |
2658 | stringstream iptr_hex; |
2659 | iptr_hex << hex << "0x" << *iptr; |
2660 | |
2661 | string mark = (iptr==imark ? "*":" "); |
2662 | |
2663 | line1 << setw(12) << iptr_hex.str() << mark; |
2664 | line2 << setw(12) << *iptr << mark; |
2665 | } |
2666 | |
2667 | cout << line1.str() << endl; |
2668 | cout << line2.str() << endl; |
2669 | cout << endl; |
2670 | } |
2671 | } |
2672 | |
2673 |