diff --git a/ClassData.h b/ClassData.h index 0c57aa2..b15f8eb 100644 --- a/ClassData.h +++ b/ClassData.h @@ -74,7 +74,8 @@ class Data{ void PrintAllData() const; //^================= Saving data - void OpenSaveFile(std::string fileNamePrefix); + bool OpenSaveFile(std::string fileNamePrefix); // return false when fail + std::string GetOutFileName() const {return outFileName;} void SaveData(); void CloseSaveFile(); unsigned int GetFileSize() const {return outFileSize;} @@ -199,7 +200,7 @@ inline void Data::CopyBuffer(const char * buffer, const unsigned int size){ //^############################################### //^############################################### Save fsu file -inline void Data::OpenSaveFile(std::string fileNamePrefix){ +inline bool Data::OpenSaveFile(std::string fileNamePrefix){ outFilePrefix = fileNamePrefix; char saveFileName[100]; @@ -207,9 +208,16 @@ inline void Data::OpenSaveFile(std::string fileNamePrefix){ outFileName = saveFileName; outFile = fopen(saveFileName, "wb"); // overwrite binary + + if (outFile == NULL) { + printf("Failed to open the file. Probably Read-ONLY.\n"); + return false; + } + fseek(outFile, 0L, SEEK_END); outFileSize = ftell(outFile); - + + return true; } inline void Data::SaveData(){ @@ -797,6 +805,7 @@ inline int Data::DecodePSDDualChannelBlock(unsigned int ChannelMask, bool fastDe if( EventIndex[channel] > MaxNData ) EventIndex[channel] = 0; NumEventsDecoded[channel] ++; + NumNonPileUpDecoded[channel] ++; TotNumEvents[channel] ++; Energy[channel][EventIndex[channel]] = Qshort; diff --git a/CustomThreads.h b/CustomThreads.h index 183779a..45f3f63 100644 --- a/CustomThreads.h +++ b/CustomThreads.h @@ -39,6 +39,15 @@ public: digi->StopACQ(); break; } + + if( isSaveData ) { + clock_gettime(CLOCK_REALTIME, &tb); + if( tb.tv_sec - ta.tv_sec > 2 ) { + emit sendMsg("FileSize ("+ QString::number(digi->GetSerialNumber()) +"): " + QString::number(digi->GetData()->GetTotalFileSize()/1024./1024.) + " MB"); + ta = tb; + } + } + } printf("ReadDataThread stopped.\n"); } diff --git a/EventBuilder.cpp b/EventBuilder.cpp new file mode 100644 index 0000000..065a982 --- /dev/null +++ b/EventBuilder.cpp @@ -0,0 +1,445 @@ +#include "ClassData.h" + +#include "TROOT.h" +#include "TSystem.h" +#include "TClonesArray.h" +#include "TGraph.h" +#include "TFile.h" +#include "TTree.h" + +#define MAX_MULTI 100 +#define NTimeWinForBuffer 3 + +TFile * outRootFile = NULL; +TTree * tree = NULL; + +unsigned long long evID = 0; +unsigned short multi = 0; +unsigned short bd[MAX_MULTI] = {0}; /// boardID +unsigned short ch[MAX_MULTI] = {0}; /// chID +unsigned short e[MAX_MULTI] = {0}; /// 15 bit +unsigned long long e_t[MAX_MULTI] = {0}; /// timestamp 47 bit +unsigned short e_f[MAX_MULTI] = {0}; /// fine time 10 bit + + +class Trace{ + public: + Trace() {trace.clear(); } + ~Trace(); + void Clear() { trace.clear(); }; + Trace operator = (std::vector v){ + Trace tt; + for( int i = 0 ; i < (int) v.size() ; i++){ + trace.push_back(v[i]); + } + return tt; + } + std::vector trace; +}; + +/// using TClonesArray to hold the trace in TGraph +TClonesArray * arrayTrace = NULL; +unsigned short traceLength[MAX_MULTI] = {0}; +TGraph * trace = NULL; + +template void swap(T * a, T *b ); +int partition(int arr[], int kaka[], TString file[], int start, int end); +void quickSort(int arr[], int kaka[], TString file[], int start, int end); +unsigned long get_time(); +void EventBuilder(Data * data, const unsigned int timeWin, bool traceOn = false, bool isLastData = false, unsigned int verbose = 0); + +int main(int argc, char **argv) { + + printf("=====================================\n"); + printf("=== *.fsu Events Builder ===\n"); + printf("=====================================\n"); + if (argc <= 3) { + printf("Incorrect number of arguments:\n"); + printf("%s [timeWindow] [traceOn/Off] [verbose] [inFile1] [inFile2] .... \n", argv[0]); + printf(" timeWindow : number of tick, 1 tick. default = 100 \n"); + printf(" traceOn/Off : is traces stored \n"); + printf(" verbose : > 0 for debug \n"); + printf(" Output file name is contructed from inFile1 \n"); + return 1; + } + + /// File format must be YYY...Y_runXXX_AAA_BBB_CCC.fsu + /// YYY...Y = prefix + /// XXX = runID, 3 digits + /// AAA = board Serial Number, 3 digits + /// BBB = DPPtype, 3 digits + /// CCC = over size index, 3 digits + + ///============= read input + unsigned int timeWindow = atoi(argv[1]); + bool traceOn = atoi(argv[2]); + unsigned int debug = atoi(argv[3]); + int nFile = argc - 4; + TString inFileName[nFile]; + for( int i = 0 ; i < nFile ; i++){ + inFileName[i] = argv[i+4]; + } + + /// Form outFileName; + TString outFileName = inFileName[0]; + int pos = outFileName.Index("_"); + pos = outFileName.Index("_", pos+1); + outFileName.Remove(pos); + outFileName += ".root"; + printf("-------> Out file name : %s \n", outFileName.Data()); + + + printf(" Number of Files : %d \n", nFile); + for( int i = 0; i < nFile; i++) printf("%2d | %s \n", i, inFileName[i].Data()); + printf("=====================================\n"); + printf(" Time Window = %u \n", timeWindow); + printf("=====================================\n"); + + ///============= sorting file by the serial number & order + int ID[nFile]; /// serial+ order*1000; + int type[nFile]; + for( int i = 0; i < nFile; i++){ + int snPos = inFileName[i].Index("_"); + snPos = inFileName[i].Index("_", snPos+1); + int sn = atoi(&inFileName[i][snPos+1]); + type[i] = atoi(&inFileName[i][snPos+5]); + int order = atoi(&inFileName[i][snPos+9]); + ID[i] = sn + order * 1000; + } + quickSort(&(ID[0]), &(type[0]), &(inFileName[0]), 0, nFile-1); + for( int i = 0 ; i < nFile; i++){ + printf("%d | %6d | %3d | %s \n", i, ID[i], type[i], inFileName[i].Data()); + } + + ///=============== Seperate files + std::vector idCat; + std::vector> typeCat; + std::vector> fileCat; + for( int i = 0; i < nFile; i++){ + if( ID[i] / 1000 == 0 ) { + std::vector temp = {inFileName[i]}; + std::vector temp2 = {type[i]}; + fileCat.push_back(temp); + typeCat.push_back(temp2); + idCat.push_back(ID[i]%1000); + }else{ + for( int p = 0; p < (int) idCat.size(); p++){ + if( (ID[i] % 1000) == idCat[p] ) { + fileCat[p].push_back(inFileName[i]); + typeCat[p].push_back(type[i]); + } + } + } + } + + printf("=====================================\n"); + for( int i = 0; i < (int) idCat.size(); i++){ + printf("............ %d \n", idCat[i]); + for( int j = 0; j< (int) fileCat[i].size(); j++){ + printf("%s | %d\n", fileCat[i][j].Data(), typeCat[i][j]); + } + } + + ///============= Set Root Tree + outRootFile = new TFile(outFileName, "recreate"); + tree = new TTree("tree", outFileName); + tree->Branch("evID", &evID, "event_ID/l"); + tree->Branch("multi", &multi, "multi/s"); + tree->Branch("bd", bd, "bd[multi]/s"); + tree->Branch("ch", ch, "ch[multi]/s"); + tree->Branch("e", e, "e[multi]/s"); + tree->Branch("e_t", e_t, "e_timestamp[multi]/l"); + tree->Branch("e_f", e_f, "e_timestamp[multi]/s"); + + if( traceOn ) { + arrayTrace = new TClonesArray("TGraph"); + tree->Branch("traceLength", traceLength, "traceLength[multi]/s"); + tree->Branch("trace", arrayTrace, 2560000); + arrayTrace->BypassStreamer(); + } + + ///============= Open input Files + printf("##############################################\n"); + FILE * haha = fopen(fileCat[0][0], "r"); + if( haha == NULL ){ + printf("#### Cannot open file : %s. Abort.\n", fileCat[0][0].Data()); + return -1; + } + fseek(haha, 0L, SEEK_END); + const size_t inFileSize = ftell(haha); + printf("%s | file size : %d Byte = %.2f MB\n", fileCat[0][0].Data(), (int) inFileSize, inFileSize/1024./1024.); + fclose(haha); + + + Data * data = new Data(); + data->DPPType = typeCat[0][0]; + data->boardSN = idCat[0]; + data->SetSaveWaveToMemory(true); + + ///============= Main Loop + haha = fopen(inFileName[0], "r"); + int countBdAgg = 0; + + unsigned long currentTime = 0; + unsigned long oldTime = 0; + + char * buffer = NULL; + do{ + + ///========== Get 1 aggreration + oldTime = get_time(); + if( debug) printf("*********************** file pos : %d, %lu\n", (int) ftell(haha), oldTime); + unsigned int word[1]; /// 4 bytes + size_t dump = fread(word, 4, 1, haha); + fseek(haha, -4, SEEK_CUR); + + short header = ((word[0] >> 28 ) & 0xF); + if( header != 0xA ) break; + + unsigned int aggSize = (word[0] & 0x0FFFFFFF) * 4; ///byte + + if( debug) printf("Board Agg. has %d word = %d bytes\n", aggSize/4, aggSize); + + buffer = new char[aggSize]; + dump = fread(buffer, aggSize, 1, haha); + countBdAgg ++; + if( debug) printf("==================== %d Agg\n", countBdAgg); + + data->DecodeBuffer(buffer, aggSize, false, 0); + data->ClearBuffer(); + if( !data->IsNotRollOverFakeAgg ) continue; + + currentTime = get_time(); + + if( debug) { + printf("~~~~~~~~~~~~~~~~ time used : %lu usec\n", currentTime - oldTime); + data->PrintStat(); + } + + EventBuilder(data, timeWindow, traceOn, false, debug); + + if( debug) printf("---------- event built : %llu \n", evID); + + //if( countBdAgg > 74) break; + + }while(!feof(haha) && ftell(haha) < inFileSize); + + fclose(haha); + + printf("=======@@@@@@@@###############============= end of loop \n"); + EventBuilder(data, timeWindow, traceOn, true, debug); + + + tree->Write(); + outRootFile->Close(); + + printf("========================= finsihed.\n"); + printf("total events built = %llu \n", evID); + printf("=======> saved to %s \n", outFileName.Data()); + +} + +void EventBuilder(Data * data, const unsigned int timeWin, bool traceOn, bool isLastData, unsigned int verbose){ + + if( verbose) { + printf("======================== Event Builder \n"); + data->PrintData(); + } + + /// find the last event timestamp; + unsigned long long firstTimeStamp = -1; + unsigned long long lastTimeStamp = 0; + unsigned long long smallestLastTimeStamp = -1; + unsigned int maxNumEvent = 0; + for( int chI = 0; chI < MaxNChannels ; chI ++){ + if( data->NumEvents[chI] == 0 ) continue; + + if( data->Timestamp[chI][0] < firstTimeStamp ) { + firstTimeStamp = data->Timestamp[chI][0]; + } + unsigned short ev = data->NumEvents[chI]-1; + if( data->Timestamp[chI][ev] > lastTimeStamp ) { + lastTimeStamp = data->Timestamp[chI][ev]; + } + if( ev + 1 > maxNumEvent ) maxNumEvent = ev + 1; + if( data->Timestamp[chI][ev] < smallestLastTimeStamp ){ + smallestLastTimeStamp = data->Timestamp[chI][ev]; + } + } + + if( maxNumEvent == 0 ) return; + + if( verbose) printf("================ time range : %llu - %llu, smallest Last %llu\n", firstTimeStamp, lastTimeStamp, smallestLastTimeStamp ); + unsigned short lastEv[MaxNChannels] = {0}; /// store the last event number for each ch + unsigned short exhaustedCh = 0; /// when exhaustedCh == MaxNChannels ==> stop + bool singleChannelExhaustedFlag = false; /// when a single ch has data but exhaused ==> stop + + do { + + /// find the 1st event + int ch1st = -1; + unsigned long long time1st = -1; + for( int chI = 0; chI < MaxNChannels ; chI ++){ + if( data->NumEvents[chI] == 0 ) continue; + if( data->NumEvents[chI] <= lastEv[chI] ) continue; + if( data->Timestamp[chI][lastEv[chI]] < time1st ) { + time1st = data->Timestamp[chI][lastEv[chI]]; + ch1st = chI; + } + } + if( !isLastData && ((smallestLastTimeStamp - time1st) < NTimeWinForBuffer * timeWin) && maxNumEvent < MaxNData * 0.6 ) break; + if( ch1st > MaxNChannels ) break; + + multi ++; + bd[multi-1] = data->boardSN; + ch[multi-1] = ch1st; + e[multi-1] = data->Energy[ch1st][lastEv[ch1st]]; + e_t[multi-1] = data->Timestamp[ch1st][lastEv[ch1st]]; + e_f[multi-1] = data->fineTime[ch1st][lastEv[ch1st]]; + if( traceOn ){ + arrayTrace->Clear("C"); + traceLength[multi-1] = (unsigned short) data->Waveform1[ch1st][lastEv[ch1st]].size(); + ///if( verbose )printf("------- trace Length : %u \n", traceLength[multi-1]); + trace = (TGraph *) arrayTrace->ConstructedAt(multi-1, "C"); + trace->Clear(); + for( int hh = 0; hh < traceLength[multi-1]; hh++){ + trace->SetPoint(hh, hh, data->Waveform1[ch1st][lastEv[ch1st]][hh]); + ///if( verbose )if( hh % 200 == 0 ) printf("%3d | %u \n", hh, data->Waveform1[ch1st][lastEv[ch1st]][hh]); + } + } + lastEv[ch1st] ++; + + /// build the rest of the event + exhaustedCh = 0; + singleChannelExhaustedFlag = false; + for( int chI = ch1st; chI < ch1st + MaxNChannels; chI ++){ + unsigned short chX = chI % MaxNChannels; + if( data->NumEvents[chX] == 0 ) { + exhaustedCh ++; + continue; + } + if( data->NumEvents[chX] <= lastEv[chX] ) { + exhaustedCh ++; + singleChannelExhaustedFlag = true; + continue; + } + if( timeWin == 0 ) continue; + for( int ev = lastEv[chX]; ev < data->NumEvents[chX] ; ev++){ + if( data->Timestamp[chX][ev] > 0 && (data->Timestamp[chX][ev] - e_t[0] ) < timeWin ) { + multi ++; + bd[multi-1] = data->boardSN; + ch[multi-1] = chX; + e[multi-1] = data->Energy[chX][ev]; + e_t[multi-1] = data->Timestamp[chX][ev]; + e_f[multi-1] = data->fineTime[chX][ev]; + if( traceOn ){ + traceLength[multi-1] = (unsigned short) data->Waveform1[chX][ev].size(); + trace = (TGraph *) arrayTrace->ConstructedAt(multi-1, "C"); + trace->Clear(); + for( int hh = 0; hh < traceLength[multi-1]; hh++){ + trace->SetPoint(hh, hh, data->Waveform1[chX][ev][hh]); + } + } + lastEv[chX] = ev + 1; + if( lastEv[chX] == data->NumEvents[chX] ) exhaustedCh ++; + } + } + } + + if( verbose) { + printf("=============== multi : %d , ev : %llu\n", multi, evID); + for( int ev = 0; ev < multi; ev++){ + printf("%3d, ch : %2d, %u, %llu \n", ev, ch[ev], e[ev], e_t[ev]); + } + + printf("=============== Last Ev , exhaustedCh %d \n", exhaustedCh); + for( int chI = 0; chI < MaxNChannels ; chI++){ + if( lastEv[chI] == 0 ) continue; + printf("%2d, %d %d\n", chI, lastEv[chI], data->NumEvents[chI]); + } + } + + /// fill Tree + outRootFile->cd(); + tree->Fill(); + evID++; + multi = 0; + + }while( !singleChannelExhaustedFlag || (exhaustedCh < MaxNChannels) ); + + ///========== clear built data + /// move the last data to the top, + for( int chI = 0; chI < MaxNChannels; chI++){ + if( data->NumEvents[chI] == 0 ) continue; + int count = 0; + for( int ev = lastEv[chI] ; ev < data->NumEvents[chI] ; ev++){ + data->Energy[chI][count] = data->Energy[chI][ev]; + data->Timestamp[chI][count] = data->Timestamp[chI][ev]; + data->fineTime[chI][count] = data->fineTime[chI][ev]; + count++; + } + int lala = data->NumEvents[chI] - lastEv[chI]; + data->NumEvents[chI] = (lala >= 0 ? lala: 0); + } + + if( verbose > 0 ) { + printf("&&&&&&&&&&&&&&&&&&&&&&&&&& end of one event build loop\n"); + data->PrintData(); + } + +} + +unsigned long get_time(){ + unsigned long time_us; + struct timeval t1; + struct timezone tz; + gettimeofday(&t1, &tz); + time_us = (t1.tv_sec) * 1000000 + t1.tv_usec; + return time_us; +} + + +template void swap(T * a, T *b ){ + T temp = * b; + *b = *a; + *a = temp; +} + +int partition(int arr[], int kaka[], TString file[], int start, int end){ + int pivot = arr[start]; + int count = 0; + for (int i = start + 1; i <= end; i++) { + if (arr[i] <= pivot) count++; + } + /// Giving pivot element its correct position + int pivotIndex = start + count; + swap(&arr[pivotIndex], &arr[start]); + swap(&file[pivotIndex], &file[start]); + swap(&kaka[pivotIndex], &kaka[start]); + + /// Sorting left and right parts of the pivot element + int i = start, j = end; + while (i < pivotIndex && j > pivotIndex) { + while (arr[i] <= pivot) {i++;} + while (arr[j] > pivot) {j--;} + if (i < pivotIndex && j > pivotIndex) { + int ip = i++; + int jm = j--; + swap( &arr[ip], &arr[jm]); + swap(&file[ip], &file[jm]); + swap(&kaka[ip], &kaka[jm]); + } + } + return pivotIndex; +} + +void quickSort(int arr[], int kaka[], TString file[], int start, int end){ + /// base case + if (start >= end) return; + /// partitioning the array + int p = partition(arr, kaka, file, start, end); + /// Sorting the left part + quickSort(arr, kaka, file, start, p - 1); + /// Sorting the right part + quickSort(arr, kaka, file, p + 1, end); +} diff --git a/FSUDAQ.cpp b/FSUDAQ.cpp index 3d0f3f6..921e9ea 100644 --- a/FSUDAQ.cpp +++ b/FSUDAQ.cpp @@ -115,7 +115,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ lbComment->setAlignment(Qt::AlignRight | Qt::AlignCenter); leComment = new QLineEdit(this); - leComment->setEnabled(false); + leComment->setReadOnly(true); bnOpenScaler = new QPushButton("Scalar", this); connect(bnOpenScaler, &QPushButton::clicked, this, &MainWindow::OpenScalar); @@ -478,7 +478,7 @@ void MainWindow::SetupScalar(){ scalarThread = new TimingThread(); connect(scalarThread, &TimingThread::timeUp, this, &MainWindow::UpdateScalar); - scalar->setGeometry(0, 0, 10 + nDigi * 180, 110 + MaxNChannels * 20); + scalar->setGeometry(0, 0, 10 + nDigi * 200, 110 + MaxNChannels * 25); if( lbLastUpdateTime == nullptr ){ lbLastUpdateTime = new QLabel("Last update : NA", scalar); @@ -583,6 +583,8 @@ void MainWindow::OpenScalar(){ void MainWindow::UpdateScalar(){ if( digi == nullptr ) return; + if( scalar == nullptr ) return; + if( !scalar->isVisible() ) return; lbLastUpdateTime->setText("Last update: " + QDateTime::currentDateTime().toString("MM.dd hh:mm:ss")); @@ -607,13 +609,18 @@ void MainWindow::StartACQ(){ if( chkSaveData->isChecked() ) commentResult = CommentDialog(true); if( commentResult == false) return; + LogMsg("===================== Start a new Run-" + QString::number(runID)); + for( unsigned int i = 0; i < nDigi ; i++){ if( chkSaveData->isChecked() ) { - digi[i]->GetData()->OpenSaveFile((rawDataPath + "/" + prefix).toStdString()); - readDataThread[i]->SetSaveData(chkSaveData->isChecked()); + if( digi[i]->GetData()->OpenSaveFile((rawDataPath + "/" + prefix + "_" + QString::number(runID).rightJustified(3, '0')).toStdString()) == false ) { + LogMsg("Cannot open save file : " + QString::fromStdString(digi[i]->GetData()->GetOutFileName() ) + ". Probably read-only?"); + continue; + }; } + readDataThread[i]->SetSaveData(chkSaveData->isChecked()); + LogMsg("Digi-" + QString::number(digi[i]->GetSerialNumber()) + " is starting ACQ." ); digi[i]->StartACQ(); - readDataThread[i]->SetSaveData(false); readDataThread[i]->start(); } if( chkSaveData->isChecked() ) SaveLastRunFile(); @@ -629,17 +636,19 @@ void MainWindow::StartACQ(){ bnStartACQ->setEnabled(false); bnStopACQ->setEnabled(true); bnOpenScope->setEnabled(false); - } void MainWindow::StopACQ(){ if( digi == nullptr ) return; + LogMsg("===================== Stop Run-" + QString::number(runID)); + bool commentResult = true; if( chkSaveData->isChecked() ) commentResult = CommentDialog(true); if( commentResult == false) return; for( unsigned int i = 0; i < nDigi; i++){ + LogMsg("Digi-" + QString::number(digi[i]->GetSerialNumber()) + " is stoping ACQ." ); digi[i]->StopACQ(); if( chkSaveData->isChecked() ) digi[i]->GetData()->CloseSaveFile(); @@ -703,6 +712,7 @@ bool MainWindow::CommentDialog(bool isStartRun){ if( startComment == "") startComment = "No commet was typed."; startComment = "Start Comment: " + startComment; leComment->setText(startComment); + leRunID->setText(QString::number(runID)); }else{ stopComment = lineEdit->text(); if( stopComment == "") stopComment = "No commet was typed."; @@ -772,6 +782,16 @@ void MainWindow::OpenScope(){ bnStartACQ->setEnabled(true); bnStopACQ->setEnabled(false); }); + connect(scope, &Scope::TellACQOnOff, this, [=](bool onOff){ + if( scope == nullptr ) return; + if( onOff ) { + lbScalarACQStatus->setText("ACQ On"); + }else{ + lbScalarACQStatus->setText("ACQ Off"); + } + }); + + connect(scope, &Scope::UpdateScaler, this, &MainWindow::UpdateScalar); scope->show(); }else{ scope->show(); diff --git a/Scope.cpp b/Scope.cpp index b007891..51ca754 100644 --- a/Scope.cpp +++ b/Scope.cpp @@ -325,6 +325,8 @@ void Scope::UpdateScope(){ plot->axes(Qt::Horizontal).first()->setRange(0, ch2ns * traceLength * factor); + emit UpdateScaler(); + } //*======================================================= diff --git a/Scope.h b/Scope.h index 57b1969..fe50ccb 100644 --- a/Scope.h +++ b/Scope.h @@ -48,6 +48,7 @@ signals: void CloseWindow(); void SendLogMsg(const QString &msg); void TellACQOnOff(const bool onOff); + void UpdateScaler(); private: diff --git a/test.cpp b/test.cpp index cc962e0..9ac2288 100644 --- a/test.cpp +++ b/test.cpp @@ -40,6 +40,8 @@ int main(int argc, char* argv[]){ Data * data = dig[0]->GetData(); + data->OpenSaveFile("haha"); + printf("################# DPP Type : %d , %s\n", data->DPPType, data->DPPTypeStr.c_str()); dig[0]->StartACQ(); @@ -50,6 +52,8 @@ int main(int argc, char* argv[]){ data->DecodeBuffer(false, 5); data->PrintStat(); + data->SaveData(); + int index = data->NumEventsDecoded[0]; printf("-------------- %ld \n", data->Waveform1[0][index].size());