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}
An options class which parses command line, config file and environment.
Array container for managing multiple subsystems.
ULong64_t BankID_t
Definition QwTypes.h:21
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
Definition of the pure virtual base class of all subsystems.
Event buffer management for reading and processing CODA data.
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.
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.