source: fact/FADctrl/FADBoard.cc@ 10117

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