Index: /tools/ddd/Functions.cpp
===================================================================
--- /tools/ddd/Functions.cpp	(revision 29)
+++ /tools/ddd/Functions.cpp	(revision 29)
@@ -0,0 +1,321 @@
+
+#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; i<RD->RHeader->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;
+  
+  Socket->write("stop\n");
+  Socket->flush();
+  usleep(10000);
+  sprintf(Command, "read %d %d %d", 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];
+
+    while((NextNumber=strtok(NULL, " "))!=NULL && Count<NumberOfEntries) {	// All entries are separated by a whitespace
+      *(y+Count) = atof(NextNumber);
+      x[Count] = Count;
+      Count++;
+    }
+    if (Count==NumberOfEntries && NextNumber!=0)
+      QMessageBox::warning(this, "ddd Message","Found too many numbers in data block, truncated.",QMessageBox::Ok);
+    Signal->setData(x, y, Count);	// Copies data, arrays can be deleted afterwards
+    Signal->show();
+    Zoomer->setZoomBase(Signal->boundingRect());
+
+    delete[] x;   delete[] y;
+
+    Socket->write("start\n");   Socket->flush();
+    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.");
+}
Index: /tools/ddd/GUI.cpp
===================================================================
--- /tools/ddd/GUI.cpp	(revision 29)
+++ /tools/ddd/GUI.cpp	(revision 29)
@@ -0,0 +1,234 @@
+/* ============================================================ 
+
+DRS Data Display
+
+Qt-based graphical user interface for displaying data taken with
+the drsdaq program.
+There are two operation modes: inspection of a raw data file and
+data taking via the socket interface. Connecting to a socket server
+automatically disables raw data file operation and closes any open
+file.
+
+Oliver Grimm
+
+============================================================ */
+
+#include "GUI.h"
+
+ddd::ddd() {
+  
+  WaitForData = false;
+  
+  // Instantiate without console output
+  RD = new RawDataCTX(true);
+  PixMap = new PixelMap("../../config/PixelMap.txt", false);
+   
+  //---------------------------------------------------------------------
+  //**************************** Main window ****************************
+  //---------------------------------------------------------------------
+
+  Central = new QWidget(this);
+  setCentralWidget(Central);
+
+  Socket = new QTcpSocket(Central);
+  connect(Socket, SIGNAL(readyRead()), this, SLOT(ReadFromSocket()));   
+  connect(Socket, SIGNAL(disconnected()), this, SLOT(GotDisconnected()));   
+ 
+  // SpinBox for event number
+  EventNo = new QSpinBox(Central);
+  EventNo->setEnabled(false);
+  connect(EventNo, SIGNAL(valueChanged(int)), this, SLOT(DisplayEvent(int)));
+  EventNo->setToolTip("Event number in file");
+  SpinLayout = new QFormLayout();
+  SpinLayout->setRowWrapPolicy(QFormLayout::WrapAllRows);
+  SpinLayout->addRow("E&vent #", EventNo);
+
+  // SpinBox for channel number 
+  ChannelNo = new QSpinBox(Central);
+  ChannelNo->setEnabled(false);
+  connect(ChannelNo, SIGNAL(valueChanged(int)), this, SLOT(DisplayEvent(int)));
+  ChannelNo->setToolTip("Channels 0-19 for 2 DRS chips per mezzanine board");
+  
+  // SpinBox for board number 
+  BoardNo = new QSpinBox(Central);
+  BoardNo->setEnabled(false);
+  connect(BoardNo, SIGNAL(valueChanged(int)), this, SLOT(DisplayEvent(int)));
+  BoardNo->setToolTip("Mezzanine board number");
+ 
+   // TextBox for pixel ID
+  PixelID = new QLineEdit(Central);
+  PixelID->setEnabled(false);
+  connect(PixelID, SIGNAL(returnPressed()), this, SLOT(TranslatePixelID()));
+  PixelID->setToolTip("Pixel identification");
+ 
+  // Layout of pixel addressing widgets
+  FormLayout = new QFormLayout;
+  FormLayout->setRowWrapPolicy(QFormLayout::WrapAllRows);
+  FormLayout->addRow("&Channel #", ChannelNo);
+  FormLayout->addRow("&Board #", BoardNo);
+  FormLayout->addRow("Pixel ID", PixelID);
+
+  // Socket button
+  SocketButton = new QPushButton("Socke&t\nInterface", Central);
+  SocketButton->setFont(QFont("Times", 10, QFont::Bold));
+  connect(SocketButton, SIGNAL(clicked()), this, SLOT(OpenSocketWindow()));
+  SocketButton->setToolTip("Open window for socket communication");
+
+  // Acquire button and Continuous check box
+  GetButton = new QPushButton("&Acquire", Central);
+  GetButton->setFont(QFont("Times", 10, QFont::Bold));
+  GetButton->setEnabled(false);
+  connect(GetButton, SIGNAL(clicked()), this, SLOT(GetSignalFromSocket()));
+  GetButton->setToolTip("Acquire event over socket interface");
+  ContinuousBox = new QCheckBox("Continuous", Central);
+  ContinuousBox->setFont(QFont("Times", 10, QFont::Bold));
+  ContinuousBox->setToolTip("Acquire continuously");
+
+  // Plot area
+  Graph = new QwtPlot(Central);
+  Graph->setAxisTitle(QwtPlot::xBottom, "Time (ns)");
+  Graph->setAxisTitle(QwtPlot::yLeft, "Signal (mV)");
+  Graph->setAutoReplot(true);
+  Graph->setCanvasBackground(QColor(Qt::yellow));
+  Graph->setToolTip("Left mouse button to zoom (+Shift to pan)");
+  Zoomer = new QwtPlotZoomer(QwtPlot::xBottom,QwtPlot::yLeft,Graph->canvas());
+  Panner = new QwtPlotPanner(Graph->canvas());
+  Panner->setMouseButton(Qt::LeftButton, Qt::ShiftModifier);
+  Grid = new QwtPlotGrid;
+  Grid->setMajPen(QPen(Qt::gray, 0, Qt::DotLine));
+  Grid->attach(Graph);
+  Signal = new QwtPlotCurve;
+  Signal->attach(Graph);
+      
+  // Text boxes for run and event header
+  RunHeaderDisplay = new QPlainTextEdit(Central);
+  EventHeaderDisplay = new QPlainTextEdit(Central);
+  RunHeaderDisplay->setReadOnly(true);
+  EventHeaderDisplay->setReadOnly(true);
+
+  // Browse botton
+  LoadButton = new QToolButton(Central);
+  LoadButton->setToolButtonStyle (Qt::ToolButtonTextOnly);
+  LoadButton->setText("...");
+  connect(LoadButton, SIGNAL(clicked()), this, SLOT(FileDialog()));
+  LoadButton->setToolTip("Open file dialog to select raw data file");
+
+  // Filename box
+  FilenameBox = new QLineEdit(Central);
+  connect(FilenameBox, SIGNAL(returnPressed()), this, SLOT(OpenDatafile()));
+  FilenameBox->setToolTip("Raw data file name");
+
+  // Tab widget
+  TabWidget = new QTabWidget(Central);
+  TabWidget->addTab(Graph, "&Signal");
+  TabWidget->addTab(RunHeaderDisplay, "&Run Header");
+  TabWidget->addTab(EventHeaderDisplay, "&Event Header");
+ 
+  // Layout of all widgets
+  MainLayout = new QGridLayout(Central);
+  MainLayout->addWidget(FilenameBox, 0, 0, 1, 3);
+  MainLayout->addWidget(LoadButton, 0, 3);
+  MainLayout->addLayout(SpinLayout, 1, 0);
+  MainLayout->addLayout(FormLayout, 2, 0);
+  MainLayout->addWidget(SocketButton, 6,0);
+  MainLayout->addWidget(GetButton, 4,0);
+  MainLayout->addWidget(ContinuousBox, 5,0);
+  MainLayout->addWidget(TabWidget, 1, 1, 6, 5);
+  MainLayout->setColumnStretch(1, 10);
+  
+  // Menu bar
+  QMenu* Menu = menuBar()->addMenu("&Menu");
+  OpenAction = Menu->addAction("Open data file", this, SLOT(FileDialog()));
+  OpenAction->setShortcut(Qt::CTRL + Qt::Key_O);
+  QAction* SaveAction = Menu->addAction("Save plot", this, SLOT(MenuSave()));
+  SaveAction->setShortcut(Qt::CTRL + Qt::Key_S);
+  Menu->addAction("Print plot", this, SLOT(MenuPrint()));
+  Menu->addSeparator();
+  ConnectAction = Menu->addAction("Connect", this, SLOT(MakeConnection()));
+  ConnectAction->setShortcut(Qt::CTRL + Qt::Key_C);
+  Menu->addSeparator();
+  Menu->addAction("Help", this, SLOT(MenuHelp()));
+  Menu->addAction("About", this, SLOT(MenuAbout()));
+  Menu->addSeparator();
+  QAction* QuitAction = Menu->addAction("Quit", qApp, SLOT(quit()));
+  QuitAction->setShortcut(Qt::CTRL + Qt::Key_Q);
+    
+  //-----------------------------------------------------------------------
+  //**************************** Socket window ****************************
+  //-----------------------------------------------------------------------
+  
+  // Create widget (initially hidden)
+  SocketWindow = new QWidget();
+  SocketWindow->setWindowTitle("ddd - Socket Interface");
+  
+  // Edit box for IP Address  
+  IPAddress = new QLineEdit(SocketWindow);
+  IPAddress->setText("eth-vme02");
+  IPAddress->setToolTip("Address of socket server");
+  AddressLayout = new QFormLayout;
+  AddressLayout->addRow("&Remote Address", IPAddress);
+  
+  // SpinBox for port selection
+  Port = new QSpinBox(SocketWindow);
+  Port->setRange(0,65535);
+  Port->setValue(2000);
+  Port->setToolTip("Port number of socket server");
+  PortLayout = new QFormLayout;  
+  PortLayout->addRow("&Port", Port);
+
+  // Button to make connection
+  Connect = new QPushButton("Connect", SocketWindow);
+  Connect->setFont(QFont("Times", 10, QFont::Bold));
+  connect(Connect, SIGNAL(clicked()), this, SLOT(MakeConnection()));
+  Connect->setToolTip("Connect to server");
+    
+  // Edit box for command
+  Command = new QLineEdit(SocketWindow);
+  CommandLayout = new QFormLayout;  
+  CommandLayout->addRow("&Command", Command);
+  Command->setEnabled(false);
+  connect(Command, SIGNAL(returnPressed()), this, SLOT(SendToSocket()));
+  Command->setToolTip("Command to send to socket server");
+
+  // Text box for socket output
+  SocketOutput= new QPlainTextEdit(SocketWindow);
+  SocketOutput->setReadOnly(true);
+  SocketOutput->setMaximumBlockCount(MAX_OUTPUT_LINES);
+  SocketOutput->setToolTip("Output of socket server");
+  
+  // Layout of all widgets
+  SocketLayout = new QGridLayout(SocketWindow);
+  SocketLayout->addLayout(AddressLayout, 0, 0, 0, 1);
+  SocketLayout->addLayout(PortLayout, 0, 2);
+  SocketLayout->addWidget(Connect, 0, 3);
+  SocketLayout->addLayout(CommandLayout, 1, 0, 1, 4);
+  SocketLayout->addWidget(SocketOutput, 2, 0, 4, 4);  
+}
+
+ddd::~ddd() {
+  // Qwt items
+  delete Grid;			delete Signal;
+  // Layout items
+  delete PortLayout;		delete CommandLayout;
+  delete AddressLayout;		delete FormLayout;
+  delete SpinLayout;
+  // Other items 		
+  delete SocketWindow;
+  delete PixMap;		delete RD;
+}
+
+
+//---------------------------------------------------------------------
+//**************************** Main program ***************************
+//---------------------------------------------------------------------
+
+int main(int argc, char *argv[]) {
+  QApplication app(argc, argv);
+  
+  ddd MainWindow;
+  MainWindow.setGeometry(100, 100, 800, 500);
+  MainWindow.setWindowTitle("ddd - DRS Data Display");
+  MainWindow.show();
+  
+  return app.exec();
+}
Index: /tools/ddd/GUI.h
===================================================================
--- /tools/ddd/GUI.h	(revision 29)
+++ /tools/ddd/GUI.h	(revision 29)
@@ -0,0 +1,72 @@
+#include <string>
+
+#include <QtGui>
+#include <QtNetwork/QTcpSocket>
+#include <QtNetwork/QAbstractSocket>
+
+#include <qwt_plot.h>
+#include <qwt_plot_curve.h>
+#include <qwt_plot_grid.h>
+#include <qwt_plot_zoomer.h>
+#include <qwt_plot_panner.h>
+
+#include "../../drsdaq/RawDataCTX.h"
+#include "../../pixelmap/PixelMap.h"
+
+#define SOCKET_TIMEOUT 10000	// Milliseconds to wait for socket connection
+#define MAX_OUTPUT_LINES 200	// Maximum number of lines in socket output window
+#define MAX_COM_SIZE 10000
+#define INITIAL_DIRECTORY ""
+
+// Main window class
+class ddd : public QMainWindow {
+    Q_OBJECT
+    
+    QPushButton *GetButton, *SocketButton, *Connect;
+    QCheckBox *ContinuousBox;
+    QToolButton *LoadButton;
+    QLineEdit *FilenameBox, *IPAddress, *Command, *PixelID;
+    QSpinBox *EventNo, *ChannelNo, *BoardNo, *Port;
+    QPlainTextEdit *RunHeaderDisplay, *EventHeaderDisplay, *SocketOutput;
+    QTabWidget *TabWidget;
+    QTcpSocket *Socket;
+    QWidget *SocketWindow, *Central;
+    QAction *OpenAction, *ConnectAction;
+    QGridLayout *SocketLayout, *MainLayout;
+    QFormLayout *CommandLayout, *PortLayout, *AddressLayout, *FormLayout, *SpinLayout;
+    
+    QwtPlot *Graph;
+    QwtPlotZoomer *Zoomer;
+    QwtPlotCurve *Signal;
+    QwtPlotPanner *Panner;
+    QwtPlotGrid *Grid;
+
+    void closeEvent(QCloseEvent *); 
+
+    bool ManualDisconnect, WaitForData;
+    RawDataCTX *RD;
+    PixelMap *PixMap;
+      
+  public:
+    ddd();
+    ~ddd();
+    void CloseDatafile();
+    
+  private slots:
+    void OpenDatafile();
+    void DisplayEvent(int=0);
+    void FileDialog();
+    void OpenSocketWindow();
+    void GetSignalFromSocket();
+    void MakeConnection();
+    void SendToSocket();
+    void ReadFromSocket();
+    void GotDisconnected();
+    void TranslatePixelID();
+    
+    void MenuSave();
+    void MenuPrint();
+    void MenuHelp();
+    void MenuAbout();
+};
+
Index: /tools/ddd/Makefile
===================================================================
--- /tools/ddd/Makefile	(revision 29)
+++ /tools/ddd/Makefile	(revision 29)
@@ -0,0 +1,235 @@
+#############################################################################
+# Makefile for building: ddd
+# Generated by qmake (2.01a) (Qt 4.4.3) on: Tue Mar 24 08:02:04 2009
+# Project:  ddd.pro
+# Template: app
+# Command: /usr/local/Trolltech/Qt-4.4.3/bin/qmake -unix -o Makefile ddd.pro
+#############################################################################
+
+####### Compiler, tools and options
+
+CC            = gcc
+CXX           = g++
+DEFINES       = -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -DQT_SHARED
+CFLAGS        = -pipe -O2 -Wall -W -D_REENTRANT $(DEFINES)
+CXXFLAGS      = -pipe -O2 -Wall -W -D_REENTRANT $(DEFINES)
+INCPATH       = -I/usr/local/Trolltech/Qt-4.4.3/mkspecs/linux-g++ -I. -I/usr/local/Trolltech/Qt-4.4.3/include/QtCore -I/usr/local/Trolltech/Qt-4.4.3/include/QtCore -I/usr/local/Trolltech/Qt-4.4.3/include/QtNetwork -I/usr/local/Trolltech/Qt-4.4.3/include/QtNetwork -I/usr/local/Trolltech/Qt-4.4.3/include/QtGui -I/usr/local/Trolltech/Qt-4.4.3/include/QtGui -I/usr/local/Trolltech/Qt-4.4.3/include -I. -I/usr/local/qwt-5.1.1/include -I. -I.
+LINK          = g++
+LFLAGS        = -Wl,-rpath,/usr/local/Trolltech/Qt-4.4.3/lib
+LIBS          = $(SUBLIBS) -L/usr/local/qwt-5.1.1/lib -lqwt -L/usr/local/Trolltech/Qt-4.4.3/lib -lQtGui -L/usr/local/Trolltech/Qt-4.4.3/lib -L/usr/X11R6/lib -pthread -lpng -lSM -lICE -pthread -pthread -lXi -lXrender -lXrandr -lfreetype -lfontconfig -lXext -lX11 -lQtNetwork -pthread -pthread -lQtCore -lz -lm -pthread -lgthread-2.0 -lrt -lglib-2.0 -ldl -lpthread
+AR            = ar cqs
+RANLIB        = 
+QMAKE         = /usr/local/Trolltech/Qt-4.4.3/bin/qmake
+TAR           = tar -cf
+COMPRESS      = gzip -9f
+COPY          = cp -f
+SED           = sed
+COPY_FILE     = $(COPY)
+COPY_DIR      = $(COPY) -r
+INSTALL_FILE  = install -m 644 -p
+INSTALL_DIR   = $(COPY_DIR)
+INSTALL_PROGRAM = install -m 755 -p
+DEL_FILE      = rm -f
+SYMLINK       = ln -sf
+DEL_DIR       = rmdir
+MOVE          = mv -f
+CHK_DIR_EXISTS= test -d
+MKDIR         = mkdir -p
+
+####### Output directory
+
+OBJECTS_DIR   = ./
+
+####### Files
+
+SOURCES       = Functions.cpp \
+		GUI.cpp \
+		../../pixelmap\Pixel.cc \
+		../../pixelmap\PixelMap.cc \
+		../../drsdaq/RawDataCTX.cc \
+		moc_GUI.cpp
+OBJECTS       = Functions.o \
+		GUI.o \
+		../../pixelmap/Pixel.o \
+		../../pixelmap/PixelMap.o \
+		../../drsdaq/RawDataCTX.o \
+		moc_GUI.o
+DIST          = /usr/local/Trolltech/Qt-4.4.3/mkspecs/common/g++.conf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/common/unix.conf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/common/linux.conf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/qconfig.pri \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/qt_functions.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/qt_config.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/exclusive_builds.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/default_pre.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/release.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/default_post.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/warn_on.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/qt.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/unix/thread.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/moc.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/resources.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/uic.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/yacc.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/lex.prf \
+		ddd.pro
+QMAKE_TARGET  = ddd
+DESTDIR       = 
+TARGET        = ddd
+
+first: all
+####### Implicit rules
+
+.SUFFIXES: .o .c .cpp .cc .cxx .C
+
+.cpp.o:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
+
+.cc.o:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
+
+.cxx.o:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
+
+.C.o:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
+
+.c.o:
+	$(CC) -c $(CFLAGS) $(INCPATH) -o "$@" "$<"
+
+####### Build rules
+
+all: Makefile $(TARGET)
+
+$(TARGET):  $(OBJECTS)  
+	$(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS)
+
+Makefile: ddd.pro  /usr/local/Trolltech/Qt-4.4.3/mkspecs/linux-g++/qmake.conf /usr/local/Trolltech/Qt-4.4.3/mkspecs/common/g++.conf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/common/unix.conf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/common/linux.conf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/qconfig.pri \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/qt_functions.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/qt_config.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/exclusive_builds.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/default_pre.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/release.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/default_post.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/warn_on.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/qt.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/unix/thread.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/moc.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/resources.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/uic.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/yacc.prf \
+		/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/lex.prf \
+		/usr/local/Trolltech/Qt-4.4.3/lib/libQtGui.prl \
+		/usr/local/Trolltech/Qt-4.4.3/lib/libQtCore.prl \
+		/usr/local/Trolltech/Qt-4.4.3/lib/libQtNetwork.prl
+	$(QMAKE) -unix -o Makefile ddd.pro
+/usr/local/Trolltech/Qt-4.4.3/mkspecs/common/g++.conf:
+/usr/local/Trolltech/Qt-4.4.3/mkspecs/common/unix.conf:
+/usr/local/Trolltech/Qt-4.4.3/mkspecs/common/linux.conf:
+/usr/local/Trolltech/Qt-4.4.3/mkspecs/qconfig.pri:
+/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/qt_functions.prf:
+/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/qt_config.prf:
+/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/exclusive_builds.prf:
+/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/default_pre.prf:
+/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/release.prf:
+/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/default_post.prf:
+/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/warn_on.prf:
+/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/qt.prf:
+/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/unix/thread.prf:
+/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/moc.prf:
+/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/resources.prf:
+/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/uic.prf:
+/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/yacc.prf:
+/usr/local/Trolltech/Qt-4.4.3/mkspecs/features/lex.prf:
+/usr/local/Trolltech/Qt-4.4.3/lib/libQtGui.prl:
+/usr/local/Trolltech/Qt-4.4.3/lib/libQtCore.prl:
+/usr/local/Trolltech/Qt-4.4.3/lib/libQtNetwork.prl:
+qmake:  FORCE
+	@$(QMAKE) -unix -o Makefile ddd.pro
+
+dist: 
+	@$(CHK_DIR_EXISTS) .tmp/ddd1.0.0 || $(MKDIR) .tmp/ddd1.0.0 
+	$(COPY_FILE) --parents $(SOURCES) $(DIST) .tmp/ddd1.0.0/ && $(COPY_FILE) --parents GUI.h Pixel.h PixelMap.h RawDataCTX.h .tmp/ddd1.0.0/ && $(COPY_FILE) --parents Functions.cpp GUI.cpp Pixel.cc PixelMap.cc RawDataCTX.cc .tmp/ddd1.0.0/ && (cd `dirname .tmp/ddd1.0.0` && $(TAR) ddd1.0.0.tar ddd1.0.0 && $(COMPRESS) ddd1.0.0.tar) && $(MOVE) `dirname .tmp/ddd1.0.0`/ddd1.0.0.tar.gz . && $(DEL_FILE) -r .tmp/ddd1.0.0
+
+
+clean:compiler_clean 
+	-$(DEL_FILE) $(OBJECTS)
+	-$(DEL_FILE) *~ core *.core
+
+
+####### Sub-libraries
+
+distclean: clean
+	-$(DEL_FILE) $(TARGET) 
+	-$(DEL_FILE) Makefile
+
+
+mocclean: compiler_moc_header_clean compiler_moc_source_clean
+
+mocables: compiler_moc_header_make_all compiler_moc_source_make_all
+
+compiler_moc_header_make_all: moc_GUI.cpp
+compiler_moc_header_clean:
+	-$(DEL_FILE) moc_GUI.cpp
+moc_GUI.cpp: ../../drsdaq/RawDataCTX.h \
+		../../pixelmap/PixelMap.h \
+		../../pixelmap/Pixel.h \
+		GUI.h
+	/usr/local/Trolltech/Qt-4.4.3/bin/moc $(DEFINES) $(INCPATH) GUI.h -o moc_GUI.cpp
+
+compiler_rcc_make_all:
+compiler_rcc_clean:
+compiler_image_collection_make_all: qmake_image_collection.cpp
+compiler_image_collection_clean:
+	-$(DEL_FILE) qmake_image_collection.cpp
+compiler_moc_source_make_all:
+compiler_moc_source_clean:
+compiler_uic_make_all:
+compiler_uic_clean:
+compiler_yacc_decl_make_all:
+compiler_yacc_decl_clean:
+compiler_yacc_impl_make_all:
+compiler_yacc_impl_clean:
+compiler_lex_make_all:
+compiler_lex_clean:
+compiler_clean: compiler_moc_header_clean 
+
+####### Compile
+
+Functions.o: Functions.cpp GUI.h \
+		../../drsdaq/RawDataCTX.h \
+		../../pixelmap/PixelMap.h \
+		../../pixelmap/Pixel.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o Functions.o Functions.cpp
+
+GUI.o: GUI.cpp GUI.h \
+		../../drsdaq/RawDataCTX.h \
+		../../pixelmap/PixelMap.h \
+		../../pixelmap/Pixel.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o GUI.o GUI.cpp
+
+Pixel.o: ../../Pixel.cc ../../PixelMap.h \
+		../../Pixel.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o Pixel.o Pixel.cc
+
+PixelMap.o: ../../pixelmap/PixelMap.cc ../../PixelMap.h \
+		../../Pixel.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o PixelMap.o PixelMap.cc
+
+RawDataCTX.o: ../../drsdaq/RawDataCTX.cc ../../drsdaq/RawDataCTX.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o RawDataCTX.o RawDataCTX.cc
+
+moc_GUI.o: moc_GUI.cpp 
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_GUI.o moc_GUI.cpp
+
+####### Install
+
+install:   FORCE
+
+uninstall:   FORCE
+
+FORCE:
+
Index: /tools/ddd/ddd.pro
===================================================================
--- /tools/ddd/ddd.pro	(revision 29)
+++ /tools/ddd/ddd.pro	(revision 29)
@@ -0,0 +1,14 @@
+######################################################################
+# Automatically generated by qmake (2.01a) Tue Mar 24 07:57:00 2009
+######################################################################
+
+TEMPLATE = app
+TARGET = 
+DEPENDPATH += .
+INCLUDEPATH += . /usr/local/qwt-5.1.1/include
+
+# Input
+HEADERS += GUI.h Pixel.h PixelMap.h RawDataCTX.h
+SOURCES += Functions.cpp GUI.cpp Pixel.cc PixelMap.cc RawDataCTX.cc
+
+QT += network
