source: fact/tools/ddd/Functions.cpp@ 13376

Last change on this file since 13376 was 10118, checked in by ogrimm, 14 years ago
Adapted various programs to new PixelMap class
File size: 13.4 KB
Line 
1
2#include "GUI.h"
3
4//---------------------------------------------------------------------
5//************************ All functions ****************************
6//-------------------------------------------------------------------
7
8// +++ Open file dialog +++
9void ddd::FileDialog(void) {
10QString Filename = QFileDialog::getOpenFileName(this,
11 "Open raw file", INITIAL_DIRECTORY, "Raw data files (*.raw);; All files (*)");
12 if (Filename != NULL) {
13 FilenameBox->setText(Filename);
14 OpenDatafile();
15 }
16}
17
18// +++ Open selected file and read run header +++
19void ddd::OpenDatafile() {
20
21 if(Socket->state() == QAbstractSocket::ConnectedState) { // do not execute if socket is open
22 MakeConnection();
23 }
24
25 CloseDatafile(); // Close previous file if open
26
27 // Write run header to temporary file
28 ftruncate(fileno(Tmpfile),0);
29 rewind(Tmpfile);
30 switch (RD->OpenDataFile(FilenameBox->text().toAscii().data(), Tmpfile)) {
31 case CTX_FOPEN: QMessageBox::warning(this, "ddd Message","Could not open file.",QMessageBox::Ok);
32 return;
33 case CTX_RHEADER: QMessageBox::warning(this, "ddd Message","Could not read run header.",QMessageBox::Ok);
34 return;
35 case CTX_BSTRUCT: QMessageBox::warning(this, "ddd Message","Could not read board structures.",QMessageBox::Ok);
36 return;
37 default: break;
38 }
39 RunHeader *R = RD->RHeader;
40
41 if (R->MagicNum == MAGICNUM_OPEN) {
42 QMessageBox::warning(this, "ddd Message","Magic number in run header indicates that the file has not been closed properly.",QMessageBox::Ok);
43 }
44 if (R->MagicNum == MAGICNUM_ERROR) {
45 QMessageBox::warning(this, "ddd Message","Magic number in run header indicates that an error occurred while writing the file.",QMessageBox::Ok);
46 }
47
48 rewind(Tmpfile);
49 QTextStream in(Tmpfile);
50 QString text = in.readAll();
51 RunHeaderDisplay->setPlainText(text);
52
53 // Enable spin boxes, set ranges and display first event
54 EventNo->setEnabled(true);
55 ChannelNo->setEnabled(true);
56 ChipNo->setEnabled(true);
57 BoardNo->setEnabled(true);
58 PixelID->setEnabled(true);
59 PhysPipeAction->setEnabled(true);
60 EventNo->setRange(1, R->Events);
61 ChannelNo->setRange(0, R->NChannels-1);
62 ChipNo->setRange(0, R->NChips-1);
63 BoardNo->setRange(0, R->NBoards-1);
64 DisplayEvent();
65}
66
67// +++ Close data file file if open, delete event header and disable spin boxes and displays +++
68void ddd::CloseDatafile() {
69 if(RD->CloseDataFile()==CTX_OK) {
70 EventNo->setEnabled(false);
71 ChannelNo->setEnabled(false);
72 ChipNo->setEnabled(false);
73 BoardNo->setEnabled(false);
74 PixelID->setEnabled(false);
75 PhysPipeAction->setEnabled(false);
76 RunHeaderDisplay->clear();
77 EventHeaderDisplay->clear();
78 Signal->hide();
79 }
80}
81
82// +++ Read event header and display event (only called if Datafile is open) +++
83void ddd::DisplayEvent(int) {
84
85 PixelID->setValue(PixMap->FPA_to_Pixel(0, BoardNo->value(), ChipNo->value(), ChannelNo->value())); // Translate to pixel ID
86 if(Socket->state() == QAbstractSocket::ConnectedState) return; // do not execute if socket is open
87
88 if (PhysPipeAction->isChecked()) {
89 Graph->setAxisTitle(QwtPlot::xBottom, "Time from start of physical pipeline (ns)");
90 }
91 else {
92 Graph->setAxisTitle(QwtPlot::xBottom, "Time from trigger (ns)");
93 }
94
95 // Read event
96 ftruncate(fileno(Tmpfile),0);
97 rewind(Tmpfile);
98 if (RD->ReadEvent(EventNo->value(), Tmpfile) != CTX_OK) {
99 QMessageBox::warning(this, "ddd Warning","Could not read event.",QMessageBox::Ok);
100 EventHeaderDisplay->clear();
101 return;
102 }
103 RunHeader *R = RD->RHeader;
104
105 // Print event header and trigger cell information from event data
106 rewind(Tmpfile);
107 QTextStream in(Tmpfile);
108 QString text = in.readAll();
109
110 text.append("\nTrigger cells: ");
111 for (unsigned int i=0; i<R->NBoards*R->NChips; i++) {
112 QString a;
113 text.append(a.sprintf("%d ", *((int *)RD->Data + i)));
114 }
115 EventHeaderDisplay->setPlainText(text);
116
117 // Case data in double format required by qwt library
118 double *x = new double [R->Samples];
119 double *y = new double [R->Samples];
120
121 for (unsigned int i=0; i<R->Samples; i++) {
122 x[i] = (double) (i/RD->BStruct[BoardNo->value()].NomFreq);
123 if (PhysPipeAction->isChecked()) {
124 y[(i + *((int *) RD->Data + BoardNo->value()*R->NChips+ChipNo->value()))%1024] =
125 (double) *((short *) (RD->Data + R->NBoards*R->NChips*sizeof(int)) +
126 BoardNo->value()*R->NChips*R->NChannels*R->Samples +
127 ChipNo->value()*R->NChannels*R->Samples +
128 ChannelNo->value()*RD->RHeader->Samples + i) * RD->BStruct[BoardNo->value()].ScaleFactor;
129 }
130 else {
131 y[i] = (double) *((short *) (RD->Data + R->NBoards*R->NChips*sizeof(int)) +
132 BoardNo->value()*R->NChips*R->NChannels*R->Samples +
133 ChipNo->value()*R->NChannels*R->Samples +
134 ChannelNo->value()*R->Samples + i) * RD->BStruct[BoardNo->value()].ScaleFactor;
135 }
136 }
137
138 Signal->setData(x, y, (int) R->Samples);
139 Signal->show();
140 Zoomer->setZoomBase(Signal->boundingRect());
141
142 delete[] x; delete[] y;
143
144}
145
146// +++ Open sub window handling the socket interface +++
147void ddd::OpenSocketWindow() {
148
149 if(SocketWindow->isVisible()) SocketWindow->hide();
150 else SocketWindow->show();
151}
152
153// +++ Acquire data through socket (acquire botton only available if socket exists) +++
154void ddd::GetSignalFromSocket() {
155 char Command[MAX_COM_SIZE];
156
157 GetButton->setEnabled(false);
158 WaitForData = true;
159 sprintf(Command, "read %d %d %d restart", BoardNo->value(), ChipNo->value(), ChannelNo->value());
160 Socket->write(Command);
161}
162
163// Quit application when clicking close button on window
164void ddd::closeEvent(QCloseEvent *) {
165 qApp->quit();
166}
167
168// +++ Connecting or disconnecting from client +++
169void ddd::MakeConnection() {
170
171 if(Socket->state() == QAbstractSocket::ConnectedState) {
172 ManualDisconnect = true;
173 Socket->disconnectFromHost();
174 }
175 else {
176 if (RD->IsFileOpen() && QMessageBox::question(this, "ddd Request","Connecting will close current data file. Proceed?",
177 QMessageBox::No, QMessageBox::Yes) != QMessageBox::Yes) return;
178
179 PhysPipeAction->setChecked(false);
180
181 Socket->connectToHost(IPAddress->text(),Port->value());
182 Connect->setEnabled(false); // While waiting for connection, button not available
183 Socket->waitForConnected(SOCKET_TIMEOUT);
184 Connect->setEnabled(true);
185 if(Socket->state() != QAbstractSocket::ConnectedState)
186 QMessageBox::warning(this, "ddd Message","Could not connect to host.",QMessageBox::Ok);
187 else {
188 Connect->setText("Disconnect");
189 ConnectAction->setText("Disconnect");
190 Port->setEnabled(false);
191 IPAddress->setEnabled(false);
192 Command->setEnabled(true);
193 GetButton->setEnabled(true);
194 ManualDisconnect = false;
195
196 FilenameBox->clear();
197 CloseDatafile();
198
199 ChannelNo->setEnabled(true);
200 ChipNo->setEnabled(true);
201 BoardNo->setEnabled(true);
202 PixelID->setEnabled(true);
203 ChannelNo->setRange(0, 65535);
204 ChipNo->setRange(0, 65535);
205 BoardNo->setRange(0, 65535);
206
207 TabWidget->setTabEnabled(1,false);
208 TabWidget->setTabEnabled(2,false);
209
210 RunHeaderDisplay->clear();
211 EventHeaderDisplay->clear();
212 Signal->hide();
213 }
214 }
215}
216
217// +++ Send command to socket (command button available only if socket existing) +++
218void ddd::SendToSocket() {
219 Socket->write(Command->text().toAscii());
220 Command->clear();
221}
222
223// +++ Read data from socket and display +++
224void ddd::ReadFromSocket() {
225 // Check if channel data expected and error message arrived
226 QByteArray Data = Socket->readAll();
227 if (WaitForData && Data.contains("Error")) {
228 WaitForData = false;
229 GetButton->setEnabled(true);
230 QMessageBox::warning(this, "ddd Message","Could not read waveform data from socket.",QMessageBox::Ok);
231 return;
232 }
233
234 // Check if channel data were transmitted, if yes and waiting for data, extract and plot them
235 SocketOutput->insertPlainText(Data);
236 QString Text = SocketOutput->document()->toPlainText().trimmed();
237 if (WaitForData && Text.endsWith(QLatin1String("==END=="))) {
238 // Extract text between ==START== and ==END==
239 QByteArray Data = Text.mid(Text.lastIndexOf("==START==")+9, Text.length() - Text.lastIndexOf("==START==")-16).toAscii();
240
241 char *NextNumber = strtok(Data.data()," "); // Number of entries that follow
242 int Count=0, NumberOfEntries = atoi(NextNumber);
243 double *x = new double [NumberOfEntries];
244 double *y = new double [NumberOfEntries];
245
246 // Convert all entries (separated by a whitespace) to numbers
247 while((NextNumber=strtok(NULL, " "))!=NULL && Count<NumberOfEntries)
248 *(y+Count++) = atof(NextNumber);
249 if (Count==NumberOfEntries && NextNumber!=0)
250 QMessageBox::warning(this, "ddd Message","Found too many numbers in data block, truncated.",QMessageBox::Ok);
251 // Apply sampling frequency and scaling factor
252 for(int i=2; i<Count; i++) {
253 x[i] = (i-2) / y[0];
254 y[i] = y[i] * y[1];
255 }
256 if(NumberOfEntries>2) {
257 Signal->setData(x+2, y+2, NumberOfEntries-2); // Copies data, arrays can be deleted afterwards
258 Signal->show();
259 Zoomer->setZoomBase(Signal->boundingRect());
260 Graph->setAxisTitle(QwtPlot::xBottom, "Time from trigger (ns)");
261 }
262 delete[] x; delete[] y;
263
264 if(ContinuousBox->isChecked()) {
265 usleep(100000); // Wait to limit maximum update rate
266 GetSignalFromSocket();
267 }
268 else {
269 WaitForData = false;
270 GetButton->setEnabled(true);
271 }
272 }
273}
274
275// +++ Reset graph axes to autoscale when fully unzoomed +++
276void ddd::HandleZoom(const QwtDoubleRect &) {
277 if(Zoomer->zoomRectIndex() == 0) {
278 Graph->setAxisAutoScale(QwtPlot::xBottom);
279 Graph->setAxisAutoScale(QwtPlot::yLeft);
280 }
281}
282
283// +++ Disconnect from socket +++
284void ddd::GotDisconnected() {
285 Connect->setText("Connect");
286 ConnectAction->setText("Connect");
287 Port->setEnabled(true);
288 IPAddress->setEnabled(true);
289 Command->setEnabled(false);
290
291 GetButton->setEnabled(false);
292 ChannelNo->setEnabled(false);
293 ChipNo->setEnabled(false);
294 BoardNo->setEnabled(false);
295 PixelID->setEnabled(false);
296 Signal->hide();
297 TabWidget->setTabEnabled(1, true);
298 TabWidget->setTabEnabled(2, true);
299
300 SocketOutput->clear();
301 if(!ManualDisconnect) QMessageBox::warning(this, "ddd Message","Socket disconnected, maybe host gone.",QMessageBox::Ok);
302}
303
304// +++ Translate pixel ID +++
305void ddd::TranslatePixelID(int ID) {
306
307 // setValue() below will call UpdateScope() through signal, therefore need to store numbers here
308 int Board = PixMap->Pixel_to_FPAboard(ID);
309 int Chip = PixMap->Pixel_to_FPApatch(ID);
310 int Channel = PixMap->Pixel_to_FPApixel(ID);
311
312 if(Board >= BoardNo->minimum() && Board <= BoardNo->maximum() &&
313 Chip >= ChipNo->minimum() && Chip <= ChipNo->maximum() &&
314 Channel>= ChannelNo->minimum() && Channel <= ChannelNo->maximum()) {
315 BoardNo->setValue(Board);
316 ChipNo->setValue(Chip);
317 ChannelNo->setValue(Channel);
318 }
319 else if (Board == (int) PixMap->PM_ERROR_CODE) PixelID->setValue(-1);
320 else QMessageBox::warning(this, "ddd Message","Pixel ID out of current range.",QMessageBox::Ok);
321}
322
323
324//------------------------------------------------------------------
325//**************************** All menus ***************************
326//------------------------------------------------------------------
327
328void ddd::MenuSave() {
329 QString Filename = QFileDialog::getSaveFileName(this,
330 "Filename of image", "/home/ogrimm/ddd", "Image files (*.bmp *.jpg *.png *.ppm *.tiff *.xbm *.xpm);;All files (*)");
331 if (Filename.length()>0) {
332 QPixmap Pixmap = QPixmap::grabWidget(Graph);
333 if(!Pixmap.save(Filename)) {
334 QMessageBox::warning(this, "ddd Message","Could not write image file.",QMessageBox::Ok);
335 remove(Filename.toAscii().data());
336 }
337 }
338}
339
340void ddd::MenuPrint() {
341 QPrinter *Printer = new QPrinter;
342 QPrintDialog *PrintDialog = new QPrintDialog(Printer, this);
343 if (PrintDialog->exec() == QDialog::Accepted) {
344 QPainter Painter(Printer);
345 QPixmap Pixmap = QPixmap::grabWidget(Graph);
346 Painter.drawPixmap(0, 0, Pixmap);
347 }
348 delete Printer; delete PrintDialog;
349}
350
351void ddd::MenuSaveASCII() {
352 QString Filename = QFileDialog::getSaveFileName(this,
353 "Filename", ".", "Text files (*.txt *.ascii *.asc);;All files (*)");
354 if (Filename.length()>0) {
355 QFile File(Filename);
356 if (File.open(QFile::WriteOnly | QIODevice::Text | QFile::Truncate)) {
357 QTextStream Stream(&File);
358 for (int i=0; i<Signal->dataSize(); i++) {
359 Stream << Signal->y(i) << endl;
360 }
361 }
362 else {
363 QMessageBox::warning(this, "ddd Message","Could not write data to file.",QMessageBox::Ok);
364 }
365 }
366}
367
368void ddd::MenuHelp() {
369 QMessageBox Message;
370 Message.setText("The DRS Data Display program can be used for two purposes:\n\n"
371 "1. Reading and displaying the content of a raw data file written by the drsdaq program\n"
372 "2. Acquiring and displaying online data from a running drsdaq program via the socket interface\n\n"
373 "With an established socket connection, displaying of raw data files is disabled.\n\n"
374 "Navigation in signal display: Left mouse button to zoom, right to unzoom fully, middle to unzoom one level. Left mouse button plus shift key to pan.\n"
375 "When unzoomed, the axes are rescaled automatically.");
376
377 Message.setWindowTitle("ddd Help");
378 Message.exec();
379}
380
381void ddd::MenuAbout() {
382 QMessageBox::about(this, "ddd About","DRS Data Display\n\n"
383 "Written by Oliver Grimm, IPP, ETH Zurich\n"
384 "Event display by Quirin Weitzel.\n\n"
385 "This version compiled "__DATE__".\n\n"
386 "Graphical user interface implemented with Qt.\n"
387 "Bug reports to oliver.grimm@phys.ethz.ch.");
388}
Note: See TracBrowser for help on using the repository browser.