source: fact/FADctrl/FADBoard.cc@ 10160

Last change on this file since 10160 was 10128, checked in by ogrimm, 14 years ago
Warning for data taking if amplitude calibration not done
File size: 17.8 KB
Line 
1/********************************************************************\
2
3 Class interfacing to FAD board
4
5\********************************************************************/
6
7#include "FADBoard.h"
8using namespace std;
9
10//
11// Constructor
12//
13FADBoard::FADBoard(string Server, unsigned short Port, class FAD *Parent, unsigned int Num) {
14
15 int Ret;
16
17 // Initialization
18 m = Parent;
19 InitOK = false;
20 Active = true;
21 Continue = true;
22 CommError = false;
23 ACalibTime = -1;
24 Status.Update.tv_sec = -1;
25
26 Name = new char [Server.size()+1]; // Name in permanent memory for DIM service
27 strcpy(Name, Server.c_str());
28
29 // Initialise mutex for synchronization
30 pthread_mutexattr_t Attr;
31
32 if ((Ret = pthread_mutexattr_settype(&Attr, PTHREAD_MUTEX_ERRORCHECK)) != 0) {
33 m->Message(m->ERROR, "pthread_mutex_settype() failed (%s)", strerror(Ret));
34 }
35 if ((Ret = pthread_mutex_init(&Mutex, &Attr)) != 0) {
36 m->Message(m->FATAL, "pthread_mutex_init() failed (%s)", strerror(Ret));
37 }
38
39 // Initialise condition variable for synchronization
40 if ((Ret = pthread_cond_init(&CondVar, NULL)) != 0) {
41 m->Message(m->FATAL, "pthread_cond_init() failed (%s)", strerror(Ret));
42 }
43
44 // Resolve hostname
45 struct hostent *Host = gethostbyname(Server.c_str());
46 if (Host == 0) {
47 m->PrintMessage("Could not resolve host name for %s\n", Server.c_str());
48 return;
49 }
50
51 // Open socket descriptor
52 if ((Socket = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
53 m->Message(m->ERROR, "Could not open socket for %s (%s)\n", Server.c_str(), strerror(errno));
54 return;
55 }
56
57 // Connect to server
58 struct sockaddr_in SocketAddress;
59 SocketAddress.sin_family = PF_INET;
60 SocketAddress.sin_port = htons(Port);
61 SocketAddress.sin_addr = *(struct in_addr*) Host->h_addr;
62
63 if (connect(Socket, (struct sockaddr *) &SocketAddress, sizeof(SocketAddress)) == -1) {
64 m->PrintMessage("Could not connect to %s at port %d (%s)\n", Server.c_str(), Port, strerror(errno));
65 return;
66 }
67
68 // Construct DIM service name prefix
69 stringstream ID;
70 ID << SERVER_NAME"/Board" << setfill('0') << setw(2) << Num << "/";
71
72 DIM_Name = new DimService((ID.str()+"Server").c_str(), Name);
73 DIM_ID = new DimService((ID.str()+"BoardID").c_str(), (char *) "S", NULL, 0);
74 DIM_Temp = new DimService((ID.str()+"Temperature").c_str(), (char *) "F", NULL, 0);
75 DIM_DAC = new DimService((ID.str()+"DAC").c_str(), (char *) "S", NULL, 0);
76 DIM_ROI = new DimService((ID.str()+"ROI").c_str(), (char *) "S", NULL, 0);
77
78 // Create thread that receives data
79 if ((Ret = pthread_create(&Thread, NULL, (void * (*)(void *)) LaunchThread,(void *) this)) != 0) {
80 m->Message(m->FATAL, "pthread_create() failed in FADBoard() (%s)", strerror(Ret));
81 }
82
83 // Create thread to connect to other sockets
84 if ((Ret = pthread_create(&OtherThread, NULL, (void * (*)(void *)) OpenOtherSockets, (void *) Name)) != 0) {
85 m->Message(m->FATAL, "pthread_create() failed for OpenOtherSockets (%s)", strerror(Ret));
86 }
87
88 InitOK = true;
89}
90
91//
92// Destructor
93//
94FADBoard::~FADBoard() {
95
96 int Ret;
97
98 // Avoid segmentation faults by chekcing for InitOK
99 if (InitOK) {
100 // Terminate thread for other sockets
101 if ((Ret = pthread_cancel(OtherThread)) != 0) {
102 m->Message(m->ERROR, "pthread_cancel() failed in ~FADBoard() for OtherThread (%s)", strerror(Ret));
103 }
104 if ((Ret = pthread_join(OtherThread, NULL)) != 0) {
105 m->Message(m->ERROR, "pthread_join() failed in ~FADBoard for OtherThread (%s)", strerror(Ret));
106 }
107
108 // Cancel thread (if it did not quit already) and wait for it to quit
109 if ((Ret = pthread_cancel(Thread)) != 0 && Ret != ESRCH) {
110 m->Message(m->ERROR, "pthread_cancel() failed in ~FADBoard() (%s)", strerror(Ret));
111 }
112 if ((Ret = pthread_join(Thread, NULL)) != 0) {
113 m->Message(m->ERROR, "pthread_join() failed in ~FADBoard (%s)", strerror(Ret));
114 }
115
116 delete DIM_Name;
117 delete DIM_ID;
118 delete DIM_Temp;
119 delete DIM_DAC;
120 delete DIM_ROI;
121 }
122
123 delete[] Name;
124
125 // Close socket descriptor
126 if ((Socket != -1) && (close(Socket) == -1)) {
127 m->PrintMessage("Could not close socket descriptor (%s)", strerror(errno));
128 }
129
130 // Delete condition variable
131 if ((Ret = pthread_cond_destroy(&CondVar)) != 0) {
132 m->Message(m->ERROR, "pthread_cond_destroy() failed in ~FADBoard (%s)", strerror(Ret));
133 }
134
135 // Delete mutex
136 if ((Ret = pthread_mutex_destroy(&Mutex)) != 0) {
137 m->Message(m->ERROR, "pthread_mutex_destroy() failed in ~FADBoard (%s)", strerror(Ret));
138 }
139}
140
141
142//
143// Send data to board
144//
145void FADBoard::Send(const void *Data, size_t Bytes) {
146
147 // Do not send if not active
148 if (!Active) return;
149
150 // Write data
151 ssize_t Result = write(Socket, Data, Bytes);
152
153 // Check result
154 if (Result == -1) m->PrintMessage("Error: Could not write to socket (%s)\n", strerror(errno));
155 else if ((size_t) Result < Bytes) m->PrintMessage("Error: Could only write %d bytes out of %d to socket\n", Result, Bytes);
156}
157
158void FADBoard::Send(unsigned short Data) {
159
160 unsigned short Buffer = htons(Data);
161
162 Send(&Buffer, sizeof(unsigned short));
163}
164
165
166//
167// Get board status (mutex protected to avoid concurrent access in ReadLoop)
168//
169struct FADBoard::BoardStatus FADBoard::GetStatus() {
170
171 int Ret;
172 struct BoardStatus S;
173
174 // Lock
175 if ((Ret = pthread_mutex_lock(&Mutex)) != 0) {
176 m->Message(m->FATAL, "pthread_mutex_lock() failed in ReadLoop() (%s)", strerror(Ret));
177 }
178
179 S = Status;
180
181 // Unlock
182 if ((Ret = pthread_mutex_unlock(&Mutex)) != 0) {
183 m->Message(m->FATAL, "pthread_mutex_unlock() failed in Unlock() (%s)", strerror(Ret));
184 }
185
186 return S;
187}
188
189
190//
191// Perform amplitude calibration in steps
192//
193void FADBoard::AmplitudeCalibration() {
194
195 enum StateType {wait, init, baseline, gain, secondary};
196
197 static struct BoardStatus InitialStatus;
198 static vector<unsigned short> ROICmd;
199 static unsigned short DACCmd[] = {htons(CMD_Write | (BADDR_DAC + 1)), 0, htons(CMD_Write | (BADDR_DAC + 2)), 0, htons(CMD_Write | (BADDR_DAC + 3)), 0};
200 static StateType State = wait;
201 static int Count = 0;
202
203 // Check if mode is amplitude calibration
204 if (m->Mode != m->acalib) {
205 State = init;
206 return;
207 }
208
209 switch (State) {
210 // ====== Part A: Initialization =====
211 case init:
212 // Invalidate current calibration
213 ACalibTime = -1;
214
215 // Save initial board status, set all ROIs to 1024 and set DAC values
216 InitialStatus = GetStatus();
217
218 for (unsigned int i=0; i<NChips*NChannels; i++) {
219 ROICmd.push_back(htons(CMD_Write | (BADDR_ROI + i)));
220 ROICmd.push_back(htons(NBins));
221 }
222 Send(&ROICmd[0], ROICmd.size()*sizeof(unsigned short));
223
224 DACCmd[1] = htons(0);
225 DACCmd[3] = htons(0);
226 DACCmd[5] = htons(0);
227 Send(DACCmd, sizeof(DACCmd));
228
229 // Clear sum vector and set state to accumulate
230 memset(Sum, 0, sizeof(Sum));
231 State = baseline;
232 break;
233
234 // ====== Part B: Baseline calibration =====
235 case baseline:
236 for (unsigned int Chip=0; Chip<NChips; Chip++) {
237 for (unsigned int Chan=0; Chan<NChannels; Chan++) {
238 for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
239 Sum[Chip][Chan][(i+Status.TriggerCell[Chip]) % NBins] += Data[Chip][Chan][i];
240 }
241 }
242 }
243 Count++;
244
245 // Determine baseline if integration finished
246 if (Count == m->NumEventsRequested) {
247 for (unsigned int i=0; i<NChips; i++) {
248 for (unsigned int j=0; j<NChannels; j++) {
249 for (unsigned int k=0; k<NBins; k++) {
250 Baseline[i][j][k] = Sum[i][j][k] / m->NumEventsRequested;
251 }
252 }
253 }
254
255 // Set new DAC values and start accumulation
256 DACCmd[1] = htons(50000);
257 DACCmd[3] = htons(50000);
258 DACCmd[5] = htons(50000);
259 Send(DACCmd, sizeof(DACCmd));
260
261 // Clear sum vector and set state to accumulate
262 memset(Sum, 0, sizeof(Sum));
263 Count = 0;
264 State = gain;
265 }
266 break;
267
268 // ====== Part C: Gain calibration =====
269 case gain:
270 for (unsigned int Chip=0; Chip<NChips; Chip++) {
271 for (unsigned int Chan=0; Chan<NChannels; Chan++) {
272 for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
273 Sum[Chip][Chan][(i+Status.TriggerCell[Chip]) % NBins] += Data[Chip][Chan][i];
274 }
275 }
276 }
277 Count++;
278
279 // Determine gain if integration finished
280 if (Count == m->NumEventsRequested) {
281 for (unsigned int i=0; i<NChips; i++) {
282 for (unsigned int j=0; j<NChannels; j++) {
283 for (unsigned int k=0; k<NBins; k++) {
284 Gain[i][j][k] = (Sum[i][j][k] / m->NumEventsRequested) - Baseline[i][j][k];
285 }
286 }
287 }
288
289 // Set new DAC values and start accumulation
290 DACCmd[1] = htons(0);
291 DACCmd[3] = htons(0);
292 DACCmd[5] = htons(0);
293 Send(DACCmd, sizeof(DACCmd));
294
295 // Clear sum vector and set state to accumulate
296 memset(Sum, 0, sizeof(Sum));
297 Count = 0;
298 State = secondary;
299 }
300 break;
301
302 // ====== Part D: Secondary calibration =====
303 case secondary:
304 for (unsigned int Chip=0; Chip<NChips; Chip++) {
305 for (unsigned int Chan=0; Chan<NChannels; Chan++) {
306 for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
307 Sum[Chip][Chan][i] = Data[Chip][Chan][i] - Baseline[Chip][Chan][(i-Status.TriggerCell[Chip]) % NBins];
308 }
309 }
310 }
311 Count++;
312
313 // Determine secondary baseline if integration finished
314 if (Count == m->NumEventsRequested) {
315 for (unsigned int i=0; i<NChips; i++) {
316 for (unsigned int j=0; j<NChannels; j++) {
317 for (unsigned int k=0; k<NBins; k++) {
318 SecondaryBaseline[i][j][k] = Sum[i][j][k] / (double) m->NumEventsRequested;
319 }
320 }
321 }
322
323 // Write back original ROI and DAC settings
324 ROICmd.clear();
325 for (unsigned int i=0; i<NChips*NChannels; i++) {
326 ROICmd.push_back(htons(CMD_Write | (BADDR_ROI + i)));
327 ROICmd.push_back(htons(InitialStatus.ROI[i/NChannels][i%NChannels]));
328 }
329 Send(&ROICmd[0], ROICmd.size()*sizeof(unsigned short));
330
331 DACCmd[1] = htons(InitialStatus.DAC[1]);
332 DACCmd[3] = htons(InitialStatus.DAC[2]);
333 DACCmd[5] = htons(InitialStatus.DAC[3]);
334 Send(DACCmd, sizeof(DACCmd));
335
336 // Store calibration time and temperature
337 ACalibTime = time(NULL);
338 ACalibTemp = 0;
339 for (unsigned int i=0; i<NTemp; i++) ACalibTemp += Status.Temp[i] / NTemp;
340
341 // Inform event thread that calibration is finished
342 string Message = string("ACALIBDONE")+Name;
343 if (write(m->Pipe[1], Message.data(), Message.size()) == -1) {
344 m->Message(m->ERROR, "write() to Pipe[1] failed in class FADBoard::AmplitudeCalibration (%s)", strerror(errno));
345 }
346
347 State = wait;
348 }
349 break;
350
351 // ====== Wait for Mode not being acalib =====
352 case wait:
353 if (m->Mode != m->acalib) State = init;
354 break;
355 }
356}
357
358//
359// Read data from board
360//
361void FADBoard::ReadLoop() {
362
363 static char Buffer[READ_BUFFER_SIZE];
364 static unsigned int Pos = 0, Temp;
365 const PEVNT_HEADER *Header = (PEVNT_HEADER *) Buffer;
366 ssize_t Result;
367 struct BoardStatus PrevStatus;
368 int Ret;
369
370 memset(&PrevStatus, 0, sizeof(PrevStatus));
371
372 while (!m->ExitRequest) {
373 // Read data from socket
374 Result = read(Socket, Buffer + Pos, sizeof(Buffer)-Pos);
375
376 // Check result of read
377 if (Result == -1) {
378 m->PrintMessage("Error: Could not read from socket, exiting read loop (%s)\n", strerror(errno));
379 CommError = true;
380 break;
381 }
382 else if (Result == 0) {
383 m->PrintMessage("Server not existing anymore, exiting read loop\n");
384 CommError = true;
385 break;
386 }
387
388 // If not active, discard incoming data
389 if (!Active) continue;
390
391 // Advance write pointer
392 Pos += Result;
393
394 // Check if internal buffer full
395 if (Pos == sizeof(Buffer)) {
396 m->PrintMessage("Internal buffer full, deleting all data in buffer\n");
397 Pos = 0;
398 continue;
399 }
400
401 // Check if buffer starts with start_package_flag, remove data if not
402 Temp = 0;
403 while (ntohs(*((unsigned short *) (Buffer+Temp))) != 0xfb01 && Temp<Pos) Temp++;
404 if (Temp != 0) {
405 memmove(Buffer, Buffer+Temp, Pos-Temp);
406 Pos -= Temp;
407 m->PrintMessage("Removed %d bytes because of start_package_flag not found\n", Temp);
408 continue;
409 }
410
411 // Wait until the buffer contains at least enough bytes to potentially hold a PEVNT_HEADER
412 if (Pos < sizeof(PEVNT_HEADER)) continue;
413
414 unsigned int Length = ntohs(Header->package_length)*2*sizeof(char);
415 if (Pos < Length) continue;
416
417 // Extract data if event end package flag correct
418 if (ntohs(*(unsigned short *) (Buffer+Length-sizeof(unsigned short))) == 0x04FE) {
419
420 // Prepare pointers to channel data (channels stored in order 0,9,18,27 - 1,10,19,28 - ... - 8,17,26,35)
421 PCHANNEL *Channel[NChips*NChannels], *Pnt=(PCHANNEL *) (Header+1);
422 for(unsigned int i=0; i<NChips*NChannels; i++) {
423 Channel[i] = Pnt;
424 Pnt = (PCHANNEL *) ((short *) (Channel[i] + 1) + ntohs(Channel[i]->roi));
425 }
426
427 PrevStatus = Status;
428
429 // Wait until event thread processed the previous data and lock to avoid concurrent access in GetStatus()
430 Lock();
431 while (!Continue) {
432 if ((Ret = pthread_cond_wait(&CondVar, &Mutex)) != 0) {
433 m->Message(m->ERROR, "pthread_cond_wait() failed (%s)", strerror(Ret));
434 }
435 }
436 gettimeofday(&Status.Update, NULL);
437
438 // Extract ID and type information
439 Status.BoardID = ntohl(Header->board_id);
440 Status.FirmwareRevision = ntohl(Header->version_no);
441 Status.TriggerID = ntohl(Header->local_trigger_id);
442 Status.TriggerType = ntohs(Header->local_trigger_type);
443
444 // Extract temperatures (MSB indicates if temperature is positive or negative)
445 for (unsigned int i=0; i<NTemp; i++) {
446 if ((ntohs(Header->drs_temperature[i]) & 0x8000) == 0) Status.Temp[i] = float(ntohs(Header->drs_temperature[i]) >> 3)/16;
447 else Status.Temp[i] = float(0xE000 | (ntohs(Header->drs_temperature[i])) >> 3)/16;
448 }
449
450 // Extract DAC channels
451 for (unsigned int i=0; i<NDAC; i++) Status.DAC[i] = ntohs(Header->dac[i]);
452
453 short Buf;
454 for (unsigned int Chip=0; Chip<NChips; Chip++) {
455 // Extract trigger cells
456 Status.TriggerCell[Chip] = (int) ntohs(Channel[Chip]->start_cell);
457
458 for (unsigned int Chan=0; Chan<NChannels; Chan++) {
459 // Extract ROI
460 Status.ROI[Chip][Chan] = ntohs(Channel[Chip+NChips*Chan]->roi);
461
462 // Extract ADC data (stored in 12 bit signed twis complement with out-of-range-bit and leading zeroes)
463 for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
464 Buf = ntohs(Channel[Chip+NChips*Chan]->adc_data[i]);
465 (Buf <<= 4) >>= 4; //delete the sign-bit by shifting left and shift back
466 Data[Chip][Chan][i] = Buf;
467 }
468 }
469 }
470
471 // Prepare predicate for condition variable
472 Continue = false;
473 Unlock();
474
475 // Amplitude calibration (will check if Mode is acalib)
476 AmplitudeCalibration();
477
478 // Update DIM services if necessary
479 if (memcmp(PrevStatus.Temp, Status.Temp, sizeof(Status.Temp)) != 0) {
480 DIM_Temp->updateService(Status.Temp, sizeof(Status.Temp));
481 }
482 if (memcmp(PrevStatus.DAC, Status.DAC, sizeof(Status.DAC)) != 0) {
483 DIM_DAC->updateService(Status.DAC, sizeof(Status.DAC));
484 }
485 if (memcmp(PrevStatus.ROI, Status.ROI, sizeof(Status.ROI)) != 0) {
486 DIM_ROI->updateService(Status.ROI, sizeof(Status.ROI));
487 }
488 if (PrevStatus.BoardID != Status.BoardID) {
489 DIM_ID->updateService(&Status.BoardID, sizeof(Status.BoardID));
490 }
491 }
492 else printf("End package flag incorrect, removing corrupt event\n");
493
494 // Inform event thread of new data
495 string Message = string("EVENT")+Name;
496 if (write(m->Pipe[1], Message.data(), Message.size()) == -1) {
497 m->Message(m->ERROR, "write() to Pipe[1] failed in class FADBoard (%s)", strerror(errno));
498 m->ExitRequest = true;
499 }
500
501 // Remove event data from internal buffer
502 memmove(Buffer, Buffer+Length, Pos-Length);
503 Pos = Pos-Length;
504 } // while()
505}
506
507
508//
509// Launch read thread inside class
510//
511void FADBoard::LaunchThread(class FADBoard *m) {
512
513 m->ReadLoop();
514}
515
516
517//
518// Lock and unlock mutex
519//
520void FADBoard::Lock() {
521
522 int Ret;
523
524 if ((Ret = pthread_mutex_lock(&Mutex)) != 0) {
525 m->Message(m->FATAL, "pthread_mutex_lock() failed in class FADBoard (%s)", strerror(Ret));
526 }
527}
528
529void FADBoard::Unlock() {
530
531 int Ret;
532
533 if ((Ret = pthread_mutex_unlock(&Mutex)) != 0) {
534 m->Message(m->FATAL, "pthread_mutex_unlock() failed in class FADBoard (%s)", strerror(Ret));
535 }
536}
537
538
539//
540// OpenOtherSockets()
541//
542void FADBoard::OpenOtherSockets(char *Hostname) {
543
544 int List[] = {5001, 5002, 5003, 5004, 5005, 5006, 5007};
545 int Socket[sizeof(List)/sizeof(int)], MaxSocketNum=0, Ret;
546 fd_set DescriptorList;
547 char Buffer[1000000];
548
549 // Resolve hostname
550 struct hostent *Host = gethostbyname(Hostname);
551 if (Host == 0) {
552 printf("OtherSockets: Could not resolve host name for %s\n", Hostname);
553 return;
554 }
555
556 // Connect to server
557 struct sockaddr_in SocketAddress;
558 SocketAddress.sin_family = PF_INET;
559 SocketAddress.sin_addr = *(struct in_addr*) Host->h_addr;
560
561 for (unsigned int i=0; i<sizeof(List)/sizeof(int); i++) {
562 // Open socket descriptor
563 if ((Socket[i] = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
564 printf("OtherSockets: Could not open socket for port %d (%s)\n", List[i], strerror(errno));
565 return;
566 }
567
568 // Determine highest socket number for select()
569 if (Socket[i] > MaxSocketNum) MaxSocketNum = Socket[i];
570
571 // Connect to server
572 SocketAddress.sin_port = htons((unsigned short) List[i]);
573 if (connect(Socket[i], (struct sockaddr *) &SocketAddress, sizeof(SocketAddress)) == -1) {
574 printf("OtherSockets: Could not connect to port %d (%s)\n", List[i], strerror(errno));
575 return;
576 }
577 }
578
579 while(true) {
580 // Wait for data from terminal (stdin) or from sockets
581 FD_ZERO(&DescriptorList);
582 for (unsigned int i=0; i<sizeof(List)/sizeof(int); i++) FD_SET(Socket[i], &DescriptorList);
583 if (select(MaxSocketNum+1, &DescriptorList, NULL, NULL, NULL) == -1) {
584 perror("OtherSockets: Error with select()");
585 break;
586 }
587
588 // Data from socket
589 for (unsigned int i=0; i<sizeof(List)/sizeof(int); i++) if (FD_ISSET(Socket[i], &DescriptorList)) {
590 Ret = read(Socket[i], Buffer, sizeof(Buffer));
591 if(Ret == 0) printf("OtherSockets: Connection to port %d not existing anymore\n", List[i]);
592 else if (Ret == -1) printf("OtherSockets: Error reading from port %d (%s)\n", List[i], strerror(errno));
593 else ;//printf("OtherSockets: Read %d bytes from port %d\n", Ret, List[i]);
594 }
595 }
596
597 // Close all sockets
598 for (unsigned int i=0; i<sizeof(List)/sizeof(int); i++) {
599 if ((Socket[i] != -1) && (close(Socket[i]) == -1)) {
600 printf("OtherSockets: Could not close socket of port %d (%s)", List[i], strerror(errno));
601 }
602 }
603}
Note: See TracBrowser for help on using the repository browser.