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

Last change on this file since 11000 was 10984, checked in by ogrimm, 13 years ago
Edd allows to set plot update rate
File size: 31.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
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(QString Name, int Time, QByteArray Data, QString Format, QString) {
114
115 if (Name != this->Name) return;
116
117 // Check if service available
118 if (!SetStatus(this, Name, Time, Format)) return;
119 if (Data.size() < (int) sizeof(RunHeader)) return;
120
121 // Disconnect while processing to avoid queing of events
122 disconnect(Handler, SIGNAL(YEP(QString, int, QByteArray, QString, QString)), this, SLOT(Update(QString, int, QByteArray, QString, QString)));
123
124 // Clear temporary file and write event data to this file
125 File.resize(0);
126 if (File.write(Data) == -1) {
127 QMessageBox::warning(this, "Edd Message","Could not write data to temporary file.",QMessageBox::Ok);
128 return;
129 }
130
131 // Open temporary raw data file
132 OpenRawFile(File.fileName());
133
134 // Reconnect after processing
135 connect(Handler, SIGNAL(YEP(QString, int, QByteArray, QString, QString)), SLOT(Update(QString, int, QByteArray, QString, QString)));
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(0);
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) {
318 Handler->Subscribe(DRSBoard+"/EventData");
319 connect(Handler, SIGNAL(YEP(QString, int, QByteArray, QString, QString)), SLOT(Update(QString, int, QByteArray, QString, QString)));
320 }
321 if (!State && Active) {
322 Handler->Unsubscribe(DRSBoard+"/EventData");
323 disconnect(Handler, SIGNAL(YEP(QString, int, QByteArray, QString, QString)), this, SLOT(Update(QString, int, QByteArray, QString, QString)));
324 }
325 Active = State;
326}
327
328// Translate FPA ID to Pixel ID (use '-' instead of PM_ERROR_CODE)
329QString EventScope::ToPixel(unsigned int Crate, unsigned int Board, unsigned int Patch, unsigned int Pixel) {
330
331 if (FPA_to_Pixel(Crate, Board, Patch, Pixel) == PM_ERROR_CODE) return "-";
332 else return QString::number(FPA_to_Pixel(Crate, Board, Patch, Pixel));
333}
334
335//------------------------------------------------------------------
336//**************************** Tab pages ***************************
337//------------------------------------------------------------------
338
339//
340// Environment page (For M0, server was called ARDUINO)
341//
342TP_Environment::TP_Environment() {
343
344 QGridLayout *Layout = new QGridLayout(this);
345 setAttribute(Qt::WA_DeleteOnClose);
346
347 // Status display
348 EddLineDisplay *Line = new EddLineDisplay("FSCctrl/Message");
349 Line->setMaximumWidth(300);
350 Layout->addWidget(Line, 0, 0, 1, 4);
351
352 Line = new EddLineDisplay("FSCctrl/Time");
353 Layout->addWidget(Line, 0, 5, 1, 2);
354
355 // Temperatures
356 EddPlot *Plot = new EddPlot();
357 for (int i=0; i<64; i++) {
358 Line = new EddLineDisplay("FSCctrl/Temperature", i);
359 Line->setMaximumWidth(50);
360 Layout->addWidget(Line, i/8+1, i%8);
361 Plot->AddService("FSCctrl/Temperature", i);
362 }
363 Layout->addWidget(Plot, 0, 10, 22, 15);
364
365 // Voltages and currents
366 for (int i=0; i<40; i++) {
367 Line = new EddLineDisplay("FSCctrl/Voltage", i);
368 Line->setMaximumWidth(50);
369 Layout->addWidget(Line, i/8+10, i%8);
370
371 Line = new EddLineDisplay("FSCctrl/Current", i);
372 Line->setMaximumWidth(50);
373 Layout->addWidget(Line, i/8+16, i%8);
374 }
375
376 // Night sky monitor
377 Line = new EddLineDisplay("SQM/Message");
378 Line->setMaximumWidth(300);
379 Layout->addWidget(Line, 22, 0, 1, 4);
380
381 Line = new EddLineDisplay("SQM/NSB");
382 Layout->addWidget(Line, 22, 5, 1, 2);
383}
384
385//
386// Bias page
387//
388TP_Bias::TP_Bias() {
389
390 QGridLayout *Layout = new QGridLayout(this);
391 setAttribute(Qt::WA_DeleteOnClose);
392 EddLineDisplay *Line;
393
394 EddPlot *Plot = new EddPlot();
395 Plot->setMinimumWidth(400);
396 for (int i=0; i<18; i++) {
397 Line = new EddLineDisplay("Bias/VOLT/ID00", i+64);
398 Layout->addWidget(Line, i%9+1, 0+i/9, 1, 1);
399 Plot->AddService("Bias/VOLT/ID00", i+64);
400
401 Line = new EddLineDisplay("Bias/VOLT/ID00", i+96);
402 Layout->addWidget(Line, i%9+1, 2+i/9, 1, 1);
403 Plot->AddService("Bias/VOLT/ID00",i+96);
404 }
405
406 Layout->addWidget(Plot, 0, 4, 12, 3);
407 Line = new EddLineDisplay("Bias/Message");
408 Line->setMaximumWidth(200);
409 Layout->addWidget(Line, 0, 0, 1, 3);
410
411 EddCommand *Command = new EddCommand("Bias/Command");
412 Layout->addWidget(Command, 10, 0, 1, 4);
413
414 EddText *Text = new EddText("Bias/ConsoleOut", true);
415 Text->setFixedWidth(400);
416 Layout->addWidget(Text, 11, 0, 4, 4);
417
418 // Current page
419 EddWindow *Button = new EddWindow("Currents", "Edd - Edd - Bias currents");
420 Layout->addWidget(Button, 13, 4, 1, 1);
421
422 Plot = new EddPlot();
423
424 for (int i=0; i<36; i++) {
425 Line = new EddLineDisplay("Bias/MICROAMP/ID00", i+64);
426 Line->setMaximumWidth(60);
427 Button->Layout()->addWidget(Line, i%9, 0+i/9, 1, 1);
428 Plot->AddService("Bias/MICROAMP/ID00", i+64);
429 }
430 Button->Layout()->addWidget(Plot, 0, 4, 30, 12);
431}
432
433//
434// Feedback page
435//
436TP_Feedback::TP_Feedback() {
437
438 setAttribute(Qt::WA_DeleteOnClose);
439 QGridLayout *Layout = new QGridLayout(this);
440 EddLineDisplay *Line;
441
442 EddPlot *Plot = new EddPlot();
443 for (int i=0; i<36; i++) {
444 Line = new EddLineDisplay("Feedback/Average", i);
445 Line->setMaximumWidth(60);
446 Layout->addWidget(Line, i%9+2, 0+i/9, 1, 1);
447 Plot->AddService("Feedback/Average", i);
448 }
449 Layout->addWidget(Plot, 0, 4, 12, 10);
450
451 Line = new EddLineDisplay("Feedback/Message");
452 Line->setMaximumWidth(200);
453 Layout->addWidget(Line, 0, 0, 1, 2);
454
455 Line = new EddLineDisplay("Feedback/State");
456 Line->setMaximumWidth(150);
457 Layout->addWidget(Line, 1, 0, 1, 2);
458 Line = new EddLineDisplay("Feedback/Count");
459 Line->setMaximumWidth(60);
460 Layout->addWidget(Line, 1, 2);
461
462 // Details page
463 EddWindow *Button = new EddWindow("Details", "Edd - Feedback Details");
464 Layout->addWidget(Button, 12, 0, 1, 1);
465
466 Plot = new EddPlot();
467
468 for (int i=0; i<36; i++) {
469 Line = new EddLineDisplay("Feedback/Sigma", i);
470 Line->setMaximumWidth(60);
471 Button->Layout()->addWidget(Line, i%9, 0+i/9, 1, 1);
472 Plot->AddService("Feedback/Sigma", i);
473
474 Line = new EddLineDisplay("Feedback/Target", i);
475 Line->setMaximumWidth(60);
476 Button->Layout()->addWidget(Line, i%9+10, 0+i/9, 1, 1);
477
478 Line = new EddLineDisplay("Feedback/Response", i);
479 Line->setMaximumWidth(60);
480 Button->Layout()->addWidget(Line, i%9+20, 0+i/9, 1, 1);
481 }
482 Button->Layout()->addWidget(Plot, 0, 4, 30, 12);
483}
484
485
486//
487// FADctrl page
488//
489TP_FADctrl::TP_FADctrl() {
490
491 QString Board;
492
493 QScrollArea *scrollArea = new QScrollArea;
494 scrollArea->setBackgroundRole(QPalette::Dark);
495 scrollArea->setWidget(this);
496 setMinimumSize(QSize(0,0));
497
498 QGridLayout *Layout = new QGridLayout(this);
499 setAttribute(Qt::WA_DeleteOnClose);
500 EddLineDisplay *Line;
501
502 Line = new EddLineDisplay("FADctrl/Message");
503 Line->setMaximumWidth(200);
504 Layout->addWidget(Line, 0, 0, 1, 3);
505
506 EddCommand *Command = new EddCommand("FADctrl/Command");
507 Layout->addWidget(Command, 1, 0, 1, 3);
508
509 EddText *Text = new EddText("FADctrl/ConsoleOut", true);
510 Text->setFixedWidth(400);
511 Layout->addWidget(Text, 2, 0, 4, 4);
512
513 EddPlot *Plot = new EddPlot();
514 Layout->addWidget(Plot, 2, 4, 4, 4);
515
516 // Details page
517 EddWindow *Button[2];
518 Button[0] = new EddWindow("Boards 0-19", "Edd - FADctrl - Board 0 to 19");
519 Button[1] = new EddWindow("Boards 20-39", "Edd - FADctrl - Board 20 to 39");
520 Layout->addWidget(Button[0], 7, 0, 1, 1);
521 Layout->addWidget(Button[1], 7, 1, 1, 1);
522
523 for (int i=0; i<40; i++) {
524 Board = Board.sprintf("FADctrl/Board%.2d/", i);
525 Line = new EddLineDisplay(Board+"Server");
526 Line->setMinimumWidth(90);
527 Button[i/20]->Layout()->addWidget(Line, i+7, 0, 1, 1);
528
529 Line = new EddLineDisplay(Board+"BoardID");
530 Line->setMaximumWidth(30);
531 Button[i/20]->Layout()->addWidget(Line, i+7, 1, 1, 1);
532
533 Line = new EddLineDisplay(Board+"Frequency");
534 Line->setMaximumWidth(40);
535 Button[i/20]->Layout()->addWidget(Line, i+7, 2, 1, 1);
536
537 for (int j=0; j<4; j++) {
538 Plot->AddService(Board+"Temperature", j);
539
540 Line = new EddLineDisplay(Board+"Temperature", j);
541 Line->setMinimumWidth(40);
542 Button[i/20]->Layout()->addWidget(Line, i+7, 3+j, 1, 1);
543 }
544
545 Line = new EddLineDisplay(Board+"TriggerNum");
546 Line->setMinimumWidth(40);
547 Button[i/20]->Layout()->addWidget(Line, i+7, 7, 1, 1);
548
549 Line = new EddLineDisplay(Board+"RateHz");
550 Line->setMinimumWidth(50);
551 Button[i/20]->Layout()->addWidget(Line, i+7, 15, 1, 1);
552
553 Line = new EddLineDisplay(Board+"Status");
554 Line->setMaximumWidth(150);
555 Button[i/20]->Layout()->addWidget(Line, i+7, 16, 1, 1);
556 }
557}
558
559//
560// Event scope page
561//
562TP_DAQ::TP_DAQ(bool IsBrowser) {
563
564 EddLineDisplay *Line;
565
566 setAttribute(Qt::WA_DeleteOnClose);
567 QGridLayout *Layout = new QGridLayout(this);
568
569 // Event scope
570 Scope = new EventScope(this);
571 Scope->setMinimumWidth(700);
572
573 if (IsBrowser) Scope->SetActive(false);
574
575 // FilenameBox must exist also for online browser (but not added to layout)
576 FilenameBox = new QLineEdit();
577
578 if (!IsBrowser) {
579 // Message service
580 Line = new EddLineDisplay(DRSBoard+"/Message");
581 Line->setMinimumWidth(500);
582 Layout->addWidget(Line, 0, 1, 1, 6);
583
584 // Run-related information
585 Line = new EddLineDisplay(DRSBoard+"/EventNumber");
586 Line->setMaximumWidth(100);
587 Layout->addWidget(Line, 0, 8, 1, 1);
588 Line = new EddLineDisplay(DRSBoard+"/FileSizeMB");
589 Line->setMaximumWidth(100);
590 Layout->addWidget(Line, 0, 9, 1, 1);
591 }
592 else {
593 // Filename box
594 Layout->addWidget(FilenameBox, 0, 1, 1, 6);
595 connect(FilenameBox, SIGNAL(returnPressed()), SLOT(OpenDataFile()));
596 FilenameBox->setToolTip("Raw data file name");
597
598 // Browse botton
599 QToolButton *LoadButton = new QToolButton();
600 LoadButton->setToolButtonStyle (Qt::ToolButtonTextOnly);
601 LoadButton->setText("...");
602 Layout->addWidget(LoadButton, 0, 7, 1, 1);
603 connect(LoadButton, SIGNAL(clicked()), Scope, SLOT(OpenRawFile()));
604 LoadButton->setToolTip("Open file dialog to select raw data file");
605 }
606
607 // Text boxes for run and event header
608 RunHeaderDisplay = new QPlainTextEdit();
609 EventHeaderDisplay = new QPlainTextEdit();
610 RunHeaderDisplay->setReadOnly(true);
611 EventHeaderDisplay->setReadOnly(true);
612
613 // Tab widget
614 QTabWidget *TabWidget = new QTabWidget();
615 TabWidget->addTab(Scope, "&Signals");
616 TabWidget->addTab(RunHeaderDisplay, "&Run Header");
617 TabWidget->addTab(EventHeaderDisplay, "&Event Header");
618 Layout->addWidget(TabWidget, 1, 1, 7, 12);
619
620 // Channel number
621 Channel = new QSpinBox;
622 connect(Channel, SIGNAL(valueChanged(int)), SLOT(UpdateScope(int)));
623 Channel->setToolTip("Channel number");
624
625 // Chip number
626 Chip = new QSpinBox;
627 connect(Chip, SIGNAL(valueChanged(int)), SLOT(UpdateScope(int)));
628 Chip->setToolTip("Chip number");
629
630 // Board number
631 Board = new QSpinBox;
632 connect(Board, SIGNAL(valueChanged(int)), SLOT(UpdateScope(int)));
633 Board->setToolTip("Board number");
634
635 // Pixel ID
636 PixelID = new QSpinBox;
637 PixelID->setMaximumWidth(60);
638 PixelID->setRange(-1, 9999);
639 PixelID->setSpecialValueText("n/a");
640 connect(PixelID, SIGNAL(valueChanged(int)), SLOT(TranslatePixelID(int)));
641 PixelID->setToolTip("Pixel identification");
642
643 // Add trace permanently
644 QPushButton *Button = new QPushButton("Keep trace");
645 Button->setToolTip("Keep trace in display");
646 Button->setMaximumWidth(80);
647 connect(Button, SIGNAL(clicked()), SLOT(KeepCurrent()));
648
649 // Layout of pixel addressing widgets
650 QFormLayout *FormLayout = new QFormLayout();
651 FormLayout->setRowWrapPolicy(QFormLayout::WrapAllRows);
652 FormLayout->addRow("Board", Board);
653 FormLayout->addRow("Chip", Chip);
654 FormLayout->addRow("Channel", Channel);
655 FormLayout->addRow("Pixel ID", PixelID);
656 FormLayout->addRow("", Button);
657 Layout->addLayout(FormLayout, 0, 0, 4, 1);
658
659 // Spin box for event number
660 Event = new QSpinBox;
661 Event->setToolTip("Event number");
662 Event->setEnabled (false);
663
664 // Stop/start button
665 StartStopButton = new QPushButton("Stop");
666 StartStopButton->setToolTip("Start/stop display");
667 StartStopButton->setMaximumWidth(80);
668 StartStopButton->setCheckable(true);
669 QPalette Palette = StartStopButton->palette();
670 Palette.setColor(QPalette::ButtonText, Qt::blue);
671 Palette.setColor(QPalette::Button, Qt::green);
672 StartStopButton->setPalette(Palette);
673 StartStopButton->setFont(QFont("Times", 10, QFont::Bold));
674
675 if (IsBrowser) {
676 FormLayout = new QFormLayout();
677 FormLayout->setRowWrapPolicy(QFormLayout::WrapAllRows);
678 FormLayout->addRow("Event Num", Event);
679 Layout->addLayout(FormLayout, 6, 0);
680 connect(Event, SIGNAL(valueChanged(int)), Scope, SLOT(NewEventNum(int)));
681 }
682 else {
683 Layout->addWidget(StartStopButton, 6, 0);
684 connect(StartStopButton, SIGNAL(toggled(bool)), SLOT(StartStop(bool)));
685 }
686
687 // Event display page
688 EddWindow *New = new EddWindow("Pixel display", "Edd - Event display");
689 New->setFont(QFont("Times", 10, QFont::Bold));
690 New->setMaximumWidth(80);
691 New->setToolTip("Show event display window");
692 Layout->addWidget(New, 7, 0);
693
694 Pixel = new QPushButton *[MAXPIXEL];
695 int Count = 0;
696 double x,y;
697
698 for (int ix=-22; ix<=22; ix++) for (int iy=-19; iy<=20; iy++) {
699 if (Count == MAXPIXEL) break;
700
701 x = ix*0.866;
702 y = iy - (ix%2==0 ? 0.5:0);
703 if ((pow(x,2)+pow(y,2) >= 395) && !(abs(ix)==22 && iy==7)) continue;
704
705 //Pixel[Count] = new QPushButton(Display);
706 Pixel[Count] = new QPushButton(New->Window());
707 Pixel[Count]->setAutoFillBackground(true);
708 Pixel[Count]->setGeometry((int) (x*12.5 + 250), (int) (y*12.5 + 250), 10, 10);
709 Pixel[Count]->show();
710 Count++;
711 }
712
713 // Connect slots for updating displays
714 if (!IsBrowser) StartStop(false);
715 connect(Scope, SIGNAL(PixelData(QVector<double>)), SLOT(SetPixelData(QVector<double>)));
716
717 // Call to get initial pixel ID correct
718 UpdateScope(0);
719}
720
721TP_DAQ::~TP_DAQ() {
722
723 delete[] Pixel;
724}
725
726// Translate pixel ID to board, chip, channel
727void TP_DAQ::TranslatePixelID(int ID) {
728
729 // setValue() below will call UpdateScope() through signal, therefore need to store numbers here
730 unsigned int BoardNo = Scope->Pixel_to_FPAboard(ID);
731 unsigned int PatchNo = Scope->Pixel_to_FPApatch(ID);
732 unsigned int PixelNo = Scope->Pixel_to_FPApixel(ID);
733
734 if (BoardNo == Scope->PM_ERROR_CODE) PixelID->setValue(-1);
735 else {
736 Board->setValue(BoardNo);
737 Chip->setValue(PatchNo);
738 Channel->setValue(PixelNo);
739 }
740}
741
742// Keep current trace
743void TP_DAQ::KeepCurrent() {
744
745 Scope->AddTrace(Board->value(), Chip->value(), Channel->value());
746}
747
748// Start/stop event acquisition
749void TP_DAQ::StartStop(bool State) {
750
751 Scope->SetActive(!State);
752 StartStopButton->setText(State ? "Start" : "Stop");
753}
754
755// Open raw data file
756void TP_DAQ::OpenDataFile() {
757
758 Scope->OpenRawFile(FilenameBox->text());
759}
760
761// Update event scope
762void TP_DAQ::UpdateScope(int) {
763
764 // Update pixel ID
765 PixelID->setValue(Scope->FPA_to_Pixel(0, Board->value(), Chip->value(), Channel->value()));
766 if (PixelID->value() == (int) Scope->PM_ERROR_CODE) PixelID->setValue(-1);
767
768 // Update first trace
769 Scope->UpdateFirst(Board->value(), Chip->value(), Channel->value());
770}
771
772// Show/hide pixel display
773void TP_DAQ::ShowPixelDisplay() {
774
775 Display->show();
776 Display->raise();
777}
778
779void TP_DAQ::SetPixelData(QVector<double> Data) {
780
781 QwtLinearColorMap Map;
782
783 for (int i=0; i<Data.size(); i++) {
784 Pixel[i]->setPalette(QPalette(Map.color(QwtDoubleInterval(300, 400), Data[i])));
785 }
786}
787
788
789//
790// Evidence page
791//
792TP_Evidence::TP_Evidence() {
793
794 setAttribute(Qt::WA_DeleteOnClose);
795 QGridLayout *Layout = new QGridLayout(this);
796 EddLineDisplay *Line;
797 EddText *Text;
798
799 Line = new EddLineDisplay("Alarm/Message");
800 Line->setMaximumWidth(200);
801 Layout->addWidget(Line, 0, 0, 1, 2);
802
803 QPushButton *Button = new QPushButton();
804 Button->setText("ON/OFF");
805 Button->setCheckable(true);
806 connect(Button, SIGNAL(toggled(bool)), SLOT(ToggleAlarm(bool)));
807 Layout->addWidget(Button, 0, 3, 1, 1);
808
809 Line = new EddLineDisplay("Alarm/MasterAlarm");
810 Layout->addWidget(Line, 0, 1, 1, 1);
811
812 Text = new EddText("Alarm/Summary", true);
813 Text->Accumulate = false;
814 Text->setMaximumWidth(200);
815 Text->setMaximumHeight(150);
816 Layout->addWidget(Text, 1, 0, 1, 2);
817
818 Line = new EddLineDisplay("DColl/Message");
819 Line->setMaximumWidth(200);
820 Layout->addWidget(Line, 3, 0, 1, 2);
821
822 Line = new EddLineDisplay("DColl/DataSizeMB");
823 Layout->addWidget(Line, 4, 0, 1, 1);
824
825 Line = new EddLineDisplay("DColl/LogSizeMB");
826 Layout->addWidget(Line, 4, 1, 1, 1);
827
828 Line = new EddLineDisplay("DColl/CurrentFile");
829 Line->setMaximumWidth(400);
830 Layout->addWidget(Line, 5, 0, 1, 3);
831
832 Line = new EddLineDisplay("Config/Message");
833 Line->setMaximumWidth(200);
834 Layout->addWidget(Line, 6, 0, 1, 2);
835
836 Line = new EddLineDisplay("Config/ModifyTime");
837 Line->setMaximumWidth(200);
838 Line->ShowAsTime = true;
839 Layout->addWidget(Line, 7, 0, 1, 1);
840
841 Button = new QPushButton();
842 Button->setText("eLogBook");
843 connect(Button, SIGNAL(released()), SLOT(StartELog()));
844 Layout->addWidget(Button, 6, 1, 1, 1);
845
846 Button = new QPushButton();
847 Button->setText("DIM browser");
848 connect(Button, SIGNAL(released()), SLOT(StartDIMBrowser()));
849 Layout->addWidget(Button, 7, 1, 1, 1);
850
851 Line = new EddLineDisplay("Edd/Rate_kBSec");
852 Layout->addWidget(Line, 8, 0, 1, 1);
853}
854
855// Toggle state of Alarm server
856void TP_Evidence::ToggleAlarm(bool State) {
857
858 if (State) DimClient::sendCommandNB((char *) "Alarm/Switch", (char *) "off");
859 else DimClient::sendCommandNB((char *) "Alarm/Switch", (char *) "on");
860}
861
862// Start DIM Browser
863void TP_Evidence::StartDIMBrowser() {
864
865 QProcess::startDetached("did", QStringList(), QString(getenv("DIMDIR"))+"/linux/");
866}
867
868// Start eLogBook
869void TP_Evidence::StartELog() {
870
871 QProcess::startDetached("firefox http://fact.ethz.ch/FACTelog/index.jsp");
872}
873
874
875//--------------------------------------------------------------------
876//*************************** Main GUI *******************************
877//--------------------------------------------------------------------
878//
879// All widgets have ultimately Central as parent.
880//
881GUI::GUI() {
882
883 Handler = new EddDim;
884
885 // Arrangement in tabs
886 TabWidget = new QTabWidget(this);
887 TabWidget->setTabsClosable(true);
888 connect(TabWidget, SIGNAL(tabCloseRequested(int)), SLOT(DetachTab(int)));
889 TabWidget->addTab(new TP_DAQ(false), "Event scope");
890 TabWidget->addTab(new TP_FADctrl, "FADctrl");
891 TabWidget->addTab(new TP_Bias, "Bias");
892 TabWidget->addTab(new TP_Feedback, "Feedback");
893 TabWidget->addTab(new TP_Environment, "FSC/SQM");
894 TabWidget->addTab(new TP_Evidence, "Evidence");
895
896 // Set features of main window
897 setStatusBar(new QStatusBar(this));
898 setWindowTitle("Edd - Evidence Data Display - Node: " + QString(DimServer::getDnsNode()) + ":" + QString::number(DimServer::getDnsPort()));
899 setCentralWidget(TabWidget);
900
901 // Menu bar
902 QMenu* Menu = menuBar()->addMenu("&Menu");
903 Menu->addAction("New history plot", this, SLOT(MenuNewHistory()));
904 Menu->addAction("Raw data browser", this, SLOT(MenuRawDataBrowser()));
905 Menu->addSeparator();
906 Menu->addAction("About", this, SLOT(MenuAbout()));
907 Menu->addSeparator();
908 QAction* QuitAction = Menu->addAction("Quit", qApp, SLOT(quit()));
909 QuitAction->setShortcut(Qt::CTRL + Qt::Key_Q);
910
911 // Size and show main window
912 QSize Size = TabWidget->sizeHint()*1.1;
913 Size = Size.boundedTo(QApplication::desktop()->screenGeometry(this).size()*0.6);
914 //setMaximumSize(QApplication::desktop()->screenGeometry(this).size()*0.9);
915 TabWidget->resize(Size);
916 TabWidget->setMaximumSize(QApplication::desktop()->screenGeometry(this).size()*0.9);
917 show();
918
919 // Set timer to regularly check the master alarm
920 QTimer *Timer = new QTimer(this);
921 connect(Timer, SIGNAL(timeout()), this, SLOT(CheckAlarm()));
922 Timer->start(5000);
923
924 // Force update of all widgets constructed (in thread for GUI responsiveness)
925 QtConcurrent::run(Handler, &EddDim::ForceEmit);
926}
927
928
929void GUI::MenuAbout() {
930 QString Rev(SVN_REVISION);
931 Rev.remove(0,1).chop(2);
932
933 QMessageBox::about(this, "About Edd","Evidence Data Display\n\n"
934 "Written by Oliver Grimm, IPP, ETH Zurich\n"
935 "This version compiled "__DATE__" ("+Rev+")\n\n"
936 "Graphical user interface implemented with Qt and Qwt.\n"
937 "Evidence control system based on DIM (http://dim.web.cern.ch).\n\n"
938 "Comments to oliver.grimm@phys.ethz.ch.");
939}
940
941// Open request for new history plot
942void GUI::MenuNewHistory() {
943
944 QStringList List;
945 char *Name, *Format;
946 int Type;
947 bool OK;
948
949 // Find all DIM services and sort
950 getServices("*");
951 while ((Type = getNextService(Name, Format)) != 0) {
952 if (Type==DimSERVICE) List.append(Name);
953 }
954 List.sort();
955
956 // Open dialog and open history window
957 QString Result = QInputDialog::getItem(this, "Edd Request",
958 "Enter DIM service name", List, 0, true, &OK);
959 if (OK && !Result.isEmpty()) {
960 Result = Result.trimmed();
961 QWidget *Hist = OpenHistory(Result.toAscii().data(), 0);
962 if (Hist != NULL) Hist->show();
963 }
964}
965
966// Raw data browser
967void GUI::MenuRawDataBrowser() {
968
969 DetachTab(0, true);
970}
971
972// Open tab as separate window
973void GUI::DetachTab(int Tab, bool IsDAQBrowser) {
974
975 QWidget *W = NULL;
976 QMainWindow *M = new QMainWindow;
977
978 M->setCentralWidget(new QWidget(M));
979 M->setStatusBar(new QStatusBar(M));
980
981 switch(Tab) {
982 case 0: W = new TP_DAQ(IsDAQBrowser); break;
983 case 1: W = new TP_FADctrl; break;
984 case 2: W = new TP_Bias; break;
985 case 3: W = new TP_Feedback; break;
986 case 4: W = new TP_Environment; break;
987 case 5: W = new TP_Evidence; break;
988 default: break;
989 }
990
991 if (W == NULL) {
992 delete M->centralWidget();
993 delete M;
994 return;
995 }
996
997 W->setParent(M);
998 W->resize(size());
999 M->resize(size());
1000 if (!IsDAQBrowser) M->setWindowTitle("Edd - " + TabWidget->tabText(Tab));
1001 else M->setWindowTitle("Edd - Raw Data Browser");
1002 M->show();
1003
1004 return;
1005}
1006
1007// Check alarm level and if Alarm server is alive
1008void GUI::CheckAlarm() {
1009
1010 static int WarnedLevel = 0;
1011 static bool AlarmServerWarned = false;
1012
1013 // === Check service Alarm/MasterAlarm ===
1014 DimCurrentInfo MasterAlarm("Alarm/MasterAlarm", -1);
1015
1016 if (MasterAlarm.getInt() > WarnedLevel) {
1017 QSound::play(QApplication::applicationDirPath() + "/Error.wav");
1018
1019 // Construct warning message box
1020 QMessageBox Box;
1021 Box.setWindowTitle("Edd Alarm");
1022 Box.setText("Service 'Alarm/MasterAlarm' is at " + QString::number(MasterAlarm.getInt()));
1023 Box.setInformativeText("Warn again for the same alarm level?");
1024 Box.setIcon(QMessageBox::Warning);
1025 Box.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
1026 Box.setDefaultButton(QMessageBox::No);
1027
1028 // Check if user wants to reset warned level
1029 if (Box.exec() == QMessageBox::Yes) WarnedLevel = 0;
1030 else WarnedLevel = MasterAlarm.getInt();
1031 }
1032
1033 // If MasterAlam decreased, lower also warned level
1034 if (MasterAlarm.getInt() < WarnedLevel && MasterAlarm.getInt() >=0 ) WarnedLevel = MasterAlarm.getInt();
1035
1036 // === Check Alarm server ===
1037 DimCurrentInfo ServerList("DIS_DNS/SERVER_LIST", NO_LINK);
1038 std::string Result = EvidenceServer::ToString((char *) "C", ServerList.getData(), ServerList.getSize());
1039
1040 // Warn if SERVER_LIST does not contain alarm server
1041 if (Result.find("Alarm@") == std::string::npos && !AlarmServerWarned) {
1042 QMessageBox Box;
1043 Box.setWindowTitle("Edd Alarm");
1044 Box.setText("Alarm server is unavailable or in error");
1045 Box.setIcon(QMessageBox::Critical);
1046 Box.setStandardButtons(QMessageBox::Ok);
1047 Box.setDefaultButton(QMessageBox::Ok);
1048 Box.exec();
1049
1050 AlarmServerWarned = true;
1051 }
1052
1053 if (Result.find("Alarm@") != std::string::npos) AlarmServerWarned = false;
1054}
1055
1056// Quit application when clicking close button on window
1057void GUI::closeEvent(QCloseEvent *) {
1058
1059 qApp->quit();
1060}
1061
1062
1063//
1064//**************************** Main program ***************************
1065//
1066int main(int argc, char *argv[]) {
1067
1068 if (argc>1 && strcmp(argv[1],"drsdaq")==0) DRSBoard = "drsdaq";
1069
1070 // Make RPC to get pixelmap
1071 DimRpcInfo RPC((char *) "ConfigRequest", (char *) "");
1072 RPC.setData((char *) "Misc PixelMap");
1073 PixelMapText = std::string(RPC.getString(), RPC.getSize());
1074
1075 QApplication app(argc, argv);
1076 GUI MainWindow;
1077
1078 return app.exec();
1079}
Note: See TracBrowser for help on using the repository browser.