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

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