source: fact/BIASctrl/Crate.cc@ 10525

Last change on this file since 10525 was 10153, checked in by ogrimm, 14 years ago
New command 'crate', changed signalling of program exit
File size: 9.5 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 }
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 BiasDAC = new DimService ((char *) (SERVER_NAME"/DAC/ID"+ID.str()).c_str(), (char *) "I", DAC, MAX_NUM_BOARDS*NUM_CHANNELS*sizeof(int));
48 BiasCurrent = new DimService ((char *) (SERVER_NAME"/MICROAMP/ID"+ID.str()).c_str(), (char *) "F", Current, MAX_NUM_BOARDS*NUM_CHANNELS*sizeof(float));
49
50 ClearVoltageArrays();
51
52 // Open device
53 if ((fDescriptor = open(("/dev/"+CrateName).c_str(), O_RDWR|O_NOCTTY|O_NDELAY)) == -1) {
54 if(errno != 2) m->PrintMessage("Error: Could not open device %d/%s (%s)\n", CrateNumber, Name, strerror(errno));
55 return;
56 }
57
58 // Generate FILE pointer
59 if ((File = fdopen(fDescriptor, "rb+")) == NULL) {
60 m->PrintMessage("Error: fdopen() failed on device %d/%s (%s)\n", CrateNumber, Name, strerror(errno));
61 return;
62 }
63
64 // Get current serial port settings
65 if (tcgetattr(fDescriptor, &tio) == -1) {
66 m->PrintMessage("Error: tcgetattr() failed on device %s (%s)\n", Name, strerror(errno));
67 return;
68 }
69
70 // Set baudrate and raw mode
71 if (cfsetspeed(&tio, BAUDRATE) == -1) {
72 m->PrintMessage("Error: Could not set baud rate of device %s (%s)\n", Name, strerror(errno));
73 return;
74 }
75 cfmakeraw(&tio);
76 if (tcsetattr(fDescriptor, TCSANOW, &tio ) == -1) {
77 m->PrintMessage("Error: tcsetattr() failed on device %s (%s)\n", Name, strerror(errno));
78 return;
79 }
80
81 InitOK = true;
82}
83
84//
85// Destructor (Resets board)
86//
87Crate::~Crate() {
88
89 if(fDescriptor != -1) {
90 GlobalSet(0);
91
92 SystemReset();
93 if (File == NULL) {
94 if (close(fDescriptor) == -1) m->PrintMessage("Error closing device %s (%s)\n", Name, strerror(errno));
95 }
96 else if (fclose(File) != 0) m->PrintMessage("Error closing device %s\n", Name);
97 }
98
99 delete NameService;
100 delete BiasVolt;
101 delete BiasDAC;
102 delete BiasCurrent;
103 delete[] Name;
104}
105
106
107// Communicate: Write and read from HV Board until time-out has been reached
108//
109// Returns: 0 error, 1 success, -1 time-out exceeded
110vector<unsigned char> Crate::Communicate(string Buf) {
111
112 int N;
113 fd_set SelectDescriptor;
114 struct timeval WaitTime = {(long) m->fTimeOut, (long) ((m->fTimeOut-(long) m->fTimeOut)*1e6)};
115 char Buffer[10000];
116 vector<unsigned char> Data;
117
118 // === Lock device ===
119 flockfile(File);
120
121 // Do not try to communicate if crate has too many errors
122 if (ErrorCount > MAX_ERR_COUNT) goto ExitCommunicate;
123
124 // === Write data ===
125 if ((N = write(fDescriptor, Buf.data(), Buf.size())) < (int) Buf.size()) {
126 if (N == -1) m->Message(m->ERROR, "Could not write data to crate (%s)", strerror(errno));
127 else m->Message(m->ERROR, "Could write only %d of %d bytes to board", N, Buf.size());
128 ErrorCount++;
129
130 }
131
132 // === Try to read back data with time-out ===
133 do {
134 FD_ZERO(&SelectDescriptor); FD_SET(fDescriptor, &SelectDescriptor);
135 if (select(fDescriptor+1, &SelectDescriptor, NULL, NULL, &WaitTime)==-1) {
136 if (errno = EINTR) goto ExitCommunicate; // in case program is exiting
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// ***** Set all voltages of board to zero *****
296void Crate::ClearVoltageArrays() {
297
298 for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
299 DAC[i][j] = 0;
300 Volt[i][j] = 0;
301 RefVolt[i][j] = 0;
302 }
303
304 UpdateDIM();
305}
306
307
308// ***** Return calibrated voltage of given channel *****
309double Crate::GetVoltage(unsigned int Channel) {
310
311 if (Channel >= MAX_NUM_BOARDS*NUM_CHANNELS) return 0;
312 else return Volt[Channel/NUM_CHANNELS][Channel%NUM_CHANNELS];
313}
314
315
316// ***** Return DAC value of given channel *****
317unsigned int Crate::GetDAC(unsigned int Channel) {
318
319 if (Channel >= MAX_NUM_BOARDS*NUM_CHANNELS) return 0;
320 else return DAC[Channel/NUM_CHANNELS][Channel%NUM_CHANNELS];
321}
322
323
324// ***** Return current of given channel *****
325float Crate::GetCurrent(unsigned int Channel) {
326
327 if (Channel >= MAX_NUM_BOARDS*NUM_CHANNELS) return 0;
328 else return Current[Channel/NUM_CHANNELS][Channel%NUM_CHANNELS];
329}
330
331
332// ***** Update DIM services *****
333void Crate::UpdateDIM() {
334
335 BiasVolt->updateService();
336 BiasDAC->updateService();
337}
338
339
340// ***** Set reference current for dynamic mode *****
341void Crate::SetRefCurrent() {
342
343 for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
344 RefCurrent[i][j] = Current[i][j];
345 }
346}
347
348
349// ***** Correct voltages according to current *****
350void Crate::AdaptVoltages() {
351
352 static int LastUpdate = 0;
353
354 map<unsigned int, double> Voltages;
355
356 for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
357 if (RefVolt[i][j] == 0) continue;
358 Voltages[i*NUM_CHANNELS+j] = RefVolt[i][j] + (RefCurrent[i][j]-Current[i][j])*RESISTOR/1e6;
359 }
360 SetChannels(Voltages);
361
362 if (time(NULL)-LastUpdate > 5) {
363 LastUpdate = time(NULL);
364 UpdateDIM();
365 }
366}
Note: See TracBrowser for help on using the repository browser.