#include "GUI.h" //----------------------------------------------------------------------- //**************************** All functions **************************** //----------------------------------------------------------------------- // +++ Open file dialog +++ void ddd::FileDialog(void) { QString Filename = QFileDialog::getOpenFileName(this, "Open raw file", INITIAL_DIRECTORY, "Raw data files (*.raw);; All files (*)"); if (Filename != NULL) { FilenameBox->setText(Filename); OpenDatafile(); } } // +++ Open selected file and read run header +++ void ddd::OpenDatafile() { CloseDatafile(); // Close previous file if open // Write run header to temporary file FILE *Tmpfile = tmpfile(); if(Tmpfile==NULL) { QMessageBox::warning(this, "ddd Message","Could not open temporary file.",QMessageBox::Ok); CloseDatafile(); return; } switch (RD->OpenDataFile(FilenameBox->text().toAscii().data(), Tmpfile)) { case CTX_FOPEN: QMessageBox::warning(this, "ddd Message","Could not open file.",QMessageBox::Ok); return; case CTX_RHEADER: QMessageBox::warning(this, "ddd Message","Could not read run header.",QMessageBox::Ok); return; case CTX_BSTRUCT: QMessageBox::warning(this, "ddd Message","Could not read board structures.",QMessageBox::Ok); return; default: break; } if (RD->RHeader->MagicNum != MAGICNUM_FILE_CLOSED) QMessageBox::warning(this, "ddd Message","Magic number in run header indicates that the file has not been closed properly.",QMessageBox::Ok); rewind(Tmpfile); QTextStream in(Tmpfile); QString text = in.readAll(); RunHeaderDisplay->setPlainText(text); fclose(Tmpfile); // Enable spin boxes, set ranges and display first event EventNo->setEnabled(true); ChannelNo->setEnabled(true); BoardNo->setEnabled(true); PixelID->setEnabled(true); EventNo->setValue(1); EventNo->setRange(1, RD->RHeader->Events); ChannelNo->setValue(0); ChannelNo->setRange(0, RD->RHeader->NChannels*RD->RHeader->NChips-1); BoardNo->setValue(0); BoardNo->setRange(0, RD->RHeader->NCMCBoards-1); DisplayEvent(); } // +++ Close data file file if open, delete event header and disable spin boxes and displays +++ void ddd::CloseDatafile() { if(RD->CloseDataFile()==CTX_OK) { EventNo->setEnabled(false); ChannelNo->setEnabled(false); BoardNo->setEnabled(false); PixelID->setEnabled(false); RunHeaderDisplay->clear(); EventHeaderDisplay->clear(); Signal->hide(); } } // +++ Read event header and display event (only called if Datafile is open) +++ void ddd::DisplayEvent(int) { PixelID->setText(PixMap->DRS_to_Pixel(BoardNo->value(),ChannelNo->value()/10,ChannelNo->value()%10).c_str()); if(Socket->state() == QAbstractSocket::ConnectedState) return; // do not execute if socket is open // Read event FILE *Tmpfile = tmpfile(); switch(RD->ReadEvent(EventNo->value(), Tmpfile)) { case !CTX_OK: QMessageBox::warning(this, "ddd Warning","Could not read event.",QMessageBox::Ok); EventHeaderDisplay->clear(); break; default: rewind(Tmpfile); QTextStream in(Tmpfile); QString text = in.readAll(); EventHeaderDisplay->setPlainText(text); // Case data in double format required by qwt library double* x = new double [RD->RHeader->Samples]; double* y = new double [RD->RHeader->Samples]; for (unsigned int i=0; iRHeader->Samples; i++) { x[i] = (double) (i/RD->BStruct[BoardNo->value()].NomFreq); y[i] = (double) RD->Data[BoardNo->value()*RD->RHeader->NChips*RD->RHeader->NChannels * RD->RHeader->Samples+ChannelNo->value()*RD->RHeader->Samples+i]*RD->BStruct[BoardNo->value()].ScaleFactor; } Signal->setData(x, y, RD->RHeader->Samples); Signal->show(); Zoomer->setZoomBase(Signal->boundingRect()); delete[] x; delete[] y; } if(Tmpfile!=NULL) fclose(Tmpfile); } // +++ Open sub window handling the socket interface +++ void ddd::OpenSocketWindow() { if(SocketWindow->isVisible()) SocketWindow->hide(); else SocketWindow->show(); } // +++ Acquire data through socket (acquire botton only available if socket exists) +++ void ddd::GetSignalFromSocket() { char Command[MAX_COM_SIZE]; GetButton->setEnabled(false); WaitForData = true; sprintf(Command, "read %d %d %d restart", BoardNo->value(), ChannelNo->value()/10, ChannelNo->value()%10); Socket->write(Command); } // Quit application when clicking close button on window void ddd::closeEvent(QCloseEvent *) { qApp->quit(); } // +++ Connecting or disconnecting from client +++ void ddd::MakeConnection() { if(Socket->state() == QAbstractSocket::ConnectedState) { ManualDisconnect = true; Socket->disconnectFromHost(); } else { if (RD->IsFileOpen() && QMessageBox::question(this, "ddd Request","Connecting will close current data file. Proceed?", QMessageBox::No, QMessageBox::Yes) != QMessageBox::Yes) return; Socket->connectToHost(IPAddress->text(),Port->value()); Connect->setEnabled(false); // While waiting for connection, button not available Socket->waitForConnected(SOCKET_TIMEOUT); Connect->setEnabled(true); if(Socket->state() != QAbstractSocket::ConnectedState) QMessageBox::warning(this, "ddd Message","Could not connect to host.",QMessageBox::Ok); else { Connect->setText("Disconnect"); ConnectAction->setText("Disconnect"); Port->setEnabled(false); IPAddress->setEnabled(false); Command->setEnabled(true); GetButton->setEnabled(true); ManualDisconnect = false; OpenAction->setEnabled(false); FilenameBox->setEnabled(false); LoadButton->setEnabled(false); FilenameBox->clear(); CloseDatafile(); ChannelNo->setEnabled(true); BoardNo->setEnabled(true); PixelID->setEnabled(true); ChannelNo->setRange(0, 65535); BoardNo->setRange(0, 65535); TabWidget->setTabEnabled(1,false); TabWidget->setTabEnabled(2,false); RunHeaderDisplay->clear(); EventHeaderDisplay->clear(); Signal->hide(); } } } // +++ Send command to socket (command button available only if socket existing) +++ void ddd::SendToSocket() { Socket->write(Command->text().toAscii()); Command->clear(); } // +++ Read data from socket and display +++ void ddd::ReadFromSocket() { // Check if channel data expected and error message arrived QByteArray Data = Socket->readAll(); if (WaitForData && Data.contains("Error")) { WaitForData = false; GetButton->setEnabled(true); QMessageBox::warning(this, "ddd Message","Could not read waveform data from socket.",QMessageBox::Ok); return; } // Check if channel data were transmitted, if yes and waiting for data, extract and plot them SocketOutput->insertPlainText(Data); QString Text = SocketOutput->document()->toPlainText().trimmed(); if (WaitForData && Text.endsWith(QLatin1String("==END=="))) { // Extract text between ==START== and ==END== QByteArray Data=Text.mid(Text.lastIndexOf("==START==")+9,Text.length()-Text.lastIndexOf("==START==")-16).toAscii(); char *NextNumber = strtok(Data.data()," "); // Number of entries that follow int Count=0, NumberOfEntries = atoi(NextNumber); double *x = new double [NumberOfEntries]; double *y = new double [NumberOfEntries]; // Convert all entries (separated by a whitespace) to numbers while((NextNumber=strtok(NULL, " "))!=NULL && Count2) { Signal->setData(x+2, y+2, NumberOfEntries-2); // Copies data, arrays can be deleted afterwards Signal->show(); Zoomer->setZoomBase(Signal->boundingRect()); } delete[] x; delete[] y; if(ContinuousBox->isChecked()) { usleep(100000); // Wait to limit maximum update rate GetSignalFromSocket(); } else { WaitForData = false; GetButton->setEnabled(true); } } } // +++ Disconnect from socket +++ void ddd::GotDisconnected() { Connect->setText("Connect"); ConnectAction->setText("Connect"); Port->setEnabled(true); IPAddress->setEnabled(true); Command->setEnabled(false); GetButton->setEnabled(false); FilenameBox->setEnabled(true); OpenAction->setEnabled(true); LoadButton->setEnabled(true); ChannelNo->setEnabled(false); BoardNo->setEnabled(false); PixelID->setEnabled(false); Signal->hide(); TabWidget->setTabEnabled(1, true); TabWidget->setTabEnabled(2, true); SocketOutput->clear(); if(!ManualDisconnect) QMessageBox::warning(this, "ddd Message","Socket disconnected, maybe host gone.",QMessageBox::Ok); } // +++ Translate pixel ID +++ void ddd::TranslatePixelID() { int Board = PixMap->Pixel_to_DRSboard(PixelID->text().toStdString()); int Chip = PixMap->Pixel_to_DRSchip(PixelID->text().toStdString()); int Channel = PixMap->Pixel_to_DRSchannel(PixelID->text().toStdString()); if(Board>=BoardNo->minimum() && Board<=BoardNo->maximum() && (Chip*10+Channel)>=ChannelNo->minimum() && (Chip*10+Channel)<=ChannelNo->maximum()) { BoardNo->setValue(Board); ChannelNo->setValue(Chip*10+Channel); } else if(Board==999999999) QMessageBox::warning(this, "ddd Message","Pixel ID unknown.",QMessageBox::Ok); else QMessageBox::warning(this, "ddd Message","Pixel ID out of current range.",QMessageBox::Ok); } //------------------------------------------------------------------ //**************************** All menus *************************** //------------------------------------------------------------------ void ddd::MenuSave() { QString Filename = QFileDialog::getSaveFileName(this, "Filename of image", "/home/ogrimm/ddd", "Image files (*.bmp *.jpg *.png *.ppm *.tiff *.xbm *.xpm);;All files (*)"); if (Filename.length()>0) { QPixmap Pixmap = QPixmap::grabWidget(Graph); if(!Pixmap.save(Filename)) { QMessageBox::warning(this, "ddd Message","Could not write image file.",QMessageBox::Ok); remove(Filename.toAscii().data()); } } } void ddd::MenuPrint() { QPrinter *Printer = new QPrinter; QPrintDialog *PrintDialog = new QPrintDialog(Printer, this); if (PrintDialog->exec() == QDialog::Accepted) { QPainter Painter(Printer); QPixmap Pixmap = QPixmap::grabWidget(Graph); Painter.drawPixmap(0, 0, Pixmap); } delete Printer; delete PrintDialog; } void ddd::MenuHelp() { QMessageBox Message; Message.setText("The DRS Data Display program can be used for two purposes:\n\n" "1. Reading and displaying the content of a raw data file written by the drsdaq program\n" "2. Acquiring and displaying online data from a running drsdaq program via the socket interface\n\n" "With an established socket connection, displaying of raw data files is disabled."); Message.setWindowTitle("ddd Help"); Message.exec(); } void ddd::MenuAbout() { QMessageBox::about(this, "ddd About","DRS Data Display\n\n" "Written by Oliver Grimm, IPP, ETH Zurich\n" "This version compiled "__DATE__".\n\n" "Graphical user interface implemented with Qt.\n" "Bug reports to oliver.grimm@phys.ethz.ch."); }