/* ============================================================ Edd - Evidence Data Display Qt-based graphical user interface for the Evidence contron system EddLineDisplay changes its background colour in case it display a DIM status service ============================================================ */ #include "Edd.h" QString DRSBoard = "FADctrl"; std::string PixelMapText; extern class EddDim *Handler; //////////////////////// // Event oscilloscope // //////////////////////// // Constructor EventScope::EventScope(QWidget *P): EddBasePlot(P), PixelMap(PixelMapText, false) { Name = DRSBoard+"/EventData"; Tmpfile = tmpfile(); if(Tmpfile == NULL) { QMessageBox::warning(this, "Edd Message", "Could not open temporary file.", QMessageBox::Ok); } // Open file with RawDataCTX RD = new RawDataCTX(true); ErrCode = CTX_NOTOPEN; // Context menu PhysPipeAction = new QAction("Physical pipeline", this); PhysPipeAction->setCheckable(true); connect(PhysPipeAction, SIGNAL(triggered()), SLOT(PlotTraces())); Menu->insertAction(StripAction, PhysPipeAction); PersistanceAction = new QAction("Persistance", this); PersistanceAction->setCheckable(true); Menu->insertAction(StripAction, PersistanceAction); Menu->removeAction(StripAction); // Initial trace AddTrace(0,0,0); // Connect to DIM handler if (connect(Handler, SIGNAL(YEP(QString, int, QByteArray, QString, QString)), SLOT(Update(QString, int, QByteArray, QString, QString))) == false) { printf("Failed connection for %s\n", Name.toAscii().data()); } SetActive(true); } // Destructor (items with parent widget are automatically deleted) EventScope::~EventScope() { SetActive(false); while (!List.isEmpty()) DeleteCurve(List.last().Signal); delete RD; if (Tmpfile != NULL) fclose(Tmpfile); } // Add trace void EventScope::AddTrace(int Board, int Chip, int Channel) { struct ItemDetails N; N.Signal = NewCurve(QString::number(Board)+","+QString::number(Chip)+","+ QString::number(Channel)+ " (" + ToPixel(0, Board, Chip, Channel) + ")"); N.Board = Board; N.Chip = Chip; N.Channel = Channel; N.Trigger = new QwtPlotMarker(); N.Trigger->setSymbol(QwtSymbol(QwtSymbol::Diamond, QBrush(N.Signal->pen().color()), N.Signal->pen(), QSize(10,10))); N.Trigger->attach(this); if (List.isEmpty()) { QPen Pen = N.Signal->pen(); Pen.setWidth(2); N.Signal->setPen(Pen); } List.append(N); PlotTraces(); } // Update last trace (to reflect current setting of spin boxes in DAQ page) void EventScope::UpdateFirst(int Board, int Chip, int Channel) { if (List.isEmpty()) return; // Clear in case persistance was activated ClearCurve(0); List.first().Signal->setTitle(QString::number(Board)+","+QString::number(Chip)+","+ QString::number(Channel) + " (" + ToPixel(0, Board, Chip, Channel) + ")"); List.first().Board = Board; List.first().Chip = Chip; List.first().Channel = Channel; PlotTraces(); } // Update event buffer void EventScope::Update(QString Name, int Time, QByteArray Data, QString Format, QString) { if (Name != this->Name) return; // Check if service available if (!SetStatus(this, Name, Time, Format)) return; if (Data.size() < (int) sizeof(RunHeader)) return; // Disconnect while processing to avoid queing of events disconnect(Handler, SIGNAL(YEP(QString, int, QByteArray, QString, QString)), this, SLOT(Update(QString, int, QByteArray, QString, QString))); // Open tempory file and write event data to this file QTemporaryFile File; if (!File.open()) { QMessageBox::warning(this, "Edd Message","Could not open temporary file.",QMessageBox::Ok); return; } if (File.write(Data) == -1) { QMessageBox::warning(this, "Edd Message","Could not write data to temporary file.",QMessageBox::Ok); return; } // Prepare temporary file for run header ftruncate(fileno(Tmpfile), 0); rewind(Tmpfile); // Open file with RawDataCTX switch (ErrCode = RD->OpenDataFile(File.fileName().toAscii().data(), Tmpfile)) { case CTX_FOPEN: QMessageBox::warning(this, "Edd Message","Could not open file.",QMessageBox::Ok); return; case CTX_RHEADER: QMessageBox::warning(this, "Edd Message","Could not read run header.",QMessageBox::Ok); return; case CTX_BSTRUCT: QMessageBox::warning(this, "Edd Message","Could not read board structures.",QMessageBox::Ok); return; default: break; } // Emit signal containing run header rewind(Tmpfile); QTextStream Stream(Tmpfile); emit(RunHeaderChanged(Stream.readAll())); // Prepare temporary file for event header ftruncate(fileno(Tmpfile), 0); rewind(Tmpfile); // Write event header text to file if (RD->ReadEvent(0, Tmpfile) != CTX_OK) { QMessageBox::warning(this, "Edd Warning","Could not read event.",QMessageBox::Ok); return; } // Add trigger cells to file fprintf(Tmpfile, "\nTrigger cells:"); int *TrigCells = (int *) RD->Data; for (unsigned int i=0; iRHeader->NBoards; i++) { fprintf(Tmpfile, "\n Board %d ", i); for (unsigned int j=0; jRHeader->NChips; j++) fprintf(Tmpfile, "%d ", *(TrigCells++)); } // Emit signal containing run header rewind(Tmpfile); emit(EventHeaderChanged(Stream.readAll())); // Update display PlotTraces(); // Reconnect after processing connect(Handler, SIGNAL(YEP(QString, int, QByteArray, QString, QString)), SLOT(Update(QString, int, QByteArray, QString, QString))); } // Update curves void EventScope::PlotTraces() { double x,y; unsigned int Cell, Trig; static int Last = 0; // Only process if valid data in RawDataCTX class if (ErrCode != CTX_OK) return; // Set x axis title if (PhysPipeAction->isChecked()) setAxisTitle(QwtPlot::xBottom, "Time from start of pipeline (ns)"); else setAxisTitle(QwtPlot::xBottom, "Time from trigger minus one revolution (ns)"); // Loop through event data to update event scope RunHeader *R = RD->RHeader; for (int i=0; iisChecked()) List[i].Signal->setStyle(QwtPlotCurve::Dots); else { ClearCurve(i); List[i].Signal->setStyle(QwtPlotCurve::Lines); } // Check if current event contains requested trace if (List[i].Board>=R->NBoards || List[i].Chip>=R->NChips || List[i].Channel>=R->NChannels) continue; // Set trigger marker visibility List[i].Trigger->setVisible(PhysPipeAction->isChecked()); // Determine trigger cell Trig = *((int *) RD->Data + List[i].Board*R->NChips + List[i].Chip); // Calulate point of curve for (unsigned int j=0; jSamples; j++) { if (PhysPipeAction->isChecked()) Cell = (j - Trig) % 1024; else Cell = j; x = j / RD->BStruct[List[i].Board].NomFreq; y = *((short *) (RD->Data + R->NBoards*R->NChips*sizeof(int)) + List[i].Board*R->NChips*R->NChannels*R->Samples + List[i].Chip*R->NChannels*R->Samples + List[i].Channel*R->Samples + Cell) * RD->BStruct[List[i].Board].ScaleFactor; AddPoint(i, x, y); // Set trigger point indicator if (Trig == j) List[i].Trigger->setValue(x, y); } } // Limit update rate in persistance mode if (!PersistanceAction->isChecked() || time(NULL) > Last) { UpdatePlot(); Last = time(NULL); } // Loop through event data for pixel display QVector Pixel(R->NBoards*R->NChips*R->NChannels); int Count = 0; for (unsigned int Board=0; BoardNBoards; Board++) { for (unsigned int Chip=0; ChipNChips; Chip++) { for (unsigned int Channel=0; ChannelNChannels; Channel++) { Pixel[Count] = DBL_MIN; for (unsigned int i=0; iSamples; i++) { y = *((short *) (RD->Data + R->NBoards*R->NChips*sizeof(int)) + Board*R->NChips*R->NChannels*R->Samples + Chip*R->NChannels*R->Samples + Channel*R->Samples + i) * RD->BStruct[Board].ScaleFactor; if (y > Pixel[Count]) Pixel[Count] = y; } Count++; }}} emit(PixelData(Pixel)); } // Remove list entry void EventScope::DeleteCurve(QwtPlotCurve *Curve) { for (int i=0; iSubscribe(DRSBoard+"/EventData"); if (!State && Active) Handler->Unsubscribe(DRSBoard+"/EventData"); Active = State; } // Translate FPA ID to Pixel ID (use '-' instead of PM_ERROR_CODE) QString EventScope::ToPixel(unsigned int Crate, unsigned int Board, unsigned int Patch, unsigned int Pixel) { if (FPA_to_Pixel(Crate, Board, Patch, Pixel) == PM_ERROR_CODE) return "-"; else return QString::number(FPA_to_Pixel(Crate, Board, Patch, Pixel)); } //------------------------------------------------------------------ //**************************** Tab pages *************************** //------------------------------------------------------------------ // // Environment page // TP_Environment::TP_Environment() { QGridLayout *Layout = new QGridLayout(this); setAttribute(Qt::WA_DeleteOnClose); // Status display EddLineDisplay *Line = new EddLineDisplay("ARDUINO/Message"); Line->setMaximumWidth(200); Layout->addWidget(Line, 0, 0, 1, 2); // Generate plot and data displays EddPlot *Plot = new EddPlot(); for (int i=0; i<10; i++) { Line = new EddLineDisplay("ARDUINO/Data", i); Layout->addWidget(Line, i%5+1, i/5, 1, 1); Plot->AddService("ARDUINO/Data", i); } Layout->addWidget(Plot, 0, 2, 9, 7); // Night sky monitor Line = new EddLineDisplay("SQM/Message"); Line->setMaximumWidth(200); Layout->addWidget(Line, 6, 0, 1, 2); Line = new EddLineDisplay("SQM/NSB"); Layout->addWidget(Line, 7, 0, 1, 1); } // // Bias page // TP_Bias::TP_Bias() { QGridLayout *Layout = new QGridLayout(this); setAttribute(Qt::WA_DeleteOnClose); EddLineDisplay *Line; EddPlot *Plot = new EddPlot(); Plot->setMinimumWidth(400); for (int i=0; i<18; i++) { Line = new EddLineDisplay("Bias/VOLT/ID00", i+64); Layout->addWidget(Line, i%9+1, 0+i/9, 1, 1); Plot->AddService("Bias/VOLT/ID00", i+64); Line = new EddLineDisplay("Bias/VOLT/ID00", i+96); Layout->addWidget(Line, i%9+1, 2+i/9, 1, 1); Plot->AddService("Bias/VOLT/ID00",i+96); } Layout->addWidget(Plot, 0, 4, 12, 3); Line = new EddLineDisplay("Bias/Message"); Line->setMaximumWidth(200); Layout->addWidget(Line, 0, 0, 1, 3); EddCommand *Command = new EddCommand("Bias/Command"); Layout->addWidget(Command, 10, 0, 1, 4); EddText *Text = new EddText("Bias/ConsoleOut", true); Text->setFixedWidth(400); Layout->addWidget(Text, 11, 0, 4, 4); // Current page EddWindow *Button = new EddWindow("Currents", "Edd - Edd - Bias currents"); Layout->addWidget(Button, 13, 4, 1, 1); Plot = new EddPlot(); for (int i=0; i<36; i++) { Line = new EddLineDisplay("Bias/MICROAMP/ID00", i+64); Line->setMaximumWidth(60); Button->Layout()->addWidget(Line, i%9, 0+i/9, 1, 1); Plot->AddService("Bias/MICROAMP/ID00", i+64); } Button->Layout()->addWidget(Plot, 0, 4, 30, 12); } // // Feedback page // TP_Feedback::TP_Feedback() { setAttribute(Qt::WA_DeleteOnClose); QGridLayout *Layout = new QGridLayout(this); EddLineDisplay *Line; EddPlot *Plot = new EddPlot(); for (int i=0; i<36; i++) { Line = new EddLineDisplay("Feedback/Average", i); Line->setMaximumWidth(60); Layout->addWidget(Line, i%9+2, 0+i/9, 1, 1); Plot->AddService("Feedback/Average", i); } Layout->addWidget(Plot, 0, 4, 12, 10); Line = new EddLineDisplay("Feedback/Message"); Line->setMaximumWidth(200); Layout->addWidget(Line, 0, 0, 1, 2); Line = new EddLineDisplay("Feedback/State"); Line->setMaximumWidth(150); Layout->addWidget(Line, 1, 0, 1, 2); Line = new EddLineDisplay("Feedback/Count"); Line->setMaximumWidth(60); Layout->addWidget(Line, 1, 2); // Details page EddWindow *Button = new EddWindow("Details", "Edd - Feedback Details"); Layout->addWidget(Button, 12, 0, 1, 1); Plot = new EddPlot(); for (int i=0; i<36; i++) { Line = new EddLineDisplay("Feedback/Sigma", i); Line->setMaximumWidth(60); Button->Layout()->addWidget(Line, i%9, 0+i/9, 1, 1); Plot->AddService("Feedback/Sigma", i); Line = new EddLineDisplay("Feedback/Target", i); Line->setMaximumWidth(60); Button->Layout()->addWidget(Line, i%9+10, 0+i/9, 1, 1); Line = new EddLineDisplay("Feedback/Response", i); Line->setMaximumWidth(60); Button->Layout()->addWidget(Line, i%9+20, 0+i/9, 1, 1); } Button->Layout()->addWidget(Plot, 0, 4, 30, 12); } // // FADctrl page // TP_FADctrl::TP_FADctrl() { QString Board; QScrollArea *scrollArea = new QScrollArea; scrollArea->setBackgroundRole(QPalette::Dark); scrollArea->setWidget(this); setMinimumSize(QSize(0,0)); QGridLayout *Layout = new QGridLayout(this); setAttribute(Qt::WA_DeleteOnClose); EddLineDisplay *Line; Line = new EddLineDisplay("FADctrl/Message"); Line->setMaximumWidth(200); Layout->addWidget(Line, 0, 0, 1, 3); EddCommand *Command = new EddCommand("FADctrl/Command"); Layout->addWidget(Command, 1, 0, 1, 3); EddText *Text = new EddText("FADctrl/ConsoleOut", true); Text->setFixedWidth(400); Layout->addWidget(Text, 2, 0, 4, 4); EddPlot *Plot = new EddPlot(); Layout->addWidget(Plot, 2, 4, 4, 4); // Details page EddWindow *Button[2]; Button[0] = new EddWindow("Boards 0-19", "Edd - FADctrl - Board 0 to 19"); Button[1] = new EddWindow("Boards 20-39", "Edd - FADctrl - Board 20 to 39"); Layout->addWidget(Button[0], 7, 0, 1, 1); Layout->addWidget(Button[1], 7, 1, 1, 1); for (int i=0; i<40; i++) { Board = Board.sprintf("FADctrl/Board%.2d/", i); Line = new EddLineDisplay(Board+"Server"); Line->setMinimumWidth(90); Button[i/20]->Layout()->addWidget(Line, i+7, 0, 1, 1); Line = new EddLineDisplay(Board+"BoardID"); Line->setMaximumWidth(30); Button[i/20]->Layout()->addWidget(Line, i+7, 1, 1, 1); Line = new EddLineDisplay(Board+"Frequency"); Line->setMaximumWidth(40); Button[i/20]->Layout()->addWidget(Line, i+7, 2, 1, 1); for (int j=0; j<4; j++) { Plot->AddService(Board+"Temperature", j); Line = new EddLineDisplay(Board+"Temperature", j); Line->setMinimumWidth(40); Button[i/20]->Layout()->addWidget(Line, i+7, 3+j, 1, 1); } Line = new EddLineDisplay(Board+"TriggerNum"); Line->setMinimumWidth(40); Button[i/20]->Layout()->addWidget(Line, i+7, 7, 1, 1); Line = new EddLineDisplay(Board+"RateHz"); Line->setMinimumWidth(50); Button[i/20]->Layout()->addWidget(Line, i+7, 15, 1, 1); Line = new EddLineDisplay(Board+"Status"); Line->setMaximumWidth(150); Button[i/20]->Layout()->addWidget(Line, i+7, 16, 1, 1); } } // // Event scope page // TP_DAQ::TP_DAQ() { EddLineDisplay *Line; setAttribute(Qt::WA_DeleteOnClose); QGridLayout *Layout = new QGridLayout(this); // Run-related information Line = new EddLineDisplay("drsdaq/RunNumber"); Line->setMaximumWidth(100); Layout->addWidget(Line, 0, 1, 1, 1); Line = new EddLineDisplay(DRSBoard+"/EventNumber"); Line->setMaximumWidth(100); Layout->addWidget(Line, 0, 2, 1, 1); Line = new EddLineDisplay("drsdaq/RunSizeMB"); Line->setMaximumWidth(100); Layout->addWidget(Line, 0, 3, 1, 1); Line = new EddLineDisplay("drsdaq/FileSizeMB"); Line->setMaximumWidth(100); Layout->addWidget(Line, 0, 4, 1, 1); Line = new EddLineDisplay("drsdaq/FileName"); Line->setMaximumWidth(200); Layout->addWidget(Line, 0, 5, 1, 1); // Message service Line = new EddLineDisplay(DRSBoard+"/Message"); Line->setMaximumWidth(200); Layout->addWidget(Line, 1, 1, 1, 2); // Event scope Scope = new EventScope; Scope->setMinimumWidth(700); // Text boxes for run and event header RunHeaderDisplay = new QPlainTextEdit(); EventHeaderDisplay = new QPlainTextEdit(); RunHeaderDisplay->setReadOnly(true); EventHeaderDisplay->setReadOnly(true); // Tab widget QTabWidget *TabWidget = new QTabWidget(); TabWidget->addTab(Scope, "&Signals"); TabWidget->addTab(RunHeaderDisplay, "&Run Header"); TabWidget->addTab(EventHeaderDisplay, "&Event Header"); Layout->addWidget(TabWidget, 2, 1, 6, 5); // Channel number Channel = new QSpinBox; connect(Channel, SIGNAL(valueChanged(int)), SLOT(UpdateScope(int))); Channel->setToolTip("DRS channel number"); // Chip number Chip = new QSpinBox; connect(Chip, SIGNAL(valueChanged(int)), SLOT(UpdateScope(int))); Chip->setToolTip("DRS chip number"); // Board number Board = new QSpinBox; connect(Board, SIGNAL(valueChanged(int)), SLOT(UpdateScope(int))); Board->setToolTip("DRS board number"); // Pixel ID PixelID = new QSpinBox; PixelID->setMaximumWidth(60); PixelID->setRange(-1, 9999); PixelID->setSpecialValueText("n/a"); connect(PixelID, SIGNAL(valueChanged(int)), SLOT(TranslatePixelID(int))); PixelID->setToolTip("Pixel identification"); // Layout of pixel addressing widgets QFormLayout *FormLayout = new QFormLayout(); FormLayout->setRowWrapPolicy(QFormLayout::WrapAllRows); FormLayout->addRow("Board", Board); FormLayout->addRow("Chip", Chip); FormLayout->addRow("Channel", Channel); FormLayout->addRow("Pixel ID", PixelID); Layout->addLayout(FormLayout, 0, 0, 4, 1); // Add trace permanently QPushButton *Button = new QPushButton("Keep trace"); Button->setToolTip("Keep trace in display"); Button->setMaximumWidth(80); Layout->addWidget(Button, 4, 0); connect(Button, SIGNAL(clicked()), SLOT(KeepCurrent())); // Stop/start StartStopButton = new QPushButton("Stop"); StartStopButton->setToolTip("Start/stop display"); StartStopButton->setMaximumWidth(80); StartStopButton->setCheckable(true); QPalette Palette = StartStopButton->palette(); Palette.setColor(QPalette::ButtonText, Qt::blue); Palette.setColor(QPalette::Button, Qt::green); StartStopButton->setPalette(Palette); StartStopButton->setFont(QFont("Times", 10, QFont::Bold)); Layout->addWidget(StartStopButton, 6, 0); connect(StartStopButton, SIGNAL(toggled(bool)), SLOT(StartStop(bool))); // Event display page EddWindow *New = new EddWindow("Pixel display", "Edd - Event display"); New->setFont(QFont("Times", 10, QFont::Bold)); New->setMaximumWidth(80); New->setToolTip("Show event display window"); Layout->addWidget(New, 7, 0); Pixel = new QPushButton *[MAXPIXEL]; int Count = 0; double x,y; for (int ix=-22; ix<=22; ix++) for (int iy=-19; iy<=20; iy++) { if (Count == MAXPIXEL) break; x = ix*0.866; y = iy - (ix%2==0 ? 0.5:0); if ((pow(x,2)+pow(y,2) >= 395) && !(abs(ix)==22 && iy==7)) continue; //Pixel[Count] = new QPushButton(Display); Pixel[Count] = new QPushButton(New->Window()); Pixel[Count]->setAutoFillBackground(true); Pixel[Count]->setGeometry((int) (x*12.5 + 250), (int) (y*12.5 + 250), 10, 10); Pixel[Count]->show(); Count++; } // Connect slots for updating displays connect(Scope, SIGNAL(RunHeaderChanged(QString)), RunHeaderDisplay, SLOT(setPlainText(QString))); connect(Scope, SIGNAL(EventHeaderChanged(QString)), EventHeaderDisplay, SLOT(setPlainText(QString))); StartStop(false); connect(Scope, SIGNAL(PixelData(QVector)), SLOT(SetPixelData(QVector))); // Call to get initial pixel ID correct UpdateScope(0); } TP_DAQ::~TP_DAQ() { delete[] Pixel; } // Translate pixel ID to board, chip, channel void TP_DAQ::TranslatePixelID(int ID) { // setValue() below will call UpdateScope() through signal, therefore need to store numbers here unsigned int BoardNo = Scope->Pixel_to_FPAboard(ID); unsigned int PatchNo = Scope->Pixel_to_FPApatch(ID); unsigned int PixelNo = Scope->Pixel_to_FPApixel(ID); if (BoardNo == Scope->PM_ERROR_CODE) PixelID->setValue(-1); else { Board->setValue(BoardNo); Chip->setValue(PatchNo); Channel->setValue(PixelNo); } } // Keep current trace void TP_DAQ::KeepCurrent() { Scope->AddTrace(Board->value(), Chip->value(), Channel->value()); } // Start/stop event acquisition void TP_DAQ::StartStop(bool State) { Scope->SetActive(!State); StartStopButton->setText(State ? "Start" : "Stop"); if (!State) connect(Handler, SIGNAL(YEP(QString, int, QByteArray, QString, QString)), Scope, SLOT(Update(QString, int, QByteArray, QString, QString))); else disconnect(Handler, SIGNAL(YEP(QString, int, QByteArray, QString, QString)), Scope, SLOT(Update(QString, int, QByteArray, QString, QString))); } // Update event scope void TP_DAQ::UpdateScope(int) { // Update pixel ID PixelID->setValue(Scope->FPA_to_Pixel(0, Board->value(), Chip->value(), Channel->value())); if (PixelID->value() == (int) Scope->PM_ERROR_CODE) PixelID->setValue(-1); // Update first trace Scope->UpdateFirst(Board->value(), Chip->value(), Channel->value()); } // Show/hide pixel display void TP_DAQ::ShowPixelDisplay() { Display->show(); Display->raise(); } void TP_DAQ::SetPixelData(QVector Data) { QwtLinearColorMap Map; for (int i=0; isetPalette(QPalette(Map.color(QwtDoubleInterval(300, 400), Data[i]))); } } // // Evidence page // TP_Evidence::TP_Evidence() { setAttribute(Qt::WA_DeleteOnClose); QGridLayout *Layout = new QGridLayout(this); EddLineDisplay *Line; EddText *Text; Line = new EddLineDisplay("Alarm/Message"); Line->setMaximumWidth(200); Layout->addWidget(Line, 0, 0, 1, 2); QPushButton *Button = new QPushButton(); Button->setText("ON/OFF"); Button->setCheckable(true); connect(Button, SIGNAL(toggled(bool)), SLOT(ToggleAlarm(bool))); Layout->addWidget(Button, 0, 3, 1, 1); Line = new EddLineDisplay("Alarm/MasterAlarm"); Layout->addWidget(Line, 0, 1, 1, 1); Text = new EddText("Alarm/Summary", true); Text->Accumulate = false; Text->setMaximumWidth(200); Text->setMaximumHeight(150); Layout->addWidget(Text, 1, 0, 1, 2); Line = new EddLineDisplay("DColl/Message"); Line->setMaximumWidth(200); Layout->addWidget(Line, 3, 0, 1, 2); Line = new EddLineDisplay("DColl/DataSizeMB"); Layout->addWidget(Line, 4, 0, 1, 1); Line = new EddLineDisplay("DColl/LogSizeMB"); Layout->addWidget(Line, 4, 1, 1, 1); Line = new EddLineDisplay("DColl/CurrentFile"); Line->setMaximumWidth(400); Layout->addWidget(Line, 5, 0, 1, 3); Line = new EddLineDisplay("Config/Message"); Line->setMaximumWidth(200); Layout->addWidget(Line, 6, 0, 1, 2); Line = new EddLineDisplay("Config/ModifyTime"); Line->setMaximumWidth(200); Line->ShowAsTime = true; Layout->addWidget(Line, 7, 0, 1, 1); Button = new QPushButton(); Button->setText("eLogBook"); connect(Button, SIGNAL(released()), SLOT(StartELog())); Layout->addWidget(Button, 6, 1, 1, 1); Button = new QPushButton(); Button->setText("Start DIM browser"); connect(Button, SIGNAL(released()), SLOT(StartDIMBrowser())); Layout->addWidget(Button, 7, 1, 1, 1); Line = new EddLineDisplay("Edd/Rate_kBSec"); Layout->addWidget(Line, 8, 0, 1, 1); } // Toggle state of Alarm server void TP_Evidence::ToggleAlarm(bool State) { if (State) DimClient::sendCommandNB((char *) "Alarm/Switch", (char *) "off"); else DimClient::sendCommandNB((char *) "Alarm/Switch", (char *) "on"); } // Start DIM Browser void TP_Evidence::StartDIMBrowser() { QProcess::startDetached("did", QStringList(), QString(getenv("DIMDIR"))+"/linux/"); } // Start eLogBook void TP_Evidence::StartELog() { QProcess::startDetached("firefox http://fact.ethz.ch/FACTelog/index.jsp"); } //-------------------------------------------------------------------- //*************************** Main GUI ******************************* //-------------------------------------------------------------------- // // All widgets have ultimately Central as parent. // GUI::GUI() { Handler = new EddDim; // Arrangement in tabs TabWidget = new QTabWidget(this); TabWidget->setTabsClosable(true); connect(TabWidget, SIGNAL(tabCloseRequested(int)), SLOT(DetachTab(int))); TabWidget->addTab(new TP_DAQ, "Event scope"); TabWidget->addTab(new TP_FADctrl, "FADctrl"); TabWidget->addTab(new TP_Bias, "Bias"); TabWidget->addTab(new TP_Feedback, "Feedback"); TabWidget->addTab(new TP_Environment, "Environment"); TabWidget->addTab(new TP_Evidence, "Evidence"); // Set features of main window setStatusBar(new QStatusBar(this)); setWindowTitle("Edd - Evidence Data Display - Node: " + QString(getenv("DIM_DNS_NODE"))); setCentralWidget(TabWidget); // Menu bar QMenu* Menu = menuBar()->addMenu("&Menu"); Menu->addAction("New history plot", this, SLOT(MenuNewHistory())); Menu->addSeparator(); Menu->addAction("About", this, SLOT(MenuAbout())); Menu->addSeparator(); QAction* QuitAction = Menu->addAction("Quit", qApp, SLOT(quit())); QuitAction->setShortcut(Qt::CTRL + Qt::Key_Q); // Size and show main window QSize Size = TabWidget->sizeHint()*1.1; Size = Size.boundedTo(QApplication::desktop()->screenGeometry(this).size()*0.6); //setMaximumSize(QApplication::desktop()->screenGeometry(this).size()*0.9); TabWidget->resize(Size); TabWidget->setMaximumSize(QApplication::desktop()->screenGeometry(this).size()*0.9); show(); // Set timer to regularly check the master alarm QTimer *Timer = new QTimer(this); connect(Timer, SIGNAL(timeout()), this, SLOT(CheckAlarm())); Timer->start(5000); } void GUI::MenuAbout() { QString Rev(SVN_REVISION); Rev.remove(0,1).chop(2); QMessageBox::about(this, "About Edd","Evidence Data Display\n\n" "Written by Oliver Grimm, IPP, ETH Zurich\n" "This version compiled "__DATE__" ("+Rev+")\n\n" "Graphical user interface implemented with Qt and Qwt.\n" "Evidence control system based on DIM (http://dim.web.cern.ch).\n\n" "Comments to oliver.grimm@phys.ethz.ch."); } // Open request for new history plot void GUI::MenuNewHistory() { QStringList List; char *Name, *Format; int Type; bool OK; // Find all DIM services and sort getServices("*"); while ((Type = getNextService(Name, Format)) != 0) { if (Type==DimSERVICE) List.append(Name); } List.sort(); // Open dialog and open history window QString Result = QInputDialog::getItem(this, "Edd Request", "Enter DIM service name", List, 0, true, &OK); if (OK && !Result.isEmpty()) { Result = Result.trimmed(); QWidget *Hist = OpenHistory(Result.toAscii().data(), 0); if (Hist != NULL) Hist->show(); } } // Open tab as separate window void GUI::DetachTab(int Tab) { QWidget *W = NULL; QMainWindow *M = new QMainWindow; M->setCentralWidget(new QWidget(M)); M->setStatusBar(new QStatusBar(M)); switch(Tab) { case 0: W = new TP_DAQ; break; case 1: W = new TP_Bias; break; case 2: W = new TP_Feedback; break; case 3: W = new TP_Environment; break; case 4: W = new TP_Evidence; break; default: break; } if (W == NULL) { delete M->centralWidget(); delete M; return; } W->setParent(M); M->resize(size()); M->setWindowTitle("Edd - " + TabWidget->tabText(Tab)); M->show(); } // Check alarm level and if Alarm server is alive void GUI::CheckAlarm() { static int WarnedLevel = 0; static bool AlarmServerWarned = false; // === Check service Alarm/MasterAlarm === DimCurrentInfo MasterAlarm("Alarm/MasterAlarm", -1); if (MasterAlarm.getInt() > WarnedLevel) { QSound::play(QApplication::applicationDirPath() + "/Error.wav"); // Construct warning message box QMessageBox Box; Box.setWindowTitle("Edd Alarm"); Box.setText("Service 'Alarm/MasterAlarm' is at " + QString::number(MasterAlarm.getInt())); Box.setInformativeText("Warn again for the same alarm level?"); Box.setIcon(QMessageBox::Warning); Box.setStandardButtons(QMessageBox::Yes | QMessageBox::No); Box.setDefaultButton(QMessageBox::No); // Check if user wants to reset warned level if (Box.exec() == QMessageBox::Yes) WarnedLevel = 0; else WarnedLevel = MasterAlarm.getInt(); } // If MasterAlam decreased, lower also warned level if (MasterAlarm.getInt() < WarnedLevel && MasterAlarm.getInt() >=0 ) WarnedLevel = MasterAlarm.getInt(); // === Check Alarm server === DimCurrentInfo ServerList("DIS_DNS/SERVER_LIST", NO_LINK); std::string Result = EvidenceServer::ToString((char *) "C", ServerList.getData(), ServerList.getSize()); // Warn if SERVER_LIST does not contain alarm server if (Result.find("Alarm@") == std::string::npos && !AlarmServerWarned) { QMessageBox Box; Box.setWindowTitle("Edd Alarm"); Box.setText("Alarm server is unavailable or in error"); Box.setIcon(QMessageBox::Critical); Box.setStandardButtons(QMessageBox::Ok); Box.setDefaultButton(QMessageBox::Ok); Box.exec(); AlarmServerWarned = true; } if (Result.find("Alarm@") != std::string::npos) AlarmServerWarned = false; } // Quit application when clicking close button on window void GUI::closeEvent(QCloseEvent *) { qApp->quit(); } // //**************************** Main program *************************** // int main(int argc, char *argv[]) { if (argc>1 && strcmp(argv[1],"drsdaq")==0) DRSBoard = "drsdaq"; // Make RPC to get pixelmap DimRpcInfo RPC((char *) "ConfigRequest", (char *) ""); RPC.setData((char *) "Misc PixelMap"); PixelMapText = std::string(RPC.getString(), RPC.getSize()); QApplication app(argc, argv); GUI MainWindow; return app.exec(); }