LDMX Software
EventBuilder.cxx
1#include "EventBuilder/EventBuilder.h"
2
3#include <iostream>
4#include <fstream>
5#include <iomanip>
6#include <vector>
7#include <cstdint>
8#include <cstring>
9#include <set>
10#include <algorithm>
11#include <chrono>
12#include "Framework/Logger.h"
13
14#include "EventBuilder/Fragment.h"
15#include "EventBuilder/Event/PhysicsEventData.h"
16#include "EventBuilder/Event/GenericDataBlock.h"
18#include "Packing/LDMXRoRHeader.h"
19#include "Packing/RogueFrameHeader.h"
20#include "Packing/RawDataFile/SubsystemPacket.h"
21
22using namespace eventbuilder;
23
24// Global flag to track if performance CSV header has been written
25static bool g_perf_csv_header_written = false;
26
27// Helper function to write performance metrics to CSV
28void write_performance_metric(
29 unsigned int event_id,
30 double build_time_ms,
31 double cum_events_per_sec,
32 double cum_mb_per_sec,
33 double window_events_per_sec,
34 double window_mb_per_sec,
35 uint64_t total_events,
36 uint64_t total_bytes) {
37
38 std::ofstream perf_csv("event_performance.csv", std::ios::app);
39 if (!perf_csv) return;
40
41 // Write header on first call
42 if (!g_perf_csv_header_written) {
43 perf_csv << "event_id,event_build_time_ms,cum_events_per_sec,cum_mb_per_sec,"
44 << "window_events_per_sec,window_mb_per_sec,total_events,total_bytes_mb\n";
45 g_perf_csv_header_written = true;
46 }
47
48 // Write data with consistent formatting
49 double total_mb = total_bytes / (1024.0 * 1024.0);
50 perf_csv << event_id << ","
51 << std::fixed << std::setprecision(3) << build_time_ms << ","
52 << std::fixed << std::setprecision(2) << cum_events_per_sec << ","
53 << std::fixed << std::setprecision(3) << cum_mb_per_sec << ","
54 << std::fixed << std::setprecision(2) << window_events_per_sec << ","
55 << std::fixed << std::setprecision(3) << window_mb_per_sec << ","
56 << total_events << ","
57 << std::fixed << std::setprecision(2) << total_mb << "\n";
58 perf_csv.flush();
59}
60
62 if (ps.exists("verbose_parse")) {
63 m_verbose_parse = ps.get<bool>("verbose_parse");
64 }
65 if (ps.exists("dat_file")) {
66 m_input_file = ps.get<std::string>("dat_file");
67 } else {
68 const char* env_input = std::getenv("EVENTBUILDER_INPUT");
69 if (env_input) m_input_file = env_input;
70 }
71 if (ps.exists("output_name")) m_output_name = ps.get<std::string>("output_name");
72 if (ps.exists("coherence_window_ns")) {
73 m_coherence_window_ns = ps.get<double>("coherence_window_ns");
74 }
75 if (ps.exists("min_subsystems")) {
76 m_min_subsystems = ps.get<int>("min_subsystems");
77 }
78
79 ldmx_log(info) << "configure(): dat_file='" << m_input_file << "' output_name='" << m_output_name
80 << "' verbose_parse=" << (m_verbose_parse?"true":"false")
81 << " coherence_window_ns=" << m_coherence_window_ns
82 << " min_subsystems=" << m_min_subsystems;
83
84 if (!m_input_file.empty()) {
85 ldmx_log(info) << "configure(): opening file '" << m_input_file << "'";
86 m_reader.open(m_input_file);
87 if (!m_reader) {
88 ldmx_log(error) << "failed to open input file: '" << m_input_file << "'";
89 } else {
90 ldmx_log(info) << "configure(): file opened successfully";
91 }
92 } else {
93 ldmx_log(error) << "no input file specified";
94 }
95
96 // Initialize performance tracking
97 m_start_time = std::chrono::steady_clock::now();
98 m_total_bytes_read = 0;
99 m_total_events_built = 0;
100 m_events_since_last_report = 0;
101
102 // Initialize windowed metrics for real-time DAQ monitoring
103 m_window_start_time = m_start_time;
104 m_window_events_count = 0;
105 m_window_bytes_read = 0;
106}
107
109 static int produce_call_count = 0;
110 produce_call_count++;
111 ldmx_log(debug) << "produce() called, count=" << produce_call_count;
112 ldmx_log(debug) << "verbose_parse=" << (m_verbose_parse ? "true" : "false");
113 if (m_verbose_parse || produce_call_count <= 3) {
114 ldmx_log(info) << "produce() call #" << produce_call_count;
115 }
116
117 // Start timing for this event
118 m_event_start_time = std::chrono::steady_clock::now();
119
120 // Track errors encountered during event assembly
121 uint32_t current_event_errors = 0;
122
123 while (m_reader && !m_reader.eof()) {
124 // Try to read a RogueFrameHeader
125 packing::RogueFrameHeader frame_header;
126 frame_header.read(m_reader);
127
128 // Store location of end-of-frame for potential recovery
129 const long long frame_end =
130 static_cast<long long>(m_reader.tell()) + frame_header.size();
131
132 // Check if this is a data frame (channel 0) and not YAML
133 if (frame_header.channel() != 0 || frame_header.probablyYaml()) {
134 // Skip this frame
135 if (m_verbose_parse) ldmx_log(debug) << "skipping non-data frame (channel=" << frame_header.channel() << ")";
136 m_reader.seek(frame_end);
137 continue;
138 }
139
140 // We have a valid data frame - try to parse it
141 DataFragment fragment{{}, {}, {.checksum = 0}};
142 bool parsed_ok = false;
143
144 // Try RoR format first
145 packing::LDMXRoRHeader ror_header;
146 int pos_before_ror = m_reader.tell();
147
148 // Attempt to read as RoR header
149 try {
150 ror_header.read(m_reader);
151 // Successfully parsed RoR header
152 fragment.header.subsystem_id = static_cast<uint64_t>(ror_header.subsystem());
153 fragment.header.contributor_id = static_cast<uint64_t>(ror_header.contributor());
154 fragment.header.timestamp = ror_header.timestamp();
155
156 if (m_verbose_parse) {
157 ldmx_log(debug) << "parsed RoR header subsys=" << (int)ror_header.subsystem()
158 << " contrib=" << (int)ror_header.contributor()
159 << " ts=" << ror_header.timestamp();
160 }
161
162 // Read remaining frame payload after RoR header
163 std::vector<uint8_t> payload_data;
164 long long payload_size = frame_end - m_reader.tell();
165 if (payload_size > 0) {
166 payload_data.resize(payload_size);
167 m_reader.read(reinterpret_cast<char*>(payload_data.data()), payload_size);
168 }
169 fragment.payload = std::move(payload_data);
170 parsed_ok = true;
171 } catch (...) {
172 // RoR parse failed, try packing subsystem format
173 if (m_verbose_parse) ldmx_log(debug) << "RoR header parse failed, trying packing subsystem format";
174 current_event_errors |= ldmx::EventSummary::ERROR_PARSE_FAILURE;
175 m_reader.seek(pos_before_ror);
176 }
177
178 if (!parsed_ok) {
179 // Try packing subsystem format
181 try {
182 pkt.read(m_reader);
183 fragment.header.subsystem_id = static_cast<uint64_t>(pkt.id());
184 fragment.header.contributor_id = 0; // Not available in packing subsystem format
185 fragment.header.timestamp = static_cast<uint64_t>(pkt.header()[1]) * 1000000000ULL; // event number to ns
186
187 // Convert packet data to payload bytes
188 const auto& data = pkt.data();
189 fragment.payload.resize(data.size() * 4);
190 std::memcpy(fragment.payload.data(), reinterpret_cast<const char*>(data.data()), data.size() * 4);
191
192 if (m_verbose_parse) {
193 ldmx_log(debug) << "parsed packing subsystem pkt subsys=" << pkt.id()
194 << " data_size=" << data.size();
195 }
196 parsed_ok = true;
197 } catch (...) {
198 // Both parse attempts failed, skip this frame
199 if (m_verbose_parse) ldmx_log(debug) << "failed to parse as either format, skipping frame";
200 current_event_errors |= ldmx::EventSummary::ERROR_PARSE_FAILURE;
201 m_reader.seek(frame_end);
202 continue;
203 }
204 }
205
206 if (!parsed_ok) {
207 m_reader.seek(frame_end);
208 continue;
209 }
210
211 if (m_verbose_parse) ldmx_log(debug) << "adding fragment subsys=" << fragment.header.subsystem_id
212 << " ts=" << fragment.header.timestamp << " bytes=" << fragment.payload.size();
213
214 // Check if this fragment is outside the coherence window of the current event batch
215 // If so, it means we should finalize the previous event before adding this one
216 long long fragment_ts = fragment.header.timestamp;
217 long long buffer_ref_time = m_event_buffer.get_reference_time();
218
219 if (buffer_ref_time > 0 && (fragment_ts < buffer_ref_time - m_coherence_window_ns ||
220 fragment_ts > buffer_ref_time + m_coherence_window_ns)) {
221 // This fragment is outside the current window - try to build the previous event
222 std::vector<DataFragment> assembled_event_fragments;
223 if (m_event_buffer.try_build_event(m_coherence_window_ns, m_min_subsystems, assembled_event_fragments) &&
224 !assembled_event_fragments.empty()) {
225 // Output the complete event and return
226 ++m_event_id;
227 // Add each subsystem's raw data as vector<uint8_t> directly
228 uint64_t event_timestamp = 0;
229 for (const auto &frag : assembled_event_fragments) {
230 std::string subsys_name = packing::LDMXRoRHeader::getSubsystemName(
231 static_cast<uint8_t>(frag.header.subsystem_id),
232 static_cast<uint8_t>(frag.header.contributor_id));
233 std::vector<uint8_t> payload_bytes(frag.payload.begin(), frag.payload.end());
234 event.add(subsys_name, payload_bytes);
235 if (event_timestamp == 0) {
236 event_timestamp = frag.header.timestamp;
237 }
238 }
239 event.getEventHeader().setIntParameter("RoR Timestamp", static_cast<long long>(event_timestamp));
240 // Still create PhysicsEventData for binary output file
241 PhysicsEventData final_event = assemble_payload(assembled_event_fragments);
242 write_event_binary(final_event, "events.bin");
243 ldmx_log(info) << "assembled event id=" << m_event_id << " timestamp=" << final_event.timestamp
244 << " fragments=" << assembled_event_fragments.size() << " systems=" << final_event.systems_readout.size();
245
246 ldmx::EventSummary summary;
247 summary.setEventNumber(m_event_id);
248 summary.setTimestampNs(static_cast<uint64_t>(final_event.timestamp));
249 std::set<uint64_t> unique_sys;
250 uint64_t total_payload = 0;
251 for (const auto &f : assembled_event_fragments) {
252 unique_sys.insert(f.header.subsystem_id);
253 total_payload += f.payload.size();
254 }
255 // Check for duplicate subsystems
256 if (unique_sys.size() != assembled_event_fragments.size()) {
257 current_event_errors |= ldmx::EventSummary::ERROR_DUPLICATE_SUBSYSTEM;
258 }
259 summary.setNSystems(static_cast<uint32_t>(unique_sys.size()));
260 summary.setSystemIds(std::vector<uint64_t>(unique_sys.begin(), unique_sys.end()));
261 summary.setPayloadSize(total_payload);
262 summary.setErrorFlags(current_event_errors);
263 event.add("EventSummary", summary);
264
265 // Update performance metrics
266 m_total_bytes_read += total_payload;
267 m_total_events_built++;
268 m_events_since_last_report++;
269 std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
270 std::chrono::milliseconds event_build_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_event_start_time);
271 std::chrono::seconds total_elapsed_s = std::chrono::duration_cast<std::chrono::seconds>(now - m_start_time);
272
273 double events_per_sec = (total_elapsed_s.count() > 0) ? static_cast<double>(m_total_events_built) / total_elapsed_s.count() : 0.0;
274 double mb_per_sec = (total_elapsed_s.count() > 0) ? static_cast<double>(m_total_bytes_read) / (1024.0 * 1024.0) / total_elapsed_s.count() : 0.0;
275
276 // Update windowed metrics
277 m_window_events_count++;
278 m_window_bytes_read += total_payload;
279 std::chrono::seconds window_elapsed_s = std::chrono::duration_cast<std::chrono::seconds>(now - m_window_start_time);
280
281 // Reset window if we've processed WINDOW_SIZE events
282 double window_events_per_sec = 0.0;
283 double window_mb_per_sec = 0.0;
284 if (m_window_events_count >= WINDOW_SIZE) {
285 double window_time_sec = std::max(1.0, static_cast<double>(window_elapsed_s.count()));
286 window_events_per_sec = static_cast<double>(m_window_events_count) / window_time_sec;
287 window_mb_per_sec = static_cast<double>(m_window_bytes_read) / (1024.0 * 1024.0) / window_time_sec;
288
289 // Reset window
290 m_window_start_time = now;
291 m_window_events_count = 0;
292 m_window_bytes_read = 0;
293 }
294
295 // Write performance metrics to CSV
296 long long event_build_time_ms_val = event_build_time_ms.count();
297 write_performance_metric(m_event_id, static_cast<double>(event_build_time_ms_val),
298 events_per_sec, mb_per_sec,
299 window_events_per_sec, window_mb_per_sec,
300 m_total_events_built, m_total_bytes_read);
301
302 if (m_verbose_parse || m_events_since_last_report % 100 == 0) {
303 ldmx_log(info) << "Performance: "
304 << "total_events=" << m_total_events_built << ", "
305 << "events_per_sec=" << std::fixed << std::setprecision(2) << events_per_sec << ", "
306 << "mb_per_sec=" << std::fixed << std::setprecision(3) << mb_per_sec;
307 }
308
309 current_event_errors = 0; // Reset for next event
310 // The fragment that tripped the window-close belongs to the NEXT
311 // event, not the one we just emitted. Buffer it here (the buffer is
312 // empty post-build, so this also resets the reference time) instead
313 // of dropping it -- otherwise every event after the first loses its
314 // triggering subsystem.
315 m_event_buffer.add_fragment(std::move(fragment));
316 return; // Return the event to framework
317 }
318 }
319
320 // Add fragment to buffer (may start a new event batch if buffer was empty)
321 m_event_buffer.add_fragment(std::move(fragment));
322
323 if (m_verbose_parse) ldmx_log(debug) << "frame added to buffer, searching for more frames...";
324 }
325
326 // Reached EOF - flush any remaining events in the buffer
327 if (m_verbose_parse) ldmx_log(debug) << "reached EOF, flushing remaining events";
328
329 std::vector<DataFragment> assembled_event_fragments;
330 while (m_event_buffer.try_build_event(m_coherence_window_ns, m_min_subsystems, assembled_event_fragments)) {
331 if (assembled_event_fragments.empty()) break;
332
333 // Mark truncated events (those flushed at EOF)
334 current_event_errors |= ldmx::EventSummary::ERROR_TRUNCATED_EVENT;
335
336 ++m_event_id;
337 // Add each subsystem's raw data as vector<uint8_t> directly
338 uint64_t event_timestamp = 0;
339 for (const auto &frag : assembled_event_fragments) {
340 std::string subsys_name = packing::LDMXRoRHeader::getSubsystemName(
341 static_cast<uint8_t>(frag.header.subsystem_id),
342 static_cast<uint8_t>(frag.header.contributor_id));
343 std::vector<uint8_t> payload_bytes(frag.payload.begin(), frag.payload.end());
344 event.add(subsys_name, payload_bytes);
345 if (event_timestamp == 0) {
346 event_timestamp = frag.header.timestamp;
347 }
348 }
349 event.getEventHeader().setIntParameter("RoR Timestamp", static_cast<long long>(event_timestamp));
350 // Still create PhysicsEventData for binary output file
351 PhysicsEventData final_event = assemble_payload(assembled_event_fragments);
352 write_event_binary(final_event, "events.bin");
353 ldmx_log(info) << "assembled event id=" << m_event_id << " timestamp=" << final_event.timestamp
354 << " fragments=" << assembled_event_fragments.size() << " systems=" << final_event.systems_readout.size();
355
356 ldmx::EventSummary summary;
357 summary.setEventNumber(m_event_id);
358 summary.setTimestampNs(static_cast<uint64_t>(final_event.timestamp));
359 std::set<uint64_t> unique_sys;
360 uint64_t total_payload = 0;
361 for (const auto &f : assembled_event_fragments) {
362 unique_sys.insert(f.header.subsystem_id);
363 total_payload += f.payload.size();
364 }
365 // Check for duplicate subsystems
366 if (unique_sys.size() != assembled_event_fragments.size()) {
367 current_event_errors |= ldmx::EventSummary::ERROR_DUPLICATE_SUBSYSTEM;
368 }
369 summary.setNSystems(static_cast<uint32_t>(unique_sys.size()));
370 summary.setSystemIds(std::vector<uint64_t>(unique_sys.begin(), unique_sys.end()));
371 summary.setPayloadSize(total_payload);
372 summary.setErrorFlags(current_event_errors);
373 event.add("EventSummary", summary);
374
375 // Update performance metrics
376 m_total_bytes_read += total_payload;
377 m_total_events_built++;
378 m_events_since_last_report++;
379 std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
380 std::chrono::milliseconds event_build_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_event_start_time);
381 std::chrono::seconds total_elapsed_s = std::chrono::duration_cast<std::chrono::seconds>(now - m_start_time);
382
383 double events_per_sec = (total_elapsed_s.count() > 0) ? static_cast<double>(m_total_events_built) / total_elapsed_s.count() : 0.0;
384 double mb_per_sec = (total_elapsed_s.count() > 0) ? static_cast<double>(m_total_bytes_read) / (1024.0 * 1024.0) / total_elapsed_s.count() : 0.0;
385
386 // Update windowed metrics
387 m_window_events_count++;
388 m_window_bytes_read += total_payload;
389 std::chrono::seconds window_elapsed_s = std::chrono::duration_cast<std::chrono::seconds>(now - m_window_start_time);
390
391 // Calculate window metrics (for final event, may not have full window)
392 double window_events_per_sec = 0.0;
393 double window_mb_per_sec = 0.0;
394 if (m_window_events_count >= WINDOW_SIZE || window_elapsed_s.count() > 0) {
395 double window_time_sec = std::max(1.0, static_cast<double>(window_elapsed_s.count()));
396 window_events_per_sec = static_cast<double>(m_window_events_count) / window_time_sec;
397 window_mb_per_sec = static_cast<double>(m_window_bytes_read) / (1024.0 * 1024.0) / window_time_sec;
398 }
399
400 // Write performance metrics to CSV
401 long long event_build_time_ms_val = event_build_time_ms.count();
402 write_performance_metric(m_event_id, static_cast<double>(event_build_time_ms_val),
403 events_per_sec, mb_per_sec,
404 window_events_per_sec, window_mb_per_sec,
405 m_total_events_built, m_total_bytes_read);
406
407 if (m_verbose_parse || m_events_since_last_report % 100 == 0) {
408 ldmx_log(info) << "Performance: "
409 << "total_events=" << m_total_events_built << ", "
410 << "events_per_sec=" << std::fixed << std::setprecision(2) << events_per_sec << ", "
411 << "mb_per_sec=" << std::fixed << std::setprecision(3) << mb_per_sec;
412 }
413
414 current_event_errors = 0; // Reset for next event
415
416 assembled_event_fragments.clear();
417 return;
418 }
419
420 // No more events - print final summary statistics
421 std::chrono::steady_clock::time_point final_time = std::chrono::steady_clock::now();
422 std::chrono::seconds total_time_s = std::chrono::duration_cast<std::chrono::seconds>(final_time - m_start_time);
423 double final_events_per_sec = (total_time_s.count() > 0) ? static_cast<double>(m_total_events_built) / total_time_s.count() : 0.0;
424 double final_mb_per_sec = (total_time_s.count() > 0) ? static_cast<double>(m_total_bytes_read) / (1024.0 * 1024.0) / total_time_s.count() : 0.0;
425
426 ldmx_log(info) << "\n===== FINAL STATISTICS =====";
427 ldmx_log(info) << "Total events built: " << m_total_events_built;
428 ldmx_log(info) << "Total bytes read: " << m_total_bytes_read / (1024.0 * 1024.0) << " MB";
429 ldmx_log(info) << "Total time: " << total_time_s.count() << " seconds";
430 ldmx_log(info) << "Average throughput: "
431 << "events_per_sec=" << std::fixed << std::setprecision(2) << final_events_per_sec << ", "
432 << "mb_per_sec=" << std::fixed << std::setprecision(3) << final_mb_per_sec;
433 ldmx_log(info) << "=============================\n";
434 ldmx_log(info) << "Event building complete";
435
436 abortEvent();
437}
438
439PhysicsEventData EventBuilder::assemble_payload(const std::vector<DataFragment>& fragments) {
440 PhysicsEventData event_data;
441 if (fragments.empty()) return event_data;
442 event_data.event_id = m_event_id;
443 event_data.timestamp = fragments.front().header.timestamp;
444 for (const auto &fragment : fragments) {
446 g.subsystem_id = fragment.header.subsystem_id;
447 g.timestamp_ns = fragment.header.timestamp;
448 g.data = fragment.payload;
449 if (fragment.trailer.checksum != 0) g.checksum = fragment.trailer.checksum;
450 else g.checksum = crc32(fragment.payload);
451 event_data.blocks.push_back(std::move(g));
452 event_data.systems_readout.push_back(fragment.header.subsystem_id);
453 }
454 return event_data;
455}
456
457void EventBuilder::write_event_binary(const PhysicsEventData &ev, const std::string &path) {
458 static std::mutex g_out_mutex;
459 std::lock_guard<std::mutex> lg(g_out_mutex);
460 std::ofstream ofs(path, std::ios::binary | std::ios::app);
461 if (!ofs) return;
462 uint64_t event_id_u = static_cast<uint64_t>(ev.event_id);
463 uint64_t ts = static_cast<uint64_t>(ev.timestamp);
464 uint32_t nblocks = static_cast<uint32_t>(ev.blocks.size());
465 ofs.write(reinterpret_cast<const char*>(&event_id_u), sizeof(event_id_u));
466 ofs.write(reinterpret_cast<const char*>(&ts), sizeof(ts));
467 ofs.write(reinterpret_cast<const char*>(&nblocks), sizeof(nblocks));
468 for (const auto &b : ev.blocks) {
469 uint64_t sid = b.subsystem_id;
470 uint64_t bts = b.timestamp_ns;
471 uint32_t psz = static_cast<uint32_t>(b.data.size());
472 uint32_t csum = b.checksum;
473 ofs.write(reinterpret_cast<const char*>(&sid), sizeof(sid));
474 ofs.write(reinterpret_cast<const char*>(&bts), sizeof(bts));
475 ofs.write(reinterpret_cast<const char*>(&psz), sizeof(psz));
476 ofs.write(reinterpret_cast<const char*>(&csum), sizeof(csum));
477 if (psz) ofs.write(reinterpret_cast<const char*>(b.data.data()), static_cast<std::streamsize>(psz));
478 }
479 ofs.flush();
480}
481
482// Register producer with the framework factory
#define DECLARE_PRODUCER(CLASS)
Macro which allows the framework to construct a producer given its name during configuration.
Class that provides a summary of event assembly with metadata and error flags.
void produce(framework::Event &event) override
Process the event and put new data products into it.
void configure(framework::config::Parameters &ps) override
Callback for the EventProcessor to configure itself from the given set of parameters.
void abortEvent()
Abort the event immediately.
Implements an event buffer system for storing event data.
Definition Event.h:42
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:29
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:78
bool exists(const std::string &name) const
Check to see if a parameter exists.
Definition Parameters.h:63
Provides summary information about an assembled event, including error flags for data quality assessm...
void setSystemIds(const std::vector< uint64_t > &ids)
Set the system IDs.
void setNSystems(uint32_t ns)
Set the number of systems in this event.
void setPayloadSize(uint64_t size)
Set the total payload size.
void setTimestampNs(uint64_t ts)
Set the timestamp in nanoseconds.
void setEventNumber(uint64_t num)
Set the event number.
void setErrorFlags(uint32_t flags)
Set the error flags.
@ ERROR_PARSE_FAILURE
Frame parsing error.
@ ERROR_DUPLICATE_SUBSYSTEM
Duplicate subsystem in single event.
@ ERROR_TRUNCATED_EVENT
Event was truncated (EOF reached)
the header that the LDMX DAQ Firmware block includes in the output data stream at the beginning of ea...
static std::tuple< int, int > subsystem(const std::string &name)
Get the (subsystem, contributor) pair for the input subsystem name.
uint8_t contributor() const
ID number for contributor within subsystem (configured into firmware)
static std::string getSubsystemName(uint8_t subsystem_id, uint8_t contributor_id)
Get the subsystem name from subsystem and contributor IDs.
uint64_t timestamp() const
get timestamp of this RoR
utility::Reader & read(utility::Reader &r)
read the next LDMX RoR header into memory
the header that the Rogue StreamWriter puts includes at the beginning of each frame.
unsigned int size() const
get the size of the frame not including this header
bool probablyYaml() const
check if this frame is probably a yaml dump
int channel() const
get the channel this data was written to
utility::Reader & read(utility::Reader &r)
read the next rogue frame header into memory
std::vector< uint32_t > & data()
Get data.
utility::Reader & read(utility::Reader &r)
read the subsystem packet from the input reader
std::vector< uint32_t > header() const
get the header words
std::streampos tell()
Tell us where the reader is.
Definition Reader.h:88
void open(const std::string &file_name)
Open a file with this reader.
Definition Reader.h:36
bool eof()
check if file is done
Definition Reader.h:217
void seek(std::streampos off, std::ios_base::seekdir dir=std::ios::beg)
Go ("seek") a specific position in the file.
Definition Reader.h:62
Reader & read(WordType *w, std::size_t count)
Read the next 'count' words into the input handle.
Definition Reader.h:114