#ifndef BINREADER_H #define BINREADER_H #include /// for FILE #include #include #include #include #include "TString.h" #include "TBenchmark.h" #include "TMath.h" struct Data{ uint16_t Header; /// only the last 4 bits uint16_t BoardID; uint16_t Channel; uint64_t TimeStamp; uint16_t Energy; uint16_t Energy_short; uint32_t Flags; uint8_t WaveformCode; uint32_t NSample; std::vector Trace; void Clear(){ Header = 0xCAE0; BoardID = 0; Channel = 0; TimeStamp = 0; Energy = 0; Energy_short = 0; Flags = 0; WaveformCode = 0; NSample = 0; Trace.clear(); }; void Print(){ printf("header : 0x%X \n", Header); printf(" Board : %u , Channel : %u\n", BoardID, Channel); if( Header & 4 ) { printf("Energy : %5u, Energy2 : %5u, TimeStamp : %16lu ps\n", Energy, Energy_short, TimeStamp); }else{ printf("Energy : %5u, TimeStamp : %16lu ps\n", Energy, TimeStamp); } printf(" Flag : 0x%08X\n", Flags); if( (Header & 0x8 ) >= 1 ){ /// is waevform exist printf(" Wave form code : %d , nSample : %d\n", WaveformCode, NSample); for( unsigned int i = 0 ; i < NSample ; i++){ printf("%4d | %d \n", i, Trace[i]); } } } }; //^################################################ class BinReader{ public: Data data; private: FILE * inFile; long int inFileSize; long int inFilePos; bool endOfFile; bool isOpened; Long64_t hitID; long int numHit; int64_t timeOffset; TBenchmark gClock; long int inFilePosPrecent[10]; Long64_t blockIDPrecent[10]; bool isHeaderOK; bool isOldFormat; bool isNoHeaderFormat; template int FillData(T * dataItem); // if successful, return 1, else 0; cannot fill Trace ///============================================ Methods public: BinReader(); BinReader(TString inFileName, int64_t timeOffset = 0, bool noHeader = false); ~BinReader(); void OpenFile(TString inFileName, int64_t timeOffset = 0, bool noHeader = false); void SetCustomHeader(uint16_t Header); // void SetDataFormat(bool has ); void CloseFile(); void UpdateFileSize(); bool IsEndOfFile(); bool IsOpen() const {return isOpened;} long int GetFilePos() const {return inFilePos;} long int GetFileSize() const {return inFileSize;} Long64_t GetHitID() const {return hitID;} Long64_t GetNumHit() const {return numHit;} int ReadBlock(int skipTrace = 0); /// 0 = default, fill waveform if any. slow /// 1 = no fill waveform, fast void ScanNumHit(); void JumptoPrecent(int precent); ///this is offset by 1 block void PrintStatus(int mod); void SetTimeOffset(int64_t timeOffset) { this->timeOffset = timeOffset; } }; //========================== implementation BinReader::BinReader(){ inFile = 0; data.Clear(); inFileSize = 0; inFilePos = 0; numHit = 0; hitID = -1; endOfFile = false; isOpened = false; isHeaderOK = false; isOldFormat = false; isNoHeaderFormat = false; } BinReader::~BinReader(){ if( inFile ) fclose(inFile); /// fclose already delete inFile; } BinReader::BinReader(TString inFileName, int64_t timeOffset, bool noHeader){ inFile = 0; data.Clear(); inFileSize = 0; inFilePos = 0; numHit = 0; hitID = -1; endOfFile = false; isOpened = false; OpenFile(inFileName, timeOffset, noHeader); } void BinReader::OpenFile(TString inFileName, int64_t timeOffset, bool noHeader){ inFile = fopen(inFileName, "r"); this->timeOffset = timeOffset; if( inFile == NULL ){ printf("Cannot read file : %s \n", inFileName.Data()); }else{ fseek(inFile, 0L, SEEK_END); inFileSize = ftell(inFile); rewind(inFile); ///back to the File begining data.Clear(); gClock.Reset(); gClock.Start("timer"); isOpened = true; // normal format: isHeaderOK = true, isNoHeaderFormat= false, isOldFormat = false // old format: isHeaderOK = true, isNoHeaderFormat= false, isOldFormat = true //no header format: isHeaderOK = false, isNoHeaderFormat= true, isOldFormat = false if( noHeader ){ data.Header = 0x0; isOldFormat = false; isHeaderOK = false; isNoHeaderFormat = true; return; } ///============= Read the Header, /// the header only at the beginning of a file isHeaderOK = FillData(&data.Header); if( isHeaderOK == false ){ printf(" header cannot read. \n"); return; } ///printf("HEADER: 0x%X , 0x%X\n", data.Header, (data.Header >> 4)); if( (data.Header >> 4 ) == 0 ){ printf(" Old format of CoMPASS, 0x%04x\n", data.Header); isHeaderOK = true; isOldFormat = true; isNoHeaderFormat = false; data.Header = 0xCAE5; // only with energy and energy short return; } if( (data.Header >> 4 ) != 0xCAE ) { printf(" Header format not right. 0x%04x\n", data.Header); isOldFormat = false; isHeaderOK = false; isNoHeaderFormat = false; return ; } printf(" Header format. 0x%04x\n", data.Header); isHeaderOK = true; } }; void BinReader::SetCustomHeader(uint16_t Header){ data.Header = Header; isHeaderOK = true; } void BinReader::CloseFile(){ if(inFile) fclose(inFile); inFile = nullptr; isOpened = false; data.Clear(); inFileSize = 0; inFilePos = 0; numHit = 0; hitID = -1; endOfFile = false; }; void BinReader::UpdateFileSize(){ if( inFile == NULL ) return; fseek(inFile, 0L, SEEK_END); inFileSize = ftell(inFile); fseek(inFile, inFilePos, SEEK_SET); } bool BinReader::IsEndOfFile() { if( endOfFile ) return true; if( inFile == nullptr ) return true; return feof(inFile) > 0 ? true: false; } template int BinReader::FillData(T * dataItem){ if ( fread(dataItem, sizeof(*dataItem), 1, inFile) != 1 ) { printf("!!!!! problem for reading data\n"); endOfFile = IsEndOfFile(); return -1; } ///printf("----- 0x%16llX \n", *dataItem); return 1; } int BinReader::ReadBlock(int skipTrace){ if( inFile == nullptr ) return -1; if( feof(inFile) ) return -1; if( endOfFile ) return -1; if( isNoHeaderFormat && data.Header == 0x0 ) { FillData(&data.BoardID); FillData(&data.Channel); FillData(&data.TimeStamp); if( timeOffset != 0 ) data.TimeStamp += timeOffset; FillData(&data.Energy); FillData(&data.Flags); hitID ++; inFilePos = ftell(inFile); if( inFilePos >= inFileSize ) endOfFile = true; return 1; } if( !isHeaderOK ) return -2; /// see the CoMPASS manual v19, P.67 FillData(&data.BoardID); FillData(&data.Channel); FillData(&data.TimeStamp); if( timeOffset != 0 ) data.TimeStamp += timeOffset; if( (data.Header & 0x3) ) FillData(&data.Energy); if( (data.Header & 0x2) ) { uint64_t dummy = 0; FillData(&dummy); } if( (data.Header & 0x4 ) ) FillData(&data.Energy_short); FillData(&data.Flags); if( isOldFormat ) { uint32_t dummy = 0; FillData(&dummy); } /// check is wave form exist if( (data.Header & 0x8) ){ FillData(&data.WaveformCode); FillData(&data.NSample); if( skipTrace == 0 ){ // if ( fread(data.Trace, sizeof(data.Trace), 1, inFile) != 1 ) endOfFile = IsEndOfFile(); for( unsigned int i = 0; i < data.NSample; i++ ){ uint16_t haha; size_t dummy = fread(&haha, 2, 1, inFile); data.Trace.push_back(haha); } }else{ /// skip trace fseek(inFile, inFilePos + data.NSample*2, SEEK_SET); /// 2 becasue each trace is 2 bytes } } hitID ++; inFilePos = ftell(inFile); if( inFilePos >= inFileSize ) endOfFile = true; return 1; } void BinReader::ScanNumHit(){ numHit = 0; int count = 0; while( ReadBlock(1) != -1 ){ numHit ++; int haha = (inFilePos*10/inFileSize)%10; if( haha == count ) { inFilePosPrecent[count] = inFilePos; blockIDPrecent[count] = hitID; count++; } PrintStatus(10000); } PrintStatus(1); printf("\n\n\n"); printf("scan complete: number of data Block : %ld\n", numHit); rewind(inFile); ///back to the File begining if( isOldFormat == false && isNoHeaderFormat == false ){ // only when normal format FillData(&data.Header); } inFilePos = 0; hitID = -1; endOfFile = false; } void BinReader::JumptoPrecent(int precent){ if( precent < 0 || precent > 10 ) { printf("input precent should be 0 to 10\n"); return; } fseek(inFile, inFilePosPrecent[precent], SEEK_SET); hitID = blockIDPrecent[precent]; } void BinReader::PrintStatus(int mod){ ///==== event stats, print status every 10000 events if ( hitID % mod == 0 ) { UpdateFileSize(); gClock.Stop("timer"); double time = gClock.GetRealTime("timer"); gClock.Start("timer"); printf("Hit ID: \x1B[32m%llu \x1B[0m\nReading Pos: \x1B[32m %.3f/%.3f GB\x1B[0m\nTime used:%3.0f min %5.2f sec\033[A\033[A\r", hitID, inFilePos/(1024.*1024.*1024.), inFileSize/1024./1024./1024, TMath::Floor(time/60.), time - TMath::Floor(time/60.)*60.); } } #endif