JAPAn
Just Another Parity Analyzer
Loading...
Searching...
No Matches
QwEventBuffer.cc
Go to the documentation of this file.
1/*!
2 * \file QwEventBuffer.cc
3 * \brief Event buffer management for reading and processing CODA data files
4 */
5
6#include "QwEventBuffer.h"
7
8#include <chrono>
9#include <thread>
10
11#include "QwOptions.h"
12#include "QwEPICSEvent.h"
13#include "VQwSubsystem.h"
14#include "QwSubsystemArray.h"
15
16#include <TMath.h>
17
18#include <vector>
19#include <glob.h>
20
21#include <csignal>
24void sigint_handler(int sig)
25{
26 std::cout << "handling signal no. " << sig << " ";
27 std::cout << "(press ctrl-\\ to abort now)\n";
28 globalEXIT=1;
29}
30void sigusr_handler(int sig)
31{
32 std::cout << "handling signal no. " << sig << "\n";
33 std::cout << "Restarts the event loop in online mode." << std::endl;
34 onlineRestart = 1;
35}
36
37#include "THaCodaFile.h"
38#ifdef __CODA_ET
39#include "THaEtClient.h"
40#endif
41
42std::string QwEventBuffer::fDefaultDataDirectory = "/adaq1/data1/apar";
43std::string QwEventBuffer::fDefaultDataFileStem = "QwRun_";
45
46const Int_t QwEventBuffer::kRunNotSegmented = -20;
47const Int_t QwEventBuffer::kNoNextDataFile = -30;
49
50/// This is the ASCII character array 'NULL', and is used by the
51/// DAQ to indicate a known empty buffer.
52const UInt_t QwEventBuffer::kNullDataWord = 0x4e554c4c;
53
54
55/// Default constructor
57 : fRunListFile(nullptr),
58 fEventListFile(nullptr),
63 fEvStream(NULL),
64 fCurrentRun(-1),
66 fSingleFile(kFALSE),
67 decoder(NULL)
68{
69 // Set up the signal handler.
70 globalEXIT=0;
71 signal(SIGINT, sigint_handler);// ctrl+c
72 signal(SIGTERM, sigint_handler);// kill in shell // 15
73 // signal(SIGTSTP, sigint_handler);// ctrl+z // 20
75 signal(SIGUSR1, sigusr_handler);
76
77 fCleanParameter[0] = 0.0;
78 fCleanParameter[1] = 0.0;
79 fCleanParameter[2] = 0.0;
80}
81
82/**
83 * Defines configuration options for QwEventBuffer class using QwOptions
84 * functionality.
85 *
86 * @param options Options object
87 */
89{
90 // Define the execution options
91 options.AddDefaultOptions()
92 ("online", po::value<bool>()->default_bool_value(false),
93 "use online data stream");
94 options.AddDefaultOptions()
95 ("online.RunNumber", po::value<int>()->default_bool_value(0),
96 "Effective run number to be used by online system to find the parameter files");
97 options.AddDefaultOptions()
98 ("run,r", po::value<string>()->default_value("0:0"),
99 "run range in format #[:#]");
100 options.AddDefaultOptions()
101 ("data,d", po::value<string>()->default_value(fDefaultDataDirectory),
102 "data directory, also $QW_DATA");
103 options.AddDefaultOptions()
104 ("runlist", po::value<string>()->default_value(""),
105 "run list file name");
106 options.AddDefaultOptions()
107 ("event,e", po::value<string>()->default_value("0:"),
108 "event range in format #[:#]");
109 options.AddDefaultOptions()
110 ("segment,s", po::value<string>()->default_value("0:"),
111 "run segment range in format #[:#]");
112 options.AddDefaultOptions()
113 ("chainfiles", po::value<bool>()->default_bool_value(false),
114 "chain file segments together, do not analyze them separately");
115 options.AddDefaultOptions()
116 ("codafile-stem", po::value<string>()->default_value(fDefaultDataFileStem),
117 "stem of the input CODA filename");
118 options.AddDefaultOptions()
119 ("codafile-ext", po::value<string>()->default_value(fDefaultDataFileExtension),
120 "extension of the input CODA filename");
121 options.AddOptions()
122 ("directfile", po::value<string>(),
123 "Run over single event file");
124 // Special flag to allow sub-bank IDs less than 31
125 options.AddDefaultOptions()
126 ("allow-low-subbank-ids", po::value<bool>()->default_bool_value(false),
127 "allow the sub-bank ids to be 31 or less, when using this flag, all ROCs must be sub-banked");
128 // Options specific to the ET clients
129 options.AddOptions("ET system options")
130 ("ET.hostname", po::value<string>(),
131 "Name of the ET session's host machine --- Only used in online mode\nDefaults to the environment variable $HOSTNAME");
132 options.AddOptions("ET system options")
133 ("ET.session", po::value<string>(),
134 "ET session name --- Only used in online mode\nDefaults to the environment variable $SESSION");
135 options.AddOptions("ET system options")
136 ("ET.station", po::value<string>(),
137 "ET station name --- Only used in online mode");
138 options.AddOptions("ET system options")
139 ("ET.waitmode", po::value<int>()->default_value(0),
140 "ET system wait mode: 0 is wait-forever, 1 is timeout \"quickly\" --- Only used in online mode");
141 options.AddOptions("ET system options")
142 ("ET.exit-on-end", po::value<bool>()->default_value(false),
143 "Exit the event loop if the end event is found. JAPAN remains open and waits for the next run. --- Only used in online mode");
144 options.AddOptions("CodaVersion")
145 ("coda-version", po::value<int>()->default_value(3),
146 "Sets the Coda Version. Allowed values = {2,3}. \nThis is needed for writing and reading mock data. Mock data needs to be written and read with the same Coda Version.");
147 options.AddOptions("Event rate limiting")
148 ("max-event-rate", po::value<double>()->default_value(0.0),
149 "Maximum event write rate in Hz (0 = disabled, no rate limiting)");
150}
151
153{
154 fOnline = options.GetValue<bool>("online");
155 if (fOnline){
156 fETWaitMode = options.GetValue<int>("ET.waitmode");
157 fExitOnEnd = options.GetValue<bool>("ET.exit-on-end");
158#ifndef __CODA_ET
159 QwError << "Online mode will not work without the CODA libraries!"
160 << QwLog::endl;
161 exit(EXIT_FAILURE);
162#else
163 if (options.HasValue("online.RunNumber")) {
164 fCurrentRun = options.GetValue<int>("online.RunNumber");
165 }
166 if (options.HasValue("ET.station")) {
167 fETStationName = options.GetValue<string>("ET.station");
168 } else {
169 fETStationName = "";
170 }
171 if (options.HasValue("ET.hostname")) {
172 fETHostname = options.GetValue<string>("ET.hostname");
173 } else {
174 fETHostname = getenv("HOSTNAME");
175 }
176 if (options.HasValue("ET.session")) {
177 fETSession = options.GetValue<string>("ET.session");
178 } else {
179 fETSession = getenv("SESSION");
180 }
181 if (fETHostname.Length() == 0 || fETSession.Length() == 0) {
182 TString tmp = "";
183 if (fETHostname == NULL || fETHostname.Length() == 0)
184 tmp += " \"HOSTNAME\"";
185 if (fETSession == NULL || fETSession.Length() == 0){
186 if (tmp.Length() > 0)
187 tmp += " and";
188 tmp += " ET \"SESSION\"";
189 }
190 QwError << "The" << tmp
191 << " variable(s) is(are) not defined in your environment.\n"
192 << " This is needed to run the online analysis."
193 << QwLog::endl;
194 exit(EXIT_FAILURE);
195 }
196#endif
197 }
198 if(options.HasValue("directfile")){
199 fSingleFile = kTRUE;
200 fDataFile = options.GetValue<string>("directfile");
201 } else {
202 fSingleFile = kFALSE;
203 }
204 fDataDirectory = options.GetValue<string>("data");
205 if (fDataDirectory.Length() == 0){
206 QwError << "ERROR: Can't get the data directory in the QwEventBuffer creator."
207 << QwLog::endl;
208 } else if (! fDataDirectory.EndsWith("/")) {
209 fDataDirectory.Append("/");
210 }
211
212 fRunRange = options.GetIntValuePair("run");
213 fEventRange = options.GetIntValuePair("event");
214 fSegmentRange = options.GetIntValuePair("segment");
215 fRunListFileName = options.GetValue<string>("runlist");
216 fChainDataFiles = options.GetValue<bool>("chainfiles");
217 fDataFileStem = options.GetValue<string>("codafile-stem");
218 fDataFileExtension = options.GetValue<string>("codafile-ext");
219 fDataVersion = options.GetValue<int>("coda-version");
220
221 if(fDataVersion == 2){
223 } else if(fDataVersion == 3) {
225 } else{
226 QwError << "Invalid Coda Version. Only versions 2 and 3 are supported. "
227 << "Please set using --coda-version 2(3)" << QwLog::endl;
228 exit(EXIT_FAILURE);
229 }
230
231 decoder->SetAllowLowSubbankIDs( options.GetValue<bool>("allow-low-subbank-ids") );
232
233 // Process event rate limiting option
234 fMaxEventRate = options.GetValue<double>("max-event-rate");
235 if (fMaxEventRate > 0.0) {
237 fMinEventInterval = std::chrono::duration<double>(1.0 / fMaxEventRate);
238 QwMessage << "Event rate limiting enabled: " << fMaxEventRate << " Hz "
239 << "(minimum interval: " << (1000.0 / fMaxEventRate) << " ms)"
240 << QwLog::endl;
241 } else {
243 }
244 fLastEventTime = std::chrono::steady_clock::now();
245
246 // Open run list file
247 /* runlist file format example:
248 [5253]
249 234
250 246
251 256
252 345:456
253 567:789
254 [5259]
255 [5260]
256 0:10000
257 [5261:5270]
258 9000:10000
259 - for run 5253 it will analyze three individual events, and two event ranges
260 - for run 5259 it will analyze the entire run (all segments)
261 - for run 5260 it will analyze the first 10000 events
262 - for runs 5261 through 5270 it will analyze the events 9000 through 10000)
263 */
264 if (fRunListFileName.size() > 0) {
265 fRunListFile = std::make_unique<QwParameterFile>(fRunListFileName);
266 fEventListFile = nullptr;
267 if (! GetNextRunRange()) {
268 QwWarning << "No run range found in run list file: " << fRunListFile->GetLine() << QwLog::endl;
269 }
270 } else {
271 fRunListFile = nullptr;
272 fEventListFile = nullptr;
273 }
274}
275
277{
278 UInt_t nevents = fNumPhysicsEvents - fStartingPhysicsEvent;
279 if (nevents==0) nevents=1;
281 << "Analysis of run " << GetRunNumber() << QwLog::endl
282 << fNumPhysicsEvents << " physics events were processed"<< QwLog::endl
283 << "CPU time used: " << fRunTimer.CpuTime() << " s "
284 << "(" << 1000.0 * fRunTimer.CpuTime() / nevents << " ms per event)" << QwLog::endl
285 << "Real time used: " << fRunTimer.RealTime() << " s "
286 << "(" << 1000.0 * fRunTimer.RealTime() / nevents << " ms per event)" << QwLog::endl
287 << QwLog::endl;
288}
289
290
291
292/// Read the next requested event range, return true if success
294 // If there is an event list, open the next section
295 if (fEventListFile && !fEventListFile->IsEOF()) {
296 std::string eventrange;
297 // Find next non-whitespace, non-comment, non-empty line, before EOF
298 do {
299 fEventListFile->ReadNextLine(eventrange);
300 fEventListFile->TrimWhitespace();
301 fEventListFile->TrimComment('#');
302 } while (fEventListFile->LineIsEmpty() && !fEventListFile->IsEOF());
303 // If EOF return false; no next event range
304 if (fEventListFile->IsEOF()) return kFALSE;
305 // Parse the event range
307 QwMessage << "Next event range is " << eventrange << QwLog::endl;
308 return kTRUE;
309 }
310 return kFALSE;
311}
312
313/// Read the next requested run range, return true if success
315 // If there is a run list, open the next section
316 std::string runrange;
317 if (fRunListFile && !fRunListFile->IsEOF() &&
318 (fEventListFile = fRunListFile->ReadNextSection(runrange))) {
319 // Parse the run range
321 QwMessage << "Next run range is " << runrange << QwLog::endl;
322 // If there is no event range for this run range, set to default of 0:MAXINT
323 if (! GetNextEventRange()) {
324 QwWarning << "No valid event range in run list file: "
325 << fEventListFile->GetLine() << ". "
326 << "Assuming the full event range." << QwLog::endl;
328 }
329 return kTRUE;
330 }
331 return kFALSE;
332}
333
334/// Get the next run in the active run range, proceed to next range if needed
336 // First run
337 if (fCurrentRun == -1) {
338 fCurrentRun = fRunRange.first;
339 return kTRUE;
340 // Run is in range
341 } else if (fCurrentRun < fRunRange.second) {
342 fCurrentRun++;
343 return kTRUE;
344 // Run is not in range, get new range
345 } else if (GetNextRunRange()) {
346 fCurrentRun = fRunRange.first;
347 return kTRUE;
348 }
349 return kFALSE;
350}
351
353{
354 TString runlabel = Form("%d",fCurrentRun);
356 runlabel += Form(".%03d",*fRunSegmentIterator);
357 }
358 return runlabel;
359}
360
362{
363 Int_t status = CODA_ERROR;
364 // Reset the physics event counter
366
367 if (fOnline) {
368 // Online stream
370 } else {
371 // Offline data file
372 if (fRunIsSegmented)
373 // Segmented
374 status = OpenNextSegment();
375 else
376 // Not segmented
377 status = OpenDataFile(fCurrentRun);
378 }
379 return status;
380}
381
383{
384 Int_t status = CODA_ERROR;
385 if (globalEXIT==1) {
386 // We want to exit, so don't open the next stream.
387 status = CODA_ERROR;
388 } else if (fOnline) {
389 /* Modify the call below for your ET system, if needed.
390 OpenETStream( ET host name , $SESSION , mode)
391 mode=0: wait forever
392 mode=1: timeout quickly
393 */
394 QwMessage << "Try to open the ET station with HOSTNAME=="
395 << fETHostname
396 << ", SESSION==" << fETSession << "."
397 << QwLog::endl;
399
400 } else {
401 // Try to open the next data file for the current run,
402 // but only if we haven't hit the event limit.
403 if (fCurrentRun != -1 && !fChainDataFiles
404 && decoder->GetEvtNumber() <= fEventRange.second) {
405 status = OpenNextSegment();
406 }
407 while (status != CODA_OK && GetNextRunNumber()) {
408 status = OpenDataFile(fCurrentRun);
409 if (status == CODA_ERROR){
410 // The data file can't be opened.
411 // Get ready to process the next run.
412 QwError << "ERROR: Unable to find data files for run "
413 << fCurrentRun << ". Moving to the next run.\n"
414 << QwLog::endl;
415 }
416 }
417
418 }
419 // Grab the starting event counter
421 // Start the timers.
422 fRunTimer.Reset();
423 fRunTimer.Start();
424 fStopwatch.Start();
425 return status;
426}
427
429{
430 // Stop the timers.
431 fRunTimer.Stop();
432 fStopwatch.Stop();
433 QwWarning << "Starting CloseStream."
434 << QwLog::endl;
435 Int_t status = kFileHandleNotConfigured;
438 // The run is segmented and we are not chaining the
439 // segments together in the event loop, so close
440 // the current segment.
441 status = CloseThisSegment();
442 } else if (fEvStreamMode==fEvStreamFile) {
443 status = CloseDataFile();
444 } else if (fEvStreamMode==fEvStreamFile){
445 status = CloseETStream();
446 }
447 return status;
448}
449
450
451
453{
454 // This will return for read errors,
455 // non-physics events, and for physics
456 // events that are within the event range.
457 Int_t status = CODA_OK;
458 do {
459 status = GetEvent();
460 if (globalEXIT == 1) {
461 // QUESTION: Should we continue to loop once we've
462 // reached the maximum event, to allow access to
463 // non-physics events?
464 // For now, mock up EOF if we've reached the maximum event.
465 status = EOF;
466 }
467 if (decoder->GetEvtNumber() > fEventRange.second) {
468 do {
469 if (GetNextEventRange()) status = CODA_OK;
470 else status = EOF;
471 } while (decoder->GetEvtNumber() < fEventRange.first);
472 }
473 // While we're in a run segment which was not requested (which
474 // should happen only when reading the zeroth segment for startup
475 // information), pretend that there's an event cut causing us to
476 // ignore events. Read configuration events only from the first
477 // part of the file.
479 fEventRange.first = decoder->GetEvtNumber() + 1;
480 if (decoder->GetEvtNumber() > 1000) status = EOF;
481 }
482 if (fOnline && fExitOnEnd && decoder->GetEndTime()>0){
483 // fExitOnEnd exits the event loop only and does not exit JAPAN.
484 // The root file gets processed and JAPAN immediately waits for the next run.
485 // We considered adding a exit-JAPAN-on-end flag that quits JAPAN but decided
486 // we didn't have a use case for it. If quitting JAPAN is desired, just set:
487 // globalEXIT = 1
488 // -- mrc (01/21/25)
489 QwMessage << "Caught End Event (end time=="<< decoder->GetEndTime()
490 << "). Exit event loop." << QwLog::endl;
491 status = EOF;
492 }
493 if (fOnline && onlineRestart){
495 status = EOF;
496 }
497 } while (status == CODA_OK &&
498 IsPhysicsEvent() &&
499 (decoder->GetEvtNumber() < fEventRange.first
500 || decoder->GetEvtNumber() > fEventRange.second)
501 );
502 if (status == CODA_OK && IsPhysicsEvent()) fNumPhysicsEvents++;
503
504 // Progress meter (this should probably produce less output in production)
505 int nevents = 10000;
506 if (IsPhysicsEvent() && decoder->GetEvtNumber() > 0 && decoder->GetEvtNumber() % nevents == 0) {
507 QwMessage << "Processing event " << decoder->GetEvtNumber() << " ";
508 fStopwatch.Stop();
509 double efficiency = 100.0 * fStopwatch.CpuTime() / fStopwatch.RealTime();
510 QwMessage << "(" << fStopwatch.CpuTime()*1e3/nevents << " ms per event with ";
511 QwMessage << efficiency << "% efficiency)";
512 fStopwatch.Reset();
513 fStopwatch.Start();
515 } else if (decoder->GetEvtNumber() > 0 && decoder->GetEvtNumber() % 100 == 0) {
516 QwVerbose << "Processing event " << decoder->GetEvtNumber() << QwLog::endl;
517 }
518
519 return status;
520}
521
522
524{
525 Int_t status = kFileHandleNotConfigured;
526 ResetFlags();
528 status = GetFileEvent();
529 } else if (fEvStreamMode==fEvStreamET){
530 status = GetEtEvent();
531 }
532 if (status == CODA_OK){
533 // Coda Data was loaded correctly
534 UInt_t* evBuffer = (UInt_t*)fEvStream->getEvBuffer();
535 if(fDataVersionVerify == 0){ // Default = 0 => Undetermined
536 VerifyCodaVersion(evBuffer);
537 }
538 decoder->DecodeEventIDBank(evBuffer);
539 }
540 return status;
541}
542
543// Tries to figure out what Coda Version the Data is
544// fDataVersionVerify =
545// 2 -- Coda Version 2
546// 3 -- Coda Version 3
547// 0 -- Default (Unknown, Could be a EPICs Event or a ROCConfiguration)
548void QwEventBuffer::VerifyCodaVersion( const UInt_t *buffer )
549{
550 if(buffer[0] == 0) return;
551 UInt_t header = buffer[1];
552 int top = (header & 0xff000000) >> 24;
553 int bot = (header & 0xff );
554 fDataVersionVerify = 0; // Default
555 if( (top == 0xff) && (bot != 0xcc) ){
556 fDataVersionVerify = 3; // Coda 3
557 } else if( (top != 0xff) && (bot == 0xcc) ){
558 fDataVersionVerify = 2; // Coda 2
559 }
560 // Validate
562 QwError << "QwEventBuffer::GetEvent: Coda Version is not recognized" << QwLog::endl;
563 QwError << "fDataVersion == " << fDataVersion
564 << ", but it looks like the data is from Coda Version "
566 << "\nTry running with --coda-version " << fDataVersionVerify
567 << "\nExiting ... " << QwLog::endl;
568 globalEXIT = 1;
569 }
570 return;
571}
572
574 Int_t status = CODA_OK;
575 // Try to get a new event. If the EOF occurs,
576 // and the run is segmented, try to open the
577 // next segment and read a new event; repeat
578 // if needed.
579 do {
580 status = fEvStream->codaRead();
581 if (fChainDataFiles && status == EOF){
583 // Crash out of the loop if we can't open the
584 // next segment!
585 if (OpenNextSegment()!=CODA_OK) break;
586 }
587 } while (fChainDataFiles && status == EOF);
588 return status;
589}
590
592 Int_t status = CODA_OK;
593 // Do we want to have any loop here to wait for a bad
594 // read to be cleared?
595 status = fEvStream->codaRead();
596 if (status != CODA_OK) {
597 globalEXIT = 1;
598 }
599 return status;
600}
601
602
604{
605 Int_t status = kFileHandleNotConfigured;
606 ResetFlags();
607
608 // Rate limiting: sleep until minimum interval has elapsed, accounting for accumulated delays
610 auto now = std::chrono::steady_clock::now();
611 auto elapsed = now - fLastEventTime;
612
613 if (elapsed < fMinEventInterval) {
614 // We're ahead of schedule - need to wait
615 auto target_sleep = fMinEventInterval - elapsed;
616
617 // Reduce sleep time by accumulated delay (time we're behind)
618 auto actual_sleep = target_sleep - fAccumulatedDelay;
619
620 if (actual_sleep > std::chrono::duration<double>(0)) {
621 // Still need to sleep after compensation
622 auto sleep_until_time = now + actual_sleep;
623 std::this_thread::sleep_until(sleep_until_time);
624
625 // We've compensated for some or all of the accumulated delay
626 fAccumulatedDelay -= (target_sleep - actual_sleep);
627 if (fAccumulatedDelay < std::chrono::duration<double>(0)) {
628 fAccumulatedDelay = std::chrono::duration<double>(0);
629 }
630 } else {
631 // Accumulated delay is larger than needed sleep - don't sleep at all
632 fAccumulatedDelay -= target_sleep;
633 }
634 } else {
635 // We're behind schedule - accumulate the delay
636 auto delay = elapsed - fMinEventInterval;
637 fAccumulatedDelay += delay;
638 }
639 fLastEventTime = std::chrono::steady_clock::now();
640 }
641
643 status = WriteFileEvent(buffer);
644 } else if (fEvStreamMode==fEvStreamET) {
645 status = WriteEtEvent(buffer);
646 }
647
648 if (globalEXIT == 1) {
649 status = CODA_ERROR;
650 }
651
652 return status;
653}
654
656{
657 Int_t status = CODA_OK;
658 // fEvStream is of inherited type THaCodaData,
659 // but codaWrite is only defined for THaCodaFile.
660 status = ((THaCodaFile*)fEvStream)->codaWrite((UInt_t*) buffer);
661 return status;
662}
663
665{
666 Int_t status = CODA_OK;
667 // fEvStream is of inherited type THaCodaData,
668 // but codaWrite for ET is defined in THaEtClient.
669#ifdef __CODA_ET
670 // Get the buffer length from the first word (CODA event header)
671 UInt_t* ubuffer = (UInt_t*)buffer;
672 UInt_t event_length = ubuffer[0]; // First word is event length in words
673
674 if( event_length == 0 || event_length > MAXEVLEN ) {
675 QwError << "WriteEtEvent: Invalid event length: " << event_length << QwLog::endl;
676 return CODA_ERROR;
677 }
678
679 status = ((THaEtClient*)fEvStream)->codaWrite(ubuffer, event_length);
680 if( status != CODA_OK ) {
681 QwError << "WriteEtEvent: codaWrite failed with status " << status << QwLog::endl;
682 }
683#else
684 QwError << "WriteEtEvent: ET support not compiled in" << QwLog::endl;
685 status = CODA_ERROR;
686#endif
687 return status;
688}
689
690
692{
693 // Encode the data in the elements of the subsystem array
694 std::vector<UInt_t> buffer;
695 std::vector<ROCID_t> ROCList;
696 subsystems.EncodeEventData(buffer);
697 subsystems.GetROCIDList(ROCList);
698 // Add CODA event header
699 std::vector<UInt_t> header = decoder->EncodePHYSEventHeader(ROCList);
700
701 // Copy the encoded event buffer into an array of integers,
702 // as expected by the CODA routines.
703 // Size of the event buffer in long words
704 int* codabuffer = new int[header.size() + buffer.size() + 1];
705 // First entry contains the buffer size
706 int k = 0;
707 codabuffer[k++] = header.size() + buffer.size();
708 for (size_t i = 0; i < header.size(); i++)
709 codabuffer[k++] = header.at(i);
710 for (size_t i = 0; i < buffer.size(); i++)
711 codabuffer[k++] = buffer.at(i);
712
713 // Now write the buffer to the stream
714 Int_t status = WriteEvent(codabuffer);
715 // delete the buffer
716 delete[] codabuffer;
717 // and report success or fail
718 return status;
719}
720
721
723{
724 decoder->ResetControlParameters();
725}
727{
728 decoder->ReportRunSummary();
729}
730
732{
733 return decoder->GetStartSQLTime();
734}
735
737{
738 return decoder->GetEndSQLTime();
739}
740
742{
743 return decoder->GetStartUnixTime();
744}
745
747{
748 return decoder->GetEndUnixTime();
749}
750
751Int_t QwEventBuffer::EncodePrestartEvent(int runnumber, int runtype)
752{
753 int buffer[5];
754 int localtime = (int)time(0);
755 decoder->EncodePrestartEventHeader(buffer, runnumber, runtype, localtime);
756 return WriteEvent(buffer);
757}
759{
760 int buffer[5];
761 int localtime = (int)time(0);
762 int eventcount = 0;
763 decoder->EncodeGoEventHeader(buffer, eventcount, localtime);
764 return WriteEvent(buffer);
765}
767{
768 int buffer[5];
769 int localtime = (int)time(0);
770 int eventcount = 0;
771 decoder->EncodePauseEventHeader(buffer, eventcount, localtime);
772 return WriteEvent(buffer);
773}
775{
776 int buffer[5];
777 int localtime = (int)time(0);
778 int eventcount = 0;
779 decoder->EncodeEndEventHeader(buffer, eventcount, localtime);
780 return WriteEvent(buffer);
781}
782
783
786
788{
789 /// Passes the data for the configuration events into each subsystem
790 /// object. Each object is responsible for recognizing the configuration
791 /// data which it ought to decode.
792 /// NOTE TO DAQ PROGRAMMERS:
793 /// The configuration event for a ROC must have the same
794 /// subbank structure as the physics events for that ROC.
795 Bool_t okay = kTRUE;
796 UInt_t rocnum = decoder->GetEvtType() - 0x90;
797 QwMessage << "QwEventBuffer::FillSubsystemConfigurationData: "
798 << "Found configuration event for ROC"
799 << rocnum
800 << QwLog::endl;
801 decoder->PrintDecoderInfo(QwMessage);
802 // Loop through the data buffer in this event.
803 UInt_t *localbuff = (UInt_t*)(fEvStream->getEvBuffer());
804 decoder->DecodeEventIDBank(localbuff);
805 while ((okay = decoder->DecodeSubbankHeader(&localbuff[decoder->GetWordsSoFar()]))){
806 // If this bank has further subbanks, restart the loop.
807 if (decoder->GetSubbankType() == 0x10) {
808 QwMessage << "This bank has further subbanks, restart the loop" << QwLog::endl;
809 continue;
810 }
811 // If this bank only contains the word 'NULL' then skip
812 // this bank.
813 if (decoder->GetFragLength()==1 && localbuff[decoder->GetWordsSoFar()]==kNullDataWord){
814 decoder->AddWordsSoFarAndFragLength();
815 QwMessage << "Skip this bank" << QwLog::endl;
816 continue;
817 }
818
819 // Subsystems may be configured to accept data in formats
820 // other than 32 bit integer (banktype==1), but the
821 // bank type is not provided. Subsystems must be able
822 // to process their data knowing only the ROC and bank tags.
823 //
824 // After trying the data in each subsystem, bump the
825 // fWordsSoFar to move to the next bank.
826
827 subsystems.ProcessConfigurationBuffer(rocnum, decoder->GetSubbankTag(),
828 &localbuff[decoder->GetWordsSoFar()],
829 decoder->GetFragLength());
830 decoder->AddWordsSoFarAndFragLength();
831 QwDebug << "QwEventBuffer::FillSubsystemConfigurationData: "
832 << "Ending loop: fWordsSoFar=="<<decoder->GetWordsSoFar()
833 <<QwLog::endl;
834 }
835
836 return okay;
837}
838
840{
841 // Initialize local flag
842 Bool_t okay = kTRUE;
843
844 // Reload the data buffer and decode the header again, this allows
845 // multiple calls to this function for different subsystem arrays.
846 UInt_t *localbuff = (UInt_t*)(fEvStream->getEvBuffer());
847
848 decoder->DecodeEventIDBank(localbuff);
849
850 // Clear the old event information from the subsystems.
851 subsystems.ClearEventData();
852
853 // Pass CODA run, segment, event number and type to the subsystem array.
854 subsystems.SetCodaRunNumber(fCurrentRun);
856 subsystems.SetCodaEventNumber(decoder->GetEvtNumber());
857 subsystems.SetCodaEventType(decoder->GetEvtType());
858
859 // If this event type is masked for the subsystem array, return right away
860 if (((0x1 << (decoder->GetEvtType() - 1)) & subsystems.GetEventTypeMask()) == 0) {
861 return kTRUE;
862 }
863
864 UInt_t offset;
865
866 // Loop through the data buffer in this event.
867 while ((okay = decoder->DecodeSubbankHeader(&localbuff[decoder->GetWordsSoFar()]))){
868
869 // If this bank has further subbanks, restart the loop.
870 if (decoder->GetSubbankType() == 0x10) continue;
871
872 // If this bank only contains the word 'NULL' then skip
873 // this bank.
874 if (decoder->GetFragLength() == 1 && localbuff[decoder->GetWordsSoFar()]==kNullDataWord) {
875 decoder->AddWordsSoFarAndFragLength();
876 continue;
877 }
878
879 // if (GetSubbankType() == 0x85) {
880 // std::cout << "ProcessEventBuffer: , SubbankTag= "<< GetSubbankTag()<<" FragLength="<<GetFragLength() <<std::endl;
881 // }
882
883// QwDebug << "QwEventBuffer::FillSubsystemData: "
884// << "Beginning loop: fWordsSoFar=="<<GetWordsSoFar()
885// <<QwLog::endl;
886
887 // Loop through the subsystems and try to store the data
888 // from this bank in each subsystem.
889 //
890 // Subsystems may be configured to accept data in formats
891 // other than 32 bit integer (banktype==1), but the
892 // bank type is not provided. Subsystems must be able
893 // to process their data knowing only the ROC and bank tags.
894 //
895 // After trying the data in each subsystem, bump the
896 // fWordsSoFar to move to the next bank.
897
898 // TODO:
899 // What is special about this subbank?
900 if( decoder->GetROC() == 0 && decoder->GetSubbankTag()==0x6101) {
901 //std::cout << "ProcessEventBuffer: ROC="<<GetROC()<<", SubbankTag="<< GetSubbankTag()<<", FragLength="<<GetFragLength() <<std::endl;
902 fCleanParameter[0]=localbuff[decoder->GetWordsSoFar()+decoder->GetFragLength()-4];//clean data
903 fCleanParameter[1]=localbuff[decoder->GetWordsSoFar()+decoder->GetFragLength()-3];//scan data 1
904 fCleanParameter[2]=localbuff[decoder->GetWordsSoFar()+decoder->GetFragLength()-2];//scan data 2
905 //std::cout << "ProcessEventBuffer: ROC="<<GetROC()<<", SubbankTag="<< GetSubbankTag()
906 // <<", FragLength="<<GetFragLength() << " " <<fCleanParameter[0]<< " " <<fCleanParameter[1]<< " " <<fCleanParameter[2]<<std::endl;
907
908 }
909
911
912 std::size_t nmarkers = CheckForMarkerWords(subsystems);
913 if (nmarkers>0) {
914 // There are markerwords for this ROC/Bank
915 for (size_t i=0; i<nmarkers; i++){
916 offset = FindMarkerWord(i,&localbuff[decoder->GetWordsSoFar()],decoder->GetFragLength());
917 BankID_t tmpbank = GetMarkerWord(i);
918 tmpbank = ((tmpbank)<<32) + decoder->GetSubbankTag();
919 offset++; // Skip the marker word
920 subsystems.ProcessEvBuffer(decoder->GetEvtType(), decoder->GetROC(), tmpbank,
921 &localbuff[decoder->GetWordsSoFar()+offset],
922 decoder->GetFragLength()-offset);
923 }
924 } else {
925 QwDebug << "QwEventBuffer::FillSubsystemData: "
926 << "fROC=="<<decoder->GetROC() << ", GetSubbankTag()==" << decoder->GetSubbankTag()
927 << QwLog::endl;
928 subsystems.ProcessEvBuffer(decoder->GetEvtType(), decoder->GetROC(), decoder->GetSubbankTag(),
929 &localbuff[decoder->GetWordsSoFar()],
930 decoder->GetFragLength());
931 }
932 decoder->AddWordsSoFarAndFragLength();
933// QwDebug << "QwEventBuffer::FillSubsystemData: "
934// << "Ending loop: fWordsSoFar=="<<GetWordsSoFar()
935// <<QwLog::endl;
936 }
937 return okay;
938}
939
940
941// added all this method for QwEPICSEvent class
943{
944 // QwVerbose << "QwEventBuffer::FillEPICSData: "
945// << Form("Length: %d; Tag: 0x%x; Bank ID num: 0x%x; ",
946// fEvtLength, fEvtTag, fIDBankNum)
947// << Form("Evt type: 0x%x; Evt number %d; Evt Class 0x%.8x; ",
948// fEvtType(), fEvtNumber, fEvtClass)
949// << Form("Status Summary: 0x%.8x; Words so far %d",
950// fStatSum, fWordsSoFar)
951// << QwLog::endl;
952
953
954 ///
955 Bool_t okay = kTRUE;
956 if (! IsEPICSEvent()){
957 okay = kFALSE;
958 return okay;
959 }
960 QwVerbose << "QwEventBuffer::FillEPICSData: "
961 << QwLog::endl;
962 // Loop through the data buffer in this event.
963 UInt_t *localbuff = (UInt_t*)(fEvStream->getEvBuffer());
964 if (decoder->GetBankDataType()==0x10){
965 while ((okay = decoder->DecodeSubbankHeader(&localbuff[decoder->GetWordsSoFar()]))){
966 // If this bank has further subbanks, restart the loop.
967 if (decoder->GetSubbankType() == 0x10) continue;
968 // If this bank only contains the word 'NULL' then skip
969 // this bank.
970 if (decoder->GetFragLength()==1 && localbuff[decoder->GetWordsSoFar()]==kNullDataWord){
971 decoder->AddWordsSoFarAndFragLength();
972 continue;
973 }
974
975 if (decoder->GetSubbankType() == 0x3){
976 // This is an ASCII string bank. Try to decode it and
977 // pass it to the EPICS class.
978 char* tmpchar = (Char_t*)&localbuff[decoder->GetWordsSoFar()];
979
980 epics.ExtractEPICSValues(string(tmpchar), GetEventNumber());
981 QwVerbose << "test for GetEventNumber =" << GetEventNumber() << QwLog::endl;// always zero, wrong.
982
983 }
984
985
986 decoder->AddWordsSoFarAndFragLength();
987
988// QwDebug << "QwEventBuffer::FillEPICSData: "
989// << "Ending loop: fWordsSoFar=="<<GetWordsSoFar()
990// <<QwLog::endl;
991// QwMessage<<"\nQwEventBuffer::FillEPICSData: fWordsSoFar = "<<GetWordsSoFar()<<QwLog::endl;
992
993
994 }
995 } else {
996 // Single bank in the event, use event headers.
997 if (decoder->GetBankDataType() == 0x3){
998 // This is an ASCII string bank. Try to decode it and
999 // pass it to the EPICS class.
1000 Char_t* tmpchar = (Char_t*)&localbuff[decoder->GetWordsSoFar()];
1001
1002 QwError << tmpchar << QwLog::endl;
1003
1004 epics.ExtractEPICSValues(string(tmpchar), GetEventNumber());
1005
1006 }
1007
1008 }
1009
1010 //std::cout<<"\nEpics data coming!! "<<GetWordsSoFar()<<std::endl;
1011 QwVerbose << "QwEventBuffer::FillEPICSData: End of routine"
1012 << QwLog::endl;
1013 return okay;
1014}
1015
1016const TString& QwEventBuffer::DataFile(const UInt_t run, const Short_t seg = -1)
1017{
1018 if(!fSingleFile){
1019 TString basename = fDataFileStem + Form("%u.",run) + fDataFileExtension;
1020 if(seg == -1){
1021 fDataFile = fDataDirectory + basename;
1022 } else {
1023 fDataFile = fDataDirectory + basename + Form(".%d",seg);
1024 }
1025 }
1026 return fDataFile;
1027}
1028
1029
1031{
1032 glob_t globbuf;
1033
1034 TString searchpath;
1035 TString scanvalue;
1036 Int_t local_segment;
1037
1038 std::vector<Int_t> tmp_segments;
1039 std::vector<Int_t> local_index;
1040
1041 /* Clear and set up the fRunSegments vector. */
1042 tmp_segments.clear();
1043 fRunSegments.clear();
1044 fRunSegments.resize(0);
1045 fRunIsSegmented = kFALSE;
1046
1047 searchpath = fDataFile;
1048 glob(searchpath.Data(), GLOB_ERR, NULL, &globbuf);
1049
1050 if(fSingleFile){
1051
1052 fRunIsSegmented = kFALSE;
1053
1054 } else if (globbuf.gl_pathc == 1){
1055 /* The base file name exists. *
1056 * Do not look for file segments. */
1057 fRunIsSegmented = kFALSE;
1058
1059 } else {
1060 /* The base file name does not exist. *
1061 * Look for file segments. */
1062 QwWarning << "File " << fDataFile << " does not exist!\n"
1063 << " Trying to find run segments for run "
1064 << fCurrentRun << "... ";
1065
1066 searchpath.Append(".[0-9]*");
1067 glob(searchpath.Data(), GLOB_ERR, NULL, &globbuf);
1068
1069 if (globbuf.gl_pathc == 0){
1070 /* There are no file segments and no base file *
1071 * Produce and error message and exit. */
1072 QwError << "\n There are no file segments either!!" << QwLog::endl;
1073
1074 // This could mean a single gzipped file!
1075 fRunIsSegmented = kFALSE;
1076
1077 } else {
1078 /* There are file segments. *
1079 * Determine the segment numbers and fill fRunSegments *
1080 * to indicate the existing file segments. */
1081
1082 QwMessage << "OK" << QwLog::endl;
1083 scanvalue = fDataFile + ".%d";
1084
1085 /* Get the list of segment numbers in file listing *
1086 * order. */
1087 for (size_t iloop=0;iloop<globbuf.gl_pathc;++iloop){
1088 /* Extract the segment numbers from the file name. */
1089 sscanf(globbuf.gl_pathv[iloop], scanvalue.Data(), &local_segment);
1090 tmp_segments.push_back(local_segment);
1091 }
1092 local_index.resize(tmp_segments.size(),0);
1093 /* Get the list of segments sorted numerically in *
1094 * increasing order. */
1095 TMath::Sort(static_cast<int>(tmp_segments.size()),&(tmp_segments[0]),&(local_index[0]),
1096 kFALSE);
1097 /* Put the segments into numerical order in fRunSegments. Add *
1098 * only those segments requested (though always add segment 0). */
1099 QwMessage << " Found the segment(s): ";
1100 size_t printed = 0;
1101 for (size_t iloop=0; iloop<tmp_segments.size(); ++iloop){
1102 local_segment = tmp_segments[local_index[iloop]];
1103 if (printed++) QwMessage << ", ";
1104 QwMessage << local_segment ;
1105 if (local_segment == 0 ||
1106 ( fSegmentRange.first <= local_segment &&
1107 local_segment <= fSegmentRange.second ) ) {
1108 fRunSegments.push_back(local_segment);
1109 } else {
1110 QwMessage << " (skipped)" ;
1111 }
1112 }
1113 QwMessage << "." << QwLog::endl;
1115
1116 fRunIsSegmented = kTRUE;
1117
1118 /* If the first requested segment hasn't been found,
1119 forget everything. */
1120 if ( local_segment < fSegmentRange.first ) {
1121 QwError << "First requested run segment "
1122 << fSegmentRange.first << " not found.\n";
1123 fRunSegments.pop_back();
1125 fRunIsSegmented = kTRUE; // well, it is true.
1126 }
1127 }
1128 }
1129 globfree(&globbuf);
1130 return fRunIsSegmented;
1131}
1132
1133//------------------------------------------------------------
1134
1136{
1137 Int_t status = kFileHandleNotConfigured;
1138 Int_t last_runsegment;
1139 if (fRunIsSegmented){
1140 last_runsegment = *fRunSegmentIterator;
1142 if (fRunSegmentIterator <= fRunSegments.end()){
1143 QwMessage << "Closing run segment " << last_runsegment <<"."
1144 << QwLog::endl;
1145 status = CloseDataFile();
1146 }
1147 } else {
1148 // Don't try to close a nonsegmented file; we will explicitly
1149 // use CloseDataFile() later.
1150 }
1151 return status;
1152}
1153
1154//------------------------------------------------------------
1155
1157{
1158 Int_t status;
1159 if (! fRunIsSegmented){
1160 /* We are processing a non-segmented run. *
1161 * We should not have entered this routine, but *
1162 * since we are here, don't do anything. */
1163 status = kRunNotSegmented;
1164
1165 } else if (fRunSegments.size()==0){
1166 /* There are actually no file segments located. *
1167 * Return "kNoNextDataFile", but don't print an *
1168 * error message. */
1169 status = kNoNextDataFile;
1170
1171 } else if (fRunSegmentIterator >= fRunSegments.begin() &&
1173 QwMessage << "Trying to open run segment " << *fRunSegmentIterator << QwLog::endl;
1175
1176 } else if (fRunSegmentIterator == fRunSegments.end() ) {
1177 /* We have reached the last run segment. */
1178 QwMessage << "There are no run segments remaining." << QwLog::endl;
1179 status = kNoNextDataFile;
1180
1181 } else {
1182 QwError << "QwEventBuffer::OpenNextSegment(): Unrecognized error" << QwLog::endl;
1183 status = CODA_ERROR;
1184 }
1185 return status;
1186}
1187
1188
1189//------------------------------------------------------------
1190//call this routine if we've selected the run segment by hand
1191Int_t QwEventBuffer::OpenDataFile(UInt_t current_run, Short_t seg)
1192{
1193 fCurrentRun = current_run;
1194
1195 fRunSegments.clear();
1196 fRunIsSegmented = kTRUE;
1197
1198 fRunSegments.push_back(seg);
1200 return OpenNextSegment();
1201}
1202
1203//------------------------------------------------------------
1204//call this routine if the run is not segmented
1205Int_t QwEventBuffer::OpenDataFile(UInt_t current_run, const TString rw)
1206{
1207 Int_t status;
1208 fCurrentRun = current_run;
1210 if (DataFileIsSegmented()){
1211 status = OpenNextSegment();
1212 } else {
1213 status = OpenDataFile(DataFile(fCurrentRun),rw);
1214 }
1215 return status;
1216}
1217
1218
1219
1220//------------------------------------------------------------
1221Int_t QwEventBuffer::OpenDataFile(const TString filename, const TString rw)
1222{
1224 QwDebug << "QwEventBuffer::OpenDataFile: File handle doesn't exist.\n"
1225 << " Try to open a new file handle!"
1226 << QwLog::endl;
1227 fEvStream = new THaCodaFile();
1229 } else if (fEvStreamMode!=fEvStreamFile){
1230 QwError << "QwEventBuffer::OpenDataFile: The stream is not configured as an input\n"
1231 << " file stream! Can't deal with this!\n"
1232 << QwLog::endl;
1233 exit(1);
1234 }
1235 fDataFile = filename;
1236
1237 if (rw.Contains("w",TString::kIgnoreCase)) {
1238 // If we open a file for write access, let's suppose
1239 // we've given the path we want to use.
1240 QwMessage << "Opening data file: " << fDataFile << QwLog::endl;
1241 } else {
1242 // Let's try to find the data file for read access.
1243 glob_t globbuf;
1244 glob(fDataFile.Data(), GLOB_ERR, NULL, &globbuf);
1245 if (globbuf.gl_pathc == 0){
1246 // Can't find the file; try in the "fDataDirectory".
1247 fDataFile = fDataDirectory + filename;
1248 glob(fDataFile.Data(), GLOB_ERR, NULL, &globbuf);
1249 }
1250 if (globbuf.gl_pathc == 0){
1251 // Can't find the file; try gzipped.
1252 fDataFile = filename + ".gz";
1253 glob(fDataFile.Data(), GLOB_ERR, NULL, &globbuf);
1254 }
1255 if (globbuf.gl_pathc == 0){
1256 // Can't find the file; try gzipped in the "fDataDirectory".
1257 fDataFile = fDataDirectory + filename + ".gz";
1258 glob(fDataFile.Data(), GLOB_ERR, NULL, &globbuf);
1259 }
1260 if (globbuf.gl_pathc == 1){
1261 QwMessage << "Opening data file: " << fDataFile << QwLog::endl;
1262 } else {
1263 fDataFile = filename;
1264 QwError << "Unable to find "
1265 << filename.Data() << " or "
1266 << (fDataDirectory + filename).Data() << QwLog::endl;
1267 }
1268 globfree(&globbuf);
1269 }
1270 return fEvStream->codaOpen(fDataFile, rw);
1271}
1272
1273
1274//------------------------------------------------------------
1276{
1277 Int_t status = kFileHandleNotConfigured;
1279 status = fEvStream->codaClose();
1280 }
1281 return status;
1282}
1283
1284//------------------------------------------------------------
1285Int_t QwEventBuffer::OpenETStream(TString computer, TString session, int mode,
1286 const TString stationname)
1287{
1288 Int_t status = CODA_OK;
1290#ifdef __CODA_ET
1291 if (stationname != ""){
1292 fEvStream = new THaEtClient(computer, session, mode, stationname.Data());
1293 } else {
1294 fEvStream = new THaEtClient(computer, session, mode);
1295 }
1297#endif
1298 }
1299 return status;
1300}
1301
1302//------------------------------------------------------------
1304{
1305 Int_t status = kFileHandleNotConfigured;
1307 status = fEvStream->codaClose();
1308 }
1309 return status;
1310}
1311
1312//------------------------------------------------------------
1314{
1315 QwDebug << "QwEventBuffer::GetMarkerWordList: start function" <<QwLog::endl;
1316 fThisRocBankLabel = decoder->GetROC();
1318 fThisRocBankLabel += decoder->GetSubbankTag();
1319 if (fMarkerList.count(fThisRocBankLabel)==0){
1320 std::vector<UInt_t> tmpvec;
1321 subsystems.GetMarkerWordList(decoder->GetROC(), decoder->GetSubbankTag(), tmpvec);
1322 fMarkerList.emplace(fThisRocBankLabel, tmpvec);
1323 fOffsetList.emplace(fThisRocBankLabel, std::vector<UInt_t>(tmpvec.size(),0));
1324 }
1325 QwDebug << "QwEventBuffer::GetMarkerWordList: fMarkerList.count(fThisRocBankLabel)=="
1327 << " fMarkerList.at(fThisRocBankLabel).size()=="
1328 << fMarkerList.at(fThisRocBankLabel).size()
1329 << QwLog::endl;
1330 return fMarkerList.at(fThisRocBankLabel).size();
1331}
1332
1333UInt_t QwEventBuffer::GetMarkerWord(UInt_t markerID){
1334 return fMarkerList.at(fThisRocBankLabel).at(markerID);
1335};
1336
1337
1338UInt_t QwEventBuffer::FindMarkerWord(UInt_t markerindex, UInt_t* buffer, UInt_t num_words){
1339 UInt_t markerpos = fOffsetList.at(fThisRocBankLabel).at(markerindex);
1340 UInt_t markerval = fMarkerList.at(fThisRocBankLabel).at(markerindex);
1341 if (markerpos < num_words && buffer[markerpos] == markerval){
1342 // The marker word is where it was last time
1343 return markerpos;
1344 } else {
1345 for (size_t i=0; i<num_words; i++){
1346 if (buffer[i] == markerval){
1347 fOffsetList.at(fThisRocBankLabel).at(markerindex) = i;
1348 markerpos = i;
1349 break;
1350 }
1351 }
1352 }
1353 return markerpos;
1354}
Array container for managing multiple subsystems.
Definition of the pure virtual base class of all subsystems.
Event buffer management for reading and processing CODA data.
EPICS data event handling and storage.
#define QwVerbose
Predefined log drain for verbose messages.
Definition QwLog.h:54
#define QwError
Predefined log drain for errors.
Definition QwLog.h:39
#define QwWarning
Predefined log drain for warnings.
Definition QwLog.h:44
#define QwMessage
Predefined log drain for regular messages.
Definition QwLog.h:49
#define QwDebug
Predefined log drain for debugging output.
Definition QwLog.h:59
ULong64_t BankID_t
Definition QwTypes.h:21
An options class which parses command line, config file and environment.
void sigint_handler(int sig)
Bool_t onlineRestart
void sigusr_handler(int sig)
Bool_t globalEXIT
CODA version 2 event decoder implementation.
CODA version 3 event decoder implementation.
EPICS slow controls data management.
void ExtractEPICSValues(const string &data, int event)
TString GetRunLabel() const
Returns a string like <run#> or <run#>.<file#>
Int_t EncodeSubsystemData(QwSubsystemArray &subsystems)
TString fETHostname
static const Int_t kRunNotSegmented
Int_t EncodeGoEvent()
TString GetEndSQLTime()
time_t GetStartUnixTime()
TString fDataDirectory
Int_t EncodePauseEvent()
UInt_t fStartingPhysicsEvent
Int_t GetEventNumber()
Int_t CloseThisSegment()
void ReportRunSummary()
static std::string fDefaultDataDirectory
Int_t EncodeEndEvent()
Bool_t fChainDataFiles
std::unordered_map< RocBankLabel_t, std::vector< UInt_t > > fMarkerList
enum QwEventBuffer::CodaStreamMode fEvStreamMode
Int_t CloseStream()
Closes a currently open event stream.
Int_t WriteEtEvent(int *buffer)
Bool_t IsEPICSEvent()
Int_t OpenETStream(TString computer, TString session, int mode, const TString stationname="")
Bool_t fRunIsSegmented
Bool_t GetNextRunRange()
Read the next requested run range, return true if success.
Int_t EncodePrestartEvent(int runnumber, int runtype=0)
QwEventBuffer()
Default constructor.
void VerifyCodaVersion(const UInt_t *buffer)
Int_t WriteFileEvent(int *buffer)
Int_t OpenNextStream()
Opens the event stream (file or ET) based on the internal flags.
static const Int_t kFileHandleNotConfigured
std::vector< Int_t >::iterator fRunSegmentIterator
std::chrono::duration< double > fAccumulatedDelay
void ProcessOptions(QwOptions &options)
Sets internal flags based on the QwOptions.
Bool_t FillSubsystemData(QwSubsystemArray &subsystems)
VEventDecoder * decoder
TStopwatch fStopwatch
Timer used for internal timing.
Int_t WriteEvent(int *buffer)
Int_t GetSegmentNumber() const
Return CODA file segment number.
std::unique_ptr< QwParameterFile > fEventListFile
void ResetControlParameters()
const TString & DataFile(const UInt_t run, const Short_t seg)
TString GetStartSQLTime()
TString fETStationName
Bool_t fEventRateLimitEnabled
static void DefineOptions(QwOptions &options)
std::unordered_map< RocBankLabel_t, std::vector< UInt_t > > fOffsetList
Double_t fCleanParameter[3]
Scan data/clean data from the green monster.
UInt_t FindMarkerWord(UInt_t markerID, UInt_t *buffer, UInt_t num_words)
TString fDataFileExtension
Int_t GetRunNumber() const
Return CODA file run number.
static const UInt_t kNullDataWord
static const Int_t kNoNextDataFile
RocBankLabel_t fThisRocBankLabel
Double_t fMaxEventRate
Bool_t GetNextEventRange()
Read the next requested event range, return true if success.
Bool_t DataFileIsSegmented()
std::pair< Int_t, Int_t > fRunRange
std::pair< UInt_t, UInt_t > fEventRange
Int_t OpenDataFile(UInt_t current_run, Short_t seg)
static std::string fDefaultDataFileExtension
std::string fRunListFileName
Int_t OpenNextSegment()
UInt_t fNumPhysicsEvents
TStopwatch fRunTimer
Timer used for runlet processing loop.
time_t GetEndUnixTime()
static std::string fDefaultDataFileStem
Bool_t GetNextRunNumber()
Get the next run in the active run range, proceed to next range if needed.
std::chrono::duration< double > fMinEventInterval
Bool_t IsPhysicsEvent()
Bool_t FillEPICSData(QwEPICSEvent &epics)
THaCodaData * fEvStream
std::pair< Int_t, Int_t > fSegmentRange
std::unique_ptr< QwParameterFile > fRunListFile
std::size_t CheckForMarkerWords(QwSubsystemArray &subsystems)
std::chrono::steady_clock::time_point fLastEventTime
std::vector< Int_t > fRunSegments
Bool_t FillSubsystemConfigurationData(QwSubsystemArray &subsystems)
TString fDataFileStem
Int_t fDataVersionVerify
UInt_t GetMarkerWord(UInt_t markerID)
static std::ostream & endl(std::ostream &)
End of the line.
Definition QwLog.cc:297
Command-line and configuration file options processor.
Definition QwOptions.h:141
std::pair< int, int > GetIntValuePair(const std::string &key)
Get a pair of integer values.
Definition QwOptions.cc:357
po::options_description_easy_init AddDefaultOptions()
Add a default option.
Definition QwOptions.h:165
T GetValue(const std::string &key)
Get a templated value.
Definition QwOptions.h:236
bool HasValue(const std::string &key)
Has this key been defined.
Definition QwOptions.h:229
po::options_description_easy_init AddOptions(const std::string &blockname="Specialized options")
Add an option to a named block or create new block.
Definition QwOptions.h:170
static std::pair< int, int > ParseIntRange(const std::string &separatorchars, const std::string &range)
Parse a range of integers as #:# where either can be missing.
Container for managing multiple subsystems with common operations.
void SetCodaRunNumber(UInt_t runnum)
Set the internal record of the CODA run number.
void SetCleanParameters(Double_t cleanparameter[3])
Set the internal record of the CODA event number.
UInt_t GetEventTypeMask() const
Get event type mask.
void GetMarkerWordList(const ROCID_t roc_id, const BankID_t bank_id, std::vector< UInt_t > &marker) const
void EncodeEventData(std::vector< UInt_t > &buffer)
Encode the data in this event.
void SetCodaSegmentNumber(UInt_t segnum)
Set the internal record of the CODA segment number.
Int_t ProcessEvBuffer(const UInt_t event_type, const ROCID_t roc_id, const BankID_t bank_id, UInt_t *buffer, UInt_t num_words)
Process the event buffer for events.
void SetCodaEventNumber(UInt_t evtnum)
Set the internal record of the CODA event number.
void SetCodaEventType(UInt_t evttype)
Set the internal record of the CODA event type.
Int_t ProcessConfigurationBuffer(const ROCID_t roc_id, const BankID_t bank_id, UInt_t *buffer, UInt_t num_words)
Process the event buffer for configuration events.
void GetROCIDList(std::vector< ROCID_t > &list)
Get the ROCID list.