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