source: fact/FADctrl/FADBoard.cc

Last change on this file was 14278, checked in by ogrimm, 12 years ago
Added modified calibration procedure for FADctrl for new FAD-based stand-alone oscilloscope.
File size: 27.7 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->ModifiedCalibration) ModifiedCalibCount = 0;
208
209 if (m->Mode == m->dynrange) {
210 // No amplitude calibration allowed!
211 DAC_DR = 0;
212 Delta_DAC = 1000;
213 State = setdac;
214 }
215
216 break;
217
218 // ====== Part B: Baseline calibration =====
219 case baseline:
220 // Check for stopping
221 if (m->Mode != m->acalib) {
222 State = cleanup;
223 break;
224 }
225
226 // Average
227 for (unsigned int Chip=0; Chip<NChips; Chip++) {
228 for (unsigned int Chan=0; Chan<NChannels; Chan++) {
229 for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
230 Sum[Chip][Chan][(i+Status.TriggerCell[Chip]) % NBins] += Data[Chip][Chan][i];
231 }
232 }
233 }
234 Count++;
235
236 // Determine baseline if integration finished
237 if (Count < m->NumEventsRequested) break;
238
239 for (unsigned int i=0; i<NChips; i++) {
240 for (unsigned int j=0; j<NChannels; j++) {
241 for (unsigned int k=0; k<NBins; k++) {
242 ACalib.Baseline[i][j][k] = Sum[i][j][k] / m->NumEventsRequested;
243 }
244 }
245 }
246
247 // Set new DAC values and start accumulation
248 DACCmd[1] = htons(50000);
249 DACCmd[3] = htons(50000);
250 DACCmd[5] = htons(50000);
251 Send(DACCmd, sizeof(DACCmd));
252
253 // Clear sum vector and set state to accumulate
254 memset(Sum, 0, sizeof(Sum));
255 Count = 0;
256 State = gain;
257 break;
258
259 // ====== Part C: Gain calibration =====
260 case gain:
261 // Check for stopping
262 if (m->Mode != m->acalib) {
263 State = cleanup;
264 break;
265 }
266
267 // Average
268 for (unsigned int Chip=0; Chip<NChips; Chip++) {
269 for (unsigned int Chan=0; Chan<NChannels; Chan++) {
270 for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
271 Sum[Chip][Chan][(i+Status.TriggerCell[Chip]) % NBins] += Data[Chip][Chan][i];
272 }
273 }
274 }
275 Count++;
276
277 // Determine gain if integration finished
278 if (Count < m->NumEventsRequested) break;
279
280 // Check for modified calibration procedure, then repeat gain calibration
281 if (m->ModifiedCalibration) {
282 if (ModifiedCalibCount == 0) {
283 DACCmd[1] = htons(65000);
284 DACCmd[3] = htons(0);
285 DACCmd[5] = htons(0);
286 }
287 else if (ModifiedCalibCount == 1) {
288 for (unsigned int i=0; i<NChips; i++) {
289 for (unsigned int j=0; j<NChannels; j++) {
290 if (i*NChannels+j >= 12) continue;
291 for (unsigned int k=0; k<NBins; k++) {
292 ACalib.Gain[i][j][k] = (Sum[i][j][k] / m->NumEventsRequested) - ACalib.Baseline[i][j][k];
293 }
294 }
295 }
296
297 DACCmd[1] = htons(0);
298 DACCmd[3] = htons(50000);
299 DACCmd[5] = htons(0);
300 }
301 else if (ModifiedCalibCount == 2) {
302 for (unsigned int i=0; i<NChips; i++) {
303 for (unsigned int j=0; j<NChannels; j++) {
304 if (i*NChannels+j < 12 || i*NChannels+j >= 24) continue;
305 for (unsigned int k=0; k<NBins; k++) {
306 ACalib.Gain[i][j][k] = (Sum[i][j][k] / m->NumEventsRequested) - ACalib.Baseline[i][j][k];
307 }
308 }
309 }
310
311 DACCmd[1] = htons(4000);
312 DACCmd[3] = htons(0);
313 DACCmd[5] = htons(0);
314 }
315 else {
316 for (unsigned int i=0; i<NChips; i++) {
317 for (unsigned int j=0; j<NChannels; j++) {
318 if (i*NChannels+j < 24) continue;
319 for (unsigned int k=0; k<NBins; k++) {
320 ACalib.Gain[i][j][k] = (Sum[i][j][k] / m->NumEventsRequested) - ACalib.Baseline[i][j][k];
321 }
322 }
323 }
324 DACCmd[1] = htons(0);
325 DACCmd[3] = htons(0);
326 DACCmd[5] = htons(0);
327 State = secondary;
328 }
329 Send(DACCmd, sizeof(DACCmd));
330
331 ModifiedCalibCount++;
332
333 memset(Sum, 0, sizeof(Sum));
334 Count = 0;
335 break;
336 }
337
338 for (unsigned int i=0; i<NChips; i++) {
339 for (unsigned int j=0; j<NChannels; j++) {
340 for (unsigned int k=0; k<NBins; k++) {
341 ACalib.Gain[i][j][k] = (Sum[i][j][k] / m->NumEventsRequested) - ACalib.Baseline[i][j][k];
342 }
343 }
344 }
345
346 // Set new DAC values and start accumulation
347 DACCmd[1] = htons(0);
348 DACCmd[3] = htons(0);
349 DACCmd[5] = htons(0);
350 Send(DACCmd, sizeof(DACCmd));
351
352 // Clear sum vector and set state to accumulate
353 memset(Sum, 0, sizeof(Sum));
354 Count = 0;
355 State = secondary;
356 break;
357
358 // ====== Part D: Secondary calibration =====
359 case secondary:
360 // Check for stopping
361 if (m->Mode != m->acalib) {
362 State = cleanup;
363 break;
364 }
365
366 // Average
367 for (unsigned int Chip=0; Chip<NChips; Chip++) {
368 for (unsigned int Chan=0; Chan<NChannels; Chan++) {
369 for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
370 Sum[Chip][Chan][i] = Data[Chip][Chan][i] - ACalib.Baseline[Chip][Chan][(i-Status.TriggerCell[Chip]) % NBins];
371 }
372 }
373 }
374 Count++;
375
376 // Determine secondary baseline if integration finished
377 if (Count < m->NumEventsRequested) break;
378
379 for (unsigned int i=0; i<NChips; i++) {
380 for (unsigned int j=0; j<NChannels; j++) {
381 for (unsigned int k=0; k<NBins; k++) {
382 ACalib.Secondary[i][j][k] = Sum[i][j][k] / (double) m->NumEventsRequested;
383 }
384 }
385 }
386
387 // Store calibration time and temperature
388 ACalib.DNA = Status.DNA;
389 ACalib.Frequency = Status.Frequency;
390 ACalib.Time = time(NULL);
391 ACalib.Temp = 0;
392 for (unsigned int i=0; i<NTemp; i++) ACalib.Temp += Status.Temp[i] / NTemp;
393
394 // Update DIM service with calibration information
395 for (unsigned int i=0; i<NChips; i++) {
396 for (unsigned int j=0; j<NChannels; j++) {
397 for (unsigned int k=0; k<NBins; k++) {
398 ACalData[0][i][j][k] = ACalib.Baseline[i][j][k];
399 ACalData[1][i][j][k] = ACalib.Gain[i][j][k];
400 ACalData[2][i][j][k] = ACalib.Secondary[i][j][k];
401 }
402 }
403 }
404 DIM_ACalData->updateService(ACalData, 3*NChips*NChannels*NBins*sizeof(float));
405
406 SetStatus("Finished calibration");
407 State = cleanup;
408 break;
409
410 // ====== Part E: Write back original ROI and DAC settings =====
411 case cleanup:
412 // ROI values
413
414 ROICmd.clear();
415 for (unsigned int i=0; i<NChips*NChannels; i++) {
416 ROICmd.push_back(htons(CMD_Write | (BADDR_ROI + i)));
417 ROICmd.push_back(htons(InitialStatus.ROI[i/NChannels][i%NChannels]));
418 }
419 ROICmd.push_back(htons(CMD_Execute));
420 Send(&ROICmd[0], ROICmd.size()*sizeof(unsigned short));
421
422 // DAC values
423 DACCmd[1] = htons(InitialStatus.DAC[1]);
424 DACCmd[3] = htons(InitialStatus.DAC[2]);
425 DACCmd[5] = htons(InitialStatus.DAC[3]);
426 Send(DACCmd, sizeof(DACCmd));
427
428 // Inform event thread that calibration is finished for this board
429 if (write(m->Pipe[1], Message.data(), Message.size()) == -1) {
430 m->Message(m->ERROR, "write() to Pipe[1] failed in class FADBoard::AmplitudeCalibration (%s)", strerror(errno));
431 }
432
433 SetStatus("Cleaning up");
434 State = wait;
435 break;
436
437 // ====== Wait for Mode not being idle =====
438 case wait:
439 if (m->Mode == m->idle) State = standbye;
440 break;
441
442
443 // ************************************************************************
444 // ****************** DYNAMIC RANGE DETERMINATION *********************
445 // ************************************************************************
446
447 // ====== Set calibration DACs 1-3 =====
448 case setdac:
449 // Check for stopping
450 if (m->Mode != m->dynrange) {
451 State = cleanup;
452 break;
453 }
454
455 // Set new DAC values
456 DACCmd[1] = htons(DAC_DR);
457 DACCmd[3] = htons(DAC_DR);
458 DACCmd[5] = htons(DAC_DR);
459 Send(DACCmd, sizeof(DACCmd));
460
461 SetStatus("Dynamic range: DACs 1-3 at %u", DAC_DR);
462 State = measure;
463 break;
464
465 // ====== Determine mean and sigma =====
466 case measure:
467 // Check for stopping
468 if (m->Mode != m->dynrange) {
469 State = cleanup;
470 break;
471 }
472
473 // Check if current event has correct DAC values
474 if (Status.DAC[1] != DAC_DR || Status.DAC[2] != DAC_DR || Status.DAC[3] != DAC_DR) break;
475
476 // Discard first few events with correct DAC setting (can still have wrong voltage)
477 if (Count_DR++ < 2) break;
478 Count_DR = 0;
479
480 bool Clip;
481
482 // Evaluate current event for all channels
483 for (unsigned int Chip=0; Chip<NChips; Chip++) {
484 for (unsigned int Chan=0; Chan<NChannels; Chan++) {
485 Clip = false;
486 Mean[Chip][Chan] = 0;
487
488 // Determine mean value and check if CLIP_LEVEL exceeded
489 for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
490 Mean[Chip][Chan] += Data[Chip][Chan][i] / Status.ROI[Chip][Chan];
491 if (abs(Data[Chip][Chan][i]) >= CLIP_LEVEL) Clip = true;
492 }
493 }
494 }
495
496 // If clipping occurred, continue to increase/decrease DAC until at 16-bit limit
497 if (Clip) {
498 if (DAC_DR + Delta_DAC < 0 || DAC_DR + Delta_DAC > 65535) State = cleanup;
499 else {
500 DAC_DR += Delta_DAC;
501 State = setdac;
502 }
503 break;
504 }
505
506 // Start again from maximum DAC value downwards
507 if (Delta_DAC > 0) {
508 for (unsigned int Chip=0; Chip<NChips; Chip++) {
509 for (unsigned int Chan=0; Chan<NChannels; Chan++) Mean_low[Chip][Chan] = Mean[Chip][Chan];
510 }
511 DAC_low = DAC_DR;
512 DAC_DR = 65535;
513 Delta_DAC = -1000;
514 State = setdac;
515 break;
516 }
517
518 // Procedure finished
519 double Sigma;
520 printf("Extrapolated DAC values for range with 1-sigma\nclearance to ADC count level +/-%u\n", CLIP_LEVEL);
521
522 for (unsigned int Chip=0; Chip<NChips; Chip++) {
523 for (unsigned int Chan=0; Chan<NChannels; Chan++) {
524
525 // Calculate baseline sigma for current event
526 Sigma = 0;
527 for (int i=0; i<Status.ROI[Chip][Chan]; i++) Sigma += pow(Data[Chip][Chan][i] - Mean[Chip][Chan], 2);
528 if (Status.ROI[Chip][Chan] > 1) Sigma = sqrt(Sigma / (Status.ROI[Chip][Chan] - 1));
529
530 // Extrapolate to find DAC values corresponding to 1-sigma clearance to CLIP_LEVEL
531 DR_low[Chip][Chan] = DAC_low - (Mean_low[Chip][Chan] + (CLIP_LEVEL-Sigma))* (DAC_DR-DAC_low) / (Mean[Chip][Chan]-Mean_low[Chip][Chan]);
532 DR_high[Chip][Chan] = DAC_DR + (CLIP_LEVEL - Sigma - Mean[Chip][Chan]) * (DAC_DR-DAC_low) / (Mean[Chip][Chan]-Mean_low[Chip][Chan]);
533
534 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]);
535 }
536 }
537
538 State = cleanup;
539 break;
540 }
541}
542
543//
544// Connect to board and read data
545//
546void FADBoard::ReadLoop() {
547
548 char Buffer[READ_BUFFER_SIZE];
549 unsigned int Pos = 0, Count = 0;
550 const PEVNT_HEADER *Header = (PEVNT_HEADER *) Buffer;
551 ssize_t Result;
552 struct sockaddr_in SocketAddress;
553 struct BoardStatus PrevStatus;
554 int Ret;
555
556 // Resolve hostname
557 struct hostent *Host = gethostbyname(Name);
558 if (Host == 0) {
559 SetStatus("Could not resolve host name '%s'", Name);
560 return;
561 }
562
563 SocketAddress.sin_family = PF_INET;
564 SocketAddress.sin_port = htons(Port);
565 SocketAddress.sin_addr = *(struct in_addr*) Host->h_addr;
566
567 // Open socket descriptor
568 if ((Socket = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
569 m->Message(m->ERROR, "Could not open socket for %s (%s)\n", Name, strerror(errno));
570 return;
571 }
572
573 // Connect to server
574 if (connect(Socket, (struct sockaddr *) &SocketAddress, sizeof(SocketAddress)) == -1) {
575 SetStatus("Could not connect to port %hu (%s)", Port, strerror(errno));
576 }
577 else {
578 CommOK = true;
579 Active = true;
580 SetStatus("Connected");
581 }
582
583 // Use not zero so that comparing Status and PrevStatus at first test will likely show differences
584 memset(&PrevStatus, 0xee, sizeof(PrevStatus));
585
586 // Leave loop if program termination requested or board communication not OK
587 while (!m->ExitRequest && CommOK) {
588 // Read data from socket
589 Result = read(Socket, Buffer + Pos, sizeof(Buffer)-Pos);
590
591 // Check result of read
592 if (Result == -1) {
593 m->Message(m->ERROR, "Could not read from socket for %s, exiting read loop (%s)\n", Name, strerror(errno));
594 CommOK = false;
595 break;
596 }
597 else if (Result == 0) {
598 SetStatus("Server not existing anymore, exiting read loop");
599 CommOK = false;
600 break;
601 }
602
603 // If not active, discard incoming data
604 if (!Active) continue;
605
606 // Advance write pointer
607 Pos += Result;
608
609 // Check if internal buffer full
610 if (Pos == sizeof(Buffer)) {
611 SetStatus("Internal buffer full, deleting all data in buffer");
612 Pos = 0;
613 continue;
614 }
615
616 // Check if buffer starts with start_package_flag, remove data if not
617 unsigned int Temp = 0;
618 while (ntohs(*((unsigned short *) (Buffer+Temp))) != 0xfb01 && Temp<Pos) Temp++;
619 if (Temp != 0) {
620 memmove(Buffer, Buffer+Temp, Pos-Temp);
621 Pos -= Temp;
622 SetStatus("Removed %d bytes because of start_package_flag not found", Temp);
623 continue;
624 }
625
626 // Wait until the buffer contains at least enough bytes to potentially hold a PEVNT_HEADER
627 if (Pos < sizeof(PEVNT_HEADER)) continue;
628
629 unsigned int Length = ntohs(Header->package_length)*2*sizeof(char);
630 if (Pos < Length) continue;
631
632 // Extract data if event end package flag correct
633 if (ntohs(*(unsigned short *) (Buffer+Length-sizeof(unsigned short))) == 0x04FE) {
634
635 // Prepare pointers to channel data (channels stored in order 0,9,18,27 - 1,10,19,28 - ... - 8,17,26,35)
636 PCHANNEL *Channel[NChips*NChannels], *Pnt=(PCHANNEL *) (Header+1);
637 for(unsigned int i=0; i<NChips*NChannels; i++) {
638 Channel[i] = Pnt;
639 Pnt = (PCHANNEL *) ((short *) (Channel[i] + 1) + ntohs(Channel[i]->roi));
640 }
641
642 // Wait until event thread processed the previous data and lock to avoid concurrent access in GetStatus()
643 Lock();
644 while (!Continue) {
645 struct timespec Wakeup;
646 Wakeup.tv_sec = time(NULL)+MAX_WAIT_FOR_CONDITION;
647 Wakeup.tv_nsec = 0;
648 if ((Ret = pthread_cond_timedwait(&CondVar, &Mutex, &Wakeup)) != 0) {
649 if (Ret == ETIMEDOUT) SetStatus("Board %s timed out (%d s) waiting for condition\n", Name, MAX_WAIT_FOR_CONDITION);
650 else m->Message(m->ERROR, "pthread_cond_wait() failed (%s)", strerror(Ret));
651 }
652 }
653 gettimeofday(&Status.Update, NULL);
654
655 // Extract board and trigger information
656 Status.BoardID = ntohs(Header->board_id);
657 Status.FirmwareRevision = ntohs(Header->version_no);
658 Status.BoardTime = ntohl(Header->time);
659 Status.EventCounter = ntohl(Header->fad_evt_counter);
660 Status.TriggerNum = ntohl(Header->trigger_id);
661 Status.Runnumber = ntohl(Header->runnumber);
662 Status.TriggerType = ntohs(Header->trigger_type);
663 Status.TriggerCRC = ntohs(Header->trigger_crc);
664 Status.DNA = Header->DNA;
665
666 // Extract frequency related information
667 Status.Frequency = ntohl(Header->REFCLK_frequency)/1.0e3*2.048;
668 Status.PhaseShift = Header->adc_clock_phase_shift;
669 for (unsigned int i=0; i<NChips; i++) {
670 if ((ntohs(Header->PLLLCK)>>12 & (1<<i)) != 0) Status.Lock[i] = 1;
671 else Status.Lock[i] = 0;
672 }
673
674 // Extract Firmware status info
675 Status.denable = (bool) ( ntohs(Header->PLLLCK) & (1<<11) );
676 Status.dwrite = (bool) ( ntohs(Header->PLLLCK) & (1<<10) );
677 Status.DCM_lock = (bool) ( ntohs(Header->PLLLCK) & (1<<7) );
678 Status.DCM_ready = (bool) ( ntohs(Header->PLLLCK) & (1<<6) );
679 Status.spi_clk = (bool) ( ntohs(Header->PLLLCK) & (1<<5) );
680 Status.RefClk_low = (bool) ( ntohs(Header->PLLLCK) & (1<<8) );
681
682 // Extract temperatures (MSB indicates if temperature is positive or negative)
683 for (unsigned int i=0; i<NTemp; i++) {
684 if ((ntohs(Header->drs_temperature[i]) & 0x8000) == 0) Status.Temp[i] = float(ntohs(Header->drs_temperature[i]) >> 3)/16;
685 else Status.Temp[i] = float(0xE000 | (ntohs(Header->drs_temperature[i])) >> 3)/16;
686 }
687
688 // Extract DAC channels
689 for (unsigned int i=0; i<NDAC; i++) Status.DAC[i] = ntohs(Header->dac[i]);
690
691 for (unsigned int Chip=0; Chip<NChips; Chip++) {
692 // Extract trigger cells
693 Status.TriggerCell[Chip] = (int) ntohs(Channel[Chip]->start_cell);
694
695 for (unsigned int Chan=0; Chan<NChannels; Chan++) {
696 // Extract ROI
697 Status.ROI[Chip][Chan] = ntohs(Channel[Chip+NChips*Chan]->roi);
698
699 // Extract ADC data (stored as signed short)
700 // FADs ADC is 12 bit (values -2048 .. 2047)
701 // negative/positive overflow is -2049 / +2048
702 for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
703 Data[Chip][Chan][i] = Channel[Chip+NChips*Chan]->adc_data[i];
704 }
705 }
706 }
707
708 // Prepare predicate for condition variable
709 Continue = false;
710 Count++;
711 Unlock();
712
713 // Amplitude calibration (will check if Mode is acalib)
714 AmplitudeCalibration();
715
716 // Update DIM services if necessary
717 if (Status.Update.tv_sec - PrevStatus.Update.tv_sec > m->EventUpdateDelay) {
718
719 // Check if trigger cells resonable (to trace FAD 'double signal' bug)
720 int Diff = abs((*max_element(Status.TriggerCell,Status.TriggerCell+4) - *min_element(Status.TriggerCell,Status.TriggerCell+4)));
721 if (Diff > 20 && Diff < 1000) {
722 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]);
723 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]);
724 }
725
726 // Determine event rate
727 Status.Rate =
728 Count / (double(Status.Update.tv_sec-PrevStatus.Update.tv_sec) + (Status.Update.tv_usec-PrevStatus.Update.tv_usec)/1000000.0);
729 Count = 0;
730
731 if (PrevStatus.Frequency != Status.Frequency) DIM_Frequency->updateService();
732 if (PrevStatus.TriggerNum != Status.TriggerNum) DIM_TriggerNum->updateService();
733 if (PrevStatus.BoardTime != Status.BoardTime) DIM_BoardTime->updateService();
734 if (PrevStatus.Rate != Status.Rate) DIM_Rate->updateService();
735
736 if (memcmp(PrevStatus.Lock, Status.Lock, sizeof(Status.Lock)) != 0) {
737 DIM_Lock->updateService(Status.Lock, sizeof(Status.Lock));
738 }
739 if (memcmp(PrevStatus.Temp, Status.Temp, sizeof(Status.Temp)) != 0) {
740 DIM_Temp->updateService(Status.Temp, sizeof(Status.Temp));
741 }
742 if (memcmp(PrevStatus.DAC, Status.DAC, sizeof(Status.DAC)) != 0) {
743 DIM_DAC->updateService(Status.DAC, sizeof(Status.DAC));
744 }
745 if (memcmp(PrevStatus.ROI, Status.ROI, sizeof(Status.ROI)) != 0) {
746 DIM_ROI->updateService(Status.ROI, sizeof(Status.ROI));
747 }
748 if (PrevStatus.BoardID != Status.BoardID) {
749 DIM_ID->updateService(&Status.BoardID, sizeof(Status.BoardID));
750 }
751
752 PrevStatus = Status;
753 }
754
755 // Inform event thread of new data
756 string Message = string("EVENT")+Name+"\n";
757 if (write(m->Pipe[1], Message.data(), Message.size()) == -1) {
758 m->Message(m->ERROR, "write() to Pipe[1] failed in class FADBoard (%s)", strerror(errno));
759 break;
760 }
761 }
762 else SetStatus("End package flag incorrect, removing corrupt event");
763
764 // Remove event data from internal buffer
765 memmove(Buffer, Buffer+Length, Pos-Length);
766 Pos = Pos-Length;
767 } // while()
768
769 // Set inactive and close socket descriptor
770 Active = false;
771
772 if (close(Socket) == -1) {
773 m->Message(m->ERROR, "Could not close socket descriptor for board %s (%s)", Name, strerror(errno));
774 }
775
776}
777
778//
779// Install cleanup handler and launch read thread inside class
780//
781void FADBoard::LaunchThread(class FADBoard *m) {
782
783 pthread_cleanup_push((void (*)(void *)) FADBoard::ThreadCleanup, (void *) m);
784 m->ReadLoop();
785 pthread_cleanup_pop(0);
786}
787
788
789//
790// Set status message
791//
792void FADBoard::SetStatus(const char *Format, ...) {
793
794 int Ret;
795
796 // Assemble message
797 va_list ArgumentPointer;
798 va_start(ArgumentPointer, Format);
799 Lock();
800 Ret = vsnprintf(Status.Message, sizeof(Status.Message), Format, ArgumentPointer);
801 Unlock();
802 va_end(ArgumentPointer);
803
804 if (Ret == -1) m->Message(m->FATAL, "snprintf() in FADBoard::SetStatus() failed (%s)", strerror(errno));
805
806 // Update status service
807 DIM_Status->updateService(Status.Message);
808}
809
810
811//
812// Lock and unlock mutex
813//
814void FADBoard::Lock() {
815
816 int Ret;
817
818 if ((Ret = pthread_mutex_lock(&Mutex)) != 0) {
819 m->Message(m->FATAL, "pthread_mutex_lock() failed in class FADBoard (%s)", strerror(Ret));
820 }
821}
822
823void FADBoard::Unlock() {
824
825 int Ret;
826
827 if ((Ret = pthread_mutex_unlock(&Mutex)) != 0) {
828 m->Message(m->FATAL, "pthread_mutex_unlock() failed in class FADBoard (%s)", strerror(Ret));
829 }
830}
831
832// Ensure that mutex is unlocked when before cancelling thread
833void FADBoard::ThreadCleanup(class FADBoard *This) {
834
835 int Ret;
836
837 if ((Ret = pthread_mutex_trylock(&This->Mutex)) != 0) {
838 if (Ret != EBUSY) This->m->Message(This->m->FATAL, "pthread_mutex_trylock() failed in FADBoard::ThreadCleanup (%s)", strerror(Ret));
839 }
840 This->Unlock();
841}
842
843//
844// Open other sockets
845//
846// Error reporting is limited as this function is expected to be removed when firmware allows single socket
847//
848void FADBoard::threadHandler() {
849
850 int List[] = {31920, 31921, 31922, 31923, 31924, 31925, 31926};
851 int Socket[sizeof(List)/sizeof(int)], MaxSocketNum, Ret;
852 fd_set DescriptorList;
853 char Buffer[1000000];
854
855 // Resolve hostname
856 struct hostent *Host = gethostbyname(Name);
857 if (Host == 0) return;
858
859 // Connect to server
860 struct sockaddr_in SocketAddress;
861 SocketAddress.sin_family = PF_INET;
862 SocketAddress.sin_addr = *(struct in_addr*) Host->h_addr;
863
864 for (unsigned int i=0; i<sizeof(List)/sizeof(int); i++) {
865 // Open socket descriptor
866 if ((Socket[i] = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
867 m->Message(m->ERROR, "OtherSockets: Could not open socket for port %d (%s)\n", List[i], strerror(errno));
868 return;
869 }
870 MaxSocketNum = *max_element(Socket, Socket+sizeof(List)/sizeof(int));
871
872 // Connect to server
873 SocketAddress.sin_port = htons((unsigned short) List[i]);
874 if (connect(Socket[i], (struct sockaddr *) &SocketAddress, sizeof(SocketAddress)) == -1) return;
875 }
876
877 while(true) {
878 // Wait for data from sockets
879 FD_ZERO(&DescriptorList);
880 for (unsigned int i=0; i<sizeof(List)/sizeof(int); i++) FD_SET(Socket[i], &DescriptorList);
881 if (select(MaxSocketNum+1, &DescriptorList, NULL, NULL, NULL) == -1) {
882 m->Message(m->ERROR, "OtherSockets: Error with select() (%s)\n", strerror(errno));
883 break;
884 }
885
886 // Data from socket
887 for (unsigned int i=0; i<sizeof(List)/sizeof(int); i++) if (FD_ISSET(Socket[i], &DescriptorList)) {
888 Ret = read(Socket[i], Buffer, sizeof(Buffer));
889 if (Ret == -1) m->Message(m->ERROR, "OtherSockets: Error reading from port %d (%s)\n", List[i], strerror(errno));
890 }
891 }
892
893 // Close all sockets
894 for (unsigned int i=0; i<sizeof(List)/sizeof(int); i++) {
895 if ((Socket[i] != -1) && (close(Socket[i]) == -1)) {
896 m->Message(m->ERROR, "OtherSockets: Could not close socket of port %d (%s)", List[i], strerror(errno));
897 }
898 }
899}
Note: See TracBrowser for help on using the repository browser.