source: fact/FADctrl/FADBoard.cc@ 11386

Last change on this file since 11386 was 11385, checked in by ogrimm, 15 years ago
Board time published as DIM service, files written with permissions for OTHER
File size: 22.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 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", &Status.Lock, sizeof(Status.Lock));
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;
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 // ====== Part A: Check if amplitude calibration should start and initialise =====
173 case standbye:
174 if (m->Mode != m->acalib) break;
175
176 // Invalidate current calibration
177 ACalib.Time = -1;
178 Count = 0;
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 DACCmd[1] = htons(0);
191 DACCmd[3] = htons(0);
192 DACCmd[5] = htons(0);
193 Send(DACCmd, sizeof(DACCmd));
194
195 // Clear sum vector and set state to accumulate
196 memset(Sum, 0, sizeof(Sum));
197 State = baseline;
198 SetStatus("Starting calilbration");
199 break;
200
201 // ====== Part B: Baseline calibration =====
202 case baseline:
203 // Check for stopping
204 if (m->Mode != m->acalib) {
205 State = cleanup;
206 break;
207 }
208
209 // Average
210 for (unsigned int Chip=0; Chip<NChips; Chip++) {
211 for (unsigned int Chan=0; Chan<NChannels; Chan++) {
212 for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
213 Sum[Chip][Chan][(i+Status.TriggerCell[Chip]) % NBins] += Data[Chip][Chan][i];
214 }
215 }
216 }
217 Count++;
218
219 // Determine baseline if integration finished
220 if (Count < m->NumEventsRequested) break;
221
222 for (unsigned int i=0; i<NChips; i++) {
223 for (unsigned int j=0; j<NChannels; j++) {
224 for (unsigned int k=0; k<NBins; k++) {
225 ACalib.Baseline[i][j][k] = Sum[i][j][k] / m->NumEventsRequested;
226 }
227 }
228 }
229
230 // Set new DAC values and start accumulation
231 DACCmd[1] = htons(50000);
232 DACCmd[3] = htons(50000);
233 DACCmd[5] = htons(50000);
234 Send(DACCmd, sizeof(DACCmd));
235
236 // Clear sum vector and set state to accumulate
237 memset(Sum, 0, sizeof(Sum));
238 Count = 0;
239 State = gain;
240 break;
241
242 // ====== Part C: Gain calibration =====
243 case gain:
244 // Check for stopping
245 if (m->Mode != m->acalib) {
246 State = cleanup;
247 break;
248 }
249
250 // Average
251 for (unsigned int Chip=0; Chip<NChips; Chip++) {
252 for (unsigned int Chan=0; Chan<NChannels; Chan++) {
253 for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
254 Sum[Chip][Chan][(i+Status.TriggerCell[Chip]) % NBins] += Data[Chip][Chan][i];
255 }
256 }
257 }
258 Count++;
259
260 // Determine gain if integration finished
261 if (Count < m->NumEventsRequested) break;
262
263 for (unsigned int i=0; i<NChips; i++) {
264 for (unsigned int j=0; j<NChannels; j++) {
265 for (unsigned int k=0; k<NBins; k++) {
266 ACalib.Gain[i][j][k] = (Sum[i][j][k] / m->NumEventsRequested) - ACalib.Baseline[i][j][k];
267 }
268 }
269 }
270
271 // Set new DAC values and start accumulation
272 DACCmd[1] = htons(0);
273 DACCmd[3] = htons(0);
274 DACCmd[5] = htons(0);
275 Send(DACCmd, sizeof(DACCmd));
276
277 // Clear sum vector and set state to accumulate
278 memset(Sum, 0, sizeof(Sum));
279 Count = 0;
280 State = secondary;
281 break;
282
283 // ====== Part D: Secondary calibration =====
284 case secondary:
285 // Check for stopping
286 if (m->Mode != m->acalib) {
287 State = cleanup;
288 break;
289 }
290
291 // Average
292 for (unsigned int Chip=0; Chip<NChips; Chip++) {
293 for (unsigned int Chan=0; Chan<NChannels; Chan++) {
294 for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
295 Sum[Chip][Chan][i] = Data[Chip][Chan][i] - ACalib.Baseline[Chip][Chan][(i-Status.TriggerCell[Chip]) % NBins];
296 }
297 }
298 }
299 Count++;
300
301 // Determine secondary baseline if integration finished
302 if (Count < m->NumEventsRequested) break;
303
304 for (unsigned int i=0; i<NChips; i++) {
305 for (unsigned int j=0; j<NChannels; j++) {
306 for (unsigned int k=0; k<NBins; k++) {
307 ACalib.Secondary[i][j][k] = Sum[i][j][k] / (double) m->NumEventsRequested;
308 }
309 }
310 }
311
312 // Store calibration time and temperature
313 ACalib.DNA = Status.DNA;
314 ACalib.Frequency = Status.Frequency;
315 ACalib.Time = time(NULL);
316 ACalib.Temp = 0;
317 for (unsigned int i=0; i<NTemp; i++) ACalib.Temp += Status.Temp[i] / NTemp;
318
319 // Inform event thread that calibration is finished for this board
320 if (write(m->Pipe[1], Message.data(), Message.size()) == -1) {
321 m->Message(m->ERROR, "write() to Pipe[1] failed in class FADBoard::AmplitudeCalibration (%s)", strerror(errno));
322 }
323
324 SetStatus("Finished calibration");
325 State = cleanup;
326 break;
327
328 // ====== Part E: Write back original ROI and DAC settings =====
329 case cleanup:
330 // ROI values
331
332 ROICmd.clear();
333 for (unsigned int i=0; i<NChips*NChannels; i++) {
334 ROICmd.push_back(htons(CMD_Write | (BADDR_ROI + i)));
335 ROICmd.push_back(htons(InitialStatus.ROI[i/NChannels][i%NChannels]));
336 }
337 ROICmd.push_back(htons(CMD_Execute));
338 Send(&ROICmd[0], ROICmd.size()*sizeof(unsigned short));
339
340 // DAC values
341 DACCmd[1] = htons(InitialStatus.DAC[1]);
342 DACCmd[3] = htons(InitialStatus.DAC[2]);
343 DACCmd[5] = htons(InitialStatus.DAC[3]);
344 Send(DACCmd, sizeof(DACCmd));
345
346 // Update DIM service with calibration information
347 for (unsigned int i=0; i<NChips; i++) {
348 for (unsigned int j=0; j<NChannels; j++) {
349 for (unsigned int k=0; k<NBins; k++) {
350 ACalData[0][i][j][k] = ACalib.Baseline[i][j][k];
351 ACalData[1][i][j][k] = ACalib.Gain[i][j][k];
352 ACalData[2][i][j][k] = ACalib.Secondary[i][j][k];
353 }
354 }
355 }
356 DIM_ACalData->updateService(ACalData, 3*NChips*NChannels*NBins*sizeof(float));
357
358 State = wait;
359 break;
360
361 // ====== Wait for Mode not being idle =====
362 case wait:
363 if (m->Mode == m->idle) State = standbye;
364 break;
365 }
366}
367
368//
369// Connect to board and read data
370//
371void FADBoard::ReadLoop() {
372
373 char Buffer[READ_BUFFER_SIZE];
374 unsigned int Pos = 0, Count = 0;
375 const PEVNT_HEADER *Header = (PEVNT_HEADER *) Buffer;
376 ssize_t Result;
377 struct sockaddr_in SocketAddress;
378 struct BoardStatus PrevStatus;
379 int Ret;
380
381 // Resolve hostname
382 struct hostent *Host = gethostbyname(Name);
383 if (Host == 0) {
384 SetStatus("Could not resolve host name '%s'", Name);
385 return;
386 }
387
388 SocketAddress.sin_family = PF_INET;
389 SocketAddress.sin_port = htons(Port);
390 SocketAddress.sin_addr = *(struct in_addr*) Host->h_addr;
391
392 // Open socket descriptor
393 if ((Socket = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
394 m->Message(m->ERROR, "Could not open socket for %s (%s)\n", Name, strerror(errno));
395 return;
396 }
397
398 // Connect to server
399 if (connect(Socket, (struct sockaddr *) &SocketAddress, sizeof(SocketAddress)) == -1) {
400 SetStatus("Could not connect to port %hu (%s)", Port, strerror(errno));
401 }
402 else {
403 CommOK = true;
404 Active = true;
405 SetStatus("Connected");
406 }
407
408 // Use not zero so that comparing Status and PrevStatus at first test will likely show differences
409 memset(&PrevStatus, 0xee, sizeof(PrevStatus));
410
411 // Leave loop if program termination requested or board communication not OK
412 while (!m->ExitRequest && CommOK) {
413 // Read data from socket
414 Result = read(Socket, Buffer + Pos, sizeof(Buffer)-Pos);
415
416 // Check result of read
417 if (Result == -1) {
418 m->Message(m->ERROR, "Could not read from socket for %s, exiting read loop (%s)\n", Name, strerror(errno));
419 CommOK = false;
420 break;
421 }
422 else if (Result == 0) {
423 SetStatus("Server not existing anymore, exiting read loop");
424 CommOK = false;
425 break;
426 }
427
428 // If not active, discard incoming data
429 if (!Active) continue;
430
431 // Advance write pointer
432 Pos += Result;
433
434 // Check if internal buffer full
435 if (Pos == sizeof(Buffer)) {
436 SetStatus("Internal buffer full, deleting all data in buffer");
437 Pos = 0;
438 continue;
439 }
440
441 // Check if buffer starts with start_package_flag, remove data if not
442 unsigned int Temp = 0;
443 while (ntohs(*((unsigned short *) (Buffer+Temp))) != 0xfb01 && Temp<Pos) Temp++;
444 if (Temp != 0) {
445 memmove(Buffer, Buffer+Temp, Pos-Temp);
446 Pos -= Temp;
447 SetStatus("Removed %d bytes because of start_package_flag not found", Temp);
448 continue;
449 }
450
451 // Wait until the buffer contains at least enough bytes to potentially hold a PEVNT_HEADER
452 if (Pos < sizeof(PEVNT_HEADER)) continue;
453
454 unsigned int Length = ntohs(Header->package_length)*2*sizeof(char);
455 if (Pos < Length) continue;
456
457 // Extract data if event end package flag correct
458 if (ntohs(*(unsigned short *) (Buffer+Length-sizeof(unsigned short))) == 0x04FE) {
459
460 // Prepare pointers to channel data (channels stored in order 0,9,18,27 - 1,10,19,28 - ... - 8,17,26,35)
461 PCHANNEL *Channel[NChips*NChannels], *Pnt=(PCHANNEL *) (Header+1);
462 for(unsigned int i=0; i<NChips*NChannels; i++) {
463 Channel[i] = Pnt;
464 Pnt = (PCHANNEL *) ((short *) (Channel[i] + 1) + ntohs(Channel[i]->roi));
465 }
466
467 // Wait until event thread processed the previous data and lock to avoid concurrent access in GetStatus()
468 Lock();
469 while (!Continue) {
470 struct timespec Wakeup;
471 Wakeup.tv_sec = time(NULL)+MAX_WAIT_FOR_CONDITION;
472 Wakeup.tv_nsec = 0;
473 if ((Ret = pthread_cond_timedwait(&CondVar, &Mutex, &Wakeup)) != 0) {
474 if (Ret == ETIMEDOUT) SetStatus("Board %s timed out (%d s) waiting for condition\n", Name, MAX_WAIT_FOR_CONDITION);
475 else m->Message(m->ERROR, "pthread_cond_wait() failed (%s)", strerror(Ret));
476 }
477 }
478 gettimeofday(&Status.Update, NULL);
479
480 // Extract board and trigger information
481 Status.BoardID = ntohs(Header->board_id);
482 Status.FirmwareRevision = ntohs(Header->version_no);
483 Status.BoardTime = ntohl(Header->time);
484 Status.EventCounter = ntohl(Header->fad_evt_counter);
485 Status.TriggerNum = ntohl(Header->trigger_id);
486 Status.Runnumber = ntohl(Header->runnumber);
487 Status.TriggerType = ntohs(Header->trigger_type);
488 Status.TriggerCRC = ntohs(Header->trigger_crc);
489 Status.DNA = Header->DNA;
490
491 // Extract frequency related information
492 Status.Frequency = ntohl(Header->REFCLK_frequency)/1.0e3*2.048;
493 Status.PhaseShift = Header->adc_clock_phase_shift;
494 for (unsigned int i=0; i<NChips; i++) {
495 if ((ntohs(Header->PLLLCK)>>12 & (1<<i)) != 0) Status.Lock[i] = 1;
496 else Status.Lock[i] = 0;
497 }
498
499 // Extract Firmware status info
500 Status.denable = (bool) ( ntohs(Header->PLLLCK) & (1<<11) );
501 Status.dwrite = (bool) ( ntohs(Header->PLLLCK) & (1<<10) );
502 Status.DCM_lock = (bool) ( ntohs(Header->PLLLCK) & (1<<7) );
503 Status.DCM_ready = (bool) ( ntohs(Header->PLLLCK) & (1<<6) );
504 Status.spi_clk = (bool) ( ntohs(Header->PLLLCK) & (1<<5) );
505 Status.RefClk_low = (bool) ( ntohs(Header->PLLLCK) & (1<<8) );
506
507 // Extract temperatures (MSB indicates if temperature is positive or negative)
508 for (unsigned int i=0; i<NTemp; i++) {
509 if ((ntohs(Header->drs_temperature[i]) & 0x8000) == 0) Status.Temp[i] = float(ntohs(Header->drs_temperature[i]) >> 3)/16;
510 else Status.Temp[i] = float(0xE000 | (ntohs(Header->drs_temperature[i])) >> 3)/16;
511 }
512
513 // Extract DAC channels
514 for (unsigned int i=0; i<NDAC; i++) Status.DAC[i] = ntohs(Header->dac[i]);
515
516 for (unsigned int Chip=0; Chip<NChips; Chip++) {
517 // Extract trigger cells
518 Status.TriggerCell[Chip] = (int) ntohs(Channel[Chip]->start_cell);
519
520 for (unsigned int Chan=0; Chan<NChannels; Chan++) {
521 // Extract ROI
522 Status.ROI[Chip][Chan] = ntohs(Channel[Chip+NChips*Chan]->roi);
523
524 // Extract ADC data (stored as signed short)
525 // FADs ADC is 12 bit (values -2048 .. 2047)
526 // negative/positive overflow is -2049 / +2048
527 for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
528 Data[Chip][Chan][i] = Channel[Chip+NChips*Chan]->adc_data[i];
529 }
530 }
531 }
532
533 // Prepare predicate for condition variable
534 Continue = false;
535 Count++;
536 Unlock();
537
538 // Amplitude calibration (will check if Mode is acalib)
539 AmplitudeCalibration();
540
541 // Update DIM services if necessary
542 if (Status.Update.tv_sec - PrevStatus.Update.tv_sec > m->EventUpdateDelay) {
543
544 // Determine event rate
545 Status.Rate =
546 Count / (double(Status.Update.tv_sec-PrevStatus.Update.tv_sec) + (Status.Update.tv_usec-PrevStatus.Update.tv_usec)/1000000.0);
547 Count = 0;
548
549 if (PrevStatus.Frequency != Status.Frequency) DIM_Frequency->updateService();
550 if (PrevStatus.TriggerNum != Status.TriggerNum) DIM_TriggerNum->updateService();
551 if (PrevStatus.BoardTime != Status.BoardTime) DIM_BoardTime->updateService();
552 if (PrevStatus.Rate != Status.Rate) DIM_Rate->updateService();
553
554 if (memcmp(PrevStatus.Lock, Status.Lock, sizeof(Status.Lock)) != 0) {
555 DIM_Lock->updateService();
556 }
557 if (memcmp(PrevStatus.Temp, Status.Temp, sizeof(Status.Temp)) != 0) {
558 DIM_Temp->updateService(Status.Temp, sizeof(Status.Temp));
559 }
560 if (memcmp(PrevStatus.DAC, Status.DAC, sizeof(Status.DAC)) != 0) {
561 DIM_DAC->updateService(Status.DAC, sizeof(Status.DAC));
562 }
563 if (memcmp(PrevStatus.ROI, Status.ROI, sizeof(Status.ROI)) != 0) {
564 DIM_ROI->updateService(Status.ROI, sizeof(Status.ROI));
565 }
566 if (PrevStatus.BoardID != Status.BoardID) {
567 DIM_ID->updateService(&Status.BoardID, sizeof(Status.BoardID));
568 }
569
570 PrevStatus = Status;
571 }
572
573 // Inform event thread of new data
574 string Message = string("EVENT")+Name+"\n";
575 if (write(m->Pipe[1], Message.data(), Message.size()) == -1) {
576 m->Message(m->ERROR, "write() to Pipe[1] failed in class FADBoard (%s)", strerror(errno));
577 break;
578 }
579 }
580 else SetStatus("End package flag incorrect, removing corrupt event");
581
582 // Remove event data from internal buffer
583 memmove(Buffer, Buffer+Length, Pos-Length);
584 Pos = Pos-Length;
585 } // while()
586
587 // Set inactive and close socket descriptor
588 Active = false;
589
590 if (close(Socket) == -1) {
591 m->Message(m->ERROR, "Could not close socket descriptor for board %s (%s)", Name, strerror(errno));
592 }
593
594}
595
596//
597// Install cleanup handler and launch read thread inside class
598//
599void FADBoard::LaunchThread(class FADBoard *m) {
600
601 pthread_cleanup_push((void (*)(void *)) FADBoard::ThreadCleanup, (void *) m);
602 m->ReadLoop();
603 pthread_cleanup_pop(0);
604}
605
606
607//
608// Set status message
609//
610void FADBoard::SetStatus(const char *Format, ...) {
611
612 int Ret;
613
614 // Assemble message
615 va_list ArgumentPointer;
616 va_start(ArgumentPointer, Format);
617 Lock();
618 Ret = vsnprintf(Status.Message, sizeof(Status.Message), Format, ArgumentPointer);
619 Unlock();
620 va_end(ArgumentPointer);
621
622 if (Ret == -1) m->Message(m->FATAL, "snprintf() in FADBoard::SetStatus() failed (%s)", strerror(errno));
623
624 // Update status service
625 DIM_Status->updateService(Status.Message);
626}
627
628
629//
630// Lock and unlock mutex
631//
632void FADBoard::Lock() {
633
634 int Ret;
635
636 if ((Ret = pthread_mutex_lock(&Mutex)) != 0) {
637 m->Message(m->FATAL, "pthread_mutex_lock() failed in class FADBoard (%s)", strerror(Ret));
638 }
639}
640
641void FADBoard::Unlock() {
642
643 int Ret;
644
645 if ((Ret = pthread_mutex_unlock(&Mutex)) != 0) {
646 m->Message(m->FATAL, "pthread_mutex_unlock() failed in class FADBoard (%s)", strerror(Ret));
647 }
648}
649
650// Ensure that mutex is unlocked when before cancelling thread
651void FADBoard::ThreadCleanup(class FADBoard *This) {
652
653 int Ret;
654
655 if ((Ret = pthread_mutex_trylock(&This->Mutex)) != 0) {
656 if (Ret != EBUSY) This->m->Message(This->m->FATAL, "pthread_mutex_trylock() failed in FADBoard::ThreadCleanup (%s)", strerror(Ret));
657 }
658 This->Unlock();
659}
660
661//
662// Open other sockets
663//
664// Error reporting is limited as this function is expected to be removed when firmware allows single socket
665//
666void FADBoard::threadHandler() {
667
668 //int List[] = {5001, 5002, 5003, 5004, 5005, 5006, 5007};
669 int List[] = {31920, 31921, 31922, 31923, 31924, 31925, 31926};
670 int Socket[sizeof(List)/sizeof(int)], MaxSocketNum, Ret;
671 fd_set DescriptorList;
672 char Buffer[1000000];
673
674 // Resolve hostname
675 struct hostent *Host = gethostbyname(Name);
676 if (Host == 0) return;
677
678 // Connect to server
679 struct sockaddr_in SocketAddress;
680 SocketAddress.sin_family = PF_INET;
681 SocketAddress.sin_addr = *(struct in_addr*) Host->h_addr;
682
683 for (unsigned int i=0; i<sizeof(List)/sizeof(int); i++) {
684 // Open socket descriptor
685 if ((Socket[i] = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
686 m->Message(m->ERROR, "OtherSockets: Could not open socket for port %d (%s)\n", List[i], strerror(errno));
687 return;
688 }
689 MaxSocketNum = *max_element(Socket, Socket+sizeof(List)/sizeof(int));
690
691 // Connect to server
692 SocketAddress.sin_port = htons((unsigned short) List[i]);
693 if (connect(Socket[i], (struct sockaddr *) &SocketAddress, sizeof(SocketAddress)) == -1) return;
694 }
695
696 while(true) {
697 // Wait for data from sockets
698 FD_ZERO(&DescriptorList);
699 for (unsigned int i=0; i<sizeof(List)/sizeof(int); i++) FD_SET(Socket[i], &DescriptorList);
700 if (select(MaxSocketNum+1, &DescriptorList, NULL, NULL, NULL) == -1) {
701 m->Message(m->ERROR, "OtherSockets: Error with select() (%s)\n", strerror(errno));
702 break;
703 }
704
705 // Data from socket
706 for (unsigned int i=0; i<sizeof(List)/sizeof(int); i++) if (FD_ISSET(Socket[i], &DescriptorList)) {
707 Ret = read(Socket[i], Buffer, sizeof(Buffer));
708 if (Ret == -1) m->Message(m->ERROR, "OtherSockets: Error reading from port %d (%s)\n", List[i], strerror(errno));
709 }
710 }
711
712 // Close all sockets
713 for (unsigned int i=0; i<sizeof(List)/sizeof(int); i++) {
714 if ((Socket[i] != -1) && (close(Socket[i]) == -1)) {
715 m->Message(m->ERROR, "OtherSockets: Could not close socket of port %d (%s)", List[i], strerror(errno));
716 }
717 }
718}
Note: See TracBrowser for help on using the repository browser.