usermagnetps.cpp
1 /***************************************************************************
2  Copyright (C) 2002-2015 Kentaro Kitagawa
3  kitagawa@phys.s.u-tokyo.ac.jp
4 
5  This program is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License as published by the Free Software Foundation; either
8  version 2 of the License, or (at your option) any later version.
9 
10  You should have received a copy of the GNU Library General
11  Public License and a list of authors along with this program;
12  see the files COPYING and AUTHORS.
13 ***************************************************************************/
14 //---------------------------------------------------------------------------
15 #include "usermagnetps.h"
16 //---------------------------------------------------------------------------
17 
18 REGISTER_TYPE(XDriverList, PS120, "Oxford PS-120 magnet power supply");
19 REGISTER_TYPE(XDriverList, IPS120, "Oxford IPS-120 magnet power supply");
20 REGISTER_TYPE(XDriverList, CryogenicSMS, "Cryogenic SMS10/30/120C magnet power supply");
21 
22 XPS120::XPS120(const char *name, bool runtime,
23  Transaction &tr_meas, const shared_ptr<XMeasure> &meas) :
24  XOxfordDriver<XMagnetPS>(name, runtime, ref(tr_meas), meas) {
25 }
26 
27 void
28 XPS120::setActivity(int val) throw (XInterface::XInterfaceError&) {
29  int ret;
30  XScopedLock<XInterface> lock( *interface());
31  for(int i = 0; i < 3; i++) {
32  //query Activity
33  interface()->query("X");
34  if(interface()->scanf("X%*2dA%1dC%*1dH%*1dM%*2dP%*2d", &ret) != 1)
35  throw XInterface::XConvError(__FILE__, __LINE__);
36  if(ret == val) break;
37  interface()->sendf("A%u", val);
38  msecsleep(i * 100);
39  }
40 }
41 
42 void
43 XPS120::toPersistent() {
44  XScopedLock<XInterface> lock( *interface());
45  //Set to HOLD
46  interface()->send("A0");
47  msecsleep(100);
48 
49  setPCSHeater(false);
50 }
51 
52 void
53 XPS120::toZero() {
54  XScopedLock<XInterface> lock( *interface());
55  int ret;
56  //query Activity
57  interface()->query("X");
58  if(interface()->scanf("X%*2dA%1dC%*1dH%*1dM%*2dP%*2d", &ret) != 1)
59  throw XInterface::XConvError(__FILE__, __LINE__);
60  //CLAMPED
61  if(ret == 4) {
62  //Set to HOLD
63  setActivity(0);
64  msecsleep(100);
65  }
66  //Set to TO_ZERO
67  setActivity(2);
68 }
69 void
70 XPS120::toNonPersistent() {
71  XScopedLock<XInterface> lock( *interface());
72  int ret;
73  for(int i = 0; i < 3; i++) {
74  msecsleep(100);
75  //query MODE
76  interface()->query("X");
77  if(interface()->scanf("X%*2dA%*1dC%*1dH%*1dM%*1d%1dP%*2d", &ret) != 1)
78  throw XInterface::XConvError(__FILE__, __LINE__);
79  if(ret == 0) break; //At rest
80  }
81  if(ret != 0)
83  i18n("Cannot enter non-persistent mode. Output is busy."), __FILE__, __LINE__);
84 
85  //Set to HOLD
86  setActivity(0);
87 
88  setPCSHeater(true);
89 }
90 void
91 XPS120::toSetPoint() {
92  XScopedLock<XInterface> lock( *interface());
93  int ret;
94  //query Activity
95  interface()->query("X");
96  if(interface()->scanf("X%*2dA%1dC%*1dH%*1dM%*2dP%*2d", &ret) != 1)
97  throw XInterface::XConvError(__FILE__, __LINE__);
98  //CLAMPED
99  if(ret == 4) {
100  //Set to HOLD
101  setActivity(0);
102  msecsleep(300);
103  }
104  setActivity(1);
105 }
106 
107 void
108 XPS120::setPoint(double field) {
109  for(int i = 0; i < 2; i++) {
110  int df;
111  if(fabs(getTargetField() - field) < fieldResolution()) break;
112  msecsleep(100);
113  interface()->sendf("P%d", ((field >= 0) ? 1 : 2));
114  df = lrint(fabs(field) / fieldResolution());
115  interface()->sendf("J%d", df);
116  }
117 }
118 void
119 XIPS120::setPoint(double field) {
120  for(int i = 0; i < 2; i++) {
121  if(fabs(getTargetField() - field) < fieldResolution()) break;
122  msecsleep(100);
123  interface()->sendf("J%f", field);
124  }
125 }
126 
127 double
128 XIPS120::getSweepRate() {
129  return read(9);
130 }
131 double
132 XPS120::getSweepRate() {
133  return read(9) * fieldResolution();
134 }
135 double
136 XIPS120::getTargetField() {
137  return read(8);
138 }
139 double
140 XPS120::getTargetField() {
141  int ret;
142  interface()->query("X");
143  if(interface()->scanf("X%*2dA%*1dC%*1dH%*1dM%*2dP%1d%*1d", &ret) != 1)
144  throw XInterface::XConvError(__FILE__, __LINE__);
145  return ((ret & 4) ? -1 : 1) * fabs(read(8) * fieldResolution());
146 }
147 double
148 XIPS120::getPersistentField() {
149  return read(18);
150 }
151 double
152 XPS120::getPersistentField() {
153  int ret;
154  interface()->query("X");
155  if(interface()->scanf("X%*2dA%*1dC%*1dH%*1dM%*2dP%1d%*1d", &ret) != 1)
156  throw XInterface::XConvError(__FILE__, __LINE__);
157  return ((ret & 2) ? -1 : 1) * fabs(read(18) * fieldResolution());
158 }
159 double
160 XIPS120::getOutputField() {
161  return read(7);
162 }
163 double
164 XPS120::getOutputField() {
165  int ret;
166  interface()->query("X");
167  if(interface()->scanf("X%*2dA%*1dC%*1dH%*1dM%*2dP%1d%*1d", &ret) != 1)
168  throw XInterface::XConvError(__FILE__, __LINE__);
169  return ((ret & 1) ? -1 : 1) * fabs(read(7) * fieldResolution());
170 }
171 double
172 XIPS120::getOutputVolt() {
173  return read(1);
174 }
175 double
176 XPS120::getOutputVolt() {
177  return read(1) * voltageResolution();
178 }
179 double
180 XIPS120::getOutputCurrent() {
181  return read(0);
182 }
183 double
184 XPS120::getOutputCurrent() {
185  int ret;
186  interface()->query("X");
187  if(interface()->scanf("X%*2dA%*1dC%*1dH%*1dM%*2dP%1d%*1d", &ret) != 1)
188  throw XInterface::XConvError(__FILE__, __LINE__);
189  return ((ret & 1) ? -1 : 1) * fabs(read(0) * currentResolution());
190 }
191 bool
193  int ret;
194  interface()->query("X");
195  if(interface()->scanf("X%*2dA%*1dC%*1dH%1dM%*2dP%*2d", &ret) != 1)
196  throw XInterface::XConvError(__FILE__, __LINE__);
197  return (ret == 1) || (ret == 8) || (ret == 5); //On or Fault or NOPCS
198 }
199 bool
201  int ret;
202  interface()->query("X");
203  if(interface()->scanf("X%*2dA%*1dC%*1dH%1dM%*2dP%*2d", &ret) != 1)
204  throw XInterface::XConvError(__FILE__, __LINE__);
205  return (ret != 8);
206 }
207 void
208 XPS120::setPCSHeater(bool val) throw (XInterface::XInterfaceError&) {
209  interface()->sendf("H%u", (unsigned int)(val ? 1 : 0));
210  msecsleep(200);
211  if(isPCSHeaterOn() != val)
213  i18n("Persistent Switch Heater not responding"), __FILE__, __LINE__);
214 }
215 void
216 XIPS120::setRate(double hpm) {
217  for(int i = 0; i < 2; i++) {
218  if(fabs(getSweepRate() - hpm) < fieldResolution()) break;
219  interface()->sendf("T%f", hpm);
220  msecsleep(100);
221  }
222 }
223 
224 void
225 XPS120::setRate(double hpm) {
226  int ihpm = lrint(hpm / fieldResolution());
227  for(int i = 0; i < 2; i++) {
228  if(fabs(getSweepRate() - hpm) < fieldResolution()) break;
229  interface()->sendf("T%d", ihpm);
230  msecsleep(100);
231  }
232 }
233 
234 void
236  interface()->send("$Q6");
237  start();
238 }
239 
240 XCryogenicSMS::XCryogenicSMS(const char *name, bool runtime,
241  Transaction &tr_meas, const shared_ptr<XMeasure> &meas) :
242  XCharDeviceDriver<XMagnetPS>(name, runtime, ref(tr_meas), meas) {
243 
244  interface()->setSerialFlushBeforeWrite(false);
245 
246 /*
247  * Notes not mentioned in the manufacturer's manual for ver 6.
248  * GET PER command does not return a value or delimiter when it is not in persistent mode or at zero field.
249  * RAMP/DIRECTION ... command does not reply.
250  * PAUSE ... command does not reply the second line.
251  * Some commands respond with a form of HH:MM:SS ....... (command).
252  * Local button operations will emit status lines.
253  *
254  * This driver assumes...
255  * (i) TPA (tesla per ampere) has been set properly.
256  * (ii) PCSH is fitted, or "HEATER OUTPUT" is set to zero.
257  */
258  interface()->setEOS("\r\n");
259 }
260 
261 std::string
262 XCryogenicSMS::receiveMessage(const char *title, bool is_stamp_required) {
263  for(;;) {
264  interface()->receive();
265  bool has_stamp = false;
266  const char *pbuf = &interface()->buffer()[0];
267  if( *pbuf == 0x13 /*XOFF*/)
268  pbuf++; //ignores strange non-necessary XOFF for ver 7
269  if(strncmp(pbuf, "........", 8)) {
270  if( !strncmp(pbuf, "------->", 8)) {
271  //Error message is passed.
272  throw XInterface::XInterfaceError(pbuf + 8, __FILE__, __LINE__);
273  }
274  //Message w/ time stamp.
275  int ss;
276  if(sscanf( pbuf, "%*2d:%*2d:%2d", &ss) != 1)
277  throw XInterface::XConvError(__FILE__, __LINE__);
278  has_stamp = true;
279  }
280  auto cl_pos = std::find(interface()->buffer().begin() + 8, interface()->buffer().end(), ':');
281  if(cl_pos == interface()->buffer().end())
282  throw XInterface::XConvError(__FILE__, __LINE__);
283  int cnt = cl_pos - interface()->buffer().begin();
284  if(cnt < 10)
285  throw XInterface::XConvError(__FILE__, __LINE__);
286  if( !strncmp( pbuf + 9, title, strlen(title))) {
287  if(is_stamp_required && !has_stamp)
288  throw XInterface::XConvError(__FILE__, __LINE__);
289  cl_pos++; //skipping colon.
290  while(cl_pos != interface()->buffer().end()) {
291  if( *cl_pos != ' ')
292  return &*cl_pos;
293  cl_pos++; //skipping white space.
294  }
295  throw XInterface::XConvError(__FILE__, __LINE__);
296  }
297  }
298 }
299 
300 void
302  interface()->send("SET TPA");
303  if(sscanf(receiveMessage("FIELD CONSTANT").c_str(), "%lf", &m_tpa) != 1)
304  throw XInterface::XConvError(__FILE__, __LINE__);
305 
306  interface()->send("TESLA ON");
307  receiveMessage("UNITS");
308 
309  start();
310 }
311 void
312 XCryogenicSMS::changePauseState(bool pause) {
313 // Lock before calling me.
314 // XScopedLock<XInterface> lock( *interface());
315  interface()->send("PAUSE");
316  char buf[10];
317  if(sscanf(receiveMessage("PAUSE STATUS").c_str(), "%4s", buf) != 1)
318  throw XInterface::XConvError(__FILE__, __LINE__);
319  if( !strncmp("ON", buf, 2)) {
320  if(pause)
321  return;
322  interface()->send("PAUSE OFF");
323  receiveMessage("PAUSE STATUS", true);
324  }
325  else {
326  if( !pause)
327  return;
328  interface()->send("PAUSE ON");
329  receiveMessage("PAUSE STATUS", true);
330  }
331 }
332 void
333 XCryogenicSMS::toPersistent() {
334  XScopedLock<XInterface> lock( *interface());
335  changePauseState(true);
336  interface()->send("HEATER OFF");
337  receiveMessage("HEATER STATUS");
338 
339  setRate(10.0); //Setting very high rate.
340 }
341 void
342 XCryogenicSMS::toNonPersistent() {
343  XScopedLock<XInterface> lock( *interface());
344  setRate(Snapshot( *this)[ *sweepRate()]);
345  changePauseState(true);
346  interface()->send("HEATER ON");
347  receiveMessage("HEATER STATUS");
348 }
349 void
350 XCryogenicSMS::ramp(const char *str) {
351  interface()->sendf("RAMP %s", str); //"RAMP..." does not respond for firmware > 6.
352  msecsleep(100);
353 }
354 void
355 XCryogenicSMS::toZero() {
356  XScopedLock<XInterface> lock( *interface());
357  ramp("ZERO");
358  changePauseState(false);
359 }
360 void
361 XCryogenicSMS::toSetPoint() {
362  XScopedLock<XInterface> lock( *interface());
363  ramp("MID");
364  changePauseState(false);
365 }
366 void
367 XCryogenicSMS::changePolarity(int p) {
368  for(int tcnt = 0; tcnt < 3; ++tcnt) {
369  interface()->sendf("DIRECTION %c", (p > 0) ? '+' : '-'); //"DIR..." does not respond for firmware > 6.
370  msecsleep(100);
371  interface()->sendf("GET OUTPUT");
372  char c;
373  if(sscanf(receiveMessage("OUTPUT").c_str(), "%c", &c) != 1)
374  throw XInterface::XConvError(__FILE__, __LINE__);
375  int x = (c != '-') ? 1 : -1;
376  if(x * p > 0)
377  return;
378  }
379  throw XInterface::XInterfaceError(i18n("Failed to reverse current direction."), __FILE__, __LINE__);
380 }
381 void
382 XCryogenicSMS::setPoint(double field) {
383  XScopedLock<XInterface> lock( *interface());
384  interface()->send("TESLA ON");
385  receiveMessage("UNITS");
386 
387  double x = getOutputField();
388 
389  if(fabs(x) < fieldResolution() * 10) {
390  if(field < 0.0) {
391  changePolarity(-1);
392  }
393  if(field > 0.0) {
394  if( !isOutputPositive())
395  changePolarity(+1);
396  }
397  }
398  else if(x * field < 0) {
399  throw XInterface::XInterfaceError(i18n("Failed to reverse current direction."), __FILE__, __LINE__);
400  }
401 
402  interface()->sendf("SET MID %.5f", fabs(field));
403  if(sscanf(receiveMessage("MID SETTING", true).c_str(), "%lf", &x) != 1)
404  throw XInterface::XConvError(__FILE__, __LINE__);
405 }
406 void
407 XCryogenicSMS::setRate(double hpm) {
408  XScopedLock<XInterface> lock( *interface());
409  double amp_per_sec = hpm / 60.0 / teslaPerAmp();
410  interface()->sendf("SET RAMP %.5g", amp_per_sec);
411  double x;
412  if(sscanf(receiveMessage("RAMP RATE", true).c_str(), "%lf", &x) != 1)
413  throw XInterface::XConvError(__FILE__, __LINE__);
414 }
415 bool
416 XCryogenicSMS::isOutputPositive() {
417  XScopedLock<XInterface> lock( *interface());
418  interface()->send("GET OUTPUT");
419  char c;
420  if(sscanf(receiveMessage("OUTPUT").c_str(), "%c", &c) != 1)
421  throw XInterface::XConvError(__FILE__, __LINE__);
422  return (c != '-');
423 }
424 double
425 XCryogenicSMS::getTargetField() {
426  XScopedLock<XInterface> lock( *interface());
427  interface()->send("SET MID");
428  char unit[10];
429  double x;
430  if(sscanf(receiveMessage("MID SETTING").c_str(), "%lf %9s", &x, unit) != 2)
431  throw XInterface::XConvError(__FILE__, __LINE__);
432  if(strncmp(unit, "TESLA", 5))
433  x *= teslaPerAmp();
434  return x * (isOutputPositive() ? 1 : -1);
435 }
436 double
437 XCryogenicSMS::getSweepRate() {
438  XScopedLock<XInterface> lock( *interface());
439  double x;
440  interface()->send("SET RATE");
441  if(sscanf(receiveMessage("RAMP RATE").c_str(), "%lf", &x) != 1) //[A/s]
442  throw XInterface::XConvError(__FILE__, __LINE__);
443  return x * teslaPerAmp() * 60.0;
444 }
445 double
446 XCryogenicSMS::getOutputField() {
447  XScopedLock<XInterface> lock( *interface());
448  interface()->send("GET OUTPUT");
449  char unit[10];
450  double x;
451  if(sscanf(receiveMessage("OUTPUT").c_str(), "%lf %9s", &x, unit) != 2)
452  throw XInterface::XConvError(__FILE__, __LINE__);
453  if(strncmp(unit, "TESLA", 5))
454  x *= teslaPerAmp();
455  return x;
456 }
457 double
458 XCryogenicSMS::getPersistentField() {
459  XScopedLock<XInterface> lock( *interface());
460  interface()->send("HEATER");
461  std::string buf = receiveMessage("HEATER STATUS");
462  if( !strncmp("ON", buf.c_str(), 2))
463  throw XInterface::XInterfaceError(i18n("Trying to read persistent current while PCSH is on."), __FILE__, __LINE__);
464  if( !strncmp("OFF", buf.c_str(), 3))
465  return 0.0;
466  char unit[10];
467  double x;
468  if(sscanf(buf.c_str(), "SWITCHED OFF AT %lf %9s", &x, unit) != 2)
469  throw XInterface::XConvError(__FILE__, __LINE__);
470  if(strncmp(unit, "TESLA", 5))
471  x *= teslaPerAmp();
472  return x;
473 }
474 double
475 XCryogenicSMS::getOutputVolt() {
476  XScopedLock<XInterface> lock( *interface());
477  interface()->send("GET OUTPUT");
478  double x;
479  if(sscanf(receiveMessage("OUTPUT").c_str(), "%*s %*s AT %lf", &x) != 1)
480  throw XInterface::XConvError(__FILE__, __LINE__);
481  return x;
482 }
483 double
484 XCryogenicSMS::getOutputCurrent() {
485  XScopedLock<XInterface> lock( *interface());
486  double x = getOutputField();
487 
488  return x / teslaPerAmp();
489 }
490 double
491 XCryogenicSMS::fieldResolution() {
492  return std::min(0.01, 0.15 * teslaPerAmp());
493 }
494 //! Persistent Current Switch Heater
495 bool
497  XScopedLock<XInterface> lock( *interface());
498  interface()->send("HEATER");
499  char buf[10];
500  if(sscanf(receiveMessage("HEATER STATUS").c_str(), "%5s", buf) != 1)
501  throw XInterface::XConvError(__FILE__, __LINE__);
502  if( !strncmp("ON", buf, 2))
503  return true;
504  return false;
505 }
506 //! please return false if no PCS fitted
507 bool
509  XScopedLock<XInterface> lock( *interface());
510  interface()->send("SET HEATER"); //queries heater power setting by Volts.
511  double x;
512  if(sscanf(receiveMessage("HEATER OUTPUT").c_str(), "%lf", &x) != 1)
513  throw XInterface::XConvError(__FILE__, __LINE__);
514  return (x > 0.01);
515 }

Generated for KAME4 by  doxygen 1.8.3