source: fact/FADctrl/FADBoard.cc @ 10120

Last change on this file since 10120 was 10120, checked in by ogrimm, 9 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.