source: fact/BIASctrl/Crate.cc@ 11908

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