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

Last change on this file since 10870 was 10642, checked in by ogrimm, 14 years ago
FADctrl publishes amplitude calibration information as DIM service
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 = "FADctrl";
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 Line = new EddLineDisplay(Board+"TriggerNum");
480 Line->setMinimumWidth(40);
481 Button[i/20]->Layout()->addWidget(Line, i+7, 7, 1, 1);
482
483 Line = new EddLineDisplay(Board+"RateHz");
484 Line->setMinimumWidth(50);
485 Button[i/20]->Layout()->addWidget(Line, i+7, 15, 1, 1);
486
487 Line = new EddLineDisplay(Board+"Status");
488 Line->setMaximumWidth(150);
489 Button[i/20]->Layout()->addWidget(Line, i+7, 16, 1, 1);
490 }
491}
492
493//
494// Event scope page
495//
496TP_DAQ::TP_DAQ() {
497
498 EddLineDisplay *Line;
499
500 setAttribute(Qt::WA_DeleteOnClose);
501 QGridLayout *Layout = new QGridLayout(this);
502
503 // Run-related information
504 Line = new EddLineDisplay("drsdaq/RunNumber");
505 Line->setMaximumWidth(100);
506 Layout->addWidget(Line, 0, 1, 1, 1);
507 Line = new EddLineDisplay(DRSBoard+"/EventNumber");
508 Line->setMaximumWidth(100);
509 Layout->addWidget(Line, 0, 2, 1, 1);
510 Line = new EddLineDisplay("drsdaq/RunSizeMB");
511 Line->setMaximumWidth(100);
512 Layout->addWidget(Line, 0, 3, 1, 1);
513 Line = new EddLineDisplay("drsdaq/FileSizeMB");
514 Line->setMaximumWidth(100);
515 Layout->addWidget(Line, 0, 4, 1, 1);
516 Line = new EddLineDisplay("drsdaq/FileName");
517 Line->setMaximumWidth(200);
518 Layout->addWidget(Line, 0, 5, 1, 1);
519
520 // Message service
521 Line = new EddLineDisplay(DRSBoard+"/Message");
522 Line->setMaximumWidth(200);
523 Layout->addWidget(Line, 1, 1, 1, 2);
524
525 // Event scope
526 Scope = new EventScope;
527 Scope->setMinimumWidth(700);
528
529 // Text boxes for run and event header
530 RunHeaderDisplay = new QPlainTextEdit();
531 EventHeaderDisplay = new QPlainTextEdit();
532 RunHeaderDisplay->setReadOnly(true);
533 EventHeaderDisplay->setReadOnly(true);
534
535 // Tab widget
536 QTabWidget *TabWidget = new QTabWidget();
537 TabWidget->addTab(Scope, "&Signals");
538 TabWidget->addTab(RunHeaderDisplay, "&Run Header");
539 TabWidget->addTab(EventHeaderDisplay, "&Event Header");
540 Layout->addWidget(TabWidget, 2, 1, 6, 5);
541
542 // Channel number
543 Channel = new QSpinBox;
544 connect(Channel, SIGNAL(valueChanged(int)), SLOT(UpdateScope(int)));
545 Channel->setToolTip("DRS channel number");
546
547 // Chip number
548 Chip = new QSpinBox;
549 connect(Chip, SIGNAL(valueChanged(int)), SLOT(UpdateScope(int)));
550 Chip->setToolTip("DRS chip number");
551
552 // Board number
553 Board = new QSpinBox;
554 connect(Board, SIGNAL(valueChanged(int)), SLOT(UpdateScope(int)));
555 Board->setToolTip("DRS board number");
556
557 // Pixel ID
558 PixelID = new QSpinBox;
559 PixelID->setMaximumWidth(60);
560 PixelID->setRange(-1, 9999);
561 PixelID->setSpecialValueText("n/a");
562 connect(PixelID, SIGNAL(valueChanged(int)), SLOT(TranslatePixelID(int)));
563 PixelID->setToolTip("Pixel identification");
564
565 // Layout of pixel addressing widgets
566 QFormLayout *FormLayout = new QFormLayout();
567 FormLayout->setRowWrapPolicy(QFormLayout::WrapAllRows);
568 FormLayout->addRow("Board", Board);
569 FormLayout->addRow("Chip", Chip);
570 FormLayout->addRow("Channel", Channel);
571 FormLayout->addRow("Pixel ID", PixelID);
572 Layout->addLayout(FormLayout, 0, 0, 4, 1);
573
574 // Add trace permanently
575 QPushButton *Button = new QPushButton("Keep trace");
576 Button->setToolTip("Keep trace in display");
577 Button->setMaximumWidth(80);
578 Layout->addWidget(Button, 4, 0);
579 connect(Button, SIGNAL(clicked()), SLOT(KeepCurrent()));
580
581 // Stop/start
582 StartStopButton = new QPushButton("Stop");
583 StartStopButton->setToolTip("Start/stop display");
584 StartStopButton->setMaximumWidth(80);
585 StartStopButton->setCheckable(true);
586 QPalette Palette = StartStopButton->palette();
587 Palette.setColor(QPalette::ButtonText, Qt::blue);
588 Palette.setColor(QPalette::Button, Qt::green);
589 StartStopButton->setPalette(Palette);
590 StartStopButton->setFont(QFont("Times", 10, QFont::Bold));
591 Layout->addWidget(StartStopButton, 6, 0);
592 connect(StartStopButton, SIGNAL(toggled(bool)), SLOT(StartStop(bool)));
593
594
595 // Event display page
596 EddWindow *New = new EddWindow("Pixel display", "Edd - Event display");
597 New->setFont(QFont("Times", 10, QFont::Bold));
598 New->setMaximumWidth(80);
599 New->setToolTip("Show event display window");
600 Layout->addWidget(New, 7, 0);
601
602 Pixel = new QPushButton *[MAXPIXEL];
603 int Count = 0;
604 double x,y;
605
606 for (int ix=-22; ix<=22; ix++) for (int iy=-19; iy<=20; iy++) {
607 if (Count == MAXPIXEL) break;
608
609 x = ix*0.866;
610 y = iy - (ix%2==0 ? 0.5:0);
611 if ((pow(x,2)+pow(y,2) >= 395) && !(abs(ix)==22 && iy==7)) continue;
612
613 //Pixel[Count] = new QPushButton(Display);
614 Pixel[Count] = new QPushButton(New->Window());
615 Pixel[Count]->setAutoFillBackground(true);
616 Pixel[Count]->setGeometry((int) (x*12.5 + 250), (int) (y*12.5 + 250), 10, 10);
617 Pixel[Count]->show();
618 Count++;
619 }
620
621 // Connect slots for updating displays
622 connect(Scope, SIGNAL(RunHeaderChanged(QString)), RunHeaderDisplay, SLOT(setPlainText(QString)));
623 connect(Scope, SIGNAL(EventHeaderChanged(QString)), EventHeaderDisplay, SLOT(setPlainText(QString)));
624
625 StartStop(false);
626 connect(Scope, SIGNAL(PixelData(QVector<double>)), SLOT(SetPixelData(QVector<double>)));
627
628 // Call to get initial pixel ID correct
629 UpdateScope(0);
630}
631
632TP_DAQ::~TP_DAQ() {
633
634 delete[] Pixel;
635}
636
637// Translate pixel ID to board, chip, channel
638void TP_DAQ::TranslatePixelID(int ID) {
639
640 // setValue() below will call UpdateScope() through signal, therefore need to store numbers here
641 unsigned int BoardNo = Scope->Pixel_to_FPAboard(ID);
642 unsigned int PatchNo = Scope->Pixel_to_FPApatch(ID);
643 unsigned int PixelNo = Scope->Pixel_to_FPApixel(ID);
644
645 if (BoardNo == Scope->PM_ERROR_CODE) PixelID->setValue(-1);
646 else {
647 Board->setValue(BoardNo);
648 Chip->setValue(PatchNo);
649 Channel->setValue(PixelNo);
650 }
651}
652
653// Keep current trace
654void TP_DAQ::KeepCurrent() {
655
656 Scope->AddTrace(Board->value(), Chip->value(), Channel->value());
657}
658
659// Start/stop event acquisition
660void TP_DAQ::StartStop(bool State) {
661
662 Scope->SetActive(!State);
663 StartStopButton->setText(State ? "Start" : "Stop");
664 if (!State) connect(Handler, SIGNAL(YEP(QString, int, QByteArray, QString, QString)), Scope, SLOT(Update(QString, int, QByteArray, QString, QString)));
665 else disconnect(Handler, SIGNAL(YEP(QString, int, QByteArray, QString, QString)), Scope, SLOT(Update(QString, int, QByteArray, QString, QString)));
666}
667
668// Update event scope
669void TP_DAQ::UpdateScope(int) {
670
671 // Update pixel ID
672 PixelID->setValue(Scope->FPA_to_Pixel(0, Board->value(), Chip->value(), Channel->value()));
673 if (PixelID->value() == (int) Scope->PM_ERROR_CODE) PixelID->setValue(-1);
674
675 // Update first trace
676 Scope->UpdateFirst(Board->value(), Chip->value(), Channel->value());
677}
678
679// Show/hide pixel display
680void TP_DAQ::ShowPixelDisplay() {
681
682 Display->show();
683 Display->raise();
684}
685
686void TP_DAQ::SetPixelData(QVector<double> Data) {
687
688 QwtLinearColorMap Map;
689
690 for (int i=0; i<Data.size(); i++) {
691 Pixel[i]->setPalette(QPalette(Map.color(QwtDoubleInterval(300, 400), Data[i])));
692 }
693}
694
695
696//
697// Evidence page
698//
699TP_Evidence::TP_Evidence() {
700
701 setAttribute(Qt::WA_DeleteOnClose);
702 QGridLayout *Layout = new QGridLayout(this);
703 EddLineDisplay *Line;
704 EddText *Text;
705
706 Line = new EddLineDisplay("Alarm/Message");
707 Line->setMaximumWidth(200);
708 Layout->addWidget(Line, 0, 0, 1, 2);
709
710 QPushButton *Button = new QPushButton();
711 Button->setText("ON/OFF");
712 Button->setCheckable(true);
713 connect(Button, SIGNAL(toggled(bool)), SLOT(ToggleAlarm(bool)));
714 Layout->addWidget(Button, 0, 3, 1, 1);
715
716 Line = new EddLineDisplay("Alarm/MasterAlarm");
717 Layout->addWidget(Line, 0, 1, 1, 1);
718
719 Text = new EddText("Alarm/Summary", true);
720 Text->Accumulate = false;
721 Text->setMaximumWidth(200);
722 Text->setMaximumHeight(150);
723 Layout->addWidget(Text, 1, 0, 1, 2);
724
725 Line = new EddLineDisplay("DColl/Message");
726 Line->setMaximumWidth(200);
727 Layout->addWidget(Line, 3, 0, 1, 2);
728
729 Line = new EddLineDisplay("DColl/DataSizeMB");
730 Layout->addWidget(Line, 4, 0, 1, 1);
731
732 Line = new EddLineDisplay("DColl/LogSizeMB");
733 Layout->addWidget(Line, 4, 1, 1, 1);
734
735 Line = new EddLineDisplay("DColl/CurrentFile");
736 Line->setMaximumWidth(400);
737 Layout->addWidget(Line, 5, 0, 1, 3);
738
739 Line = new EddLineDisplay("Config/Message");
740 Line->setMaximumWidth(200);
741 Layout->addWidget(Line, 6, 0, 1, 2);
742
743 Line = new EddLineDisplay("Config/ModifyTime");
744 Line->setMaximumWidth(200);
745 Line->ShowAsTime = true;
746 Layout->addWidget(Line, 7, 0, 1, 1);
747
748 Button = new QPushButton();
749 Button->setText("eLogBook");
750 connect(Button, SIGNAL(released()), SLOT(StartELog()));
751 Layout->addWidget(Button, 6, 1, 1, 1);
752
753 Button = new QPushButton();
754 Button->setText("Start DIM browser");
755 connect(Button, SIGNAL(released()), SLOT(StartDIMBrowser()));
756 Layout->addWidget(Button, 7, 1, 1, 1);
757
758 Line = new EddLineDisplay("Edd/Rate_kBSec");
759 Layout->addWidget(Line, 8, 0, 1, 1);
760}
761
762// Toggle state of Alarm server
763void TP_Evidence::ToggleAlarm(bool State) {
764
765 if (State) DimClient::sendCommandNB((char *) "Alarm/Switch", (char *) "off");
766 else DimClient::sendCommandNB((char *) "Alarm/Switch", (char *) "on");
767}
768
769// Start DIM Browser
770void TP_Evidence::StartDIMBrowser() {
771
772 QProcess::startDetached("did", QStringList(), QString(getenv("DIMDIR"))+"/linux/");
773}
774
775// Start eLogBook
776void TP_Evidence::StartELog() {
777
778 QProcess::startDetached("firefox http://fact.ethz.ch/FACTelog/index.jsp");
779}
780
781
782//--------------------------------------------------------------------
783//*************************** Main GUI *******************************
784//--------------------------------------------------------------------
785//
786// All widgets have ultimately Central as parent.
787//
788GUI::GUI() {
789
790 Handler = new EddDim;
791
792 // Arrangement in tabs
793 TabWidget = new QTabWidget(this);
794 TabWidget->setTabsClosable(true);
795 connect(TabWidget, SIGNAL(tabCloseRequested(int)), SLOT(DetachTab(int)));
796 TabWidget->addTab(new TP_DAQ, "Event scope");
797 TabWidget->addTab(new TP_FADctrl, "FADctrl");
798 TabWidget->addTab(new TP_Bias, "Bias");
799 TabWidget->addTab(new TP_Feedback, "Feedback");
800 TabWidget->addTab(new TP_Environment, "Environment");
801 TabWidget->addTab(new TP_Evidence, "Evidence");
802
803 // Set features of main window
804 setStatusBar(new QStatusBar(this));
805 setWindowTitle("Edd - Evidence Data Display - Node: " + QString(getenv("DIM_DNS_NODE")));
806 setCentralWidget(TabWidget);
807
808 // Menu bar
809 QMenu* Menu = menuBar()->addMenu("&Menu");
810 Menu->addAction("New history plot", this, SLOT(MenuNewHistory()));
811 Menu->addSeparator();
812 Menu->addAction("About", this, SLOT(MenuAbout()));
813 Menu->addSeparator();
814 QAction* QuitAction = Menu->addAction("Quit", qApp, SLOT(quit()));
815 QuitAction->setShortcut(Qt::CTRL + Qt::Key_Q);
816
817 // Size and show main window
818 QSize Size = TabWidget->sizeHint()*1.1;
819 Size = Size.boundedTo(QApplication::desktop()->screenGeometry(this).size()*0.6);
820 //setMaximumSize(QApplication::desktop()->screenGeometry(this).size()*0.9);
821 TabWidget->resize(Size);
822TabWidget->setMaximumSize(QApplication::desktop()->screenGeometry(this).size()*0.9);
823 show();
824
825 // Set timer to regularly check the master alarm
826 QTimer *Timer = new QTimer(this);
827 connect(Timer, SIGNAL(timeout()), this, SLOT(CheckAlarm()));
828 Timer->start(5000);
829}
830
831
832void GUI::MenuAbout() {
833 QString Rev(SVN_REVISION);
834 Rev.remove(0,1).chop(2);
835
836 QMessageBox::about(this, "About Edd","Evidence Data Display\n\n"
837 "Written by Oliver Grimm, IPP, ETH Zurich\n"
838 "This version compiled "__DATE__" ("+Rev+")\n\n"
839 "Graphical user interface implemented with Qt and Qwt.\n"
840 "Evidence control system based on DIM (http://dim.web.cern.ch).\n\n"
841 "Comments to oliver.grimm@phys.ethz.ch.");
842}
843
844// Open request for new history plot
845void GUI::MenuNewHistory() {
846
847 QStringList List;
848 char *Name, *Format;
849 int Type;
850 bool OK;
851
852 // Find all DIM services and sort
853 getServices("*");
854 while ((Type = getNextService(Name, Format)) != 0) {
855 if (Type==DimSERVICE) List.append(Name);
856 }
857 List.sort();
858
859 // Open dialog and open history window
860 QString Result = QInputDialog::getItem(this, "Edd Request",
861 "Enter DIM service name", List, 0, true, &OK);
862 if (OK && !Result.isEmpty()) {
863 Result = Result.trimmed();
864 QWidget *Hist = OpenHistory(Result.toAscii().data(), 0);
865 if (Hist != NULL) Hist->show();
866 }
867}
868
869// Open tab as separate window
870void GUI::DetachTab(int Tab) {
871
872 QWidget *W = NULL;
873 QMainWindow *M = new QMainWindow;
874
875 M->setCentralWidget(new QWidget(M));
876 M->setStatusBar(new QStatusBar(M));
877
878 switch(Tab) {
879 case 0: W = new TP_DAQ; break;
880 case 1: W = new TP_Bias; break;
881 case 2: W = new TP_Feedback; break;
882 case 3: W = new TP_Environment; break;
883 case 4: W = new TP_Evidence; break;
884 default: break;
885 }
886
887 if (W == NULL) {
888 delete M->centralWidget();
889 delete M;
890 return;
891 }
892
893 W->setParent(M);
894 M->resize(size());
895 M->setWindowTitle("Edd - " + TabWidget->tabText(Tab));
896 M->show();
897}
898
899// Check alarm level and if Alarm server is alive
900void GUI::CheckAlarm() {
901
902 static int WarnedLevel = 0;
903 static bool AlarmServerWarned = false;
904
905 // === Check service Alarm/MasterAlarm ===
906 DimCurrentInfo MasterAlarm("Alarm/MasterAlarm", -1);
907
908 if (MasterAlarm.getInt() > WarnedLevel) {
909 QSound::play(QApplication::applicationDirPath() + "/Error.wav");
910
911 // Construct warning message box
912 QMessageBox Box;
913 Box.setWindowTitle("Edd Alarm");
914 Box.setText("Service 'Alarm/MasterAlarm' is at " + QString::number(MasterAlarm.getInt()));
915 Box.setInformativeText("Warn again for the same alarm level?");
916 Box.setIcon(QMessageBox::Warning);
917 Box.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
918 Box.setDefaultButton(QMessageBox::No);
919
920 // Check if user wants to reset warned level
921 if (Box.exec() == QMessageBox::Yes) WarnedLevel = 0;
922 else WarnedLevel = MasterAlarm.getInt();
923 }
924
925 // If MasterAlam decreased, lower also warned level
926 if (MasterAlarm.getInt() < WarnedLevel && MasterAlarm.getInt() >=0 ) WarnedLevel = MasterAlarm.getInt();
927
928 // === Check Alarm server ===
929 DimCurrentInfo ServerList("DIS_DNS/SERVER_LIST", NO_LINK);
930 std::string Result = EvidenceServer::ToString((char *) "C", ServerList.getData(), ServerList.getSize());
931
932 // Warn if SERVER_LIST does not contain alarm server
933 if (Result.find("Alarm@") == std::string::npos && !AlarmServerWarned) {
934 QMessageBox Box;
935 Box.setWindowTitle("Edd Alarm");
936 Box.setText("Alarm server is unavailable or in error");
937 Box.setIcon(QMessageBox::Critical);
938 Box.setStandardButtons(QMessageBox::Ok);
939 Box.setDefaultButton(QMessageBox::Ok);
940 Box.exec();
941
942 AlarmServerWarned = true;
943 }
944
945 if (Result.find("Alarm@") != std::string::npos) AlarmServerWarned = false;
946}
947
948// Quit application when clicking close button on window
949void GUI::closeEvent(QCloseEvent *) {
950
951 qApp->quit();
952}
953
954
955//
956//**************************** Main program ***************************
957//
958int main(int argc, char *argv[]) {
959
960 if (argc>1 && strcmp(argv[1],"drsdaq")==0) DRSBoard = "drsdaq";
961
962 // Make RPC to get pixelmap
963 DimRpcInfo RPC((char *) "ConfigRequest", (char *) "");
964 RPC.setData((char *) "Misc PixelMap");
965 PixelMapText = std::string(RPC.getString(), RPC.getSize());
966
967 QApplication app(argc, argv);
968 GUI MainWindow;
969
970 return app.exec();
971}
Note: See TracBrowser for help on using the repository browser.