source: fact/BIASctrl/Crate.cc@ 10071

Last change on this file since 10071 was 10070, checked in by ogrimm, 14 years ago
Updates to bias
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 // === Write data ===
123 if ((N = write(fDescriptor, Buf.data(), Buf.size())) < (int) Buf.size()) {
124 if (N == -1) m->Message(m->ERROR, "Could not write data to crate (%s)", strerror(errno));
125 else m->Message(m->ERROR, "Could write only %d of %d bytes to board", N, Buf.size());
126 ErrorCount++;
127 goto ExitCommunicate;
128 }
129
130 // === Try to read back data with time-out ===
131 do {
132 FD_ZERO(&SelectDescriptor); FD_SET(fDescriptor, &SelectDescriptor);
133 if (select(fDescriptor+1, &SelectDescriptor, NULL, NULL, &WaitTime)==-1) {
134 m->Message(m->ERROR, "Error with select() (%s)", strerror(errno));
135 goto ExitCommunicate;
136 }
137
138 // Time-out expired?
139 if (!FD_ISSET(fDescriptor, &SelectDescriptor)) {
140 goto ExitCommunicate;
141 }
142
143 // Read data
144 if ((N = read(fDescriptor, Buffer, sizeof(Buffer))) == -1) {
145 m->Message(m->ERROR, "Read error (%s)", strerror(errno));
146 ErrorCount++;
147 goto ExitCommunicate;
148 }
149
150 // Add data to buffer
151 for (int i=0; i<N; i++) Data.push_back(Buffer[i]);
152 } while(Data.size() < Buf.size());
153
154 // === Check if multiple of three bytes were returned ===
155 if (Data.size() % 3 != 0) {
156 Data.clear();
157 goto ExitCommunicate;
158 }
159
160 // === Check/update all wrap counter ===
161 for (unsigned int i=0; i<Data.size(); i+=3) {
162 if (WrapCount != -1) {
163 if ((WrapCount+1)%8 == ((Data[i]>>4) & 7)) WrapOK = true;
164 else WrapOK = false;
165 }
166 WrapCount = (Data[i]>>4) & 7;
167 }
168
169 // === UnLock file descriptor ===
170 ExitCommunicate:
171 funlockfile(File);
172
173 if (Data.empty()) Data.push_back(0);
174
175 return Data;
176}
177
178//
179// System reset of bias crate
180//
181int Crate::SystemReset() {
182
183 vector<unsigned char> Data = Communicate(string(3, 0));
184
185 if (Data.size() == 3) {
186 ErrorCount = 0;
187 return 1;
188 }
189 return 0;
190}
191
192//
193// Read all channels status
194//
195int Crate::ReadAll() {
196
197 string Buf;
198
199 // Prepare command to read all channels
200 for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
201 Buf.push_back(1<<5 | i<<1 | (j&16)>>4);
202 Buf.push_back(j<<4);
203 Buf.push_back(0);
204 }
205
206 // Execute command
207 vector<unsigned char> Data = Communicate(Buf);
208
209 if (Data.size() != Buf.size()) return 0;
210
211 // Evaluate data returned from crate
212 int Count = 0;
213 for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
214 Current[i][j] = (Data[Count+1] + (Data[Count] & 0x0f)*256) * 1.22;
215 OC[i][j] = Data[Count] & 128;
216 Present[i][j] = Data[Count+2] & 0x70 ? false : true;
217 ResetHit = Data[Count+2] & 128;
218 Count += 3;
219 if (i==2 && j==19) OC[i][j] = false;
220 }
221 return 1;
222}
223
224
225// ***** Global set *****
226int Crate::GlobalSet(double Voltage) {
227
228 unsigned int SetPoint = (unsigned int) (Voltage/90.0*0x0fff);
229
230 // Execute command
231 string Buf;
232 Buf = (((Buf + char(1<<6)) + char(SetPoint>>8)) + char(SetPoint));
233 vector<unsigned char> Data = Communicate(Buf);
234
235 if (Data.size() == 3) {
236 for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
237 DAC[i][j] = SetPoint;
238 Volt[i][j] = Voltage;
239 RefVolt[i][j] = Voltage;
240 }
241 return 1;
242 }
243 return 0;
244}
245
246
247// ***** Set channel voltages *****
248int Crate::SetChannels(map<unsigned int, double> V) {
249
250 string Buf;
251
252 if (V.empty()) return 1;
253
254 // Build and execute commands
255 for (map<unsigned int, double>::const_iterator it = V.begin(); it != V.end(); ++it) {
256 // If DAC value unchanged, do not send command
257 if (DAC[it->first/NUM_CHANNELS][it->first%NUM_CHANNELS] == it->second/90.0*0x0fff) continue;
258
259 // Add command to buffer
260 Buf += char(3<<5) | char(it->first/NUM_CHANNELS<<1 & 0x0f) | char((it->first%NUM_CHANNELS&16)>>4 & 1);
261 Buf += char(it->first%NUM_CHANNELS<<4) | ((((unsigned int) (it->second/90.0*0x0fff))>>8) & 0x0f);
262 Buf += char(it->second/90.0*0x0fff);
263 }
264 vector<unsigned char> Data = Communicate(Buf);
265
266 // Store new voltage values of successful
267 if (Data.size() == Buf.size()) {
268 for (map<unsigned int, double>::const_iterator it = V.begin(); it != V.end(); ++it) {
269 DAC[it->first/NUM_CHANNELS][it->first%NUM_CHANNELS] = (unsigned int) (it->second/90.0*0x0fff);
270 Volt[it->first/NUM_CHANNELS][it->first%NUM_CHANNELS] = it->second;
271 RefVolt[it->first/NUM_CHANNELS][it->first%NUM_CHANNELS] = it->second;
272 }
273 return 1;
274 }
275 return 0;
276}
277
278
279// ***** Synchronize board *****
280bool Crate::Synch() {
281
282 int Trial = 0;
283 vector<unsigned char> Data;
284
285 while(++Trial <= 3) {
286 Data = Communicate(string(1, 0));
287 if (Data.size() == 3) return true;
288 }
289 return false;
290}
291
292
293// ***** Determine offset for current measurement *****
294bool Crate::CurrentCalib(double Voltage) {
295
296 // Set voltage of all channels and wait for current to settle
297 if (GlobalSet((int) (Voltage/90*0xfff)) != 1) return false;
298 sleep(1);
299
300 // Measure current of all channels
301 if (ReadAll() != 1) return false;
302
303 for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
304 CurrentOffset[i][j] = Current[i][j];
305 }
306 return true;
307}
308
309
310// ***** Set all voltages of board to zero *****
311void Crate::ClearVoltageArrays() {
312
313 for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
314 DAC[i][j] = 0;
315 Volt[i][j] = 0;
316 RefVolt[i][j] = 0;
317 }
318
319 UpdateDIM();
320}
321
322
323// ***** Return calibrated voltage of given channel *****
324double Crate::GetVoltage(unsigned int Channel) {
325
326 if (Channel >= MAX_NUM_BOARDS*NUM_CHANNELS) return 0;
327 else return Volt[Channel/NUM_CHANNELS][Channel%NUM_CHANNELS];
328}
329
330
331// ***** Return DAC value of given channel *****
332unsigned int Crate::GetDAC(unsigned int Channel) {
333
334 if (Channel >= MAX_NUM_BOARDS*NUM_CHANNELS) return 0;
335 else return DAC[Channel/NUM_CHANNELS][Channel%NUM_CHANNELS];
336}
337
338
339// ***** Return current of given channel *****
340float Crate::GetCurrent(unsigned int Channel) {
341
342 if (Channel >= MAX_NUM_BOARDS*NUM_CHANNELS) return 0;
343 else return Current[Channel/NUM_CHANNELS][Channel%NUM_CHANNELS]-CurrentOffset[Channel/NUM_CHANNELS][Channel%NUM_CHANNELS];
344}
345
346
347// ***** Update DIM services *****
348void Crate::UpdateDIM() {
349
350 BiasVolt->updateService();
351 BiasDAC->updateService();
352}
353
354
355// ***** Set reference current for dynamic mode *****
356void Crate::SetRefCurrent() {
357
358 for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
359 RefCurrent[i][j] = Current[i][j];
360 }
361}
362
363
364// ***** Correct voltages according to current *****
365void Crate::AdaptVoltages() {
366
367 static int LastUpdate = 0;
368
369 map<unsigned int, double> Voltages;
370
371 for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
372 if (RefVolt[i][j] == 0) continue;
373 Voltages[i*NUM_CHANNELS+j] = RefVolt[i][j] + (RefCurrent[i][j]-Current[i][j])*RESISTOR/1e6;
374 }
375 SetChannels(Voltages);
376
377 if (time(NULL)-LastUpdate > 5) {
378 LastUpdate = time(NULL);
379 UpdateDIM();
380 }
381}
Note: See TracBrowser for help on using the repository browser.