#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%X\n", Flags); if( (Header & 0x8 ) >= 1 ){ /// is waevform exist printf(" Wave form code : %d , nSample : %d\n", WaveformCode, NSample); for( 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; TBenchmark gClock; long int inFilePosPrecent[10]; Long64_t blockIDPrecent[10]; bool isHeaderOK; template int FillData(T * dataItem); // if successful, return 1, else 0; cannot fill Trace ///============================================ Methods public: BinReader(); BinReader(TString inFileName); ~BinReader(); void OpenFile(TString inFileName); 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); }; //========================== implementation BinReader::BinReader(){ inFile = 0; data.Clear(); inFileSize = 0; inFilePos = 0; numHit = 0; hitID = -1; endOfFile = false; isOpened = false; isHeaderOK = false; } BinReader::~BinReader(){ fclose(inFile); /// fclose already delete inFile; } BinReader::BinReader(TString inFileName){ inFile = 0; data.Clear(); inFileSize = 0; inFilePos = 0; numHit = 0; hitID = -1; endOfFile = false; isOpened = false; OpenFile(inFileName); } void BinReader::OpenFile(TString inFileName){ inFile = fopen(inFileName, "r"); 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; ///============= 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 ) != 0xCAE ) { printf(" Header format not right. \n"); isHeaderOK = false; return ; } isHeaderOK = true; } }; void BinReader::CloseFile(){ fclose(inFile); 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; 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( !isHeaderOK ) return -2; /// see the CoMPASS manual v19, P.67 FillData(&data.BoardID); FillData(&data.Channel); FillData(&data.TimeStamp); if( (data.Header & 0x3) != 0 ) FillData(&data.Energy); if( (data.Header & 0x2) == 1 ) { uint64_t dummy = 0; FillData(&dummy); } if( (data.Header & 0x4 ) != 0 ) FillData(&data.Energy_short); FillData(&data.Flags); /// check is wave form exist if( (data.Header & 0x8) == 1){ FillData(&data.WaveformCode); FillData(&data.NSample); if( skipTrace == 0 ){ // if ( fread(data.Trace, sizeof(data.Trace), 1, inFile) != 1 ) endOfFile = IsEndOfFile(); for( 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 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