source: fact/FADctrl/FADBoard.cc@ 10108

Last change on this file since 10108 was 10101, checked in by ogrimm, 14 years ago
Amplitude calibration information stored in file
File size: 9.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 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(*((unsigned short *) (Buffer+Temp))) != 0xfb01 && Temp<Pos) Temp++;
223 if (Temp != 0) {
224 memmove(Buffer, Buffer+Temp, Pos-Temp);
225 Pos -= Temp;
226 m->PrintMessage("Removed %d bytes because of start_package_flag not found\n", Temp);
227 continue;
228 }
229
230 // Wait until the buffer contains at least enough bytes to potentially hold a PEVNT_HEADER
231 if (Pos < sizeof(PEVNT_HEADER)) continue;
232
233 unsigned int Length = ntohs(Header->package_length)*2*sizeof(char);
234 if (Pos < Length) continue;
235
236 // Extract data if event end package flag correct
237 if (ntohs(*(unsigned short *) (Buffer+Length-sizeof(unsigned short))) == 0x04FE) {
238
239 // Prepare pointers to channel data (channels stored in order 0,9,18,27 - 1,10,19,28 - ... - 8,17,26,35)
240 PCHANNEL *Channel[NChips*NChannels], *Pnt=(PCHANNEL *) (Header+1);
241 for(unsigned int i=0; i<NChips*NChannels; i++) {
242 Channel[i] = Pnt;
243 Pnt = (PCHANNEL *) ((short *) (Channel[i] + 1) + ntohs(Channel[i]->roi));
244 }
245
246 PrevStatus = Status;
247
248 // Lock to avoid concurrent access in GetStatus()
249 Lock();
250
251 gettimeofday(&Status.Update, NULL);
252
253 // Extract ID and type information
254 Status.BoardID = ntohl(Header->board_id);
255 Status.TriggerID = ntohl(Header->local_trigger_id);
256 Status.TriggerType = ntohs(Header->local_trigger_type);
257
258 // Extract temperatures (MSB indicates if temperature is positive or negative)
259 for (unsigned int i=0; i<NTemp; i++) {
260 if ((ntohs(Header->drs_temperature[i]) & 0x8000) == 0) Status.Temp[i] = float(ntohs(Header->drs_temperature[i]) >> 3)/16;
261 else Status.Temp[i] = float(0xE000 | (ntohs(Header->drs_temperature[i])) >> 3)/16;
262 }
263
264 // Extract DAC channels
265 for (unsigned int i=0; i<NDAC; i++) Status.DAC[i] = ntohs(Header->dac[i]);
266
267 short Buf;
268 for (unsigned int Chip=0; Chip<NChips; Chip++) {
269 // Extract trigger cells
270 Status.TriggerCell[Chip] = (int) ntohs(Channel[Chip]->start_cell);
271
272 for (unsigned int Chan=0; Chan<NChannels; Chan++) {
273 // Extract ROI
274 Status.ROI[Chip][Chan] = ntohs(Channel[Chip+NChips*Chan]->roi);
275
276 // Extract ADC data (stored in 12 bit signed twis complement with out-of-range-bit and leading zeroes)
277 for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
278 Buf = ntohs(Channel[Chip+NChips*Chan]->adc_data[i]);
279 (Buf <<= 4) >>= 4; //delete the sign-bit by shifting left and shift back
280 Data[Chip][Chan][i] = Buf;
281 }
282 }
283 }
284
285 // If requested for calibration, add rotated data for later averaging
286 if (DoSum && NumForSum>0) {
287 for (unsigned int Chip=0; Chip<NChips; Chip++) for (unsigned int Chan=0; Chan<NChannels; Chan++) {
288 for (int i=0; i<Status.ROI[Chip][Chan]; i++) {
289 Sum[Chip][Chan][(i+Status.TriggerCell[Chip]) % NBins] += Data[Chip][Chan][i];
290 }
291 }
292 NumForSum--;
293 if (NumForSum == 0) DoSum = false;
294 }
295
296 Unlock();
297
298 // Update DIM services if necessary
299 if (memcmp(PrevStatus.Temp, Status.Temp, sizeof(Status.Temp)) != 0) {
300 DIM_Temp->updateService(Status.Temp, sizeof(Status.Temp));
301 }
302 if (memcmp(PrevStatus.DAC, Status.DAC, sizeof(Status.DAC)) != 0) {
303 DIM_DAC->updateService(Status.DAC, sizeof(Status.DAC));
304 }
305 if (memcmp(PrevStatus.ROI, Status.ROI, sizeof(Status.ROI)) != 0) {
306 DIM_ROI->updateService(Status.ROI, sizeof(Status.ROI));
307 }
308 if (PrevStatus.BoardID != Status.BoardID) {
309 DIM_ID->updateService(&Status.BoardID, sizeof(Status.BoardID));
310 }
311 }
312 else printf("End package flag incorrect, removing corrupt event\n");
313
314 // Remove event data from internal buffer
315 memmove(Buffer, Buffer+Length, Pos-Length);
316 Pos = Pos-Length;
317 } // while()
318}
319
320
321//
322// Launch read thread inside class
323//
324void FADBoard::LaunchThread(class FADBoard *m) {
325
326 m->ReadLoop();
327}
328
329
330//
331// Lock and unlock mutex
332//
333void FADBoard::Lock() {
334
335 int Ret;
336
337 if ((Ret = pthread_mutex_lock(&Mutex)) != 0) {
338 m->Message(m->FATAL, "pthread_mutex_lock() failed in class FADBoard (%s)", strerror(Ret));
339 }
340}
341
342void FADBoard::Unlock() {
343
344 int Ret;
345
346 if ((Ret = pthread_mutex_unlock(&Mutex)) != 0) {
347 m->Message(m->FATAL, "pthread_mutex_unlock() failed in class FADBoard (%s)", strerror(Ret));
348 }
349}
Note: See TracBrowser for help on using the repository browser.