source: fact/FADctrl/FADBoard.cc@ 10120

Last change on this file since 10120 was 10120, checked in by ogrimm, 14 years ago
Moved OpenOtherSockets() to FADBoard class
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 // Lock to avoid concurrent access in GetStatus()
430 Lock();
431
432 // Wait until event thread processed the previous data
433 while (!Continue) {
434 if ((Ret = pthread_cond_wait(&CondVar, &Mutex)) != 0) {
435 m->Message(m->ERROR, "pthread_cond_wait() failed (%s)", strerror(Ret));
436 }
437 }
438
439 gettimeofday(&Status.Update, NULL);
440
441 // Extract ID and type information
442 Status.BoardID = ntohl(Header->board_id);
443 Status.FirmwareRevision = ntohl(Header->version_no);
444 Status.TriggerID = ntohl(Header->local_trigger_id);
445 Status.TriggerType = ntohs(Header->local_trigger_type);
446
447 // Extract temperatures (MSB indicates if temperature is positive or negative)
448 for (unsigned int i=0; i<NTemp; i++) {
449 if ((ntohs(Header->drs_temperature[i]) & 0x8000) == 0) Status.Temp[i] = float(ntohs(Header->drs_temperature[i]) >> 3)/16;
450 else Status.Temp[i] = float(0xE000 | (ntohs(Header->drs_temperature[i])) >> 3)/16;
451 }
452
453 // Extract DAC channels
454 for (unsigned int i=0; i<NDAC; i++) Status.DAC[i] = ntohs(Header->dac[i]);
455
456 short Buf;
457 for (unsigned int Chip=0; Chip<NChips; Chip++) {
458 // Extract trigger cells
459 Status.TriggerCell[Chip] = (int) ntohs(Channel[Chip]->start_cell);
460
461 for (unsigned int Chan=0; Chan<NChannels; Chan++) {
462 // Extract ROI
463 Status.ROI[Chip][Chan] = ntohs(Channel[Chip+NChips*Chan]->roi);
464
465 // Extract ADC data (stored in 12 bit signed twis complement with out-of-range-bit and leading zeroes)
466 for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
467 Buf = ntohs(Channel[Chip+NChips*Chan]->adc_data[i]);
468 (Buf <<= 4) >>= 4; //delete the sign-bit by shifting left and shift back
469 Data[Chip][Chan][i] = Buf;
470 }
471 }
472 }
473
474 // Prepare predicate for condition variable
475 Continue = false;
476 Unlock();
477
478 // Amplitude calibration (will check if Mode is acalib)
479 AmplitudeCalibration();
480
481 // Update DIM services if necessary
482 if (memcmp(PrevStatus.Temp, Status.Temp, sizeof(Status.Temp)) != 0) {
483 DIM_Temp->updateService(Status.Temp, sizeof(Status.Temp));
484 }
485 if (memcmp(PrevStatus.DAC, Status.DAC, sizeof(Status.DAC)) != 0) {
486 DIM_DAC->updateService(Status.DAC, sizeof(Status.DAC));
487 }
488 if (memcmp(PrevStatus.ROI, Status.ROI, sizeof(Status.ROI)) != 0) {
489 DIM_ROI->updateService(Status.ROI, sizeof(Status.ROI));
490 }
491 if (PrevStatus.BoardID != Status.BoardID) {
492 DIM_ID->updateService(&Status.BoardID, sizeof(Status.BoardID));
493 }
494 }
495 else printf("End package flag incorrect, removing corrupt event\n");
496
497 // Inform event thread of new data
498 string Message = string("EVENT")+Name;
499 if (write(m->Pipe[1], Message.data(), Message.size()) == -1) {
500 m->Message(m->ERROR, "write() to Pipe[1] failed in class FADBoard (%s)", strerror(errno));
501 m->ExitRequest = true;
502 }
503
504 // Remove event data from internal buffer
505 memmove(Buffer, Buffer+Length, Pos-Length);
506 Pos = Pos-Length;
507 } // while()
508}
509
510
511//
512// Launch read thread inside class
513//
514void FADBoard::LaunchThread(class FADBoard *m) {
515
516 m->ReadLoop();
517}
518
519
520//
521// Lock and unlock mutex
522//
523void FADBoard::Lock() {
524
525 int Ret;
526
527 if ((Ret = pthread_mutex_lock(&Mutex)) != 0) {
528 m->Message(m->FATAL, "pthread_mutex_lock() failed in class FADBoard (%s)", strerror(Ret));
529 }
530}
531
532void FADBoard::Unlock() {
533
534 int Ret;
535
536 if ((Ret = pthread_mutex_unlock(&Mutex)) != 0) {
537 m->Message(m->FATAL, "pthread_mutex_unlock() failed in class FADBoard (%s)", strerror(Ret));
538 }
539}
540
541
542//
543// OpenOtherSockets()
544//
545void FADBoard::OpenOtherSockets(char *Hostname) {
546
547 int List[] = {5001, 5002, 5003, 5004, 5005, 5006, 5007};
548 int Socket[sizeof(List)/sizeof(int)], MaxSocketNum=0, Ret;
549 fd_set DescriptorList;
550 char Buffer[1000000];
551
552 // Resolve hostname
553 struct hostent *Host = gethostbyname(Hostname);
554 if (Host == 0) {
555 printf("OtherSockets: Could not resolve host name for %s\n", Hostname);
556 return;
557 }
558
559 // Connect to server
560 struct sockaddr_in SocketAddress;
561 SocketAddress.sin_family = PF_INET;
562 SocketAddress.sin_addr = *(struct in_addr*) Host->h_addr;
563
564 for (unsigned int i=0; i<sizeof(List)/sizeof(int); i++) {
565 // Open socket descriptor
566 if ((Socket[i] = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
567 printf("OtherSockets: Could not open socket for port %d (%s)\n", List[i], strerror(errno));
568 return;
569 }
570
571 // Determine highest socket number for select()
572 if (Socket[i] > MaxSocketNum) MaxSocketNum = Socket[i];
573
574 // Connect to server
575 SocketAddress.sin_port = htons((unsigned short) List[i]);
576 if (connect(Socket[i], (struct sockaddr *) &SocketAddress, sizeof(SocketAddress)) == -1) {
577 printf("OtherSockets: Could not connect to port %d (%s)\n", List[i], strerror(errno));
578 return;
579 }
580 }
581
582 while(true) {
583 // Wait for data from terminal (stdin) or from sockets
584 FD_ZERO(&DescriptorList);
585 for (unsigned int i=0; i<sizeof(List)/sizeof(int); i++) FD_SET(Socket[i], &DescriptorList);
586 if (select(MaxSocketNum+1, &DescriptorList, NULL, NULL, NULL) == -1) {
587 perror("OtherSockets: Error with select()");
588 break;
589 }
590
591 // Data from socket
592 for (unsigned int i=0; i<sizeof(List)/sizeof(int); i++) if (FD_ISSET(Socket[i], &DescriptorList)) {
593 Ret = read(Socket[i], Buffer, sizeof(Buffer));
594 if(Ret == 0) printf("OtherSockets: Connection to port %d not existing anymore\n", List[i]);
595 else if (Ret == -1) printf("OtherSockets: Error reading from port %d (%s)\n", List[i], strerror(errno));
596 else ;//printf("OtherSockets: Read %d bytes from port %d\n", Ret, List[i]);
597 }
598 }
599
600 // Close all sockets
601 for (unsigned int i=0; i<sizeof(List)/sizeof(int); i++) {
602 if ((Socket[i] != -1) && (close(Socket[i]) == -1)) {
603 printf("OtherSockets: Could not close socket of port %d (%s)", List[i], strerror(errno));
604 }
605 }
606}
Note: See TracBrowser for help on using the repository browser.