source: fact/tools/Edd/Edd.cc @ 10280

Last change on this file since 10280 was 10280, checked in by ogrimm, 9 years ago
Separated Edd into generic Evidence part and FACT-specific part
File size: 28.8 KB
Line 
1/* ============================================================
2
3Edd - Evidence Data Display
4
5Qt-based graphical user interface for the Evidence contron system
6
7EddLineDisplay changes its background colour in case it display
8a DIM status service
9
10============================================================ */
11
12#include "Edd.h"
13
14QString DRSBoard = "drsdaq";
15std::string PixelMapText;
16
17extern class EddDim *Handler;
18
19////////////////////////
20// Event oscilloscope //
21////////////////////////
22
23// Constructor
24EventScope::EventScope(QWidget *P): EddBasePlot(P), PixelMap(PixelMapText, false) {
25
26  Name = DRSBoard+"/EventData";
27
28  Tmpfile = tmpfile();
29  if(Tmpfile == NULL) {
30    QMessageBox::warning(this, "Edd Message", "Could not open temporary file.", QMessageBox::Ok);
31  }
32
33  // Open file with RawDataCTX
34  RD = new RawDataCTX(true);
35  ErrCode = CTX_NOTOPEN;
36
37  // Context menu
38  PhysPipeAction = new QAction("Physical pipeline", this);
39  PhysPipeAction->setCheckable(true);
40  connect(PhysPipeAction, SIGNAL(triggered()), SLOT(PlotTraces()));
41  Menu->insertAction(StripAction, PhysPipeAction);
42
43  PersistanceAction = new QAction("Persistance", this);
44  PersistanceAction->setCheckable(true);
45  Menu->insertAction(StripAction, PersistanceAction);
46  Menu->removeAction(StripAction);
47
48  // Initial trace
49  AddTrace(0,0,0);
50
51  // Connect to DIM handler
52  if (connect(Handler, SIGNAL(YEP(QString, int, QByteArray, QString, QString)), SLOT(Update(QString, int, QByteArray, QString, QString))) == false) {
53    printf("Failed connection for %s\n", Name.toAscii().data());
54  }
55  SetActive(true);
56}
57
58// Destructor (items with parent widget are automatically deleted)
59EventScope::~EventScope() {
60
61  SetActive(false);
62  while (!List.isEmpty()) DeleteCurve(List.last().Signal);
63  delete RD;
64  if (Tmpfile != NULL) fclose(Tmpfile);
65} 
66
67// Add trace
68void EventScope::AddTrace(int Board, int Chip, int Channel) {
69
70  struct ItemDetails N;
71 
72  N.Signal = NewCurve(QString::number(Board)+","+QString::number(Chip)+","+ QString::number(Channel)+ " (" + ToPixel(0, Board, Chip, Channel) + ")");
73  N.Board = Board;
74  N.Chip = Chip;
75  N.Channel = Channel;
76  N.Trigger = new QwtPlotMarker();
77  N.Trigger->setSymbol(QwtSymbol(QwtSymbol::Diamond, QBrush(N.Signal->pen().color()), N.Signal->pen(), QSize(10,10)));
78  N.Trigger->attach(this);
79
80  if (List.isEmpty()) {
81    QPen Pen = N.Signal->pen();
82        Pen.setWidth(2);
83        N.Signal->setPen(Pen);
84  }
85  List.append(N);
86   
87  PlotTraces();
88}
89
90// Update last trace (to reflect current setting of spin boxes in DAQ page)
91void EventScope::UpdateFirst(int Board, int Chip, int Channel) {
92
93  if (List.isEmpty()) return;
94 
95  // Clear in case persistance was activated
96  ClearCurve(0);
97
98  List.first().Signal->setTitle(QString::number(Board)+","+QString::number(Chip)+","+ QString::number(Channel) + " (" + ToPixel(0, Board, Chip, Channel) + ")");
99  List.first().Board = Board;
100  List.first().Chip = Chip;
101  List.first().Channel = Channel;
102   
103  PlotTraces();
104}
105 
106// Update event buffer
107void EventScope::Update(QString Name, int Time, QByteArray Data, QString Format, QString) {
108 
109  if (Name != this->Name) return;
110
111  // Check if service available
112  if (!SetStatus(this, Name, Time, Format)) return;
113  if (Data.size() < (int) sizeof(RunHeader)) return;
114 
115  // Disconnect while processing to avoid queing of events
116  disconnect(Handler, SIGNAL(YEP(QString, int, QByteArray, QString, QString)), this, SLOT(Update(QString, int, QByteArray, QString, QString)));
117 
118  // Open tempory file and write event data to this file
119  QTemporaryFile File;
120  if (!File.open()) {
121        QMessageBox::warning(this, "Edd Message","Could not open temporary file.",QMessageBox::Ok);
122        return;
123  }
124  if (File.write(Data) == -1) {
125        QMessageBox::warning(this, "Edd Message","Could not write data to temporary file.",QMessageBox::Ok);
126        return; 
127  }
128
129  // Prepare temporary file for run header 
130  ftruncate(fileno(Tmpfile), 0);
131  rewind(Tmpfile);
132
133  // Open file with RawDataCTX
134  switch (ErrCode = RD->OpenDataFile(File.fileName().toAscii().data(), Tmpfile)) {
135    case CTX_FOPEN:             QMessageBox::warning(this, "Edd Message","Could not open file.",QMessageBox::Ok);
136                                                return;
137    case CTX_RHEADER:   QMessageBox::warning(this, "Edd Message","Could not read run header.",QMessageBox::Ok);
138                                        return;
139    case CTX_BSTRUCT:   QMessageBox::warning(this, "Edd Message","Could not read board structures.",QMessageBox::Ok);
140                                                return;
141        default: break;
142  }
143
144  // Emit signal containing run header
145  rewind(Tmpfile);
146  QTextStream Stream(Tmpfile);
147  emit(RunHeaderChanged(Stream.readAll()));
148
149  // Prepare temporary file for event header 
150  ftruncate(fileno(Tmpfile), 0);
151  rewind(Tmpfile);
152
153  // Write event header text to file
154  if (RD->ReadEvent(0, Tmpfile) != CTX_OK) {
155    QMessageBox::warning(this, "Edd Warning","Could not read event.",QMessageBox::Ok);
156    return;
157  }
158
159  // Add trigger cells to file
160  fprintf(Tmpfile, "\nTrigger cells:");
161  int *TrigCells = (int *) RD->Data;
162  for (unsigned int i=0; i<RD->RHeader->NBoards; i++) {
163    fprintf(Tmpfile, "\n Board %d   ", i);
164        for (unsigned int j=0; j<RD->RHeader->NChips; j++) fprintf(Tmpfile, "%d ", *(TrigCells++));
165  }
166
167  // Emit signal containing run header
168  rewind(Tmpfile);
169  emit(EventHeaderChanged(Stream.readAll()));
170
171  // Update display
172  PlotTraces();
173 
174  // Reconnect after processing
175  connect(Handler, SIGNAL(YEP(QString, int, QByteArray, QString, QString)), SLOT(Update(QString, int, QByteArray, QString, QString)));
176}
177
178// Update curves
179void EventScope::PlotTraces() {
180
181  double x,y;
182  unsigned int Cell, Trig;
183  static int Last = 0;
184 
185  // Only process if valid data in RawDataCTX class
186  if (ErrCode != CTX_OK) return;
187 
188  // Set x axis title
189  if (PhysPipeAction->isChecked()) setAxisTitle(QwtPlot::xBottom, "Time from start of pipeline (ns)");
190  else setAxisTitle(QwtPlot::xBottom, "Time from trigger minus one revolution (ns)");
191
192  // Loop through event data to update event scope
193  RunHeader *R = RD->RHeader;
194  for (int i=0; i<List.size(); i++) {
195
196        if (PersistanceAction->isChecked()) List[i].Signal->setStyle(QwtPlotCurve::Dots);
197        else {
198          ClearCurve(i);
199          List[i].Signal->setStyle(QwtPlotCurve::Lines);
200        }
201
202        // Check if current event contains requested trace
203    if (List[i].Board>=R->NBoards || List[i].Chip>=R->NChips || List[i].Channel>=R->NChannels) continue;
204
205        // Set trigger marker visibility
206        List[i].Trigger->setVisible(PhysPipeAction->isChecked());
207       
208        // Determine trigger cell
209        Trig = *((int *) RD->Data + List[i].Board*R->NChips + List[i].Chip);
210
211        // Calulate point of curve
212        for (unsigned int j=0; j<R->Samples; j++) {
213
214          if (PhysPipeAction->isChecked()) Cell = (j - Trig) % 1024;
215          else Cell = j;
216
217          x = j / RD->BStruct[List[i].Board].NomFreq;
218          y = *((short *) (RD->Data + R->NBoards*R->NChips*sizeof(int)) +
219                List[i].Board*R->NChips*R->NChannels*R->Samples + List[i].Chip*R->NChannels*R->Samples +
220                List[i].Channel*R->Samples + Cell) * RD->BStruct[List[i].Board].ScaleFactor;
221
222          AddPoint(i, x, y);
223         
224          // Set trigger point indicator
225          if (Trig == j) List[i].Trigger->setValue(x, y);       
226    }
227  }
228
229  // Limit update rate in persistance mode
230  if (!PersistanceAction->isChecked() || time(NULL) > Last) {
231    UpdatePlot();
232    Last = time(NULL);
233  }
234
235
236  // Loop through event data for pixel display
237  QVector<double> Pixel(R->NBoards*R->NChips*R->NChannels);
238  int Count = 0;
239
240  for (unsigned int Board=0; Board<R->NBoards; Board++) {
241  for (unsigned int Chip=0; Chip<R->NChips; Chip++) {
242  for (unsigned int Channel=0; Channel<R->NChannels; Channel++) {
243    Pixel[Count] = DBL_MIN;
244
245        for (unsigned int i=0; i<R->Samples; i++) {
246          y = *((short *) (RD->Data + R->NBoards*R->NChips*sizeof(int)) +
247                Board*R->NChips*R->NChannels*R->Samples + Chip*R->NChannels*R->Samples +
248                Channel*R->Samples + i) * RD->BStruct[Board].ScaleFactor;
249
250          if (y > Pixel[Count]) Pixel[Count] = y;
251    }
252        Count++;         
253  }}}
254 
255  emit(PixelData(Pixel));
256}
257
258// Remove list entry
259void EventScope::DeleteCurve(QwtPlotCurve *Curve) {
260
261  for (int i=0; i<List.size(); i++) if (List[i].Signal == Curve) {
262        delete List[i].Trigger;
263    List.removeAt(i);
264  }
265}
266
267// Set display active (if inactive, disconnect from server)
268void EventScope::SetActive(bool State) {
269
270  static bool Active = false;
271
272  if (State && !Active) Handler->Subscribe(DRSBoard+"/EventData");
273  if (!State && Active) Handler->Unsubscribe(DRSBoard+"/EventData");
274  Active = State;
275}
276
277// Translate FPA ID to Pixel ID (use '-' instead of PM_ERROR_CODE)
278QString EventScope::ToPixel(unsigned int Crate, unsigned int Board, unsigned int Patch, unsigned int Pixel) {
279 
280  if (FPA_to_Pixel(Crate, Board, Patch, Pixel) == PM_ERROR_CODE) return "-";
281  else return QString::number(FPA_to_Pixel(Crate, Board, Patch, Pixel));
282}
283 
284//------------------------------------------------------------------
285//**************************** Tab pages ***************************
286//------------------------------------------------------------------
287
288//
289// Environment page
290//
291TP_Environment::TP_Environment() {
292
293  QGridLayout *Layout = new QGridLayout(this);
294  setAttribute(Qt::WA_DeleteOnClose);
295
296  // Status display
297  EddLineDisplay *Line = new EddLineDisplay("ARDUINO/Message");
298  Line->setMaximumWidth(200);
299  Layout->addWidget(Line, 0, 0, 1, 2);     
300
301  // Generate plot and data displays
302  EddPlot *Plot = new EddPlot();
303  for (int i=0; i<10; i++) {
304    Line = new EddLineDisplay("ARDUINO/Data", i);
305    Layout->addWidget(Line, i%5+1, i/5, 1, 1);
306    Plot->AddService("ARDUINO/Data", i);
307  }
308  Layout->addWidget(Plot, 0, 2, 9, 7);     
309
310  // Night sky monitor
311  Line = new EddLineDisplay("SQM/Message");
312  Line->setMaximumWidth(200);
313  Layout->addWidget(Line, 6, 0, 1, 2);     
314
315  Line = new EddLineDisplay("SQM/NSB");
316  Layout->addWidget(Line, 7, 0, 1, 1);         
317}
318
319//
320// Bias page
321//
322TP_Bias::TP_Bias() {
323
324  QGridLayout *Layout = new QGridLayout(this);
325  setAttribute(Qt::WA_DeleteOnClose);
326  EddLineDisplay *Line;
327 
328  EddPlot *Plot = new EddPlot();
329  Plot->setMinimumWidth(400);
330  for (int i=0; i<18; i++) {
331    Line = new EddLineDisplay("Bias/VOLT/ID00", i+64);
332    Layout->addWidget(Line, i%9+1, 0+i/9, 1, 1);
333    Plot->AddService("Bias/VOLT/ID00", i+64);
334
335    Line = new EddLineDisplay("Bias/VOLT/ID00", i+96);
336    Layout->addWidget(Line, i%9+1, 2+i/9, 1, 1);
337    Plot->AddService("Bias/VOLT/ID00",i+96);
338  }
339
340  Layout->addWidget(Plot, 0, 4, 12, 3);
341  Line = new EddLineDisplay("Bias/Message");
342  Line->setMaximumWidth(200);
343  Layout->addWidget(Line, 0, 0, 1, 3);     
344
345  EddCommand *Command = new EddCommand("Bias/Command");
346  Layout->addWidget(Command, 10, 0, 1, 4);   
347
348  EddText *Text = new EddText("Bias/ConsoleOut", true);
349  Text->setFixedWidth(400);
350  Layout->addWidget(Text, 11, 0, 4, 4);
351
352  // Current page
353  EddWindow *Button = new EddWindow("Currents", "Edd - Edd - Bias currents");
354  Layout->addWidget(Button, 13, 4, 1, 1);     
355
356  Plot = new EddPlot();
357
358  for (int i=0; i<36; i++) {
359    Line = new EddLineDisplay("Bias/MICROAMP/ID00", i+64);
360        Line->setMaximumWidth(60);
361    Button->Layout()->addWidget(Line, i%9, 0+i/9, 1, 1);
362    Plot->AddService("Bias/MICROAMP/ID00", i+64);       
363  }
364  Button->Layout()->addWidget(Plot, 0, 4, 30, 12);
365}
366
367//
368// Feedback page
369//
370TP_Feedback::TP_Feedback() {
371
372  setAttribute(Qt::WA_DeleteOnClose);
373  QGridLayout *Layout = new QGridLayout(this);
374  EddLineDisplay *Line;
375
376  EddPlot *Plot = new EddPlot();
377  for (int i=0; i<36; i++) {
378    Line = new EddLineDisplay("Feedback/Average", i);
379        Line->setMaximumWidth(60);
380    Layout->addWidget(Line, i%9+2, 0+i/9, 1, 1);
381    Plot->AddService("Feedback/Average", i);
382  }
383  Layout->addWidget(Plot, 0, 4, 12, 10);
384
385  Line = new EddLineDisplay("Feedback/Message");
386  Line->setMaximumWidth(200);
387  Layout->addWidget(Line, 0, 0, 1, 2);     
388
389  Line = new EddLineDisplay("Feedback/State");
390  Line->setMaximumWidth(150);
391  Layout->addWidget(Line, 1, 0, 1, 2);     
392  Line = new EddLineDisplay("Feedback/Count");
393  Line->setMaximumWidth(60);
394  Layout->addWidget(Line, 1, 2);     
395
396  // Details page
397  EddWindow *Button = new EddWindow("Details", "Edd - Feedback Details");
398  Layout->addWidget(Button, 12, 0, 1, 1);     
399
400  Plot = new EddPlot();
401
402  for (int i=0; i<36; i++) {
403    Line = new EddLineDisplay("Feedback/Sigma", i);
404        Line->setMaximumWidth(60);
405    Button->Layout()->addWidget(Line, i%9, 0+i/9, 1, 1);
406    Plot->AddService("Feedback/Sigma", i);
407       
408    Line = new EddLineDisplay("Feedback/Target", i);
409        Line->setMaximumWidth(60);
410    Button->Layout()->addWidget(Line, i%9+10, 0+i/9, 1, 1);
411       
412        Line = new EddLineDisplay("Feedback/Response", i);
413        Line->setMaximumWidth(60);
414    Button->Layout()->addWidget(Line, i%9+20, 0+i/9, 1, 1);
415  }
416  Button->Layout()->addWidget(Plot, 0, 4, 30, 12);
417}
418
419
420//
421// FADctrl page
422//
423TP_FADctrl::TP_FADctrl() {
424
425  QString Board;
426
427  QScrollArea *scrollArea = new QScrollArea;
428  scrollArea->setBackgroundRole(QPalette::Dark);
429  scrollArea->setWidget(this);
430  setMinimumSize(QSize(0,0)); 
431 
432  QGridLayout *Layout = new QGridLayout(this);
433  setAttribute(Qt::WA_DeleteOnClose);
434  EddLineDisplay *Line;
435
436  Line = new EddLineDisplay("FADctrl/Message");
437  Line->setMaximumWidth(200);
438  Layout->addWidget(Line, 0, 0, 1, 3);     
439
440  EddCommand *Command = new EddCommand("FADctrl/Command");
441  Layout->addWidget(Command, 1, 0, 1, 3);   
442
443  EddText *Text = new EddText("FADctrl/ConsoleOut", true);
444  Text->setFixedWidth(400);
445  Layout->addWidget(Text, 2, 0, 4, 4);
446
447  EddPlot *Plot = new EddPlot();
448  Layout->addWidget(Plot, 2, 4, 4, 4);
449
450  // Details page
451  EddWindow *Button[2];
452  Button[0] = new EddWindow("Boards 0-19", "Edd - FADctrl - Board 0 to 19");
453  Button[1] = new EddWindow("Boards 20-39", "Edd - FADctrl - Board 20 to 39");
454  Layout->addWidget(Button[0], 7, 0, 1, 1);     
455  Layout->addWidget(Button[1], 7, 1, 1, 1);     
456
457  for (int i=0; i<40; i++) {
458    Board = Board.sprintf("FADctrl/Board%.2d/", i);
459    Line = new EddLineDisplay(Board+"Server");
460        Line->setMinimumWidth(90);
461    Button[i/20]->Layout()->addWidget(Line, i+7, 0, 1, 1);
462
463    Line = new EddLineDisplay(Board+"BoardID");
464        Line->setMaximumWidth(30);
465    Button[i/20]->Layout()->addWidget(Line, i+7, 1, 1, 1);
466
467    Line = new EddLineDisplay(Board+"Frequency");
468        Line->setMaximumWidth(40);
469    Button[i/20]->Layout()->addWidget(Line, i+7, 2, 1, 1);
470
471        for (int j=0; j<4; j++) {
472          Plot->AddService(Board+"Temperature", j);
473
474      Line = new EddLineDisplay(Board+"Temperature", j);
475          Line->setMinimumWidth(40);
476      Button[i/20]->Layout()->addWidget(Line, i+7, 3+j, 1, 1);
477        }
478
479        for (int j=0; j<8; j++) {
480      Line = new EddLineDisplay(Board+"DAC", j);
481          Line->setMinimumWidth(40);
482      Button[i/20]->Layout()->addWidget(Line, i+7, 7+j, 1, 1);
483        }
484
485        Line = new EddLineDisplay(Board+"Status");
486        Line->setMaximumWidth(150);
487    Button[i/20]->Layout()->addWidget(Line, i+7, 15, 1, 1);
488  }
489}
490
491//
492// Event scope page
493//
494TP_DAQ::TP_DAQ() {
495
496  EddLineDisplay *Line;
497
498  setAttribute(Qt::WA_DeleteOnClose);
499  QGridLayout *Layout = new QGridLayout(this);
500
501  // Run-related information
502  Line = new EddLineDisplay("drsdaq/RunNumber");
503  Line->setMaximumWidth(100);
504  Layout->addWidget(Line, 0, 1, 1, 1);     
505  Line = new EddLineDisplay(DRSBoard+"/EventNumber");
506  Line->setMaximumWidth(100);
507  Layout->addWidget(Line, 0, 2, 1, 1);     
508  Line = new EddLineDisplay("drsdaq/RunSizeMB");
509  Line->setMaximumWidth(100);
510  Layout->addWidget(Line, 0, 3, 1, 1);     
511  Line = new EddLineDisplay("drsdaq/FileSizeMB");
512  Line->setMaximumWidth(100);
513  Layout->addWidget(Line, 0, 4, 1, 1);     
514  Line = new EddLineDisplay("drsdaq/FileName");
515  Line->setMaximumWidth(200);
516  Layout->addWidget(Line, 0, 5, 1, 1);     
517
518  // Message service
519  Line = new EddLineDisplay(DRSBoard+"/Message");
520  Line->setMaximumWidth(200);
521  Layout->addWidget(Line, 1, 1, 1, 2);     
522
523  // Event scope
524  Scope = new EventScope;
525  Scope->setMinimumWidth(700);
526
527  // Text boxes for run and event header
528  RunHeaderDisplay = new QPlainTextEdit();
529  EventHeaderDisplay = new QPlainTextEdit();
530  RunHeaderDisplay->setReadOnly(true);
531  EventHeaderDisplay->setReadOnly(true);
532
533  // Tab widget
534  QTabWidget *TabWidget = new QTabWidget();
535  TabWidget->addTab(Scope, "&Signals");
536  TabWidget->addTab(RunHeaderDisplay, "&Run Header");
537  TabWidget->addTab(EventHeaderDisplay, "&Event Header");
538  Layout->addWidget(TabWidget, 2, 1, 6, 5);
539
540  // Channel number
541  Channel = new QSpinBox;
542  connect(Channel, SIGNAL(valueChanged(int)), SLOT(UpdateScope(int)));
543  Channel->setToolTip("DRS channel number");
544
545  // Chip number
546  Chip = new QSpinBox;
547  connect(Chip, SIGNAL(valueChanged(int)), SLOT(UpdateScope(int)));
548  Chip->setToolTip("DRS chip number");
549
550  // Board number
551  Board = new QSpinBox;
552  connect(Board, SIGNAL(valueChanged(int)), SLOT(UpdateScope(int)));
553  Board->setToolTip("DRS board number");
554
555  // Pixel ID
556  PixelID = new QSpinBox;
557  PixelID->setMaximumWidth(60);
558  PixelID->setRange(-1, 9999);
559  PixelID->setSpecialValueText("n/a");
560  connect(PixelID, SIGNAL(valueChanged(int)), SLOT(TranslatePixelID(int)));
561  PixelID->setToolTip("Pixel identification");
562 
563  // Layout of pixel addressing widgets
564  QFormLayout *FormLayout = new QFormLayout();
565  FormLayout->setRowWrapPolicy(QFormLayout::WrapAllRows);
566  FormLayout->addRow("Board", Board);
567  FormLayout->addRow("Chip", Chip);
568  FormLayout->addRow("Channel", Channel);
569  FormLayout->addRow("Pixel ID", PixelID);
570  Layout->addLayout(FormLayout, 0, 0, 4, 1);
571 
572  // Add trace permanently
573  QPushButton *Button = new QPushButton("Keep trace");
574  Button->setToolTip("Keep trace in display");
575  Button->setMaximumWidth(80);
576  Layout->addWidget(Button, 4, 0);
577  connect(Button, SIGNAL(clicked()), SLOT(KeepCurrent()));
578
579  // Stop/start
580  StartStopButton = new QPushButton("Stop");
581  StartStopButton->setToolTip("Start/stop display");
582  StartStopButton->setMaximumWidth(80);
583  StartStopButton->setCheckable(true);
584  QPalette Palette = StartStopButton->palette();
585  Palette.setColor(QPalette::ButtonText, Qt::blue);
586  Palette.setColor(QPalette::Button, Qt::green);
587  StartStopButton->setPalette(Palette);
588  StartStopButton->setFont(QFont("Times", 10, QFont::Bold));
589  Layout->addWidget(StartStopButton, 6, 0);
590  connect(StartStopButton, SIGNAL(toggled(bool)), SLOT(StartStop(bool)));
591
592
593  // Event display page
594  EddWindow *New = new EddWindow("Pixel display", "Edd - Event display");
595  New->setFont(QFont("Times", 10, QFont::Bold));
596  New->setMaximumWidth(80);
597  New->setToolTip("Show event display window");
598  Layout->addWidget(New, 7, 0);     
599 
600  Pixel = new QPushButton *[MAXPIXEL];
601  int Count = 0;
602  double x,y;
603 
604  for (int ix=-22; ix<=22; ix++) for (int iy=-19; iy<=20; iy++) { 
605    if (Count == MAXPIXEL) break;
606       
607        x = ix*0.866;
608        y = iy - (ix%2==0 ? 0.5:0);
609    if ((pow(x,2)+pow(y,2) >= 395) && !(abs(ix)==22 && iy==7)) continue;
610       
611    //Pixel[Count] = new QPushButton(Display);
612    Pixel[Count] = new QPushButton(New->Window());
613        Pixel[Count]->setAutoFillBackground(true);
614        Pixel[Count]->setGeometry((int) (x*12.5 + 250), (int) (y*12.5 + 250), 10, 10);
615        Pixel[Count]->show();
616        Count++;
617  }
618
619  // Connect slots for updating displays
620  connect(Scope, SIGNAL(RunHeaderChanged(QString)), RunHeaderDisplay, SLOT(setPlainText(QString)));
621  connect(Scope, SIGNAL(EventHeaderChanged(QString)), EventHeaderDisplay, SLOT(setPlainText(QString)));
622
623  StartStop(false);
624  connect(Scope, SIGNAL(PixelData(QVector<double>)), SLOT(SetPixelData(QVector<double>)));
625
626  // Call to get initial pixel ID correct
627  UpdateScope(0);
628}
629
630TP_DAQ::~TP_DAQ() {
631
632  delete[] Pixel;
633}
634
635// Translate pixel ID to board, chip, channel
636void TP_DAQ::TranslatePixelID(int ID) {
637
638  // setValue() below will call UpdateScope() through signal, therefore need to store numbers here
639  unsigned int BoardNo = Scope->Pixel_to_FPAboard(ID);
640  unsigned int PatchNo = Scope->Pixel_to_FPApatch(ID);
641  unsigned int PixelNo = Scope->Pixel_to_FPApixel(ID);
642 
643  if (BoardNo == Scope->PM_ERROR_CODE) PixelID->setValue(-1);
644  else {
645    Board->setValue(BoardNo);
646    Chip->setValue(PatchNo);
647    Channel->setValue(PixelNo);
648  }
649}
650
651// Keep current trace
652void TP_DAQ::KeepCurrent() {
653
654  Scope->AddTrace(Board->value(), Chip->value(), Channel->value());
655}
656
657// Start/stop event acquisition
658void TP_DAQ::StartStop(bool State) {
659
660  Scope->SetActive(!State);
661  StartStopButton->setText(State ? "Start" : "Stop");
662  if (!State) connect(Handler, SIGNAL(YEP(QString, int, QByteArray, QString, QString)), Scope, SLOT(Update(QString, int, QByteArray, QString, QString)));
663  else disconnect(Handler, SIGNAL(YEP(QString, int, QByteArray, QString, QString)), Scope, SLOT(Update(QString, int, QByteArray, QString, QString)));
664}
665
666// Update event scope
667void TP_DAQ::UpdateScope(int) {
668
669  // Update pixel ID
670  PixelID->setValue(Scope->FPA_to_Pixel(0, Board->value(), Chip->value(), Channel->value()));
671  if (PixelID->value() == (int) Scope->PM_ERROR_CODE) PixelID->setValue(-1);
672 
673  // Update first trace
674  Scope->UpdateFirst(Board->value(), Chip->value(), Channel->value());
675}
676
677// Show/hide pixel display
678void TP_DAQ::ShowPixelDisplay() {
679
680  Display->show();
681  Display->raise();
682}
683
684void TP_DAQ::SetPixelData(QVector<double> Data) {
685
686  QwtLinearColorMap Map;
687
688  for (int i=0; i<Data.size(); i++) {
689        Pixel[i]->setPalette(QPalette(Map.color(QwtDoubleInterval(300, 400), Data[i])));
690  }
691}
692
693
694//
695// Evidence page
696//
697TP_Evidence::TP_Evidence() {
698
699  setAttribute(Qt::WA_DeleteOnClose);
700  QGridLayout *Layout = new QGridLayout(this);
701  EddLineDisplay *Line;
702  EddText *Text;
703 
704  Line = new EddLineDisplay("Alarm/Message");
705  Line->setMaximumWidth(200);
706  Layout->addWidget(Line, 0, 0, 1, 2);     
707
708  QPushButton *Button = new QPushButton();
709  Button->setText("ON/OFF");
710  Button->setCheckable(true);
711  connect(Button, SIGNAL(toggled(bool)), SLOT(ToggleAlarm(bool)));
712  Layout->addWidget(Button, 0, 3, 1, 1);
713
714  Line = new EddLineDisplay("Alarm/MasterAlarm");
715  Layout->addWidget(Line, 0, 1, 1, 1);
716
717  Text = new EddText("Alarm/Summary", true);
718  Text->Accumulate = false;
719  Text->setMaximumWidth(200);
720  Text->setMaximumHeight(150);
721  Layout->addWidget(Text, 1, 0, 1, 2);
722
723  Line = new EddLineDisplay("DColl/Message");
724  Line->setMaximumWidth(200);
725  Layout->addWidget(Line, 3, 0, 1, 2);     
726
727  Line = new EddLineDisplay("DColl/DataSizeMB");
728  Layout->addWidget(Line, 4, 0, 1, 1);
729
730  Line = new EddLineDisplay("DColl/LogSizeMB");
731  Layout->addWidget(Line, 4, 1, 1, 1);
732
733  Line = new EddLineDisplay("DColl/CurrentFile");
734  Line->setMaximumWidth(400);
735  Layout->addWidget(Line, 5, 0, 1, 3);
736
737  Line = new EddLineDisplay("Config/Message");
738  Line->setMaximumWidth(200);
739  Layout->addWidget(Line, 6, 0, 1, 2);     
740
741  Line = new EddLineDisplay("Config/ModifyTime");
742  Line->setMaximumWidth(200);
743  Line->ShowAsTime = true;
744  Layout->addWidget(Line, 7, 0, 1, 1);
745
746  Button = new QPushButton();
747  Button->setText("eLogBook");
748  connect(Button, SIGNAL(released()), SLOT(StartELog()));
749  Layout->addWidget(Button, 6, 1, 1, 1);
750
751  Button = new QPushButton();
752  Button->setText("Start DIM browser");
753  connect(Button, SIGNAL(released()), SLOT(StartDIMBrowser()));
754  Layout->addWidget(Button, 7, 1, 1, 1);
755
756  Line = new EddLineDisplay("Edd/Rate_kBSec");
757  Layout->addWidget(Line, 8, 0, 1, 1);
758}
759
760// Toggle state of Alarm server
761void TP_Evidence::ToggleAlarm(bool State) {
762
763  if (State) DimClient::sendCommandNB((char *) "Alarm/Switch", (char *) "off");
764  else DimClient::sendCommandNB((char *) "Alarm/Switch", (char *) "on");
765}
766 
767// Start DIM Browser
768void TP_Evidence::StartDIMBrowser() {
769
770  QProcess::startDetached("did", QStringList(), QString(getenv("DIMDIR"))+"/linux/");
771}
772
773// Start eLogBook
774void TP_Evidence::StartELog() {
775
776  QProcess::startDetached("firefox http://fact.ethz.ch/FACTelog/index.jsp");
777}
778
779 
780//--------------------------------------------------------------------
781//*************************** Main GUI *******************************
782//--------------------------------------------------------------------
783//
784// All widgets have ultimately Central as parent.
785//
786GUI::GUI() {
787
788  Handler = new EddDim;
789
790  // Arrangement in tabs
791  TabWidget = new QTabWidget(this);
792  TabWidget->setTabsClosable(true);
793  connect(TabWidget, SIGNAL(tabCloseRequested(int)), SLOT(DetachTab(int)));
794  TabWidget->addTab(new TP_DAQ, "Event scope " + DRSBoard);
795  TabWidget->addTab(new TP_FADctrl, "FADctrl");
796  TabWidget->addTab(new TP_Bias, "Bias");
797  TabWidget->addTab(new TP_Feedback, "Feedback");
798  TabWidget->addTab(new TP_Environment, "Environment");
799  TabWidget->addTab(new TP_Evidence, "Evidence");
800
801  // Set features of main window
802  setStatusBar(new QStatusBar(this));
803  setWindowTitle("Edd - Evidence Data Display");
804  setCentralWidget(TabWidget);
805
806  // Menu bar
807  QMenu* Menu = menuBar()->addMenu("&Menu");
808  Menu->addAction("New history plot", this, SLOT(MenuNewHistory()));
809  Menu->addSeparator();
810  Menu->addAction("About", this, SLOT(MenuAbout()));
811  Menu->addSeparator();
812  QAction* QuitAction = Menu->addAction("Quit", qApp, SLOT(quit()));
813  QuitAction->setShortcut(Qt::CTRL + Qt::Key_Q);
814
815  // Size and show main window
816  QSize Size = TabWidget->sizeHint()*1.1;
817  Size = Size.boundedTo(QApplication::desktop()->screenGeometry(this).size()*0.6);
818  //setMaximumSize(QApplication::desktop()->screenGeometry(this).size()*0.9);
819  TabWidget->resize(Size);
820TabWidget->setMaximumSize(QApplication::desktop()->screenGeometry(this).size()*0.9);
821  show();
822
823  // Set timer to regularly check the master alarm
824  QTimer *Timer = new QTimer(this);
825  connect(Timer, SIGNAL(timeout()), this, SLOT(CheckAlarm()));
826  Timer->start(5000);
827} 
828   
829
830void GUI::MenuAbout() {
831  QString Rev(SVN_REVISION);
832  Rev.remove(0,1).chop(2);
833 
834  QMessageBox::about(this, "About Edd","Evidence Data Display\n\n"
835    "Written by Oliver Grimm, IPP, ETH Zurich\n"
836    "This version compiled "__DATE__" ("+Rev+")\n\n"
837    "Graphical user interface implemented with Qt and Qwt.\n"
838    "Evidence control system based on DIM (http://dim.web.cern.ch).\n\n"
839    "Comments to oliver.grimm@phys.ethz.ch.");
840}
841
842// Open request for new history plot
843void GUI::MenuNewHistory() {
844
845  QStringList List;
846  char *Name, *Format;
847  int Type;
848  bool OK;
849
850  // Find all DIM services and sort
851  getServices("*");
852  while ((Type = getNextService(Name, Format)) != 0) {
853    if (Type==DimSERVICE) List.append(Name);
854  }
855  List.sort();
856
857  // Open dialog and open history window
858  QString Result = QInputDialog::getItem(this, "Edd Request",
859    "Enter DIM service name", List, 0, true, &OK);
860  if (OK && !Result.isEmpty()) {
861    Result = Result.trimmed();
862    QWidget *Hist = OpenHistory(Result.toAscii().data(), 0);
863    if (Hist != NULL) Hist->show();
864  }
865}
866
867// Open tab as separate window
868void GUI::DetachTab(int Tab) {
869
870  QWidget *W = NULL;
871  QMainWindow *M = new QMainWindow;
872
873  M->setCentralWidget(new QWidget(M));
874  M->setStatusBar(new QStatusBar(M));
875
876  switch(Tab) {
877        case 0: W = new TP_DAQ; break;
878        case 1: W = new TP_Bias; break;
879        case 2: W = new TP_Feedback; break;
880        case 3: W = new TP_Environment; break;
881        case 4: W = new TP_Evidence; break;
882        default: break;
883  }
884
885  if (W == NULL) {
886    delete M->centralWidget();
887        delete M;
888        return;
889  }
890
891  W->setParent(M);
892  M->resize(size());
893  M->setWindowTitle("Edd - " + TabWidget->tabText(Tab));
894  M->show();
895}
896
897// Check alarm level and if Alarm server is alive
898void GUI::CheckAlarm() {
899
900  static int WarnedLevel = 0;
901  static bool AlarmServerWarned = false;
902
903  // === Check service Alarm/MasterAlarm ===
904  DimCurrentInfo MasterAlarm("Alarm/MasterAlarm", -1);
905
906  if (MasterAlarm.getInt() > WarnedLevel) {
907        QSound::play(QApplication::applicationDirPath() + "/Error.wav");
908
909    // Construct warning message box
910        QMessageBox Box;
911        Box.setWindowTitle("Edd Alarm");
912        Box.setText("Service 'Alarm/MasterAlarm' is at " + QString::number(MasterAlarm.getInt()));
913        Box.setInformativeText("Warn again for the same alarm level?");
914        Box.setIcon(QMessageBox::Warning);
915        Box.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
916        Box.setDefaultButton(QMessageBox::No);
917
918        // Check if user wants to reset warned level
919        if (Box.exec() == QMessageBox::Yes) WarnedLevel = 0;
920        else WarnedLevel = MasterAlarm.getInt();
921  }
922
923  // If MasterAlam decreased, lower also warned level
924  if (MasterAlarm.getInt() < WarnedLevel && MasterAlarm.getInt() >=0 ) WarnedLevel = MasterAlarm.getInt();
925 
926  // === Check Alarm server ===
927  DimCurrentInfo ServerList("DIS_DNS/SERVER_LIST", NO_LINK);
928  std::string Result = EvidenceServer::ToString((char *) "C", ServerList.getData(), ServerList.getSize());
929
930  // Warn if SERVER_LIST does not contain alarm server
931  if (Result.find("Alarm@") == std::string::npos && !AlarmServerWarned) {
932        QMessageBox Box;
933        Box.setWindowTitle("Edd Alarm");
934        Box.setText("Alarm server is unavailable or in error");
935        Box.setIcon(QMessageBox::Critical);
936        Box.setStandardButtons(QMessageBox::Ok);
937        Box.setDefaultButton(QMessageBox::Ok);
938        Box.exec();
939
940        AlarmServerWarned = true;
941  }
942 
943  if (Result.find("Alarm@") != std::string::npos) AlarmServerWarned = false; 
944}
945
946// Quit application when clicking close button on window
947void GUI::closeEvent(QCloseEvent *) {
948
949  qApp->quit();
950}
951
952
953//
954//**************************** Main program ***************************
955//
956int main(int argc, char *argv[]) {
957
958  if (argc > 1) DRSBoard = "FADctrl";
959
960  // Make RPC to get pixelmap
961  DimRpcInfo RPC((char *) "ConfigRequest", (char *) "");
962  RPC.setData((char *) "Misc PixelMap");
963  PixelMapText = std::string(RPC.getString(), RPC.getSize());
964
965  QApplication app(argc, argv); 
966  GUI MainWindow;
967
968  return app.exec();
969}
Note: See TracBrowser for help on using the repository browser.