diff --git a/.gitignore b/.gitignore index 84e79bb..2bb661a 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ Bin2Root data Data raw_binary +log *.d *.pcm diff --git a/Aux/Makefile b/Aux/Makefile index 1433ca5..c3b10e1 100644 --- a/Aux/Makefile +++ b/Aux/Makefile @@ -12,9 +12,9 @@ CAENLIBS = -lCAENDigitizer -lCAENVME ROOTLIBS = `root-config --cflags --glibs` -OBJS = ClassDigitizer.o MultiBuilder.o ClassInfluxDB.o +OBJS = ClassDigitizer.o MultiBuilder.o ClassInfluxDB.o ClassDigitizerAPI.o -ALL = test EventBuilder DataReader DumpFSU2ROOT SettingsExplorer FSU2CAEN +ALL = test EventBuilder DataReader DumpFSU2ROOT SettingsExplorer FSU2CAEN haha ######################################################################### @@ -29,12 +29,15 @@ MultiBuilder.o : ../MultiBuilder.cpp ../MultiBuilder.h ../Hit.h ClassDigitizer.o : ../ClassDigitizer.cpp ../ClassDigitizer.h ../RegisterAddress.h ../macro.h ../ClassData.h $(CC) $(COPTS) -c ../ClassDigitizer.cpp +ClassDigitizerAPI.o : ../ClassDigitizer.cpp ClassDigitizerAPI.cpp ../ClassDigitizer.h ../RegisterAddress.h ../macro.h ../ClassData.h + $(CC) $(COPTS) -c ClassDigitizerAPI.cpp + ClassInfluxDB.o : ../ClassInfluxDB.cpp ../ClassInfluxDB.h $(CC) $(COPTS) -c ../ClassInfluxDB.cpp -lcurl -test : test.cpp ../ClassDigitizer.o ../MultiBuilder.o ../ClassInfluxDB.o +test : test.cpp ../ClassDigitizer.o ../MultiBuilder.o ../ClassInfluxDB.o ClassDigitizerAPI.o @echo "--------- making test" - $(CC) -fPIC -DLINUX -O0 -std=c++17 -lpthread -g -o test test.cpp ../ClassDigitizer.o ../MultiBuilder.o ../ClassInfluxDB.o $(CAENLIBS) $(ROOTLIBS) -lcurl + $(CC) -fPIC -DLINUX -O0 -std=c++17 -lpthread -g -o test test.cpp ../ClassDigitizer.o ClassDigitizerAPI.o ../MultiBuilder.o ../ClassInfluxDB.o $(CAENLIBS) $(ROOTLIBS) -lcurl # test_indep : test_indep.cpp ../RegisterAddress.h ../macro.h # @echo "--------- making test_indep" diff --git a/Aux/test.cpp b/Aux/test.cpp index 63966c2..6864749 100644 --- a/Aux/test.cpp +++ b/Aux/test.cpp @@ -3,6 +3,7 @@ #include "../ClassDigitizer.h" #include "../MultiBuilder.h" #include "../ClassInfluxDB.h" +#include "ClassDigitizerAPI.h" #include #include @@ -322,6 +323,39 @@ int TestDigitizerRaw(){ } +void SimpleDAQ(){ + + std::unique_ptr digi = std::make_unique(0, 49093, false, true); + + digi->ProgramBoard(); + digi->SetBits(DPP::QDC::DPPAlgorithmControl, DPP::QDC::Bit_DPPAlgorithmControl::Polarity, 0, -1); + digi->WriteRegister(DPP::QDC::NumberEventsPerAggregate, 5); + digi->SetBits(DPP::BoardConfiguration, DPP::Bit_BoardConfig::RecordTrace, 1, -1); // enable trace recording + digi->WriteRegister(DPP::MaxAggregatePerBlockTransfer, 10); + + Data * data = digi->GetData(); + data->OpenSaveFile("haha2"); + + digi->StartACQ(); + + for( int i = 0; i < 10 ; i++ ){ + + usleep(500*1000); + + digi->ReadData(); + data->DecodeBuffer(true, 0); + data->SetDecimationFactor(3); + data->SaveData(); + + data->PrintStat(); + + } + + digi->StopACQ(); + +} + + void Compare_CAEN_Decoder(){ std::unique_ptr digi = std::make_unique(0, 49093, false, true); @@ -384,14 +418,20 @@ void Compare_CAEN_Decoder(){ //^====================================== int main(int argc, char* argv[]){ - Compare_CAEN_Decoder(); + // Compare_CAEN_Decoder(); // Data * data = digi->GetData(); + SimpleDAQ(); + // MultiBuilder * builder = new MultiBuilder(data, DPPType::DPP_PHA_CODE, digi->GetSerialNumber()); // builder->SetTimeWindow(100); + // std::unique_ptr digi = std::make_unique(0, 49093, false, true); + + + return 0; } diff --git a/ClassData.h b/ClassData.h index 39606c9..0e0afd5 100644 --- a/ClassData.h +++ b/ClassData.h @@ -16,9 +16,6 @@ #include "macro.h" -//#define MaxNData 10000 /// store 10k events per channels -#define DefaultDataSize 10000 - enum DPPTypeCode{ DPP_PHA_CODE = 0x8B, DPP_PSD_CODE = 0x88, @@ -55,14 +52,15 @@ class Data{ int GetLoopIndex(unsigned short ch) const {return LoopIndex[ch];} int GetDataIndex(unsigned short ch) const {return DataIndex[ch];} + long GetAbsDataIndex(unsigned short ch) const {return LoopIndex[ch] * dataSize + DataIndex[ch];} uShort GetDataSize() const {return dataSize;} - ullong GetTimestamp(unsigned short ch, unsigned int index) const {return Timestamp[ch][index];} - uShort GetFineTime(unsigned short ch, unsigned int index) const {return fineTime[ch][index];} - uShort GetEnergy(unsigned short ch, unsigned int index) const {return Energy[ch][index];} - uShort GetEnergy2(unsigned short ch, unsigned int index) const {return Energy2[ch][index];} - bool GetPileUp(unsigned short ch, unsigned int index) const {return PileUp[ch][index];} + ullong GetTimestamp(unsigned short ch, unsigned int index) const {return Timestamp[ch][index % dataSize];} + uShort GetFineTime(unsigned short ch, unsigned int index) const {return fineTime[ch][index % dataSize];} + uShort GetEnergy(unsigned short ch, unsigned int index) const {return Energy[ch][index % dataSize];} + uShort GetEnergy2(unsigned short ch, unsigned int index) const {return Energy2[ch][index % dataSize];} + bool GetPileUp(unsigned short ch, unsigned int index) const {return PileUp[ch][index % dataSize];} uInt GetWordIndex() const {return nw;} @@ -105,7 +103,8 @@ class Data{ //^================= Saving data bool OpenSaveFile(std::string fileNamePrefix); // return false when fail std::string GetOutFileName() const {return outFileName;} - void SaveData(); + void SetDecimationFactor(unsigned short factor) { decimation = factor; printf("Set Decimation Factor to be %d\n", factor);} + void SaveData(); void CloseSaveFile(); unsigned int GetFileSize() const {return outFileSize;} uint64_t GetTotalFileSize() const {return FinishedOutFilesSize + outFileSize;} @@ -138,6 +137,8 @@ class Data{ std::vector tempDigiWaveform3; std::vector tempDigiWaveform4; + unsigned short decimation; + FILE * outFile; uint64_t FinishedOutFilesSize; // sum of files size. unsigned int outFileIndex; @@ -177,6 +178,8 @@ inline Data::Data(unsigned short numCh, uInt dataSize): numInputCh(numCh){ ClearNumEventsDecoded(); nw = 0; + decimation = 0; + outFileIndex = 0; outFilePrefix = ""; outFileName = ""; @@ -472,10 +475,146 @@ inline void Data::SaveData(){ outFile = fopen(outFileName.c_str(), "wb"); //overwrite binary } - fwrite(buffer, nByte, 1, outFile); - outFileSize = ftell(outFile); + if( decimation == 0){ + fwrite(buffer, nByte, 1, outFile); + }else{ + + int Deci = pow(2, decimation); + // printf("Decimation Factor : %d | Deci : %d | nByte %d | nWord %d\n", decimation, Deci, nByte, nByte / 4); + + const size_t chunkSize = 4; + size_t numChunk = nByte / chunkSize; + + uint32_t word = 0; + + int bdAggWordCount = 0; + int groupWordCount = 0; + int chWordCount = 0; + int sampleWordCount = 0; + + int bdAggSize = 0; + int groupAggSize = 0; + int sampleSize = 0; + int chAggSize = 0; + + uint32_t oldHeader1 = 0; + uint32_t oldHeader2 = 0; + uint32_t oldHeader3 = 0; + + uint16_t average = 0; // to calculate Decimation average + + for( size_t i = 0; i < numChunk; i++ ){ + + bdAggWordCount ++; + memcpy(&word, buffer + i * chunkSize, chunkSize); + + if( bdAggWordCount <= 4) { + + if( bdAggWordCount == 1 ) { + bdAggSize = word & 0x0FFFFFFF; + // printf("###################### Bd Agg Size : %d\n", bdAggSize); + } + + // fwrite(buffer + i * chunkSize, sizeof(char), chunkSize, outFile); + // fwrite(&word, sizeof(word), 1, outFile); + + if( bdAggWordCount == 2 ) oldHeader1 = word; + if( bdAggWordCount == 3 ) oldHeader2 = word; + if( bdAggWordCount == 4 ) oldHeader3 = word; + + }else{ + + groupWordCount ++; + + if( groupWordCount == 1 ) { + groupAggSize = word & 0x3FFFFFFF; + // printf("============= Coupled Channel Agg Size : %d \n", groupAggSize); + } + if( groupWordCount == 2 ) { + sampleSize = (word & 0xFFF) * 8; + bool isExtra = ( (word >> 28 ) & 0x1 ); + chAggSize = 2 + sampleSize / 2 + isExtra; + uint32_t newSampleSize = sampleSize / Deci; + // uint32_t oldWord = word; + // word = (word & 0xFFFFF000) + (newSampleSize / 8 ); // change the number of sample + // printf("============= Sample Size : %d | Ch Size : %d | old %08X new %08X\n", sampleSize, chAggSize, oldWord, word); + + int nEvent = (groupAggSize - 2 ) / chAggSize; + int newGroupAggSize = 2 + nEvent * ( 2 + newSampleSize / 2 + isExtra ); + int newBdAggSize = 4 + newGroupAggSize; + + //Write board header and Agg header + uint32_t newHeader0 = (0xA << 28) + newBdAggSize; + fwrite(&newHeader0, sizeof(uint32_t), 1, outFile); + fwrite(&oldHeader1, sizeof(uint32_t), 1, outFile); + fwrite(&oldHeader2, sizeof(uint32_t), 1, outFile); + fwrite(&oldHeader3, sizeof(uint32_t), 1, outFile); + + uint32_t newAggHeader0 = (0x8 << 28) + newGroupAggSize ; // add decimation factor in the word + uint32_t newAggHeader1 = (word & 0xFFFFF000) + (newSampleSize / 8 ) + (decimation << 12); // add decimation factor in the word + fwrite(&newAggHeader0, sizeof(uint32_t), 1, outFile); + fwrite(&newAggHeader1, sizeof(uint32_t), 1, outFile); + + // printf(" New Board Agg Size : %d \n", newBdAggSize); + // printf(" New Group Agg Size : %d \n", newGroupAggSize); + // printf(" nEvent : %d \n", nEvent); + // printf(" New Event Agg Size : %d \n", 2 + sampleSize / Deci / 2 + isExtra); + + // printf("%3d | %08X \n", 1, newHeader0); + // printf("%3d | %08X \n", 2, oldHeader1); + // printf("%3d | %08X \n", 3, oldHeader2); + // printf("%3d | %08X \n", 4, oldHeader3); + // printf("%3d | %3d | %08X \n", 5, 1, newAggHeader0); + // printf("%3d | %3d | %08X \n", 6, 2, newAggHeader1); + } + + if( groupWordCount > 2 ) { + chWordCount ++; + + if( 1 < chWordCount && chWordCount <= chAggSize - 2 ){ // trace + sampleWordCount ++; + uint16_t S0 = word & 0xFFFF; + uint16_t S1 = (word >> 16) & 0xFFFF; + + if( decimation == 1 ){ + average = S0/2 + S1/2; + // printf("%3d | %3d | %3d | %3d | %08X | %4X \n", bdAggWordCount, groupWordCount, chWordCount, sampleWordCount, word, average); + fwrite(&average, sizeof(average), 1, outFile); + }else{ + average += S0/Deci + S1/Deci; + // printf("%3d | %3d | %3d | %3d | %08X | %4X \n", bdAggWordCount, groupWordCount, chWordCount, sampleWordCount, word, average); + if( sampleWordCount % (Deci/2) == 0) { + // fwrite(&S0, sizeof(S0), 1, outFile); + // printf(" --> %4X \n", average); + fwrite(&average, sizeof(average), 1, outFile); + average = 0; + } + } + + }else{ + // printf("%3d | %3d | %3d | %08X \n", bdAggWordCount, groupWordCount, chWordCount, word); + fwrite(&word, sizeof(word), 1, outFile); + } + } + + if( sampleWordCount == sampleSize / 2 ) sampleWordCount = 0; + + if( chAggSize == chWordCount) chWordCount = 0; + + if( groupWordCount == groupAggSize ) groupWordCount = 0; + + } + + if( bdAggWordCount == bdAggSize ) bdAggWordCount = 0; + + } + + } + + outFileSize = ftell(outFile); } + inline void Data::CloseSaveFile(){ if( outFile != nullptr ){ fclose(outFile); @@ -576,7 +715,8 @@ inline unsigned int Data::ReadBuffer(unsigned int nWord, int verbose){ if( buffer == NULL ) return 0; unsigned int word = 0; - for( int i = 0 ; i < 4 ; i++) word += ((buffer[i + 4 * nWord] & 0xFF) << 8*i); + // for( int i = 0 ; i < 4 ; i++) word += ((buffer[i + 4 * nWord] & 0xFF) << 8*i); + memcpy(&word, buffer + 4 * nWord, 4); // Copy 4 bytes directly into word if( verbose >= 2) printf("%6d | 0x%08X |", nWord, word); return word; } @@ -700,6 +840,7 @@ inline int Data::DecodePHADualChannelBlock(unsigned int ChannelMask, bool fastDe bool hasFormatInfo = ((word >> 31) & 0x1); unsigned int aggSize = ( word & 0x7FFFFFFF ) ; if( verbose >= 2 ) printf("Dual Channel size : %d \n", aggSize); + unsigned short decimation = (word >> 12) & 0xF ; unsigned int nSample = 0; /// wave form; unsigned int nEvents = 0; unsigned int extra2Option = 0; @@ -740,6 +881,7 @@ inline int Data::DecodePHADualChannelBlock(unsigned int ChannelMask, bool fastDe } } if( hasWaveForm ){ + printf("Sample Size : %d | Decimation: %d \n", nSample, decimation); printf("...... Analog Probe 1 : "); switch (analogProbe1 ){ case 0 : printf("Input \n"); break; @@ -950,6 +1092,7 @@ inline int Data::DecodePSDDualChannelBlock(unsigned int ChannelMask, bool fastDe unsigned int nEvents = 0; nw = nw + 1; word = ReadBuffer(nw, verbose); + unsigned short decimation = (word >> 12) & 0xF ; unsigned int nSample = ( word & 0xFFFF ) * 8; unsigned int digitalProbe1 = ( (word >> 16 ) & 0x7 ); unsigned int digitalProbe2 = ( (word >> 19 ) & 0x7 ); @@ -979,6 +1122,7 @@ inline int Data::DecodePSDDualChannelBlock(unsigned int ChannelMask, bool fastDe } } if( hasWaveForm ){ + printf("Sample Size : %d | Decimation: %d \n", nSample, decimation); printf(".... digital Probe 1 : "); switch(digitalProbe1){ case 0 : printf("Long gate \n"); break; @@ -1158,6 +1302,7 @@ inline int Data::DecodePSDDualChannelBlock(unsigned int ChannelMask, bool fastDe //*================================================= inline int Data::DecodeQDCGroupedChannelBlock(unsigned int ChannelMask, bool fastDecode, int verbose){ + if( verbose ) printf("########## %s \n", __func__); //nw = nw + 1; unsigned int word = ReadBuffer(nw, verbose); @@ -1169,7 +1314,8 @@ inline int Data::DecodeQDCGroupedChannelBlock(unsigned int ChannelMask, bool fas unsigned int nEvents = 0; nw = nw + 1; word = ReadBuffer(nw, verbose); - unsigned int nSample = ( word & 0xFFFF ) * 8; + unsigned short decimation = (word >> 12) & 0xF ; + unsigned int nSample = ( word & 0xFFF ) * 8; unsigned int analogProbe = ( (word >> 22 ) & 0x3 ); bool hasWaveForm = ( (word >> 27 ) & 0x1 ); bool hasExtra = ( (word >> 28 ) & 0x1 ); @@ -1180,7 +1326,7 @@ inline int Data::DecodeQDCGroupedChannelBlock(unsigned int ChannelMask, bool fas if( verbose >= 2 ) { printf("Charge : %d, Time: %d, Wave : %d, Extra: %d\n", hasEnergy, hasTimeStamp, hasWaveForm, hasExtra); if( hasWaveForm ){ - printf(".... analog Probe (%d): ", analogProbe); + printf("Sample Size : %d | Decimation %d .... analog Probe (%d): ", nSample, decimation, analogProbe); switch(analogProbe){ case 0 : printf("Input\n"); break; case 1 : printf("Smoothed Input\n"); break; @@ -1232,7 +1378,7 @@ inline int Data::DecodeQDCGroupedChannelBlock(unsigned int ChannelMask, bool fas if( verbose >= 3 ){ printf("%4d| %5d, %d, %d, %d, %d \n", 2*wi, (word & 0xFFF) , (( word >> 12 ) & 0x1 ), (( word >> 13 ) & 0x1 ), (( word >> 14 ) & 0x1 ), (( word >> 15 ) & 0x1 )); - printf("%-22s", ""); + printf("%-21s", ""); printf("%4d| %5d, %d, %d, %d, %d \n", 2*wi+1, (( word >> 16) & 0xFFF), (( word >> 28 ) & 0x1 ), (( word >> 29 ) & 0x1 ), (( word >> 30 ) & 0x1 ), (( word >> 31 ) & 0x1 )); } } diff --git a/ClassDigitizer.cpp b/ClassDigitizer.cpp index 1c3bb54..918c0bf 100644 --- a/ClassDigitizer.cpp +++ b/ClassDigitizer.cpp @@ -142,8 +142,31 @@ int Digitizer::OpenDigitizer(int boardID, int portID, bool program, bool verbose NCoupledCh = NumRegChannel; isInputChEqRegCh = false; ModelType = ModelTypeCode::VME; - tick2ns = 16.0; break; ///ns -> 62.5 MSamples/s - } + tick2ns = 16.0; ///ns -> 62.5 MSamples/s + + // std::string ROC = BoardInfo.ROC_FirmwareRel; + // std::size_t pos = ROC.find(" - "); + // std::string versionROCStr = (pos != std::string::npos) ? ROC.substr(0, pos) : ""; + // double versionROC = 0.0; + // if (!versionROCStr.empty()) versionROC = std::stod(versionROCStr); + // printf(" QDC ROC version : %.2f \n", versionROC); + + std::string AMC = BoardInfo.AMC_FirmwareRel; + std::size_t pos = AMC.find(" - "); + std::string versionAMCStr = (pos != std::string::npos) ? AMC.substr(0, pos) : ""; + + double versionAMC = 0.0; + if (!versionAMCStr.empty()) versionAMC = std::stod(versionAMCStr); + + printf(" QDC AMC version : %.2f \n", versionAMC); + if( versionAMC < 135.17 ){ + printf(" QDC AMC version not support OverThreshold Width.\n"); + hasOverThresholdWidth = false; + }else{ + hasOverThresholdWidth = true; + } + + }; break; default : tick2ns = 4.0; break; } @@ -326,183 +349,183 @@ void Digitizer::ProgramBoard(){ if( DPPType == DPPTypeCode::DPP_QDC_CODE ) ProgramBoard_QDC(); } +void Digitizer::ProgramChannel(short chOrGroup){ + if( softwareDisable ) return; + if( AcqRun ) return; + if( DPPType == DPPTypeCode::DPP_PHA_CODE ) ProgramChannel_PHA(chOrGroup); + if( DPPType == DPPTypeCode::DPP_PSD_CODE ) ProgramChannel_PSD(chOrGroup); + if( DPPType == DPPTypeCode::DPP_QDC_CODE ) ProgramChannel_QDC(chOrGroup); +} + int Digitizer::ProgramBoard_PHA(){ DebugPrint("%s", "Digitizer"); - printf("===== Digitizer::%s\n", __func__); - //ret = CAEN_DGTZ_Reset(handle); - Reset(); - ret = CAEN_DGTZ_WriteRegister(handle, DPP::RecordLength_G + 0x7000, 62); + //*========================== Board + /// change address 0xEF08 (5 bits), this will reflected in the 2nd word of the Board Agg. header. + ret = CAEN_DGTZ_WriteRegister(handle, DPP::BoardID, (DPPType & 0xF)); + //WriteRegister(DPP::BoardID, (DPPType & 0xF)); + //ret = CAEN_DGTZ_WriteRegister(handle, DPP::BoardConfiguration, 0x0F8915); /// has Extra2, dual trace, input and trap-baseline - ret = CAEN_DGTZ_WriteRegister(handle, DPP::BoardConfiguration, 0x0E8915); /// has Extra2, no trace + ret |= CAEN_DGTZ_WriteRegister(handle, DPP::BoardConfiguration, 0x0E8915); /// has Extra2, no trace //ret = CAEN_DGTZ_WriteRegister(handle, DPP::BoardConfiguration, 0x0D8115); /// diable Extra2 //TODO change to write register ret = CAEN_DGTZ_SetAcquisitionMode(handle, CAEN_DGTZ_SW_CONTROLLED); /// software command + ret |= CAEN_DGTZ_SetChannelEnableMask(handle, ModelType == ModelTypeCode::VME ? 0xFFFF : 0x00FF); + ret |= CAEN_DGTZ_SetRunSynchronizationMode(handle, CAEN_DGTZ_RUN_SYNC_Disabled); ret |= CAEN_DGTZ_SetIOLevel(handle, CAEN_DGTZ_IOLevel_NIM); ret |= CAEN_DGTZ_SetExtTriggerInputMode(handle, CAEN_DGTZ_TRGMODE_ACQ_ONLY); + ret |= CAEN_DGTZ_WriteRegister(handle, (int32_t)(DPP::GlobalTriggerMask), 0x0); + ret |= CAEN_DGTZ_WriteRegister(handle, (int32_t)(DPP::FrontPanelTRGOUTEnableMask), 0x0); - ret = CAEN_DGTZ_SetChannelEnableMask(handle, ModelType == ModelTypeCode::VME ? 0xFFFF : 0x00FF); - //ret = CAEN_DGTZ_SetNumEventsPerAggregate(handle, 0); - ret = CAEN_DGTZ_SetRunSynchronizationMode(handle, CAEN_DGTZ_RUN_SYNC_Disabled); if( ret != 0 ) { printf("==== set board error.\n"); return 0;} - uint32_t address; - - address = DPP::PHA::DecayTime; ret |= CAEN_DGTZ_WriteRegister(handle, address + 0x7000 , 5000 ); - address = DPP::PHA::TrapezoidFlatTop; ret |= CAEN_DGTZ_WriteRegister(handle, address + 0x7000 , 0x1A ); - address = DPP::PHA::TrapezoidRiseTime; ret |= CAEN_DGTZ_WriteRegister(handle, address + 0x7000 , 6 ); - address = DPP::PHA::PeakingTime; ret |= CAEN_DGTZ_WriteRegister(handle, address + 0x7000 , 6 ); - address = DPP::PHA::RCCR2SmoothingFactor; ret |= CAEN_DGTZ_WriteRegister(handle, address + 0x7000 , 4 ); - address = DPP::PHA::InputRiseTime; ret |= CAEN_DGTZ_WriteRegister(handle, address + 0x7000 , 6 ); - address = DPP::PHA::TriggerThreshold; ret |= CAEN_DGTZ_WriteRegister(handle, address + 0x7000 , 1000 ); - address = DPP::PHA::PeakHoldOff; ret |= CAEN_DGTZ_WriteRegister(handle, address + 0x7000 , 0x3E ); - address = DPP::PHA::TriggerHoldOffWidth; ret |= CAEN_DGTZ_WriteRegister(handle, address + 0x7000 , 0x3E ); - address = DPP::PHA::RiseTimeValidationWindow;ret |= CAEN_DGTZ_WriteRegister(handle, address + 0x7000 , 0x0 ); - - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0x0, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0x1, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0x2, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0x3, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0x4, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0x5, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0x6, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0x7, 0xAAAA); - if( ModelType == ModelTypeCode::VME ){ - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0x8, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0x9, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0xA, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0xB, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0xC, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0xD, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0xE, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0xF, 0xAAAA); - } - - ret |= CAEN_DGTZ_WriteRegister(handle, (uint32_t)(DPP::PreTrigger) + 0x7000 , 32 ); - ret |= CAEN_DGTZ_WriteRegister(handle, (uint32_t)(DPP::InputDynamicRange) + 0x7000 , 0x0 ); - ret |= CAEN_DGTZ_WriteRegister(handle, (int32_t)(DPP::DPPAlgorithmControl) + 0x7000, 0x030200f); - - if( ret != 0 ) { printf("!!!!!!!! set channels error.\n");} - - AutoSetDPPEventAggregation(); - - /// change address 0xEF08 (5 bits), this will reflected in the 2nd word of the Board Agg. header. - ret = CAEN_DGTZ_WriteRegister(handle, DPP::BoardID, (DPPType & 0xF)); - //WriteRegister(DPP::BoardID, (DPPType & 0xF)); + //*========================== Group + ProgramChannel_PHA(-1); isSettingFilledinMemeory = false; /// unlock the ReadAllSettingsFromBoard(); - usleep(1000*300); - ReadAllSettingsFromBoard(); return ret; } +int Digitizer::ProgramChannel_PHA(short ch){ + DebugPrint("%s", "Digitizer"); + printf("===== Digitizer::%s|ch:%d\n", __func__,ch); + + uint32_t channel = (ch << 8); + if( ch < 0 ) channel = 0x7000; + + uint32_t address = (ch << 8); + + address = channel + DPP::RecordLength_G; ret = CAEN_DGTZ_WriteRegister(handle, address, 62); + address = channel + DPP::PHA::DecayTime; ret |= CAEN_DGTZ_WriteRegister(handle, address, 5000 ); + address = channel + DPP::PHA::TrapezoidFlatTop; ret |= CAEN_DGTZ_WriteRegister(handle, address, 0x1A ); + address = channel + DPP::PHA::TrapezoidRiseTime; ret |= CAEN_DGTZ_WriteRegister(handle, address, 6 ); + address = channel + DPP::PHA::PeakingTime; ret |= CAEN_DGTZ_WriteRegister(handle, address, 6 ); + address = channel + DPP::PHA::RCCR2SmoothingFactor; ret |= CAEN_DGTZ_WriteRegister(handle, address, 4 ); + address = channel + DPP::PHA::InputRiseTime; ret |= CAEN_DGTZ_WriteRegister(handle, address, 6 ); + address = channel + DPP::PHA::TriggerThreshold; ret |= CAEN_DGTZ_WriteRegister(handle, address, 1000 ); + address = channel + DPP::PHA::PeakHoldOff; ret |= CAEN_DGTZ_WriteRegister(handle, address, 0x3E ); + address = channel + DPP::PHA::TriggerHoldOffWidth; ret |= CAEN_DGTZ_WriteRegister(handle, address, 0x3E ); + address = channel + DPP::PHA::RiseTimeValidationWindow;ret |= CAEN_DGTZ_WriteRegister(handle, address, 0x0 ); + address = channel + DPP::PreTrigger; ret |= CAEN_DGTZ_WriteRegister(handle, address, 32 ); + address = channel + DPP::InputDynamicRange; ret |= CAEN_DGTZ_WriteRegister(handle, address, 0x0 ); + address = channel + DPP::DPPAlgorithmControl; ret |= CAEN_DGTZ_WriteRegister(handle, address, 0x030200f); + address = channel + DPP::PHA::DPPAlgorithmControl2_G; ret |= CAEN_DGTZ_WriteRegister(handle, address, 0x200); // use fine time + + if( ch >= 0 ) { + ret |= CAEN_DGTZ_SetChannelDCOffset(handle, ch, 0xAAAA); + }else{ + for( int i = 0; i < NumRegChannel; i ++ ){ + ret |= CAEN_DGTZ_SetChannelDCOffset(handle, i, 0xAAAA); + } + } + + if( ret != 0 ) { printf("!!!!!!!! set channels error.\n");} + + AutoSetDPPEventAggregation(); + + if( ch >= 0 ){ + isSettingFilledinMemeory = false; + usleep(1000*300); + ReadAllSettingsFromBoard(); + } + + return ret; +} + int Digitizer::ProgramBoard_PSD(){ + DebugPrint("%s", "Digitizer"); printf("===== Digitizer::%s\n", __func__); //ret = CAEN_DGTZ_Reset(handle); Reset(); - //ret = CAEN_DGTZ_WriteRegister(handle, DPP::BoardConfiguration, 0x0F0115); /// has Extra2, dual trace, input and CFD - ret = CAEN_DGTZ_WriteRegister(handle, DPP::BoardConfiguration, 0x0E0115); /// has Extra2, no trace - - ret = CAEN_DGTZ_SetAcquisitionMode(handle, CAEN_DGTZ_SW_CONTROLLED); /// software command - ret |= CAEN_DGTZ_SetIOLevel(handle, CAEN_DGTZ_IOLevel_NIM); - ret |= CAEN_DGTZ_SetExtTriggerInputMode(handle, CAEN_DGTZ_TRGMODE_ACQ_ONLY); - - ret |= CAEN_DGTZ_SetChannelEnableMask(handle, 0xFFFF); - - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0x0, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0x1, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0x2, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0x3, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0x4, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0x5, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0x6, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0x7, 0xAAAA); - if( ModelType == ModelTypeCode::VME ){ - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0x8, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0x9, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0xA, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0xB, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0xC, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0xD, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0xE, 0xAAAA); - ret |= CAEN_DGTZ_SetChannelDCOffset(handle, 0xF, 0xAAAA); - } - - ret |= CAEN_DGTZ_WriteRegister(handle, (uint32_t)(DPP::PSD::DPPAlgorithmControl2_G) + 0x7000 , 0x00000200 ); // use fine time - - ret |= CAEN_DGTZ_WriteRegister(handle, (uint32_t)(DPP::DPPAlgorithmControl) + 0x7000 , 0x00100000 ); // baseline 16 sample - - ret |= CAEN_DGTZ_WriteRegister(handle, (uint32_t)(DPP::PSD::TriggerThreshold) + 0x7000 , 100 ); - - ret |= CAEN_DGTZ_WriteRegister(handle, (uint32_t)(DPP::PreTrigger) + 0x7000 , 20 ); - ret |= CAEN_DGTZ_WriteRegister(handle, (uint32_t)(DPP::RecordLength_G) + 0x7000 , 80 ); - - ret |= CAEN_DGTZ_WriteRegister(handle, (uint32_t)(DPP::PSD::ShortGateWidth) + 0x7000 , 32 ); - ret |= CAEN_DGTZ_WriteRegister(handle, (uint32_t)(DPP::PSD::LongGateWidth) + 0x7000 , 64 ); - ret |= CAEN_DGTZ_WriteRegister(handle, (uint32_t)(DPP::PSD::GateOffset) + 0x7000 , 19 ); - - if( ret != 0 ) { printf("!!!!!!!! set channels error.\n");} - + //*========================== Board /// change address 0xEF08 (5 bits), this will reflected in the 2nd word of the Board Agg. header. ret = CAEN_DGTZ_WriteRegister(handle, DPP::BoardID, (DPPType & 0xF)); //WriteRegister(DPP::BoardID, (DPPType & 0xF)); - AutoSetDPPEventAggregation(); + //ret = CAEN_DGTZ_WriteRegister(handle, DPP::BoardConfiguration, 0x0F0115); /// has Extra2, dual trace, input and CFD + ret |= CAEN_DGTZ_WriteRegister(handle, DPP::BoardConfiguration, 0x0E0115); /// has Extra2, no trace + ret |= CAEN_DGTZ_SetAcquisitionMode(handle, CAEN_DGTZ_SW_CONTROLLED); /// software command + ret |= CAEN_DGTZ_SetIOLevel(handle, CAEN_DGTZ_IOLevel_NIM); + ret |= CAEN_DGTZ_SetExtTriggerInputMode(handle, CAEN_DGTZ_TRGMODE_ACQ_ONLY); + ret |= CAEN_DGTZ_WriteRegister(handle, (int32_t)(DPP::GlobalTriggerMask), 0x0); + ret |= CAEN_DGTZ_WriteRegister(handle, (int32_t)(DPP::FrontPanelTRGOUTEnableMask), 0x0); + + ret |= CAEN_DGTZ_SetChannelEnableMask(handle, 0xFFFF); + + //*========================== Group + ProgramChannel_PSD(-1); isSettingFilledinMemeory = false; /// unlock the ReadAllSettingsFromBoard(); - usleep(1000*300); - ReadAllSettingsFromBoard(); + + return ret; +} + +int Digitizer::ProgramChannel_PSD(short ch){ + DebugPrint("%s", "Digitizer"); + printf("===== Digitizer::%s|ch:%d\n", __func__,ch); + + uint32_t channel = (ch << 8); + if( ch < 0 ) channel = 0x7000; + uint32_t address = (ch << 8); + + address = channel + DPP::PSD::DPPAlgorithmControl2_G; ret = CAEN_DGTZ_WriteRegister(handle, address, 0x00000200 ); // use fine time + address = channel + DPP::DPPAlgorithmControl; ret |= CAEN_DGTZ_WriteRegister(handle, address, 0x00100003 ); // baseline 16 sample, 320fC + address = channel + DPP::PSD::TriggerThreshold; ret |= CAEN_DGTZ_WriteRegister(handle, address, 100 ); + address = channel + DPP::PreTrigger; ret |= CAEN_DGTZ_WriteRegister(handle, address, 20 ); + address = channel + DPP::RecordLength_G; ret |= CAEN_DGTZ_WriteRegister(handle, address, 80 ); + address = channel + DPP::PSD::ShortGateWidth; ret |= CAEN_DGTZ_WriteRegister(handle, address, 32 ); + address = channel + DPP::PSD::LongGateWidth; ret |= CAEN_DGTZ_WriteRegister(handle, address, 64 ); + address = channel + DPP::PSD::GateOffset; ret |= CAEN_DGTZ_WriteRegister(handle, address, 19 ); + + if( ch >= 0 ) { + ret |= CAEN_DGTZ_SetChannelDCOffset(handle, ch, 0xAAAA); + }else{ + for( int i = 0; i < NumRegChannel; i ++ ){ + ret |= CAEN_DGTZ_SetChannelDCOffset(handle, i, 0xAAAA); + } + } + + if( ret != 0 ) { printf("!!!!!!!! set channels error.\n");} + + AutoSetDPPEventAggregation(); + + if( ch >= 0 ){ + isSettingFilledinMemeory = false; + usleep(1000*300); + ReadAllSettingsFromBoard(); + } + return ret; } int Digitizer::ProgramBoard_QDC(){ + DebugPrint("%s", "Digitizer"); printf("===== Digitizer::%s\n", __func__); Reset(); int ret = 0; + //*========================== Board + /// change address 0xEF08 (5 bits), this will reflected in the 2nd word of the Board Agg. header. + ret = CAEN_DGTZ_WriteRegister(handle, DPP::BoardID, (DPPType & 0xF)); + //WriteRegister(DPP::BoardID, (DPPType & 0xF)); + //WriteRegister(DPP::QDC::NumberEventsPerAggregate, 0x10, -1); WriteRegister(DPP::QDC::RecordLength_W, 16, -1); // 128 sample = 2048 ns - WriteRegister(DPP::QDC::PreTrigger, 60, -1); // at 60 sample = 960 ns - - WriteRegister(DPP::QDC::GateWidth, 100/16, -1); - WriteRegister(DPP::QDC::GateOffset, 0, -1); - WriteRegister(DPP::QDC::FixedBaseline, 0, -1); - - //WriteRegister(DPP::QDC::DPPAlgorithmControl, 0x300112); // with test pulse, positive - //WriteRegister(DPP::QDC::DPPAlgorithmControl, 0x300102); // No test pulse, positive - WriteRegister(DPP::QDC::DPPAlgorithmControl, 0x310102); // No test pulse, negative - - WriteRegister(DPP::QDC::TriggerHoldOffWidth, 100/16, -1); - WriteRegister(DPP::QDC::TRGOUTWidth, 100/16, -1); - //WriteRegister(DPP::QDC::OverThresholdWidth, 100/16, -1); - WriteRegister(DPP::QDC::SubChannelMask, 0xFF, -1); - - WriteRegister(DPP::QDC::DCOffset, 0xAAAA, -1); - - WriteRegister(DPP::QDC::TriggerThreshold_sub0, 100, -1); - WriteRegister(DPP::QDC::TriggerThreshold_sub1, 100, -1); - WriteRegister(DPP::QDC::TriggerThreshold_sub2, 100, -1); - WriteRegister(DPP::QDC::TriggerThreshold_sub3, 100, -1); - WriteRegister(DPP::QDC::TriggerThreshold_sub4, 100, -1); - WriteRegister(DPP::QDC::TriggerThreshold_sub5, 100, -1); - WriteRegister(DPP::QDC::TriggerThreshold_sub6, 100, -1); - WriteRegister(DPP::QDC::TriggerThreshold_sub7, 100, -1); - WriteRegister(DPP::BoardConfiguration, 0xE0110); //WriteRegister(DPP::AggregateOrganization, 0x0); //WriteRegister(DPP::MaxAggregatePerBlockTransfer, 100); @@ -512,18 +535,55 @@ int Digitizer::ProgramBoard_QDC(){ WriteRegister(DPP::FrontPanelIOControl, 0x0); WriteRegister(DPP::QDC::GroupEnableMask, 0xFF); - /// change address 0xEF08 (5 bits), this will reflected in the 2nd word of the Board Agg. header. - ret = CAEN_DGTZ_WriteRegister(handle, DPP::BoardID, (DPPType & 0xF)); - //WriteRegister(DPP::BoardID, (DPPType & 0xF)); + //*========================== Group + ProgramChannel_QDC(-1); + + isSettingFilledinMemeory = false; /// unlock the ReadAllSettingsFromBoard(); + usleep(1000*300); + ReadAllSettingsFromBoard(); + + return ret; + +} + +int Digitizer::ProgramChannel_QDC(short group){ + + printf("===== Digitizer::%s|ch:%d\n", __func__,group); + + WriteRegister(DPP::QDC::PreTrigger, 60, group); // at 60 sample = 960 ns + WriteRegister(DPP::QDC::GateWidth, 100/16, group); + WriteRegister(DPP::QDC::GateOffset, 0, group); + WriteRegister(DPP::QDC::FixedBaseline, 0, group); + + //WriteRegister(DPP::QDC::DPPAlgorithmControl, 0x300112); // with test pulse, positive + //WriteRegister(DPP::QDC::DPPAlgorithmControl, 0x300102); // No test pulse, positive + WriteRegister(DPP::QDC::DPPAlgorithmControl, 0x310102); // No test pulse, negative + + WriteRegister(DPP::QDC::TriggerHoldOffWidth, 100/16, group); + WriteRegister(DPP::QDC::TRGOUTWidth, 100/16, group); + //WriteRegister(DPP::QDC::OverThresholdWidth, 100/16, group); + WriteRegister(DPP::QDC::SubChannelMask, 0xFF, group); + + WriteRegister(DPP::QDC::DCOffset, 0xAAAA, group); + + WriteRegister(DPP::QDC::TriggerThreshold_sub0, 100, group); + WriteRegister(DPP::QDC::TriggerThreshold_sub1, 100, group); + WriteRegister(DPP::QDC::TriggerThreshold_sub2, 100, group); + WriteRegister(DPP::QDC::TriggerThreshold_sub3, 100, group); + WriteRegister(DPP::QDC::TriggerThreshold_sub4, 100, group); + WriteRegister(DPP::QDC::TriggerThreshold_sub5, 100, group); + WriteRegister(DPP::QDC::TriggerThreshold_sub6, 100, group); + WriteRegister(DPP::QDC::TriggerThreshold_sub7, 100, group); AutoSetDPPEventAggregation(); - isSettingFilledinMemeory = false; /// unlock the ReadAllSettingsFromBoard(); + if( group >= 0 ){ + isSettingFilledinMemeory = false; + usleep(1000*300); + ReadAllSettingsFromBoard(); + } - usleep(1000*300); - ReadAllSettingsFromBoard(); return ret; - } //========================================================= ACQ control @@ -576,7 +636,7 @@ void Digitizer::StartACQ(){ data->ClearTriggerRate(); data->ClearData(); - if( DPPType == DPPTypeCode::DPP_QDC_CODE ) SetOptimialAggOrg(); + if( DPPType == DPPTypeCode::DPP_QDC_CODE ) SetQDCOptimialAggOrg(); printf(" ACQ mode : %s (%d), TRG-OUT mode : %s (%d) \n", acqStr.c_str(), acqID, trgOutStr.c_str(), trgOutID); @@ -740,9 +800,12 @@ void Digitizer::WriteRegister (Reg registerAddress, uint32_t value, int ch, bool } if( registerAddress.GetRWType() == RW::ReadONLY ) return; + if( !hasOverThresholdWidth && registerAddress == DPP::QDC::OverThresholdWidth ) return ; ret = CAEN_DGTZ_WriteRegister(handle, registerAddress.ActualAddress(ch), value); + if( registerAddress == DPP::DecimationFactor ) data->SetDecimationFactor(value); + if( ret == 0 && isSave2MemAndFile && !AcqRun && registerAddress.GetRWType() == RW::ReadWrite ) { if( ch < 0 ) { if( registerAddress.GetAddress() < 0x8000 ){ @@ -782,6 +845,8 @@ uint32_t Digitizer::ReadRegister(Reg registerAddress, unsigned short ch, bool is if( registerAddress.GetRWType() == RW::WriteONLY ) return 0; // if( registerAddress == DPP::QDC::RecordLength_W ) return 0; + if( !hasOverThresholdWidth && registerAddress == DPP::QDC::OverThresholdWidth ) return 0; + ret = CAEN_DGTZ_ReadRegister(handle, registerAddress.ActualAddress(ch), &returnData); if( ret == 0 && isSave2MemAndFile && !AcqRun) { @@ -790,6 +855,8 @@ uint32_t Digitizer::ReadRegister(Reg registerAddress, unsigned short ch, bool is SaveSettingToFile(registerAddress, returnData, ch); } + if( registerAddress == DPP::DecimationFactor ) data->SetDecimationFactor( returnData ); + std::stringstream ss; ss << std::hex << registerAddress.ActualAddress(ch); @@ -995,6 +1062,8 @@ void Digitizer::ProgramSettingsToBoard(){ haha = DPP::QDC::RecordLength_W; WriteRegister(haha, GetSettingFromMemory(haha), -1, false); // haha = DPP::QDC::NumberEventsPerAggregate; WriteRegister(haha, GetSettingFromMemory(haha), -1, false); + haha = DPP::DecimationFactor; WriteRegister(haha, GetSettingFromMemory(haha), -1, false); + /// Channels Setting for( int ch = 0; ch < GetNumRegChannels(); ch ++){ for( int p = 0; p < (int) RegisterChannelList_QDC.size(); p++){ @@ -1345,7 +1414,50 @@ void Digitizer::SetBits(Reg address, unsigned int bitValue, unsigned int bitLeng if( ret != 0 ) ErrorMsg(__func__); } -void Digitizer::SetOptimialAggOrg(){ +void Digitizer::AutoSetDPPEventAggregation(){ + //ret = CAEN_DGTZ_SetDPPAcquisitionMode(handle, CAEN_DGTZ_DPP_ACQ_MODE_List, CAEN_DGTZ_DPP_SAVE_PARAM_EnergyAndTime); + + // if( DPPType == DPPTypeCode::DPP_QDC_CODE ){ + + // }else{ + + // for( int ch = 0; ch < GetNumInputCh(); ch += 2 ){ + // uint32_t a1, a2; + // ret |= CAEN_DGTZ_GetRecordLength(handle, &a1, ch); + // ret |= CAEN_DGTZ_GetNumEventsPerAggregate(handle, &a2, ch); + // printf("Ch %2d | RecordLength : %d | Event Agg : %d \n", ch, a1, a2); + // } + + // uint32_t chMask ; + // ret |= CAEN_DGTZ_GetChannelEnableMask(handle, &chMask); + // printf("Ch Mask %0X \n", chMask); + + // } + + ret = 0; + ret |= CAEN_DGTZ_SetDPPEventAggregation(handle, 0, 0); // AutoSet + if( ret != 0 ) { + printf("!!!!!!!! set %s error.\n", __func__); + }else{ + Reg regAdd = DPP::AggregateOrganization; + uint32_t haha = ReadRegister(regAdd); + SetSettingToMemory(regAdd, haha, 0); + SaveSettingToFile(regAdd, haha, 0); + } +} + +uint32_t Digitizer::ReadQDCRecordLength() { + returnData = ReadRegister(DPP::QDC::RecordLength_R); + Reg temp = DPP::QDC::RecordLength_R; + int indexR = temp.Index(0); + temp = DPP::QDC::RecordLength_W; + int indexW = temp.Index(0); + setting[indexW] = setting[indexR]; + //printf("%d %d | %u %u \n", indexR, indexW, setting[indexR], setting[indexW]); + return returnData; +} + +void Digitizer::SetQDCOptimialAggOrg(){ DebugPrint("%s", "Digitizer"); if( DPPType != DPPTypeCode::DPP_QDC_CODE ) { printf("%s | this method only support QDC board.\n", __func__); @@ -1367,7 +1479,7 @@ void Digitizer::SetOptimialAggOrg(){ printf("=================================== Setting related to Buffer\n"); printf(" agg. orgainzation (bit) : 0x%X \n", aggOrgan); - printf(" Channel Mask : %04X \n", chMask); + printf(" Channel Mask : %08X \n", chMask); printf("Max number of Agg per Readout : %u \n", AggRead); printf(" is Extra enabed : %u \n", Ex ); printf(" is Record wave : %u \n", traceOn ); diff --git a/ClassDigitizer.h b/ClassDigitizer.h index 6087493..36bc628 100644 --- a/ClassDigitizer.h +++ b/ClassDigitizer.h @@ -60,6 +60,7 @@ class Digitizer{ bool isSettingFileExist; /// bool isSettingFileUpdate; bool isSettingFilledinMemeory; /// false for disabled ReadAllSettingFromBoard() + bool hasOverThresholdWidth; /// for QDC unsigned int setting[SETTINGSIZE]; /// Setting, 4bytes x 2048 = 8192 bytes //^-------- other protected functions @@ -73,6 +74,10 @@ class Digitizer{ int ProgramBoard_PSD() ; int ProgramBoard_QDC() ; + int ProgramChannel_PHA(short ch) ; /// program a default PHA Channel for Si-detector, ch = -1 for all channel + int ProgramChannel_PSD(short ch) ; /// program a default PSD Channel for Si-detector, ch = -1 for all channel + int ProgramChannel_QDC(short group) ; /// program a default QDC group for Si-detector, ch = -1 for all group + public: Digitizer(); /// no digitizer open Digitizer(int boardID, int portID = 0, bool program = false, bool verbose = false); @@ -95,12 +100,9 @@ class Digitizer{ void PrintBoard(); void ProgramBoard(); - void AutoSetDPPEventAggregation(){ - //ret = CAEN_DGTZ_SetDPPAcquisitionMode(handle, CAEN_DGTZ_DPP_ACQ_MODE_List, CAEN_DGTZ_DPP_SAVE_PARAM_EnergyAndTime); - ret |= CAEN_DGTZ_SetNumEventsPerAggregate(handle, 10); - ret |= CAEN_DGTZ_SetDPPEventAggregation(handle, 0, 0); // AutoSet - if( ret != 0 ) { printf("!!!!!!!! set %s error.\n", __func__);} - } + void ProgramChannel(short chOrGroup); + + void AutoSetDPPEventAggregation(); //^================ ACQ control void StopACQ(); @@ -151,6 +153,7 @@ class Digitizer{ int GetErrorCode() const {return ret;} unsigned int GetChMemSizekSample() const {return MemorySizekSample;} std::string GetFamilyName() const {return familyName;} + bool HasOverThresholdWidth_QDC() const {return hasOverThresholdWidth;} //^================ Setting Reg FindRegister(uint32_t address); @@ -192,19 +195,9 @@ class Digitizer{ bool IsDualTrace_PHA() {return ( (GetSettingFromMemory(DPP::BoardConfiguration) >> 11) & 0x1 );} bool IsRecordTrace() {return ( (GetSettingFromMemory(DPP::BoardConfiguration) >> 16) & 0x1 );} - void SetOptimialAggOrg(); - //QDC read recordLength - uint32_t ReadQDCRecordLength() { - returnData = ReadRegister(DPP::QDC::RecordLength_R); - Reg temp = DPP::QDC::RecordLength_R; - int indexR = temp.Index(0); - temp = DPP::QDC::RecordLength_W; - int indexW = temp.Index(0); - setting[indexW] = setting[indexR]; - //printf("%d %d | %u %u \n", indexR, indexW, setting[indexR], setting[indexW]); - return returnData; - } + uint32_t ReadQDCRecordLength(); + void SetQDCOptimialAggOrg(); void SetTrace(bool onOff){ SetBits(DPP::BoardConfiguration, DPP::Bit_BoardConfig::RecordTrace, onOff, -1); diff --git a/CustomWidgets.h b/CustomWidgets.h index 6d0ccda..ff13ba5 100644 --- a/CustomWidgets.h +++ b/CustomWidgets.h @@ -130,7 +130,7 @@ protected: QAction *selectedAction = menu->exec(event->globalPosition().toPoint()); if( selectedAction == a1 ) { chart()->zoomReset(); - chart()->axes(Qt::Vertical).first()->setRange(-(0x3FFF), 0x3FFF); + // chart()->axes(Qt::Vertical).first()->setRange(-(0x3FFF), 0x3FFF); } } @@ -169,7 +169,7 @@ protected: case Qt::Key_Down: chart()->scroll(0, -10); break; case Qt::Key_R : chart()->zoomReset(); - chart()->axes(Qt::Vertical).first()->setRange(-(0x3FFF), 0x3FFF); + // chart()->axes(Qt::Vertical).first()->setRange(-(0x3FFF), 0x3FFF); break; default: QGraphicsView::keyPressEvent(event); break; } diff --git a/DigiSettingsPanel.cpp b/DigiSettingsPanel.cpp index 264a8a2..0c66b11 100644 --- a/DigiSettingsPanel.cpp +++ b/DigiSettingsPanel.cpp @@ -257,6 +257,8 @@ DigiSettingsPanel::DigiSettingsPanel(Digitizer ** digi, unsigned int nDigi, QStr SendLogMsg("Digi-" +QString::number(digi[ID]->GetSerialNumber()) + " : AutoSetDPPEventAggregation()"); digi[ID]->AutoSetDPPEventAggregation(); UpdateBoardAndChannelsStatus(); + UpdatePanelFromMemory(); + emit UpdateOtherPanels(); }); // bnSendSoftwareClockSyncSignal = new QPushButton("Send SW Clock-Sync Signal", this); @@ -352,6 +354,7 @@ DigiSettingsPanel::DigiSettingsPanel(Digitizer ** digi, unsigned int nDigi, QStr } SetUpInquiryCopyTab(); + CheckRadioAndCheckedButtons(); connect(tabWidget, &QTabWidget::currentChanged, this, [=](int index){ if( index < (int) nDigi) { @@ -404,7 +407,13 @@ void DigiSettingsPanel::SetUpCheckBox(QCheckBox * &chkBox, QString label, QGridL if( !enableSignalSlot ) return; int chID = ch < 0 ? chSelection[ID]->currentData().toInt() : ch; - digi[ID]->SetBits(para, bit, state ? 1 : 0, chID); + + if( para == DPP::DisableExternalTrigger ) { + digi[ID]->SetBits(para, bit, state ? 0 : 1, chID); + }else{ + digi[ID]->SetBits(para, bit, state ? 1 : 0, chID); + } + if( para.IsCoupled() == true && chID >= 0 ) digi[ID]->SetBits(para, bit, state ? 1 : 0, chID%2 == 0 ? chID + 1 : chID - 1); UpdatePanelFromMemory(); emit UpdateOtherPanels(); @@ -548,6 +557,16 @@ void DigiSettingsPanel::SetUpSpinBox(RSpinBox * &sb, QString label, QGridLayout return; } + if( para == DPP::DecimationFactor ){ + int deci = pow(2, sb->value()); + if( sbRecordLength[ID][0]->value() / digi[ID]->GetTick2ns() <= 2 * deci ){ + SendLogMsg("Tried to set waveform decimation to be " + QString::number(deci) + ", which make the number of trace less than 2. Abort."); + sbSWDecimation[ID]->setValue(0); + }else{ + SendLogMsg("Set waveform decimation to be " + QString::number(deci) + "."); + } + } + uint32_t bit = para.GetPartialStep() == -1 ? sb->value() : sb->value() / para.GetPartialStep() / digi[ID]->GetTick2ns(); if( para.IsCoupled() == true && chID >= 0 ) { @@ -612,6 +631,11 @@ void DigiSettingsPanel::SetUpGlobalTriggerMaskAndFrontPanelMask(QGridLayout * & }); SetUpCheckBox(chkEnableExternalTrigger[ID], "Enable TRG-IN ", gLayout, 1, 1, DPP::DisableExternalTrigger, {1, 0}); + + connect(chkEnableExternalTrigger[ID], &QCheckBox::stateChanged, this, [=](int state){ + cbTRGINMode[ID]->setEnabled(state); + cbTRINMezzanines[ID]->setEnabled(state); + }); ///============================ Trig In mode QLabel * trgInMode = new QLabel("TRI-In Mode ", this); @@ -638,18 +662,13 @@ void DigiSettingsPanel::SetUpGlobalTriggerMaskAndFrontPanelMask(QGridLayout * & cbTRINMezzanines[ID] = new RComboBox(this); gLayout->addWidget(cbTRINMezzanines[ID], 3, 1, 1, 2); - items = DPP::Bit_FrontPanelIOControl::ListTRGIMezzanine; + items = DPP::Bit_FrontPanelIOControl::ListTRGINMezzanine; for(int i = 0; i < (int) items.size(); i++){ cbTRINMezzanines[ID]->addItem(QString::fromStdString(items[i].first), items[i].second); } connect( cbTRINMezzanines[ID], &RComboBox::currentIndexChanged, this, [=](int index){ if( !enableSignalSlot ) return; - digi[ID]->SetBits(DPP::FrontPanelIOControl, DPP::Bit_FrontPanelIOControl::TRGINMode, index, -1); - }); - - connect(chkEnableExternalTrigger[ID], &QCheckBox::stateChanged, this, [=](int state){ - cbTRGINMode[ID]->setEnabled(state); - cbTRINMezzanines[ID]->setEnabled(state); + digi[ID]->SetBits(DPP::FrontPanelIOControl, DPP::Bit_FrontPanelIOControl::TRGINMezzanine, index, -1); }); SetUpComboBox(cbAnalogMonitorMode[ID], "Analog Monitor Mode ", gLayout, 4, 0, DPP::AnalogMonitorMode, 0); @@ -1315,6 +1334,7 @@ void DigiSettingsPanel::SetUpInquiryCopyTab(){ std::vector regList; if( digi[fromIndex]->GetDPPType() == V1730_DPP_PHA_CODE ) regList = RegisterChannelList_PHA; if( digi[fromIndex]->GetDPPType() == V1730_DPP_PSD_CODE ) regList = RegisterChannelList_PSD; + if( digi[fromIndex]->GetDPPType() == V1740_DPP_QDC_CODE ) regList = RegisterChannelList_QDC; int fromCh = -1; for( int i = 0; i < MaxRegChannel; i++) { @@ -1326,8 +1346,13 @@ void DigiSettingsPanel::SetUpInquiryCopyTab(){ if( fromCh == -1 ) return; + printf("Copy Digi-%d, ch %d \n", digi[fromIndex]->GetSerialNumber(), fromCh); + for( int i = 0; i < MaxRegChannel; i++){ - if( ! chkCh[i]->isChecked() ) return; + + if( !chkCh[i]->isChecked() || !chkCh[i]->isEnabled() ) continue; + + printf("... to Digi-%d, ch %d \n", digi[toIndex]->GetSerialNumber(), i); //Copy setting for( int k = 0; k < (int) regList.size(); k ++){ if( regList[k].GetRWType() != RW::ReadWrite ) continue; @@ -1537,12 +1562,13 @@ void DigiSettingsPanel::SetUpChannel_PHA(){ QWidget * jaja = new QWidget(this); allSettingLayout->addWidget(jaja); - QHBoxLayout * papa = new QHBoxLayout(jaja); - papa->setAlignment(Qt::AlignLeft); const unsigned short numChannel = digi[ID]->GetNumRegChannels(); {//^============================== Channel selection + QHBoxLayout * papa = new QHBoxLayout(jaja); + papa->setAlignment(Qt::AlignLeft); + QLabel * lbChSel = new QLabel ("Channel : ", this); lbChSel->setAlignment(Qt::AlignCenter | Qt::AlignRight); papa->addWidget(lbChSel); @@ -1555,6 +1581,16 @@ void DigiSettingsPanel::SetUpChannel_PHA(){ connect(chSelection[ID], &RComboBox::currentIndexChanged, this, [=](){ SyncAllChannelsTab_PHA(); }); + + bnProgramChannel[ID] = new QPushButton("Program Default Channel Settings",this); + papa->addWidget(bnProgramChannel[ID]); + connect(bnProgramChannel[ID], &QPushButton::clicked, this, [=](){ + short ch = chSelection[ID]->currentData().toInt(); + digi[ID]->ProgramChannel(ch); + digi[ID]->ReadAllSettingsFromBoard(true); + UpdatePanelFromMemory(); + emit UpdateOtherPanels(); + }); } {//*========================= input @@ -1792,7 +1828,7 @@ void DigiSettingsPanel::SetUpChannel_PHA(){ QLabel * lb2 = new QLabel("Local Shaped Trig. [G]", this); lb2->setAlignment(Qt::AlignHCenter); tabLayout->addWidget(lb2, 0, 4); QLabel * lb1 = new QLabel("Trig. Counter Flag [G]", this); lb1->setAlignment(Qt::AlignHCenter); tabLayout->addWidget(lb1, 0, 6); } - SetUpSpinBox(sbShapedTrigWidth[ID][ch], "", tabLayout, ch + 1, 1, DPP::PSD::ShapedTriggerWidth, ch); + SetUpSpinBox(sbShapedTrigWidth[ID][ch], "", tabLayout, ch + 1, 1, DPP::PHA::ShapedTriggerWidth, ch); SetUpComboBoxBit(cbLocalShapedTrigger[ID][ch], "", tabLayout, ch + 1, 3, DPP::PHA::Bit_DPPAlgorithmControl2::ListLocalShapeTrigMode, DPP::PHA::DPPAlgorithmControl2_G, DPP::PHA::Bit_DPPAlgorithmControl2::LocalShapeTriggerMode, 1, ch); SetUpComboBoxBit(cbTrigCount[ID][ch], "", tabLayout, ch + 1, 5, DPP::PHA::Bit_DPPAlgorithmControl2::ListTrigCounter, DPP::PHA::DPPAlgorithmControl2_G, DPP::PHA::Bit_DPPAlgorithmControl2::TriggerCounterFlag, 1, ch); SetUpCheckBox(chkTagCorrelation[ID][ch], "Tag Correlated events [G]", tabLayout, ch + 1, 7, DPP::PHA::DPPAlgorithmControl2_G, DPP::PHA::Bit_DPPAlgorithmControl2::TagCorrelatedEvents, ch); @@ -1986,12 +2022,12 @@ void DigiSettingsPanel::SetUpChannel_PSD(){ QWidget * jaja = new QWidget(this); allSettingLayout->addWidget(jaja); - QHBoxLayout * papa = new QHBoxLayout(jaja); - papa->setAlignment(Qt::AlignLeft); - const unsigned short numChannel = digi[ID]->GetNumRegChannels(); {//^============================== Channel selection + QHBoxLayout * papa = new QHBoxLayout(jaja); + papa->setAlignment(Qt::AlignLeft); + QLabel * lbChSel = new QLabel ("Ch : ", this); lbChSel->setAlignment(Qt::AlignCenter | Qt::AlignRight); papa->addWidget(lbChSel); @@ -2004,6 +2040,16 @@ void DigiSettingsPanel::SetUpChannel_PSD(){ connect(chSelection[ID], &RComboBox::currentIndexChanged, this, [=](){ SyncAllChannelsTab_PSD(); }); + + bnProgramChannel[ID] = new QPushButton("Program Default Channel Settings",this); + papa->addWidget(bnProgramChannel[ID]); + connect(bnProgramChannel[ID], &QPushButton::clicked, this, [=](){ + short ch = chSelection[ID]->currentData().toInt(); + digi[ID]->ProgramChannel(ch); + digi[ID]->ReadAllSettingsFromBoard(true); + UpdatePanelFromMemory(); + emit UpdateOtherPanels(); + }); } {//*=============== input @@ -2534,6 +2580,10 @@ void DigiSettingsPanel::SetUpBoard_QDC(){ SetUpSpinBox(sbNumEventAgg[ID][0], "Event pre Agg. : ", bdCfgLayout[ID], 5, 0, DPP::QDC::NumberEventsPerAggregate, -1, true); SetUpSpinBox(sbRecordLength[ID][0], "Record Length [ns] : ", bdCfgLayout[ID], 6, 0, DPP::QDC::RecordLength_W, -1, true); + SetUpSpinBox( sbSWDecimation[ID], "SW Decimation Factor : ", bdCfgLayout[ID], 7, 0, DPP::DecimationFactor, -1, true); + QLabel * lbDeci = new QLabel("This average trace.", this); + bdCfgLayout[ID]->addWidget(lbDeci, 7, 2, 1, 2); + } void DigiSettingsPanel::SetUpChannel_QDC(){ @@ -2566,12 +2616,12 @@ void DigiSettingsPanel::SetUpChannel_QDC(){ QWidget * jaja = new QWidget(this); allSettingLayout->addWidget(jaja); - QHBoxLayout * papa = new QHBoxLayout(jaja); - papa->setAlignment(Qt::AlignLeft); - const unsigned short numGroup = digi[ID]->GetNumRegChannels(); {//^============================== Group selection + QHBoxLayout * papa = new QHBoxLayout(jaja); + papa->setAlignment(Qt::AlignLeft); + QLabel * lbChSel = new QLabel ("Group : ", this); lbChSel->setAlignment(Qt::AlignCenter | Qt::AlignRight); papa->addWidget(lbChSel); @@ -2583,14 +2633,21 @@ void DigiSettingsPanel::SetUpChannel_QDC(){ connect(chSelection[ID], &RComboBox::currentIndexChanged, this, [=](){ SyncAllChannelsTab_QDC(); - int grpID = chSelection[ID]->currentIndex() - 1; - for( int i = 0; i < 8; i ++){ lbSubCh[ID][i] ->setText((grpID == -1 ? "Sub-Ch:" : "Ch:" )+ QString::number(grpID < 0 ? i : grpID*8 + i)); lbSubCh2[ID][i]->setText((grpID == -1 ? "Sub-Ch:" : "Ch:" )+ QString::number(grpID < 0 ? i : grpID*8 + i)); - } + } + }); + bnProgramChannel[ID] = new QPushButton("Program Default Channel Settings",this); + papa->addWidget(bnProgramChannel[ID]); + connect(bnProgramChannel[ID], &QPushButton::clicked, this, [=](){ + short group = chSelection[ID]->currentData().toInt(); + digi[ID]->ProgramChannel(group); + digi[ID]->ReadAllSettingsFromBoard(true); + UpdatePanelFromMemory(); + emit UpdateOtherPanels(); }); } @@ -2703,13 +2760,22 @@ void DigiSettingsPanel::SetUpChannel_QDC(){ SetUpCheckBox(chkDisableSelfTrigger[ID][numGroup], "Disable Self Trigger ", triggerLayout, 0, 1, DPP::QDC::DPPAlgorithmControl, DPP::QDC::Bit_DPPAlgorithmControl::DisableSelfTrigger); SetUpCheckBox(chkDisableTriggerHysteresis[ID][numGroup], "Disbale Trig. Hysteresis ", triggerLayout, 2, 1, DPP::QDC::DPPAlgorithmControl, DPP::QDC::Bit_DPPAlgorithmControl::DisableTriggerHysteresis, -1, 2); + SetUpComboBoxBit(cbTrigMode[ID][numGroup], "Trig. Mode : ", triggerLayout, 0, 2, DPP::QDC::Bit_DPPAlgorithmControl::ListTrigMode, DPP::QDC::DPPAlgorithmControl, DPP::QDC::Bit_DPPAlgorithmControl::TriggerMode); SetUpSpinBox(sbTriggerHoldOff[ID][numGroup], "Trig. Holdoff [ns] : ", triggerLayout, 2, 2, DPP::QDC::TriggerHoldOffWidth); SetUpSpinBox(sbShapedTrigWidth[ID][numGroup], "Trig. Out Width [ns] : ", triggerLayout, 3, 2, DPP::QDC::TRGOUTWidth); + + int rowID = 4; + if( digi[ID]->HasOverThresholdWidth_QDC() ){ + SetUpCheckBox(chkOverthreshold[ID][numGroup], "Enable OverThreshold Width ", triggerLayout, rowID, 1, DPP::QDC::DPPAlgorithmControl, DPP::QDC::Bit_DPPAlgorithmControl::OverThresholdWitdhEnable); + SetUpSpinBox(sbOverThresholdWidth[ID][numGroup], "OverThreshold Width [ns] :", triggerLayout, rowID, 2, DPP::QDC::OverThresholdWidth); + rowID ++; + } + /// Trigger Threshold QGroupBox * widget = new QGroupBox("Threshold [LSB]", triggerBox); - triggerLayout->addWidget(widget, 4, 0, 1, 4); + triggerLayout->addWidget(widget, rowID, 0, 1, 4); QGridLayout * dcLayout = new QGridLayout(widget); dcLayout->setSpacing(2); @@ -2968,7 +3034,7 @@ void DigiSettingsPanel::SetUpChannel_QDC(){ QTabWidget * trigTab = new QTabWidget(this); trigLayout->addWidget(trigTab); - QStringList tabName = {"Common Settings", "Threshold", "Others"}; + QStringList tabName = {"Common Settings", "Threshold", "OverThreshold Width", "Others"}; const int nTab = tabName.count(); @@ -3048,6 +3114,20 @@ void DigiSettingsPanel::SetUpChannel_QDC(){ } if( i == 2 ){ + + if( digi[ID]->HasOverThresholdWidth_QDC() ){ + if( ch == 0 ){ + QLabel * lb0 = new QLabel("OverThreshold Width [ns]", this); lb0->setAlignment(Qt::AlignHCenter); tabLayout->addWidget(lb0, 0, 4); + } + SetUpCheckBox(chkOverthreshold[ID][ch], "Enable OverThreshold Width ", tabLayout, ch+1, 1, DPP::QDC::DPPAlgorithmControl, DPP::QDC::Bit_DPPAlgorithmControl::OverThresholdWitdhEnable, ch); + SetUpSpinBox(sbOverThresholdWidth[ID][ch], "", tabLayout, ch+1, 3, DPP::QDC::OverThresholdWidth, ch); + }else{ + QLabel * lb0 = new QLabel("OverThreshold Width not supported.", this); lb0->setAlignment(Qt::AlignHCenter); tabLayout->addWidget(lb0, 0, 1); + } + + } + + if( i == 3 ){ SetUpCheckBox(chkDisableSelfTrigger[ID][ch], "Disable Self Trigger ", tabLayout, ch+1, 1, DPP::QDC::DPPAlgorithmControl, DPP::QDC::Bit_DPPAlgorithmControl::DisableSelfTrigger, ch); SetUpCheckBox(chkDisableTriggerHysteresis[ID][ch], "Disbale Trig. Hysteresis ", tabLayout, ch+1, 3, DPP::QDC::DPPAlgorithmControl, DPP::QDC::Bit_DPPAlgorithmControl::DisableTriggerHysteresis, ch, 2); } @@ -3056,7 +3136,7 @@ void DigiSettingsPanel::SetUpChannel_QDC(){ } } -{//^================================== QDC + {//^================================== QDC QVBoxLayout *trapLayout = new QVBoxLayout(chTrap); @@ -3115,7 +3195,7 @@ void DigiSettingsPanel::SetUpChannel_QDC(){ } } -{//^======================================== Others + {//^======================================== Others QVBoxLayout *otherLayout = new QVBoxLayout(chOthers); QTabWidget * othersTab = new QTabWidget(this); @@ -3367,7 +3447,7 @@ void DigiSettingsPanel::UpdatePanelFromMemory(){ sbAggNum[ID]->setValue(digi[ID]->GetSettingFromMemory(DPP::MaxAggregatePerBlockTransfer)); - chkEnableExternalTrigger[ID]->setChecked( ! ( digi[ID]->GetSettingFromMemory(DPP::DisableExternalTrigger) & 0x1) ); + chkEnableExternalTrigger[ID]->setChecked( !( digi[ID]->GetSettingFromMemory(DPP::DisableExternalTrigger) & 0x1) ); sbRunDelay[ID]->setValue(digi[ID]->GetSettingFromMemory(DPP::RunStartStopDelay) * DPP::RunStartStopDelay.GetPartialStep() * digi[ID]->GetTick2ns()); @@ -3412,6 +3492,9 @@ void DigiSettingsPanel::UpdatePanelFromMemory(){ } } + cbTRGINMode[ID]->setCurrentIndex((frontPanel >> 10 ) & 0x1); + cbTRINMezzanines[ID]->setCurrentIndex((frontPanel >> 11 ) & 0x1); + //*======================================== uint32_t glbTrgMask = digi[ID]->GetSettingFromMemory(DPP::GlobalTriggerMask); @@ -3424,10 +3507,16 @@ void DigiSettingsPanel::UpdatePanelFromMemory(){ } } sbGlbMajLvl[ID]->setValue( Digitizer::ExtractBits(glbTrgMask, DPP::Bit_GlobalTriggerMask::MajorLevel) ); - } - sbGlbMajCoinWin[ID]->setValue( Digitizer::ExtractBits(glbTrgMask, DPP::Bit_GlobalTriggerMask::MajorCoinWin) ); - cbGlbUseOtherTriggers[ID]->setCurrentIndex(Digitizer::ExtractBits(glbTrgMask, {2, 30})); + sbGlbMajCoinWin[ID]->setValue( Digitizer::ExtractBits(glbTrgMask, DPP::Bit_GlobalTriggerMask::MajorCoinWin) * 4 * digi[ID]->GetTick2ns()); + cbGlbUseOtherTriggers[ID]->setCurrentIndex(Digitizer::ExtractBits(glbTrgMask, {2, 30})); + + if( sbGlbMajLvl[ID]->value() > 0 ) { + sbGlbMajCoinWin[ID]->setEnabled(true); + }else{ + sbGlbMajCoinWin[ID]->setEnabled(false); + } + } //*======================================== uint32_t TRGOUTMask = digi[ID]->GetSettingFromMemory(DPP::FrontPanelTRGOUTEnableMask); @@ -3634,7 +3723,7 @@ void DigiSettingsPanel::SyncCheckBox(QCheckBox *(&chk)[][MaxRegChannel+1]){ } void DigiSettingsPanel::EnableButtons(bool enable){ - for( int i = 0; i < nDigi; i++ ){ + for( unsigned int i = 0; i < nDigi; i++ ){ if( !enable ) { leSaveFilePath[i]->setText("changing setting is disabled due to ACQ is running."); leSaveFilePath[i]->setStyleSheet("color:red;"); @@ -3906,22 +3995,23 @@ void DigiSettingsPanel::SyncAllChannelsTab_QDC(){ DebugPrint("%s", "DigiSettingsPanel"); if( !enableSignalSlot ) return; - // SyncSpinBox(sbRecordLength); SyncSpinBox(sbPreTrigger); SyncSpinBox(sbDCOffset); SyncSpinBox(sbTriggerHoldOff); SyncSpinBox(sbShapedTrigWidth); - // SyncSpinBox(sbNumEventAgg); SyncSpinBox(sbShortGate); SyncSpinBox(sbGateOffset); - //SyncSpinBox(sbOverThresholdWidth); SyncCheckBox(chkDisableSelfTrigger); SyncCheckBox(chkDisableTriggerHysteresis); - //SyncCheckBox(chkOverthreshold); SyncCheckBox(chkChargePedestal); SyncCheckBox(chkTestPule); + if( digi[ID]->HasOverThresholdWidth_QDC() ){ + SyncSpinBox(sbOverThresholdWidth); + SyncCheckBox(chkOverthreshold); + } + SyncComboBox(cbPolarity); SyncComboBox(cbRCCR2Smoothing); SyncComboBox(cbBaseLineAvg); @@ -4005,6 +4095,8 @@ void DigiSettingsPanel::UpdateSettings_QDC(){ UpdateSpinBox(sbNumEventAgg[ID][0], DPP::QDC::NumberEventsPerAggregate, -1); + UpdateSpinBox(sbSWDecimation[ID], DPP::DecimationFactor, -1); + for(int grp = 0; grp < digi[ID]->GetNumRegChannels(); grp ++){ UpdateSpinBox(sbPreTrigger[ID][grp], DPP::QDC::PreTrigger, grp); @@ -4013,7 +4105,7 @@ void DigiSettingsPanel::UpdateSettings_QDC(){ UpdateSpinBox(sbShapedTrigWidth[ID][grp], DPP::QDC::TRGOUTWidth, grp); UpdateSpinBox(sbShortGate[ID][grp], DPP::QDC::GateWidth, grp); UpdateSpinBox(sbGateOffset[ID][grp], DPP::QDC::GateOffset, grp); - //UpdateSpinBox(sbOverThresholdWidth[ID][grp], DPP::QDC::OverThresholdWidth, grp); + uint32_t subChMask = digi[ID]->GetSettingFromMemory(DPP::QDC::SubChannelMask, grp); @@ -4036,10 +4128,13 @@ void DigiSettingsPanel::UpdateSettings_QDC(){ chkDisableSelfTrigger[ID][grp]->setChecked( Digitizer::ExtractBits(dpp, DPP::QDC::Bit_DPPAlgorithmControl::DisableSelfTrigger) ); chkDisableTriggerHysteresis[ID][grp]->setChecked( Digitizer::ExtractBits(dpp, DPP::QDC::Bit_DPPAlgorithmControl::DisableTriggerHysteresis) ); - //chkOverthreshold[ID][grp]->setChecked( Digitizer::ExtractBits(dpp, DPP::QDC::Bit_DPPAlgorithmControl::OverThresholdWitdhEnable) ); chkChargePedestal[ID][grp]->setChecked( Digitizer::ExtractBits(dpp, DPP::QDC::Bit_DPPAlgorithmControl::ChargePedestal)); chkTestPule[ID][grp]->setChecked( Digitizer::ExtractBits(dpp, DPP::QDC::Bit_DPPAlgorithmControl::InternalTestPulse)); + if( digi[ID]->HasOverThresholdWidth_QDC() ) { + UpdateSpinBox(sbOverThresholdWidth[ID][grp], DPP::QDC::OverThresholdWidth, grp); + chkOverthreshold[ID][grp]->setChecked( Digitizer::ExtractBits(dpp, DPP::QDC::Bit_DPPAlgorithmControl::OverThresholdWitdhEnable) ); + } uint32_t dcOffSet_low = digi[ID]->GetSettingFromMemory(DPP::QDC::DCOffset_LowCh, grp); @@ -4087,17 +4182,29 @@ void DigiSettingsPanel::CheckRadioAndCheckedButtons(){ int id1 = cbFromBoard->currentIndex(); int id2 = cbToBoard->currentIndex(); - for( int i = 0 ; i < MaxRegChannel; i++){ - if( i >= digi[id1]->GetNumRegChannels() ) rbCh[i]->setEnabled(false); - if( i >= digi[id2]->GetNumRegChannels() ) chkCh[i]->setEnabled(false); + if( digi[id1]->GetDPPType() == DPPTypeCode::DPP_QDC_CODE ){ + bnCopyChannel->setText("Copy Group(s)"); + }else{ + bnCopyChannel->setText("Copy Channel(s)"); } if( digi[id1]->GetDPPType() != digi[id2]->GetDPPType() ){ bnCopyBoard->setEnabled(false); bnCopyChannel->setEnabled(false); + + for( int i = 0 ; i < MaxRegChannel; i++){ + rbCh[i]->setEnabled(false); + chkCh[i]->setEnabled(false); + } + return; } + for( int i = 0 ; i < MaxRegChannel; i++){ + rbCh[i]->setEnabled(i < digi[id1]->GetNumRegChannels()); + chkCh[i]->setEnabled(i < digi[id1]->GetNumRegChannels()); + } + if( id1 == id2 ){ bnCopyBoard->setEnabled(false); }else{ diff --git a/DigiSettingsPanel.h b/DigiSettingsPanel.h index 495d972..407aabd 100644 --- a/DigiSettingsPanel.h +++ b/DigiSettingsPanel.h @@ -125,6 +125,9 @@ private: QGridLayout * bdTriggerLayout[MaxNDigitizer]; QGridLayout * bdLVDSLayout[MaxNDigitizer]; + // RComboBox * cbSWDecimation[MaxNDigitizer]; // software decimation + RSpinBox * sbSWDecimation[MaxNDigitizer]; + QCheckBox * chkAutoDataFlush[MaxNDigitizer]; QCheckBox * chkDecimateTrace[MaxNDigitizer]; QCheckBox * chkTrigPropagation[MaxNDigitizer]; @@ -195,6 +198,7 @@ private: QTabWidget * chTab; RComboBox * chSelection[MaxNDigitizer]; + QPushButton * bnProgramChannel[MaxNDigitizer]; //----------- common for PHA and PSD RSpinBox * sbRecordLength[MaxNDigitizer][MaxRegChannel + 1]; @@ -290,8 +294,8 @@ private: //Trig Hold off with -> sbTriggerHoldOff //Trig out width -> sbShapedTrigWidth - //QCheckBox * chkOverthreshold[MaxNDigitizer][MaxRegChannel+1]; //TODO need firmware version 4.25 & 135.17 - //RSpinBox * sbOverThresholdWidth[MaxNDigitizer][MaxRegChannel + 1]; + QCheckBox * chkOverthreshold[MaxNDigitizer][MaxRegChannel+1]; //TODO need firmware version 4.25 & 135.17 + RSpinBox * sbOverThresholdWidth[MaxNDigitizer][MaxRegChannel + 1]; QPushButton * pbSubChMask[MaxNDigitizer][MaxRegChannel+1][8]; RSpinBox * sbSubChOffset[MaxNDigitizer][MaxRegChannel + 1][8]; RSpinBox * sbSubChThreshold[MaxNDigitizer][MaxRegChannel + 1][8]; diff --git a/FSUDAQ b/FSUDAQ index 04a3b23..a990aef 100755 --- a/FSUDAQ +++ b/FSUDAQ @@ -2,6 +2,10 @@ timestamp=$(date +%Y%m%d_%H%M%S) -outFile=program_${timestamp}.log +outFile=log/program_${timestamp}.log + +mkdir -p "$(dirname "$outFile")" + +echo "FSUDAQ, save stdout to $outFile" stdbuf -oL ./FSUDAQ_Qt6 | tee $outFile \ No newline at end of file diff --git a/FSUDAQ.cpp b/FSUDAQ.cpp index e4a74bf..395992d 100644 --- a/FSUDAQ.cpp +++ b/FSUDAQ.cpp @@ -19,10 +19,10 @@ #include "analyzers/SplitPoleAnalyzer.h" #include "analyzers/EncoreAnalyzer.h" #include "analyzers/MUSICAnalyzer.h" -#include "analyzers/RAISOR.h" #include "analyzers/NeutronGamma.h" +#include "analyzers/Cross.h" -std::vector onlineAnalyzerList = {"Coincident","Splie-Pole", "Encore", "RAISOR", "MUSICS", "Neutron-Gamma"}; +std::vector onlineAnalyzerList = {"Coincident","Splie-Pole", "Encore", "MUSICS", "Neutron-Gamma", "Cross"}; FSUDAQ::FSUDAQ(QWidget *parent) : QMainWindow(parent){ DebugPrint("%s", "FSUDAQ"); @@ -59,9 +59,6 @@ FSUDAQ::FSUDAQ(QWidget *parent) : QMainWindow(parent){ cbOpenDigitizers = new RComboBox(this); cbOpenDigitizers->addItem("Open Digitizers ... ", 0); cbOpenDigitizers->addItem("Open Digitizers via Optical/USB", 1); - // cbOpenDigitizers->addItem("Open Digitizers (default program)", 2); - // cbOpenDigitizers->addItem("Open Digitizers + load Settings", 3); - //cbOpenDigitizers->addItem("Open Digitizers via USB", 3); cbOpenDigitizers->addItem("Open Digitizers via A4818(s)", 4); layout->addWidget(cbOpenDigitizers, 0, 0); connect(cbOpenDigitizers, &RComboBox::currentIndexChanged, this, &FSUDAQ::OpenDigitizers); @@ -449,9 +446,10 @@ void FSUDAQ::LoadProgramSettings(){ if( count == 2 ) dataBaseName = line; if( count == 3 ) influxToken = line; if( count == 4 ) elogIP = line; - if( count == 5 ) elogName = line; - if( count == 6 ) elogUser = line; - if( count == 7 ) elogPWD = line; + if( count == 5 ) elogPort = line; + if( count == 6 ) elogName = line; + if( count == 7 ) elogUser = line; + if( count == 8 ) elogPWD = line; count ++; line = in.readLine(); @@ -470,6 +468,7 @@ void FSUDAQ::LoadProgramSettings(){ LogMsg(" Database Name : " + dataBaseName); LogMsg("Database Token : " + maskText(influxToken)); LogMsg(" Elog IP : " + elogIP); + LogMsg(" Elog Port : " + elogPort); LogMsg(" Elog Name : " + elogName); LogMsg(" Elog User : " + maskText(elogUser)); LogMsg(" Elog PWD : " + maskText(elogPWD)); @@ -504,6 +503,7 @@ void FSUDAQ::SaveProgramSettings(){ file.write((dataBaseName+"\n").toStdString().c_str()); file.write((influxToken+"\n").toStdString().c_str()); file.write((elogIP+"\n").toStdString().c_str()); + file.write((elogPort+"\n").toStdString().c_str()); file.write((elogName+"\n").toStdString().c_str()); file.write((elogUser+"\n").toStdString().c_str()); file.write((elogPWD+"\n").toStdString().c_str()); @@ -684,9 +684,6 @@ void FSUDAQ::OpenDigitizers(){ digi[i] = new Digitizer(portList[i].first, portList[i].second); //digi[i]->Reset(); - //===== set no trace, even when FSQDAQ segfault at scope, the digitizer will save no trace - digi[i]->SetTrace(false); - if( cbOpenMethod->currentData().toInt() == 2 ) { digi[i]->ProgramBoard(); } @@ -731,6 +728,10 @@ void FSUDAQ::OpenDigitizers(){ } digi[i]->ReadAllSettingsFromBoard(true); + //===== set no trace, even when FSQDAQ segfault at scope, the digitizer will save no trace + digi[i]->SetTrace(false); + // if( digi[i]->GetDPPType() == V1730_DPP_PHA_CODE) digi[i]->WriteRegister(DPP::BoardConfiguration, 0xE8915); + readDataThread[i] = new ReadDataThread(digi[i], i); connect(readDataThread[i], &ReadDataThread::sendMsg, this, &FSUDAQ::LogMsg); @@ -1017,6 +1018,8 @@ void FSUDAQ::UpdateScalar(){ DebugPrint("%s", "FSUDAQ"); + // qDebug() << __func__ << "| thread:" << QThread::currentThreadId(); + // printf("================== FSUDAQ::%s\n", __func__); if( digi == nullptr ) return; @@ -1207,7 +1210,7 @@ void FSUDAQ::StartACQ(){ influx->ClearDataPointsBuffer(); } - if( elogID > 0 && !chkElog->isChecked() && chkSaveData->isChecked() ){ + if( elogID > 0 && chkElog->isChecked() && chkSaveData->isChecked() ){ QString msg = "================================= Run-" + QString::number(runID).rightJustified(3, '0') + "

" + QDateTime::currentDateTime().toString("MM.dd hh:mm:ss") + "

" + startComment + "

" @@ -1297,7 +1300,7 @@ void FSUDAQ::StopACQ(){ influx->ClearDataPointsBuffer(); } - if( elogID > 0 && !chkElog->isChecked() && chkSaveData->isChecked()){ + if( elogID > 0 && chkElog->isChecked() && chkSaveData->isChecked()){ QString msg = QDateTime::currentDateTime().toString("MM.dd hh:mm:ss") + "

" + stopComment + "

"; uint64_t totalFileSize = 0; for(unsigned int i = 0 ; i < nDigi; i++){ @@ -1563,13 +1566,16 @@ void FSUDAQ::SetAndLockInfluxElog(){ QVBoxLayout layout(&dialog); QFormLayout formLayout; + QLineEdit portLineEdit; QLineEdit usernameLineEdit; QLineEdit passwordLineEdit; //passwordLineEdit.setEchoMode(QLineEdit::Password); + formLayout.addRow("Port:", &portLineEdit); formLayout.addRow("Username:", &usernameLineEdit); formLayout.addRow("Password:", &passwordLineEdit); + portLineEdit.setText(elogPort); usernameLineEdit.setText(elogUser); passwordLineEdit.setText(elogPWD); @@ -1586,17 +1592,19 @@ void FSUDAQ::SetAndLockInfluxElog(){ // Show the dialog and get the result if (dialog.exec() == QDialog::Accepted) { - QString username = usernameLineEdit.text(); - QString password = passwordLineEdit.text(); + QString portNum = portLineEdit.text(); + QString username = usernameLineEdit.text(); + QString password = passwordLineEdit.text(); - // Check if username and password are not empty - if (!username.isEmpty() && !password.isEmpty()) { - elogUser = username; - elogPWD = password; + // Check if username and password are not empty + if (!portNum.isEmpty() && !username.isEmpty() && !password.isEmpty()) { + elogPort = portNum; + elogUser = username; + elogPWD = password; - } else { - qDebug() << "Please enter both username and password."; - } + } else { + qDebug() << "Please enter both port, username, and password."; + } } } @@ -1783,6 +1791,7 @@ void FSUDAQ::OpenScope(){ scope->show(); }else{ scope->show(); + scope->UpdatePanelFromMomeory(); scope->activateWindow(); } @@ -1802,10 +1811,12 @@ void FSUDAQ::OpenDigiSettings(){ digiSettings = new DigiSettingsPanel(digi, nDigi, rawDataPath); //connect(scope, &Scope::SendLogMsg, this, &FSUDAQ::LogMsg); connect(digiSettings, &DigiSettingsPanel::UpdateOtherPanels, this, [=](){ UpdateAllPanels(2); }); + connect(digiSettings, &DigiSettingsPanel::SendLogMsg, this, &FSUDAQ::LogMsg); digiSettings->show(); }else{ digiSettings->show(); + digiSettings->UpdatePanelFromMemory(); digiSettings->activateWindow(); } } @@ -1837,9 +1848,11 @@ void FSUDAQ::OpenAnalyzer(){ if( id == 0 ) onlineAnalyzer = new CoincidentAnalyzer(digi, nDigi, rawDataPath); if( id == 1 ) onlineAnalyzer = new SplitPole(digi, nDigi); if( id == 2 ) onlineAnalyzer = new Encore(digi, nDigi); - if( id == 3 ) onlineAnalyzer = new RAISOR(digi, nDigi); - if( id == 4 ) onlineAnalyzer = new MUSIC(digi, nDigi); - if( id == 5 ) onlineAnalyzer = new NeutronGamma(digi, nDigi, rawDataPath); + if( id == 3 ) onlineAnalyzer = new MUSIC(digi, nDigi); + if( id == 4 ) onlineAnalyzer = new NeutronGamma(digi, nDigi, rawDataPath); + + if( id == 5 ) onlineAnalyzer = new Cross(digi, nDigi); + if( id >= 0 ) onlineAnalyzer->show(); if( isACQStarted ) onlineAnalyzer->startTimer(); @@ -1851,9 +1864,10 @@ void FSUDAQ::OpenAnalyzer(){ if( id == 0 ) onlineAnalyzer = new CoincidentAnalyzer(digi, nDigi, rawDataPath); if( id == 1 ) onlineAnalyzer = new SplitPole(digi, nDigi); if( id == 2 ) onlineAnalyzer = new Encore(digi, nDigi); - if( id == 3 ) onlineAnalyzer = new RAISOR(digi, nDigi); - if( id == 4 ) onlineAnalyzer = new MUSIC(digi, nDigi); - if( id == 5 ) onlineAnalyzer = new NeutronGamma(digi, nDigi, rawDataPath); + if( id == 3 ) onlineAnalyzer = new MUSIC(digi, nDigi); + if( id == 4 ) onlineAnalyzer = new NeutronGamma(digi, nDigi, rawDataPath); + + if( id == 5 ) onlineAnalyzer = new Cross(digi, nDigi); if( id >= 0 ){ onlineAnalyzer->show(); @@ -2042,7 +2056,7 @@ void FSUDAQ::WriteElog(QString htmlText, QString subject, QString category, int if( elogUser == "" ) return; if( elogPWD == "" ) return; QStringList arg; - arg << "-h" << elogIP << "-p" << "8080" << "-l" << elogName << "-u" << elogUser << elogPWD << "-a" << "Author=FSUDAQ"; + arg << "-h" << elogIP << "-p" << elogPort << "-l" << elogName << "-u" << elogUser << elogPWD << "-a" << "Author=FSUDAQ"; if( runNumber > 0 ) arg << "-a" << "RunNo=" + QString::number(runNumber); if( category != "" ) arg << "-a" << "Category=" + category; arg << "-a" << "Subject=" + subject @@ -2072,7 +2086,7 @@ void FSUDAQ::AppendElog(QString appendHtmlText){ QProcess elogBash(this); QStringList arg; - arg << "-h" << elogIP << "-p" << "8080" << "-l" << elogName << "-u" << elogUser << elogPWD << "-w" << QString::number(elogID); + arg << "-h" << elogIP << "-p" << elogPort << "-l" << elogName << "-u" << elogUser << elogPWD << "-w" << QString::number(elogID); //retrevie the elog elogBash.start("elog", arg); elogBash.waitForFinished(); @@ -2083,7 +2097,7 @@ void FSUDAQ::AppendElog(QString appendHtmlText){ if( index != -1){ QString originalHtml = output.mid(index + separator.length()); arg.clear(); - arg << "-h" << elogIP << "-p" << "8080" << "-l" << elogName << "-u" << elogUser << elogPWD << "-e" << QString::number(elogID) + arg << "-h" << elogIP << "-p" << elogPort << "-l" << elogName << "-u" << elogUser << elogPWD << "-e" << QString::number(elogID) << "-n" << "2" << originalHtml + "
" + appendHtmlText; elogBash.start("elog", arg); diff --git a/FSUDAQ.h b/FSUDAQ.h index 07f22d7..6a87eea 100644 --- a/FSUDAQ.h +++ b/FSUDAQ.h @@ -144,6 +144,7 @@ private: //@----- Elog QString elogIP; + QString elogPort; QString elogName; QString elogUser; QString elogPWD; diff --git a/FSUDAQ_Qt6.pro b/FSUDAQ_Qt6.pro index c0ca0bd..0846a1b 100644 --- a/FSUDAQ_Qt6.pro +++ b/FSUDAQ_Qt6.pro @@ -25,28 +25,29 @@ QMAKE_CFLAGS_RELEASE = -O0 # Input HEADERS += ClassData.h \ ClassDigitizer.h \ + ClassInfluxDB.h\ CustomThreads.h \ CustomWidgets.h \ - Histogram1D.h \ - Histogram2D.h \ DigiSettingsPanel.h \ FSUDAQ.h \ - macro.h \ - RegisterAddress.h \ - ClassInfluxDB.h\ - Scope.h \ - SingleSpectra.h \ + Histogram1D.h \ + Histogram2D.h \ Hit.h \ + macro.h \ MultiBuilder.h \ qcustomplot.h \ - analyzers/Isotope.h \ + RegisterAddress.h \ + Scope.h \ + SingleSpectra.h \ analyzers/Analyser.h \ analyzers/CoincidentAnalyzer.h \ - analyzers/SplitPoleAnalyzer.h \ + analyzers/Cross.h\ analyzers/EncoreAnalyzer.h \ + analyzers/Isotope.h \ + analyzers/SplitPoleAnalyzer.h \ analyzers/MUSICAnalyzer.h \ - analyzers/NeutronGamma.h \ - analyzers/RAISOR.h + analyzers/NeutronGamma.h + SOURCES += ClassDigitizer.cpp \ DigiSettingsPanel.cpp \ FSUDAQ.cpp \ diff --git a/Histogram1D.h b/Histogram1D.h index a0f5704..4c6cdc1 100644 --- a/Histogram1D.h +++ b/Histogram1D.h @@ -276,6 +276,7 @@ public: UpdatePlot(); } + void SetLineTitle(QString title, int lineID = 0) { graph(lineID)->setName(title); } void SetXTitle(QString xTitle) { xAxis->setLabel(xTitle);} void Rebin(int xbin, double xmin, double xmax){ @@ -283,6 +284,7 @@ public: xMin = xmin; xMax = xmax; xBin = xbin; + if( xBin > 1000) xBin = 1000; dX = (xMax - xMin)/(xBin); diff --git a/Histogram2D.h b/Histogram2D.h index 33492b6..fb9ae49 100644 --- a/Histogram2D.h +++ b/Histogram2D.h @@ -32,7 +32,7 @@ public: void SetChannelMap(bool onOff, int tickStep = 1) { isChannelMap = onOff; this->tickStep = tickStep;} - void UpdatePlot(){ colorMap->rescaleDataRange(); replot(); } + void UpdatePlot(){ colorMap->rescaleDataRange(true); replot(); } void Clear(); // Clear Data and histrogram void Fill(double x, double y); @@ -135,7 +135,7 @@ inline Histogram2D::Histogram2D(QString title, QString xLabel, QString yLabel, i QCPColorGradient color; color.setNanHandling(QCPColorGradient::NanHandling::nhNanColor); - color.setNanColor(QColor("white")); + color.setNanColor(QColor(0,0,0,0)); color.clearColorStops(); // color.setColorStopAt( 0.0, QColor("white" )); color.setColorStopAt( 0.0, QColor("purple" )); @@ -268,8 +268,6 @@ inline Histogram2D::Histogram2D(QString title, QString xLabel, QString yLabel, i }); } - - inline void Histogram2D::Fill(double x, double y){ // DebugPrint("%s", "Histogram2D"); if( isBusy ) return; @@ -310,6 +308,9 @@ inline void Histogram2D::Rebin(int xbin, double xmin, double xmax, int ybin, do xBin = xbin + 2; yBin = ybin + 2; + if( xBin > 1002) xBin = 1002; + if( yBin > 1002) yBin = 1002; + colorMap->data()->clear(); colorMap->data()->setSize(xBin, yBin); colorMap->data()->setRange(QCPRange(xMin, xMax), QCPRange(yMin, yMax)); @@ -436,12 +437,15 @@ inline void Histogram2D::rightMouseClickMenu(QMouseEvent * event){ QAction * a4 = menu->addAction("Rebin (clear histogram)"); QAction * a8 = menu->addAction("Load Cut(s)"); QAction * a5 = menu->addAction("Create a Cut"); - QAction * a7 = nullptr; + + QAction * b0 = nullptr; + QAction * b1 = nullptr; + QAction * b2 = nullptr; if( numCut > 0 ) { - a7 = menu->addAction("Save Cut(s)"); menu->addSeparator(); - menu->addAction("Add/Edit names to Cuts"); - menu->addAction("Clear all Cuts"); + b0 = menu->addAction("Save Cut(s)"); + b2 = menu->addAction("Add/Edit names to Cuts"); + b1 = menu->addAction("Clear all Cuts"); } for( int i = 0; i < cutList.size(); i++){ if( cutList[i].isEmpty()) continue; @@ -451,20 +455,25 @@ inline void Histogram2D::rightMouseClickMenu(QMouseEvent * event){ QAction *selectedAction = menu->exec(event->globalPosition().toPoint()); + // qDebug() << "======================="; + // qDebug() << selectedAction; + // qDebug() << b2; + + if( selectedAction == nullptr ){ + usingMenu = false; + return; + } + if( selectedAction == a1 ){ xAxis->setRangeLower(xMin); xAxis->setRangeUpper(xMax); yAxis->setRangeLower(yMin); yAxis->setRangeUpper(yMax); replot(); - usingMenu = false; - return; } if( selectedAction == a2 ) { Clear(); - usingMenu = false; - return; } if( selectedAction == a3 ){ @@ -475,23 +484,17 @@ inline void Histogram2D::rightMouseClickMenu(QMouseEvent * event){ } } replot(); - usingMenu = false; - return; } if( selectedAction == a4){ rightMouseClickRebin(); - usingMenu = false; - return; } if( selectedAction == a5 ){ tempCut.clear(); tempCutID ++; isDrawCut= true; - usingMenu = false; numCut ++; - return; } if( selectedAction == a6){ @@ -505,6 +508,55 @@ inline void Histogram2D::rightMouseClickMenu(QMouseEvent * event){ replot(); } + if( selectedAction == a8 ){ // load Cuts + QString filePath = QFileDialog::getOpenFileName(this, + "Load Cuts from File", + settingPath, + "Text file (*.txt)"); + + if (!filePath.isEmpty()) LoadCuts(filePath); + } + + //*==================================== when there are cuts + if( selectedAction == b0 ){ // Save Cuts + + QString filePath = QFileDialog::getSaveFileName(this, + "Save Cuts to File", + settingPath, + "Text file (*.txt)"); + + if (!filePath.isEmpty()) SaveCuts(filePath); + } + + if( selectedAction == b1 ){ + ClearAllCuts(); + } + + if( selectedAction == b2 ){ + + QDialog dialog(this); + dialog.setWindowTitle("Add/Edit name of cuts "); + + QFormLayout layout(&dialog); + + for(int i = 0; i < cutTextIDList.count(); i++){ + if( cutTextIDList[i] < 0 ) continue; + QLineEdit * le = new QLineEdit(&dialog); + layout.addRow(colorCycle[i%colorCycle.count()].second, le); + le->setText( cutNameList[i] ); + connect(le, &QLineEdit::textChanged, this, [=](){ + le->setStyleSheet("color : blue;"); + }); + connect(le, &QLineEdit::returnPressed, this, [=](){ + le->setStyleSheet(""); + cutNameList[i] = le->text(); + ((QCPItemText *) this->item(cutTextIDList[i]))->setText(le->text()); + replot(); + }); + } + dialog.exec(); + } + if( selectedAction && numCut > 0 && selectedAction->text().contains("Delete ") ){ QString haha = selectedAction->text(); @@ -539,61 +591,11 @@ inline void Histogram2D::rightMouseClickMenu(QMouseEvent * event){ cutNameList.clear(); cutEntryList.clear(); } - return; } - if( selectedAction && numCut > 0 && selectedAction->text().contains("Clear all Cuts") ){ - ClearAllCuts(); - return; - } - if( selectedAction && numCut > 0 && selectedAction->text().contains("Add/Edit names to Cuts") ){ - - QDialog dialog(this); - dialog.setWindowTitle("Add/Edit name of cuts "); - - QFormLayout layout(&dialog); - - for(int i = 0; i < cutTextIDList.count(); i++){ - if( cutTextIDList[i] < 0 ) continue; - QLineEdit * le = new QLineEdit(&dialog); - layout.addRow(colorCycle[i%colorCycle.count()].second, le); - le->setText( cutNameList[i] ); - connect(le, &QLineEdit::textChanged, this, [=](){ - le->setStyleSheet("color : blue;"); - }); - connect(le, &QLineEdit::returnPressed, this, [=](){ - le->setStyleSheet(""); - cutNameList[i] = le->text(); - ((QCPItemText *) this->item(cutTextIDList[i]))->setText(le->text()); - replot(); - }); - } - dialog.exec(); - return; - } - - if( selectedAction == a8 ){ // load Cuts - QString filePath = QFileDialog::getOpenFileName(this, - "Load Cuts from File", - settingPath, - "Text file (*.txt)"); - - if (!filePath.isEmpty()) LoadCuts(filePath); - - } - - if( selectedAction == a7 ){ // Save Cuts - - QString filePath = QFileDialog::getSaveFileName(this, - "Save Cuts to File", - settingPath, - "Text file (*.txt)"); - - if (!filePath.isEmpty()) SaveCuts(filePath); - - } + usingMenu = false; } @@ -752,7 +754,7 @@ inline void Histogram2D::LoadCuts(QString cutFileName){ int colorID = tempCutID% colorCycle.count(); text->setColor(colorCycle[colorID].first); cutTextIDList.push_back(itemCount() - 1); - // cutList.push_back(tempCut); + cutList.push_back(tempCut); cutIDList.push_back(tempCutID); } tempCut.clear(); @@ -792,6 +794,7 @@ inline void Histogram2D::LoadCuts(QString cutFileName){ // Close the file file.close(); qDebug() << "File read successfully from" << cutFileName; + qDebug() << " Number of cut loaded " << numCut << ", " << cutList.count(); // PrintCutEntry(); // DrawCut(); diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/MultiBuilder.cpp b/MultiBuilder.cpp index 88d0e8d..c71e70d 100644 --- a/MultiBuilder.cpp +++ b/MultiBuilder.cpp @@ -58,7 +58,6 @@ void MultiBuilder::ClearEvents(){ for( int i = 0; i < MaxNDigitizer; i++){ for( int j = 0; j < MaxNChannels; j++){ - loopIndex[i][j] = 0; nextIndex[i][j] = -1; chExhaused[i][j] = false; lastBackWardIndex[i][j] = 0; @@ -79,7 +78,7 @@ void MultiBuilder::PrintStat(){ printf("Total number of evet built : %ld\n", totalEventBuilt); for( int i = 0; i < nData ; i++){ for( int ch = 0; ch < data[i]->GetNChannel() ; ch++){ - if( nextIndex[i][ch] >= 0 ) printf("%d %3d %2d | %7d (%d)\n", i, snList[i], ch, nextIndex[i][ch], loopIndex[i][ch]); + if( nextIndex[i][ch] >= 0 ) printf("%d %3d %2d | %7ld\n", i, snList[i], ch, nextIndex[i][ch]); } } } @@ -95,6 +94,8 @@ void MultiBuilder::PrintAllEvent(){ } } +//^############################################### forward event builder + void MultiBuilder::FindEarlistTimeAndCh(bool verbose){ DebugPrint("%s", "MultiBuilder"); earlistTime = -1; @@ -103,9 +104,7 @@ void MultiBuilder::FindEarlistTimeAndCh(bool verbose){ nExhaushedCh = 0; for( int i = 0; i < nData; i++){ - for( int j = 0; j < data[i]->GetNChannel(); j++ ) { - chExhaused[i][j] = false; - } + for( int j = 0; j < data[i]->GetNChannel(); j++ ) chExhaused[i][j] = false; for(unsigned int ch = 0; ch < data[i]->GetNChannel(); ch ++){ @@ -117,8 +116,7 @@ void MultiBuilder::FindEarlistTimeAndCh(bool verbose){ continue; } - if( data[i]->GetTimestamp(ch, index) == 0 || - loopIndex[i][ch] * dataSize[i] > data[i]->GetLoopIndex(ch) * dataSize[i] + data[i]->GetDataIndex(ch)) { + if( data[i]->GetTimestamp(ch, index) == 0 || nextIndex[i][ch] > data[i]->GetAbsDataIndex(ch)) { nExhaushedCh ++; chExhaused[i][ch] = true; continue; @@ -138,42 +136,6 @@ void MultiBuilder::FindEarlistTimeAndCh(bool verbose){ } if( verbose ) printf("%s | bd : %d, ch : %d, %llu\n", __func__, earlistDigi, earlistCh, earlistTime); - -} - -void MultiBuilder::FindLatestTimeAndCh(bool verbose){ - DebugPrint("%s", "MultiBuilder"); - latestTime = 0; - latestDigi = -1; - latestCh = -1; - - nExhaushedCh = 0; - - for( int i = 0; i < nData; i++){ - - for( int j = 0; j < data[i]->GetNChannel(); j++ ) chExhaused[i][j] = false; - - for(unsigned int ch = 0; ch < data[i]->GetNChannel(); ch ++){ - - if( nextIndex[i][ch] < 0 || data[i]->GetDataIndex(ch) < 0 || nextIndex[i][ch] <= lastBackWardIndex[i][ch] ) { - nExhaushedCh ++; - chExhaused[i][ch] = true; - // printf(", exhanshed. %d \n", nExhaushedCh); - continue; - } - - unsigned long long time = data[i]->GetTimestamp(ch, nextIndex[i][ch]); - // printf(", time : %llu\n", time ); - if( time > latestTime ) { - latestTime = time; - latestDigi = i; - latestCh = ch; - } - } - } - - if( verbose ) printf("%s | bd : %d, ch : %d, %llu\n", __func__, latestDigi, latestCh, latestTime); - } void MultiBuilder::FindEarlistTimeAmongLastData(bool verbose){ @@ -195,6 +157,187 @@ void MultiBuilder::FindEarlistTimeAmongLastData(bool verbose){ } if( verbose ) printf("%s | bd : %d, ch : %d, %lld \n", __func__, latestDigi, latestCh, latestTime); } + + +void MultiBuilder::BuildEvents(bool isFinal, bool skipTrace, bool verbose){ + DebugPrint("%s", "MultiBuilder"); + + FindEarlistTimeAndCh(verbose); //Give the earliest time, ch, digi + + FindEarlistTimeAmongLastData(verbose); // give lastest Time, Ch, and Digi for event building + + if( earlistCh == -1 || nExhaushedCh == numTotCh) return; /// no data + + eventBuilt = 0; + //======= Start building event + Hit em; + do{ + + if( forceStop ) break; + + eventIndex ++; + if( eventIndex >= MaxNEvent ) eventIndex = 0; + events[eventIndex].clear(); + em.Clear(); + + for( int k = 0; k < nData; k++){ + int bd = (k + earlistDigi) % nData; + + // printf("##### %d/%d | ", bd, nData); + // data[bd]->PrintAllData(true); + + const int numCh = data[bd]->GetNChannel(); + + for( int i = 0; i < numCh; i++){ + int ch = (i + earlistCh ) % numCh; + // printf("ch : %d | exhaused ? %s \n", ch, chExhaused[bd][ch] ? "Yes" : "No"); + if( chExhaused[bd][ch] ) continue; + + // printf(" ch : %2d | %d(%d) | %d(%d)\n", ch, loopIndex[bd][ch], nextIndex[bd][ch], data[bd]->GetLoopIndex(ch), data[bd]->GetDataIndex(ch) ); + + if( nextIndex[bd][ch] == -1 || nextIndex[bd][ch] > data[bd]->GetAbsDataIndex(ch)) { + nExhaushedCh ++; + chExhaused[bd][ch] = true; + + // printf(" ch : %d exhaused\n", ch); + continue; + } + + do { + + unsigned long long time = data[bd]->GetTimestamp(ch, nextIndex[bd][ch]); + // printf("%6d, sn: %5d, ch: %2d, timestamp : %16llu | earlistTime : %16llu | timeWindow : %u \n", nextIndex[bd][ch], data[bd]->boardSN, ch, time, earlistTime, timeWindow); + + if( time >= earlistTime && (time - earlistTime <= timeWindow) ){ + em.sn = snList[bd]; + em.ch = ch; + em.energy = data[bd]->GetEnergy(ch, nextIndex[bd][ch]); + em.timestamp = time; + em.fineTime = data[bd]->GetFineTime(ch, nextIndex[bd][ch]); + + if( !skipTrace ) em.trace = data[bd]->Waveform1[ch][nextIndex[bd][ch]]; + if( typeList[bd] == DPPTypeCode::DPP_PSD_CODE ) em.energy2 = data[bd]->GetEnergy2(ch, nextIndex[bd][ch]); + + events[eventIndex].push_back(em); + nextIndex[bd][ch]++; + + }else{ + break; + } + if( timeWindow == 0 ) break; + }while( true ); + if( timeWindow == 0 ) break; + } + if( timeWindow == 0 ) break; + } + + if( events[eventIndex].size() == 0 ) { + if( eventIndex > 1) { + eventIndex --; + }else{ + eventIndex = MaxNEvent - 1; + } + continue; + } + + if( events[eventIndex].size() > 1) { + std::sort(events[eventIndex].begin(), events[eventIndex].end(), [](const Hit& a, const Hit& b) { + return a.timestamp < b.timestamp; + }); + } + + // lastEventTime = events[eventIndex].back().timestamp; + + ///Find the next earlist + FindEarlistTimeAndCh(false); + + // //if there is a time jump, say, bigger than TimeJump. break + // if( earlistTime - lastEventTime > timeJump ) { + // if( verbose ){ + // printf("!!!!!!!! Time Jump detected stop event building and get more data.\n"); + // printf("event index : %6lu, last event time : %16llu\n", eventIndex, lastEventTime); + // printf(" %6s earilest time : %16llu \n", "", earlistTime); + // printf(" %6s time jump > %16llu \n", "", timeJump); + // } + // return; + // } + + eventBuilt ++; + totalEventBuilt ++; + + if( verbose ){ + printf(">>>>>>>>>>>>>>>>> Event ID : %ld, total built: %ld, multiplicity : %ld\n", eventIndex, totalEventBuilt, events[eventIndex].size()); + for( int i = 0; i <(int) events[eventIndex].size(); i++){ + int chxxx = events[eventIndex][i].ch; + int sn = events[eventIndex][i].sn; + int bd = 0; + for( int pp = 0; pp < nData; pp++){ + if( sn == data[pp]->boardSN ) { + bd = pp; + break; + } + } + printf("%05d, %02d | %7ld | %5d %llu \n", sn, chxxx, nextIndex[bd][chxxx], events[eventIndex][i].energy, events[eventIndex][i].timestamp); + } + + if( nExhaushedCh == numTotCh ) { + printf("######################### no more event to be built\n"); + break; + } + printf("----- next bd : %d, ch : %d, next earlist Time : %llu.\n", earlistDigi, earlistCh, earlistTime); + //printf("leftOver %llu, breakTime %llu \n", leftOverTime, breakTime); + } + + if( !isFinal ){ + if( latestTime - earlistTime <= leftOverTime){ + if( verbose ) printf("######################### left over data for next build, latesTime : %llu. | leftOverTime : %llu\n", latestTime, leftOverTime); + break; + } + + if( earlistTime > breakTime ) { + if( verbose ) printf("######################### left over data for next build, earlistTime : %llu. | breakTime : %llu\n", earlistTime, breakTime); + break; + } + } + }while(nExhaushedCh < numTotCh); + + forceStop = false; + +} + +//^############################################### backward event builder + +void MultiBuilder::FindLatestTimeAndCh(bool verbose){ + DebugPrint("%s", "MultiBuilder"); + latestTime = 0; + latestDigi = -1; + latestCh = -1; + + nExhaushedCh = 0; + + for( int i = 0; i < nData; i++){ + for( int j = 0; j < data[i]->GetNChannel(); j++ ) chExhaused[i][j] = false; + + for(unsigned int ch = 0; ch < data[i]->GetNChannel(); ch ++){ + if( nextIndex[i][ch] < 0 || data[i]->GetDataIndex(ch) < 0 || nextIndex[i][ch] <= lastBackWardIndex[i][ch] ) { + nExhaushedCh ++; + chExhaused[i][ch] = true; + // printf(", exhanshed. %d \n", nExhaushedCh); + continue; + } + + unsigned long long time = data[i]->GetTimestamp(ch, nextIndex[i][ch]); + // printf(", time : %llu\n", time ); + if( time > latestTime ) { + latestTime = time; + latestDigi = i; + latestCh = ch; + } + } + } + + if( verbose ) printf("%s | bd : %d, ch : %d, %llu\n", __func__, latestDigi, latestCh, latestTime); +} void MultiBuilder::FindLatestTimeOfData(bool verbose){ DebugPrint("%s", "MultiBuilder"); @@ -217,143 +360,6 @@ void MultiBuilder::FindLatestTimeOfData(bool verbose){ if( verbose ) printf("%s | bd : %d, ch : %d, %lld \n", __func__, latestDigi, latestCh, latestTime); } -void MultiBuilder::BuildEvents(bool isFinal, bool skipTrace, bool verbose){ - DebugPrint("%s", "MultiBuilder"); - - FindEarlistTimeAmongLastData(verbose); // give lastest Time, Ch, and Digi for event building - - FindEarlistTimeAndCh(verbose); //Give the earliest time, ch, digi - if( earlistCh == -1 || nExhaushedCh == nData * MaxNChannels) return; /// no data - - eventBuilt = 0; - //======= Start building event - Hit em; - do{ - - if( forceStop ) break; - - eventIndex ++; - if( eventIndex >= MaxNEvent ) eventIndex = 0; - events[eventIndex].clear(); - - em.Clear(); - - for( int k = 0; k < nData; k++){ - int bd = (k + earlistDigi) % nData; - - // printf("##### %d/%d | ", k, nData); - // data[k]->PrintAllData(true, 10); - - const int numCh = data[bd]->GetNChannel(); - - for( int i = 0; i < numCh; i++){ - int ch = (i + earlistCh ) % numCh; - // printf("ch : %d | exhaused ? %s \n", ch, chExhaused[bd][ch] ? "Yes" : "No"); - if( chExhaused[bd][ch] ) continue; - if( loopIndex[bd][ch] * dataSize[bd] + nextIndex[bd][ch] > data[bd]->GetLoopIndex(ch) * dataSize[bd] + data[bd]->GetDataIndex(ch)) { - nExhaushedCh ++; - chExhaused[bd][ch] = true; - continue; - } - - do { - - unsigned long long time = data[bd]->GetTimestamp(ch, nextIndex[bd][ch]); - //printf("%6ld, sn: %5d, ch: %2d, timestamp : %16llu | earlistTime : %16llu | timeWindow : %u \n", eventIndex, data[bd]->boardSN, ch, time, earlistTime, timeWindow); - - if( time >= earlistTime && (time - earlistTime <= timeWindow) ){ - em.sn = snList[bd]; - em.ch = ch; - em.energy = data[bd]->GetEnergy(ch, nextIndex[bd][ch]); - em.timestamp = time; - em.fineTime = data[bd]->GetFineTime(ch, nextIndex[bd][ch]); - - if( !skipTrace ) em.trace = data[bd]->Waveform1[ch][nextIndex[bd][ch]]; - if( typeList[bd] == DPPTypeCode::DPP_PSD_CODE ) em.energy2 = data[bd]->GetEnergy2(ch, nextIndex[bd][ch]); - - events[eventIndex].push_back(em); - nextIndex[bd][ch]++; - if( nextIndex[bd][ch] >= dataSize[bd]) { - loopIndex[bd][ch] ++; - nextIndex[bd][ch] = 0; - } - }else{ - break; - } - if( timeWindow <= 0 ) break; - }while( true ); - if( timeWindow <= 0 ) break; - } - if( timeWindow <= 0 ) break; - } - - if( events[eventIndex].size() == 0 ) continue; - - if( events[eventIndex].size() > 1) { - std::sort(events[eventIndex].begin(), events[eventIndex].end(), [](const Hit& a, const Hit& b) { - return a.timestamp < b.timestamp; - }); - } - - lastEventTime = events[eventIndex].back().timestamp; - - ///Find the next earlist - FindEarlistTimeAndCh(false); - - // //if there is a time jump, say, bigger than TimeJump. break - if( earlistTime - lastEventTime > timeJump ) { - if( verbose ){ - printf("!!!!!!!! Time Jump detected stop event building and get more data.\n"); - printf("event index : %6lu, earlist time : %16llu\n", eventIndex, earlistTime); - printf(" %6s last event time : %16llu \n", "", lastEventTime); - printf(" %6s time jump > %16llu \n", "", timeJump); - } - return; - } - - eventBuilt ++; - totalEventBuilt ++; - - if( verbose ){ - printf(">>>>>>>>>>>>>>>>> Event ID : %ld, total built: %ld, multiplicity : %ld\n", eventIndex, totalEventBuilt, events[eventIndex].size()); - for( int i = 0; i <(int) events[eventIndex].size(); i++){ - int chxxx = events[eventIndex][i].ch; - int sn = events[eventIndex][i].sn; - int bd = 0; - for( int pp = 0; pp < nData; pp++){ - if( sn == data[pp]->boardSN ) { - bd = pp; - break; - } - } - printf("%05d, %02d | %5d | %5d %llu \n", sn, chxxx, nextIndex[bd][chxxx], events[eventIndex][i].energy, events[eventIndex][i].timestamp); - } - - if( nExhaushedCh == nData * MaxNChannels ) { - printf("######################### no more event to be built\n"); - break; - } - printf("----- next bd : %d, ch : %d, next earlist Time : %llu.\n", earlistDigi, earlistCh, earlistTime); - //printf("leftOver %llu, breakTime %llu \n", leftOverTime, breakTime); - } - - if( !isFinal ){ - if( latestTime - earlistTime <= leftOverTime){ - if( verbose ) printf("######################### left over data for next build, latesTime : %llu. | leftOverTime : %llu\n", latestTime, leftOverTime); - break; - } - - if( earlistTime > breakTime ) { - if( verbose ) printf("######################### left over data for next build, earlistTime : %llu. | breakTime : %llu\n", earlistTime, breakTime); - break; - } - } - }while(nExhaushedCh < nData * MaxNChannels); - - forceStop = false; - -} - void MultiBuilder::BuildEventsBackWard(int maxNumEvent, bool verbose){ DebugPrint("%s", "MultiBuilder"); //skip trace, and only build for maxNumEvent events max @@ -362,8 +368,7 @@ void MultiBuilder::BuildEventsBackWard(int maxNumEvent, bool verbose){ for( int k = 0; k < nData; k++){ for( int i = 0; i < data[k]->GetNChannel(); i++){ - nextIndex[k][i] = data[k]->GetDataIndex(i); - loopIndex[k][i] = data[k]->GetLoopIndex(i); + nextIndex[k][i] = data[k]->GetAbsDataIndex(i); } } @@ -406,7 +411,7 @@ void MultiBuilder::BuildEventsBackWard(int maxNumEvent, bool verbose){ events[eventIndex].push_back(em); nextIndex[bd][ch]--; - if( nextIndex[bd][ch] < 0 && data[bd]->GetLoopIndex(ch) > 0 ) nextIndex[bd][ch] = dataSize[bd] - 1; + // if( nextIndex[bd][ch] < 0 && data[bd]->GetLoopIndex(ch) > 0 ) nextIndex[bd][ch] = dataSize[bd] - 1; }else{ break; @@ -451,7 +456,7 @@ void MultiBuilder::BuildEventsBackWard(int maxNumEvent, bool verbose){ break; } } - printf("%5d, %02d | %5d | %5d %llu \n", sn, chxxx, nextIndex[bd][chxxx], events[eventIndex][i].energy, events[eventIndex][i].timestamp); + printf("%5d, %02d | %7ld | %5d %llu \n", sn, chxxx, nextIndex[bd][chxxx], events[eventIndex][i].energy, events[eventIndex][i].timestamp); } } @@ -462,7 +467,7 @@ void MultiBuilder::BuildEventsBackWard(int maxNumEvent, bool verbose){ // remember the end of DataIndex, prevent over build for( int k = 0; k < nData; k++){ for( int i = 0; i < data[k]->GetNChannel(); i++){ - lastBackWardIndex[k][i] = data[k]->GetDataIndex(i); + lastBackWardIndex[k][i] = data[k]->GetAbsDataIndex(i); } } diff --git a/MultiBuilder.h b/MultiBuilder.h index 9fa8d13..bcade46 100644 --- a/MultiBuilder.h +++ b/MultiBuilder.h @@ -61,8 +61,8 @@ private: unsigned long long timeJump; //time diff for a time jump, default is 1e8 ns unsigned long long lastEventTime; // timestamp for detect time jump - int loopIndex[MaxNDigitizer][MaxNChannels]; - int nextIndex[MaxNDigitizer][MaxNChannels]; + // int loopIndex[MaxNDigitizer][MaxNChannels]; + long nextIndex[MaxNDigitizer][MaxNChannels]; // loopIndex * dataSize + index int nExhaushedCh; bool chExhaused[MaxNDigitizer][MaxNChannels]; @@ -79,7 +79,7 @@ private: void FindEarlistTimeAmongLastData(bool verbose = false); void FindLatestTimeOfData(bool verbose = false); - int lastBackWardIndex[MaxNDigitizer][MaxNChannels]; + int lastBackWardIndex[MaxNDigitizer][MaxNChannels]; // abs. index bool forceStop; diff --git a/README.md b/README.md index aa95aaa..1aa1703 100644 --- a/README.md +++ b/README.md @@ -188,6 +188,7 @@ second, ensure the core dump file has unlimited size and set the core dump file * Sometimes, the buffer is not in time order, and make the trigger/Accept rate to be nagative. This is nothing to do with the program but the digitizer settings. Recommand reporgram the digitizer. * For 1740 QDC, RecordLenght is board setting, but readout is indivuial group. * For PHA, the trapezoid scaling and fine-gain register are calculated before ACQ start. +* For 1740D QDC, when 1st grouped channel is enabled, the 0th-channel must be enabled, otherwise, there is a ReadData error and the ACQ will stop. # Known Bugs diff --git a/RegisterAddress.h b/RegisterAddress.h index 2bf8036..9be71e9 100644 --- a/RegisterAddress.h +++ b/RegisterAddress.h @@ -171,7 +171,7 @@ const Reg FrontPanelTRGOUTEnableMask ("FrontPanelTRGOUTEnableMask" , 0x8110, const Reg PostTrigger ("PostTrigger" , 0x8114, RW::ReadWrite, false, {}); /// R/W const Reg LVDSIOData ("LVDSIOData" , 0x8118, RW::ReadWrite, false, {}); /// R/W const Reg FrontPanelIOControl ("FrontPanelIOControl" , 0x811C, RW::ReadWrite, false, {}); /// R/W -const Reg RegChannelEnableMask ("RegChannelEnableMask" , 0x8120, RW::ReadWrite, false, {}); /// R/W +const Reg RegChannelEnableMask ("RegChannelEnableMask" , 0x8120, RW::ReadWrite, false, {}); /// R/W const Reg ROCFPGAFirmwareRevision_R ("ROCFPGAFirmwareRevision_R" , 0x8124, RW::ReadONLY , false, {}); /// R const Reg EventStored_R ("EventStored_R" , 0x812C, RW::ReadONLY , false, {}); /// R const Reg VoltageLevelModeConfig ("VoltageLevelModeConfig" , 0x8138, RW::ReadWrite, false, {}); /// R/W @@ -199,7 +199,6 @@ const Reg Scratch ("Scratch" , 0xEF20, const Reg SoftwareReset_W ("SoftwareReset_W" , 0xEF24, RW::WriteONLY, false, {}); /// W const Reg SoftwareClear_W ("SoftwareClear_W" , 0xEF28, RW::WriteONLY, false, {}); /// W - ///====== Common for PHA and PSD namespace DPP { @@ -315,7 +314,7 @@ namespace DPP { const std::vector> ListPolarity = {{"Positive", 0}, {"Negative", 1}}; - const std::vector> ListTrigMode = {{"Independent", 0}, + const std::vector> ListTrigMode = {{"Normal", 0}, {"Coincident", 1}, {"Anti-Coincident", 3}}; @@ -382,7 +381,7 @@ namespace DPP { const std::vector> ListPolarity = {{"Positive", 0}, {"Negative", 1}}; - const std::vector> ListTrigMode = {{"Independent", 0}, + const std::vector> ListTrigMode = {{"Normal", 0}, {"Coincident ", 1}, {"Anti-Coincident", 3}}; @@ -481,7 +480,7 @@ namespace DPP { {"TTL I/O", 1}}; const std::vector> ListTRGIMode = {{"Edge of TRG-IN", 0}, {"Whole duration of TRG-IN", 1}}; - const std::vector> ListTRGIMezzanine = {{"Pocessed by Motherboard", 0}, + const std::vector> ListTRGINMezzanine = {{"Pocessed by Motherboard", 0}, {"Skip Motherboard", 1}}; const std::vector> ListTRGOUTConfig = {{"Disable", 0x00002}, /// this is TRG_OUT high imped. 0x811C bit[1] @@ -509,7 +508,7 @@ namespace DPP { const Reg RecordLength_G ("RecordLength_G" , 0x1020, RW::ReadWrite, true, 0x3FFF, 8); /// R/W const Reg InputDynamicRange ("InputDynamicRange" , 0x1028, RW::ReadWrite, false, {{"2 Vpp", 0},{"0.5 Vpp", 1}}); /// R/W - const Reg NumberEventsPerAggregate_G ("NumberEventsPerAggregate_G" , 0x1034, RW::ReadWrite, true, 0x3FF, -1); /// R/W + const Reg NumberEventsPerAggregate_G ("NumberEventsPerAggregate_G" , 0x1034, RW::ReadWrite, true, 0x1FF, -1); /// R/W const Reg PreTrigger ("PreTrigger" , 0x1038, RW::ReadWrite, false, 0xFF, 4); /// R/W const Reg TriggerThreshold ("TriggerThreshold" , 0x106C, RW::ReadWrite, false, 0x3FFF, -1); /// R/W const Reg TriggerHoldOffWidth ("TriggerHoldOffWidth" , 0x1074, RW::ReadWrite, false, 0x3FF, 4); /// R/W @@ -546,7 +545,7 @@ namespace DPP { const Reg RegChannelEnableMask ("RegChannelEnableMask" , 0x8120, RW::ReadWrite, false, {}); /// R/W const Reg ROCFPGAFirmwareRevision_R ("ROCFPGAFirmwareRevision_R" , 0x8124, RW::ReadONLY , false, {}); /// R const Reg EventStored_R ("EventStored_R" , 0x812C, RW::ReadONLY , false, {}); /// R - const Reg VoltageLevelModeConfig ("VoltageLevelModeConfig" , 0x8138, RW::ReadWrite, false, {}); /// R/W + const Reg VoltageLevelModeConfig ("VoltageLevelModeConfig" , 0x8138, RW::ReadWrite, false, 0xFFF, -1); /// R/W const Reg SoftwareClockSync_W ("SoftwareClockSync_W" , 0x813C, RW::WriteONLY, false, {}); /// W const Reg BoardInfo_R ("BoardInfo_R" , 0x8140, RW::ReadONLY , false, {}); /// R const Reg AnalogMonitorMode ("AnalogMonitorMode" , 0x8144, RW::ReadWrite, false, {{"Trig. Maj. Mode", 0}, @@ -601,6 +600,9 @@ namespace DPP { const Reg TriggerValidationMask_G ("TriggerValidationMask_G" , 0x8180, RW::ReadWrite, true, {}); /// R/W, + //& Artifical Register that not in CAEN manual + const Reg DecimationFactor ("Decimation Factor" , 0x8044, RW::ReadWrite, false, 0x7, -1); /// R/W + namespace PHA { const Reg DataFlush_W ("DataFlush_W" , 0x103C, RW::WriteONLY, false, {}); /// W not sure const Reg ChannelStopAcquisition ("ChannelStopAcquisition" , 0x1040, RW::ReadWrite, false, {{"Run", 0}, {"Stop", 1}}); /// R/W not sure @@ -645,7 +647,7 @@ namespace DPP { const std::vector> ListLocalTrigValidMode = {{"Disabled", 0}, {"Crossed Trigger", 4}, - {"Both from Mother board", 5}, + {"Both from TRG_VAL", 5}, {"AND", 6}, {"OR", 7}}; @@ -734,7 +736,7 @@ namespace DPP { const std::vector> ListLocalTrigValidMode = {{"Disabled", 0}, {"Crossed Trigger", 4}, - {"Both from Mother board", 5}, + {"Both from TRG_VAL", 5}, {"AND", 6}, {"OR", 7}}; @@ -793,7 +795,7 @@ namespace DPP { const Reg DPPAlgorithmControl ("DPPAlgorithmControl" , 0x1040, RW::ReadWrite, false, {}); /// R/W const Reg TriggerHoldOffWidth ("Trigger Hold-off width" , 0x1074, RW::ReadWrite, false, 0xFFFF, 1); /// R/W const Reg TRGOUTWidth ("Trigger out width" , 0x1078, RW::ReadWrite, false, 0xFFFF, 1); /// R/W - //const Reg OverThresholdWidth ("Over Threshold width" , 0x107C, RW::ReadWrite, false, 0xFFFF, 1); /// R/W // need firmware version 4.25 & 135.17 + const Reg OverThresholdWidth ("Over Threshold width" , 0x107C, RW::ReadWrite, false, 0xFFFF, 1); /// R/W // need firmware version 4.25 & 135.17 const Reg GroupStatus_R ("Group Status" , 0x1088, RW::ReadONLY, false, {}); /// R/ const Reg AMCFirmwareRevision_R ("AMC firmware version" , 0x108C, RW::ReadONLY, false, {}); /// R/ const Reg DCOffset ("DC offset" , 0x1098, RW::ReadWrite, false, 0xFFFF, -1); /// R/W @@ -819,7 +821,7 @@ namespace DPP { const std::pair ChargeSensitivity = {3, 0} ; /// length, smallest pos const std::pair InternalTestPulse = {1, 4}; const std::pair TestPulseRate = {2, 5}; - //const std::pair OverThresholdWitdhEnable = {1, 7}; ///need firmware version 4.25 & 135.17 + const std::pair OverThresholdWitdhEnable = {1, 7}; ///need firmware version 4.25 & 135.17 const std::pair ChargePedestal = {1, 8}; const std::pair InputSmoothingFactor = {3, 12}; const std::pair Polarity = {1, 16}; @@ -935,7 +937,7 @@ const std::vector RegisterChannelList_QDC = { DPP::QDC::DPPAlgorithmControl, DPP::QDC::TriggerHoldOffWidth, DPP::QDC::TRGOUTWidth, - //DPP::QDC::OverThresholdWidth, + DPP::QDC::OverThresholdWidth, DPP::QDC::GroupStatus_R, DPP::QDC::AMCFirmwareRevision_R, DPP::QDC::DCOffset, @@ -1027,6 +1029,7 @@ const std::vector RegisterBoardList_QDC = { DPP::QDC::NumberEventsPerAggregate, DPP::QDC::RecordLength_W, DPP::QDC::RecordLength_R, + DPP::DecimationFactor, DPP::AcquisitionControl, DPP::AcquisitionStatus_R, DPP::SoftwareTrigger_W, diff --git a/Scope.cpp b/Scope.cpp index 372e719..9a7d4a3 100644 --- a/Scope.cpp +++ b/Scope.cpp @@ -147,12 +147,39 @@ Scope::Scope(Digitizer ** digi, unsigned int nDigi, ReadDataThread ** readDataTh if( digi[ID]->GetDPPType() == V1730_DPP_PSD_CODE ) SetUpPanel_PSD(); if( digi[ID]->GetDPPType() == V1740_DPP_QDC_CODE ) SetUpPanel_QDC(); + if( digi[ID]->GetDPPType() == V1730_DPP_PHA_CODE ) { + QValueAxis * yaxis = qobject_cast (plot->axes(Qt::Vertical).first()); + yaxis->setRange(-(0x1FFF), 0x1FFF); + } + if( digi[ID]->GetDPPType() == V1730_DPP_PSD_CODE ) { + QValueAxis * yaxis = qobject_cast (plot->axes(Qt::Vertical).first()); + yaxis->setRange(0, 0x3FFF); + } + if( digi[ID]->GetDPPType() == V1740_DPP_QDC_CODE ) { + QValueAxis * yaxis = qobject_cast (plot->axes(Qt::Vertical).first()); + yaxis->setRange(0, 0xFFF); + } + ReadSettingsFromBoard(); if( saveACQStartStatus )StartScope(); }); + if( digi[ID]->GetDPPType() == V1730_DPP_PHA_CODE ) { + QValueAxis * yaxis = qobject_cast (plot->axes(Qt::Vertical).first()); + yaxis->setRange(-(0x1FFF), 0x1FFF); + } + if( digi[ID]->GetDPPType() == V1730_DPP_PSD_CODE ) { + QValueAxis * yaxis = qobject_cast (plot->axes(Qt::Vertical).first()); + yaxis->setRange(0, 0x3FFF); + } + if( digi[ID]->GetDPPType() == V1740_DPP_QDC_CODE ) { + QValueAxis * yaxis = qobject_cast (plot->axes(Qt::Vertical).first()); + yaxis->setRange(0, 0xFFF); + } + + connect(cbScopeCh, &RComboBox::currentIndexChanged, this, [=](){ if( !enableSignalSlot ) return; @@ -264,19 +291,6 @@ Scope::Scope(Digitizer ** digi, unsigned int nDigi, ReadDataThread ** readDataTh UpdatePanelFromMomeory(); - if( digi[ID]->GetDPPType() == V1730_DPP_PHA_CODE ) { - QValueAxis * yaxis = qobject_cast (plot->axes(Qt::Vertical).first()); - yaxis->setRange(-(0x1FFF), 0x1FFF); - } - if( digi[ID]->GetDPPType() == V1730_DPP_PSD_CODE ) { - QValueAxis * yaxis = qobject_cast (plot->axes(Qt::Vertical).first()); - yaxis->setRange(0, 0x3FFF); - } - if( digi[ID]->GetDPPType() == V1740_DPP_QDC_CODE ) { - QValueAxis * yaxis = qobject_cast (plot->axes(Qt::Vertical).first()); - yaxis->setRange(0, 0xFFF); - } - workerThread = new QThread(this); scopeWorker = new ScopeWorker(this); scopeTimer = new QTimer(this); @@ -361,9 +375,9 @@ void Scope::StartScope(){ //save present settings, channleMap, trigger condition traceOn[ID] = digi[ID]->IsRecordTrace(); digi[ID]->SetBits(DPP::BoardConfiguration, DPP::Bit_BoardConfig::RecordTrace, 1, -1); - chMask = digi[ID]->GetSettingFromMemory(DPP::RegChannelEnableMask); if( digi[ID]->GetDPPType() == DPPTypeCode::DPP_PHA_CODE ){ + chMask = digi[ID]->GetSettingFromMemory(DPP::RegChannelEnableMask); dppAlg = digi[ID]->GetSettingFromMemory(DPP::DPPAlgorithmControl, ch); dppAlg2 = digi[ID]->GetSettingFromMemory(DPP::PHA::DPPAlgorithmControl2_G, ch); @@ -372,10 +386,13 @@ void Scope::StartScope(){ digi[ID]->SetBits(DPP::PHA::DPPAlgorithmControl2_G, DPP::PHA::Bit_DPPAlgorithmControl2::LocalShapeTriggerMode, 0, ch); digi[ID]->SetBits(DPP::PHA::DPPAlgorithmControl2_G, DPP::PHA::Bit_DPPAlgorithmControl2::LocalTrigValidMode, 0, ch); + + digi[ID]->WriteRegister(DPP::RegChannelEnableMask, (1 << ch)); } if( digi[ID]->GetDPPType() == DPPTypeCode::DPP_PSD_CODE ){ + chMask = digi[ID]->GetSettingFromMemory(DPP::RegChannelEnableMask); dppAlg = digi[ID]->GetSettingFromMemory(DPP::DPPAlgorithmControl, ch); dppAlg2 = digi[ID]->GetSettingFromMemory(DPP::PSD::DPPAlgorithmControl2_G, ch); @@ -384,14 +401,24 @@ void Scope::StartScope(){ digi[ID]->SetBits(DPP::PSD::DPPAlgorithmControl2_G, DPP::PSD::Bit_DPPAlgorithmControl2::LocalShapeTriggerMode, 0, ch); digi[ID]->SetBits(DPP::PSD::DPPAlgorithmControl2_G, DPP::PSD::Bit_DPPAlgorithmControl2::LocalTrigValidMode, 0, ch); + + digi[ID]->WriteRegister(DPP::RegChannelEnableMask, (1 << ch)); } if( digi[ID]->GetDPPType() == DPPTypeCode::DPP_QDC_CODE ){ + chMask = digi[ID]->GetSettingFromMemory(DPP::QDC::GroupEnableMask); + subChMask = digi[ID]->GetSettingFromMemory(DPP::QDC::SubChannelMask); dppAlg = digi[ID]->GetSettingFromMemory(DPP::QDC::DPPAlgorithmControl, ch); digi[ID]->SetBits(DPP::QDC::DPPAlgorithmControl, DPP::QDC::Bit_DPPAlgorithmControl::TriggerMode, 0, ch); //set self-triiger + + digi[ID]->WriteRegister(DPP::QDC::GroupEnableMask, (1 << (ch/8))); + + uint32_t haha = (1 << (ch%8)); + if( ch/8 == 0 ) haha |= 0x1; //must include the first subchannel + + digi[ID]->WriteRegister(DPP::QDC::SubChannelMask, haha); } - digi[ID]->WriteRegister(DPP::RegChannelEnableMask, (1 << ch)); //=========== start digi[ID]->WriteRegister(DPP::SoftwareClear_W, 1); @@ -474,20 +501,23 @@ void Scope::StopScope(){ //restore setting digi[ID]->SetBits(DPP::BoardConfiguration, DPP::Bit_BoardConfig::RecordTrace, traceOn[ID], -1); - digi[ID]->WriteRegister(DPP::RegChannelEnableMask, chMask); if( digi[ID]->GetDPPType() == DPPTypeCode::DPP_PHA_CODE ){ digi[ID]->WriteRegister(DPP::DPPAlgorithmControl, dppAlg, oldCh); digi[ID]->WriteRegister(DPP::PHA::DPPAlgorithmControl2_G, dppAlg2, oldCh); + digi[ID]->WriteRegister(DPP::RegChannelEnableMask, chMask); } if( digi[ID]->GetDPPType() == DPPTypeCode::DPP_PSD_CODE ){ digi[ID]->WriteRegister(DPP::DPPAlgorithmControl, dppAlg, oldCh); digi[ID]->WriteRegister(DPP::PSD::DPPAlgorithmControl2_G, dppAlg2, oldCh); + digi[ID]->WriteRegister(DPP::RegChannelEnableMask, chMask); } if( digi[ID]->GetDPPType() == DPPTypeCode::DPP_QDC_CODE ){ digi[ID]->WriteRegister(DPP::QDC::DPPAlgorithmControl, dppAlg, oldCh); + digi[ID]->WriteRegister(DPP::QDC::GroupEnableMask, chMask); + digi[ID]->WriteRegister(DPP::QDC::SubChannelMask, subChMask); } }else{ diff --git a/Scope.h b/Scope.h index be68607..5498a30 100644 --- a/Scope.h +++ b/Scope.h @@ -86,6 +86,7 @@ private: bool traceOn[MaxNDigitizer]; uint32_t dppAlg, dppAlg2, chMask; //for single channel run + uint32_t subChMask; // for QDC unsigned short oldCh, oldDigi; ReadDataThread ** readDataThread; diff --git a/SingleSpectra.cpp b/SingleSpectra.cpp index bc08501..c23461d 100644 --- a/SingleSpectra.cpp +++ b/SingleSpectra.cpp @@ -4,6 +4,7 @@ #include #include #include +#include // #include SingleSpectra::SingleSpectra(Digitizer ** digi, unsigned int nDigi, QString rawDataPath, QMainWindow * parent) : QMainWindow(parent){ @@ -12,8 +13,7 @@ SingleSpectra::SingleSpectra(Digitizer ** digi, unsigned int nDigi, QString rawD this->nDigi = nDigi; this->settingPath = rawDataPath + "/HistogramSettings.txt"; - maxFillTimeinMilliSec = 1000; - maxFillTimePerDigi = maxFillTimeinMilliSec/nDigi; + maxFillTimeinMilliSec = SingleHistogramFillingTime; isSignalSlotActive = true; @@ -51,15 +51,17 @@ SingleSpectra::SingleSpectra(Digitizer ** digi, unsigned int nDigi, QString rawD isSignalSlotActive = true; //printf("oldCh = %d \n", oldCh); - if( oldCh >= digi[index]->GetNumInputCh()) { - cbCh->setCurrentIndex(0); - }else{ - if( oldCh >= 0 ){ - cbCh->setCurrentIndex(oldCh); - }else{ - cbCh->setCurrentIndex(0); - } - } + // if( oldCh >= digi[index]->GetNumInputCh()) { + // cbCh->setCurrentIndex(0); + // }else{ + // if( oldCh >= 0 ){ + // cbCh->setCurrentIndex(oldCh); + // }else{ + // cbCh->setCurrentIndex(0); + // } + // } + + cbCh->setCurrentIndex(oldChComboBoxindex[index]); ChangeHistView(); }); @@ -81,6 +83,7 @@ SingleSpectra::SingleSpectra(Digitizer ** digi, unsigned int nDigi, QString rawD } }); + chkIsFillHistogram = new QCheckBox("Fill Histograms", this); ctrlLayout->addWidget(chkIsFillHistogram, 0, 6, 1, 2); chkIsFillHistogram->setChecked(false); @@ -133,10 +136,12 @@ SingleSpectra::SingleSpectra(Digitizer ** digi, unsigned int nDigi, QString rawD histLayout->addWidget(hist2D[0], 0, 0); hist2DVisibility[0] = true; - oldBd = 0; - oldCh = digi[0]->GetNumInputCh(); } + //set default oldChComboBoxindex + for( unsigned int i = 0; i < nDigi; i++ ) oldChComboBoxindex[i] = 0; + oldBd = 0; + layout->setStretch(0, 1); layout->setStretch(1, 6); @@ -149,8 +154,16 @@ SingleSpectra::SingleSpectra(Digitizer ** digi, unsigned int nDigi, QString rawD histWorker->moveToThread(workerThread); - // Setup the timer to trigger every second + // this is another way + // timer = new QTimer(); + // timer->moveToThread(workerThread); + // connect(this, &SingleSpectra::startWorkerTimer, timer, static_cast(&QTimer::start)); + // connect(this, &SingleSpectra::stopWorkerTimer, timer, &QTimer::stop); + + isFillingHistograms = false; connect(timer, &QTimer::timeout, histWorker, &HistWorker::FillHistograms); + connect( histWorker, &HistWorker::workDone, this, &SingleSpectra::ReplotHistograms); + workerThread->start(); } @@ -180,7 +193,6 @@ void SingleSpectra::ClearInternalDataCount(){ for( unsigned int i = 0; i < nDigi; i++){ for( int ch = 0; ch < MaxRegChannel ; ch++) { lastFilledIndex[i][ch] = -1; - loopFilledIndex[i][ch] = 0; } } } @@ -195,13 +207,13 @@ void SingleSpectra::ChangeHistView(){ //printf("bd : %d, ch : %d \n", bd, ch); // Remove oldCh - if( oldCh >= 0 && oldCh < digi[oldBd]->GetNumInputCh()){ - histLayout->removeWidget(hist[oldBd][oldCh]); - hist[oldBd][oldCh]->setParent(nullptr); - histVisibility[oldBd][oldCh] = false; - } + int oldCh = oldChComboBoxindex[oldBd] == 0 ? digi[oldBd]->GetNumInputCh() : oldChComboBoxindex[oldBd] - 1; - if( oldCh == digi[oldBd]->GetNumInputCh() ){ + if( oldChComboBoxindex[oldBd] > 0 ){ + histLayout->removeWidget(hist[oldBd][oldCh]); + histVisibility[oldBd][oldCh] = false; + hist[oldBd][oldCh]->setParent(nullptr); + }else{ histLayout->removeWidget(hist2D[oldBd]); hist2D[oldBd]->setParent(nullptr); hist2DVisibility[oldBd] = false; @@ -211,7 +223,6 @@ void SingleSpectra::ChangeHistView(){ if( ch >=0 && ch < digi[bd]->GetNumInputCh()) { histLayout->addWidget(hist[bd][ch], 0, 0); histVisibility[bd][ch] = true; - hist[bd][ch]->UpdatePlot(); } @@ -222,14 +233,7 @@ void SingleSpectra::ChangeHistView(){ } oldBd = bd; - oldCh = ch; - - // for( unsigned int i = 0; i < nDigi; i++ ){ - // if( hist2DVisibility[i] ) printf(" hist2D-%d is visible\n", i); - // for( int j = 0; j < digi[i]->GetNumInputCh(); j++){ - // if( histVisibility[i][j] ) printf(" hist-%d-%d is visible\n", i, j); - // } - // } + oldChComboBoxindex[bd] = cbCh->currentIndex(); } @@ -241,79 +245,111 @@ void SingleSpectra::FillHistograms(){ if( isFillingHistograms) return; isFillingHistograms = true; - timespec t0, t1; + // timespec t0, t1; + timespec ta, tb; - QVector randomDigiList = generateNonRepeatedCombination(nDigi); + printf("####################### SingleSpectra::%s\n", __func__); + // qDebug() << __func__ << "| thread:" << QThread::currentThreadId(); - // qDebug() << randomDigiList; + clock_gettime(CLOCK_REALTIME, &ta); - for( int i = 0; i < nDigi; i++){ - int ID = randomDigiList[i]; + std::vector digiChList; // (digi*1000 + ch) + std::vector digiChLastIndex; // loop * dataSize + index; + std::vector digiChAvalibleData; + std::vector digiChFilled; + std::vector digiChFilledCount; - QVector randomChList = generateNonRepeatedCombination(digi[ID]->GetNumInputCh()); - // qDebug() << randomChList; - // digiMTX[ID].lock(); - // digi[ID]->GetData()->PrintAllData(); - - clock_gettime(CLOCK_REALTIME, &t0); - for( int k = 0; k < digi[ID]->GetNumInputCh(); k ++ ){ - int ch = randomChList[k]; - int lastIndex = digi[ID]->GetData()->GetDataIndex(ch); - if( lastIndex < 0 ) continue; - // printf("--- ch %2d | last index %d \n", ch, lastIndex); - - int loopIndex = digi[ID]->GetData()->GetLoopIndex(ch); - - int temp1 = lastIndex + loopIndex * digi[ID]->GetData()->GetDataSize(); - int temp2 = lastFilledIndex[ID][ch] + loopFilledIndex[ID][ch] * digi[ID]->GetData()->GetDataSize() + 1; - - // printf("loopIndx : %d | ID now : %d, ID old : %d \n", loopIndex, temp1, temp2); + for( int ID = 0; ID < nDigi; ID++){ + for( int ch = 0; ch < digi[ID]->GetNumInputCh(); ch++){ + int temp1 = digi[ID]->GetData()->GetAbsDataIndex(ch); + int temp2 = lastFilledIndex[ID][ch]; if( temp1 <= temp2 ) continue; + digiChList.push_back( ID*1000 + ch ) ; + digiChLastIndex.push_back(temp1); + digiChAvalibleData.push_back(temp1-temp2); + digiChFilled.push_back(false); + digiChFilledCount.push_back(0); - if( temp1 - temp2 > digi[ID]->GetData()->GetDataSize() ) { //DefaultDataSize = 10k - temp2 = temp1 - digi[ID]->GetData()->GetDataSize(); - lastFilledIndex[ID][ch] = lastIndex; - lastFilledIndex[ID][ch] = loopIndex - 1; - } + if( temp1 - temp2 > digi[ID]->GetData()->GetDataSize() ) lastFilledIndex[ID][ch] = temp1 - digi[ID]->GetData()->GetDataSize() ; - // printf("ch %d | regulated ID now %d new %d | last fill idx %d\n", ch, temp2, temp1, lastFilledIndex[ID][ch]); - - for( int j = 0 ; j <= temp1 - temp2; j ++){ - lastFilledIndex[ID][ch] ++; - if( lastFilledIndex[ID][ch] > digi[ID]->GetData()->GetDataSize() ) { - lastFilledIndex[ID][ch] = 0; - loopFilledIndex[ID][ch] ++; - } - - uShort data = digi[ID]->GetData()->GetEnergy(ch, lastFilledIndex[ID][ch]); - - // printf(" ch: %d, last fill idx : %d | %d \n", ch, lastFilledIndex[ID][ch], data); - - hist[ID][ch]->Fill( data ); - if( digi[i]->GetDPPType() == DPPTypeCode::DPP_PSD_CODE ){ - uShort e2 = digi[ID]->GetData()->GetEnergy2(ch, lastFilledIndex[ID][ch]); - // printf("%u \n", e2); - hist[ID][ch]->Fill( e2, 1); - } - hist2D[ID]->Fill(ch, data); - } - if( histVisibility[ID][ch] ) hist[ID][ch]->UpdatePlot(); - - clock_gettime(CLOCK_REALTIME, &t1); - if( t1.tv_nsec - t0.tv_nsec + (t1.tv_sec - t0.tv_sec)*1e9 > maxFillTimePerDigi * 1e6 ) break; } - - if( hist2DVisibility[ID] ) hist2D[ID]->UpdatePlot(); - // digiMTX[ID].unlock(); - } + int nSize = digiChList.size(); + + if( nSize == 0 ) { + isFillingHistograms = false; + return; + } + + // this method, small trigger rate channel will have more chance to fill all data + do{ + size_t filledCount = 0; + for( size_t i = 0; i < digiChFilled.size() ; i++ ){ + if( digiChFilled[i] ) filledCount ++; + } + if( filledCount == digiChFilled.size() ) break; + + int randomValue = QRandomGenerator::global()->bounded(nSize); + if( digiChFilled[randomValue] == true ) continue; + + int ID = digiChList[randomValue] / 1000; + int ch = digiChList[randomValue] % 1000; + // printf(" -------------------- %d / %d | %d\n", randomValue, nSize-1, digiCh); + + if( digiChLastIndex[randomValue] <= lastFilledIndex[ID][ch] ) { + digiChFilled[randomValue] = true; + // printf("Digi-%2d ch-%2d all filled | %zu\n", ID, ch, digiChList.size()); + continue; + } + + lastFilledIndex[ID][ch] ++; + digiChFilledCount[randomValue]++; + + uShort data = digi[ID]->GetData()->GetEnergy(ch, lastFilledIndex[ID][ch]); + + hist[ID][ch]->Fill( data ); + if( digi[ID]->GetDPPType() == DPPTypeCode::DPP_PSD_CODE ){ + uShort e2 = digi[ID]->GetData()->GetEnergy2(ch, lastFilledIndex[ID][ch]); + hist[ID][ch]->Fill( e2, 1); + } + hist2D[ID]->Fill(ch, data); + + // QCoreApplication::processEvents(); + + clock_gettime(CLOCK_REALTIME, &tb); + }while( isFillingHistograms && (tb.tv_nsec - ta.tv_nsec)/1e6 + (tb.tv_sec - ta.tv_sec)*1e3 < maxFillTimeinMilliSec ); + + //*--------------- generate fillign report + for( size_t i = 0; i < digiChFilled.size() ; i++){ + printf("Digi-%2d ch-%2d | event filled %d / %d\n", digiChList[i] / 1000, digiChList[i] % 1000, digiChFilledCount[i], digiChAvalibleData[i] ); + } + + clock_gettime(CLOCK_REALTIME, &tb); + printf("total time : %8.3f ms\n", (tb.tv_nsec - ta.tv_nsec)/1e6 + (tb.tv_sec - ta.tv_sec)*1e3 ); + isFillingHistograms = false; } +void SingleSpectra::ReplotHistograms(){ + + // qDebug() << __func__ << "| thread:" << QThread::currentThreadId(); + + int ID = cbDigi->currentData().toInt(); + int ch = cbCh->currentData().toInt(); + + if( ch == digi[ID]->GetNumInputCh()) { + if( hist2DVisibility[ID] ) hist2D[ID]->UpdatePlot(); + return; + } + + if( histVisibility[ID][ch] ) hist[ID][ch]->UpdatePlot(); + +} + void SingleSpectra::SaveSetting(){ DebugPrint("%s", "SingleSpectra"); diff --git a/SingleSpectra.h b/SingleSpectra.h index 9a0d19d..2808187 100644 --- a/SingleSpectra.h +++ b/SingleSpectra.h @@ -43,16 +43,25 @@ public: QVector generateNonRepeatedCombination(int size); + void ReplotHistograms(); + +signals: + // void startWorkerTimer(int interval); + // void stopWorkerTimer(); + public slots: void FillHistograms(); void ChangeHistView(); void startTimer(){ // printf("timer start\n"); timer->start(maxFillTimeinMilliSec); + // emit startWorkerTimer(maxFillTimeinMilliSec); } void stopTimer(){ // printf("timer stop\n"); timer->stop(); + // emit stopWorkerTimer(); + isFillingHistograms = false; // this will also break the FillHistogram do-loop ClearInternalDataCount(); } @@ -61,17 +70,14 @@ private: Digitizer ** digi; unsigned short nDigi; - int lastFilledIndex[MaxNDigitizer][MaxNChannels]; - int loopFilledIndex[MaxNDigitizer][MaxNChannels]; + long lastFilledIndex[MaxNDigitizer][MaxNChannels]; // index * dataSize + index bool histVisibility[MaxNDigitizer][MaxNChannels]; bool hist2DVisibility[MaxNDigitizer]; - unsigned short maxFillTimePerDigi; bool isFillingHistograms; Histogram1D * hist[MaxNDigitizer][MaxNChannels]; Histogram2D * hist2D[MaxNDigitizer]; - QCheckBox * chkIsFillHistogram; RComboBox * cbDivision; @@ -81,7 +87,8 @@ private: QGroupBox * histBox; QGridLayout * histLayout; - int oldBd, oldCh; + int oldBd; + int oldChComboBoxindex[MaxNDigitizer]; // the ID of hist for display QString settingPath; @@ -95,7 +102,7 @@ private: }; -//^#======================================================== HistWorker +// //^#======================================================== HistWorker class HistWorker : public QObject{ Q_OBJECT public: diff --git a/analyzers/Analyser.cpp b/analyzers/Analyser.cpp index 38330d0..dad6212 100644 --- a/analyzers/Analyser.cpp +++ b/analyzers/Analyser.cpp @@ -60,6 +60,8 @@ Analyzer::Analyzer(Digitizer ** digi, unsigned int nDigi, QMainWindow * parent ) // printf(" --------- work Done\n"); // }); + connect( anaWorker, &AnalyzerWorker::workDone, this, &Analyzer::ReplotHistograms); + anaThread->start(); } @@ -138,12 +140,12 @@ void Analyzer::SetDatabase(QString IP, QString Name, QString Token){ influx = nullptr; } }else{ - printf("Database name : %s NOT found.\n", dataBaseName.toStdString().c_str()); + printf(RED "Database name : %s NOT found.\n" RESET, dataBaseName.toStdString().c_str()); delete influx; influx = nullptr; } }else{ - printf("InfluxDB URL (%s) is NOT Valid. \n", dataBaseIP.toStdString().c_str()); + printf(RED "InfluxDB URL (%s) is NOT Valid. \n" RESET, dataBaseIP.toStdString().c_str()); delete influx; influx = nullptr; } @@ -167,7 +169,7 @@ void Analyzer::RedefineEventBuilder(std::vector idList){ } void Analyzer::BuildEvents(bool verbose){ - + // qDebug() << __func__ << "| thread:" << QThread::currentThreadId(); // unsigned int nData = mb->GetNumOfDigitizer(); // std::vector idList = mb->GetDigiIDList(); // for( unsigned int i = 0; i < nData; i++ ) digiMTX[idList[i]].lock(); @@ -242,4 +244,9 @@ void Analyzer::SetUpCanvas(){ void Analyzer::UpdateHistograms(){ +} + +void Analyzer::ReplotHistograms(){ + + } \ No newline at end of file diff --git a/analyzers/Analyser.h b/analyzers/Analyser.h index 75dade6..8c1a677 100644 --- a/analyzers/Analyser.h +++ b/analyzers/Analyser.h @@ -17,6 +17,7 @@ #include "CustomWidgets.h" #include "MultiBuilder.h" #include "ClassInfluxDB.h" +#include "math.h" /************************************** @@ -62,18 +63,19 @@ public: virtual void SetUpCanvas(); virtual void UpdateHistograms(); // where event-building, analysis, and ploting + virtual void ReplotHistograms(); public slots: void startTimer(){ // printf("start timer\n"); mb->ForceStop(false); - mb->ClearEvents(); anaTimer->start(waitTimeinSec*1000); } void stopTimer(){ // printf("stop worker\n"); anaTimer->stop(); mb->ForceStop(true); + mb->ClearEvents(); } private slots: @@ -130,4 +132,4 @@ private: Analyzer * SS; }; -#endif \ No newline at end of file +#endif diff --git a/analyzers/CoincidentAnalyzer.h b/analyzers/CoincidentAnalyzer.h index 44556e1..93476c8 100644 --- a/analyzers/CoincidentAnalyzer.h +++ b/analyzers/CoincidentAnalyzer.h @@ -31,6 +31,7 @@ public: public slots: void UpdateHistograms(); + void ReplotHistograms(); private: @@ -486,11 +487,6 @@ inline void CoincidentAnalyzer::UpdateHistograms(){ } - h2D->UpdatePlot(); - h1->UpdatePlot(); - hMulti->UpdatePlot(); - h1g->UpdatePlot(); - if( influx ){ QList cutNameList = h2D->GetCutNameList(); for( int p = 0; p < cutList.count(); p ++){ @@ -509,6 +505,13 @@ inline void CoincidentAnalyzer::UpdateHistograms(){ } +inline void CoincidentAnalyzer::ReplotHistograms(){ + h2D->UpdatePlot(); + h1->UpdatePlot(); + hMulti->UpdatePlot(); + h1g->UpdatePlot(); +} + inline void CoincidentAnalyzer::SaveSettings(){ QString filePath = QFileDialog::getSaveFileName(this, "Save Settings to File", diff --git a/analyzers/Cross.h b/analyzers/Cross.h new file mode 100644 index 0000000..c2060f0 --- /dev/null +++ b/analyzers/Cross.h @@ -0,0 +1,311 @@ +#ifndef Cross_h +#define Cross_h + +/********************************************* + * This is online analyzer for PID, ANL + * + * Created by Khushi @ 2024-09-03 + * + * ******************************************/ +#include "Analyser.h" + +class Cross : public Analyzer{ + +public: + Cross(Digitizer ** digi, unsigned int nDigi, QMainWindow * parent = nullptr): Analyzer(digi, nDigi, parent){ + + SetUpdateTimeInSec(1.0); + + RedefineEventBuilder({0}); // only builder for the 0-th digitizer. + tick2ns = digi[0]->GetTick2ns(); + + SetBackwardBuild(false, 100); // using normal building (acceding in time) or backward building, int the case of backward building, default events to be build is 100. + evtbder = GetEventBuilder(); + evtbder->SetTimeWindow(500); + + SetDatabase("http://localhost:8086/", "testing", "zKhzKk4Yhf1l9QU-yE2GsIZ1RazqUgoW3NlF8LJqq_xDMwatOJwg1sKrjgq36uLEsQf8Fmn4sJALP7Kkilk14A=="); + + SetUpCanvas(); // see below + + }; + + void SetUpCanvas(); + +public slots: + void UpdateHistograms(); + void ReplotHistograms(); + +private: + + MultiBuilder *evtbder; + + //Histogram2D * hPID; + + Histogram1D * hdE; // raw dE (ch=1): ch1 + Histogram1D * hE; // raw E (ch=4) : ch4 + Histogram1D * hdT; // raw dT (ch=7): ch7 + + Histogram1D * hTotE; // total energy (dE+E): ch1+ch4 + Histogram1D * hTWin; // coincidence time window TWin: (t4-t1)*1e9 + + Histogram2D * hdEE; // dE versus E : ch1 versus ch4 + Histogram2D * hdEtotE; // dE versus totE : ch1 versus (ch1+ch4) + + Histogram2D * hdEdT; // dE versus TOF: ch1 versus (t7-t1)*1e9 + + Histogram1D * hMulti; //Multiplicity of an event + + int tick2ns; + + int chDE, chE; + float energyDE, energyE, ch7; + unsigned long long t1, t4, t7; + + QPushButton * bnClearHist; + QLabel * lbInfluxIP; + RComboBox * cbLocation; + QCheckBox * chkDEFourTime; + +}; + +inline void Cross::ReplotHistograms(){ + + hdE->UpdatePlot(); + hE->UpdatePlot(); + hdT->UpdatePlot(); + hTotE->UpdatePlot(); + hdEE->UpdatePlot(); + hdEtotE->UpdatePlot(); + hdEdT->UpdatePlot(); + hTWin->UpdatePlot(); + hMulti->UpdatePlot(); + +} + +inline void Cross::SetUpCanvas(){ + + setGeometry(0, 0, 2000, 1000); + + //============ histograms + + //hPID = new Histogram2D("RAISOR", "E", "dE", 100, 0, 5000, 100, 0, 5000, this); + //layout->addWidget(hPID, 2, 0); + + int row = 0; + cbLocation = new RComboBox(this); + cbLocation->addItem("Cross", 0); + cbLocation->addItem("Target", 1); + layout->addWidget(cbLocation, row, 0); + + connect(cbLocation, &RComboBox::currentIndexChanged, this, [=](){ + switch (cbLocation->currentData().toInt() ) { + case 0 : { + hdE->SetLineTitle("raw dE (ch = 0)"); + hE->SetLineTitle("raw E (ch = 2)"); + hdE->replot(); + hE->replot(); + chDE = 0; + chE = 2; + //Can also set histograms range + + } + break; + case 1 : { + hdE->SetLineTitle("raw dE (ch = 1)"); + hE->SetLineTitle("raw E (ch = 4)"); + hdE->replot(); + hE->replot(); + chDE = 1; + chE = 4; + //Can also set histograms range + } + } + }); + + chkDEFourTime = new QCheckBox("dE channel / 4", this); + layout->addWidget(chkDEFourTime, row, 1); + + bnClearHist = new QPushButton("Clear All Hist.", this); + layout->addWidget(bnClearHist, row, 2); + + connect( bnClearHist, &QPushButton::clicked, this, [=](){ + hdE->Clear(); + hE->Clear(); + hdT->Clear(); + hTotE->Clear(); + hdEE->Clear(); + hdEtotE->Clear(); + hdEdT->Clear(); + hTWin->Clear(); + hMulti->Clear(); + }); + + + QString haha; + if( influx ) { + haha = dataBaseIP + ", DB : " + dataBaseName; + }else{ + haha = "No influxDB connection."; + } + lbInfluxIP = new QLabel( haha , this); + if( influx == nullptr ) lbInfluxIP->setStyleSheet("color : red;"); + layout->addWidget(lbInfluxIP, row, 3, 1, 3); + + row ++; + hdEE = new Histogram2D("dE vs E", "E[ch]", "dE[ch]", 500, -100, 5000, 500, -100, 5000, this); + layout->addWidget(hdEE, row, 0, 1, 2); + + hdE = new Histogram1D("raw dE (ch=0)", "dE [ch]", 300, 0, 5000, this); + layout->addWidget(hdE, row, 2); + + hE = new Histogram1D("raw E (ch=2)", "E [ch]", 300, 0, 10000, this); + layout->addWidget(hE, row, 3); + + hTotE = new Histogram1D("total energy (dE+E)", "TotE [ch]", 300, 0, 16000, this); + layout->addWidget(hTotE, row, 4); + + hMulti = new Histogram1D("Multiplicity", "", 10, 0, 10, this); + layout->addWidget(hMulti, row, 5); + + row ++; + hdEtotE = new Histogram2D("dE vs TotE", "TotE[ch]", "dE[ch]", 500, 0, 10000, 500, 0, 5000, this); + layout->addWidget(hdEtotE, row, 0, 1, 2); + + hdT = new Histogram1D("raw dT (ch=7)", "dT [ch]", 300, 0, 1000, this); + layout->addWidget(hdT, row, 2); + + hdEdT = new Histogram2D("dE vs TOF", "TOF [ns]", "dE", 100, 0, 500, 100, 0, 4000, this); + layout->addWidget(hdEdT, row, 3); + + hTWin = new Histogram1D("coincidence time window", "TWin [ns]", 100, 0, 100, this); + layout->addWidget(hTWin, row, 4); + + +} + +inline void Cross::UpdateHistograms(){ + + if( this->isVisible() == false ) return; + + BuildEvents(false); // call the event builder to build events + + //============ Get events, and do analysis + long eventBuilt = evtbder->eventBuilt; + if( eventBuilt == 0 ) return; + + //============ Get the cut list, if any + QList cutList1 = hdEE->GetCutList(); + const int nCut1 = cutList1.count(); + unsigned long long tMin1[nCut1], tMax1[nCut1]; + unsigned int count1[nCut1]; + + QList cutList2 = hdEtotE->GetCutList(); + const int nCut2 = cutList2.count(); + unsigned long long tMin2[nCut2], tMax2[nCut2]; + unsigned int count2[nCut2]; + + //============ Processing data and fill histograms + long eventIndex = evtbder->eventIndex; + long eventStart = eventIndex - eventBuilt + 1; + if(eventStart < 0 ) eventStart += MaxNEvent; + + for( int i = 0; i < nCut1; i++) { + tMin1[i] = -1; + tMax1[i] = 0; + count1[i] = 0; + } + + for( int i = 0; i < nCut2; i++) { + tMin2[i] = -1; + tMax2[i] = 0; + count2[i] = 0; + } + + for( long i = eventStart ; i <= eventIndex; i ++ ){ + + std::vector event = evtbder->events[i]; + //printf("-------------- %ld\n", i); + + if( event.size() == 0 ) return; + + hMulti->Fill(event.size()); + + energyDE = -100; t1 = 0; + energyE = -100; t4 = 0; + ch7 = -100; t7 = 0; + + for( int k = 0; k < (int) event.size(); k++ ){ + //event[k].Print(); + if( event[k].ch == chDE ) {energyDE = event[k].energy; t1 = event[k].timestamp;} // Reads channel 0 of the digitizer corresponding to dE + if( event[k].ch == chE ) {energyE = event[k].energy; t4 = event[k].timestamp;} // Reads channel 2 of the digitizer corresponding to E + if( event[k].ch == 7 ) {ch7 = event[k].energy; t7 = event[k].timestamp;} //RF Timing if setup + + } + + // printf("(E, dE) = (%f, %f)\n", E, dE); + //hPID->Fill(ch4 , ch1); // x, y + //etotal = ch1*0.25*0.25 + ch4 + if( energyDE > 0 ) hdE->Fill(energyDE); + if( energyE > 0 ) hE->Fill(energyE); + if( ch7 > 0 ) hdT->Fill(ch7); + if( energyDE > 0 && energyE > 0 ){ + hTotE->Fill(0.25 * energyDE + energyE); + hdEE->Fill(energyE,energyDE); + if( t4 > t1 ) { + hTWin->Fill((t4-t1)); + }else{ + hTWin->Fill((t1-t4)); + } + hdEtotE->Fill( (chkDEFourTime->isChecked() ? 0.25 : 1) * energyDE + energyE,energyDE); + } + + if( energyDE > 0 && ch7 > 0) hdEdT->Fill((t7-t1)*1e9,energyDE); + + //check events inside any Graphical cut and extract the rate + // if( ch1 == 0 && ch4 == 0 ) continue; + for(int p = 0; p < cutList1.count(); p++ ){ + if( cutList1[p].isEmpty() ) continue; + if( cutList1[p].containsPoint(QPointF(energyE, energyDE), Qt::OddEvenFill) ){ + if( t1 < tMin1[p] ) tMin1[p] = t1; + if( t1 > tMax1[p] ) tMax1[p] = t1; + count1[p] ++; + //printf("hdEE.... %d \n", count1[p]); + } + } + + for(int p = 0; p < cutList2.count(); p++ ){ + if( cutList2[p].isEmpty() ) continue; + if( cutList2[p].containsPoint(QPointF(energyDE+energyE,energyDE), Qt::OddEvenFill) ){ + if( t1 < tMin2[p] ) tMin2[p] = t1; + if( t1 > tMax2[p] ) tMax2[p] = t1; + count2[p] ++; + //printf("hdEtotE.... %d \n", count2[p]); + } + } + } + + + for(int p = 0; p < cutList2.count(); p++ ){ + printf("hdEE.... %d %d \n", p, count1[p]); + } + + //========== output to Influx + QList cutNameList1 = hdEE->GetCutNameList(); + for( int p = 0; p < cutList1.count(); p ++){ + if( cutList1[p].isEmpty() ) continue; + double dT = (tMax1[p]-tMin1[p]) / 1e9; // tick to sec + double rate = count1[p]*1.0/(dT); + //printf("%llu %llu, %f %d\n", tMin1[p], tMax1[p], dT, count1[p]); + printf("%10s | %d | %f Hz \n", cutNameList1[p].toStdString().c_str(), count1[p], rate); + + if( influx ){ + influx->AddDataPoint("Cut,name=" + cutNameList1[p].toStdString()+ " value=" + std::to_string(rate)); + influx->WriteData("testing"); + influx->ClearDataPointsBuffer(); + } + } + +} + + +#endif diff --git a/analyzers/NeutronGamma.h b/analyzers/NeutronGamma.h index 94b10cf..513fbe4 100644 --- a/analyzers/NeutronGamma.h +++ b/analyzers/NeutronGamma.h @@ -59,6 +59,8 @@ public: public slots: void UpdateHistograms(); + void ReplotHistograms(); + private: QVector generateNonRepeatedCombination(int size); void SetUpCanvas(); @@ -74,8 +76,7 @@ private: QGroupBox * histBox; QGridLayout * histLayout; - int lastFilledIndex[MaxNDigitizer][MaxNChannels]; - int loopFilledIndex[MaxNDigitizer][MaxNChannels]; + int lastFilledIndex[MaxNDigitizer][MaxNChannels];// absolute data index = loop * dataSize + index bool fillHistograms; @@ -178,7 +179,6 @@ inline void NeutronGamma::ClearInternalDataCount(){ for( unsigned int i = 0; i < nDigi; i++){ for( int ch = 0; ch < MaxRegChannel ; ch++) { lastFilledIndex[i][ch] = -1; - loopFilledIndex[i][ch] = 0; } } } @@ -187,42 +187,36 @@ inline void NeutronGamma::UpdateHistograms(){ if( !fillHistograms ) return; if( this->isVisible() == false ) return; + // qDebug() << __func__ << "| thread:" << QThread::currentThreadId(); + int ID = cbDigi->currentData().toInt(); int ch = cbCh->currentData().toInt(); - int lastIndex = digi[ID]->GetData()->GetDataIndex(ch); - if( lastIndex < 0 ) return; + if( digi[ID]->GetData()->GetDataIndex(ch) < 0 ) return; - int loopIndex = digi[ID]->GetData()->GetLoopIndex(ch); + int dataAvalible = digi[ID]->GetData()->GetAbsDataIndex(ch) - lastFilledIndex[ID][ch]; - int temp1 = lastIndex + loopIndex * digi[ID]->GetData()->GetDataSize(); - int temp2 = lastFilledIndex[ID][ch] + loopFilledIndex[ID][ch] * digi[ID]->GetData()->GetDataSize() + 1; - - if( temp1 - temp2 > digi[ID]->GetData()->GetDataSize() ) { //DefaultDataSize = 10k - temp2 = temp1 - digi[ID]->GetData()->GetDataSize(); - lastFilledIndex[ID][ch] = lastIndex; - lastFilledIndex[ID][ch] = loopIndex - 1; + if( dataAvalible > digi[ID]->GetData()->GetDataSize() ) { //DefaultDataSize = 10k + lastFilledIndex[ID][ch] = digi[ID]->GetData()->GetAbsDataIndex(ch) - digi[ID]->GetData()->GetDataSize(); } - for( int j = 0 ; j <= temp1 - temp2; j ++){ + do{ lastFilledIndex[ID][ch] ++; - if( lastFilledIndex[ID][ch] > digi[ID]->GetData()->GetDataSize() ) { - lastFilledIndex[ID][ch] = 0; - loopFilledIndex[ID][ch] ++; - } uShort data_long = digi[ID]->GetData()->GetEnergy(ch, lastFilledIndex[ID][ch]); uShort data_short = digi[ID]->GetData()->GetEnergy2(ch, lastFilledIndex[ID][ch]); // printf(" ch: %d, last fill idx : %d | %d \n", ch, lastFilledIndex[ID][ch], data); - double psd = (data_long - data_short) *1.0 / data_long; - hist2D->Fill(data_long, psd); - } + }while(lastFilledIndex[ID][ch] <= digi[ID]->GetData()->GetAbsDataIndex(ch)); + +} + +inline void NeutronGamma::ReplotHistograms(){ + // qDebug() << __func__ << "| thread:" << QThread::currentThreadId(); hist2D->UpdatePlot(); - } inline QVector NeutronGamma::generateNonRepeatedCombination(int size) { diff --git a/analyzers/SplitPoleAnalyzer.h b/analyzers/SplitPoleAnalyzer.h index 088a1fe..c279084 100644 --- a/analyzers/SplitPoleAnalyzer.h +++ b/analyzers/SplitPoleAnalyzer.h @@ -63,6 +63,7 @@ public: public slots: void UpdateHistograms(); + void ReplotHistograms(); private: @@ -421,11 +422,6 @@ inline void SplitPole::UpdateHistograms(){ } } - hPID->UpdatePlot(); - h1->UpdatePlot(); - hMulti->UpdatePlot(); - h1g->UpdatePlot(); - QList cutNameList = hPID->GetCutNameList(); for( int p = 0; p < cutList.count(); p ++){ if( cutList[p].isEmpty() ) continue; @@ -441,5 +437,11 @@ inline void SplitPole::UpdateHistograms(){ } +inline void SplitPole::ReplotHistograms(){ + hPID->UpdatePlot(); + h1->UpdatePlot(); + hMulti->UpdatePlot(); + h1g->UpdatePlot(); +} #endif \ No newline at end of file diff --git a/macro.h b/macro.h index 34c802d..3aea773 100644 --- a/macro.h +++ b/macro.h @@ -11,14 +11,27 @@ #define MaxRecordLength 0x3fff * 8 #define MaxSaveFileSize 1024 * 1024 * 1024 * 2 +#define DefaultDataSize 10000 /// store 10k events per channels + #define ScalarUpdateinMiliSec 1000 // msec +#define SingleHistogramFillingTime 900 // msec + #define MaxDisplayTraceTimeLength 20000 //ns #define ScopeUpdateMiliSec 200 // msec #define MaxNumberOfTrace 5 // in an event #define SETTINGSIZE 2048 +#define RESET "\033[0m" +#define RED "\033[31m" +#define GREEN "\033[32m" +#define YELLOW "\033[33m" +#define BLUE "\033[34m" +#define MAGENTA "\033[35m" +#define CYAN "\033[36m" +#define WHITE "\033[37m" + #define DAQLockFile "DAQLock.dat" #define PIDFile "pid.dat"