GRSISort "v4.0.0.5"
An extension of the ROOT analysis Framework
Loading...
Searching...
No Matches
TMidasEvent.cxx
Go to the documentation of this file.
1//
2// TMidasEvent.cxx.
3//
4// $Id: TMidasEvent.cxx 91 2012-04-12 18:36:17Z olchansk $
5//
6
7#include <cstdio>
8#include <cstdlib>
9#include <ctime>
10#include <cstring>
11#include <cassert>
12#include <sstream>
13
14#include "TMidasEvent.h"
15#include "TGRSIOptions.h"
16#include "TRunInfo.h"
17#include "TXMLOdb.h"
18
20 : fData(nullptr), fBanksN(0), fBankList(nullptr), fAllocatedByUs(false)
21{
22 // Default constructor
28}
29
30void TMidasEvent::Copy(TObject& rhs) const
31{
32 // Copies the entire TMidasEvent. This includes the bank information.
33 static_cast<TMidasEvent&>(rhs).fEventHeader = fEventHeader;
34
35 static_cast<TMidasEvent&>(rhs).fData = static_cast<char*>(malloc(static_cast<TMidasEvent&>(rhs).fEventHeader.fDataSize)); // NOLINT(cppcoreguidelines-no-malloc)
36 assert(static_cast<TMidasEvent&>(rhs).fData);
37 memcpy(static_cast<TMidasEvent&>(rhs).fData, fData, static_cast<TMidasEvent&>(rhs).fEventHeader.fDataSize);
38 static_cast<TMidasEvent&>(rhs).fAllocatedByUs = true;
39
40 static_cast<TMidasEvent&>(rhs).fBanksN = fBanksN;
41 static_cast<TMidasEvent&>(rhs).fBankList = nullptr;
42 // if(fBankList) static_cast<TMidasEvent&>(rhs).fBankList = strdup(fBankList);
43 // assert(static_cast<TMidasEvent&>(rhs).fBankList);
44}
45
47{
48 // Copy ctor.
49 rhs.Copy(*this);
50}
51
56
58{
59 if(&rhs != this) {
60 Clear();
61 }
62
63 rhs.Copy(*this);
64 return *this;
65}
66
67void TMidasEvent::Clear(Option_t*)
68{
69 // Clears the TMidasEvent.
70 delete fBankList;
71 fBankList = nullptr;
72
73 if(fAllocatedByUs) {
74 delete fData;
75 }
76 fData = nullptr;
77
78 fAllocatedByUs = false;
79 fBanksN = 0;
80
86
88}
89
90void TMidasEvent::SetData(uint32_t size, char* data)
91{
92 // Sets the data in the TMidasEvent as the data argument passed into
93 // this function.
95 assert(!fAllocatedByUs);
96 assert(IsGoodSize());
97 fData = data;
98 fAllocatedByUs = false;
99 SwapBytes(false);
100}
101
103{
104 return fEventHeader.fEventId;
105}
106
108{
110}
111
113{
115}
116
118{
120}
121
123{
124 return fEventHeader.fDataSize;
125}
126
128{
129 // Allocates the data if it has not been already, and then
130 // returns the allocated data.
131 if(fData == nullptr) {
132 AllocateData();
133 }
134 return fData;
135}
136
141
143{
144 return fEventHeader.fDataSize > 0 && fEventHeader.fDataSize <= 500 * 1024 * 1024;
145}
146
148{
149 return ((reinterpret_cast<TMidas_BANK_HEADER*>(fData))->fFlags & (1 << 4)) != 0u;
150}
151
152int TMidasEvent::LocateBank(const void*, const char* name, void** pdata) const
153{
154 /// See FindBank()
155
156 int bktype = 0;
157 int bklen = 0;
158
159 int status = FindBank(name, &bklen, &bktype, pdata);
160
161 if(status == 0) {
162 *pdata = nullptr;
163 return 0;
164 }
165
166 return bklen;
167}
168
169/// Find a data bank.
170/// \param [in] name Name of the data bank to look for.
171/// \param [out] bklen Number of array elements in this bank.
172/// \param [out] bktype Bank data type (MIDAS TID_xxx).
173/// \param [out] pdata Pointer to bank data, Returns nullptr if bank not found.
174/// \returns 1 if bank found, 0 otherwise.
175///
176int TMidasEvent::FindBank(const char* name, int* bklen, int* bktype, void** pdata) const
177{
178 auto* pbkh = reinterpret_cast<TMidas_BANK_HEADER*>(fData);
179 TMidas_BANK* pbk = nullptr;
180
181 std::array<unsigned, 17> TID_SIZE = {0, 1, 1, 1, 2, 2, 4, 4, 4, 4, 8, 1, 0, 0, 0, 0, 0};
182
183 if(((pbkh->fFlags & (1 << 4)) > 0)) {
184 TMidas_BANK32* pbk32 = nullptr;
185
186 while(true) {
187 IterateBank32(&pbk32, reinterpret_cast<char**>(pdata));
188 if(pbk32 == nullptr) {
189 break;
190 }
191
192 if(name[0] == pbk32->fName[0] && name[1] == pbk32->fName[1] && name[2] == pbk32->fName[2] &&
193 name[3] == pbk32->fName[3]) {
194
195 if(TID_SIZE[pbk32->fType & 0xFF] == 0) {
196 *bklen = pbk32->fDataSize;
197 } else {
198 *bklen = pbk32->fDataSize / TID_SIZE[pbk32->fType & 0xFF];
199 }
200
201 *bktype = pbk32->fType;
202 return 1;
203 }
204 }
205 } else {
206 pbk = reinterpret_cast<TMidas_BANK*>(pbkh + 1);
207 do {
208 if(name[0] == pbk->fName[0] && name[1] == pbk->fName[1] && name[2] == pbk->fName[2] &&
209 name[3] == pbk->fName[3]) {
210 *pdata = pbk + 1;
211 if(TID_SIZE[pbk->fType & 0xFF] == 0) {
212 *bklen = pbk->fDataSize;
213 } else {
214 *bklen = pbk->fDataSize / TID_SIZE[pbk->fType & 0xFF];
215 }
216
217 *bktype = pbk->fType;
218 return 1;
219 }
220 pbk = reinterpret_cast<TMidas_BANK*>(reinterpret_cast<char*>(pbk + 1) + (((pbk->fDataSize) + 7) & ~7));
221 } while(reinterpret_cast<char*>(pbk) < reinterpret_cast<char*>(pbkh) + pbkh->fDataSize + sizeof(TMidas_BANK_HEADER));
222 }
223 //
224 // bank not found
225 //
226 *pdata = nullptr;
227 return 0;
228}
229
230void TMidasEvent::Print(const char* option) const
231{
232 /// Print data held in this class.
233 /// \param [in] option If 'a' (for "all") then the raw data will be
234 /// printed out too.
235 ///
236
237 auto t = static_cast<time_t>(fEventHeader.fTimeStamp);
238
239 std::cout << "Event start:" << std::endl;
240 std::cout << " event id: " << hex(fEventHeader.fEventId, 4) << std::endl;
241 std::cout << " trigger mask: " << hex(fEventHeader.fTriggerMask, 4) << std::endl;
242 std::cout << " serial number: " << fEventHeader.fSerialNumber << std::endl;
243 std::cout << " time stamp: " << fEventHeader.fTimeStamp << ", " << ctime(&t) << std::endl;
244 std::cout << " data size: " << std::setw(8) << fEventHeader.fDataSize << std::endl;
245 // const_cast<TMidasEvent*>(this)->SetBankList(); // moved here to get event information in case SetBankList crashes
246 if((fEventHeader.fEventId & 0xffff) == 0x8000) {
247 std::cout << "Begin of run " << fEventHeader.fSerialNumber << std::endl;
248 } else if((fEventHeader.fEventId & 0xffff) == 0x8001) {
249 std::cout << "End of run " << fEventHeader.fSerialNumber << std::endl;
250 } else if((fEventHeader.fEventId & 0xffff) == 0x8002) {
251 std::cout << "Message event \"" << fData << "\"" << std::endl;
252 } else if(fBanksN <= 0) {
253 std::cout << "TMidasEvent::Print: Use SetBankList() before Print() to print bank data" << std::endl;
254 } else {
255 std::cout << "Banks: " << fBankList << std::endl;
256
257 for(int i = 0; i < fBanksN * 4; i += 4) {
258 int bankLength = 0;
259 int bankType = 0;
260 void* pdata = nullptr;
261 int found = FindBank(&fBankList[i], &bankLength, &bankType, &pdata);
262
263 std::cout << "Bank " << fBankList[i] << fBankList[i + 1] << fBankList[i + 2] << fBankList[i + 3] << ", length " << std::setw(6) << bankLength << ", type " << bankType << std::endl;
264
265 int highlight = -1;
266 if(strlen(option) > 1) {
267 highlight = atoi(option + 1);
268 }
269
270 if(option[0] == 'a' && (found != 0)) {
271 switch(bankType) {
272 case 4: // TID_WORD
273 for(int j = 0; j < bankLength; j++) {
274 if(j == highlight) {
275 std::cout << ALERTTEXT << hex((reinterpret_cast<uint16_t*>(pdata))[j], 4) << RESET_COLOR << ((j % 10 == 9) ? '\n' : ' ');
276 } else {
277 std::cout << hex((reinterpret_cast<uint16_t*>(pdata))[j], 4) << ((j % 10 == 9) ? '\n' : ' ');
278 }
279 }
280 std::cout << std::endl;
281 break;
282 case 6: // TID_DWORD
283 for(int j = 0; j < bankLength; j++) {
284 if(j == highlight) {
285 std::cout << ALERTTEXT << hex((reinterpret_cast<uint32_t*>(pdata))[j], 8) << RESET_COLOR << ((j % 10 == 9) ? '\n' : ' ');
286 } else {
287 std::cout << hex((reinterpret_cast<uint32_t*>(pdata))[j], 8) << ((j % 10 == 9) ? '\n' : ' ');
288 }
289 }
290 std::cout << std::endl;
291 break;
292 case 7: // TID_nd280 (like a DWORD?)
293 for(int j = 0; j < bankLength; j++) {
294 if(j == highlight) {
295 std::cout << ALERTTEXT << hex((reinterpret_cast<uint32_t*>(pdata))[j], 8) << RESET_COLOR << ((j % 10 == 9) ? '\n' : ' ');
296 } else {
297 std::cout << hex((reinterpret_cast<uint32_t*>(pdata))[j], 8) << ((j % 10 == 9) ? '\n' : ' ');
298 }
299 }
300 std::cout << std::endl;
301 break;
302 case 9: // TID_FLOAT
303 for(int j = 0; j < bankLength; j++) {
304 if(j == highlight) {
305 std::cout << ALERTTEXT << (reinterpret_cast<float*>(pdata))[j] << RESET_COLOR << ((j % 10 == 9) ? '\n' : ' ');
306 } else {
307 std::cout << (reinterpret_cast<float*>(pdata))[j] << ((j % 10 == 9) ? '\n' : ' ');
308 }
309 }
310 std::cout << std::endl;
311 break;
312 case 10: // TID_DOUBLE
313 for(int j = 0; j < bankLength; j++) {
314 if(j == highlight) {
315 std::cout << ALERTTEXT << (reinterpret_cast<double*>(pdata))[j] << RESET_COLOR << ((j % 10 == 9) ? '\n' : ' ');
316 } else {
317 std::cout << (reinterpret_cast<double*>(pdata))[j] << ((j % 10 == 9) ? '\n' : ' ');
318 }
319 }
320 std::cout << std::endl;
321 break;
322 default:
323 std::cout << "TMidasEvent::Print: Do not know how to print bank of type " << bankType << std::endl;
324 break;
325 }
326 }
327 }
328 }
329}
330
332{
333 // Allocates space for the data from the event header if it is a good size
334 assert(!fAllocatedByUs);
335 assert(IsGoodSize());
336 fData = reinterpret_cast<char*>(malloc(fEventHeader.fDataSize)); // NOLINT(cppcoreguidelines-no-malloc)
337 assert(fData);
338 fAllocatedByUs = true;
339}
340
341const char* TMidasEvent::GetBankList() const
342{
343 return fBankList;
344}
345
347{
348 // Sets the bank list by Iterating of the banks.
349 // See IterateBank32 and IterateBank
350 if(fEventHeader.fEventId <= 0) {
351 return 0;
352 }
353
354 if(fBankList != nullptr) {
355 return fBanksN;
356 }
357
358 int listSize = 0;
359
360 fBanksN = 0;
361
362 TMidas_BANK32* pmbk32 = nullptr;
363 TMidas_BANK* pmbk = nullptr;
364 char* pdata = nullptr;
365
366 while(true) {
367 if(fBanksN * 4 >= listSize) {
368 listSize += 400;
369 fBankList = reinterpret_cast<char*>(realloc(fBankList, listSize)); // NOLINT(cppcoreguidelines-no-malloc)
370 }
371
372 if(IsBank32()) {
373 IterateBank32(&pmbk32, &pdata);
374 if(pmbk32 == nullptr) {
375 break;
376 }
377 memcpy(fBankList + fBanksN * 4, pmbk32->fName, 4); // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
378 fBanksN++;
379 } else {
380 IterateBank(&pmbk, &pdata);
381 if(pmbk == nullptr) {
382 break;
383 }
384 memcpy(fBankList + fBanksN * 4, pmbk->fName, 4); // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
385 fBanksN++;
386 }
387 }
388
389 fBankList[fBanksN * 4] = 0;
390
391 return fBanksN;
392}
393
394int TMidasEvent::IterateBank(TMidas_BANK** pbk, char** pdata) const
395{
396 /// Iterates through banks inside an event. The function can be used
397 /// to enumerate all banks of an event.
398 /// \param [in] pbk Pointer to the bank header, must be nullptr for the
399 /// first call to this function. Returns nullptr if no more banks
400 /// \param [in] pdata Pointer to data area of bank. Returns nullptr if no more banks
401 /// \returns Size of bank in bytes or 0 if no more banks.
402 ///
403 auto* event = reinterpret_cast<TMidas_BANK_HEADER*>(fData);
404
405 if(*pbk == nullptr) {
406 *pbk = reinterpret_cast<TMidas_BANK*>(event + 1);
407 } else {
408 *pbk = reinterpret_cast<TMidas_BANK*>(reinterpret_cast<char*>(*pbk + 1) + ((((*pbk)->fDataSize) + 7) & ~7));
409 }
410
411 *pdata = reinterpret_cast<char*>((*pbk) + 1);
412
413 if(reinterpret_cast<char*>(*pbk) >=
414 reinterpret_cast<char*>(event) + event->fDataSize + sizeof(TMidas_BANK_HEADER)) {
415 *pbk = nullptr;
416 *pdata = nullptr;
417 return 0;
418 }
419
420 return (*pbk)->fDataSize;
421}
422
423int TMidasEvent::IterateBank32(TMidas_BANK32** pbk, char** pdata) const
424{
425 /// See IterateBank()
426
427 auto* event = reinterpret_cast<TMidas_BANK_HEADER*>(fData);
428 if(*pbk == nullptr) {
429 *pbk = reinterpret_cast<TMidas_BANK32*>(event + 1);
430 } else {
431 uint32_t length = (*pbk)->fDataSize;
432 uint32_t length_adjusted = (length + 7) & ~7;
433 *pbk = reinterpret_cast<TMidas_BANK32*>(reinterpret_cast<char*>(*pbk + 1) + length_adjusted);
434 }
435
436 auto* bk4 = reinterpret_cast<TMidas_BANK32*>((reinterpret_cast<char*>(*pbk)) + 4);
437
438 if((*pbk)->fType > 17) { // bad - unknown bank type - it's invalid MIDAS file?
439 if(bk4->fType <= 17) { // okey, this is a malformed T2K/ND280 data file
440 *pbk = bk4;
441 } else {
442 // truncate invalid data
443 *pbk = nullptr;
444 *pdata = nullptr;
445 return 0;
446 }
447 }
448
449 *pdata = reinterpret_cast<char*>((*pbk) + 1);
450
451 if(reinterpret_cast<char*>(*pbk) >= reinterpret_cast<char*>(event) + event->fDataSize + sizeof(TMidas_BANK_HEADER)) {
452 *pbk = nullptr;
453 *pdata = nullptr;
454 return 0;
455 }
456
457 return (*pbk)->fDataSize;
458}
459
460using BYTE = uint8_t;
461
462// NOLINTBEGIN(cppcoreguidelines-macro-usage, cppcoreguidelines-pro-type-cstyle-cast)
463/// Byte swapping routine.
464///
465#define QWORD_SWAP(x) \
466 { \
467 BYTE _tmp; \
468 _tmp = *((BYTE*)(x)); \
469 *((BYTE*)(x)) = *(((BYTE*)(x)) + 7); \
470 *(((BYTE*)(x)) + 7) = _tmp; \
471 _tmp = *(((BYTE*)(x)) + 1); \
472 *(((BYTE*)(x)) + 1) = *(((BYTE*)(x)) + 6); \
473 *(((BYTE*)(x)) + 6) = _tmp; \
474 _tmp = *(((BYTE*)(x)) + 2); \
475 *(((BYTE*)(x)) + 2) = *(((BYTE*)(x)) + 5); \
476 *(((BYTE*)(x)) + 5) = _tmp; \
477 _tmp = *(((BYTE*)(x)) + 3); \
478 *(((BYTE*)(x)) + 3) = *(((BYTE*)(x)) + 4); \
479 *(((BYTE*)(x)) + 4) = _tmp; \
480 }
481
482/// Byte swapping routine.
483///
484#define DWORD_SWAP(x) \
485 { \
486 BYTE _tmp; \
487 _tmp = *((BYTE*)(x)); \
488 *((BYTE*)(x)) = *(((BYTE*)(x)) + 3); \
489 *(((BYTE*)(x)) + 3) = _tmp; \
490 _tmp = *(((BYTE*)(x)) + 1); \
491 *(((BYTE*)(x)) + 1) = *(((BYTE*)(x)) + 2); \
492 *(((BYTE*)(x)) + 2) = _tmp; \
493 }
494
495/// Byte swapping routine.
496///
497#define WORD_SWAP(x) \
498 { \
499 BYTE _tmp; \
500 _tmp = *((BYTE*)(x)); \
501 *((BYTE*)(x)) = *(((BYTE*)(x)) + 1); \
502 *(((BYTE*)(x)) + 1) = _tmp; \
503 }
504// NOLINTEND(cppcoreguidelines-macro-usage, cppcoreguidelines-pro-type-cstyle-cast)
505
515
517{
518 // Swaps bytes for endian-ness reasons
519 TMidas_BANK_HEADER* pbh = nullptr;
520 TMidas_BANK* pbk = nullptr;
521 TMidas_BANK32* pbk32 = nullptr;
522 void* pdata = nullptr;
523 uint16_t type = 0;
524
525 pbh = reinterpret_cast<TMidas_BANK_HEADER*>(fData);
526
527 uint32_t dssw = pbh->fDataSize;
528
529 DWORD_SWAP(&dssw);
530
531 // only swap if flags in high 16-bit
532 //
533 if(pbh->fFlags < 0x10000 && !force) {
534 return 0;
535 }
536
537 if(pbh->fDataSize == 0x6d783f3c) { // string "<xml..." in wrong-endian format
538 return 1;
539 }
540
541 if(pbh->fDataSize == 0x3c3f786d) { // string "<xml..."
542 return 1;
543 }
544
545 if(dssw > fEventHeader.fDataSize + 100) { // swapped data size looks wrong. do not swap.
546 return 1;
547 }
548
549 //
550 // swap bank header
551 //
552 DWORD_SWAP(&pbh->fDataSize);
553 DWORD_SWAP(&pbh->fFlags);
554 //
555 // check for 32-bit banks
556 //
557 bool b32 = IsBank32();
558
559 pbk = reinterpret_cast<TMidas_BANK*>(pbh + 1);
560 pbk32 = reinterpret_cast<TMidas_BANK32*>(pbk);
561 //
562 // scan event
563 //
564 while(reinterpret_cast<char*>(pbk) < reinterpret_cast<char*>(pbh) + pbh->fDataSize + sizeof(TMidas_BANK_HEADER)) {
565 //
566 // swap bank header
567 //
568 if(b32) {
569 DWORD_SWAP(&pbk32->fType);
570 DWORD_SWAP(&pbk32->fDataSize);
571 pdata = pbk32 + 1;
572 type = static_cast<uint16_t>(pbk32->fType);
573 } else {
574 WORD_SWAP(&pbk->fType);
575 WORD_SWAP(&pbk->fDataSize);
576 pdata = pbk + 1;
577 type = pbk->fType;
578 }
579 //
580 // pbk points to next bank
581 //
582 if(b32) {
583 assert(pbk32->fDataSize < fEventHeader.fDataSize + 100);
584 pbk32 = reinterpret_cast<TMidas_BANK32*>(reinterpret_cast<char*>(pbk32 + 1) + (((pbk32->fDataSize) + 7) & ~7));
585 pbk = reinterpret_cast<TMidas_BANK*>(pbk32);
586 } else {
587 assert(pbk->fDataSize < fEventHeader.fDataSize + 100);
588 pbk = reinterpret_cast<TMidas_BANK*>(reinterpret_cast<char*>(pbk + 1) + (((pbk->fDataSize) + 7) & ~7));
589 pbk32 = reinterpret_cast<TMidas_BANK32*>(pbk);
590 }
591
592 switch(type) {
593 case 4:
594 case 5:
595 while(pdata < pbk) {
596 WORD_SWAP(pdata);
597 pdata = (reinterpret_cast<char*>(pdata)) + 2;
598 }
599 break;
600 case 6:
601 case 7:
602 case 8:
603 case 9:
604 while(pdata < pbk) {
605 DWORD_SWAP(pdata);
606 pdata = (reinterpret_cast<char*>(pdata)) + 4;
607 }
608 break;
609 case 10:
610 while(pdata < pbk) {
611 QWORD_SWAP(pdata);
612 pdata = (reinterpret_cast<char*>(pdata)) + 8;
613 }
614 break;
615 }
616 }
617 return 1;
618}
std::string hex(T val, int width=-1)
Definition Globals.h:129
#define RESET_COLOR
Definition Globals.h:5
uint8_t BYTE
#define WORD_SWAP(x)
#define QWORD_SWAP(x)
#define DWORD_SWAP(x)
MIDAS event.
Definition TMidasEvent.h:35
bool IsBank32() const
returns "true" if event uses 32-bit banks
int IterateBank32(TMidas_BANK32 **, char **pdata) const
iterate through 32-bit data banks
TMidas_EVENT_HEADER * GetEventHeader()
return pointer to the event header
int fBanksN
number of banks in this event
Definition TMidasEvent.h:85
int SetBankList()
create the list of data banks, return number of banks
void SetData(uint32_t size, char *data)
set an externally allocated data buffer
void Clear(Option_t *opt="") override
clear event for reuse
char * GetData() override
return pointer to the data buffer
void AllocateData()
allocate data buffer using the existing event header
const char * GetBankList() const
return a list of data banks
int IterateBank(TMidas_BANK **, char **pdata) const
iterate through 16-bit data banks
uint16_t GetEventId() const
return the event id
void Print(const char *option="") const override
show all event information
~TMidasEvent() override
destructor
uint32_t GetTimeStamp() const override
return the time stamp (unix time in seconds)
int FindBank(const char *name, int *bklen, int *bktype, void **pdata) const
TMidasEvent()
default constructor
TMidasEvent & operator=(const TMidasEvent &)
assignement operator
bool fAllocatedByUs
"true" if we own the data buffer
Definition TMidasEvent.h:87
int LocateBank(const void *unused, const char *name, void **pdata) const
char * fData
event data buffer
Definition TMidasEvent.h:84
uint32_t GetSerialNumber() const
return the serial number
uint16_t GetTriggerMask() const
return the triger mask
int SwapBytes(bool) override
convert event data between little-endian (Linux-x86) and big endian (MacOS-PPC)
TMidas_EVENT_HEADER fEventHeader
event header
Definition TMidasEvent.h:83
bool IsGoodSize() const
validate the event length
uint32_t GetDataSize() const override
return the event size
void Copy(TObject &) const override
copy helper
char * fBankList
list of bank names in this event
Definition TMidasEvent.h:86
void SwapBytesEventHeader()
convert event header between little-endian (Linux-x86) and big endian (MacOS-PPC)
RAW event.
Definition TRawEvent.h:23
void Clear(Option_t *="") override
clear event for reuse
Definition TRawEvent.h:32
uint32_t fDataSize
event size in bytes
uint16_t fTriggerMask
event trigger mask
uint16_t fEventId
event id
uint32_t fSerialNumber
event serial number
uint32_t fTimeStamp
event timestamp in seconds
char fName[4]
bank name // NOLINT(*-avoid-c-arrays)
Definition TMidasEvent.h:47
16-bit data bank
Definition TMidasEvent.h:38
char fName[4]
bank name // NOLINT(*-avoid-c-arrays)
Definition TMidasEvent.h:39