source: fact/FADctrl/FADBoard.cc@ 10100

Last change on this file since 10100 was 10099, checked in by ogrimm, 14 years ago
Corrupt events (wrong start-package flag) are removed from internal buffer
File size: 9.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 Port, class FAD *Parent, unsigned int Num) {
14
15 int Ret;
16
17 // Initialization
18 m = Parent;
19 InitOK = false;
20 Active = true;
21 CommError = false;
22 ACalibTime = -1;
23 Status.Update.tv_sec = -1;
24 Thread = pthread_self(); // For checking in destructor
25
26 Name = new char [Server.size()+1]; // Name in permanent memory for DIM service
27 strcpy(Name, Server.c_str());
28
29 // Resolve hostname
30 struct hostent *Host = gethostbyname(Server.c_str());
31 if (Host == 0) {
32 m->PrintMessage("Could not resolve host name for %s\n", Server.c_str());
33 return;
34 }
35
36 // Open socket descriptor
37 if ((Socket = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
38 m->PrintMessage("Could not open socket for %s (%s)\n", Server.c_str(), strerror(errno));
39 return;
40 }
41
42 // Connect to server
43 struct sockaddr_in SocketAddress;
44 SocketAddress.sin_family = PF_INET;
45 SocketAddress.sin_port = htons(Port);
46 SocketAddress.sin_addr = *(struct in_addr*) Host->h_addr;
47
48 if (connect(Socket, (struct sockaddr *) &SocketAddress, sizeof(SocketAddress)) == -1) {
49 m->PrintMessage("Could not connect to %s at port %d (%s)\n", Server.c_str(), Port, strerror(errno));
50 return;
51 }
52
53 // Construct DIM service name prefix
54 stringstream ID;
55 ID << SERVER_NAME"/Board" << setfill('0') << setw(2) << Num << "/";
56
57 DIM_Name = new DimService((ID.str()+"Server").c_str(), Name);
58 DIM_ID = new DimService((ID.str()+"BoardID").c_str(), (char *) "S", NULL, 0);
59 DIM_Temp = new DimService((ID.str()+"Temperature").c_str(), (char *) "F", NULL, 0);
60 DIM_DAC = new DimService((ID.str()+"DAC").c_str(), (char *) "S", NULL, 0);
61 DIM_ROI = new DimService((ID.str()+"ROI").c_str(), (char *) "S", NULL, 0);
62
63 // Initialise mutex for synchronization
64 pthread_mutexattr_t Attr;
65
66 if ((Ret = pthread_mutexattr_settype(&Attr, PTHREAD_MUTEX_ERRORCHECK)) != 0) {
67 m->Message(m->ERROR, "pthread_mutex_settype() failed (%s)", strerror(Ret));
68 }
69 if ((Ret = pthread_mutex_init(&Mutex, &Attr)) != 0) {
70 m->Message(m->ERROR, "pthread_mutex_init() failed (%s)", strerror(Ret));
71 return;
72 }
73
74 // Create thread that receives data
75 if ((Ret = pthread_create(&Thread, NULL, (void * (*)(void *)) LaunchThread,(void *) this)) != 0) {
76 m->Message(m->ERROR, "pthread_create() failed in FADBoard() (%s)\n", strerror(Ret));
77 Thread = pthread_self();
78 return;
79 }
80
81 InitOK = true;
82}
83
84//
85// Destructor
86//
87FADBoard::~FADBoard() {
88
89 int Ret;
90
91 // Cancel thread and wait for it to quit
92 if (pthread_equal(Thread, pthread_self()) == 0) {
93 if ((Ret = pthread_cancel(Thread)) != 0) m->Message(m->ERROR, "pthread_cancel() failed in ~FADBoard() (%s)", strerror(Ret));
94 if ((Ret = pthread_join(Thread, NULL)) != 0) m->Message(m->ERROR, "pthread_join() failed in ~FADBoard (%s)", strerror(Ret));
95 }
96
97 // Delete mutex
98 if (InitOK && ((Ret = pthread_mutex_destroy(&Mutex)) != 0)) {
99 m->Message(m->ERROR, "pthread_mutex_destroy() failed in ~FADBoard (%s)", strerror(Ret));
100 }
101
102 delete DIM_Name;
103 delete DIM_ID;
104 delete DIM_Temp;
105 delete DIM_DAC;
106 delete DIM_ROI;
107 delete[] Name;
108
109 // Close socket descriptor
110 if ((Socket != -1) && (close(Socket) == -1)) {
111 m->PrintMessage("Could not close socket descriptor (%s)", strerror(errno));
112 }
113}
114
115
116//
117// Send data to board
118//
119void FADBoard::Send(const void *Data, size_t Bytes) {
120
121 // Do not send if not active
122 if (!Active) return;
123
124 // Write data
125 ssize_t Result = write(Socket, Data, Bytes);
126
127 // Check result
128 if (Result == -1) m->PrintMessage("Error: Could not write to socket (%s)\n", strerror(errno));
129 else if ((size_t) Result < Bytes) m->PrintMessage("Error: Could only write %d bytes out of %d to socket\n", Result, Bytes);
130}
131
132void FADBoard::Send(unsigned short Data) {
133
134 unsigned short Buffer = htons(Data);
135
136 Send(&Buffer, sizeof(unsigned short));
137}
138
139
140//
141// Get board status (mutex protected to avoid concurrent access in ReadLoop)
142//
143struct FADBoard::BoardStatus FADBoard::GetStatus() {
144
145 int Ret;
146 struct BoardStatus S;
147
148 // Lock
149 if ((Ret = pthread_mutex_lock(&Mutex)) != 0) {
150 m->Message(m->FATAL, "pthread_mutex_lock() failed in ReadLoop() (%s)", strerror(Ret));
151 }
152
153 S = Status;
154
155 // Unlock
156 if ((Ret = pthread_mutex_unlock(&Mutex)) != 0) {
157 m->Message(m->FATAL, "pthread_mutex_unlock() failed in Unlock() (%s)", strerror(Ret));
158 }
159
160 return S;
161}
162
163//
164// Initiate average
165//
166void FADBoard::AccumulateSum(unsigned int n) {
167
168 if (!Active) return;
169
170 Lock();
171 memset(Sum, 0, sizeof(Sum));
172 NumForSum = n;
173 DoSum = true;
174 Unlock();
175}
176
177
178//
179// Read data from board
180//
181void FADBoard::ReadLoop() {
182
183 static char Buffer[READ_BUFFER_SIZE];
184 static unsigned int Pos = 0, Temp;
185 const PEVNT_HEADER *Header = (PEVNT_HEADER *) Buffer;
186 ssize_t Result;
187 struct BoardStatus PrevStatus;
188
189 memset(&PrevStatus, 0, sizeof(PrevStatus));
190
191 while (!m->ExitRequest) {
192 // Read data from socket
193 Result = read(Socket, Buffer + Pos, sizeof(Buffer)-Pos);
194
195 // Check result of read
196 if (Result == -1) {
197 m->PrintMessage("Error: Could not read from socket, exiting read loop (%s)\n", strerror(errno));
198 CommError = true;
199 break;
200 }
201 else if (Result == 0) {
202 m->PrintMessage("Server not existing anymore, exiting read loop\n");
203 CommError = true;
204 break;
205 }
206
207 // If not active, discard incoming data
208 if (!Active) continue;
209
210 // Advance write pointer
211 Pos += Result;
212
213 // Check if internal buffer full
214 if (Pos == sizeof(Buffer)) {
215 m->PrintMessage("Internal buffer full, deleting all data in buffer\n");
216 Pos = 0;
217 continue;
218 }
219
220 // Check if buffer starts with start_package_flag, remove data if not
221 Temp = 0;
222 while (ntohs(Header->start_package_flag) != 0xfb01 && Pos > 0) {
223 memmove(Buffer, Buffer+1, Pos-1);
224 Pos--;
225 Temp++;
226 }
227 if (Temp != 0) {
228 printf("Removed %d bytes because of start_package_flag not found\n", Temp);
229 continue;
230 }
231
232 // Wait until the buffer contains at least enough bytes to potentially hold a PEVNT_HEADER
233 if (Pos < sizeof(PEVNT_HEADER)) continue;
234
235 unsigned int Length = ntohs(Header->package_length)*2*sizeof(char);
236 if (Pos < Length) continue;
237
238 // Extract data if event end package flag correct
239 if (ntohs(*(unsigned short *) (Buffer+Length-sizeof(unsigned short))) == 0x04FE) {
240
241 // Prepare pointers to channel data (channels stored in order 0,9,18,27 - 1,10,19,28 - ... - 8,17,26,35)
242 PCHANNEL *Channel[NChips*NChannels], *Pnt=(PCHANNEL *) (Header+1);
243 for(unsigned int i=0; i<NChips*NChannels; i++) {
244 Channel[i] = Pnt;
245 Pnt = (PCHANNEL *) ((short *) (Channel[i] + 1) + ntohs(Channel[i]->roi));
246 }
247
248 PrevStatus = Status;
249
250 // Lock to avoid concurrent access in GetStatus()
251 Lock();
252
253 gettimeofday(&Status.Update, NULL);
254
255 // Extract ID and type information
256 Status.BoardID = ntohl(Header->board_id);
257 Status.TriggerID = ntohl(Header->local_trigger_id);
258 Status.TriggerType = ntohs(Header->local_trigger_type);
259
260 // Extract temperatures (MSB indicates if temperature is positive or negative)
261 for (unsigned int i=0; i<NTemp; i++) {
262 if ((ntohs(Header->drs_temperature[i]) & 0x8000) == 0) Status.Temp[i] = float(ntohs(Header->drs_temperature[i]) >> 3)/16;
263 else Status.Temp[i] = float(0xE000 | (ntohs(Header->drs_temperature[i])) >> 3)/16;
264 }
265
266 // Extract DAC channels
267 for (unsigned int i=0; i<NDAC; i++) Status.DAC[i] = ntohs(Header->dac[i]);
268
269 short Buf;
270 for (unsigned int Chip=0; Chip<NChips; Chip++) {
271 // Extract trigger cells
272 Status.TriggerCell[Chip] = (int) ntohs(Channel[Chip]->start_cell);
273
274 for (unsigned int Chan=0; Chan<NChannels; Chan++) {
275 // Extract ROI
276 Status.ROI[Chip][Chan] = ntohs(Channel[Chip+NChips*Chan]->roi);
277
278 // Extract ADC data (stored in 12 bit signed twis complement with out-of-range-bit and leading zeroes)
279 for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
280 Buf = ntohs(Channel[Chip+NChips*Chan]->adc_data[i]);
281 (Buf <<= 4) >>= 4; //delete the sign-bit by shifting left and shift back
282 Data[Chip][Chan][i] = Buf;
283 }
284 }
285 }
286
287 // If requested for calibration, add rotated data for later averaging
288 if (DoSum && NumForSum>0) {
289 for (unsigned int Chip=0; Chip<NChips; Chip++) for (unsigned int Chan=0; Chan<NChannels; Chan++) {
290 for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
291 Sum[Chip][Chan][(i+Status.TriggerCell[Chip]) % NBins] += Data[Chip][Chan][i];
292 }
293 }
294 NumForSum--;
295 if (NumForSum == 0) DoSum = false;
296 }
297
298 Unlock();
299
300 // Update DIM services if necessary
301 if (memcmp(PrevStatus.Temp, Status.Temp, sizeof(Status.Temp)) != 0) {
302 DIM_Temp->updateService(Status.Temp, sizeof(Status.Temp));
303 }
304 if (memcmp(PrevStatus.DAC, Status.DAC, sizeof(Status.DAC)) != 0) {
305 DIM_DAC->updateService(Status.DAC, sizeof(Status.DAC));
306 }
307 if (memcmp(PrevStatus.ROI, Status.ROI, sizeof(Status.ROI)) != 0) {
308 DIM_ROI->updateService(Status.ROI, sizeof(Status.ROI));
309 }
310 if (PrevStatus.BoardID != Status.BoardID) {
311 DIM_ID->updateService(&Status.BoardID, sizeof(Status.BoardID));
312 }
313 }
314 else printf("End package flag incorrect, removing corrupt event\n");
315
316 // Remove event data from internal buffer
317 memmove(Buffer, Buffer+Length, Pos-Length);
318 Pos = Pos-Length;
319 } // while()
320}
321
322
323//
324// Launch read thread inside class
325//
326void FADBoard::LaunchThread(class FADBoard *m) {
327
328 m->ReadLoop();
329}
330
331
332//
333// Lock and unlock mutex
334//
335void FADBoard::Lock() {
336
337 int Ret;
338
339 if ((Ret = pthread_mutex_lock(&Mutex)) != 0) {
340 m->Message(m->FATAL, "pthread_mutex_lock() failed in class FADBoard (%s)", strerror(Ret));
341 }
342}
343
344void FADBoard::Unlock() {
345
346 int Ret;
347
348 if ((Ret = pthread_mutex_unlock(&Mutex)) != 0) {
349 m->Message(m->FATAL, "pthread_mutex_unlock() failed in class FADBoard (%s)", strerror(Ret));
350 }
351}
Note: See TracBrowser for help on using the repository browser.