source: fact/FADctrl/FADBoard.cc@ 10113

Last change on this file since 10113 was 10113, checked in by ogrimm, 12 years ago
Event thread informed through pipe of new incoming data
File size: 10.2 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 (if it did not quit already) and wait for it to quit
92 if (pthread_equal(Thread, pthread_self()) == 0) {
93 if ((Ret = pthread_cancel(Thread)) != 0 && Ret != ESRCH) 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, bool Rotate) {
167
168 if (!Active) return;
169
170 Lock();
171 SumPhysPipeline = Rotate;
172 memset(Sum, 0, sizeof(Sum));
173 NumForSum = n;
174 DoSum = true;
175 Unlock();
176}
177
178
179//
180// Read data from board
181//
182void FADBoard::ReadLoop() {
183
184 static char Buffer[READ_BUFFER_SIZE];
185 static unsigned int Pos = 0, Temp;
186 const PEVNT_HEADER *Header = (PEVNT_HEADER *) Buffer;
187 ssize_t Result;
188 struct BoardStatus PrevStatus;
189
190 memset(&PrevStatus, 0, sizeof(PrevStatus));
191
192 while (!m->ExitRequest) {
193 // Read data from socket
194 Result = read(Socket, Buffer + Pos, sizeof(Buffer)-Pos);
195
196 // Check result of read
197 if (Result == -1) {
198 m->PrintMessage("Error: Could not read from socket, exiting read loop (%s)\n", strerror(errno));
199 CommError = true;
200 break;
201 }
202 else if (Result == 0) {
203 m->PrintMessage("Server not existing anymore, exiting read loop\n");
204 CommError = true;
205 break;
206 }
207
208 // If not active, discard incoming data
209 if (!Active) continue;
210
211 // Advance write pointer
212 Pos += Result;
213
214 // Check if internal buffer full
215 if (Pos == sizeof(Buffer)) {
216 m->PrintMessage("Internal buffer full, deleting all data in buffer\n");
217 Pos = 0;
218 continue;
219 }
220
221 // Check if buffer starts with start_package_flag, remove data if not
222 Temp = 0;
223 while (ntohs(*((unsigned short *) (Buffer+Temp))) != 0xfb01 && Temp<Pos) Temp++;
224 if (Temp != 0) {
225 memmove(Buffer, Buffer+Temp, Pos-Temp);
226 Pos -= Temp;
227 m->PrintMessage("Removed %d bytes because of start_package_flag not found\n", Temp);
228 continue;
229 }
230
231 // Wait until the buffer contains at least enough bytes to potentially hold a PEVNT_HEADER
232 if (Pos < sizeof(PEVNT_HEADER)) continue;
233
234 unsigned int Length = ntohs(Header->package_length)*2*sizeof(char);
235 if (Pos < Length) continue;
236
237 // Extract data if event end package flag correct
238 if (ntohs(*(unsigned short *) (Buffer+Length-sizeof(unsigned short))) == 0x04FE) {
239
240 // Prepare pointers to channel data (channels stored in order 0,9,18,27 - 1,10,19,28 - ... - 8,17,26,35)
241 PCHANNEL *Channel[NChips*NChannels], *Pnt=(PCHANNEL *) (Header+1);
242 for(unsigned int i=0; i<NChips*NChannels; i++) {
243 Channel[i] = Pnt;
244 Pnt = (PCHANNEL *) ((short *) (Channel[i] + 1) + ntohs(Channel[i]->roi));
245 }
246
247 PrevStatus = Status;
248
249 // Lock to avoid concurrent access in GetStatus()
250 Lock();
251
252 gettimeofday(&Status.Update, NULL);
253
254 // Extract ID and type information
255 Status.BoardID = ntohl(Header->board_id);
256 Status.FirmwareRevision = ntohl(Header->version_no);
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 if (SumPhysPipeline) Sum[Chip][Chan][(i+Status.TriggerCell[Chip]) % NBins] += Data[Chip][Chan][i];
292 else Sum[Chip][Chan][i] = Data[Chip][Chan][i]-Baseline[Chip][Chan][(i-Status.TriggerCell[Chip]) % NBins];
293 }
294 }
295 NumForSum--;
296 if (NumForSum == 0) DoSum = false;
297 }
298
299 Unlock();
300
301 // Update DIM services if necessary
302 if (memcmp(PrevStatus.Temp, Status.Temp, sizeof(Status.Temp)) != 0) {
303 DIM_Temp->updateService(Status.Temp, sizeof(Status.Temp));
304 }
305 if (memcmp(PrevStatus.DAC, Status.DAC, sizeof(Status.DAC)) != 0) {
306 DIM_DAC->updateService(Status.DAC, sizeof(Status.DAC));
307 }
308 if (memcmp(PrevStatus.ROI, Status.ROI, sizeof(Status.ROI)) != 0) {
309 DIM_ROI->updateService(Status.ROI, sizeof(Status.ROI));
310 }
311 if (PrevStatus.BoardID != Status.BoardID) {
312 DIM_ID->updateService(&Status.BoardID, sizeof(Status.BoardID));
313 }
314 }
315 else printf("End package flag incorrect, removing corrupt event\n");
316
317 // Inform event thread of new data
318 if (write(m->Pipe[1], Name, strlen(Name)+1) == -1) {
319 m->Message(m->ERROR, "write() to Pipe[1] failed in class FADBoard (%s)", strerror(errno));
320 m->ExitRequest = true;
321 }
322
323 // Remove event data from internal buffer
324 memmove(Buffer, Buffer+Length, Pos-Length);
325 Pos = Pos-Length;
326 } // while()
327}
328
329
330//
331// Launch read thread inside class
332//
333void FADBoard::LaunchThread(class FADBoard *m) {
334
335 m->ReadLoop();
336}
337
338
339//
340// Lock and unlock mutex
341//
342void FADBoard::Lock() {
343
344 int Ret;
345
346 if ((Ret = pthread_mutex_lock(&Mutex)) != 0) {
347 m->Message(m->FATAL, "pthread_mutex_lock() failed in class FADBoard (%s)", strerror(Ret));
348 }
349}
350
351void FADBoard::Unlock() {
352
353 int Ret;
354
355 if ((Ret = pthread_mutex_unlock(&Mutex)) != 0) {
356 m->Message(m->FATAL, "pthread_mutex_unlock() failed in class FADBoard (%s)", strerror(Ret));
357 }
358}
Note: See TracBrowser for help on using the repository browser.