source: fact/BIASctrl/Crate.cc@ 16334

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