diff --git a/.gitignore b/.gitignore index c5f2117..151c139 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ SOLARIS_DAQ *.sol programSettings.txt test +windowID +screenshot.* *~ *.autosave diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index fec381b..2e598e1 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -5,7 +5,7 @@ "includePath": [ "${workspaceFolder}/**", "/usr/include/x86_64-linux-gnu/qt6/**", - "/opt/root/include/*" + "/opt/root/include/**" ], "defines": [], "compilerPath": "/usr/bin/gcc", diff --git a/SOLARIS_Qt6_DAQ.pro b/SOLARIS_Qt6_DAQ.pro index 0f4bdc0..7b5f96d 100644 --- a/SOLARIS_Qt6_DAQ.pro +++ b/SOLARIS_Qt6_DAQ.pro @@ -8,7 +8,7 @@ INCLUDEPATH += . QT += widgets charts -LIBS += -lcurl -lCAEN_FELib +LIBS += -lcurl -lCAEN_FELib -lX11 # You can make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. diff --git a/mainwindow.cpp b/mainwindow.cpp index 622dec2..9e18651 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -15,6 +15,11 @@ #include #include #include +#include +#include + +#include +#include #include @@ -33,6 +38,8 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ influx = NULL; readDataThread = NULL; scope = NULL; + runTimer = new QTimer(); + connect(runTimer, &QTimer::timeout, this, &MainWindow::AutoRun); { scalar = new QMainWindow(this); @@ -69,10 +76,10 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ QGridLayout * layout1 = new QGridLayout(box1); bnProgramSettings = new QPushButton("Program Settings", this); - connect(bnProgramSettings, &QPushButton::clicked, this, &MainWindow::ProgramSettings); + connect(bnProgramSettings, &QPushButton::clicked, this, &MainWindow::ProgramSettingsPanel); bnNewExp = new QPushButton("New/Change/Reload Exp", this); - connect(bnNewExp, &QPushButton::clicked, this, &MainWindow::SetupNewExp); + connect(bnNewExp, &QPushButton::clicked, this, &MainWindow::SetupNewExpPanel); QLabel * lExpName = new QLabel("Exp Name ", this); lExpName->setAlignment(Qt::AlignRight | Qt::AlignCenter); @@ -107,10 +114,10 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ layout1->addWidget(lExpName, 0, 2); layout1->addWidget(leExpName, 0, 3); - layout1->addWidget(bnOpenScope, 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); @@ -152,12 +159,17 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ chkSaveRun->setEnabled(false); cbAutoRun = new QComboBox(this); - cbAutoRun->addItem("Single Run"); - cbAutoRun->addItem("Auto 30 mins"); - cbAutoRun->addItem("Auto 60 mins"); - cbAutoRun->addItem("Auto 2 hrs"); - cbAutoRun->addItem("Auto 3 hrs"); - cbAutoRun->addItem("Auto 5 hrs"); + cbAutoRun->addItem("Single infinte", -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 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); bnStartACQ = new QPushButton("Start ACQ", this); @@ -218,7 +230,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ LogMsg("Welcome to SOLARIS DAQ."); - if( OpenProgramSettings() ) OpenExpSettings(); + if( LoadProgramSettings() ) LoadExpSettings(); } @@ -233,8 +245,10 @@ MainWindow::~MainWindow(){ //delete logInfo; printf("- %s\n", __func__); - for( int i = 0; i < nDigi ; i++){ - if( readDataThread[i]->isRunning()) StopACQ(); + if( digi ){ + for( int i = 0; i < nDigi ; i++){ + if( readDataThread[i]->isRunning()) StopACQ(); + } } DeleteTriggerLineEdit(); @@ -257,35 +271,37 @@ void MainWindow::StartACQ(){ LogMsg("=========================== Start Run-" + runIDStr + ""); //============ start comment - 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); + //if( cbAutoRun->currentData().toInt() > 0 ){ + 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); + 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); + 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(); + 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."; - leRunComment->setText(startComment); - }else{ - LogMsg("Start Run aborted. "); - return; - } + if(result == QDialog::Accepted ){ + startComment = lineEdit->text(); + if( startComment == "") startComment = "No commet was typed."; + leRunComment->setText(startComment); + }else{ + LogMsg("Start Run aborted. "); + return; + } + //} //TODO ============ elog //TODO ============ update expName.sh @@ -293,6 +309,8 @@ void MainWindow::StartACQ(){ }else{ LogMsg("=========================== Start no-save Run"); } + + //============================= start digitizer for( int i =0 ; i < nDigi; i ++){ if( digi[i]->IsDummy () ) continue; digi[i]->Reset(); @@ -320,6 +338,13 @@ void MainWindow::StartACQ(){ bnStopACQ->setEnabled(true); bnOpenScope->setEnabled(false); chkSaveRun->setEnabled(false); + cbAutoRun->setEnabled(false); + + //TODO ======= Auto Run + if( cbAutoRun->currentIndex() > 0 ){ + int timeMinite = cbAutoRun->currentData().toInt(); + runTimer->start(timeMinite * 60 * 1000); // unit is msec + } } @@ -358,6 +383,10 @@ void MainWindow::StopACQ(){ } } + //TODO ======= Stop the Auto Run + runTimer->stop(); + + //=============== Stop digitizer for( int i = 0; i < nDigi; i++){ if( digi[i]->IsDummy () ) continue; digi[i]->StopACQ(); @@ -394,6 +423,17 @@ void MainWindow::StopACQ(){ } +void MainWindow::AutoRun(){ + + if( cbAutoRun->currentData().toInt() > 0 ){ + //---- stop run + + }else{ + //----- stop run and start a new run + } + +} + //^###################################################################### open and close digitizer void MainWindow::OpenDigitizers(){ @@ -418,6 +458,8 @@ void MainWindow::OpenDigitizers(){ chkSaveRun->setEnabled(true); bnOpenDigitizers->setEnabled(false); bnOpenDigitizers->setStyleSheet(""); + //cbAutoRun->setEnabled(true); + cbAutoRun->setEnabled(false); readDataThread[i] = new ReadDataThread(digi[i], this); connect(readDataThread[i], &ReadDataThread::sendMsg, this, &MainWindow::LogMsg); @@ -467,13 +509,15 @@ void MainWindow::CloseDigitizers(){ bnOpenDigitizers->setEnabled(true); + bnOpenDigitizers->setFocus(); bnCloseDigitizers->setEnabled(false); bnDigiSettings->setEnabled(false); bnStartACQ->setEnabled(false); bnStopACQ->setEnabled(false); - bnOpenDigitizers->setFocus(); + bnOpenScope->setEnabled(false); bnOpenScalar->setEnabled(false); chkSaveRun->setEnabled(false); + cbAutoRun->setEnabled(false); } @@ -484,7 +528,7 @@ void MainWindow::OpenScope(){ 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::UpdateScalar, this, &MainWindow::UpdateScalar); connect(scope, &Scope::SendLogMsg, this, &MainWindow::LogMsg); }else{ scope->show(); @@ -645,7 +689,7 @@ void MainWindow::UpdateScalar(){ } //^###################################################################### Program Settings -void MainWindow::ProgramSettings(){ +void MainWindow::ProgramSettingsPanel(){ LogMsg("Open Program Settings."); @@ -772,7 +816,7 @@ void MainWindow::OpenDirectory(int id){ } } -bool MainWindow::OpenProgramSettings(){ +bool MainWindow::LoadProgramSettings(){ QString settingFile = QDir::current().absolutePath() + "/programSettings.txt"; @@ -898,6 +942,27 @@ void MainWindow::SetupInflux(){ } } +void MainWindow::CheckElog(){ + + WriteElog("Checking elog writing", "checking", "Testing communication"); + + if( elogID > 0 ){ + LogMsg("Ckecked Elog writing. OK."); + + //TODO =========== chrome windowID + AppendElog("Check Elog append.", 10485763); + if( elogID > 0 ){ + LogMsg("Checked Elog Append. OK."); + }else{ + LogMsg("Checked Elog Append. FAIL. (no elog will be used.)"); + } + + }else{ + LogMsg("Ckecked Elog writing. FAIL. (no elog will be used.)"); + } + +} + void MainWindow::SaveProgramSettings(){ IPListStr = lIPDomain->text(); @@ -932,13 +997,13 @@ void MainWindow::SaveProgramSettings(){ DecodeIPList(); SetupInflux(); - OpenExpSettings(); + LoadExpSettings(); } //^###################################################################### Setup new exp -void MainWindow::SetupNewExp(){ +void MainWindow::SetupNewExpPanel(){ LogMsg("Open New/Change/Reload Exp."); @@ -1163,13 +1228,13 @@ void MainWindow::SetupNewExp(){ layout->setRowStretch(0, 1); for( int i = 1; i < rowID; i++) layout->setRowStretch(i, 2); - OpenExpSettings(); + LoadExpSettings(); dialog.exec(); } -bool MainWindow::OpenExpSettings(){ +bool MainWindow::LoadExpSettings(){ //this method set the analysis setting ann symbloic link to raw data //ONLY load file, not check the git @@ -1219,6 +1284,8 @@ bool MainWindow::OpenExpSettings(){ bnOpenDigitizers->setStyleSheet("color:red;"); + CheckElog(); + return true; } @@ -1300,7 +1367,7 @@ void MainWindow::ChangeExperiment(const QString newExpName){ CreateRawDataFolderAndLink(newExpName); - OpenExpSettings(); + LoadExpSettings(); } @@ -1348,3 +1415,86 @@ void MainWindow::LogMsg(QString msg){ //qDebug() << msg; logInfo->repaint(); } + +void MainWindow::WriteElog(QString htmlText, QString category, QString subject){ + + if( elogID < 0 ) return; + if( expName == "" ) return; + + QStringList arg; + arg << "-h" << ElogIP << "-p" << "8080" << "-l" << expName << "-u" << "GeneralFSU" << "fsuphysics-888" + << "-a" << "Author=GeneralFSU" << "-a" << "Category=" + category + << "-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" << "GeneralFSU" << "fsuphysics-888" << "-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" << "GeneralFSU" << "fsuphysics-888" << "-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"; + } + } + + 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; + } + +} + diff --git a/mainwindow.h b/mainwindow.h index ee291b4..6a0dd37 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -18,6 +19,7 @@ #include #include // time in nano-sec + #include "ClassDigitizer2Gen.h" #include "influxdb.h" @@ -43,20 +45,23 @@ private slots: void OpenScope(); void OpenDigitizersSettings(); + void AutoRun(); + void OpenScaler(); void SetUpScalar(); void DeleteTriggerLineEdit(); void UpdateScalar(); - void ProgramSettings(); - bool OpenProgramSettings(); + void ProgramSettingsPanel(); + bool LoadProgramSettings(); void SaveProgramSettings(); void DecodeIPList(); void SetupInflux(); + void CheckElog(); void OpenDirectory(int id); - void SetupNewExp(); - bool OpenExpSettings(); + void SetupNewExpPanel(); + bool LoadExpSettings(); void CreateNewExperiment(const QString newExpName); void ChangeExperiment(const QString newExpName); void CreateRawDataFolderAndLink(const QString newExpName); @@ -67,6 +72,8 @@ private slots: event->accept(); } + void WriteElog(QString htmlText, QString category = "", QString subject = ""); + void AppendElog(QString appendHtmlText, int screenID = -1); signals : @@ -146,7 +153,11 @@ private: QString rawDataFolder; unsigned int runID; QString runIDStr; - unsigned int elogID; + int elogID; // 0 = ready, -1 = disable, >1 = elogID + + QTimer * runTimer; + unsigned int autoRunStartRunID; + }; diff --git a/makeTest.sh b/makeTest.sh old mode 100644 new mode 100755 index 13309ee..3915f5f --- a/makeTest.sh +++ b/makeTest.sh @@ -22,7 +22,11 @@ OBJS="ClassDigitizer2Gen.o influxdb.o" - +echo "------- influxdb.o" ${CC} ${COPTS} -c influxdb.cpp ${CURLLIBS} +echo "------- ClassDigitizer2Gen.o" ${CC} ${COPTS} -c ClassDigitizer2Gen.cpp ${CAENLIBS} -${CC} ${COPTS} ${OBJS} -o test test.cpp ${CAENLIBS} ${CURLLIBS} \ No newline at end of file +echo "------- test" +${CC} ${COPTS} ${OBJS} -o test test.cpp ${CAENLIBS} ${CURLLIBS} +echo "------- windowID" +${CC} ${COPTS} -o windowID windowID.cpp -lX11 -lpng diff --git a/manyThread.h b/manyThread.h index 465f7c9..ce8fcb9 100644 --- a/manyThread.h +++ b/manyThread.h @@ -63,6 +63,8 @@ public: waitTime = 2; stop = false; } + unsigned int GetWaitTimeSec() const {return waitTime;} + void SetWaitTimeSec(unsigned sec) {waitTime = sec;} void Stop() {this->stop = true;} void run(){ unsigned int count = 0; diff --git a/scope.cpp b/scope.cpp index f9a3170..c9fae0c 100644 --- a/scope.cpp +++ b/scope.cpp @@ -327,7 +327,11 @@ Scope::Scope(Digitizer2Gen **digi, unsigned int nDigi, ReadDataThread ** readDat //------------- Ketbinding rowID ++; QLabel * lbhints = new QLabel("Type 'r' to restore view.", this); - layout->addWidget(lbhints, rowID, 0, 1, 4); + layout->addWidget(lbhints, rowID, 0, 1, 3); + + QLabel * lbinfo = new QLabel("Trace update every " + QString::number(updateTraceThread->GetWaitTimeSec()) + " sec.", this); + lbinfo->setAlignment(Qt::AlignRight); + layout->addWidget(lbinfo, rowID, 5); //------------ close button rowID ++; diff --git a/windowID.cpp b/windowID.cpp new file mode 100644 index 0000000..2a9d624 --- /dev/null +++ b/windowID.cpp @@ -0,0 +1,94 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +void saveScreenshot(Display* display, const Window window, const char* filename){ + + XWindowAttributes attrs; + XGetWindowAttributes(display, window, &attrs); + + printf("(x,y) :(%d, %d), (w,h) : (%d, %d) \n", attrs.x, attrs.y, attrs.width, attrs.height); + + int window_width = attrs.width; + int window_height = attrs.height; + + XImage *image = XGetImage(display, window, 0, 0, window_width, window_height, AllPlanes, ZPixmap); + + png_bytep *row_pointers = new png_bytep[window_height]; + for (int i = 0; i < window_height; i++) { + row_pointers[i] = (png_bytep)(image->data + i * image->bytes_per_line); + } + + FILE *png_file = fopen(filename, "w"); + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + png_infop info_ptr = png_create_info_struct(png_ptr); + png_init_io(png_ptr, png_file); + png_set_IHDR(png_ptr, info_ptr, window_width, window_height, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + png_write_info(png_ptr, info_ptr); + png_write_image(png_ptr, row_pointers); + png_write_end(png_ptr, NULL); + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(png_file); + + XFree(image->data); + +} + +int main(int argc, char* argv[]){ + + Window screenID; + if( argc > 1){ + screenID = atoi(argv[1]); + } + + // Connect to the X server + Display *display = XOpenDisplay(nullptr); + + //============== show all windows ID + Window root = DefaultRootWindow(display); + + Window parent; + Window *children; + unsigned int numChildren; + Status status = XQueryTree(display, root, &root, &parent, &children, &numChildren); + + if (!status) { + std::cerr << "Failed to query window tree\n"; + return 1; + } + + for (unsigned int i = 0; i < numChildren; i++) { + XTextProperty windowName; + status = XGetWMName(display, children[i], &windowName); + if( i == 0 ) { + printf("%12s | %12s \n", "Window ID", "Name"); + printf("--------------+--------------------------------\n"); + } + if (status) { + char **list; + int count; + status = XmbTextPropertyToTextList(display, &windowName, &list, &count); + if (status >= Success && count > 0 && *list) { + printf("%12ld | %s \n", children[i], *list); + //std::cout << "Window ID: " << children[i] << ", Window Name: " << *list << "\n"; + XFreeStringList(list); + } + XFree(windowName.value); + } + } + XFree(children); + //================ end of show windows ID + + if( argc >1 ){ + saveScreenshot(display, screenID, "screenshot.png"); + printf("captured screenshot of windowID(%ld) as screenshot.png\n", screenID); + } + // Close the display connection + XCloseDisplay(display); + return 0; +} \ No newline at end of file