source: fact/BIASctrl/Crate.cc@ 10096

Last change on this file since 10096 was 10096, checked in by ogrimm, 12 years ago
Small changes to limit error messages in case crate communication breaks
File size: 9.9 KB
Line 
1/********************************************************************\
2
3 Interface to FACT bias voltage crate
4
5\********************************************************************/
6#include <utility>
7
8#include "Crate.h"
9#include "User.h" // Must not be in header file to avoid problem with declaring class User
10
11using namespace std;
12
13//
14// Constructor
15//
16Crate::Crate(string CrateName, int Number, class User *PIO) {
17
18 struct termios tio;
19
20 // Initialize
21 InitOK = false;
22 File = NULL;
23 m = PIO;
24 Name = new char [CrateName.size()+1];
25 strcpy(Name, CrateName.c_str());
26 CrateNumber = Number;
27 WrapCount = -1;
28
29 for (int i=0; i<MAX_NUM_BOARDS; i++) {
30 for (int j=0; j<NUM_CHANNELS; j++) {
31 OC[i][j] = false;
32 Present[i][j] = false;
33 Current[i][j] = 0;
34 CurrentOffset[i][j] = 0;
35 }
36 }
37 ResetHit = false;
38 WrapOK = true;
39 WrapCount = -1;
40 ErrorCount = 0;
41
42 // Create DIM services
43 stringstream ID;
44 ID << setfill('0') << setw(2) << CrateNumber;
45
46 NameService = new DimService ((SERVER_NAME"/NAME/ID"+ID.str()).c_str(), Name);
47 BiasVolt = new DimService ((char *) (SERVER_NAME"/VOLT/ID"+ID.str()).c_str(), (char *) "D", Volt, MAX_NUM_BOARDS*NUM_CHANNELS*sizeof(double));
48 BiasDAC = new DimService ((char *) (SERVER_NAME"/DAC/ID"+ID.str()).c_str(), (char *) "I", DAC, MAX_NUM_BOARDS*NUM_CHANNELS*sizeof(int));
49 BiasCurrent = new DimService ((char *) (SERVER_NAME"/MICROAMP/ID"+ID.str()).c_str(), (char *) "F", Current, MAX_NUM_BOARDS*NUM_CHANNELS*sizeof(float));
50
51 ClearVoltageArrays();
52
53 // Open device
54 if ((fDescriptor = open(("/dev/"+CrateName).c_str(), O_RDWR|O_NOCTTY|O_NDELAY)) == -1) {
55 if(errno != 2) m->PrintMessage("Error: Could not open device %d/%s (%s)\n", CrateNumber, Name, strerror(errno));
56 return;
57 }
58
59 // Generate FILE pointer
60 if ((File = fdopen(fDescriptor, "rb+")) == NULL) {
61 m->PrintMessage("Error: fdopen() failed on device %d/%s (%s)\n", CrateNumber, Name, strerror(errno));
62 return;
63 }
64
65 // Get current serial port settings
66 if (tcgetattr(fDescriptor, &tio) == -1) {
67 m->PrintMessage("Error: tcgetattr() failed on device %s (%s)\n", Name, strerror(errno));
68 return;
69 }
70
71 // Set baudrate and raw mode
72 if (cfsetspeed(&tio, BAUDRATE) == -1) {
73 m->PrintMessage("Error: Could not set baud rate of device %s (%s)\n", Name, strerror(errno));
74 return;
75 }
76 cfmakeraw(&tio);
77 if (tcsetattr(fDescriptor, TCSANOW, &tio ) == -1) {
78 m->PrintMessage("Error: tcsetattr() failed on device %s (%s)\n", Name, strerror(errno));
79 return;
80 }
81
82 InitOK = true;
83}
84
85//
86// Destructor (Resets board)
87//
88Crate::~Crate() {
89
90 if(fDescriptor != -1) {
91 GlobalSet(0);
92
93 SystemReset();
94 if (File == NULL) {
95 if (close(fDescriptor) == -1) m->PrintMessage("Error closing device %s (%s)\n", Name, strerror(errno));
96 }
97 else if (fclose(File) != 0) m->PrintMessage("Error closing device %s\n", Name);
98 }
99
100 delete NameService;
101 delete BiasVolt;
102 delete BiasDAC;
103 delete BiasCurrent;
104 delete[] Name;
105}
106
107
108// Communicate: Write and read from HV Board until time-out has been reached
109//
110// Returns: 0 error, 1 success, -1 time-out exceeded
111vector<unsigned char> Crate::Communicate(string Buf) {
112
113 int N;
114 fd_set SelectDescriptor;
115 struct timeval WaitTime = {(long) m->fTimeOut, (long) ((m->fTimeOut-(long) m->fTimeOut)*1e6)};
116 char Buffer[10000];
117 vector<unsigned char> Data;
118
119 // === Lock device ===
120 flockfile(File);
121
122 // Do not try to communicate if crate has too many errors
123 if (ErrorCount > MAX_ERR_COUNT) goto ExitCommunicate;
124
125 // === Write data ===
126 if ((N = write(fDescriptor, Buf.data(), Buf.size())) < (int) Buf.size()) {
127 if (N == -1) m->Message(m->ERROR, "Could not write data to crate (%s)", strerror(errno));
128 else m->Message(m->ERROR, "Could write only %d of %d bytes to board", N, Buf.size());
129 ErrorCount++;
130
131 }
132
133 // === Try to read back data with time-out ===
134 do {
135 FD_ZERO(&SelectDescriptor); FD_SET(fDescriptor, &SelectDescriptor);
136 if (select(fDescriptor+1, &SelectDescriptor, NULL, NULL, &WaitTime)==-1) {
137 m->Message(m->FATAL, "Error with select() (%s)", strerror(errno));
138 }
139
140 // Time-out expired?
141 if (!FD_ISSET(fDescriptor, &SelectDescriptor)) {
142 goto ExitCommunicate;
143 }
144
145 // Read data
146 if ((N = read(fDescriptor, Buffer, sizeof(Buffer))) == -1) {
147 m->Message(m->ERROR, "Read error (%s)", strerror(errno));
148 ErrorCount++;
149 goto ExitCommunicate;
150 }
151
152 // Add data to buffer
153 for (int i=0; i<N; i++) Data.push_back(Buffer[i]);
154 } while(Data.size() < Buf.size());
155
156 // === Check if multiple of three bytes were returned ===
157 if (Data.size() % 3 != 0) {
158 Data.clear();
159 goto ExitCommunicate;
160 }
161
162 // === Check/update all wrap counter ===
163 for (unsigned int i=0; i<Data.size(); i+=3) {
164 if (WrapCount != -1) {
165 if ((WrapCount+1)%8 == ((Data[i]>>4) & 7)) WrapOK = true;
166 else WrapOK = false;
167 }
168 WrapCount = (Data[i]>>4) & 7;
169 }
170
171 // === UnLock file descriptor ===
172 ExitCommunicate:
173 funlockfile(File);
174
175 if (Data.empty()) Data.push_back(0);
176
177 return Data;
178}
179
180//
181// System reset of bias crate
182//
183int Crate::SystemReset() {
184
185 vector<unsigned char> Data = Communicate(string(3, 0));
186
187 if (Data.size() == 3) {
188 ErrorCount = 0;
189 return 1;
190 }
191 return 0;
192}
193
194//
195// Read all channels status
196//
197int Crate::ReadAll() {
198
199 string Buf;
200
201 // Prepare command to read all channels
202 for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
203 Buf.push_back(1<<5 | i<<1 | (j&16)>>4);
204 Buf.push_back(j<<4);
205 Buf.push_back(0);
206 }
207
208 // Execute command
209 vector<unsigned char> Data = Communicate(Buf);
210
211 if (Data.size() != Buf.size()) return 0;
212
213 // Evaluate data returned from crate
214 int Count = 0;
215 for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
216 Current[i][j] = (Data[Count+1] + (Data[Count] & 0x0f)*256) * 1.22;
217 OC[i][j] = Data[Count] & 128;
218 Present[i][j] = Data[Count+2] & 0x70 ? false : true;
219 ResetHit = Data[Count+2] & 128;
220 Count += 3;
221 if (i==2 && j==19) OC[i][j] = false;
222 }
223 return 1;
224}
225
226
227// ***** Global set *****
228int Crate::GlobalSet(double Voltage) {
229
230 unsigned int SetPoint = (unsigned int) (Voltage/90.0*0x0fff);
231
232 // Execute command
233 string Buf;
234 Buf = (((Buf + char(1<<6)) + char(SetPoint>>8)) + char(SetPoint));
235 vector<unsigned char> Data = Communicate(Buf);
236
237 if (Data.size() == 3) {
238 for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
239 DAC[i][j] = SetPoint;
240 Volt[i][j] = Voltage;
241 RefVolt[i][j] = Voltage;
242 }
243 return 1;
244 }
245 return 0;
246}
247
248
249// ***** Set channel voltages *****
250int Crate::SetChannels(map<unsigned int, double> V) {
251
252 string Buf;
253
254 if (V.empty()) return 1;
255
256 // Build and execute commands
257 for (map<unsigned int, double>::const_iterator it = V.begin(); it != V.end(); ++it) {
258 // If DAC value unchanged, do not send command
259 if (DAC[it->first/NUM_CHANNELS][it->first%NUM_CHANNELS] == it->second/90.0*0x0fff) continue;
260
261 // Add command to buffer
262 Buf += char(3<<5) | char(it->first/NUM_CHANNELS<<1 & 0x0f) | char((it->first%NUM_CHANNELS&16)>>4 & 1);
263 Buf += char(it->first%NUM_CHANNELS<<4) | ((((unsigned int) (it->second/90.0*0x0fff))>>8) & 0x0f);
264 Buf += char(it->second/90.0*0x0fff);
265 }
266 vector<unsigned char> Data = Communicate(Buf);
267
268 // Store new voltage values of successful
269 if (Data.size() == Buf.size()) {
270 for (map<unsigned int, double>::const_iterator it = V.begin(); it != V.end(); ++it) {
271 DAC[it->first/NUM_CHANNELS][it->first%NUM_CHANNELS] = (unsigned int) (it->second/90.0*0x0fff);
272 Volt[it->first/NUM_CHANNELS][it->first%NUM_CHANNELS] = it->second;
273 RefVolt[it->first/NUM_CHANNELS][it->first%NUM_CHANNELS] = it->second;
274 }
275 return 1;
276 }
277 return 0;
278}
279
280
281// ***** Synchronize board *****
282bool Crate::Synch() {
283
284 int Trial = 0;
285 vector<unsigned char> Data;
286
287 while(++Trial <= 3) {
288 Data = Communicate(string(1, 0));
289 if (Data.size() == 3) return true;
290 }
291 return false;
292}
293
294
295// ***** Determine offset for current measurement *****
296bool Crate::CurrentCalib(double Voltage) {
297
298 // Set voltage of all channels and wait for current to settle
299 if (GlobalSet((int) (Voltage/90*0xfff)) != 1) return false;
300 sleep(1);
301
302 // Measure current of all channels
303 if (ReadAll() != 1) return false;
304
305 for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
306 CurrentOffset[i][j] = Current[i][j];
307 }
308 return true;
309}
310
311
312// ***** Set all voltages of board to zero *****
313void Crate::ClearVoltageArrays() {
314
315 for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
316 DAC[i][j] = 0;
317 Volt[i][j] = 0;
318 RefVolt[i][j] = 0;
319 }
320
321 UpdateDIM();
322}
323
324
325// ***** Return calibrated voltage of given channel *****
326double Crate::GetVoltage(unsigned int Channel) {
327
328 if (Channel >= MAX_NUM_BOARDS*NUM_CHANNELS) return 0;
329 else return Volt[Channel/NUM_CHANNELS][Channel%NUM_CHANNELS];
330}
331
332
333// ***** Return DAC value of given channel *****
334unsigned int Crate::GetDAC(unsigned int Channel) {
335
336 if (Channel >= MAX_NUM_BOARDS*NUM_CHANNELS) return 0;
337 else return DAC[Channel/NUM_CHANNELS][Channel%NUM_CHANNELS];
338}
339
340
341// ***** Return current of given channel *****
342float Crate::GetCurrent(unsigned int Channel) {
343
344 if (Channel >= MAX_NUM_BOARDS*NUM_CHANNELS) return 0;
345 else return Current[Channel/NUM_CHANNELS][Channel%NUM_CHANNELS]-CurrentOffset[Channel/NUM_CHANNELS][Channel%NUM_CHANNELS];
346}
347
348
349// ***** Update DIM services *****
350void Crate::UpdateDIM() {
351
352 BiasVolt->updateService();
353 BiasDAC->updateService();
354}
355
356
357// ***** Set reference current for dynamic mode *****
358void Crate::SetRefCurrent() {
359
360 for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
361 RefCurrent[i][j] = Current[i][j];
362 }
363}
364
365
366// ***** Correct voltages according to current *****
367void Crate::AdaptVoltages() {
368
369 static int LastUpdate = 0;
370
371 map<unsigned int, double> Voltages;
372
373 for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
374 if (RefVolt[i][j] == 0) continue;
375 Voltages[i*NUM_CHANNELS+j] = RefVolt[i][j] + (RefCurrent[i][j]-Current[i][j])*RESISTOR/1e6;
376 }
377 SetChannels(Voltages);
378
379 if (time(NULL)-LastUpdate > 5) {
380 LastUpdate = time(NULL);
381 UpdateDIM();
382 }
383}
Note: See TracBrowser for help on using the repository browser.