source: fact/FADctrl/FADBoard.cc@ 10114

Last change on this file since 10114 was 10114, checked in by ogrimm, 12 years ago
Event data can be written to disk in M0 format with command take
File size: 10.9 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// Initiate average
177//
178void FADBoard::AccumulateSum(unsigned int n, bool Rotate) {
179
180 if (!Active) return;
181
182 Lock();
183 SumPhysPipeline = Rotate;
184 memset(Sum, 0, sizeof(Sum));
185 NumForSum = n;
186 DoSum = true;
187 Unlock();
188}
189
190
191//
192// Read data from board
193//
194void FADBoard::ReadLoop() {
195
196 static char Buffer[READ_BUFFER_SIZE];
197 static unsigned int Pos = 0, Temp;
198 const PEVNT_HEADER *Header = (PEVNT_HEADER *) Buffer;
199 ssize_t Result;
200 struct BoardStatus PrevStatus;
201 int Ret;
202
203 memset(&PrevStatus, 0, sizeof(PrevStatus));
204
205 while (!m->ExitRequest) {
206 // Read data from socket
207 Result = read(Socket, Buffer + Pos, sizeof(Buffer)-Pos);
208
209 // Check result of read
210 if (Result == -1) {
211 m->PrintMessage("Error: Could not read from socket, exiting read loop (%s)\n", strerror(errno));
212 CommError = true;
213 break;
214 }
215 else if (Result == 0) {
216 m->PrintMessage("Server not existing anymore, exiting read loop\n");
217 CommError = true;
218 break;
219 }
220
221 // If not active, discard incoming data
222 if (!Active) continue;
223
224 // Advance write pointer
225 Pos += Result;
226
227 // Check if internal buffer full
228 if (Pos == sizeof(Buffer)) {
229 m->PrintMessage("Internal buffer full, deleting all data in buffer\n");
230 Pos = 0;
231 continue;
232 }
233
234 // Check if buffer starts with start_package_flag, remove data if not
235 Temp = 0;
236 while (ntohs(*((unsigned short *) (Buffer+Temp))) != 0xfb01 && Temp<Pos) Temp++;
237 if (Temp != 0) {
238 memmove(Buffer, Buffer+Temp, Pos-Temp);
239 Pos -= Temp;
240 m->PrintMessage("Removed %d bytes because of start_package_flag not found\n", Temp);
241 continue;
242 }
243
244 // Wait until the buffer contains at least enough bytes to potentially hold a PEVNT_HEADER
245 if (Pos < sizeof(PEVNT_HEADER)) continue;
246
247 unsigned int Length = ntohs(Header->package_length)*2*sizeof(char);
248 if (Pos < Length) continue;
249
250 // Extract data if event end package flag correct
251 if (ntohs(*(unsigned short *) (Buffer+Length-sizeof(unsigned short))) == 0x04FE) {
252
253 // Prepare pointers to channel data (channels stored in order 0,9,18,27 - 1,10,19,28 - ... - 8,17,26,35)
254 PCHANNEL *Channel[NChips*NChannels], *Pnt=(PCHANNEL *) (Header+1);
255 for(unsigned int i=0; i<NChips*NChannels; i++) {
256 Channel[i] = Pnt;
257 Pnt = (PCHANNEL *) ((short *) (Channel[i] + 1) + ntohs(Channel[i]->roi));
258 }
259
260 PrevStatus = Status;
261
262 // Lock to avoid concurrent access in GetStatus()
263 Lock();
264
265 // Wait until event thread processed the previous data
266 while (!Continue) {
267 if ((Ret = pthread_cond_wait(&CondVar, &Mutex)) != 0) {
268 m->Message(m->ERROR, "pthread_cond_wait() failed (%s)", strerror(Ret));
269 }
270 }
271
272 gettimeofday(&Status.Update, NULL);
273
274 // Extract ID and type information
275 Status.BoardID = ntohl(Header->board_id);
276 Status.FirmwareRevision = ntohl(Header->version_no);
277 Status.TriggerID = ntohl(Header->local_trigger_id);
278 Status.TriggerType = ntohs(Header->local_trigger_type);
279
280 // Extract temperatures (MSB indicates if temperature is positive or negative)
281 for (unsigned int i=0; i<NTemp; i++) {
282 if ((ntohs(Header->drs_temperature[i]) & 0x8000) == 0) Status.Temp[i] = float(ntohs(Header->drs_temperature[i]) >> 3)/16;
283 else Status.Temp[i] = float(0xE000 | (ntohs(Header->drs_temperature[i])) >> 3)/16;
284 }
285
286 // Extract DAC channels
287 for (unsigned int i=0; i<NDAC; i++) Status.DAC[i] = ntohs(Header->dac[i]);
288
289 short Buf;
290 for (unsigned int Chip=0; Chip<NChips; Chip++) {
291 // Extract trigger cells
292 Status.TriggerCell[Chip] = (int) ntohs(Channel[Chip]->start_cell);
293
294 for (unsigned int Chan=0; Chan<NChannels; Chan++) {
295 // Extract ROI
296 Status.ROI[Chip][Chan] = ntohs(Channel[Chip+NChips*Chan]->roi);
297
298 // Extract ADC data (stored in 12 bit signed twis complement with out-of-range-bit and leading zeroes)
299 for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
300 Buf = ntohs(Channel[Chip+NChips*Chan]->adc_data[i]);
301 (Buf <<= 4) >>= 4; //delete the sign-bit by shifting left and shift back
302 Data[Chip][Chan][i] = Buf;
303 }
304 }
305 }
306
307 // If requested for calibration, add rotated data for later averaging
308 if (DoSum && NumForSum>0) {
309 for (unsigned int Chip=0; Chip<NChips; Chip++) for (unsigned int Chan=0; Chan<NChannels; Chan++) {
310 for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
311 if (SumPhysPipeline) Sum[Chip][Chan][(i+Status.TriggerCell[Chip]) % NBins] += Data[Chip][Chan][i];
312 else Sum[Chip][Chan][i] = Data[Chip][Chan][i]-Baseline[Chip][Chan][(i-Status.TriggerCell[Chip]) % NBins];
313 }
314 }
315 NumForSum--;
316 if (NumForSum == 0) DoSum = false;
317 }
318
319 Continue = false;
320 Unlock();
321
322 // Update DIM services if necessary
323 if (memcmp(PrevStatus.Temp, Status.Temp, sizeof(Status.Temp)) != 0) {
324 DIM_Temp->updateService(Status.Temp, sizeof(Status.Temp));
325 }
326 if (memcmp(PrevStatus.DAC, Status.DAC, sizeof(Status.DAC)) != 0) {
327 DIM_DAC->updateService(Status.DAC, sizeof(Status.DAC));
328 }
329 if (memcmp(PrevStatus.ROI, Status.ROI, sizeof(Status.ROI)) != 0) {
330 DIM_ROI->updateService(Status.ROI, sizeof(Status.ROI));
331 }
332 if (PrevStatus.BoardID != Status.BoardID) {
333 DIM_ID->updateService(&Status.BoardID, sizeof(Status.BoardID));
334 }
335 }
336 else printf("End package flag incorrect, removing corrupt event\n");
337
338 // Inform event thread of new data
339 if (write(m->Pipe[1], Name, strlen(Name)+1) == -1) {
340 m->Message(m->ERROR, "write() to Pipe[1] failed in class FADBoard (%s)", strerror(errno));
341 m->ExitRequest = true;
342 }
343
344 // Remove event data from internal buffer
345 memmove(Buffer, Buffer+Length, Pos-Length);
346 Pos = Pos-Length;
347 } // while()
348}
349
350
351//
352// Launch read thread inside class
353//
354void FADBoard::LaunchThread(class FADBoard *m) {
355
356 m->ReadLoop();
357}
358
359
360//
361// Lock and unlock mutex
362//
363void FADBoard::Lock() {
364
365 int Ret;
366
367 if ((Ret = pthread_mutex_lock(&Mutex)) != 0) {
368 m->Message(m->FATAL, "pthread_mutex_lock() failed in class FADBoard (%s)", strerror(Ret));
369 }
370}
371
372void FADBoard::Unlock() {
373
374 int Ret;
375
376 if ((Ret = pthread_mutex_unlock(&Mutex)) != 0) {
377 m->Message(m->FATAL, "pthread_mutex_unlock() failed in class FADBoard (%s)", strerror(Ret));
378 }
379}
Note: See TracBrowser for help on using the repository browser.