source: fact/FADctrl/FADBoard.cc@ 14225

Last change on this file since 14225 was 14174, checked in by ogrimm, 12 years ago
Fixed hanging signal handler in Evidence before abort() was called. Added command to determine dynamic range to FADctrl.
File size: 26.1 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 = false;
20 Continue = true;
21 CommOK = false;
22 ACalib.Time = -1;
23 Status.Update.tv_sec = -1;
24 Port = ServerPort;
25 Status.Frequency = 0;
26 Status.Rate = 0;
27 Status.BoardID = 0;
28
29 Name = new char [Server.size()+1]; // Name in permanent memory for DIM service
30 strcpy(Name, Server.c_str());
31
32 // Initialise mutex for synchronization
33 pthread_mutexattr_t Attr;
34
35 if ((Ret = pthread_mutexattr_init(&Attr)) != 0) {
36 m->Message(m->ERROR, "pthread_mutex_init() failed in FADBoard constructor (%s)", strerror(Ret));
37 }
38 if ((Ret = pthread_mutexattr_settype(&Attr, PTHREAD_MUTEX_ERRORCHECK)) != 0) {
39 m->Message(m->ERROR, "pthread_mutex_settype() failed in FADBoard constructor (%s)", strerror(Ret));
40 }
41 if ((Ret = pthread_mutex_init(&Mutex, &Attr)) != 0) {
42 m->Message(m->FATAL, "pthread_mutex_init() failed in FADBoard constructor (%s)", strerror(Ret));
43 }
44
45 // Initialise condition variable for synchronization
46 if ((Ret = pthread_cond_init(&CondVar, NULL)) != 0) {
47 m->Message(m->FATAL, "pthread_cond_init() failed in FADBoard constructor (%s)", strerror(Ret));
48 }
49
50 // Construct DIM service name prefix
51 stringstream ID;
52 ID << SERVER_NAME"/Board" << setfill('0') << setw(2) << Num << "/";
53
54 DIM_Name = new DimService((ID.str()+"Server").c_str(), Name);
55 DIM_Status = new DimService((ID.str()+"Status").c_str(), (char *) "");
56 DIM_ID = new DimService((ID.str()+"BoardID").c_str(), (char *) "S", NULL, 0);
57 DIM_Rate = new DimService((ID.str()+"RateHz").c_str(), Status.Rate);
58 DIM_Frequency = new DimService((ID.str()+"Frequency").c_str(), Status.Frequency);
59 DIM_BoardTime = new DimService((ID.str()+"BoardTime").c_str(), (char *) "I", &Status.BoardTime, sizeof(Status.BoardTime));
60 DIM_Lock = new DimService((ID.str()+"Lock").c_str(), (char *) "S", NULL, 0);
61 DIM_TriggerNum = new DimService((ID.str()+"TriggerNum").c_str(), (char *) "I", &Status.TriggerNum, sizeof(Status.TriggerNum));
62 DIM_Temp = new DimService((ID.str()+"Temperature").c_str(), (char *) "F", NULL, 0);
63 DIM_DAC = new DimService((ID.str()+"DAC").c_str(), (char *) "S", NULL, 0);
64 DIM_ROI = new DimService((ID.str()+"ROI").c_str(), (char *) "S", NULL, 0);
65 DIM_ACalData = new DimService((ID.str()+"ACalData").c_str(), (char *) "F", NULL, 0);
66
67 // Create thread that connects and receives data
68 SetStatus("Trying to connect...");
69
70 if ((Ret = pthread_create(&Thread, NULL, (void * (*)(void *)) LaunchThread, (void *) this)) != 0) {
71 m->Message(m->FATAL, "pthread_create() failed in FADBoard() (%s)", strerror(Ret));
72 }
73
74 // Start thread to connect to other sockets
75 DimThread::start();
76}
77
78//
79// Destructor
80//
81FADBoard::~FADBoard() {
82
83 int Ret;
84
85 // Cancel thread (if it did not quit already) and wait for it to quit
86 if ((Ret = pthread_cancel(Thread)) != 0 && Ret != ESRCH) {
87 m->Message(m->ERROR, "pthread_cancel() failed in ~FADBoard() (%s)", strerror(Ret));
88 }
89 if ((Ret = pthread_join(Thread, NULL)) != 0) {
90 m->Message(m->ERROR, "pthread_join() failed in ~FADBoard (%s)", strerror(Ret));
91 }
92
93 // Delete condition variable
94 if ((Ret = pthread_cond_destroy(&CondVar)) != 0) {
95 m->Message(m->ERROR, "pthread_cond_destroy() failed for %s in ~FADBoard (%s)", Name, strerror(Ret));
96 }
97
98 // Delete mutex
99 if ((Ret = pthread_mutex_destroy(&Mutex)) != 0) {
100 m->Message(m->ERROR, "pthread_mutex_destroy() failed for %s in ~FADBoard (%s)", Name, strerror(Ret));
101 }
102
103 delete DIM_Name; delete DIM_Status;
104 delete DIM_ID; delete DIM_Rate;
105 delete DIM_Frequency; delete DIM_Lock;
106 delete DIM_TriggerNum; delete DIM_Temp;
107 delete DIM_DAC; delete DIM_ROI;
108 delete DIM_ACalData; delete DIM_BoardTime;
109 delete[] Name;
110}
111
112
113//
114// Send data to board
115//
116void FADBoard::Send(const void *Data, size_t Bytes) {
117
118 // Do not send if not active or communication problem
119 if (!Active || !CommOK) return;
120
121 // Write data
122 ssize_t Result = write(Socket, Data, Bytes);
123
124 // Check result
125 if (Result == -1) m->PrintMessage("Error: Could not write to socket (%s)\n", strerror(errno));
126 else if ((size_t) Result < Bytes) m->PrintMessage("Error: Could only write %d bytes out of %d to socket\n", Result, Bytes);
127}
128
129void FADBoard::Send(unsigned short Data) {
130
131 unsigned short Buffer = htons(Data);
132
133 Send(&Buffer, sizeof(unsigned short));
134}
135
136
137//
138// Get board status (mutex protected to avoid concurrent access in ReadLoop)
139//
140struct FADBoard::BoardStatus FADBoard::GetStatus() {
141
142 int Ret;
143 struct BoardStatus S;
144
145 // Lock
146 if ((Ret = pthread_mutex_lock(&Mutex)) != 0) {
147 m->Message(m->FATAL, "pthread_mutex_lock() failed in ReadLoop() (%s)", strerror(Ret));
148 }
149
150 S = Status;
151
152 // Unlock
153 if ((Ret = pthread_mutex_unlock(&Mutex)) != 0) {
154 m->Message(m->FATAL, "pthread_mutex_unlock() failed in Unlock() (%s)", strerror(Ret));
155 }
156
157 return S;
158}
159
160
161//
162// Perform amplitude calibration in steps
163//
164// The steps are intended to assure that up to date data is available
165void FADBoard::AmplitudeCalibration() {
166
167 vector<unsigned short> ROICmd;
168 unsigned short DACCmd[] = {htons(CMD_Write | (BADDR_DAC + 1)), 0, htons(CMD_Write | (BADDR_DAC + 2)), 0, htons(CMD_Write | (BADDR_DAC + 3)), 0, htons(CMD_Execute) };
169 string Message = string("ACALIBDONE")+Name+"\n";
170
171 switch (State) {
172 // *******************************************************************
173 // ****************** AMPLITUDE CALIBRATION *********************
174 // *******************************************************************
175
176 // ====== Part A: Check if amplitude calibration should start and initialise =====
177 case standbye:
178 if (m->Mode != m->acalib && m->Mode != m->dynrange) break;
179
180 // Save initial board status, set all ROIs to 1024 and set DAC values (no triggers while setting ROI)
181 InitialStatus = GetStatus();
182
183 for (unsigned int i=0; i<NChips*NChannels; i++) {
184 ROICmd.push_back(htons(CMD_Write | (BADDR_ROI + i)));
185 ROICmd.push_back(htons(NBins));
186 }
187 ROICmd.push_back(htons(CMD_Execute));
188 Send(&ROICmd[0], ROICmd.size()*sizeof(unsigned short));
189
190 if (m->Mode == m->acalib) {
191 // Set DAC to zero
192 DACCmd[1] = htons(0);
193 DACCmd[3] = htons(0);
194 DACCmd[5] = htons(0);
195 Send(DACCmd, sizeof(DACCmd));
196
197 // Invalidate current calibration
198 ACalib.Time = -1;
199 Count = 0;
200
201 // Clear sum vector and set state to accumulate
202 memset(Sum, 0, sizeof(Sum));
203 State = baseline;
204 SetStatus("Starting calilbration");
205 }
206
207 if (m->Mode == m->dynrange) {
208 // No amplitude calibration allowed!
209 DAC_DR = 0;
210 Delta_DAC = 1000;
211 State = setdac;
212 }
213
214 break;
215
216 // ====== Part B: Baseline calibration =====
217 case baseline:
218 // Check for stopping
219 if (m->Mode != m->acalib) {
220 State = cleanup;
221 break;
222 }
223
224 // Average
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 baseline if integration finished
235 if (Count < m->NumEventsRequested) break;
236
237 for (unsigned int i=0; i<NChips; i++) {
238 for (unsigned int j=0; j<NChannels; j++) {
239 for (unsigned int k=0; k<NBins; k++) {
240 ACalib.Baseline[i][j][k] = Sum[i][j][k] / m->NumEventsRequested;
241 }
242 }
243 }
244
245 // Set new DAC values and start accumulation
246 DACCmd[1] = htons(50000);
247 DACCmd[3] = htons(50000);
248 DACCmd[5] = htons(50000);
249 Send(DACCmd, sizeof(DACCmd));
250
251 // Clear sum vector and set state to accumulate
252 memset(Sum, 0, sizeof(Sum));
253 Count = 0;
254 State = gain;
255 break;
256
257 // ====== Part C: Gain calibration =====
258 case gain:
259 // Check for stopping
260 if (m->Mode != m->acalib) {
261 State = cleanup;
262 break;
263 }
264
265 // Average
266 for (unsigned int Chip=0; Chip<NChips; Chip++) {
267 for (unsigned int Chan=0; Chan<NChannels; Chan++) {
268 for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
269 Sum[Chip][Chan][(i+Status.TriggerCell[Chip]) % NBins] += Data[Chip][Chan][i];
270 }
271 }
272 }
273 Count++;
274
275 // Determine gain if integration finished
276 if (Count < m->NumEventsRequested) break;
277
278 for (unsigned int i=0; i<NChips; i++) {
279 for (unsigned int j=0; j<NChannels; j++) {
280 for (unsigned int k=0; k<NBins; k++) {
281 ACalib.Gain[i][j][k] = (Sum[i][j][k] / m->NumEventsRequested) - ACalib.Baseline[i][j][k];
282 }
283 }
284 }
285
286 // Set new DAC values and start accumulation
287 DACCmd[1] = htons(0);
288 DACCmd[3] = htons(0);
289 DACCmd[5] = htons(0);
290 Send(DACCmd, sizeof(DACCmd));
291
292 // Clear sum vector and set state to accumulate
293 memset(Sum, 0, sizeof(Sum));
294 Count = 0;
295 State = secondary;
296 break;
297
298 // ====== Part D: Secondary calibration =====
299 case secondary:
300 // Check for stopping
301 if (m->Mode != m->acalib) {
302 State = cleanup;
303 break;
304 }
305
306 // Average
307 for (unsigned int Chip=0; Chip<NChips; Chip++) {
308 for (unsigned int Chan=0; Chan<NChannels; Chan++) {
309 for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
310 Sum[Chip][Chan][i] = Data[Chip][Chan][i] - ACalib.Baseline[Chip][Chan][(i-Status.TriggerCell[Chip]) % NBins];
311 }
312 }
313 }
314 Count++;
315
316 // Determine secondary baseline if integration finished
317 if (Count < m->NumEventsRequested) break;
318
319 for (unsigned int i=0; i<NChips; i++) {
320 for (unsigned int j=0; j<NChannels; j++) {
321 for (unsigned int k=0; k<NBins; k++) {
322 ACalib.Secondary[i][j][k] = Sum[i][j][k] / (double) m->NumEventsRequested;
323 }
324 }
325 }
326
327 // Store calibration time and temperature
328 ACalib.DNA = Status.DNA;
329 ACalib.Frequency = Status.Frequency;
330 ACalib.Time = time(NULL);
331 ACalib.Temp = 0;
332 for (unsigned int i=0; i<NTemp; i++) ACalib.Temp += Status.Temp[i] / NTemp;
333
334 // Update DIM service with calibration information
335 for (unsigned int i=0; i<NChips; i++) {
336 for (unsigned int j=0; j<NChannels; j++) {
337 for (unsigned int k=0; k<NBins; k++) {
338 ACalData[0][i][j][k] = ACalib.Baseline[i][j][k];
339 ACalData[1][i][j][k] = ACalib.Gain[i][j][k];
340 ACalData[2][i][j][k] = ACalib.Secondary[i][j][k];
341 }
342 }
343 }
344 DIM_ACalData->updateService(ACalData, 3*NChips*NChannels*NBins*sizeof(float));
345
346 SetStatus("Finished calibration");
347 State = cleanup;
348 break;
349
350 // ====== Part E: Write back original ROI and DAC settings =====
351 case cleanup:
352 // ROI values
353
354 ROICmd.clear();
355 for (unsigned int i=0; i<NChips*NChannels; i++) {
356 ROICmd.push_back(htons(CMD_Write | (BADDR_ROI + i)));
357 ROICmd.push_back(htons(InitialStatus.ROI[i/NChannels][i%NChannels]));
358 }
359 ROICmd.push_back(htons(CMD_Execute));
360 Send(&ROICmd[0], ROICmd.size()*sizeof(unsigned short));
361
362 // DAC values
363 DACCmd[1] = htons(InitialStatus.DAC[1]);
364 DACCmd[3] = htons(InitialStatus.DAC[2]);
365 DACCmd[5] = htons(InitialStatus.DAC[3]);
366 Send(DACCmd, sizeof(DACCmd));
367
368 // Inform event thread that calibration is finished for this board
369 if (write(m->Pipe[1], Message.data(), Message.size()) == -1) {
370 m->Message(m->ERROR, "write() to Pipe[1] failed in class FADBoard::AmplitudeCalibration (%s)", strerror(errno));
371 }
372
373 SetStatus("Cleaning up");
374 State = wait;
375 break;
376
377 // ====== Wait for Mode not being idle =====
378 case wait:
379 if (m->Mode == m->idle) State = standbye;
380 break;
381
382
383 // ************************************************************************
384 // ****************** DYNAMIC RANGE DETERMINATION *********************
385 // ************************************************************************
386
387 // ====== Set calibration DACs 1-3 =====
388 case setdac:
389 // Check for stopping
390 if (m->Mode != m->dynrange) {
391 State = cleanup;
392 break;
393 }
394
395 // Set new DAC values
396 DACCmd[1] = htons(DAC_DR);
397 DACCmd[3] = htons(DAC_DR);
398 DACCmd[5] = htons(DAC_DR);
399 Send(DACCmd, sizeof(DACCmd));
400
401 SetStatus("Dynamic range: DACs 1-3 at %u", DAC_DR);
402 State = measure;
403 break;
404
405 // ====== Determine mean and sigma =====
406 case measure:
407 // Check for stopping
408 if (m->Mode != m->dynrange) {
409 State = cleanup;
410 break;
411 }
412
413 // Check if current event has correct DAC values
414 if (Status.DAC[1] != DAC_DR || Status.DAC[2] != DAC_DR || Status.DAC[3] != DAC_DR) break;
415
416 // Discard first few events with correct DAC setting (can still have wrong voltage)
417 if (Count_DR++ < 2) break;
418 Count_DR = 0;
419
420 bool Clip;
421
422 // Evaluate current event for all channels
423 for (unsigned int Chip=0; Chip<NChips; Chip++) {
424 for (unsigned int Chan=0; Chan<NChannels; Chan++) {
425 Clip = false;
426 Mean[Chip][Chan] = 0;
427
428 // Determine mean value and check if CLIP_LEVEL exceeded
429 for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
430 Mean[Chip][Chan] += Data[Chip][Chan][i] / Status.ROI[Chip][Chan];
431 if (abs(Data[Chip][Chan][i]) >= CLIP_LEVEL) Clip = true;
432 }
433 }
434 }
435
436 // If clipping occurred, continue to increase/decrease DAC until at 16-bit limit
437 if (Clip) {
438 if (DAC_DR + Delta_DAC < 0 || DAC_DR + Delta_DAC > 65535) State = cleanup;
439 else {
440 DAC_DR += Delta_DAC;
441 State = setdac;
442 }
443 break;
444 }
445
446 // Start again from maximum DAC value downwards
447 if (Delta_DAC > 0) {
448 for (unsigned int Chip=0; Chip<NChips; Chip++) {
449 for (unsigned int Chan=0; Chan<NChannels; Chan++) Mean_low[Chip][Chan] = Mean[Chip][Chan];
450 }
451 DAC_low = DAC_DR;
452 DAC_DR = 65535;
453 Delta_DAC = -1000;
454 State = setdac;
455 break;
456 }
457
458 // Procedure finished
459 double Sigma;
460 printf("Extrapolated DAC values for range with 1-sigma\nclearance to ADC count level +/-%u\n", CLIP_LEVEL);
461
462 for (unsigned int Chip=0; Chip<NChips; Chip++) {
463 for (unsigned int Chan=0; Chan<NChannels; Chan++) {
464
465 // Calculate baseline sigma for current event
466 Sigma = 0;
467 for (int i=0; i<Status.ROI[Chip][Chan]; i++) Sigma += pow(Data[Chip][Chan][i] - Mean[Chip][Chan], 2);
468 if (Status.ROI[Chip][Chan] > 1) Sigma = sqrt(Sigma / (Status.ROI[Chip][Chan] - 1));
469
470 // Extrapolate to find DAC values corresponding to 1-sigma clearance to CLIP_LEVEL
471 DR_low[Chip][Chan] = DAC_low - (Mean_low[Chip][Chan] + (CLIP_LEVEL-Sigma))* (DAC_DR-DAC_low) / (Mean[Chip][Chan]-Mean_low[Chip][Chan]);
472 DR_high[Chip][Chan] = DAC_DR + (CLIP_LEVEL - Sigma - Mean[Chip][Chan]) * (DAC_DR-DAC_low) / (Mean[Chip][Chan]-Mean_low[Chip][Chan]);
473
474 printf("Chip %u, chan %u: DAC Min %6d Max %d Range %6d\n", Chip, Chan, DR_low[Chip][Chan], DR_high[Chip][Chan], DR_high[Chip][Chan]-DR_low[Chip][Chan]);
475 }
476 }
477
478 State = cleanup;
479 break;
480 }
481}
482
483//
484// Connect to board and read data
485//
486void FADBoard::ReadLoop() {
487
488 char Buffer[READ_BUFFER_SIZE];
489 unsigned int Pos = 0, Count = 0;
490 const PEVNT_HEADER *Header = (PEVNT_HEADER *) Buffer;
491 ssize_t Result;
492 struct sockaddr_in SocketAddress;
493 struct BoardStatus PrevStatus;
494 int Ret;
495
496 // Resolve hostname
497 struct hostent *Host = gethostbyname(Name);
498 if (Host == 0) {
499 SetStatus("Could not resolve host name '%s'", Name);
500 return;
501 }
502
503 SocketAddress.sin_family = PF_INET;
504 SocketAddress.sin_port = htons(Port);
505 SocketAddress.sin_addr = *(struct in_addr*) Host->h_addr;
506
507 // Open socket descriptor
508 if ((Socket = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
509 m->Message(m->ERROR, "Could not open socket for %s (%s)\n", Name, strerror(errno));
510 return;
511 }
512
513 // Connect to server
514 if (connect(Socket, (struct sockaddr *) &SocketAddress, sizeof(SocketAddress)) == -1) {
515 SetStatus("Could not connect to port %hu (%s)", Port, strerror(errno));
516 }
517 else {
518 CommOK = true;
519 Active = true;
520 SetStatus("Connected");
521 }
522
523 // Use not zero so that comparing Status and PrevStatus at first test will likely show differences
524 memset(&PrevStatus, 0xee, sizeof(PrevStatus));
525
526 // Leave loop if program termination requested or board communication not OK
527 while (!m->ExitRequest && CommOK) {
528 // Read data from socket
529 Result = read(Socket, Buffer + Pos, sizeof(Buffer)-Pos);
530
531 // Check result of read
532 if (Result == -1) {
533 m->Message(m->ERROR, "Could not read from socket for %s, exiting read loop (%s)\n", Name, strerror(errno));
534 CommOK = false;
535 break;
536 }
537 else if (Result == 0) {
538 SetStatus("Server not existing anymore, exiting read loop");
539 CommOK = false;
540 break;
541 }
542
543 // If not active, discard incoming data
544 if (!Active) continue;
545
546 // Advance write pointer
547 Pos += Result;
548
549 // Check if internal buffer full
550 if (Pos == sizeof(Buffer)) {
551 SetStatus("Internal buffer full, deleting all data in buffer");
552 Pos = 0;
553 continue;
554 }
555
556 // Check if buffer starts with start_package_flag, remove data if not
557 unsigned int Temp = 0;
558 while (ntohs(*((unsigned short *) (Buffer+Temp))) != 0xfb01 && Temp<Pos) Temp++;
559 if (Temp != 0) {
560 memmove(Buffer, Buffer+Temp, Pos-Temp);
561 Pos -= Temp;
562 SetStatus("Removed %d bytes because of start_package_flag not found", Temp);
563 continue;
564 }
565
566 // Wait until the buffer contains at least enough bytes to potentially hold a PEVNT_HEADER
567 if (Pos < sizeof(PEVNT_HEADER)) continue;
568
569 unsigned int Length = ntohs(Header->package_length)*2*sizeof(char);
570 if (Pos < Length) continue;
571
572 // Extract data if event end package flag correct
573 if (ntohs(*(unsigned short *) (Buffer+Length-sizeof(unsigned short))) == 0x04FE) {
574
575 // Prepare pointers to channel data (channels stored in order 0,9,18,27 - 1,10,19,28 - ... - 8,17,26,35)
576 PCHANNEL *Channel[NChips*NChannels], *Pnt=(PCHANNEL *) (Header+1);
577 for(unsigned int i=0; i<NChips*NChannels; i++) {
578 Channel[i] = Pnt;
579 Pnt = (PCHANNEL *) ((short *) (Channel[i] + 1) + ntohs(Channel[i]->roi));
580 }
581
582 // Wait until event thread processed the previous data and lock to avoid concurrent access in GetStatus()
583 Lock();
584 while (!Continue) {
585 struct timespec Wakeup;
586 Wakeup.tv_sec = time(NULL)+MAX_WAIT_FOR_CONDITION;
587 Wakeup.tv_nsec = 0;
588 if ((Ret = pthread_cond_timedwait(&CondVar, &Mutex, &Wakeup)) != 0) {
589 if (Ret == ETIMEDOUT) SetStatus("Board %s timed out (%d s) waiting for condition\n", Name, MAX_WAIT_FOR_CONDITION);
590 else m->Message(m->ERROR, "pthread_cond_wait() failed (%s)", strerror(Ret));
591 }
592 }
593 gettimeofday(&Status.Update, NULL);
594
595 // Extract board and trigger information
596 Status.BoardID = ntohs(Header->board_id);
597 Status.FirmwareRevision = ntohs(Header->version_no);
598 Status.BoardTime = ntohl(Header->time);
599 Status.EventCounter = ntohl(Header->fad_evt_counter);
600 Status.TriggerNum = ntohl(Header->trigger_id);
601 Status.Runnumber = ntohl(Header->runnumber);
602 Status.TriggerType = ntohs(Header->trigger_type);
603 Status.TriggerCRC = ntohs(Header->trigger_crc);
604 Status.DNA = Header->DNA;
605
606 // Extract frequency related information
607 Status.Frequency = ntohl(Header->REFCLK_frequency)/1.0e3*2.048;
608 Status.PhaseShift = Header->adc_clock_phase_shift;
609 for (unsigned int i=0; i<NChips; i++) {
610 if ((ntohs(Header->PLLLCK)>>12 & (1<<i)) != 0) Status.Lock[i] = 1;
611 else Status.Lock[i] = 0;
612 }
613
614 // Extract Firmware status info
615 Status.denable = (bool) ( ntohs(Header->PLLLCK) & (1<<11) );
616 Status.dwrite = (bool) ( ntohs(Header->PLLLCK) & (1<<10) );
617 Status.DCM_lock = (bool) ( ntohs(Header->PLLLCK) & (1<<7) );
618 Status.DCM_ready = (bool) ( ntohs(Header->PLLLCK) & (1<<6) );
619 Status.spi_clk = (bool) ( ntohs(Header->PLLLCK) & (1<<5) );
620 Status.RefClk_low = (bool) ( ntohs(Header->PLLLCK) & (1<<8) );
621
622 // Extract temperatures (MSB indicates if temperature is positive or negative)
623 for (unsigned int i=0; i<NTemp; i++) {
624 if ((ntohs(Header->drs_temperature[i]) & 0x8000) == 0) Status.Temp[i] = float(ntohs(Header->drs_temperature[i]) >> 3)/16;
625 else Status.Temp[i] = float(0xE000 | (ntohs(Header->drs_temperature[i])) >> 3)/16;
626 }
627
628 // Extract DAC channels
629 for (unsigned int i=0; i<NDAC; i++) Status.DAC[i] = ntohs(Header->dac[i]);
630
631 for (unsigned int Chip=0; Chip<NChips; Chip++) {
632 // Extract trigger cells
633 Status.TriggerCell[Chip] = (int) ntohs(Channel[Chip]->start_cell);
634
635 for (unsigned int Chan=0; Chan<NChannels; Chan++) {
636 // Extract ROI
637 Status.ROI[Chip][Chan] = ntohs(Channel[Chip+NChips*Chan]->roi);
638
639 // Extract ADC data (stored as signed short)
640 // FADs ADC is 12 bit (values -2048 .. 2047)
641 // negative/positive overflow is -2049 / +2048
642 for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
643 Data[Chip][Chan][i] = Channel[Chip+NChips*Chan]->adc_data[i];
644 }
645 }
646 }
647
648 // Prepare predicate for condition variable
649 Continue = false;
650 Count++;
651 Unlock();
652
653 // Amplitude calibration (will check if Mode is acalib)
654 AmplitudeCalibration();
655
656 // Update DIM services if necessary
657 if (Status.Update.tv_sec - PrevStatus.Update.tv_sec > m->EventUpdateDelay) {
658
659 // Check if trigger cells resonable (to trace FAD 'double signal' bug)
660 int Diff = abs((*max_element(Status.TriggerCell,Status.TriggerCell+4) - *min_element(Status.TriggerCell,Status.TriggerCell+4)));
661 if (Diff > 20 && Diff < 1000) {
662 SetStatus("Warning: Trigger cell mismatch board %s, cells are %d %d %d %d", Name, Status.TriggerCell[0], Status.TriggerCell[1], Status.TriggerCell[2], Status.TriggerCell[3]);
663 m->Message(m->WARN, "Trigger cell mismatch board %s, cells are %d %d %d %d", Name, Status.TriggerCell[0], Status.TriggerCell[1], Status.TriggerCell[2], Status.TriggerCell[3]);
664 }
665
666 // Determine event rate
667 Status.Rate =
668 Count / (double(Status.Update.tv_sec-PrevStatus.Update.tv_sec) + (Status.Update.tv_usec-PrevStatus.Update.tv_usec)/1000000.0);
669 Count = 0;
670
671 if (PrevStatus.Frequency != Status.Frequency) DIM_Frequency->updateService();
672 if (PrevStatus.TriggerNum != Status.TriggerNum) DIM_TriggerNum->updateService();
673 if (PrevStatus.BoardTime != Status.BoardTime) DIM_BoardTime->updateService();
674 if (PrevStatus.Rate != Status.Rate) DIM_Rate->updateService();
675
676 if (memcmp(PrevStatus.Lock, Status.Lock, sizeof(Status.Lock)) != 0) {
677 DIM_Lock->updateService(Status.Lock, sizeof(Status.Lock));
678 }
679 if (memcmp(PrevStatus.Temp, Status.Temp, sizeof(Status.Temp)) != 0) {
680 DIM_Temp->updateService(Status.Temp, sizeof(Status.Temp));
681 }
682 if (memcmp(PrevStatus.DAC, Status.DAC, sizeof(Status.DAC)) != 0) {
683 DIM_DAC->updateService(Status.DAC, sizeof(Status.DAC));
684 }
685 if (memcmp(PrevStatus.ROI, Status.ROI, sizeof(Status.ROI)) != 0) {
686 DIM_ROI->updateService(Status.ROI, sizeof(Status.ROI));
687 }
688 if (PrevStatus.BoardID != Status.BoardID) {
689 DIM_ID->updateService(&Status.BoardID, sizeof(Status.BoardID));
690 }
691
692 PrevStatus = Status;
693 }
694
695 // Inform event thread of new data
696 string Message = string("EVENT")+Name+"\n";
697 if (write(m->Pipe[1], Message.data(), Message.size()) == -1) {
698 m->Message(m->ERROR, "write() to Pipe[1] failed in class FADBoard (%s)", strerror(errno));
699 break;
700 }
701 }
702 else SetStatus("End package flag incorrect, removing corrupt event");
703
704 // Remove event data from internal buffer
705 memmove(Buffer, Buffer+Length, Pos-Length);
706 Pos = Pos-Length;
707 } // while()
708
709 // Set inactive and close socket descriptor
710 Active = false;
711
712 if (close(Socket) == -1) {
713 m->Message(m->ERROR, "Could not close socket descriptor for board %s (%s)", Name, strerror(errno));
714 }
715
716}
717
718//
719// Install cleanup handler and launch read thread inside class
720//
721void FADBoard::LaunchThread(class FADBoard *m) {
722
723 pthread_cleanup_push((void (*)(void *)) FADBoard::ThreadCleanup, (void *) m);
724 m->ReadLoop();
725 pthread_cleanup_pop(0);
726}
727
728
729//
730// Set status message
731//
732void FADBoard::SetStatus(const char *Format, ...) {
733
734 int Ret;
735
736 // Assemble message
737 va_list ArgumentPointer;
738 va_start(ArgumentPointer, Format);
739 Lock();
740 Ret = vsnprintf(Status.Message, sizeof(Status.Message), Format, ArgumentPointer);
741 Unlock();
742 va_end(ArgumentPointer);
743
744 if (Ret == -1) m->Message(m->FATAL, "snprintf() in FADBoard::SetStatus() failed (%s)", strerror(errno));
745
746 // Update status service
747 DIM_Status->updateService(Status.Message);
748}
749
750
751//
752// Lock and unlock mutex
753//
754void FADBoard::Lock() {
755
756 int Ret;
757
758 if ((Ret = pthread_mutex_lock(&Mutex)) != 0) {
759 m->Message(m->FATAL, "pthread_mutex_lock() failed in class FADBoard (%s)", strerror(Ret));
760 }
761}
762
763void FADBoard::Unlock() {
764
765 int Ret;
766
767 if ((Ret = pthread_mutex_unlock(&Mutex)) != 0) {
768 m->Message(m->FATAL, "pthread_mutex_unlock() failed in class FADBoard (%s)", strerror(Ret));
769 }
770}
771
772// Ensure that mutex is unlocked when before cancelling thread
773void FADBoard::ThreadCleanup(class FADBoard *This) {
774
775 int Ret;
776
777 if ((Ret = pthread_mutex_trylock(&This->Mutex)) != 0) {
778 if (Ret != EBUSY) This->m->Message(This->m->FATAL, "pthread_mutex_trylock() failed in FADBoard::ThreadCleanup (%s)", strerror(Ret));
779 }
780 This->Unlock();
781}
782
783//
784// Open other sockets
785//
786// Error reporting is limited as this function is expected to be removed when firmware allows single socket
787//
788void FADBoard::threadHandler() {
789
790 int List[] = {31920, 31921, 31922, 31923, 31924, 31925, 31926};
791 int Socket[sizeof(List)/sizeof(int)], MaxSocketNum, Ret;
792 fd_set DescriptorList;
793 char Buffer[1000000];
794
795 // Resolve hostname
796 struct hostent *Host = gethostbyname(Name);
797 if (Host == 0) return;
798
799 // Connect to server
800 struct sockaddr_in SocketAddress;
801 SocketAddress.sin_family = PF_INET;
802 SocketAddress.sin_addr = *(struct in_addr*) Host->h_addr;
803
804 for (unsigned int i=0; i<sizeof(List)/sizeof(int); i++) {
805 // Open socket descriptor
806 if ((Socket[i] = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
807 m->Message(m->ERROR, "OtherSockets: Could not open socket for port %d (%s)\n", List[i], strerror(errno));
808 return;
809 }
810 MaxSocketNum = *max_element(Socket, Socket+sizeof(List)/sizeof(int));
811
812 // Connect to server
813 SocketAddress.sin_port = htons((unsigned short) List[i]);
814 if (connect(Socket[i], (struct sockaddr *) &SocketAddress, sizeof(SocketAddress)) == -1) return;
815 }
816
817 while(true) {
818 // Wait for data from sockets
819 FD_ZERO(&DescriptorList);
820 for (unsigned int i=0; i<sizeof(List)/sizeof(int); i++) FD_SET(Socket[i], &DescriptorList);
821 if (select(MaxSocketNum+1, &DescriptorList, NULL, NULL, NULL) == -1) {
822 m->Message(m->ERROR, "OtherSockets: Error with select() (%s)\n", strerror(errno));
823 break;
824 }
825
826 // Data from socket
827 for (unsigned int i=0; i<sizeof(List)/sizeof(int); i++) if (FD_ISSET(Socket[i], &DescriptorList)) {
828 Ret = read(Socket[i], Buffer, sizeof(Buffer));
829 if (Ret == -1) m->Message(m->ERROR, "OtherSockets: Error reading from port %d (%s)\n", List[i], strerror(errno));
830 }
831 }
832
833 // Close all sockets
834 for (unsigned int i=0; i<sizeof(List)/sizeof(int); i++) {
835 if ((Socket[i] != -1) && (close(Socket[i]) == -1)) {
836 m->Message(m->ERROR, "OtherSockets: Could not close socket of port %d (%s)", List[i], strerror(errno));
837 }
838 }
839}
Note: See TracBrowser for help on using the repository browser.