source: fact/FADctrl/FADBoard.cc@ 11285

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