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

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