#include "mainwindow.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //------ static memeber Digitizer2Gen ** MainWindow::digi = nullptr; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ setWindowTitle("FSU SOLARIS DAQ"); setGeometry(500, 100, 1000, 500); QIcon icon("SOLARIS_favicon.png"); setWindowIcon(icon); programPath = QDir::currentPath(); nDigi = 0; nDigiConnected = 0; digiSetting = nullptr; influx = nullptr; readDataThread = nullptr; runTimer = new QTimer(); needManualComment = true; ACQStopButtonPressed = false; isACQRunning = false; { scalarOutputInflux = false; scalar = new QMainWindow(this); scalar->setWindowTitle("Scalar"); scalar->setGeometry(0, 0, 1000, 800); QScrollArea * scopeScroll = new QScrollArea(scalar); scalar->setCentralWidget(scopeScroll); scopeScroll->setWidgetResizable(true); scopeScroll->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); QWidget * layoutWidget = new QWidget(scalar); scopeScroll->setWidget(layoutWidget); scalarLayout = new QGridLayout(layoutWidget); scalarLayout->setSpacing(0); scalarLayout->setAlignment(Qt::AlignTop); leTrigger = nullptr; leAccept = nullptr; lbFileSize = nullptr; scalarThread = new TimingThread(); connect(scalarThread, &TimingThread::TimeUp, this, &MainWindow::UpdateScalar); } solarisSetting = nullptr; scope = nullptr; digiSetting = nullptr; QWidget * mainLayoutWidget = new QWidget(this); setCentralWidget(mainLayoutWidget); QVBoxLayout * layoutMain = new QVBoxLayout(mainLayoutWidget); mainLayoutWidget->setLayout(layoutMain); {//====================== General QGroupBox * box1 = new QGroupBox("General", mainLayoutWidget); layoutMain->addWidget(box1); QGridLayout * layout1 = new QGridLayout(box1); bnProgramSettings = new QPushButton("Program Settings", this); connect(bnProgramSettings, &QPushButton::clicked, this, &MainWindow::ProgramSettingsPanel); bnNewExp = new QPushButton("New/Change/Reload Exp", this); connect(bnNewExp, &QPushButton::clicked, this, &MainWindow::SetupNewExpPanel); QLabel * lExpName = new QLabel("Exp Name ", this); lExpName->setAlignment(Qt::AlignRight | Qt::AlignCenter); leExpName = new QLineEdit("", this); leExpName->setAlignment(Qt::AlignHCenter); leExpName->setReadOnly(true); bnOpenScope = new QPushButton("Open scope", this); bnOpenScope->setEnabled(false); connect(bnOpenScope, &QPushButton::clicked, this, &MainWindow::OpenScope); bnOpenDigitizers = new QPushButton("Open Digitizers", this); connect(bnOpenDigitizers, &QPushButton::clicked, this, &MainWindow::OpenDigitizers); bnCloseDigitizers = new QPushButton("Close Digitizers", this); bnCloseDigitizers->setEnabled(false); connect(bnCloseDigitizers, &QPushButton::clicked, this, &MainWindow::CloseDigitizers); bnDigiSettings = new QPushButton("Digitizers Settings", this); bnDigiSettings->setEnabled(false); connect(bnDigiSettings, &QPushButton::clicked, this, &MainWindow::OpenDigitizersSettings); bnSOLSettings = new QPushButton("SOLARIS Settings", this); bnSOLSettings->setEnabled(false); connect(bnSOLSettings, &QPushButton::clicked, this, &MainWindow::OpenSOLARISpanel); bnSyncHelper = new QPushButton("Sync Helper (Not Set)", this); bnSyncHelper->setEnabled(false); connect(bnSyncHelper, &QPushButton::clicked, this, &MainWindow::OpenSyncHelper); // QPushButton * bnEventBuilder = new QPushButton("Event Builder", this); // bnEventBuilder->setEnabled(false); // QPushButton * bnHVController = new QPushButton("HV Controller", this); // bnHVController->setEnabled(false); // QPushButton * bnTargetFanController = new QPushButton("Target Fan", this); // bnTargetFanController->setEnabled(false); layout1->addWidget(bnProgramSettings, 0, 0); layout1->addWidget(bnNewExp, 0, 1); layout1->addWidget(lExpName, 0, 2); layout1->addWidget(leExpName, 0, 3); layout1->addWidget(bnSyncHelper, 1, 0); layout1->addWidget(bnOpenDigitizers, 1, 1); layout1->addWidget(bnCloseDigitizers, 1, 2, 1, 2); layout1->addWidget(bnOpenScope, 2, 0); layout1->addWidget(bnDigiSettings, 2, 1); layout1->addWidget(bnSOLSettings, 2, 2, 1, 2); // layout1->addWidget(bnEventBuilder, 3, 0); // layout1->addWidget(bnHVController, 3, 1); // layout1->addWidget(bnTargetFanController, 3, 2, 1, 2); layout1->setColumnStretch(0, 2); layout1->setColumnStretch(1, 2); layout1->setColumnStretch(2, 1); layout1->setColumnStretch(3, 1); } {//====================== ACD control QGroupBox * box2 = new QGroupBox("ACQ control", mainLayoutWidget); layoutMain->addWidget(box2); QGridLayout * layout2 = new QGridLayout(box2); QLabel * lbRawDataPath = new QLabel("Raw Data Path : ", this); lbRawDataPath->setAlignment(Qt::AlignRight | Qt::AlignCenter); leRawDataPath = new QLineEdit(this); leRawDataPath->setReadOnly(true); leRawDataPath->setStyleSheet("background-color: #F3F3F3;"); bnOpenScalar = new QPushButton("Open Scalar", this); bnOpenScalar->setEnabled(false); connect(bnOpenScalar, &QPushButton::clicked, this, &MainWindow::OpenScaler); QLabel * lbRunID = new QLabel("Run ID : ", this); lbRunID->setAlignment(Qt::AlignRight | Qt::AlignCenter); leRunID = new QLineEdit(this); leRunID->setAlignment(Qt::AlignHCenter); leRunID->setReadOnly(true); leRunID->setStyleSheet("background-color: #F3F3F3;"); chkSaveRun = new QCheckBox("Save Run", this); chkSaveRun->setChecked(false); chkSaveRun->setEnabled(false); connect(chkSaveRun, &QCheckBox::clicked, this, [=]() { cbAutoRun->setEnabled(chkSaveRun->isChecked()); }); cbAutoRun = new QComboBox(this); cbAutoRun->addItem("Single infinte", 0); cbAutoRun->addItem("Single 1 min", 1); cbAutoRun->addItem("Single 30 mins", 30); cbAutoRun->addItem("Single 60 mins", 60); cbAutoRun->addItem("Single 2 hrs", 120); cbAutoRun->addItem("Single 3 hrs", 180); cbAutoRun->addItem("Single 5 hrs", 300); cbAutoRun->addItem("Every 1 mins", -1); cbAutoRun->addItem("Every 30 mins", -30); cbAutoRun->addItem("Every 60 mins", -60); cbAutoRun->addItem("Every 2 hrs", -120); cbAutoRun->addItem("Every 3 hrs", -180); cbAutoRun->addItem("Every 5 hrs", -300); cbAutoRun->setEnabled(false); cbDataFormat = new QComboBox(this); cbDataFormat->addItem("Everything", DataFormat::ALL); cbDataFormat->addItem("1 trace", DataFormat::OneTrace); cbDataFormat->addItem("No trace", DataFormat::NoTrace); cbDataFormat->addItem("Minimum", DataFormat::Minimum); cbDataFormat->addItem("Min + fineTimestamp", DataFormat::MiniWithFineTime); cbDataFormat->setCurrentIndex(3); cbDataFormat->setEnabled(false); bnStartACQ = new QPushButton("Start ACQ", this); bnStartACQ->setEnabled(false); //connect(bnStartACQ, &QPushButton::clicked, this, &MainWindow::StartACQ); connect(bnStartACQ, &QPushButton::clicked, this, &MainWindow::AutoRun); bnStopACQ = new QPushButton("Stop ACQ", this); bnStopACQ->setEnabled(false); connect(bnStopACQ, &QPushButton::clicked, this, [=](){ LogMsg("@@@@@@@@@ Stop ACQ Button Pressed."); ACQStopButtonPressed = true; needManualComment = true; runTimer->stop(); StopACQ(); if( !isACQRunning ){ bnStartACQ->setEnabled(true); bnStopACQ->setEnabled(false); bnComment->setEnabled(false); bnOpenScope->setEnabled(true); chkSaveRun->setEnabled(true); cbDataFormat->setEnabled(true); if(chkSaveRun->isChecked() ) cbAutoRun->setEnabled(true); if( digiSetting ) digiSetting->EnableControl(); } }); QLabel * lbRunComment = new QLabel("Run Comment : ", this); lbRunComment->setAlignment(Qt::AlignRight | Qt::AlignCenter); leRunComment = new QLineEdit(this); leRunComment->setReadOnly(true); leRunComment->setStyleSheet("background-color: #F3F3F3;"); bnComment = new QPushButton("Append Comment", this); connect(bnComment, &QPushButton::clicked, this, &MainWindow::AppendComment); bnComment->setEnabled(false); layout2->addWidget(lbRawDataPath, 0, 0); layout2->addWidget(leRawDataPath, 0, 1, 1, 5); layout2->addWidget(bnOpenScalar, 0, 6); layout2->addWidget(lbRunID, 1, 0); layout2->addWidget(leRunID, 1, 1); layout2->addWidget(chkSaveRun, 1, 2); layout2->addWidget(cbAutoRun, 1, 3); layout2->addWidget(cbDataFormat, 1, 4); layout2->addWidget(bnStartACQ, 1, 5); layout2->addWidget(bnStopACQ, 1, 6); layout2->addWidget(lbRunComment, 2, 0); layout2->addWidget(leRunComment, 2, 1, 1, 5); layout2->addWidget(bnComment, 2, 6); layout2->setColumnStretch(0, 1); layout2->setColumnStretch(1, 1); layout2->setColumnStretch(2, 1); layout2->setColumnStretch(3, 1); layout2->setColumnStretch(4, 1); layout2->setColumnStretch(5, 3); layout2->setColumnStretch(6, 3); } layoutMain->addStretch(); {//===================== Log Msg QGroupBox * box3 = new QGroupBox("Log Message", mainLayoutWidget); layoutMain->addWidget(box3); layoutMain->setStretchFactor(box3, 1); QVBoxLayout * layout3 = new QVBoxLayout(box3); logInfo = new QPlainTextEdit(this); logInfo->isReadOnly(); QFont font; font.setFamily("Courier New"); logInfo->setFont(font); layout3->addWidget(logInfo); } LogMsg("Welcome to SOLARIS DAQ."); if( LoadProgramSettings() ) LoadExpNameSh(); } MainWindow::~MainWindow(){ printf("- %s\n", __func__); LogMsg("Closing SOLARIS DAQ."); if( !expDataPath.isEmpty() ){ QDir dir(expDataPath + "/Logs/"); if( !dir.exists() ) dir.mkpath("."); QFile file(expDataPath + "/Logs/Log_" + QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss") + ".dat"); printf("-------- Save log msg to %s\n", file.fileName().toStdString().c_str()); if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { QTextStream stream(&file); stream << logInfo->toPlainText(); file.close(); } } printf("-------- remove %s\n", DAQLockFile); remove(DAQLockFile); printf("-------- delete Solaris panel\n"); if( solarisSetting ) { delete solarisSetting; solarisSetting = nullptr; } printf("-------- delete scope\n"); if( scope ) { delete scope; scope = nullptr; } printf("-------- delete digiSetting\n"); if( digiSetting ) { delete digiSetting; digiSetting = nullptr; } printf("-------- delete readData Thread\n"); if( digi ){ for( int i = 0; i < nDigi ; i++){ if( digi[i]->IsDummy()) continue; //printf("=== %d %p\n", i, readDataThread[i]); if( readDataThread[i]->isRunning()) StopACQ(); } } CloseDigitizers(); // SOlaris panel, digiSetting, scope are also deleted. printf("-------- delete scalar Thread\n"); if( scalarThread->isRunning()){ scalarThread->Stop(); scalarThread->quit(); scalarThread->wait(); } CleanUpScalar(); delete scalarThread; printf("-------- delete influx\n"); if( influx != NULL ) { influx->ClearDataPointsBuffer(); influx->AddDataPoint("ProgramStart value=0"); influx->WriteData(DatabaseName.toStdString()); delete influx; } printf("--- end of %s\n", __func__); } //*################################################################ //*################################################################ ACQ control int MainWindow::StartACQ(){ ACQStopButtonPressed = false; if( chkSaveRun->isChecked() ){ runID ++; leRunID->setText(QString::number(runID)); runIDStr = QString::number(runID).rightJustified(3, '0'); LogMsg("=========================== Start Run-" + runIDStr + ""); if( needManualComment ){ QDialog * dOpen = new QDialog(this); dOpen->setWindowTitle("Start Run Comment"); dOpen->setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint); dOpen->setMinimumWidth(600); connect(dOpen, &QDialog::finished, dOpen, &QDialog::deleteLater); QGridLayout * vlayout = new QGridLayout(dOpen); QLabel *label = new QLabel("Enter Run comment for Run-" + runIDStr + " : ", dOpen); QLineEdit *lineEdit = new QLineEdit(dOpen); QPushButton *button1 = new QPushButton("OK", dOpen); QPushButton *button2 = new QPushButton("Cancel", dOpen); vlayout->addWidget(label, 0, 0, 1, 2); vlayout->addWidget(lineEdit, 1, 0, 1, 2); vlayout->addWidget(button1, 2, 0); vlayout->addWidget(button2, 2, 1); connect(button1, &QPushButton::clicked, dOpen, &QDialog::accept); connect(button2, &QPushButton::clicked, dOpen, &QDialog::reject); int result = dOpen->exec(); if(result == QDialog::Accepted ){ startComment = lineEdit->text(); if( startComment == "") startComment = "No commet was typed."; startComment = "Start Comment: " + startComment; }else{ LogMsg("Start Run aborted. "); runID --; leRunID->setText(QString::number(runID)); return 0 ; } if( cbAutoRun -> currentData().toInt() != 0 ){ startComment = startComment + ". AutoRun for " + cbAutoRun->currentText(); } leRunComment->setText(startComment); }else{ //==========TODO auto run comment startComment = "AutoRun for " + cbAutoRun->currentText(); leRunComment->setText(startComment); } }else{ LogMsg("=========================== Start no-save Run"); } //============================= start digitizer for( int i = nDigi-1 ; i >= 0; i --){ if( digi[i]->IsDummy () ) continue; for( int ch = 0; ch < (int) digi[i]->GetNChannels(); ch ++) oldTimeStamp[i][ch] = 0; //digi[i]->SetPHADataFormat(1);// only save 1 trace int dataFormatID = cbDataFormat->currentData().toInt(); digi[i]->SetDataFormat(dataFormatID); if( dataFormatID == DataFormat::ALL || dataFormatID == DataFormat::OneTrace ){ digi[i]->WriteValue(PHA::CH::WaveSaving, "Always", -1); }else{ digi[i]->WriteValue(PHA::CH::WaveSaving, "OnRequest", -1); } //Additional settings, it is better user to control //if( cbDataFormat->currentIndex() < 2 ) { // digi[i]->WriteValue("/ch/0..63/par/WaveAnalogProbe0", "ADCInput"); // digi[i]->WriteValue(PHA::CH::WaveSaving, "True", -1); //} if( chkSaveRun->isChecked() ){ //Save setting to raw data with run ID QString fileSetting = rawDataPath + "/" + expName + "_" + runIDStr + "XSetting_" + QString::number(digi[i]->GetSerialNumber()) + ".dat"; digi[i]->SaveSettingsToFile(fileSetting.toStdString().c_str()); // name should be [ExpName]_[runID]_[digiID]_[digiSerialNumber]_[acculmulate_count].sol QString outFileName = rawDataPath + "/" + expName + "_" + runIDStr + "_" + QString::number(i).rightJustified(2, '0') + "_" + QString::number(digi[i]->GetSerialNumber()); qDebug() << outFileName; digi[i]->OpenOutFile(outFileName.toStdString());// overwrite } digi[i]->StartACQ(); //TODO ========================== Sync start. readDataThread[i]->SetSaveData(chkSaveRun->isChecked()); readDataThread[i]->start(); } if(chkSaveRun->isChecked() ){ QString startTimeStr = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss"); LogMsg(" All Digitizers started. "); // ============ elog QString elogMsg = "=============== Run-" + runIDStr + "
" + startTimeStr + "
" + "comment : " + startComment + "
" + + "----------------------------------------------"; WriteElog(elogMsg, "Run-" + runIDStr, "Run", runID); // ============ update expName.sh WriteExpNameSh(); WriteRunTimeStampDat(true, startTimeStr); } if( influx ){ influx->ClearDataPointsBuffer(); if( chkSaveRun->isChecked() ){ influx->AddDataPoint("RunID,start=1 value=" + std::to_string(runID) + ",expName=\"" + expName.toStdString() + "\",comment=\"" + startComment.replace(' ', '_').toStdString() + "\""); } influx->AddDataPoint("StartStop value=1"); influx->WriteData(DatabaseName.toStdString()); } if( !scalar->isVisible() ) { scalar->show(); if( !scalarThread->isRunning() ) scalarThread->start(); } isACQRunning = True; lbScalarACQStatus->setText("ACQ On"); //scalarThread->start(); scalarOutputInflux = true; return 1; } void MainWindow::StopACQ(){ if( !isACQRunning ) return; if( chkSaveRun->isChecked() ){ //============ stop comment if( needManualComment ){ QDialog * dOpen = new QDialog(this); dOpen->setWindowTitle("Stop Run Comment"); dOpen->setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint); dOpen->setMinimumWidth(600); connect(dOpen, &QDialog::finished, dOpen, &QDialog::deleteLater); QGridLayout * vlayout = new QGridLayout(dOpen); QLabel *label = new QLabel("Enter Run comment for ending Run-" + runIDStr + " : ", dOpen); QLineEdit *lineEdit = new QLineEdit(dOpen); QPushButton *button1 = new QPushButton("OK", dOpen); QPushButton *button2 = new QPushButton("Cancel", dOpen); vlayout->addWidget(label, 0, 0, 1, 2); vlayout->addWidget(lineEdit, 1, 0, 1, 2); vlayout->addWidget(button1, 2, 0); vlayout->addWidget(button2, 2, 1); connect(button1, &QPushButton::clicked, dOpen, &QDialog::accept); connect(button2, &QPushButton::clicked, dOpen, &QDialog::reject); int result = dOpen->exec(); if(result == QDialog::Accepted ){ stopComment = lineEdit->text(); if( stopComment == "") stopComment = "No commet was typed."; stopComment = "Stop Comment: " + stopComment; leRunComment->setText(stopComment); }else{ LogMsg("Cancel Run aborted. "); return; } }else{ stopComment = "End of AutoRun for " + cbAutoRun->currentText(); leRunComment->setText(stopComment); } } //=============== Stop digitizer for( int i = nDigi - 1; i >= 0; i--){ if( digi[i]->IsDummy () ) continue; digiMTX[i].lock(); digi[i]->StopACQ(); // readDataThread[i]->SuppressFileSizeMsg(); digi[i]->WriteValue(PHA::CH::WaveSaving, "OnRequest", -1); digiMTX[i].unlock(); } isACQRunning = false; lbScalarACQStatus->setText("ACQ Off"); QString stopTimeStr = QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss"); scalarOutputInflux = false; if( chkSaveRun->isChecked() ){ LogMsg("=========================== Run-" + runIDStr + " stopped."); LogMsg("Please wait for collecting all remaining data."); WriteRunTimeStampDat(false, stopTimeStr); // ============= elog QString msg = stopTimeStr + "
"; for( int i = 0; i < nDigi; i++){ if( digi[i]->IsDummy () ) continue; msg += "FileSize ("+ QString::number(digi[i]->GetSerialNumber()) +"): " + QString::number(digi[i]->GetTotalFilesSize()/1024./1024.) + " MB
"; } msg += "comment : " + stopComment + "
" + "======================"; AppendElog(msg, chromeWindowID); }else{ LogMsg("=========================== no-Save Run stopped."); } if( influx ){ influx->ClearDataPointsBuffer(); if( chkSaveRun->isChecked() ){ influx->AddDataPoint("RunID,start=0 value=" + std::to_string(runID) + ",expName=\"" + expName.toStdString()+ "\",comment=\"" + stopComment.replace(' ', '_').toStdString() + "\""); } influx->AddDataPoint("StartStop value=0"); influx->WriteData(DatabaseName.toStdString()); } if( chkSaveRun->isChecked() ) LogMsg("Collecting remaining data from the digitizers... "); for( int i = nDigi -1; i >=0; i--){ if( readDataThread[i]->isRunning()){ if( !chkSaveRun->isChecked() ) readDataThread[i]->Stop(); // if it is a save run, don't force stop the readDataThread, wait for it. readDataThread[i]->quit(); readDataThread[i]->wait(); } if( chkSaveRun->isChecked() ) { digi[i]->CloseOutFile(); LogMsg("Digi-" + QString::number(digi[i]->GetSerialNumber()) + " is done collecting all data."); } } if( chkSaveRun->isChecked() ){ LogMsg("Run " + programPath + "/scripts/endRunScript.sh" ); QProcess::startDetached(programPath + "/scripts/endRunScript.sh"); } LogMsg("SOLARIS DAQ is ready for next run."); } void MainWindow::AutoRun(){ if( chkSaveRun->isChecked() == false){ if( StartACQ() ){ bnStartACQ->setEnabled(false); bnStopACQ->setEnabled(true); bnComment->setEnabled(false); bnOpenScope->setEnabled(false); chkSaveRun->setEnabled(false); cbAutoRun->setEnabled(false); cbDataFormat->setEnabled(false); if( digiSetting ) digiSetting->EnableControl(); } return; } needManualComment = true; int isRun = 0; ///=========== infinite single run if( cbAutoRun->currentData().toInt() == 0 ){ isRun = StartACQ(); disconnect(runTimer, &QTimer::timeout, nullptr, nullptr); }else{ isRun = StartACQ(); connect(runTimer, &QTimer::timeout, this, [=](){ StopACQ(); if( cbAutoRun->currentData().toInt() > 0 ) { bnStartACQ->setEnabled(true); bnStopACQ->setEnabled(false); bnComment->setEnabled(false); bnOpenScope->setEnabled(true); chkSaveRun->setEnabled(true); cbAutoRun->setEnabled(true); cbDataFormat->setEnabled(true); if( digiSetting ) digiSetting->EnableControl(); }else{ LogMsg("Wait for 10 sec for next Run...."); elapsedTimer.invalidate(); elapsedTimer.start(); while(elapsedTimer.elapsed() < 10000) { QCoreApplication::processEvents(); if( ACQStopButtonPressed ) { ACQStopButtonPressed = false; return; } } StartACQ(); } }); } if( isRun == 0 ) return; int timeMiliSec = cbAutoRun->currentData().toInt() * 60 * 1000; ///=========== single timed run if( cbAutoRun->currentData().toInt() > 0 ){ runTimer->setSingleShot(true); runTimer->start(timeMiliSec); needManualComment = false; } ///=========== infinite timed run if( cbAutoRun->currentData().toInt() < 0 ){ runTimer->setSingleShot(false); runTimer->start(abs(timeMiliSec)); needManualComment = false; } bnStartACQ->setEnabled(false); bnStopACQ->setEnabled(true); if(chkSaveRun->isChecked()) bnComment->setEnabled(true); bnOpenScope->setEnabled(false); chkSaveRun->setEnabled(false); cbDataFormat->setEnabled(false); cbAutoRun->setEnabled(false); if( digiSetting ) digiSetting->EnableControl(); } //*###################################################################### //*###################################################################### open and close digitizer void MainWindow::OpenDigitizers(){ LogMsg("Opening " + QString::number(nDigi) + " Digitizers..... "); digi = new Digitizer2Gen*[nDigi]; readDataThread = new ReadDataThread*[nDigi]; nDigiConnected = 0; //Check path exist QDir dir(analysisPath + "/working/Settings/"); if( !dir.exists() ) dir.mkpath("."); for( int i = 0; i < nDigi; i++){ LogMsg("IP : " + IPList[i] + " | " + QString::number(i+1) + "/" + QString::number(nDigi)); digi[i] = new Digitizer2Gen(); digi[i]->OpenDigitizer(("dig2://" + IPList[i]).toStdString().c_str()); if(digi[i]->IsConnected()){ LogMsg("Opened digitizer : " + QString::number(digi[i]->GetSerialNumber()) + ""); readDataThread[i] = new ReadDataThread(digi[i], i, this); connect(readDataThread[i], &ReadDataThread::sendMsg, this, &MainWindow::LogMsg); //*------ search for settings_XXX_YYY.dat, YYY is DPP-type, XXX is serial number QString settingFile = analysisPath + "/working/Settings/setting_" + QString::number(digi[i]->GetSerialNumber()) + "_" + QString::fromStdString(digi[i]->GetFPGAType().substr(4)) + ".dat"; if( digi[i]->LoadSettingsFromFile( settingFile.toStdString().c_str() ) ){ LogMsg("Found setting file " + settingFile + " and loading. please wait."); digi[i]->SetSettingFileName(settingFile.toStdString()); LogMsg("done settings."); }else{ LogMsg("Unable to found setting file " + settingFile + ". "); digi[i]->SetSettingFileName(""); //LogMsg("Reset digitizer And set default PHA settings."); //digi[i]->Reset(); //digi[i]->ProgramBoard(false); } nDigiConnected ++; for( int ch = 0; ch < (int) digi[i]->GetNChannels(); ch++) { oldTimeStamp[i][ch] = 0; oldSavedCount[i][ch] = 0; } }else{ digi[i]->SetDummy(i); LogMsg("Cannot open digitizer. Use a dummy with serial number " + QString::number(i) + " and " + QString::number(digi[i]->GetNChannels()) + " ch."); readDataThread[i] = NULL; } QCoreApplication::processEvents(); // to prevent application busy. } if( nDigiConnected > 0 ){ SetUpScalar(); bnStartACQ->setEnabled(true); bnStopACQ->setEnabled(false); bnComment->setEnabled(false); bnOpenScope->setEnabled(true); chkSaveRun->setEnabled(true); bnSyncHelper->setEnabled(true); bnOpenDigitizers->setEnabled(false); bnOpenDigitizers->setStyleSheet(""); cbAutoRun->setEnabled(true); cbDataFormat->setEnabled(true); bnOpenScalar->setEnabled(true); } bnDigiSettings->setEnabled(true); bnCloseDigitizers->setEnabled(true); bnProgramSettings->setEnabled(false); bnNewExp->setEnabled(false); bnSOLSettings->setEnabled(CheckSOLARISpanelOK()); } void MainWindow::CloseDigitizers(){ if( digi == NULL) return; if( scope ){ scope->close(); delete scope; scope = NULL; } if(scalar && nDigiConnected > 0 ){ // scalar is child of this, This MUST after scope, because scope tell scalar to update ACQ status scalar->close(); if( scalarThread->isRunning()){ scalarThread->Stop(); scalarThread->quit(); scalarThread->wait(); } CleanUpScalar(); // this use digi->GetNChannels(); } if( digiSetting ){ digiSetting->close(); delete digiSetting; digiSetting = NULL; } if( solarisSetting ){ solarisSetting->close(); delete solarisSetting; solarisSetting = NULL; } for( int i = 0; i < nDigi; i++){ if( digi[i] == NULL) return; if( digi[i]->IsConnected() ){ int digiSN = digi[i]->GetSerialNumber(); LogMsg("Save digi-"+ QString::number(digiSN) + " Settings to " + programPath + "/tempSettings/"); digi[i]->SaveSettingsToFile((programPath + "/tempSettings/Setting_" + QString::number(digiSN)).toStdString().c_str()); } digi[i]->CloseDigitizer(); delete digi[i]; LogMsg("Closed Digitizer : " + QString::number(digi[i]->GetSerialNumber())); if( readDataThread[i] != NULL ){ LogMsg("Waiting for readData Thread ....."); readDataThread[i]->Stop(); readDataThread[i]->quit(); readDataThread[i]->wait(); delete readDataThread[i]; } } delete [] digi; delete [] readDataThread; digi = NULL; readDataThread = NULL; bnSyncHelper->setEnabled(false); bnOpenDigitizers->setEnabled(true); bnOpenDigitizers->setFocus(); bnCloseDigitizers->setEnabled(false); bnDigiSettings->setEnabled(false); bnSOLSettings->setEnabled(false); bnStartACQ->setEnabled(false); bnStopACQ->setEnabled(false); bnComment->setEnabled(false); bnOpenScope->setEnabled(false); bnOpenScalar->setEnabled(false); chkSaveRun->setEnabled(false); cbAutoRun->setEnabled(false); cbDataFormat->setEnabled(false); bnProgramSettings->setEnabled(true); bnNewExp->setEnabled(true); LogMsg("Closed all digitizers and readData Threads."); } void MainWindow::OpenSyncHelper(){ LogMsg("Open Sync Helper."); QDialog dialog(this); dialog.setWindowTitle("Sync Helper"); dialog.setWindowFlags(Qt::Dialog | Qt::WindowTitleHint); QVBoxLayout * layout = new QVBoxLayout(&dialog); QPushButton * bnNoSync = new QPushButton("No Sync", &dialog); QPushButton * bnMethod1 = new QPushButton("Software CLK-OUT --> CLK-IN\n(Master = 1st Digi)", &dialog); layout->addWidget( bnNoSync, 1); layout->addWidget(bnMethod1, 2); bnNoSync->setFixedHeight(40); bnMethod1->setFixedHeight(40); connect(bnNoSync, &QPushButton::clicked, [&](){ for(unsigned int i = 0; i < nDigi; i++){ digi[i]->WriteValue(PHA::DIG::ClockSource, "Internal"); digi[i]->WriteValue(PHA::DIG::StartSource, "SWcmd"); digi[i]->WriteValue(PHA::DIG::SyncOutMode, "Disabled"); } if( digiSetting ) digiSetting->UpdatePanelFromMemory(); bnSyncHelper->setText("Sync Helper (No Sync)"); dialog.accept(); }); connect(bnMethod1, &QPushButton::clicked, [&](){ digi[0]->WriteValue(PHA::DIG::ClockSource, "Internal"); digi[0]->WriteValue(PHA::DIG::EnableClockOutFrontPanel, "True"); digi[0]->WriteValue(PHA::DIG::StartSource, "SWcmd"); digi[0]->WriteValue(PHA::DIG::SyncOutMode, "Run"); for(unsigned int i = 1; i < nDigi; i++){ digi[i]->WriteValue(PHA::DIG::ClockSource, "FPClkIn"); digi[i]->WriteValue(PHA::DIG::EnableClockOutFrontPanel, "True"); digi[i]->WriteValue(PHA::DIG::StartSource, "EncodedClkIn"); digi[i]->WriteValue(PHA::DIG::SyncOutMode, "SyncIn"); } if( digiSetting ) digiSetting->UpdatePanelFromMemory(); bnSyncHelper->setText("Sync Helper (Software)"); dialog.accept(); }); dialog.exec(); } //*###################################################################### //*###################################################################### Open Scope void MainWindow::OpenScope(){ if( digi ){ if( !scope ){ scope = new Scope(digi, nDigi, readDataThread); connect(scope, &Scope::CloseWindow, this, [=](){ bnStartACQ->setEnabled(true); }); //connect(scope, &Scope::UpdateScalar, this, &MainWindow::UpdateScalar); connect(scope, &Scope::SendLogMsg, this, &MainWindow::LogMsg); connect(scope, &Scope::UpdateOtherPanels, this, [=](){ UpdateAllPanel(0);}); connect(scope, &Scope::TellACQOnOff, this, [=](const bool onOff){ if( influx ){ influx->ClearDataPointsBuffer(); influx->AddDataPoint(onOff ? "StartStop value=1" : "StartStop value=0"); influx->WriteData(DatabaseName.toStdString()); } if( onOff){ lbScalarACQStatus->setText("ACQ On"); }else{ lbScalarACQStatus->setText("ACQ Off"); } }); if( influx ){ influx->ClearDataPointsBuffer(); influx->AddDataPoint("StartStop value=1"); influx->WriteData(DatabaseName.toStdString()); } if( digiSetting) { connect(scope, &Scope::TellSettingsPanelControlOnOff, digiSetting, &DigiSettingsPanel::EnableControl); digiSetting->EnableControl(); } //scope->StartScope(); }else{ scope->show(); if( scope->isVisible() ) scope->activateWindow(); //scope->StartScope(); if( digiSetting ) digiSetting->EnableControl(); } } bnStartACQ->setEnabled(false); } //^###################################################################### Open digitizer setting panel void MainWindow::OpenDigitizersSettings(){ LogMsg("Open digitizers Settings Panel"); if( digiSetting == NULL){ digiSetting = new DigiSettingsPanel(digi, nDigi, analysisPath); connect(digiSetting, &DigiSettingsPanel::SendLogMsg, this, &MainWindow::LogMsg); connect(digiSetting, &DigiSettingsPanel::UpdateOtherPanels, this, [=](){ UpdateAllPanel(1);}); }else{ digiSetting->show(); if( digiSetting->isVisible() ) digiSetting->activateWindow(); } digiSetting->UpdatePanelFromMemory(); } //^###################################################################### Open SOLARIS setting panel void MainWindow::OpenSOLARISpanel(){ LogMsg("Open SOLARIS Panel."); solarisSetting->show(); solarisSetting->UpdatePanelFromMemory(); if( solarisSetting->isVisible() ) solarisSetting->activateWindow(); } bool MainWindow::CheckSOLARISpanelOK(){ QFile file(analysisPath + "/working/Mapping.h"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { LogMsg("Fail to open " + file.fileName() + ". SOLARIS panel disabled."); //TODO ----- Create a template of the mapping return false; } LogMsg("Found " + file.fileName() + ". Setting up SOLARIS panel."); mapping.clear(); std::vector singleDigiMap; detType.clear(); detGroupID.clear(); detMaxID.clear(); detGroupName.clear(); bool startRecord = false; QTextStream in(&file); while (!in.atEnd()) { QString line = in.readLine(); if( line.contains("//^")) continue; if( line.contains("// //")) continue; if( line.contains("////")) continue; if( line.contains("//C=")){ // detType int in1 = line.indexOf("{"); int in2 = line.lastIndexOf("}"); if( in2 > in1){ QString subLine = line.mid(in1+1, in2 - in1 -1).trimmed().remove(QRegularExpression("[\"\\\\]")); detType = subLine.split(","); }else{ LogMsg("Problem Found for the Mapping.h."); return false; } } if( line.contains("//C%")){ // groupName int in1 = line.indexOf("{"); int in2 = line.lastIndexOf("}"); if( in2 > in1){ QString subLine = line.mid(in1+1, in2 - in1 -1).trimmed().remove(QRegularExpression("[\"\\\\]")); detGroupName = subLine.split(","); }else{ LogMsg("Problem Found for the Mapping.h."); return false; } } if( line.contains("//C&")){ //groupID int in1 = line.indexOf("{"); int in2 = line.lastIndexOf("}"); if( in2 > in1){ QString subLine = line.mid(in1+1, in2 - in1 -1).trimmed().remove(QRegularExpression("[\"\\\\]")); QStringList haha = subLine.split(","); for( int i = 0; i < haha.size(); i++) detGroupID.push_back(haha[i].toInt()); }else{ LogMsg("Problem Found for the Mapping.h."); return false; } } if( line.contains("//C#")){ //detMaxID int in1 = line.indexOf("{"); int in2 = line.lastIndexOf("}"); if( in2 > in1){ QString subLine = line.mid(in1+1, in2 - in1 -1).trimmed().remove(QRegularExpression("[\"\\\\]")); QStringList haha = subLine.split(","); for( int i = 0; i < haha.size(); i++) detMaxID.push_back(haha[i].toInt()); }else{ LogMsg("Problem Found for the Mapping.h."); return false; } } if( line.contains("//C ") ) { startRecord = true; singleDigiMap.clear(); continue; } if( startRecord && line.contains("//C----")){ startRecord = false; mapping.push_back(singleDigiMap); continue; } if( startRecord ){ int index = line.lastIndexOf("///"); if( index != -1 ) { line = line.left(index).trimmed(); if( line.endsWith(",") ){ line.remove( line.length() -1, 1); } } QStringList list = line.replace(' ', "").split(","); for( int i = 0; i < list.size() ; i ++){ singleDigiMap.push_back(list[i].toInt()); } } } file.close(); LogMsg("Mapping.h | Num. Digi : " + QString::number(mapping.size())); for( int i = 0 ; i < (int) mapping.size(); i ++){ if( i < nDigi ){ LogMsg(" Digi-" + QString::number(i) + " : " + QString::number(mapping[i].size()) + " Ch. | Digi-" + QString::number(digi[i]->GetSerialNumber()) + " : " + QString::number(digi[i]->GetNChannels()) + " Ch."); }else{ LogMsg(" Digi-" + QString::number(i) + " : " + QString::number(mapping[i].size()) + " Ch. | No Conneted Digitizer" ); } } if( (int) detMaxID.size() != detType.size() ){ LogMsg("Size of detector Name and detctor max ID does not match."); return false; } if( nDigiConnected == 0 ) return false; //@============= Create SOLAIRS panel solarisSetting = new SOLARISpanel(digi, nDigi, analysisPath, mapping, detType, detGroupName, detGroupID, detMaxID); connect(solarisSetting, &SOLARISpanel::SendLogMsg, this, &MainWindow::LogMsg); connect(solarisSetting, &SOLARISpanel::UpdateOtherPanels, this, [=](){ UpdateAllPanel(2);}); if( solarisSetting == nullptr) return false; return true; } void MainWindow::UpdateAllPanel(int panelID){ printf("%s %d\n", __func__, panelID); switch (panelID) { case 0 :{ if( digiSetting && digiSetting->isVisible() ) digiSetting->UpdatePanelFromMemory(); if( solarisSetting && solarisSetting->isVisible() ) solarisSetting->UpdatePanelFromMemory(); };break; case 1 :{ if( scope && scope->isVisible() ) scope->ReadScopeSettings(); if( solarisSetting && solarisSetting->isVisible() ) solarisSetting->UpdatePanelFromMemory(); };break; case 2 :{ if( scope && scope->isVisible() ) scope->ReadScopeSettings(); if( digiSetting && digiSetting->isVisible() ) digiSetting->UpdatePanelFromMemory(); } } } //^###################################################################### Open Scaler, when DAQ is running void MainWindow::OpenScaler(){ scalar->show(); if( isACQRunning ) { lbScalarACQStatus->setText("ACQ On"); }else{ lbScalarACQStatus->setText("ACQ Off"); } scalarThread->start(); if( scalar->isVisible() ) scalar->activateWindow(); } void MainWindow::SetUpScalar(){ scalar->setGeometry(0, 0, 10 + nDigi * 230, 1500); lbLastUpdateTime = new QLabel("Last update : ", scalar); lbLastUpdateTime->setAlignment(Qt::AlignCenter); scalarLayout->removeWidget(lbLastUpdateTime); scalarLayout->addWidget(lbLastUpdateTime, 0, 1, 1, 1 + nDigi); lbScalarACQStatus = new QLabel("ACQ status", scalar); lbScalarACQStatus->setAlignment(Qt::AlignCenter); scalarLayout->removeWidget(lbScalarACQStatus); scalarLayout->addWidget(lbScalarACQStatus, 1, 1, 1, 1 + nDigi); // QPushButton * bnUpdateScaler = new QPushButton("Manual Update", scalar); // scalarLayout->addWidget(bnUpdateScaler, 2, 1, 1, 1 + nDigi); // connect(bnUpdateScaler, &QPushButton::clicked, this, &MainWindow::UpdateScalar); ///==== create the 1st row int rowID = 5; for( int ch = 0; ch < MaxNumberOfChannel; ch++){ if( ch == 0 ){ QLabel * lbCH_H = new QLabel("Ch", scalar); scalarLayout->addWidget(lbCH_H, rowID, 0); } rowID ++; QLabel * lbCH = new QLabel(QString::number(ch), scalar); lbCH->setAlignment(Qt::AlignCenter); scalarLayout->addWidget(lbCH, rowID, 0); } ///===== create the trigger and accept leTrigger = new QLineEdit**[nDigi]; leAccept = new QLineEdit**[nDigi]; lbFileSize = new QLabel *[nDigi]; for( int iDigi = 0; iDigi < nDigi; iDigi++){ rowID = 3; lbFileSize[iDigi] = new QLabel("file Size", scalar); lbFileSize[iDigi]->setAlignment(Qt::AlignCenter); leTrigger[iDigi] = new QLineEdit *[digi[iDigi]->GetNChannels()]; leAccept[iDigi] = new QLineEdit *[digi[iDigi]->GetNChannels()]; for( int ch = 0; ch < digi[iDigi]->GetNChannels(); ch++){ if( ch == 0 ){ QLabel * lbDigi = new QLabel("Digi-" + QString::number(digi[iDigi]->GetSerialNumber()), scalar); lbDigi->setAlignment(Qt::AlignCenter); scalarLayout->addWidget(lbDigi, rowID, 2*iDigi+1, 1, 2); rowID ++; scalarLayout->addWidget(lbFileSize[iDigi], rowID, 2*iDigi+1, 1, 2); rowID ++; QLabel * lbA = new QLabel("Input [Hz]", scalar); lbA->setAlignment(Qt::AlignCenter); scalarLayout->addWidget(lbA, rowID, 2*iDigi+1); QLabel * lbB = new QLabel("Trig. [Hz]", scalar); lbB->setAlignment(Qt::AlignCenter); scalarLayout->addWidget(lbB, rowID, 2*iDigi+2); } rowID ++; leTrigger[iDigi][ch] = new QLineEdit(scalar); leTrigger[iDigi][ch]->setReadOnly(true); leTrigger[iDigi][ch]->setAlignment(Qt::AlignRight); scalarLayout->addWidget(leTrigger[iDigi][ch], rowID, 2*iDigi+1); leAccept[iDigi][ch] = new QLineEdit(scalar); leAccept[iDigi][ch]->setReadOnly(true); leAccept[iDigi][ch]->setAlignment(Qt::AlignRight); leAccept[iDigi][ch]->setStyleSheet("background-color: #F0F0F0;"); scalarLayout->addWidget(leAccept[iDigi][ch], rowID, 2*iDigi+2); } } } void MainWindow::CleanUpScalar(){ if( leTrigger == nullptr ) return; for( int i = 0; i < nDigi; i++){ for( int ch = 0; ch < digi[i]->GetNChannels(); ch ++){ delete leTrigger[i][ch]; delete leAccept[i][ch]; } delete lbFileSize[i]; delete [] leTrigger[i]; delete [] leAccept[i]; } delete [] lbFileSize; delete [] leTrigger; delete [] leAccept; lbFileSize = nullptr; leTrigger = nullptr; leAccept = nullptr; //Clean up QLabel QList labelChildren = scalar->findChildren(); for( int i = 0; i < labelChildren.size(); i++) delete labelChildren[i]; } void MainWindow::UpdateScalar(){ if( !digi ) return; lbLastUpdateTime->setText("Last update: " + QDateTime::currentDateTime().toString("MM.dd hh:mm:ss")); if( influx && scalarOutputInflux) influx->ClearDataPointsBuffer(); std::string haha[MaxNumberOfChannel] = {""}; double acceptRate[MaxNumberOfChannel] = {0}; ///===== Get trigger for all channel unsigned long totalFileSize = 0; for( int iDigi = 0; iDigi < nDigi; iDigi ++ ){ if( digi[iDigi]->IsDummy() ) return; //=========== another method, directly readValue for( int ch = 0; ch < digi[iDigi]->GetNChannels(); ch ++){ digiMTX[iDigi].lock(); std::string timeStr = digi[iDigi]->ReadValue(PHA::CH::ChannelRealtime, ch); // for refreashing SelfTrgRate and SavedCount haha[ch] = digi[iDigi]->ReadValue(PHA::CH::SelfTrgRate, ch); std::string kakaStr = digi[iDigi]->ReadValue(PHA::CH::ChannelSavedCount, ch); digiMTX[iDigi].unlock(); unsigned long kaka = std::stoul(kakaStr.c_str()) ; unsigned long time = std::stoul(timeStr.c_str()) ; leTrigger[iDigi][ch]->setText(QString::fromStdString(haha[ch])); if( oldTimeStamp[iDigi][ch] > 0 && time - oldTimeStamp[iDigi][ch] > 1e9 && kaka > oldSavedCount[iDigi][ch]){ acceptRate[ch] = (kaka - oldSavedCount[iDigi][ch]) * 1e9 *1.0 / (time - oldTimeStamp[iDigi][ch]); }else{ acceptRate[ch] = 0; } //if( acceptRate[ch] > 10000 ) printf("%d-%2d | old (%lu, %lu), new (%lu, %lu)\n", iDigi, ch, oldTimeStamp[iDigi][ch], oldSavedCount[iDigi][ch], time, kaka); oldSavedCount[iDigi][ch] = kaka; oldTimeStamp[iDigi][ch] = time; //if( kaka != "0" ) printf("%s, %s | %.2f\n", time.c_str(), kaka.c_str(), acceptRate); leAccept[iDigi][ch]->setText(QString::number(acceptRate[ch],'f', 1)); lbFileSize[iDigi]->setText(QString::number(digi[iDigi]->GetTotalFilesSize()/1024./1024.) + " MB"); } ///============== push the trigger, acceptRate rate database if( influx && scalarOutputInflux ){ for( int ch = 0; ch < digi[iDigi]->GetNChannels(); ch++ ){ influx->AddDataPoint("Rate,Bd=" + std::to_string(digi[iDigi]->GetSerialNumber()) + ",Ch=" + QString::number(ch).rightJustified(2, '0').toStdString() + " value=" + haha[ch]); if( !std::isnan(acceptRate[ch]) ) influx->AddDataPoint("AccpRate,Bd=" + std::to_string(digi[iDigi]->GetSerialNumber()) + ",Ch=" + QString::number(ch).rightJustified(2, '0').toStdString() + " value=" + std::to_string(acceptRate[ch])); } } totalFileSize += digi[iDigi]->GetTotalFilesSize(); } if( influx && influx->GetDataLength() > 0 && scalarOutputInflux ){ if( chkSaveRun->isChecked() ) influx->AddDataPoint("FileSize value=" + std::to_string(totalFileSize)); //influx->PrintDataPoints(); influx->WriteData(DatabaseName.toStdString()); influx->ClearDataPointsBuffer(); } //TODO record ADC temperature, and status. In this case, the digiSetting is only UpdateFromMemory, manually looping digitizers and get the status. if( digiSetting && digiSetting->isVisible() ) digiSetting->UpdateStatus(); if( solarisSetting && solarisSetting->isVisible() ) solarisSetting->UpdateThreshold(); } //*###################################################################### //*###################################################################### Program Settings void MainWindow::ProgramSettingsPanel(){ LogMsg("Open Program Settings."); QDialog dialog(this); dialog.setWindowTitle("Program Settings"); dialog.setGeometry(0, 0, 700, 500); dialog.setWindowFlags(Qt::Dialog | Qt::WindowTitleHint); QGridLayout * layout = new QGridLayout(&dialog); layout->setVerticalSpacing(5); unsigned int rowID = 0; //-------- Instruction QPlainTextEdit * helpInfo = new QPlainTextEdit(&dialog); helpInfo->setReadOnly(true); helpInfo->setStyleSheet("background-color: #F3F3F3;"); helpInfo->setLineWrapMode(QPlainTextEdit::LineWrapMode::WidgetWidth); helpInfo->appendHtml("

"); helpInfo->appendHtml(" Analysis Path is the path of \ the folder of the analysis code. Can be omitted."); helpInfo->appendHtml("

"); helpInfo->appendHtml("

"); helpInfo->appendHtml(" Analysis Path is the path of \ the folder of the analysis code. Can be omitted."); helpInfo->appendHtml("

"); helpInfo->appendHtml(" Data Path is the path of the \ parents folder of data will store. "); helpInfo->appendHtml(" Exp Name is the name of the experiment. \ This set the exp. folder under the Data Path .\ The experiment data will be saved under this folder. e.g. Data Path/Exp Name"); helpInfo->appendHtml("

"); helpInfo->appendHtml(" Digitizers IP List is the list of IP \ digi of the digitizers IP. Break by \",\", continue by \"-\". e.g. 192.168.0.100,102 for 2 digitizers, or 192.168.0.100-102 for 3 digitizers."); helpInfo->appendHtml("

"); helpInfo->appendHtml(" Analysis Path is the path of \ the folder of the analysis code. Can be omitted."); helpInfo->appendHtml(" Database IP or Elog IP can be empty. In that case, no database and elog will be used."); helpInfo->appendHtml("

"); helpInfo->appendHtml(" * items can be ommitted"); layout->addWidget(helpInfo, rowID, 0, 1, 4); //-------- Program Setting Path // rowID ++; // QLabel *lbSaveSettingPath = new QLabel("Settings Save Path", &dialog); // lbSaveSettingPath->setAlignment(Qt::AlignRight | Qt::AlignCenter); // layout->addWidget(lbSaveSettingPath, rowID, 0); // lSaveSettingPath = new QLineEdit(programSettingsPath, &dialog); layout->addWidget(lSaveSettingPath, rowID, 1, 1, 2); // QPushButton * bnSaveSettingPath = new QPushButton("browser", &dialog); layout->addWidget(bnSaveSettingPath, rowID, 3); // connect(bnSaveSettingPath, &QPushButton::clicked, this, [=](){this->OpenDirectory(0);}); //-------- data Path rowID ++; QLabel *lbDataPath = new QLabel("Data Path", &dialog); lbDataPath->setAlignment(Qt::AlignRight | Qt::AlignCenter); layout->addWidget(lbDataPath, rowID, 0); lExpDataPath = new QLineEdit(masterExpDataPath, &dialog); layout->addWidget(lExpDataPath, rowID, 1, 1, 2); QPushButton * bnDataPath = new QPushButton("browser", &dialog); layout->addWidget(bnDataPath, rowID, 3); connect(bnDataPath, &QPushButton::clicked, this, [=](){this->OpenDirectory(2);}); //-------- root data Path // rowID ++; // QLabel *lbRootDataPath = new QLabel("Root Data Path", &dialog); // lbRootDataPath->setAlignment(Qt::AlignRight | Qt::AlignCenter); // layout->addWidget(lbRootDataPath, rowID, 0); // lRootDataPath = new QLineEdit(rootDataPath, &dialog); layout->addWidget(lRootDataPath, rowID, 1, 1, 2); // QPushButton * bnRootDataPath = new QPushButton("browser", &dialog); layout->addWidget(bnRootDataPath, rowID, 3); // connect(bnRootDataPath, &QPushButton::clicked, this, [=](){this->OpenDirectory(3);}); //-------- Exp Name Temp rowID ++; QLabel *lbExpNameTemp = new QLabel("Exp Name", &dialog); lbExpNameTemp->setAlignment(Qt::AlignRight | Qt::AlignCenter); layout->addWidget(lbExpNameTemp, rowID, 0); lExpName = new QLineEdit(expName, &dialog); layout->addWidget(lExpName, rowID, 1, 1, 2); //-------- Digitizer IP rowID ++; QLabel *lbIPDomain = new QLabel("Digitizers IP List", &dialog); lbIPDomain->setAlignment(Qt::AlignRight | Qt::AlignCenter); layout->addWidget(lbIPDomain, rowID, 0); lIPDomain = new QLineEdit(IPListStr, &dialog); layout->addWidget(lIPDomain, rowID, 1, 1, 2); //------- add a separator rowID ++; QFrame * line = new QFrame; line->setFrameShape(QFrame::HLine); line->setFrameShadow(QFrame::Sunken); layout->addWidget(line, rowID, 0, 1, 4); //-------- analysis Path rowID ++; QLabel *lbAnalysisPath = new QLabel("Analysis Path *", &dialog); lbAnalysisPath->setAlignment(Qt::AlignRight | Qt::AlignCenter); layout->addWidget(lbAnalysisPath, rowID, 0); lAnalysisPath = new QLineEdit(analysisPath, &dialog); layout->addWidget(lAnalysisPath, rowID, 1, 1, 2); QPushButton * bnAnalysisPath = new QPushButton("browser", &dialog); layout->addWidget(bnAnalysisPath, rowID, 3); connect(bnAnalysisPath, &QPushButton::clicked, this, [=](){this->OpenDirectory(1);}); //-------- DataBase IP rowID ++; QLabel *lbDatbaseIP = new QLabel("Database IP *", &dialog); lbDatbaseIP->setAlignment(Qt::AlignRight | Qt::AlignCenter); layout->addWidget(lbDatbaseIP, rowID, 0); lDatbaseIP = new QLineEdit(DatabaseIP, &dialog); layout->addWidget(lDatbaseIP, rowID, 1, 1, 2); //-------- DataBase name rowID ++; QLabel *lbDatbaseName = new QLabel("Database Name *", &dialog); lbDatbaseName->setAlignment(Qt::AlignRight | Qt::AlignCenter); layout->addWidget(lbDatbaseName, rowID, 0); lDatbaseName = new QLineEdit(DatabaseName, &dialog); layout->addWidget(lDatbaseName, rowID, 1, 1, 2); //-------- Elog IP rowID ++; QLabel *lbElogIP = new QLabel("Elog IP *", &dialog); lbElogIP->setAlignment(Qt::AlignRight | Qt::AlignCenter); layout->addWidget(lbElogIP, rowID, 0); lElogIP = new QLineEdit(ElogIP, &dialog); layout->addWidget(lElogIP, rowID, 1, 1, 2); rowID ++; QPushButton *button1 = new QPushButton("OK and Save", &dialog); layout->addWidget(button1, rowID, 1); QObject::connect(button1, &QPushButton::clicked, this, [=](){ IPListStr = lIPDomain->text(); DatabaseIP = lDatbaseIP->text(); DatabaseName = lDatbaseName->text(); ElogIP = lElogIP->text(); analysisPath = lAnalysisPath->text(); masterExpDataPath = lExpDataPath->text(); expName = lExpName->text(); SaveProgramSettings(); bnProgramSettings->setStyleSheet(""); bnNewExp->setEnabled(true); if( !IPListStr.isEmpty() ){ DecodeIPList(); bnOpenDigitizers->setEnabled(true); }else{ bnProgramSettings->setStyleSheet("color: red;"); LogMsg("Digitizer IP list is empty."); } SetupInflux(); CheckElog(); expDataPath = masterExpDataPath + "/" + expName; rawDataPath = expDataPath + "/data_raw/"; rootDataPath = expDataPath + "/root_data/"; leExpName->setText(expName); CreateRawDataFolder(); LoadExpNameSh(); if(analysisPath.isEmpty()) bnNewExp->setEnabled(false); }); QObject::connect(button1, &QPushButton::clicked, &dialog, &QDialog::accept); QPushButton *button2 = new QPushButton("Cancel", &dialog); layout->addWidget(button2, rowID, 2); QObject::connect(button2, &QPushButton::clicked, this, [=](){this->LogMsg("Cancel Program Settings");}); QObject::connect(button2, &QPushButton::clicked, &dialog, &QDialog::reject); layout->setColumnStretch(0, 2); layout->setColumnStretch(1, 2); layout->setColumnStretch(2, 2); layout->setColumnStretch(3, 1); button1->setFocus(); dialog.exec(); } bool MainWindow::LoadProgramSettings(){ QString settingFile = QDir::current().absolutePath() + "/programSettings.txt"; LogMsg("Loading " + settingFile + " for Program Settings."); QFile file(settingFile); bool ret = false; if( !file.open(QIODevice::Text | QIODevice::ReadOnly) ) { LogMsg("" + settingFile + " not found."); LogMsg("Please Open the Program Settings "); }else{ QTextStream in(&file); QString line = in.readLine(); int count = 0; while( !line.isNull()){ if( line.left(6) == "//----") break; switch (count){ // case 0 : programSettingsPath = line; break; case 0 : masterExpDataPath = line; break; case 1 : expName = line; break; case 2 : IPListStr = line; break; case 3 : analysisPath = line; break; case 4 : DatabaseIP = line; break; case 5 : DatabaseName = line; break; case 6 : ElogIP = line; break; } count ++; line = in.readLine(); } if( count == 7 ) { logMsgHTMLMode = false; // LogMsg("Setting File Path : " + programSettingsPath); LogMsg(" Analysis Path : " + analysisPath); LogMsg(" Database IP : " + DatabaseIP); LogMsg(" Database Name : " + DatabaseName); LogMsg(" ElogIP : " + ElogIP); LogMsg(" Exp Data Path : " + masterExpDataPath); LogMsg(" Temp Exp. Name : " + expName); LogMsg(" Digi. IP List : " + IPListStr); logMsgHTMLMode = true; expDataPath = masterExpDataPath + "/" + expName; rawDataPath = expDataPath + "/data_raw/"; rootDataPath = expDataPath + "/root_data/"; leExpName->setText(expName); ret = true; }else{ LogMsg("Settings are not complete."); LogMsg("Please Open the Program Settings "); } } if( ret ){ //CHeck data path exist QDir dir(rawDataPath); if (!dir.exists()) { LogMsg("Raw data path " + rawDataPath + " does not exist."); bnProgramSettings->setStyleSheet("color: red;"); bnOpenDigitizers->setEnabled(false); bnNewExp->setEnabled(false); // return false; }else{ QFileInfo dirInfo(dir.absolutePath()); if( !dirInfo.isWritable() ){ LogMsg("Raw data path " + rawDataPath + " is not writable."); bnProgramSettings->setStyleSheet("color: red;"); bnOpenDigitizers->setEnabled(false); bnNewExp->setEnabled(false); // return false; }else{ leRawDataPath->setText(rawDataPath); leExpName->setText(expName); } } if( !IPListStr.isEmpty() && dir.exists() ){ bnOpenDigitizers->setEnabled(true); bnOpenDigitizers->setStyleSheet("color:red;"); DecodeIPList(); SetupInflux(); CheckElog(); }else{ LogMsg("Digitizer IP list is empty."); bnProgramSettings->setStyleSheet("color: red;"); bnOpenDigitizers->setEnabled(false); return false; } if(analysisPath.isEmpty()) { LogMsg("Analysis Path is empty."); bnNewExp->setEnabled(false); // return false; } return true; }else{ bnProgramSettings->setStyleSheet("color: red;"); bnNewExp->setEnabled(false); bnOpenDigitizers->setEnabled(false); return false; } } void MainWindow::SaveProgramSettings(){ if( masterExpDataPath.isEmpty() ){ LogMsg("Exp Data Path is empty."); return; } QFile file(programPath + "/programSettings.txt"); file.open(QIODevice::Text | QIODevice::WriteOnly); // file.write((programSettingsPath+"\n").toStdString().c_str()); file.write((masterExpDataPath+"\n").toStdString().c_str()); file.write((expName+"\n").toStdString().c_str()); file.write((IPListStr+"\n").toStdString().c_str()); file.write((analysisPath+"\n").toStdString().c_str()); file.write((DatabaseIP+"\n").toStdString().c_str()); file.write((DatabaseName+"\n").toStdString().c_str()); file.write((ElogIP+"\n").toStdString().c_str()); file.write("//------------end of file."); file.close(); LogMsg("Saved program settings to "+programPath + "/programSettings.txt."); } void MainWindow::OpenDirectory(int id){ QFileDialog fileDialog(this); fileDialog.setFileMode(QFileDialog::Directory); fileDialog.exec(); //qDebug() << fileDialog.selectedFiles(); switch (id){ // case 0 : lSaveSettingPath->setText(fileDialog.selectedFiles().at(0)); break; case 1 : lAnalysisPath->setText(fileDialog.selectedFiles().at(0)); break; case 2 : lExpDataPath->setText(fileDialog.selectedFiles().at(0)); break; // case 3 : lRootDataPath->setText(fileDialog.selectedFiles().at(0)); break; } } void MainWindow::DecodeIPList(){ //------- decode IPListStr nDigi = 0; IPList.clear(); QStringList parts = IPListStr.replace(' ', "").split("."); QString IPDomain = parts[0] + "." + parts[1] + "." + parts[2] + "."; parts = parts[3].split(","); for(int i = 0; i < parts.size(); i++){ if( parts[i].indexOf("-") != -1){ QStringList haha = parts[i].split("-"); for( int j = haha[0].toInt(); j <= haha.last().toInt(); j++){ IPList << IPDomain + QString::number(j); } }else{ IPList << IPDomain + parts[i]; } } nDigi = IPList.size(); } //*###################################################################### //*###################################################################### Setup new exp void MainWindow::SetupNewExpPanel(){ LogMsg("Open New/Change/Reload Exp."); QDialog dialog(this); dialog.setWindowTitle("Setup / change Experiment"); dialog.setGeometry(0, 0, 500, 400); dialog.setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint); QGridLayout * layout = new QGridLayout(&dialog); layout->setVerticalSpacing(5); unsigned short rowID = 0; //------- instruction QPlainTextEdit * instr = new QPlainTextEdit(&dialog); layout->addWidget(instr, rowID, 0, 1, 4); instr->setReadOnly(true); instr->setStyleSheet("background-color: #F3F3F3;"); instr->appendHtml("Setup new experiment will do following things:"); instr->appendHtml("0, Check the git repository in Analysis Path"); instr->appendHtml("1, Create folder in Data Path and Root Data Path"); instr->appendHtml("2, Create Symbolic links in Analysis Path"); instr->appendHtml("

"); instr->appendHtml("If Use Git is checked, \ the repository MUST be clean. \ It will then create a new branch with the New Exp Name \ or change to pre-exist branch."); //------- Analysis Path rowID ++; QLabel * l1 = new QLabel("Analysis Path ", &dialog); l1->setAlignment(Qt::AlignCenter | Qt::AlignRight); layout->addWidget(l1, rowID, 0); QLineEdit * le1 = new QLineEdit(analysisPath, &dialog); le1->setReadOnly(true); layout->addWidget(le1, rowID, 1, 1, 3); // //------- Exp Data Path rowID ++; QLabel * l2 = new QLabel("Data Path ", &dialog); l2->setAlignment(Qt::AlignCenter | Qt::AlignRight); layout->addWidget(l2, rowID, 0); QLineEdit * le2 = new QLineEdit(masterExpDataPath, &dialog); le2->setReadOnly(true); layout->addWidget(le2, rowID, 1, 1, 3); // //------- Root Data Path // rowID ++; // QLabel * l2a = new QLabel("Root Data Path ", &dialog); // l2a->setAlignment(Qt::AlignCenter | Qt::AlignRight); // layout->addWidget(l2a, rowID, 0); // QLineEdit * le2a = new QLineEdit(rootDataPath, &dialog); // le2a->setReadOnly(true); // layout->addWidget(le2a, rowID, 1, 1, 3); //------- get harddisk space; rowID ++; QStorageInfo storage = QStorageInfo::root(); qint64 availableSpace = storage.bytesAvailable(); QLabel * lbDiskSpace = new QLabel("Disk space avalible ", &dialog); lbDiskSpace->setAlignment(Qt::AlignCenter | Qt::AlignRight); layout->addWidget(lbDiskSpace, rowID, 0); QLineEdit * leDiskSpace = new QLineEdit(QString::number(availableSpace/1024./1024./1024.) + " [GB]", &dialog); leDiskSpace->setReadOnly(true); layout->addWidget(leDiskSpace, rowID, 1, 1, 3); //*---------- get git branch isGitExist = false; QProcess git; git.setWorkingDirectory(analysisPath); git.start("git", QStringList() << "fetch"); git.waitForFinished(); git.start("git", QStringList() << "branch" << "-a"); git.waitForFinished(); QByteArray output = git.readAllStandardOutput(); QStringList branches = (QString::fromLocal8Bit(output)).split("\n"); branches.removeAll(""); //qDebug() << branches; if( branches.size() == 0) { isGitExist = false; }else{ isGitExist = true; } QString presentBranch; unsigned short bID = 0; // id of the present branch for( unsigned short i = 0; i < branches.size(); i++){ if( branches[i].indexOf("*") != -1 ){ presentBranch = branches[i].remove("*").remove(" "); bID = i; break; } } //*----------- check git branch is clean for git exist bool isCleanGit = false; if( isGitExist ){ git.start("git", QStringList() << "status" << "--porcelain" << "--untracked-files=no"); git.waitForFinished(); output = git.readAllStandardOutput(); if( (QString::fromLocal8Bit(output)).isEmpty() ) isCleanGit = true; } //------- present git branch rowID ++; QLabel * l3 = new QLabel("Present Git Branches ", &dialog); l3->setAlignment(Qt::AlignCenter | Qt::AlignRight); layout->addWidget(l3, rowID, 0); QLineEdit * le3 = new QLineEdit(presentBranch, &dialog); if( isGitExist == false ) { le3->setText("No git repository!!!"); le3->setStyleSheet("color: red;"); } le3->setReadOnly(true); layout->addWidget(le3, rowID, 1, 1, 3); //------- add a separator rowID ++; QFrame * line = new QFrame; line->setFrameShape(QFrame::HLine); line->setFrameShadow(QFrame::Sunken); layout->addWidget(line, rowID, 0, 1, 4); //------- use git checkbox rowID ++; QCheckBox * cbUseGit = new QCheckBox("Use Git", &dialog); cbUseGit->setChecked(true); useGit = true; layout->addWidget(cbUseGit, rowID, 1); connect(cbUseGit, &QCheckBox::clicked, this, [=](){this->useGit = cbUseGit->isChecked();}); //------- display git cleanness if( isGitExist ){ if ( !isCleanGit){ QLabel * lCleanGit = new QLabel("Git not CLEAN!!! Nothing can be done.", &dialog); lCleanGit->setStyleSheet("color: red;"); layout->addWidget(lCleanGit, rowID, 2, 1, 2); } } //------- show list of exisiting git repository rowID ++; QLabel * l4 = new QLabel("Existing Git Branches ", &dialog); l4->setAlignment(Qt::AlignCenter | Qt::AlignRight); layout->addWidget(l4, rowID, 0); QComboBox * cb = new QComboBox(&dialog); layout->addWidget(cb, rowID, 1, 1, 2); QPushButton *bnChangeBranch = new QPushButton("Change", &dialog); layout->addWidget(bnChangeBranch, rowID, 3); bnChangeBranch->setAutoDefault(false); connect(bnChangeBranch, &QPushButton::clicked, this, [=](){ this->ChangeExperiment(cb->currentText()); }); connect(bnChangeBranch, &QPushButton::clicked, &dialog, &QDialog::accept); if( isGitExist == false ){ cb->setEnabled(false); bnChangeBranch->setEnabled(false); }else{ for( int i = 0; i < branches.size(); i++){ if( i == bID ) continue; if( branches[i].contains("HEAD")) continue; if( branches[i].contains(presentBranch)) continue; cb->addItem(branches[i].remove(" ")); } if ( cb->count() == 0) { cb->setEnabled(false); cb->addItem("no other branch"); bnChangeBranch->setEnabled(false); } } connect(cbUseGit, &QCheckBox::clicked, this, [=](){ if( cb->count() > 1 ) { cb->setEnabled(cbUseGit->isChecked()); bnChangeBranch->setEnabled(cbUseGit->isChecked()); } }); //------- type existing or new experiment rowID ++; QLabel * lNewExp = new QLabel("New Exp Name ", &dialog); lNewExp->setAlignment(Qt::AlignCenter | Qt::AlignRight); layout->addWidget(lNewExp, rowID, 0); QLineEdit * newExp = new QLineEdit("type and Enter", &dialog); layout->addWidget(newExp, rowID, 1, 1, 2); //newExp->setFocus(); QPushButton *bnCreateNewExp = new QPushButton("Create", &dialog); layout->addWidget(bnCreateNewExp, rowID, 3); bnCreateNewExp->setEnabled(false); bnCreateNewExp->setAutoDefault(false); connect(newExp, &QLineEdit::textChanged, this, [=](){ newExp->setStyleSheet("color : blue;"); if( newExp->text() == "") bnCreateNewExp->setEnabled(false); }); connect(newExp, &QLineEdit::returnPressed, this, [=](){ if( newExp->text() != "") { newExp->setStyleSheet(""); bnCreateNewExp->setEnabled(true); } }); connect(bnCreateNewExp, &QPushButton::clicked, this, [=](){ this->CreateNewExperiment(newExp->text());}); connect(bnCreateNewExp, &QPushButton::clicked, &dialog, &QDialog::accept); //----- diable all possible actions if( isGitExist){ if ( !isCleanGit ){ cbUseGit->setEnabled(false); cb->setEnabled(false); bnChangeBranch->setEnabled(false); newExp->setEnabled(false); bnCreateNewExp->setEnabled(false); } } //--------- cancel rowID ++; QPushButton *bnCancel = new QPushButton("Cancel/Exit", &dialog); bnCancel->setAutoDefault(false); layout->addWidget(bnCancel, rowID, 0, 1, 4); connect(bnCancel, &QPushButton::clicked, this, [=](){this->LogMsg("Cancel New/Change/Reload Exp");}); connect(bnCancel, &QPushButton::clicked, &dialog, &QDialog::reject); layout->setRowStretch(0, 1); for( int i = 1; i < rowID; i++) layout->setRowStretch(i, 2); LoadExpNameSh(); dialog.exec(); } bool MainWindow::LoadExpNameSh(){ //this method set the analysis setting ann symbloic link to raw data //ONLY load file, not check the git if( rawDataPath == "") return false; QString settingFile = rawDataPath + "/expName.sh"; LogMsg("Loading " + settingFile + " for Experiment."); QFile file(settingFile); if( !file.open(QIODevice::Text | QIODevice::ReadOnly) ) { LogMsg("" + settingFile + " not found. Create one."); // LogMsg("Please Open the New/Change/Reload Exp"); runID = -1; elogID = 0; //bnOpenDigitizers->setEnabled(false); //leExpName->setText("no expName found."); WriteExpNameSh(); // return false; } QTextStream in(&file); QString line = in.readLine(); int count = 0; while( !line.isNull()){ int index = line.indexOf("="); QString haha = line.mid(index+1).remove(" ").remove("\""); //qDebug() << haha; switch (count){ case 0 : expName = haha; break; // case 1 : masterExpDataPath = haha; break; case 1 : runID = haha.toInt(); break; case 2 : elogID = haha.toInt(); break; } count ++; line = in.readLine(); } // rawDataPath = masterExpDataPath + "/" + expName + "/data_raw/"; // rootDataPath = masterExpDataPath + "/" + expName + "/root_data/"; // leRawDataPath->setText(rawDataPath); leExpName->setText(expName); leRunID->setText(QString::number(runID)); return true; } void MainWindow::WriteExpNameSh(){ QDir dir(rawDataPath); if( !dir.exists() ) dir.mkpath("."); //----- create the expName.sh QFile file2(rawDataPath + "/expName.sh"); file2.open(QIODevice::Text | QIODevice::WriteOnly); file2.write(("expName="+ expName + "\n").toStdString().c_str()); // file2.write(("ExpDataPath="+ masterExpDataPath + "\n").toStdString().c_str()); file2.write(("runID="+std::to_string(runID)+"\n").c_str()); file2.write(("elogID="+std::to_string(elogID)+"\n").c_str()); file2.write("#------------end of file."); file2.close(); LogMsg("Saved expName.sh to "+ rawDataPath + "/expName.sh."); } void MainWindow::CreateNewExperiment(const QString newExpName){ LogMsg("======================================"); LogMsg("Creating new Exp. : " + newExpName + ""); expName = newExpName; runID = -1; elogID = 0; CreateRawDataFolder(); WriteExpNameSh(); //@----- git must be clean //----- creat new git branch if( useGit ){ QProcess git; git.setWorkingDirectory(analysisPath); if( !isGitExist){ git.start("git", QStringList() << "init" << "-b" << newExpName); git.waitForFinished(); LogMsg("Initialzed a git repositiory with branch name " + newExpName + ""); }else{ git.start("git", QStringList() << "checkout" << "-b" << newExpName); git.waitForFinished(); LogMsg("Creat name branch : " + newExpName + ""); } } //----- create git branch if( useGit ){ QProcess git; git.setWorkingDirectory(analysisPath); git.start("git", QStringList() << "add" << "-A"); git.waitForFinished(); git.start("git", QStringList() << "commit" << "--allow-empty" << "-m" << "initial commit."); git.waitForFinished(); LogMsg("Commit branch : " + expName + " as \"initial commit\""); //check if remote exist, if exist, push to remote git.start("git", QStringList() << "remote" ); git.waitForFinished(); QString haha = QString::fromLocal8Bit(git.readAllStandardOutput()); if( haha != ""){ git.start("git", QStringList() << "push" << "--set-upstream" << haha.remove('\n') << expName); git.waitForFinished(); qDebug() << QString::fromLocal8Bit(git.readAllStandardOutput()); LogMsg("Pushed new branch : " + expName + " to remote repositiory."); } } //TODO is there anyway to create a new elog ?? direct edit the config.cfg?? //CheckElog(); logMsgHTMLMode = true; LogMsg(" !!!! Please Create a new Elog with name " + newExpName + ". "); expDataPath = masterExpDataPath + "/" + newExpName; rawDataPath = expDataPath + "/data_raw/"; rootDataPath = expDataPath + "/root_data/"; CreateRawDataFolder(); CreateDataSymbolicLink(); leRawDataPath->setText(rawDataPath); leExpName->setText(expName); leRunID->setText(QString::number(runID)); SaveProgramSettings(); bnOpenDigitizers->setEnabled(true); bnOpenDigitizers->setStyleSheet("color:red;"); if( influx ){ influx->ClearDataPointsBuffer(); startComment = "New experiment [" + expName + "] was created."; influx->AddDataPoint("RunID,start=0 value=" + std::to_string(runID) + ",expName=\"" + expName.toStdString() + "\",comment=\"" + startComment.replace(' ', '_').toStdString() + "\""); influx->WriteData(DatabaseName.toStdString()); } } void MainWindow::ChangeExperiment(const QString newExpName){ expName = newExpName; if( newExpName.contains("remotes")){ QStringList haha = newExpName.split('/'); expName = haha.last(); } //@---- git must exist. QProcess git; git.setWorkingDirectory(analysisPath); git.start("git", QStringList() << "checkout" << expName); git.waitForFinished(); LogMsg("============================================="); LogMsg("Swicted to branch : " + expName + ""); CreateRawDataFolder(); LoadExpNameSh(); if( influx ){ influx->ClearDataPointsBuffer(); startComment = "Switched to experiment [" + expName + "]."; influx->AddDataPoint("RunID,start=0 value=" + std::to_string(runID) + ",expName=\"" + expName.toStdString() + "\",comment=\"" + startComment.replace(' ', '_').toStdString() + "\""); influx->WriteData(DatabaseName.toStdString()); } } void MainWindow::CreateRawDataFolder(){ //----- create data folder QDir dir(rawDataPath); if( !dir.exists()){ if( dir.mkdir(rawDataPath)){ LogMsg("Created folder " + rawDataPath + " for storing raw data." ); }else{ LogMsg("" + rawDataPath + " cannot be created. Access right problem? " ); } }else{ LogMsg("" + rawDataPath + " already exist." ); } //----- create root data folder QDir rootDir(rootDataPath); if( !rootDir.exists()) { if( rootDir.mkdir(rootDataPath) ){ LogMsg("Created folder " + rootDataPath + " for storing root files."); }else{ LogMsg("" + rootDataPath + " cannot be created. Access right problem? " ); } }else{ LogMsg("" + rootDataPath + " already exist." ); } //----- create analysis Folder QDir anaDir; if( !anaDir.exists(analysisPath)){ if( anaDir.mkdir(analysisPath)){ LogMsg("" + analysisPath + " created." ); }else{ LogMsg("" + analysisPath + " cannot be created. Access right problem?" ); } }else{ LogMsg("" + analysisPath + " already exist."); } } void MainWindow::CreateDataSymbolicLink(){ QString linkName = analysisPath + "/data_raw"; QFile file; if( file.exists(linkName)) { file.remove(linkName); LogMsg("removing existing Link"); } if (file.link(rawDataPath, linkName)) { LogMsg("Symbolic link " + linkName +" -> " + rawDataPath + " created."); } else { LogMsg("Symbolic link " + linkName +" -> " + rawDataPath + " cannot be created. "); } linkName = analysisPath + "/root_data"; if( file.exists(linkName)) { file.remove(linkName); LogMsg("removing existing Link"); } if (file.link(rootDataPath, linkName)) { LogMsg("Symbolic link " + linkName +" -> " + rootDataPath + " created."); } else { LogMsg("Symbolic link " + linkName +" -> " + rootDataPath + " cannot be created. "); } } //*###################################################################### //*###################################################################### log msg and others void MainWindow::LogMsg(QString msg){ QString outputStr = QStringLiteral("[%1] %2").arg(QDateTime::currentDateTime().toString("MM.dd hh:mm:ss"), msg); if( logMsgHTMLMode ){ logInfo->appendHtml(outputStr); }else{ logInfo->appendPlainText(outputStr); } QScrollBar *v = logInfo->verticalScrollBar(); v->setValue(v->maximum()); //qDebug() << msg; logInfo->repaint(); } void MainWindow::SetupInflux(){ if( influx ) { delete influx; influx = NULL; } if( DatabaseIP.isEmpty() || DatabaseName.isEmpty() ){ LogMsg("No Database IP or Name. No database will be used."); return; } if( DatabaseIP != ""){ influx = new InfluxDB(DatabaseIP.toStdString(), false); if( influx->TestingConnection() ){ LogMsg(" InfluxDB URL ("+ DatabaseIP + ") is Valid "); //==== chck database exist LogMsg("List of database:"); std::vector databaseList = influx->GetDatabaseList(); bool foundDatabase = false; for( int i = 0; i < (int) databaseList.size(); i++){ if( databaseList[i] == DatabaseName.toStdString() ) foundDatabase = true; LogMsg(QString::number(i) + "|" + QString::fromStdString(databaseList[i])); } if( foundDatabase ){ LogMsg(" Database " + DatabaseName + " found."); influx->AddDataPoint("ProgramStart value=1"); influx->WriteData(DatabaseName.toStdString()); influx->ClearDataPointsBuffer(); if( influx->IsWriteOK() ){ LogMsg("test write database OK."); }else{ LogMsg("test write database FAIL."); } }else{ LogMsg(" Database " + DatabaseName + " NOT found."); delete influx; influx = NULL; } }else{ LogMsg(" InfluxDB URL ("+ DatabaseIP + ") is NOT Valid "); delete influx; influx = NULL; } }else{ LogMsg("No database is provided."); } } void MainWindow::CheckElog(){ if( ElogIP.isEmpty() ) { LogMsg("No Elog IP. No elog will be used."); elogID = -1; return; } WriteElog("Checking elog writing", "Testing communication", "checking"); if( elogID > 0 ){ LogMsg("Checked Elog writing. OK."); AppendElog("Check Elog append.", -1); if( elogID > 0 ){ LogMsg("Checked Elog Append. OK."); }else{ LogMsg("Checked Elog Append. FAIL. (no elog will be used.) "); } }else{ LogMsg("Checked Elog Write. FAIL. (no elog will be used.) (probably logbook " + expName + " does not exist) "); } } void MainWindow::WriteElog(QString htmlText, QString subject, QString category, int runNumber){ //if( elogID < 0 ) return; if( expName == "" ) return; //TODO ===== user name and pwd load from a file. QStringList arg; arg << "-h" << ElogIP << "-p" << "8080" << "-l" << expName << "-u" << "GeneralSOLARIS" << "solaris" << "-a" << "Author=\'General SOLARIS\'" ; if( runNumber > 0 ) arg << "-a" << "RunNo=" + QString::number(runNumber); if( category != "" ) arg << "-a" << "Category=" + category; arg << "-a" << "Subject=" + subject << "-n " << "2" << htmlText ; QProcess elogBash(this); elogBash.start("elog", arg); elogBash.waitForFinished(); QString output = QString::fromUtf8(elogBash.readAllStandardOutput()); int index = output.indexOf("ID="); if( index != -1 ){ elogID = output.mid(index+3).toInt(); }else{ elogID = -1; } } void MainWindow::AppendElog(QString appendHtmlText, int screenID){ if( elogID < 1 ) return; if( expName == "" ) return; QProcess elogBash(this); QStringList arg; arg << "-h" << ElogIP << "-p" << "8080" << "-l" << expName << "-u" << "GeneralSOLARIS" << "solaris" << "-w" << QString::number(elogID); //retrevie the elog elogBash.start("elog", arg); elogBash.waitForFinished(); QString output = QString::fromUtf8(elogBash.readAllStandardOutput()); //qDebug() << output; QString separator = "========================================"; int index = output.indexOf(separator); if( index != -1){ QString originalHtml = output.mid(index + separator.length()); arg.clear(); arg << "-h" << ElogIP << "-p" << "8080" << "-l" << expName << "-u" << "GeneralSOLARIS" << "solaris" << "-e" << QString::number(elogID) << "-n" << "2" << originalHtml + "
" + appendHtmlText; if( screenID >= 0) { //TODO =========== chrome windowID QScreen * screen = QGuiApplication::primaryScreen(); if( screen){ QPixmap screenshot = screen->grabWindow(screenID); screenshot.save("screenshot.png"); arg << "-f" << "screenshot.png"; } } //TODO ========= add elog bash script to tell mac, capture screenshot and send it back. elogBash.start("elog", arg); elogBash.waitForFinished(); output = QString::fromUtf8(elogBash.readAllStandardOutput()); index = output.indexOf("ID="); if( index != -1 ){ elogID = output.mid(index+3).toInt(); }else{ elogID = -1; } }else{ elogID = -1; } } void MainWindow::WriteRunTimeStampDat(bool isStartRun, QString timeStr){ QFile file(masterExpDataPath + "/" + expName + "/data_raw/RunTimeStamp.dat"); if( file.open(QIODevice::Text | QIODevice::WriteOnly | QIODevice::Append) ){ if( isStartRun ){ file.write(("Start Run | " + QString::number(runID) + " | " + timeStr + " | " + startComment + "\n").toStdString().c_str()); }else{ file.write((" Stop Run | " + QString::number(runID) + " | " + timeStr + " | " + stopComment + "\n").toStdString().c_str()); } file.close(); } QFile fileCSV(masterExpDataPath + "/" + expName + "/data_raw/RunTimeStamp.csv"); if( fileCSV.open(QIODevice::Text | QIODevice::WriteOnly | QIODevice::Append) ){ QTextStream out(&fileCSV); if( isStartRun){ out << QString::number(runID) + "," + timeStr + "," + startComment; }else{ out << "," + timeStr + "," + stopComment + "\n"; } fileCSV.close(); } } void MainWindow::AppendComment(){ //if Started ACQ, append Comment, if ACQ stopped, disbale if( !chkSaveRun->isChecked() ) return; QDialog * dOpen = new QDialog(this); dOpen->setWindowTitle("Append Run Comment"); dOpen->setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint); dOpen->setMinimumWidth(600); connect(dOpen, &QDialog::finished, dOpen, &QDialog::deleteLater); QGridLayout * vlayout = new QGridLayout(dOpen); QLabel *label = new QLabel("Enter Append Run comment for Run-" + runIDStr + " : ", dOpen); QLineEdit *lineEdit = new QLineEdit(dOpen); QPushButton *button1 = new QPushButton("OK", dOpen); QPushButton *button2 = new QPushButton("Cancel", dOpen); vlayout->addWidget(label, 0, 0, 1, 2); vlayout->addWidget(lineEdit, 1, 0, 1, 2); vlayout->addWidget(button1, 2, 0); vlayout->addWidget(button2, 2, 1); connect(button1, &QPushButton::clicked, dOpen, &QDialog::accept); connect(button2, &QPushButton::clicked, dOpen, &QDialog::reject); int result = dOpen->exec(); if(result == QDialog::Accepted ){ appendComment = lineEdit->text(); if( appendComment == "") return; appendComment = QDateTime::currentDateTime().toString("[MM.dd hh:mm:ss]") + appendComment; AppendElog(appendComment); leRunComment->setText("Append Comment: " + appendComment); if( influx ){ influx->ClearDataPointsBuffer(); influx->AddDataPoint("RunID,start=1 value=" + std::to_string(runID) + ",expName=\"" + expName.toStdString()+ + "\",comment=\"" + appendComment.replace(' ', '_').toStdString() + "\""); influx->WriteData(DatabaseName.toStdString()); } }else{ return; } }