source: fact/FADctrl/FADBoard.cc @ 10212

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