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

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