From 15a8abd3953f77eb958bcb6fdd49a4834bbe667b Mon Sep 17 00:00:00 2001 From: "Ryan@WorkStation" Date: Thu, 9 Feb 2023 18:27:20 -0500 Subject: [PATCH] move custom thread classes to a new file, move scope to a new class --- .vscode/settings.json | 3 +- ClassDigitizer2Gen.cpp | 4 +- SOLARIS_Qt6_DAQ.pro | 4 +- digiSettings.cpp | 1 - mainwindow.cpp | 638 +++-------------------------------------- mainwindow.h | 142 +-------- manyThread.h | 86 ++++++ scope.cpp | 595 ++++++++++++++++++++++++++++++++++++++ scope.h | 90 ++++++ 9 files changed, 823 insertions(+), 740 deletions(-) create mode 100644 manyThread.h create mode 100644 scope.cpp create mode 100644 scope.h diff --git a/.vscode/settings.json b/.vscode/settings.json index 439eb2b..88215dd 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -66,7 +66,8 @@ "thread": "cpp", "cinttypes": "cpp", "typeinfo": "cpp", - "variant": "cpp" + "variant": "cpp", + "qdatetime": "cpp" }, "better-comments.multilineComments": true, diff --git a/ClassDigitizer2Gen.cpp b/ClassDigitizer2Gen.cpp index b1943bc..79fbd37 100644 --- a/ClassDigitizer2Gen.cpp +++ b/ClassDigitizer2Gen.cpp @@ -6,7 +6,7 @@ Digitizer2Gen::Digitizer2Gen(){ } Digitizer2Gen::~Digitizer2Gen(){ - printf("======== %s \n",__func__); + printf("========Digitizer2Gen::%s \n",__func__); if(isConnected ) CloseDigitizer(); } @@ -196,7 +196,7 @@ int Digitizer2Gen::OpenDigitizer(const char * url){ } int Digitizer2Gen::CloseDigitizer(){ - printf("======== %s \n",__func__); + printf("========Digitizer2Gen::%s \n",__func__); if( isConnected == true ){ ret = CAEN_FELib_Close(handle); if (ret != CAEN_FELib_Success) { diff --git a/SOLARIS_Qt6_DAQ.pro b/SOLARIS_Qt6_DAQ.pro index 53c9659..0f4bdc0 100644 --- a/SOLARIS_Qt6_DAQ.pro +++ b/SOLARIS_Qt6_DAQ.pro @@ -18,5 +18,5 @@ LIBS += -lcurl -lCAEN_FELib #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 # Input -HEADERS += ClassDigitizer2Gen.h Event.h influxdb.h mainwindow.h digiSettings.h Digiparameters.h -SOURCES += ClassDigitizer2Gen.cpp influxdb.cpp main.cpp mainwindow.cpp digiSettings.cpp +HEADERS += ClassDigitizer2Gen.h Event.h influxdb.h mainwindow.h digiSettings.h Digiparameters.h scope.h manyThread.h +SOURCES += ClassDigitizer2Gen.cpp influxdb.cpp main.cpp mainwindow.cpp digiSettings.cpp scope.cpp diff --git a/digiSettings.cpp b/digiSettings.cpp index 7d47033..85d6288 100644 --- a/digiSettings.cpp +++ b/digiSettings.cpp @@ -660,5 +660,4 @@ DigiSettings::~DigiSettings(){ if( cbCh[iDig][i] != NULL) delete cbCh[iDig][i]; } } - } \ No newline at end of file diff --git a/mainwindow.cpp b/mainwindow.cpp index e1e2343..3747350 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -31,8 +32,8 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ digiSetting = NULL; readDataThread = NULL; - SetUpPlot(); - + scope = NULL; + QWidget * mainLayoutWidget = new QWidget(this); setCentralWidget(mainLayoutWidget); QVBoxLayout * layoutMain = new QVBoxLayout(mainLayoutWidget); @@ -60,7 +61,15 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ bnOpenScope = new QPushButton("Open scope", this); bnOpenScope->setEnabled(false); - connect(bnOpenScope, &QPushButton::clicked, this, &MainWindow::OpenScope); + connect(bnOpenScope, &QPushButton::clicked, this, [=](){ + if( digi ){ + if( !scope ){ + scope = new Scope(digi, nDigi, readDataThread, this); + }else{ + scope->show(); + } + } + }); bnOpenDigitizers = new QPushButton("Open Digitizers", this); connect(bnOpenDigitizers, SIGNAL(clicked()), this, SLOT(OpenDigitizers())); @@ -76,6 +85,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ bnSOLSettings = new QPushButton("SOLARIS Settings", this); bnSOLSettings->setEnabled(false); + //QPushButton * newScope = new QPushButton("Scope2", this); + + layout1->addWidget(bnProgramSettings, 0, 0); layout1->addWidget(bnNewExp, 0, 1); layout1->addWidget(lExpName, 0, 2); @@ -85,6 +97,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ layout1->addWidget(bnOpenDigitizers, 1, 1); layout1->addWidget(bnCloseDigitizers, 1, 2, 1, 2); + //layout1->addWidget(newScope, 2, 0); layout1->addWidget(bnDigiSettings, 2, 1); layout1->addWidget(bnSOLSettings, 2, 2, 1, 2); @@ -94,6 +107,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ layout1->setColumnStretch(2, 1); layout1->setColumnStretch(3, 1); + } @@ -181,22 +195,13 @@ MainWindow::~MainWindow(){ //delete bnDigiSettings; //delete bnNewExp; //delete logInfo; - - StopScope(); - - updateTraceThread->Stop(); - updateTraceThread->quit(); - updateTraceThread->wait(); - delete updateTraceThread; - - for( int i = 0; i < 6; i++) delete dataTrace[i]; - //delete [] dataTrace; /// dataTrace must be deleted before plot - delete plot; - - //---- need manually delete - if( digiSetting != NULL ) delete digiSetting; + printf("- %s\n", __func__); CloseDigitizers(); + + //---- need manually delete + if( scope != NULL ) delete scope; + if( digiSetting != NULL ) delete digiSetting; } @@ -294,14 +299,14 @@ void MainWindow::OpenDigitizers(){ bnOpenDigitizers->setEnabled(false); bnOpenDigitizers->setStyleSheet(""); - /// set scope digitizer - allowChange = false; - cbScopeDigi->clear(); ///this will also trigger QComboBox::currentIndexChanged - cbScopeCh->clear(); - for( int i = 0 ; i < nDigi; i++) { - cbScopeDigi->addItem("Digi-" + QString::number(digi[i]->GetSerialNumber()), i); - } - allowChange = true; + ///// set scope digitizer + //allowChange = false; + //cbScopeDigi->clear(); ///this will also trigger QComboBox::currentIndexChanged + //cbScopeCh->clear(); + //for( int i = 0 ; i < nDigi; i++) { + // cbScopeDigi->addItem("Digi-" + QString::number(digi[i]->GetSerialNumber()), i); + //} + //allowChange = true; } @@ -309,13 +314,13 @@ void MainWindow::CloseDigitizers(){ if( digi == NULL) return; - for( int i = 0; i < nDigi; i++){ + for( int i = 0; i < nDigi; i++){ + if( digi[i] == NULL) return; digi[i]->CloseDigitizer(); - delete digi[i]; LogMsg("Closed Digitizer : " + QString::number(digiSerialNum[0])); - + digiSerialNum.clear(); bnOpenDigitizers->setEnabled(true); @@ -336,589 +341,12 @@ void MainWindow::CloseDigitizers(){ delete [] readDataThread; digi = NULL; readDataThread = NULL; - nDigi = 0; bnOpenDigitizers->setFocus(); } //^###################################################################### Open Scope -//TODO ==== seperate Scope into a Scrop Panel class. - -void MainWindow::OpenScope(){ - - if( digi ) { - //*---- get digi setting - int iDigi = cbScopeDigi->currentIndex(); - if( digi[iDigi]->IsDummy() ) return; - - //digi[iDigi]->Reset(); - //digi[iDigi]->ProgramPHA(false); - - StartScope(iDigi); - - bnStartACQ->setEnabled(false); - bnStopACQ->setEnabled(false); - - } - - scope->show(); - -} - -void MainWindow::ReadScopeSettings(int iDigi, int ch){ - if( !digi[iDigi] && digi[iDigi]->IsDummy() ) return; - - printf("%s\n", __func__); - - allowChange = false; - - for( int i = 0 ; i < 2; i++){ - ScopeReadComboBoxValue(iDigi, ch, cbAnaProbe[i], DIGIPARA::CH::AnalogProbe[i]); - } - - for( int i = 0 ; i < 4; i++){ - ScopeReadComboBoxValue(iDigi, ch, cbDigProbe[i], DIGIPARA::CH::DigitalProbe[i]); - } - - ScopeReadComboBoxValue(iDigi, ch, cbPolarity, DIGIPARA::CH::Polarity); - ScopeReadComboBoxValue(iDigi, ch, cbWaveRes, DIGIPARA::CH::WaveResolution); - ScopeReadComboBoxValue(iDigi, ch, cbTrapPeakAvg, DIGIPARA::CH::EnergyFilterPeakingAvg); - ScopeReadComboBoxValue(iDigi, ch, cbBaselineAvg, DIGIPARA::CH::EnergyFilterBaselineAvg); - ScopeReadComboBoxValue(iDigi, ch, cbLowFreqFilter, DIGIPARA::CH::EnergyFilterLowFreqFilter); - - ScopeReadSpinBoxValue(iDigi, ch, sbRL, DIGIPARA::CH::RecordLength); - ScopeReadSpinBoxValue(iDigi, ch, sbPT, DIGIPARA::CH::PreTrigger); - ScopeReadSpinBoxValue(iDigi, ch, sbDCOffset, DIGIPARA::CH::DC_Offset); - ScopeReadSpinBoxValue(iDigi, ch, sbThreshold, DIGIPARA::CH::TriggerThreshold); - ScopeReadSpinBoxValue(iDigi, ch, sbTimeRiseTime, DIGIPARA::CH::TimeFilterRiseTime); - ScopeReadSpinBoxValue(iDigi, ch, sbTimeGuard, DIGIPARA::CH::TimeFilterRetriggerGuard); - ScopeReadSpinBoxValue(iDigi, ch, sbTrapRiseTime, DIGIPARA::CH::EnergyFilterRiseTime); - ScopeReadSpinBoxValue(iDigi, ch, sbTrapFlatTop, DIGIPARA::CH::EnergyFilterFlatTop); - ScopeReadSpinBoxValue(iDigi, ch, sbTrapPoleZero, DIGIPARA::CH::EnergyFilterPoleZero); - ScopeReadSpinBoxValue(iDigi, ch, sbEnergyFineGain, DIGIPARA::CH::EnergyFilterFineGain); - ScopeReadSpinBoxValue(iDigi, ch, sbTrapPeaking, DIGIPARA::CH::EnergyFilterPeakingPosition); - ScopeReadSpinBoxValue(iDigi, ch, sbBaselineGuard, DIGIPARA::CH::EnergyFilterBaselineGuard); - ScopeReadSpinBoxValue(iDigi, ch, sbPileUpGuard, DIGIPARA::CH::EnergyFilterPileUpGuard); - - allowChange = true; -} - -void MainWindow::StartScope(int iDigi){ - - if( !digi ) return; - if( digi[iDigi]->IsDummy() ) return; - - printf("%s\n", __func__); - - int ch = cbScopeCh->currentIndex(); - - //*---- set digitizer to take full trace; since in scope mode, no data saving, speed would be fast (How fast?) - //* when the input rate is faster than trigger rate, Digitizer will stop data taking. - - ReadScopeSettings(iDigi, ch); - - digi[iDigi]->WriteChValue("0..63", DIGIPARA::CH::ChannelEnable, "false"); - digi[iDigi]->WriteChValue(std::to_string(ch), DIGIPARA::CH::ChannelEnable, "true"); - digi[iDigi]->SetPHADataFormat(0); - - digi[iDigi]->StartACQ(); - - readDataThread[iDigi]->SetScopeRun(true); - readDataThread[iDigi]->start(); - - updateTraceThread->start(); - - ScopeControlOnOff(false); - - allowChange = true; -} - -void MainWindow::StopScope(){ - - printf("%s\n", __func__); - - updateTraceThread->Stop(); - updateTraceThread->quit(); - updateTraceThread->wait(); - - if(digi){ - for(int i = 0; i < nDigi; i++){ - if( digi[i]->IsDummy() ) continue; - digiMTX.lock(); - digi[i]->StopACQ(); - digi[i]->WriteChValue("0..63", DIGIPARA::CH::ChannelEnable, "true"); - digiMTX.unlock(); - - readDataThread[i]->quit(); - readDataThread[i]->wait(); - - } - bnStartACQ->setEnabled(true); - bnStopACQ->setEnabled(true); - } - - ScopeControlOnOff(true); - allowChange = true; -} - -void MainWindow::UpdateScope(){ - - if( scope->isVisible() == false) return; - - int iDigi = cbScopeDigi->currentIndex(); - int sample2ns = DIGIPARA::TraceStep * (1 << cbWaveRes->currentIndex()); - - if( digi ){ - digiMTX.lock(); - unsigned int traceLength = digi[iDigi]->evt->traceLenght; - unsigned int dataLength = dataTrace[0]->count(); - - //---- remove all points - for( int j = 0; j < 6; j++ ) dataTrace[j]->removePoints(0, dataLength); - - for( unsigned int i = 0 ; i < traceLength; i++){ - for( int j = 0; j < 2; j++) dataTrace[j]->append(sample2ns * i, digi[iDigi]->evt->analog_probes[j][i]); - for( int j = 2; j < 6; j++) dataTrace[j]->append(sample2ns * i, (j-1)*1000 + 4000 * digi[iDigi]->evt->digital_probes[j-2][i]); - } - - digiMTX.unlock(); - - plot->axes(Qt::Horizontal).first()->setRange(0, sample2ns * traceLength); - } - -} - -void MainWindow::ProbeChange(QComboBox * cb[], const int size ){ - - QStandardItemModel * model[size] = {NULL}; - for( int i = 0; i < size; i++){ - model[i] = qobject_cast(cb[i]->model()); - } - - /// Enable all items - for( int i = 0; i < cb[0]->count(); i++) { - for( int j = 0; j < size; j ++ ) model[j]->item(i)->setEnabled(true); - } - - for( int i = 0; i < size; i++){ - int index = cb[i]->currentIndex(); - for( int j = 0; j < size; j++){ - if( i == j ) continue; - model[j]->item(index)->setEnabled(false); - } - } - - digiMTX.lock(); - if( size == 2) {// analog probes - for( int j = 0; j < 2; j++ )dataTrace[j]->setName(cb[j]->currentText()); - } - if( size == 4){ // digitial probes - for( int j = 2; j < 6; j++ )dataTrace[j]->setName(cb[j-2]->currentText()); - } - digiMTX.unlock(); - -} - -void MainWindow::ScopeControlOnOff(bool on){ - bnScopeStop->setEnabled(!on); - - bnScopeStart->setEnabled(on); - bnScopeReset->setEnabled(on); - bnScopeReadSettings->setEnabled(on); - - sbRL->setEnabled(on); - sbPT->setEnabled(on); - sbDCOffset->setEnabled(on); - sbThreshold->setEnabled(on); - sbTimeRiseTime->setEnabled(on); - sbTimeGuard->setEnabled(on); - sbTrapRiseTime->setEnabled(on); - sbTrapFlatTop->setEnabled(on); - sbTrapPoleZero->setEnabled(on); - sbEnergyFineGain->setEnabled(on); - sbTrapPeaking->setEnabled(on); - cbPolarity->setEnabled(on); - cbWaveRes->setEnabled(on); - cbTrapPeakAvg->setEnabled(on); - - sbBaselineGuard->setEnabled(on); - sbPileUpGuard->setEnabled(on); - cbBaselineAvg->setEnabled(on); - cbLowFreqFilter->setEnabled(on); -} - -void MainWindow::ScopeReadSpinBoxValue(int iDigi, int ch, QSpinBox *sb, std::string digPara){ - std::string ans = digi[iDigi]->ReadChValue(std::to_string(ch), digPara); - sb->setValue(atoi(ans.c_str())); -} - -void MainWindow::ScopeReadComboBoxValue(int iDigi, int ch, QComboBox *cb, std::string digPara){ - std::string ans = digi[iDigi]->ReadChValue(std::to_string(ch), digPara); - int index = cb->findData(QString::fromStdString(ans)); - if( index >= 0 && index < cb->count()) { - cb->setCurrentIndex(index); - }else{ - qDebug() << QString::fromStdString(ans); - } -} - -void MainWindow::ScopeMakeSpinBox(QSpinBox *sb, QString str, QGridLayout *layout, int row, int col, int min, int max, int step, std::string digPara){ - QLabel * lb = new QLabel(str, scope); - lb->setAlignment(Qt::AlignRight | Qt::AlignCenter); - layout->addWidget(lb, row, col); - sb->setMinimum(min); - sb->setMaximum(max); - sb->setSingleStep(abs(step)); - layout->addWidget(sb, row, col+1); - connect(sb, &QSpinBox::valueChanged, this, [=](){ - if( !allowChange ) return; - int iDigi = cbScopeDigi->currentIndex(); - if( step > 1 ) sb->setValue(step*((sb->value() + step - 1)/step)); - digiMTX.lock(); - digi[iDigi]->WriteChValue(std::to_string(cbScopeCh->currentIndex()), digPara, std::to_string(sb->value())); - digiMTX.unlock(); - }); -} - -void MainWindow::ScopeMakeComoBox(QComboBox *cb, QString str, QGridLayout *layout, int row, int col, std::string digPara){ - QLabel * lb = new QLabel(str, scope); - lb->setAlignment(Qt::AlignRight | Qt::AlignCenter); - layout->addWidget(lb, row, col); - layout->addWidget(cb, row, col+1); - connect(cb, &QComboBox::currentIndexChanged, this, [=](){ - if( !allowChange ) return; - int iDigi = cbScopeDigi->currentIndex(); - digiMTX.lock(); - digi[iDigi]->WriteChValue(std::to_string(cbScopeCh->currentIndex()), digPara, cb->currentData().toString().toStdString()); - digiMTX.unlock(); - }); -} - -void MainWindow::SetUpPlot(){ //@--- this function run at start up - scope = new QMainWindow(this); - scope->setWindowTitle("Scope"); - scope->setGeometry(0, 0, 1000, 800); - scope->setWindowFlags( scope->windowFlags() & ~Qt::WindowCloseButtonHint ); - - allowChange = false; - - plot = new QChart(); - for( int i = 0; i < 6; i++) { - dataTrace[i] = new QLineSeries(); - dataTrace[i]->setName("Trace " + QString::number(i)); - for(int j = 0; j < 100; j ++) dataTrace[i]->append(j, QRandomGenerator::global()->bounded(8000) + 8000); - plot->addSeries(dataTrace[i]); - } - - dataTrace[0]->setPen(QPen(Qt::red, 2)); - dataTrace[1]->setPen(QPen(Qt::blue, 2)); - dataTrace[2]->setPen(QPen(Qt::darkRed, 1)); - dataTrace[3]->setPen(QPen(Qt::darkYellow, 1)); - dataTrace[4]->setPen(QPen(Qt::darkGreen, 1)); - dataTrace[5]->setPen(QPen(Qt::darkBlue, 1)); - - plot->createDefaultAxes(); /// this must be after addSeries(); - /// this must be after createDefaultAxes(); - QValueAxis * yaxis = qobject_cast (plot->axes(Qt::Vertical).first()); - QValueAxis * xaxis = qobject_cast (plot->axes(Qt::Horizontal).first()); - yaxis->setTickCount(6); - yaxis->setTickInterval(16384); - yaxis->setRange(-16384, 65536); - yaxis->setLabelFormat("%.0f"); - - xaxis->setRange(0, 5000); - xaxis->setTickCount(11); - xaxis->setLabelFormat("%.0f"); - xaxis->setTitleText("Time [ns]"); - - updateTraceThread = new UpdateTraceThread(); - connect(updateTraceThread, &UpdateTraceThread::updateTrace, this, &MainWindow::UpdateScope); - - //*================ add Widgets - int rowID = -1; - QWidget * layoutWidget = new QWidget(scope); - scope->setCentralWidget(layoutWidget); - QGridLayout * layout = new QGridLayout(layoutWidget); - layoutWidget->setLayout(layout); - - //------------ Digitizer + channel selection - rowID ++; - cbScopeDigi = new QComboBox(scope); - cbScopeCh = new QComboBox(scope); - layout->addWidget(cbScopeDigi, rowID, 0); - layout->addWidget(cbScopeCh, rowID, 1); - - connect(cbScopeDigi, &QComboBox::currentIndexChanged, this, [=](){ - //if( allowChange ) StopScope(); - int index = cbScopeDigi->currentIndex(); - if( index == -1 ) return; - for( int i = 0; i < digi[index]->GetNChannels(); i++){ - cbScopeCh->addItem("ch-" + QString::number(i), i); - } - //if( allowChange )StartScope(index); - }); - - connect(cbScopeCh, &QComboBox::currentIndexChanged, this, [=](){ - if( !allowChange ) return; - int iDigi = cbScopeDigi->currentIndex(); - int ch = cbScopeCh->currentIndex(); - digiMTX.lock(); - digi[iDigi]->WriteChValue("0..63", DIGIPARA::CH::ChannelEnable, "false"); - digi[iDigi]->WriteChValue(std::to_string(ch), DIGIPARA::CH::ChannelEnable, "true"); - ReadScopeSettings(iDigi, ch); - digiMTX.unlock(); - }); - - bnScopeReset = new QPushButton("ReProgram Digitizer", scope); - layout->addWidget(bnScopeReset, rowID, 2); - connect(bnScopeReset, &QPushButton::clicked, this, [=](){ - if( !allowChange ) return; - int iDigi = cbScopeDigi->currentIndex(); - digi[iDigi]->Reset(); - digi[iDigi]->ProgramPHA(false); - }); - - bnScopeReadSettings = new QPushButton("Read Ch. Settings", scope); - layout->addWidget(bnScopeReadSettings, rowID, 3); - connect(bnScopeReadSettings, &QPushButton::clicked, this, [=](){ - if( !allowChange ) return; - ReadScopeSettings(cbScopeDigi->currentIndex(), cbScopeCh->currentIndex()); - }); - - //TODO----- add copy settings and paste settings - QCheckBox * chkSetAllChannel = new QCheckBox("apply to all channels", scope); - layout->addWidget(chkSetAllChannel, rowID, 4); - - //------------ Probe selection - rowID ++; - //TODO --- add None - cbAnaProbe[0] = new QComboBox(scope); - cbAnaProbe[0]->addItem("ADC Input", "ADCInput"); - cbAnaProbe[0]->addItem("Time Filter", "TimeFilter"); - cbAnaProbe[0]->addItem("Trapazoid", "EnergyFilter"); - cbAnaProbe[0]->addItem("Trap. Baseline", "EnergyFilterBaseline"); - cbAnaProbe[0]->addItem("Trap. - Baseline", "EnergyFilterMinusBaseline"); - - cbAnaProbe[1] = new QComboBox(scope); - for( int i = 0; i < cbAnaProbe[0]->count() ; i++) cbAnaProbe[1]->addItem(cbAnaProbe[0]->itemText(i), cbAnaProbe[0]->itemData(i)); - - connect(cbAnaProbe[0], &QComboBox::currentIndexChanged, this, [=](){ this->ProbeChange(cbAnaProbe, 2);}); - connect(cbAnaProbe[1], &QComboBox::currentIndexChanged, this, [=](){ this->ProbeChange(cbAnaProbe, 2);}); - - cbAnaProbe[0]->setCurrentIndex(1); ///trigger the AnaProbeChange - cbAnaProbe[0]->setCurrentIndex(0); - cbAnaProbe[1]->setCurrentIndex(4); - - connect(cbAnaProbe[0], &QComboBox::currentIndexChanged, this, [=](){ - if( !allowChange ) return; - int iDigi = cbScopeDigi->currentIndex(); - int ch = cbScopeCh->currentIndex(); - digiMTX.lock(); - digi[iDigi]->WriteChValue(std::to_string(ch), DIGIPARA::CH::WaveAnalogProbe0, (cbAnaProbe[0]->currentData()).toString().toStdString()); - digiMTX.unlock(); - }); - - connect(cbAnaProbe[1], &QComboBox::currentIndexChanged, this, [=](){ - if( !allowChange ) return; - int iDigi = cbScopeDigi->currentIndex(); - int ch = cbScopeCh->currentIndex(); - digiMTX.lock(); - digi[iDigi]->WriteChValue(std::to_string(ch), DIGIPARA::CH::WaveAnalogProbe1, (cbAnaProbe[1]->currentData()).toString().toStdString()); - digiMTX.unlock(); - }); - - //TODO --- add None - cbDigProbe[0] = new QComboBox(scope); - cbDigProbe[0]->addItem("Trigger", "Trigger"); - cbDigProbe[0]->addItem("Time Filter Armed", "TimeFilterArmed"); - cbDigProbe[0]->addItem("ReTrigger Guard", "ReTriggerGuard"); - cbDigProbe[0]->addItem("Trap. basline Freeze", "EnergyFilterBaselineFreeze"); - cbDigProbe[0]->addItem("Peaking", "EnergyFilterPeaking"); - cbDigProbe[0]->addItem("Peak Ready", "EnergyFilterPeakReady"); - cbDigProbe[0]->addItem("Pile-up Guard", "EnergyFilterPileUpGuard"); - cbDigProbe[0]->addItem("Event Pile Up", "EventPileUp"); - cbDigProbe[0]->addItem("ADC Saturate", "ADCSaturation"); - cbDigProbe[0]->addItem("ADC Sat. Protection", "ADCSaturationProtection"); - cbDigProbe[0]->addItem("Post Sat. Event", "PostSaturationEvent"); - cbDigProbe[0]->addItem("Trap. Saturate", "EnergylterSaturation"); - cbDigProbe[0]->addItem("ACQ Inhibit", "AcquisitionInhibit"); - - cbDigProbe[1] = new QComboBox(scope); - cbDigProbe[2] = new QComboBox(scope); - cbDigProbe[3] = new QComboBox(scope); - for( int i = 0; i < cbDigProbe[0]->count() ; i++) { - cbDigProbe[1]->addItem(cbDigProbe[0]->itemText(i), cbDigProbe[0]->itemData(i)); - cbDigProbe[2]->addItem(cbDigProbe[0]->itemText(i), cbDigProbe[0]->itemData(i)); - cbDigProbe[3]->addItem(cbDigProbe[0]->itemText(i), cbDigProbe[0]->itemData(i)); - } - - connect(cbDigProbe[0], &QComboBox::currentIndexChanged, this, [=](){ this->ProbeChange(cbDigProbe, 4);}); - connect(cbDigProbe[1], &QComboBox::currentIndexChanged, this, [=](){ this->ProbeChange(cbDigProbe, 4);}); - connect(cbDigProbe[2], &QComboBox::currentIndexChanged, this, [=](){ this->ProbeChange(cbDigProbe, 4);}); - connect(cbDigProbe[3], &QComboBox::currentIndexChanged, this, [=](){ this->ProbeChange(cbDigProbe, 4);}); - - cbDigProbe[0]->setCurrentIndex(1); ///trigger the DigProbeChange - cbDigProbe[0]->setCurrentIndex(0); - cbDigProbe[1]->setCurrentIndex(4); - cbDigProbe[2]->setCurrentIndex(5); - cbDigProbe[3]->setCurrentIndex(6); - - connect(cbDigProbe[0], &QComboBox::currentIndexChanged, this, [=](){ - if( !allowChange ) return; - int iDigi = cbScopeDigi->currentIndex(); - int ch = cbScopeCh->currentIndex(); - digiMTX.lock(); - digi[iDigi]->WriteChValue(std::to_string(ch), DIGIPARA::CH::WaveDigitalProbe0, (cbDigProbe[0]->currentData()).toString().toStdString()); - digiMTX.unlock(); - }); - connect(cbDigProbe[1], &QComboBox::currentIndexChanged, this, [=](){ - if( !allowChange ) return; - int iDigi = cbScopeDigi->currentIndex(); - int ch = cbScopeCh->currentIndex(); - digiMTX.lock(); - digi[iDigi]->WriteChValue(std::to_string(ch), DIGIPARA::CH::WaveDigitalProbe1, (cbDigProbe[1]->currentData()).toString().toStdString()); - digiMTX.unlock(); - }); - connect(cbDigProbe[2], &QComboBox::currentIndexChanged, this, [=](){ - if( !allowChange ) return; - int iDigi = cbScopeDigi->currentIndex(); - int ch = cbScopeCh->currentIndex(); - digiMTX.lock(); - digi[iDigi]->WriteChValue(std::to_string(ch), DIGIPARA::CH::WaveDigitalProbe2, (cbDigProbe[2]->currentData()).toString().toStdString()); - digiMTX.unlock(); - }); - connect(cbDigProbe[3], &QComboBox::currentIndexChanged, this, [=](){ - if( !allowChange ) return; - int iDigi = cbScopeDigi->currentIndex(); - int ch = cbScopeCh->currentIndex(); - digiMTX.lock(); - digi[iDigi]->WriteChValue(std::to_string(ch), DIGIPARA::CH::WaveDigitalProbe3, (cbDigProbe[3]->currentData()).toString().toStdString()); - digiMTX.unlock(); - }); - - layout->addWidget(cbAnaProbe[0], rowID, 0); - layout->addWidget(cbAnaProbe[1], rowID, 1); - - layout->addWidget(cbDigProbe[0], rowID, 2); - layout->addWidget(cbDigProbe[1], rowID, 3); - layout->addWidget(cbDigProbe[2], rowID, 4); - layout->addWidget(cbDigProbe[3], rowID, 5); - - rowID ++; - {//------------ wave settings - QGroupBox * box = new QGroupBox("Channel Settings (need ACQ stop)", scope); - layout->addWidget(box, rowID, 0, 1, 6); - - QGridLayout * bLayout = new QGridLayout(box); - bLayout->setSpacing(0); - - sbRL = new QSpinBox(scope); - ScopeMakeSpinBox(sbRL, "Record Lenght [ns] ", bLayout, 0, 0, 32, 648000, DIGIPARA::TraceStep, DIGIPARA::CH::RecordLength); - - sbThreshold = new QSpinBox(scope); - ScopeMakeSpinBox(sbThreshold, "Threshold [LSB] ", bLayout, 0, 2, 0, 8191, -20, DIGIPARA::CH::TriggerThreshold); - - cbPolarity = new QComboBox(scope); - cbPolarity->addItem("Pos. +", "Positive"); - cbPolarity->addItem("Neg. -", "Negative"); - ScopeMakeComoBox(cbPolarity, "Polarity ", bLayout, 0, 4, DIGIPARA::CH::Polarity); - - cbWaveRes = new QComboBox(scope); - cbWaveRes->addItem(" 8 ns", "RES8"); - cbWaveRes->addItem("16 ns", "RES16"); - cbWaveRes->addItem("32 ns", "RES32"); - cbWaveRes->addItem("64 ns", "RES64"); - ScopeMakeComoBox(cbWaveRes, "Wave Re. ", bLayout, 0, 6, DIGIPARA::CH::WaveResolution); - - //------------------ next row - sbPT = new QSpinBox(scope); - ScopeMakeSpinBox(sbPT, "Pre Trigger [ns] ", bLayout, 1, 0, 32, 32000, DIGIPARA::TraceStep, DIGIPARA::CH::PreTrigger); - - sbDCOffset = new QSpinBox(scope); - ScopeMakeSpinBox(sbDCOffset, "DC offset [%] ", bLayout, 1, 2, 0, 100, -10, DIGIPARA::CH::DC_Offset); - - sbTimeRiseTime = new QSpinBox(scope); - ScopeMakeSpinBox(sbTimeRiseTime, "Trigger Rise Time [ns] ", bLayout, 1, 4, 32, 2000, DIGIPARA::TraceStep, DIGIPARA::CH::TimeFilterRiseTime); - - sbTimeGuard = new QSpinBox(scope); - ScopeMakeSpinBox(sbTimeGuard, "Trigger Guard [ns] ", bLayout, 1, 6, 0, 8000, DIGIPARA::TraceStep, DIGIPARA::CH::TimeFilterRetriggerGuard); - - //----------------- next row - sbTrapRiseTime = new QSpinBox(scope); - ScopeMakeSpinBox(sbTrapRiseTime, "Trap. Rise Time [ns] ", bLayout, 2, 0, 32, 13000, DIGIPARA::TraceStep, DIGIPARA::CH::EnergyFilterRiseTime); - - sbTrapFlatTop = new QSpinBox(scope); - ScopeMakeSpinBox(sbTrapFlatTop, "Trap. Flat Top [ns] ", bLayout, 2, 2, 32, 3000, DIGIPARA::TraceStep, DIGIPARA::CH::EnergyFilterFlatTop); - - sbTrapPoleZero = new QSpinBox(scope); - ScopeMakeSpinBox(sbTrapPoleZero, "Trap. Pole Zero [ns] ", bLayout, 2, 4, 32, 524000, DIGIPARA::TraceStep, DIGIPARA::CH::EnergyFilterPoleZero); - - sbEnergyFineGain = new QSpinBox(scope); - ScopeMakeSpinBox(sbEnergyFineGain, "Energy Fine Gain ", bLayout, 2, 6, 1, 10, -1, DIGIPARA::CH::EnergyFilterFineGain); - - //----------------- next row - sbTrapPeaking = new QSpinBox(scope); - ScopeMakeSpinBox(sbTrapPeaking, "Trap. Peaking [%] ", bLayout, 3, 0, 1, 100, -10, DIGIPARA::CH::EnergyFilterPeakingPosition); - - cbTrapPeakAvg = new QComboBox(scope); - cbTrapPeakAvg->addItem(" 1 sample", "OneShot"); - cbTrapPeakAvg->addItem(" 4 sample", "LowAVG"); - cbTrapPeakAvg->addItem("16 sample", "MediumAVG"); - cbTrapPeakAvg->addItem("64 sample", "HighAVG"); - ScopeMakeComoBox(cbTrapPeakAvg, "Trap. Peaking ", bLayout, 3, 2, DIGIPARA::CH::EnergyFilterPeakingAvg); - - sbBaselineGuard = new QSpinBox(scope); - ScopeMakeSpinBox(sbBaselineGuard, "Baseline Guard [ns] ", bLayout, 3, 4, 0, 8000, DIGIPARA::TraceStep, DIGIPARA::CH::EnergyFilterBaselineGuard); - - cbBaselineAvg = new QComboBox(scope); - cbBaselineAvg->addItem(" 0 samp.", "Fixed"); - cbBaselineAvg->addItem(" 16 samp.", "VeryLow"); - cbBaselineAvg->addItem(" 64 samp.", "Low"); - cbBaselineAvg->addItem(" 256 samp.", "MediumLow"); - cbBaselineAvg->addItem(" 1024 samp.", "Medium"); - cbBaselineAvg->addItem(" 4096 samp.", "MediumHigh"); - cbBaselineAvg->addItem("16384 samp.", "High"); - ScopeMakeComoBox(cbBaselineAvg, "Baseline Avg ", bLayout, 3, 6, DIGIPARA::CH::EnergyFilterBaselineAvg); - //---------------- - - sbPileUpGuard = new QSpinBox(scope); - ScopeMakeSpinBox(sbPileUpGuard, "Pile-up Guard [ns] ", bLayout, 4, 0, 0, 64000, DIGIPARA::TraceStep, DIGIPARA::CH::EnergyFilterPileUpGuard); - - cbLowFreqFilter = new QComboBox(scope); - cbLowFreqFilter->addItem("Disabled", "0"); - cbLowFreqFilter->addItem("Enabled", "1"); - ScopeMakeComoBox(cbLowFreqFilter, "Low Freq. Filter ", bLayout, 4, 2, DIGIPARA::CH::EnergyFilterLowFreqFilter); - - } - - //------------ plot view - rowID ++; - QChartView * plotView = new QChartView(plot); - plotView->setRenderHints(QPainter::Antialiasing); - layout->addWidget(plotView, rowID, 0, 1, 6); - - //TODO zoom and pan, see Zoom Line example - - //------------ close button - rowID ++; - bnScopeStart = new QPushButton("Start", scope); - layout->addWidget(bnScopeStart, rowID, 0); - bnScopeStart->setEnabled(false); - connect(bnScopeStart, &QPushButton::clicked, this, [=](){this->StartScope(cbScopeDigi->currentIndex());}); - - bnScopeStop = new QPushButton("Stop", scope); - layout->addWidget(bnScopeStop, rowID, 1); - connect(bnScopeStop, &QPushButton::clicked, this, &MainWindow::StopScope); - - QPushButton * bnClose = new QPushButton("Close", scope); - layout->addWidget(bnClose, rowID, 5); - connect(bnClose, &QPushButton::clicked, this, &MainWindow::StopScope); - connect(bnClose, &QPushButton::clicked, scope, &QMainWindow::close); - -} - - //^###################################################################### Open digitizer setting panel void MainWindow::OpenDigitizersSettings(){ LogMsg("Open digitizers Settings Panel"); diff --git a/mainwindow.h b/mainwindow.h index 77a3b1d..74383c9 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -5,100 +5,25 @@ #include #include #include -#include #include #include #include #include #include -#include + #include #include #include #include // time in nano-sec -#include "digiSettings.h" - #include "ClassDigitizer2Gen.h" #include "influxdb.h" -static QMutex digiMTX; - -//^#===================================================== ReadData Thread -class ReadDataThread : public QThread { - Q_OBJECT -public: - ReadDataThread(Digitizer2Gen * dig, QObject * parent = 0) : QThread(parent){ - this->digi = dig; - isScopeRun = false; - } - void SetScopeRun(bool onOff) {this->isScopeRun = onOff;} - void run(){ - clock_gettime(CLOCK_REALTIME, &ta); - while(true){ - digiMTX.lock(); - int ret = digi->ReadData(); - digiMTX.unlock(); - - if( ret == CAEN_FELib_Success){ - if( !isScopeRun) digi->SaveDataToFile(); - }else if(ret == CAEN_FELib_Stop){ - digi->ErrorMsg("No more data"); - break; - }else{ - digi->ErrorMsg("ReadDataLoop()"); - digi->evt->ClearTrace(); - } - - if( !isScopeRun ){ - clock_gettime(CLOCK_REALTIME, &tb); - if( tb.tv_sec - ta.tv_sec > 2 ) { - emit sendMsg("FileSize : " + QString::number(digi->GetFileSize()/1024./1024.) + " MB"); - - //double duration = tb.tv_nsec-ta.tv_nsec + tb.tv_sec*1e+9 - ta.tv_sec*1e+9; - //printf("%4d, duration : %10.0f, %6.1f\n", readCount, duration, 1e9/duration); - ta = tb; - } - } - } - } -signals: - void sendMsg(const QString &msg); -private: - Digitizer2Gen * digi; - timespec ta, tb; - bool isScopeRun; -}; - -//^#===================================================== UpdateTrace Thread -class UpdateTraceThread : public QThread { - Q_OBJECT -public: - UpdateTraceThread(QObject * parent = 0) : QThread(parent){ - waitTime = 2; - stop = false; - } - void Stop() {this->stop = true;} - void run(){ - unsigned int count = 0; - stop = false; - do{ - usleep(100000); - count ++; - if( count % waitTime == 0){ - emit updateTrace(); - } - }while(!stop); - } -signals: - void updateTrace(); - -private: - bool stop; - unsigned int waitTime; //100 of milisec -}; +#include "manyThread.h" +#include "digiSettings.h" +#include "scope.h" //^#===================================================== MainWindow class MainWindow : public QMainWindow{ @@ -114,18 +39,6 @@ private slots: void OpenDigitizers(); void CloseDigitizers(); - void OpenScope(); - void ReadScopeSettings(int iDigi, int ch); - void StartScope(int iDigi); - void StopScope(); - void UpdateScope(); - void ScopeControlOnOff(bool on); - void ScopeReadSpinBoxValue(int iDigi, int ch, QSpinBox *sb, std::string digPara); - void ScopeReadComboBoxValue(int iDigi, int ch, QComboBox *cb, std::string digPara); - void ScopeMakeSpinBox(QSpinBox * sb, QString str, QGridLayout* layout, int row, int col, int min, int max, int step, std::string digPara); - void ScopeMakeComoBox(QComboBox * cb, QString str, QGridLayout* layout, int row, int col, std::string digPara); - void SetUpPlot(); - void OpenDigitizersSettings(); void ProgramSettings(); @@ -139,6 +52,13 @@ private slots: void ChangeExperiment(const QString newExpName); void CreateRawDataFolderAndLink(const QString newExpName); + void closeEvent(QCloseEvent * event){ + if( digiSetting != NULL ) digiSetting->close(); + if( scope != NULL ) scope->close(); + event->accept(); + } + + signals : private: @@ -153,45 +73,9 @@ private: QPushButton * bnDigiSettings; QPushButton * bnSOLSettings; - //@------ scope things - QMainWindow * scope; + //@--- new scope + Scope * scope; QPushButton * bnOpenScope; - QChart * plot; - QLineSeries * dataTrace[6]; - UpdateTraceThread * updateTraceThread; - QComboBox * cbScopeDigi; - QComboBox * cbScopeCh; - QPushButton * bnScopeReset; - QPushButton * bnScopeReadSettings; - - - QPushButton * bnScopeStart; - QPushButton * bnScopeStop; - - QComboBox * cbAnaProbe[2]; - QComboBox * cbDigProbe[4]; - QSpinBox * sbRL; // record length - QSpinBox * sbPT; // pre trigger - QSpinBox * sbDCOffset; - QSpinBox * sbThreshold; - QSpinBox * sbTimeRiseTime; - QSpinBox * sbTimeGuard; - QSpinBox * sbTrapRiseTime; - QSpinBox * sbTrapFlatTop; - QSpinBox * sbTrapPoleZero; - QSpinBox * sbEnergyFineGain; - QSpinBox * sbTrapPeaking; - QComboBox * cbPolarity; - QComboBox * cbWaveRes; - QComboBox * cbTrapPeakAvg; - - QSpinBox * sbBaselineGuard; - QSpinBox * sbPileUpGuard; - QComboBox * cbBaselineAvg; - QComboBox * cbLowFreqFilter; - - bool allowChange; - void ProbeChange(QComboBox * cb[], const int size); //@------ ACQ things QPushButton * bnStartACQ; diff --git a/manyThread.h b/manyThread.h new file mode 100644 index 0000000..162398f --- /dev/null +++ b/manyThread.h @@ -0,0 +1,86 @@ + +#ifndef MANYTHREADS_H +#define MANYTHREADS_H + +#include +#include + +#include "ClassDigitizer2Gen.h" + +static QMutex digiMTX; + +//^#===================================================== ReadData Thread +class ReadDataThread : public QThread { + Q_OBJECT +public: + ReadDataThread(Digitizer2Gen * dig, QObject * parent = 0) : QThread(parent){ + this->digi = dig; + isScopeRun = false; + } + void SetScopeRun(bool onOff) {this->isScopeRun = onOff;} + void run(){ + clock_gettime(CLOCK_REALTIME, &ta); + while(true){ + digiMTX.lock(); + int ret = digi->ReadData(); + digiMTX.unlock(); + + if( ret == CAEN_FELib_Success){ + if( !isScopeRun) digi->SaveDataToFile(); + }else if(ret == CAEN_FELib_Stop){ + digi->ErrorMsg("No more data"); + break; + }else{ + digi->ErrorMsg("ReadDataLoop()"); + digi->evt->ClearTrace(); + } + + if( !isScopeRun ){ + clock_gettime(CLOCK_REALTIME, &tb); + if( tb.tv_sec - ta.tv_sec > 2 ) { + emit sendMsg("FileSize : " + QString::number(digi->GetFileSize()/1024./1024.) + " MB"); + + //double duration = tb.tv_nsec-ta.tv_nsec + tb.tv_sec*1e+9 - ta.tv_sec*1e+9; + //printf("%4d, duration : %10.0f, %6.1f\n", readCount, duration, 1e9/duration); + ta = tb; + } + } + } + } +signals: + void sendMsg(const QString &msg); +private: + Digitizer2Gen * digi; + timespec ta, tb; + bool isScopeRun; +}; + +//^#===================================================== UpdateTrace Thread +class UpdateTraceThread : public QThread { + Q_OBJECT +public: + UpdateTraceThread(QObject * parent = 0) : QThread(parent){ + waitTime = 2; + stop = false; + } + void Stop() {this->stop = true;} + void run(){ + unsigned int count = 0; + stop = false; + do{ + usleep(100000); + count ++; + if( count % waitTime == 0){ + emit updateTrace(); + } + }while(!stop); + } +signals: + void updateTrace(); + +private: + bool stop; + unsigned int waitTime; //100 of milisec +}; + +#endif diff --git a/scope.cpp b/scope.cpp new file mode 100644 index 0000000..51dc92e --- /dev/null +++ b/scope.cpp @@ -0,0 +1,595 @@ +#include "scope.h" + +#include +#include +#include +#include +#include +#include + + +Scope::Scope(Digitizer2Gen **digi, unsigned int nDigi, ReadDataThread ** readDataThread, QMainWindow *parent) : QMainWindow(parent){ + this->digi = digi; + this->nDigi = nDigi; + this->readDataThread = readDataThread; + + setWindowTitle("Scope"); + setGeometry(0, 0, 1000, 800); + setWindowFlags( this->windowFlags() & ~Qt::WindowCloseButtonHint ); + + allowChange = false; + + plot = new QChart(); + for( int i = 0; i < 6; i++) { + dataTrace[i] = new QLineSeries(); + dataTrace[i]->setName("Trace " + QString::number(i)); + for(int j = 0; j < 100; j ++) dataTrace[i]->append(j, QRandomGenerator::global()->bounded(8000) + 8000); + plot->addSeries(dataTrace[i]); + } + + dataTrace[0]->setPen(QPen(Qt::red, 2)); + dataTrace[1]->setPen(QPen(Qt::blue, 2)); + dataTrace[2]->setPen(QPen(Qt::darkRed, 1)); + dataTrace[3]->setPen(QPen(Qt::darkYellow, 1)); + dataTrace[4]->setPen(QPen(Qt::darkGreen, 1)); + dataTrace[5]->setPen(QPen(Qt::darkBlue, 1)); + + plot->createDefaultAxes(); /// this must be after addSeries(); + /// this must be after createDefaultAxes(); + QValueAxis * yaxis = qobject_cast (plot->axes(Qt::Vertical).first()); + QValueAxis * xaxis = qobject_cast (plot->axes(Qt::Horizontal).first()); + yaxis->setTickCount(6); + yaxis->setTickInterval(16384); + yaxis->setRange(-16384, 65536); + yaxis->setLabelFormat("%.0f"); + + xaxis->setRange(0, 5000); + xaxis->setTickCount(11); + xaxis->setLabelFormat("%.0f"); + xaxis->setTitleText("Time [ns]"); + + updateTraceThread = new UpdateTraceThread(); + connect(updateTraceThread, &UpdateTraceThread::updateTrace, this, &Scope::UpdateScope); + + //*================ add Widgets + int rowID = -1; + QWidget * layoutWidget = new QWidget(this); + setCentralWidget(layoutWidget); + QGridLayout * layout = new QGridLayout(layoutWidget); + layoutWidget->setLayout(layout); + + //------------ Digitizer + channel selection + rowID ++; + cbScopeDigi = new QComboBox(this); + cbScopeCh = new QComboBox(this); + layout->addWidget(cbScopeDigi, rowID, 0); + layout->addWidget(cbScopeCh, rowID, 1); + + connect(cbScopeDigi, &QComboBox::currentIndexChanged, this, [=](){ + //if( allowChange ) StopScope(); + int index = cbScopeDigi->currentIndex(); + if( index == -1 ) return; + for( int i = 0; i < digi[index]->GetNChannels(); i++){ + cbScopeCh->addItem("ch-" + QString::number(i), i); + } + //if( allowChange )StartScope(index); + }); + + connect(cbScopeCh, &QComboBox::currentIndexChanged, this, [=](){ + if( !allowChange ) return; + int iDigi = cbScopeDigi->currentIndex(); + int ch = cbScopeCh->currentIndex(); + digiMTX.lock(); + digi[iDigi]->WriteChValue("0..63", DIGIPARA::CH::ChannelEnable, "false"); + digi[iDigi]->WriteChValue(std::to_string(ch), DIGIPARA::CH::ChannelEnable, "true"); + ReadScopeSettings(iDigi, ch); + digiMTX.unlock(); + }); + + allowChange = false; + cbScopeDigi->clear(); ///this will also trigger QComboBox::currentIndexChanged + cbScopeCh->clear(); + for( unsigned int i = 0 ; i < nDigi; i++) { + cbScopeDigi->addItem("Digi-" + QString::number(digi[i]->GetSerialNumber()), i); + } + allowChange = true; + + + bnScopeReset = new QPushButton("ReProgram Digitizer", this); + layout->addWidget(bnScopeReset, rowID, 2); + connect(bnScopeReset, &QPushButton::clicked, this, [=](){ + if( !allowChange ) return; + int iDigi = cbScopeDigi->currentIndex(); + digi[iDigi]->Reset(); + digi[iDigi]->ProgramPHA(false); + }); + + bnScopeReadSettings = new QPushButton("Read Ch. Settings", this); + layout->addWidget(bnScopeReadSettings, rowID, 3); + connect(bnScopeReadSettings, &QPushButton::clicked, this, [=](){ + if( !allowChange ) return; + ReadScopeSettings(cbScopeDigi->currentIndex(), cbScopeCh->currentIndex()); + }); + + //TODO----- add copy settings and paste settings + QCheckBox * chkSetAllChannel = new QCheckBox("apply to all channels", this); + layout->addWidget(chkSetAllChannel, rowID, 4); + chkSetAllChannel->setEnabled(false); + + //------------ Probe selection + rowID ++; + //TODO --- add None + cbAnaProbe[0] = new QComboBox(this); + cbAnaProbe[0]->addItem("ADC Input", "ADCInput"); + cbAnaProbe[0]->addItem("Time Filter", "TimeFilter"); + cbAnaProbe[0]->addItem("Trapazoid", "EnergyFilter"); + cbAnaProbe[0]->addItem("Trap. Baseline", "EnergyFilterBaseline"); + cbAnaProbe[0]->addItem("Trap. - Baseline", "EnergyFilterMinusBaseline"); + + cbAnaProbe[1] = new QComboBox(this); + for( int i = 0; i < cbAnaProbe[0]->count() ; i++) cbAnaProbe[1]->addItem(cbAnaProbe[0]->itemText(i), cbAnaProbe[0]->itemData(i)); + + connect(cbAnaProbe[0], &QComboBox::currentIndexChanged, this, [=](){ this->ProbeChange(cbAnaProbe, 2);}); + connect(cbAnaProbe[1], &QComboBox::currentIndexChanged, this, [=](){ this->ProbeChange(cbAnaProbe, 2);}); + + cbAnaProbe[0]->setCurrentIndex(1); ///trigger the AnaProbeChange + cbAnaProbe[0]->setCurrentIndex(0); + cbAnaProbe[1]->setCurrentIndex(4); + + connect(cbAnaProbe[0], &QComboBox::currentIndexChanged, this, [=](){ + if( !allowChange ) return; + int iDigi = cbScopeDigi->currentIndex(); + int ch = cbScopeCh->currentIndex(); + digiMTX.lock(); + digi[iDigi]->WriteChValue(std::to_string(ch), DIGIPARA::CH::WaveAnalogProbe0, (cbAnaProbe[0]->currentData()).toString().toStdString()); + digiMTX.unlock(); + }); + + connect(cbAnaProbe[1], &QComboBox::currentIndexChanged, this, [=](){ + if( !allowChange ) return; + int iDigi = cbScopeDigi->currentIndex(); + int ch = cbScopeCh->currentIndex(); + digiMTX.lock(); + digi[iDigi]->WriteChValue(std::to_string(ch), DIGIPARA::CH::WaveAnalogProbe1, (cbAnaProbe[1]->currentData()).toString().toStdString()); + digiMTX.unlock(); + }); + + //TODO --- add None + cbDigProbe[0] = new QComboBox(this); + cbDigProbe[0]->addItem("Trigger", "Trigger"); + cbDigProbe[0]->addItem("Time Filter Armed", "TimeFilterArmed"); + cbDigProbe[0]->addItem("ReTrigger Guard", "ReTriggerGuard"); + cbDigProbe[0]->addItem("Trap. basline Freeze", "EnergyFilterBaselineFreeze"); + cbDigProbe[0]->addItem("Peaking", "EnergyFilterPeaking"); + cbDigProbe[0]->addItem("Peak Ready", "EnergyFilterPeakReady"); + cbDigProbe[0]->addItem("Pile-up Guard", "EnergyFilterPileUpGuard"); + cbDigProbe[0]->addItem("Event Pile Up", "EventPileUp"); + cbDigProbe[0]->addItem("ADC Saturate", "ADCSaturation"); + cbDigProbe[0]->addItem("ADC Sat. Protection", "ADCSaturationProtection"); + cbDigProbe[0]->addItem("Post Sat. Event", "PostSaturationEvent"); + cbDigProbe[0]->addItem("Trap. Saturate", "EnergylterSaturation"); + cbDigProbe[0]->addItem("ACQ Inhibit", "AcquisitionInhibit"); + + cbDigProbe[1] = new QComboBox(this); + cbDigProbe[2] = new QComboBox(this); + cbDigProbe[3] = new QComboBox(this); + for( int i = 0; i < cbDigProbe[0]->count() ; i++) { + cbDigProbe[1]->addItem(cbDigProbe[0]->itemText(i), cbDigProbe[0]->itemData(i)); + cbDigProbe[2]->addItem(cbDigProbe[0]->itemText(i), cbDigProbe[0]->itemData(i)); + cbDigProbe[3]->addItem(cbDigProbe[0]->itemText(i), cbDigProbe[0]->itemData(i)); + } + + connect(cbDigProbe[0], &QComboBox::currentIndexChanged, this, [=](){ this->ProbeChange(cbDigProbe, 4);}); + connect(cbDigProbe[1], &QComboBox::currentIndexChanged, this, [=](){ this->ProbeChange(cbDigProbe, 4);}); + connect(cbDigProbe[2], &QComboBox::currentIndexChanged, this, [=](){ this->ProbeChange(cbDigProbe, 4);}); + connect(cbDigProbe[3], &QComboBox::currentIndexChanged, this, [=](){ this->ProbeChange(cbDigProbe, 4);}); + + cbDigProbe[0]->setCurrentIndex(1); ///trigger the DigProbeChange + cbDigProbe[0]->setCurrentIndex(0); + cbDigProbe[1]->setCurrentIndex(4); + cbDigProbe[2]->setCurrentIndex(5); + cbDigProbe[3]->setCurrentIndex(6); + + connect(cbDigProbe[0], &QComboBox::currentIndexChanged, this, [=](){ + if( !allowChange ) return; + int iDigi = cbScopeDigi->currentIndex(); + int ch = cbScopeCh->currentIndex(); + digiMTX.lock(); + digi[iDigi]->WriteChValue(std::to_string(ch), DIGIPARA::CH::WaveDigitalProbe0, (cbDigProbe[0]->currentData()).toString().toStdString()); + digiMTX.unlock(); + }); + connect(cbDigProbe[1], &QComboBox::currentIndexChanged, this, [=](){ + if( !allowChange ) return; + int iDigi = cbScopeDigi->currentIndex(); + int ch = cbScopeCh->currentIndex(); + digiMTX.lock(); + digi[iDigi]->WriteChValue(std::to_string(ch), DIGIPARA::CH::WaveDigitalProbe1, (cbDigProbe[1]->currentData()).toString().toStdString()); + digiMTX.unlock(); + }); + connect(cbDigProbe[2], &QComboBox::currentIndexChanged, this, [=](){ + if( !allowChange ) return; + int iDigi = cbScopeDigi->currentIndex(); + int ch = cbScopeCh->currentIndex(); + digiMTX.lock(); + digi[iDigi]->WriteChValue(std::to_string(ch), DIGIPARA::CH::WaveDigitalProbe2, (cbDigProbe[2]->currentData()).toString().toStdString()); + digiMTX.unlock(); + }); + connect(cbDigProbe[3], &QComboBox::currentIndexChanged, this, [=](){ + if( !allowChange ) return; + int iDigi = cbScopeDigi->currentIndex(); + int ch = cbScopeCh->currentIndex(); + digiMTX.lock(); + digi[iDigi]->WriteChValue(std::to_string(ch), DIGIPARA::CH::WaveDigitalProbe3, (cbDigProbe[3]->currentData()).toString().toStdString()); + digiMTX.unlock(); + }); + + layout->addWidget(cbAnaProbe[0], rowID, 0); + layout->addWidget(cbAnaProbe[1], rowID, 1); + + layout->addWidget(cbDigProbe[0], rowID, 2); + layout->addWidget(cbDigProbe[1], rowID, 3); + layout->addWidget(cbDigProbe[2], rowID, 4); + layout->addWidget(cbDigProbe[3], rowID, 5); + + rowID ++; + {//------------ wave settings + QGroupBox * box = new QGroupBox("Channel Settings (need ACQ stop)", this); + layout->addWidget(box, rowID, 0, 1, 6); + + QGridLayout * bLayout = new QGridLayout(box); + bLayout->setSpacing(0); + + sbRL = new QSpinBox(this); + ScopeMakeSpinBox(sbRL, "Record Lenght [ns] ", bLayout, 0, 0, 32, 648000, DIGIPARA::TraceStep, DIGIPARA::CH::RecordLength); + + sbThreshold = new QSpinBox(this); + ScopeMakeSpinBox(sbThreshold, "Threshold [LSB] ", bLayout, 0, 2, 0, 8191, -20, DIGIPARA::CH::TriggerThreshold); + + cbPolarity = new QComboBox(this); + cbPolarity->addItem("Pos. +", "Positive"); + cbPolarity->addItem("Neg. -", "Negative"); + ScopeMakeComoBox(cbPolarity, "Polarity ", bLayout, 0, 4, DIGIPARA::CH::Polarity); + + cbWaveRes = new QComboBox(this); + cbWaveRes->addItem(" 8 ns", "RES8"); + cbWaveRes->addItem("16 ns", "RES16"); + cbWaveRes->addItem("32 ns", "RES32"); + cbWaveRes->addItem("64 ns", "RES64"); + ScopeMakeComoBox(cbWaveRes, "Wave Re. ", bLayout, 0, 6, DIGIPARA::CH::WaveResolution); + + //------------------ next row + sbPT = new QSpinBox(this); + ScopeMakeSpinBox(sbPT, "Pre Trigger [ns] ", bLayout, 1, 0, 32, 32000, DIGIPARA::TraceStep, DIGIPARA::CH::PreTrigger); + + sbDCOffset = new QSpinBox(this); + ScopeMakeSpinBox(sbDCOffset, "DC offset [%] ", bLayout, 1, 2, 0, 100, -10, DIGIPARA::CH::DC_Offset); + + sbTimeRiseTime = new QSpinBox(this); + ScopeMakeSpinBox(sbTimeRiseTime, "Trigger Rise Time [ns] ", bLayout, 1, 4, 32, 2000, DIGIPARA::TraceStep, DIGIPARA::CH::TimeFilterRiseTime); + + sbTimeGuard = new QSpinBox(this); + ScopeMakeSpinBox(sbTimeGuard, "Trigger Guard [ns] ", bLayout, 1, 6, 0, 8000, DIGIPARA::TraceStep, DIGIPARA::CH::TimeFilterRetriggerGuard); + + //----------------- next row + sbTrapRiseTime = new QSpinBox(this); + ScopeMakeSpinBox(sbTrapRiseTime, "Trap. Rise Time [ns] ", bLayout, 2, 0, 32, 13000, DIGIPARA::TraceStep, DIGIPARA::CH::EnergyFilterRiseTime); + + sbTrapFlatTop = new QSpinBox(this); + ScopeMakeSpinBox(sbTrapFlatTop, "Trap. Flat Top [ns] ", bLayout, 2, 2, 32, 3000, DIGIPARA::TraceStep, DIGIPARA::CH::EnergyFilterFlatTop); + + sbTrapPoleZero = new QSpinBox(this); + ScopeMakeSpinBox(sbTrapPoleZero, "Trap. Pole Zero [ns] ", bLayout, 2, 4, 32, 524000, DIGIPARA::TraceStep, DIGIPARA::CH::EnergyFilterPoleZero); + + sbEnergyFineGain = new QSpinBox(this); + ScopeMakeSpinBox(sbEnergyFineGain, "Energy Fine Gain ", bLayout, 2, 6, 1, 10, -1, DIGIPARA::CH::EnergyFilterFineGain); + + //----------------- next row + sbTrapPeaking = new QSpinBox(this); + ScopeMakeSpinBox(sbTrapPeaking, "Trap. Peaking [%] ", bLayout, 3, 0, 1, 100, -10, DIGIPARA::CH::EnergyFilterPeakingPosition); + + cbTrapPeakAvg = new QComboBox(this); + cbTrapPeakAvg->addItem(" 1 sample", "OneShot"); + cbTrapPeakAvg->addItem(" 4 sample", "LowAVG"); + cbTrapPeakAvg->addItem("16 sample", "MediumAVG"); + cbTrapPeakAvg->addItem("64 sample", "HighAVG"); + ScopeMakeComoBox(cbTrapPeakAvg, "Trap. Peaking ", bLayout, 3, 2, DIGIPARA::CH::EnergyFilterPeakingAvg); + + sbBaselineGuard = new QSpinBox(this); + ScopeMakeSpinBox(sbBaselineGuard, "Baseline Guard [ns] ", bLayout, 3, 4, 0, 8000, DIGIPARA::TraceStep, DIGIPARA::CH::EnergyFilterBaselineGuard); + + cbBaselineAvg = new QComboBox(this); + cbBaselineAvg->addItem(" 0 samp.", "Fixed"); + cbBaselineAvg->addItem(" 16 samp.", "VeryLow"); + cbBaselineAvg->addItem(" 64 samp.", "Low"); + cbBaselineAvg->addItem(" 256 samp.", "MediumLow"); + cbBaselineAvg->addItem(" 1024 samp.", "Medium"); + cbBaselineAvg->addItem(" 4096 samp.", "MediumHigh"); + cbBaselineAvg->addItem("16384 samp.", "High"); + ScopeMakeComoBox(cbBaselineAvg, "Baseline Avg ", bLayout, 3, 6, DIGIPARA::CH::EnergyFilterBaselineAvg); + //---------------- + + sbPileUpGuard = new QSpinBox(this); + ScopeMakeSpinBox(sbPileUpGuard, "Pile-up Guard [ns] ", bLayout, 4, 0, 0, 64000, DIGIPARA::TraceStep, DIGIPARA::CH::EnergyFilterPileUpGuard); + + cbLowFreqFilter = new QComboBox(this); + cbLowFreqFilter->addItem("Disabled", "Off"); + cbLowFreqFilter->addItem("Enabled", "On"); + ScopeMakeComoBox(cbLowFreqFilter, "Low Freq. Filter ", bLayout, 4, 2, DIGIPARA::CH::EnergyFilterLowFreqFilter); + + } + + //------------ plot view + rowID ++; + QChartView * plotView = new QChartView(plot); + plotView->setRenderHints(QPainter::Antialiasing); + layout->addWidget(plotView, rowID, 0, 1, 6); + + //TODO zoom and pan, see Zoom Line example + + //------------ close button + rowID ++; + bnScopeStart = new QPushButton("Start", this); + layout->addWidget(bnScopeStart, rowID, 0); + bnScopeStart->setEnabled(false); + connect(bnScopeStart, &QPushButton::clicked, this, [=](){this->StartScope();}); + + bnScopeStop = new QPushButton("Stop", this); + layout->addWidget(bnScopeStop, rowID, 1); + connect(bnScopeStop, &QPushButton::clicked, this, &Scope::StopScope); + + QPushButton * bnClose = new QPushButton("Close", this); + layout->addWidget(bnClose, rowID, 5); + connect(bnClose, &QPushButton::clicked, this, &Scope::StopScope); + connect(bnClose, &QPushButton::clicked, this, &Scope::close); + + + show(); + + StartScope(); + +} + +Scope::~Scope(){ + + updateTraceThread->Stop(); + updateTraceThread->quit(); + updateTraceThread->wait(); + delete updateTraceThread; + + + for( int i = 0; i < 6; i++) delete dataTrace[i]; + + delete plot; + +} + +void Scope::ReadScopeSettings(int iDigi, int ch){ + if( !digi[iDigi] && digi[iDigi]->IsDummy() ) return; + + printf("%s\n", __func__); + + allowChange = false; + + for( int i = 0 ; i < 2; i++){ + ScopeReadComboBoxValue(iDigi, ch, cbAnaProbe[i], DIGIPARA::CH::AnalogProbe[i]); + } + + for( int i = 0 ; i < 4; i++){ + ScopeReadComboBoxValue(iDigi, ch, cbDigProbe[i], DIGIPARA::CH::DigitalProbe[i]); + } + + ScopeReadComboBoxValue(iDigi, ch, cbPolarity, DIGIPARA::CH::Polarity); + ScopeReadComboBoxValue(iDigi, ch, cbWaveRes, DIGIPARA::CH::WaveResolution); + ScopeReadComboBoxValue(iDigi, ch, cbTrapPeakAvg, DIGIPARA::CH::EnergyFilterPeakingAvg); + ScopeReadComboBoxValue(iDigi, ch, cbBaselineAvg, DIGIPARA::CH::EnergyFilterBaselineAvg); + ScopeReadComboBoxValue(iDigi, ch, cbLowFreqFilter, DIGIPARA::CH::EnergyFilterLowFreqFilter); + + ScopeReadSpinBoxValue(iDigi, ch, sbRL, DIGIPARA::CH::RecordLength); + ScopeReadSpinBoxValue(iDigi, ch, sbPT, DIGIPARA::CH::PreTrigger); + ScopeReadSpinBoxValue(iDigi, ch, sbDCOffset, DIGIPARA::CH::DC_Offset); + ScopeReadSpinBoxValue(iDigi, ch, sbThreshold, DIGIPARA::CH::TriggerThreshold); + ScopeReadSpinBoxValue(iDigi, ch, sbTimeRiseTime, DIGIPARA::CH::TimeFilterRiseTime); + ScopeReadSpinBoxValue(iDigi, ch, sbTimeGuard, DIGIPARA::CH::TimeFilterRetriggerGuard); + ScopeReadSpinBoxValue(iDigi, ch, sbTrapRiseTime, DIGIPARA::CH::EnergyFilterRiseTime); + ScopeReadSpinBoxValue(iDigi, ch, sbTrapFlatTop, DIGIPARA::CH::EnergyFilterFlatTop); + ScopeReadSpinBoxValue(iDigi, ch, sbTrapPoleZero, DIGIPARA::CH::EnergyFilterPoleZero); + ScopeReadSpinBoxValue(iDigi, ch, sbEnergyFineGain, DIGIPARA::CH::EnergyFilterFineGain); + ScopeReadSpinBoxValue(iDigi, ch, sbTrapPeaking, DIGIPARA::CH::EnergyFilterPeakingPosition); + ScopeReadSpinBoxValue(iDigi, ch, sbBaselineGuard, DIGIPARA::CH::EnergyFilterBaselineGuard); + ScopeReadSpinBoxValue(iDigi, ch, sbPileUpGuard, DIGIPARA::CH::EnergyFilterPileUpGuard); + + allowChange = true; +} + +void Scope::StartScope(){ + + if( !digi ) return; + + int iDigi = cbScopeDigi->currentIndex(); + + if( digi[iDigi]->IsDummy() ) return; + + printf("%s\n", __func__); + + int ch = cbScopeCh->currentIndex(); + + //*---- set digitizer to take full trace; since in scope mode, no data saving, speed would be fast (How fast?) + //* when the input rate is faster than trigger rate, Digitizer will stop data taking. + + ReadScopeSettings(iDigi, ch); + + digi[iDigi]->WriteChValue("0..63", DIGIPARA::CH::ChannelEnable, "false"); + digi[iDigi]->WriteChValue(std::to_string(ch), DIGIPARA::CH::ChannelEnable, "true"); + digi[iDigi]->SetPHADataFormat(0); + + digi[iDigi]->StartACQ(); + + readDataThread[iDigi]->SetScopeRun(true); + readDataThread[iDigi]->start(); + + updateTraceThread->start(); + + ScopeControlOnOff(false); + + allowChange = true; +} + +void Scope::StopScope(){ + + printf("%s\n", __func__); + + updateTraceThread->Stop(); + updateTraceThread->quit(); + updateTraceThread->wait(); + + if(digi){ + for(int i = 0; i < nDigi; i++){ + if( digi[i]->IsDummy() ) continue; + digiMTX.lock(); + digi[i]->StopACQ(); + digi[i]->WriteChValue("0..63", DIGIPARA::CH::ChannelEnable, "true"); + digiMTX.unlock(); + + readDataThread[i]->quit(); + readDataThread[i]->wait(); + + } + } + + ScopeControlOnOff(true); + allowChange = true; +} + +void Scope::UpdateScope(){ + + int iDigi = cbScopeDigi->currentIndex(); + int sample2ns = DIGIPARA::TraceStep * (1 << cbWaveRes->currentIndex()); + + if( digi ){ + digiMTX.lock(); + unsigned int traceLength = digi[iDigi]->evt->traceLenght; + unsigned int dataLength = dataTrace[0]->count(); + + //---- remove all points + for( int j = 0; j < 6; j++ ) dataTrace[j]->removePoints(0, dataLength); + + for( unsigned int i = 0 ; i < traceLength; i++){ + for( int j = 0; j < 2; j++) dataTrace[j]->append(sample2ns * i, digi[iDigi]->evt->analog_probes[j][i]); + for( int j = 2; j < 6; j++) dataTrace[j]->append(sample2ns * i, (j-1)*1000 + 4000 * digi[iDigi]->evt->digital_probes[j-2][i]); + } + + digiMTX.unlock(); + + plot->axes(Qt::Horizontal).first()->setRange(0, sample2ns * traceLength); + } + +} + +void Scope::ProbeChange(QComboBox * cb[], const int size ){ + + QStandardItemModel * model[size] = {NULL}; + for( int i = 0; i < size; i++){ + model[i] = qobject_cast(cb[i]->model()); + } + + /// Enable all items + for( int i = 0; i < cb[0]->count(); i++) { + for( int j = 0; j < size; j ++ ) model[j]->item(i)->setEnabled(true); + } + + for( int i = 0; i < size; i++){ + int index = cb[i]->currentIndex(); + for( int j = 0; j < size; j++){ + if( i == j ) continue; + model[j]->item(index)->setEnabled(false); + } + } + + digiMTX.lock(); + if( size == 2) {// analog probes + for( int j = 0; j < 2; j++ )dataTrace[j]->setName(cb[j]->currentText()); + } + if( size == 4){ // digitial probes + for( int j = 2; j < 6; j++ )dataTrace[j]->setName(cb[j-2]->currentText()); + } + digiMTX.unlock(); + +} + +void Scope::ScopeControlOnOff(bool on){ + bnScopeStop->setEnabled(!on); + + bnScopeStart->setEnabled(on); + bnScopeReset->setEnabled(on); + bnScopeReadSettings->setEnabled(on); + + sbRL->setEnabled(on); + sbPT->setEnabled(on); + sbDCOffset->setEnabled(on); + sbThreshold->setEnabled(on); + sbTimeRiseTime->setEnabled(on); + sbTimeGuard->setEnabled(on); + sbTrapRiseTime->setEnabled(on); + sbTrapFlatTop->setEnabled(on); + sbTrapPoleZero->setEnabled(on); + sbEnergyFineGain->setEnabled(on); + sbTrapPeaking->setEnabled(on); + cbPolarity->setEnabled(on); + cbWaveRes->setEnabled(on); + cbTrapPeakAvg->setEnabled(on); + + sbBaselineGuard->setEnabled(on); + sbPileUpGuard->setEnabled(on); + cbBaselineAvg->setEnabled(on); + cbLowFreqFilter->setEnabled(on); +} + +void Scope::ScopeReadSpinBoxValue(int iDigi, int ch, QSpinBox *sb, std::string digPara){ + std::string ans = digi[iDigi]->ReadChValue(std::to_string(ch), digPara); + sb->setValue(atoi(ans.c_str())); +} + +void Scope::ScopeReadComboBoxValue(int iDigi, int ch, QComboBox *cb, std::string digPara){ + std::string ans = digi[iDigi]->ReadChValue(std::to_string(ch), digPara); + int index = cb->findData(QString::fromStdString(ans)); + if( index >= 0 && index < cb->count()) { + cb->setCurrentIndex(index); + }else{ + qDebug() << QString::fromStdString(ans); + } +} + +void Scope::ScopeMakeSpinBox(QSpinBox *sb, QString str, QGridLayout *layout, int row, int col, int min, int max, int step, std::string digPara){ + QLabel * lb = new QLabel(str, this); + lb->setAlignment(Qt::AlignRight | Qt::AlignCenter); + layout->addWidget(lb, row, col); + sb->setMinimum(min); + sb->setMaximum(max); + sb->setSingleStep(abs(step)); + layout->addWidget(sb, row, col+1); + connect(sb, &QSpinBox::valueChanged, this, [=](){ + if( !allowChange ) return; + int iDigi = cbScopeDigi->currentIndex(); + if( step > 1 ) sb->setValue(step*((sb->value() + step - 1)/step)); + digiMTX.lock(); + digi[iDigi]->WriteChValue(std::to_string(cbScopeCh->currentIndex()), digPara, std::to_string(sb->value())); + digiMTX.unlock(); + }); +} + +void Scope::ScopeMakeComoBox(QComboBox *cb, QString str, QGridLayout *layout, int row, int col, std::string digPara){ + QLabel * lb = new QLabel(str, this); + lb->setAlignment(Qt::AlignRight | Qt::AlignCenter); + layout->addWidget(lb, row, col); + layout->addWidget(cb, row, col+1); + connect(cb, &QComboBox::currentIndexChanged, this, [=](){ + if( !allowChange ) return; + int iDigi = cbScopeDigi->currentIndex(); + digiMTX.lock(); + digi[iDigi]->WriteChValue(std::to_string(cbScopeCh->currentIndex()), digPara, cb->currentData().toString().toStdString()); + digiMTX.unlock(); + }); +} + + + diff --git a/scope.h b/scope.h new file mode 100644 index 0000000..0f365c7 --- /dev/null +++ b/scope.h @@ -0,0 +1,90 @@ +#ifndef Scope_H +#define Scope_H + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ClassDigitizer2Gen.h" +#include "manyThread.h" + +class Scope : public QMainWindow{ + Q_OBJECT + +public: + Scope(Digitizer2Gen ** digi, unsigned int nDigi, ReadDataThread ** readDataThread, QMainWindow * parent = nullptr); + ~Scope(); + + +private slots: + + void ReadScopeSettings(int iDigi, int ch); + void StartScope(); + void StopScope(); + void UpdateScope(); + void ScopeControlOnOff(bool on); + void ScopeReadSpinBoxValue(int iDigi, int ch, QSpinBox *sb, std::string digPara); + void ScopeReadComboBoxValue(int iDigi, int ch, QComboBox *cb, std::string digPara); + void ScopeMakeSpinBox(QSpinBox * sb, QString str, QGridLayout* layout, int row, int col, int min, int max, int step, std::string digPara); + void ScopeMakeComoBox(QComboBox * cb, QString str, QGridLayout* layout, int row, int col, std::string digPara); + void ProbeChange(QComboBox * cb[], const int size); + + void closeEvent(QCloseEvent * event){ + StopScope(); + event->accept(); + } + +signals: + +private: + + Digitizer2Gen ** digi; + unsigned short nDigi; + + ReadDataThread ** readDataThread; + UpdateTraceThread * updateTraceThread; + + QChart * plot; + QLineSeries * dataTrace[6]; + QComboBox * cbScopeDigi; + QComboBox * cbScopeCh; + QPushButton * bnScopeReset; + QPushButton * bnScopeReadSettings; + + + QPushButton * bnScopeStart; + QPushButton * bnScopeStop; + + QComboBox * cbAnaProbe[2]; + QComboBox * cbDigProbe[4]; + QSpinBox * sbRL; // record length + QSpinBox * sbPT; // pre trigger + QSpinBox * sbDCOffset; + QSpinBox * sbThreshold; + QSpinBox * sbTimeRiseTime; + QSpinBox * sbTimeGuard; + QSpinBox * sbTrapRiseTime; + QSpinBox * sbTrapFlatTop; + QSpinBox * sbTrapPoleZero; + QSpinBox * sbEnergyFineGain; + QSpinBox * sbTrapPeaking; + QComboBox * cbPolarity; + QComboBox * cbWaveRes; + QComboBox * cbTrapPeakAvg; + + QSpinBox * sbBaselineGuard; + QSpinBox * sbPileUpGuard; + QComboBox * cbBaselineAvg; + QComboBox * cbLowFreqFilter; + + bool allowChange; + +}; + +#endif \ No newline at end of file