- added is_running to driveable ease objects - ighdriv.c: try <maxtry> times when status reply failes - ipsdriv.c: fix trainedTo parameter - reduced SEA version of SICS
1008 lines
26 KiB
C
1008 lines
26 KiB
C
/*---------------------------------------------------------------------------
|
|
ighdriv.c
|
|
|
|
Driver for the Oxford Instruments IGH Intelligent gas handling system
|
|
(based on ease).
|
|
|
|
Markus Zolliker, May 2005
|
|
----------------------------------------------------------------------------*/
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <sys/time.h>
|
|
#include <math.h>
|
|
#include <tcl.h>
|
|
#include <fortify.h>
|
|
#include <sics.h>
|
|
#include <splitter.h>
|
|
#include <obpar.h>
|
|
#include <devexec.h>
|
|
#include <nserver.h>
|
|
#include <interrupt.h>
|
|
#include <emon.h>
|
|
#include <evcontroller.h>
|
|
#include <evcontroller.i>
|
|
#include <sicsvar.h>
|
|
#include <evdriver.i>
|
|
#include <rs232controller.h>
|
|
#include "oxinst.h"
|
|
#include "fsm.h"
|
|
#include "initializer.h"
|
|
#include "syncedprot.h"
|
|
|
|
#define OLDIGH -8
|
|
#define SORBS_FLAG 1
|
|
#define MIXP_FLAG 2
|
|
#define MAXP_FLAG 3
|
|
#define STILL_FLAG 4
|
|
#define SORBP_FLAG 5
|
|
#define MOT_FLAGS 6
|
|
#define VALVE_FLAGS 9
|
|
#define MAX_FLAG 32
|
|
|
|
static char *valves[] =
|
|
{ "V9", "V8", "V7", "V11A", "V13A", "V13B", "V11B", "V12B",
|
|
"He4", "V1", "V5", "V4", "V3", "V14", "V10", "V2",
|
|
"V2A", "V1A", "V5A", "V4A", "V3A", "Roots", "Aux", "He3",
|
|
NULL
|
|
}; /* valves beginning with blank are not shown in list */
|
|
typedef enum { V9, V8, V7, V11A, V13A, V13B, V11B, V12B,
|
|
HE4, V1, V5, V4, V3, V14, V10, V2,
|
|
V2A, V1A, V5A, V4A, V3A, ROOTS, AUX, HE3, n_VALVES
|
|
} Valves;
|
|
|
|
static char *motorValves[] = { "V6", "V12A", "V1K", NULL };
|
|
typedef enum { V6, V12A, V1K, n_MOTOR } MotorValves;
|
|
static char *motorCommands[] = { "G", "H", "N" };
|
|
|
|
static char *gauges[] = { "G1", "G2", "G3", "", "", "", "P1", "P2", NULL };
|
|
typedef enum { G1, G2, G3, G4, G5, G6, P1, P2, n_PRESS } PressureGauges;
|
|
|
|
typedef struct {
|
|
EaseDriv d;
|
|
float setT;
|
|
float sorbS;
|
|
float mixT;
|
|
float onekT;
|
|
float sorbT;
|
|
float mixP;
|
|
float stillP;
|
|
float sorbP;
|
|
float press[n_PRESS];
|
|
float mv[n_MOTOR];
|
|
float v6pos;
|
|
time_t v6time;
|
|
int pdig;
|
|
int v[n_VALVES];
|
|
int e; /* heater range */
|
|
int a; /* actual heater mode */
|
|
int o; /* actual still/sorb mode */
|
|
int s; /* moving valve state */
|
|
int remote;
|
|
long hrSync;
|
|
float closedelay; /* if > 0: next valve command is a pulsed opening */
|
|
int closevalve; /* number of valve to be closed */
|
|
double opentime; /* time when valve was opened */
|
|
/* extensions (ext_watchdog Arduino) */
|
|
int extVersion; /* 0 for no extension, else extension version */
|
|
int pumpoff; /* pump signal after overpressure switch */
|
|
float upperN2; /* LN2 trap sensor */
|
|
float lowerN2;
|
|
char lastans[64];
|
|
int badcnt;
|
|
int maxtry;
|
|
int pumpoffcnt;
|
|
} Igh;
|
|
|
|
static ParClass ighClass = { "IGH", sizeof(Igh) };
|
|
|
|
static long IghSet(long pc, void *object);
|
|
/*----------------------------------------------------------------------------*/
|
|
static int IghPower2Range(float p)
|
|
{
|
|
int e;
|
|
if (p <= 0)
|
|
return 0;
|
|
for (e = 1; e < 5; e++) {
|
|
if (p < 1.9994e-3)
|
|
break;
|
|
p /= 10;
|
|
}
|
|
return e;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static float IghRange2Max(int e)
|
|
{
|
|
static float elist[] = { 0, 0.002, 0.02, 0.2, 2.0, 20.0 };
|
|
if (e < 0) {
|
|
e = 0;
|
|
} else if (e > 5) {
|
|
e = 5;
|
|
}
|
|
return elist[e];
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static void IghParDef(void *object)
|
|
{
|
|
Igh *drv = ParCast(&ighClass, object);
|
|
EaseBase *eab = object;
|
|
int i, flag, l, changed;
|
|
char *vPos, *val;
|
|
char fmt[8], vList[80];
|
|
static char *na = NULL;
|
|
float maxP;
|
|
static char *heaterList[] =
|
|
{ "off", "2uW", "20uW", "200uW", "2mW", "20mW", NULL };
|
|
static char *closedOrOpen[] = { "closed", "open", NULL };
|
|
|
|
ParName("");
|
|
ParTail("K");
|
|
ParFmt("%.4f");
|
|
ParFloat(&drv->mixT, PAR_NAN);
|
|
|
|
ParName("Tset");
|
|
ParTail("K");
|
|
ParFmt("%.4f");
|
|
if (eab->syntax == OLDIGH) {
|
|
ParList("all");
|
|
drv->setT = -1;
|
|
ParFloat(&drv->setT, -1);
|
|
} else {
|
|
if (drv->setT < 0)
|
|
drv->setT = 0;
|
|
ParFloat(&drv->setT, PAR_NAN);
|
|
}
|
|
|
|
ParName("TsorbSet");
|
|
EaseUpdate(SORBS_FLAG);
|
|
ParTail("K");
|
|
ParFmt("%.1f");
|
|
ParFloat(&drv->sorbS, PAR_NAN);
|
|
|
|
ParName("Tmix");
|
|
ParTail("K");
|
|
ParFmt("%.4f");
|
|
ParFloat(&drv->mixT, PAR_NAN);
|
|
|
|
ParName("T1K");
|
|
ParTail("K");
|
|
ParFmt("%.4f");
|
|
ParFloat(&drv->onekT, PAR_NAN);
|
|
|
|
ParName("Tsorb");
|
|
ParTail("K");
|
|
ParFmt("%.1f");
|
|
ParFloat(&drv->sorbT, PAR_NAN);
|
|
|
|
ParName("Pmix");
|
|
EaseUpdate(MIXP_FLAG);
|
|
ParTail("mW");
|
|
ParFmt("%.5g");
|
|
ParFloat(&drv->mixP, PAR_NAN);
|
|
|
|
ParName("Pmax");
|
|
ParTail("mW");
|
|
ParFmt("%.5g");
|
|
maxP = IghRange2Max(drv->e);
|
|
ParFloat(&maxP, PAR_NAN);
|
|
|
|
ParName("HtrRange");
|
|
EaseUpdate(MAXP_FLAG);
|
|
ParEnum(heaterList);
|
|
ParList(NULL);
|
|
ParInt(&drv->e, PAR_NAN);
|
|
if (ParActionIs(PAR_SET) > 0) {
|
|
drv->mixP = 0;
|
|
if (drv->hrSync == 0) {
|
|
drv->hrSync=SyncedIncr(0);
|
|
}
|
|
}
|
|
|
|
ParName("Pstill");
|
|
EaseUpdate(STILL_FLAG);
|
|
ParTail("mW");
|
|
ParFmt("%.3f");
|
|
ParFloat(&drv->stillP, PAR_NAN);
|
|
|
|
ParName("Psorb");
|
|
EaseUpdate(SORBP_FLAG);
|
|
ParTail("W");
|
|
ParFmt("%.3f");
|
|
ParFloat(&drv->sorbP, PAR_NAN);
|
|
|
|
for (i = 0; i < n_PRESS; i++) {
|
|
if (gauges[i][0] != '\0') {
|
|
ParName(gauges[i]);
|
|
ParTail("mbar");
|
|
if (i == P1) {
|
|
snprintf(fmt, sizeof fmt, "%%.%df", drv->pdig);
|
|
ParFmt(fmt);
|
|
} else if (i == P2) {
|
|
ParFmt("%.3f");
|
|
ParList("all");
|
|
} else if (i == G3) {
|
|
ParFmt("%.1f");
|
|
ParList("all");
|
|
} else {
|
|
ParFmt("%.1f");
|
|
}
|
|
ParFloat(&drv->press[i], PAR_NAN);
|
|
}
|
|
}
|
|
|
|
flag = MOT_FLAGS;
|
|
for (i = 0; i < n_MOTOR; i++) {
|
|
ParName(motorValves[i]);
|
|
ParFmt("%.1f");
|
|
ParTail("%");
|
|
if (i == V1K)
|
|
ParList("all");
|
|
EaseUpdate(flag);
|
|
flag++;
|
|
ParFloat(&drv->mv[i], PAR_NAN);
|
|
}
|
|
|
|
ParName("v6pos");
|
|
ParFmt("%.1f");
|
|
ParTail("%");
|
|
ParFloat(&drv->v6pos, PAR_NAN);
|
|
|
|
assert(flag == VALVE_FLAGS);
|
|
l = 0;
|
|
for (i = 0; i < n_VALVES; i++) {
|
|
if (valves[i][0] == ' ') {
|
|
ParName(valves[i] + 1);
|
|
changed = 0;
|
|
} else {
|
|
ParName(valves[i]);
|
|
changed = EaseUpdate(flag);
|
|
}
|
|
ParEnum(closedOrOpen);
|
|
ParInt(&drv->v[i], PAR_LNAN);
|
|
if (changed) {
|
|
if (drv->v[i] != 1)
|
|
drv->v[i] = 0; /* allow only 1 or 0 */
|
|
}
|
|
flag++;
|
|
if (ParActionIs(PAR_LIST) && valves[i][0] != ' ') {
|
|
if (drv->v[i] == 1) {
|
|
vPos = vList + l;
|
|
l += strlen(valves[i]) + 1;
|
|
if (l < sizeof vList) {
|
|
strcpy(vPos, " ");
|
|
vPos++;
|
|
strcpy(vPos, valves[i]);
|
|
vList[l] = '\0';
|
|
} else {
|
|
l = vPos - vList;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
assert(MAX_FLAG == flag - 1);
|
|
if (ParActionIs(PAR_LIST)) {
|
|
vList[l] = '\0';
|
|
ParPrintf(NULL, eValue, "open valves:%s", vList);
|
|
}
|
|
|
|
ParName("closedelay");
|
|
ParAccess(usUser);
|
|
ParSave(1);
|
|
ParFloat(&drv->closedelay, 0);
|
|
|
|
ParName("extVersion");
|
|
ParAccess(usUser);
|
|
ParSave(1);
|
|
ParInt(&drv->extVersion, PAR_LNAN);
|
|
|
|
ParName("pumpoff");
|
|
if (drv->extVersion != 0) ParTail("");
|
|
ParInt(&drv->pumpoff, PAR_LNAN);
|
|
|
|
ParName("upperN2");
|
|
ParFmt("%.1f");
|
|
if (drv->extVersion != 0) ParTail("K");
|
|
ParFloat(&drv->upperN2, PAR_NAN);
|
|
|
|
ParName("lowerN2");
|
|
ParFmt("%.1f");
|
|
if (drv->extVersion != 0) ParTail("K");
|
|
ParFloat(&drv->lowerN2, PAR_NAN);
|
|
|
|
ParName("maxtry");
|
|
ParAccess(usUser);
|
|
ParSave(1);
|
|
ParInt(&drv->maxtry, 0);
|
|
|
|
EaseBasePar(drv);
|
|
EaseSendPar(drv);
|
|
if (eab->syntax != OLDIGH) {
|
|
EaseDrivPar(drv, "%.5g", "K");
|
|
}
|
|
ParStdDef();
|
|
EaseMsgPar(eab);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
int IghStatus(Igh * drv)
|
|
{
|
|
char *ans;
|
|
int *code;
|
|
long mask, p;
|
|
int i;
|
|
|
|
if (drv->d.b.state != EASE_read)
|
|
return 1;
|
|
|
|
if (drv->opentime > 0 &&
|
|
DoubleTime() > drv->opentime + (double)drv->closedelay - 1) {
|
|
/* force a call to IghSet */
|
|
drv->d.b.todo = drv->d.b.doit;
|
|
}
|
|
|
|
code = &drv->d.b.errCode;
|
|
ans = drv->d.b.ans;
|
|
if (drv->maxtry > 0 && strcmp(ans, drv->lastans) != 0) {
|
|
strlcpy(drv->lastans, ans, sizeof(drv->lastans));
|
|
drv->badcnt++;
|
|
if (drv->badcnt >= drv->maxtry) {
|
|
drv->badcnt = 0;
|
|
ParPrintf(drv, eError, "inconsistent status response: %s", ans);
|
|
*code = EASE_FAULT;
|
|
return 1;
|
|
}
|
|
return 0; /* try again */
|
|
}
|
|
strlcpy(drv->lastans, ans, sizeof(drv->lastans));
|
|
if (ans[0] != 'X' ||
|
|
ans[2] != 'A' ||
|
|
ans[4] != 'C' ||
|
|
ans[6] != 'P' ||
|
|
ans[15] != 'S' || ans[17] != 'O' || ans[19] != 'E') {
|
|
drv->badcnt++;
|
|
if (drv->badcnt < drv->maxtry) {
|
|
return 0; /* try again */
|
|
}
|
|
ParPrintf(drv, eError, "illegal status response (dil maxtry 10 might help): %s", ans);
|
|
*code = EASE_FAULT;
|
|
return 1;
|
|
}
|
|
if (sscanf(ans + 7, "%lx", &mask) <= 0) {
|
|
drv->badcnt++;
|
|
if (drv->badcnt < drv->maxtry) {
|
|
return 0; /* try again */
|
|
}
|
|
ParPrintf(drv, eError, "illegal valve status response");
|
|
*code = EASE_FAULT;
|
|
return 1;
|
|
}
|
|
if (drv->badcnt > drv->maxtry / 2) {
|
|
ParPrintf(drv, eError, "needed %d retries for getting dil status", drv->badcnt);
|
|
}
|
|
drv->badcnt = 0;
|
|
p = 1;
|
|
for (i = 0; i < n_VALVES; i++) {
|
|
if (!EaseGetUpdate(drv, VALVE_FLAGS + i)) {
|
|
if (mask & p) {
|
|
drv->v[i] = 1;
|
|
} else {
|
|
drv->v[i] = 0;
|
|
}
|
|
}
|
|
p *= 2;
|
|
}
|
|
drv->a = ans[3] - '0';
|
|
drv->s = ans[16] - '0';
|
|
drv->o = ans[18] - '0';
|
|
if (EaseGetUpdate(drv, MAXP_FLAG) == 0) {
|
|
if (drv->a == 0) {
|
|
drv->e = 0;
|
|
} else {
|
|
drv->e = ans[20] - '0';
|
|
}
|
|
}
|
|
/*
|
|
if (ans[5] != '3' && drv->remote == 2) {
|
|
ParPrintf(drv, eError, "IGH switched to local");
|
|
*code = EASE_FAULT;
|
|
drv->remote = 1;
|
|
return 1;
|
|
}
|
|
*/
|
|
return 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static long IghRead(long pc, void *object)
|
|
{
|
|
Igh *drv = ParCast(&ighClass, object);
|
|
EaseBase *eab = object;
|
|
char *p;
|
|
int l;
|
|
int switched_off;
|
|
time_t now;
|
|
float delta;
|
|
int up10, lo10;
|
|
|
|
if (eab->state == EASE_abort) {
|
|
eab->state = EASE_idle;
|
|
FsmRestartTask(eab->task, eab->idle);
|
|
return 0;
|
|
}
|
|
switch (pc) {
|
|
default: /* FSM BEGIN ****************************** */
|
|
EasePchk(drv);
|
|
redo1:
|
|
EaseWrite(eab, "X");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
if (!IghStatus(drv)) goto redo1;
|
|
if (!drv->remote)
|
|
goto skiprmt;
|
|
EaseWrite(eab, "C0");
|
|
drv->remote = 0;
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
skiprmt:
|
|
|
|
if (!EaseNextFullRead(eab))
|
|
goto fsm_quit;
|
|
|
|
if (EaseCheckDoit(eab))
|
|
goto quit;
|
|
|
|
if (EaseGetUpdate(drv, SORBS_FLAG))
|
|
goto skip0;
|
|
if (drv->o / 2 != 1) {
|
|
drv->sorbS = 0;
|
|
goto skip0;
|
|
}
|
|
EaseWrite(eab, "R0");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
if (EaseGetUpdate(drv, SORBS_FLAG))
|
|
goto skip0;
|
|
drv->sorbS = OxiGet(eab, 1, NULL, drv->sorbS);
|
|
skip0:
|
|
|
|
if (EaseCheckDoit(eab))
|
|
goto quit;
|
|
|
|
if (eab->syntax == OLDIGH) {
|
|
EaseWrite(eab, "R3");
|
|
} else {
|
|
EaseWrite(eab, "R32");
|
|
}
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
if (eab->syntax == OLDIGH) {
|
|
drv->mixT = OxiGet(eab, 3, NULL, drv->mixT);
|
|
} else {
|
|
drv->mixT = OxiGet(eab, 4, NULL, drv->mixT);
|
|
if (drv->mixT < 0)
|
|
drv->mixT += 6.5536; /* correct a bug in firmware < 3.03 */
|
|
}
|
|
if (EaseCheckDoit(eab))
|
|
goto quit;
|
|
|
|
if (eab->syntax == OLDIGH)
|
|
goto noSetTemp;
|
|
EaseWrite(eab, "R33");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
drv->setT = OxiGet(eab, 4, NULL, drv->setT);
|
|
|
|
noSetTemp:
|
|
EaseWrite(eab, "R1");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
drv->sorbT = OxiGet(eab, 1, NULL, drv->sorbT);
|
|
|
|
if (EaseCheckDoit(eab))
|
|
goto quit;
|
|
|
|
EaseWrite(eab, "R2");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
drv->onekT = OxiGet(eab, 3, NULL, drv->onekT);
|
|
|
|
if (EaseCheckDoit(eab))
|
|
goto quit;
|
|
|
|
if (drv->e == 0) {
|
|
drv->mixP = 0;
|
|
goto skip4;
|
|
}
|
|
if (EaseGetUpdate(drv, MIXP_FLAG) || EaseGetUpdate(drv, MAXP_FLAG))
|
|
goto skip4;
|
|
EaseWrite(eab, "R4");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
if (EaseGetUpdate(drv, MIXP_FLAG) || EaseGetUpdate(drv, MAXP_FLAG))
|
|
goto skip4;
|
|
drv->mixP = OxiGet(eab, 5 - drv->e, NULL, drv->mixP * 100) * 0.01;
|
|
skip4:
|
|
|
|
if (EaseCheckDoit(eab))
|
|
goto quit;
|
|
|
|
if (EaseGetUpdate(drv, STILL_FLAG))
|
|
goto skip5;
|
|
EaseWrite(eab, "R5");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
if (EaseGetUpdate(drv, STILL_FLAG))
|
|
goto skip5;
|
|
drv->stillP = OxiGet(eab, 1, NULL, drv->stillP);
|
|
skip5:
|
|
|
|
if (EaseCheckDoit(eab))
|
|
goto quit;
|
|
|
|
if (EaseGetUpdate(drv, SORBP_FLAG))
|
|
goto skip6;
|
|
EaseWrite(eab, "R6");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
if (EaseGetUpdate(drv, SORBP_FLAG))
|
|
goto skip6;
|
|
drv->sorbP = OxiGet(eab, 3, NULL, drv->sorbP);
|
|
skip6:
|
|
|
|
if (EaseCheckDoit(eab))
|
|
goto quit;
|
|
|
|
if (EaseGetUpdate(drv, MOT_FLAGS + V6))
|
|
goto skip7;
|
|
EaseWrite(eab, "R7");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
if (EaseGetUpdate(drv, MOT_FLAGS + V6))
|
|
goto skip7;
|
|
drv->mv[V6] = OxiGet(eab, 1, NULL, drv->mv[V6]);
|
|
time(&now);
|
|
delta = (now - drv->v6time) / 2.64; /* speed: 1/2.64 %/sec */
|
|
drv->v6time = now;
|
|
if (drv->v6pos > drv->mv[V6] + delta) {
|
|
if (drv->v6pos > 99.9) {
|
|
drv->v6pos = 99.9;
|
|
}
|
|
drv->v6pos -= delta;
|
|
} else if (drv->v6pos < drv->mv[V6] - delta) {
|
|
if (drv->v6pos < 0) {
|
|
drv->v6pos = 0;
|
|
}
|
|
drv->v6pos += delta;
|
|
} else {
|
|
drv->v6pos = drv->mv[V6];
|
|
}
|
|
skip7:
|
|
|
|
if (EaseCheckDoit(eab))
|
|
goto quit;
|
|
|
|
if (EaseGetUpdate(drv, MOT_FLAGS + V12A))
|
|
goto skip8;
|
|
EaseWrite(eab, "R8");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
if (EaseGetUpdate(drv, MOT_FLAGS + V12A))
|
|
goto skip8;
|
|
drv->mv[V12A] = OxiGet(eab, 1, NULL, drv->mv[V12A]);
|
|
skip8:
|
|
|
|
if (EaseCheckDoit(eab))
|
|
goto quit;
|
|
|
|
if (EaseGetUpdate(drv, MOT_FLAGS + V1K))
|
|
goto skip9;
|
|
EaseWrite(eab, "R9");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
if (EaseGetUpdate(drv, MOT_FLAGS + V1K))
|
|
goto skip9;
|
|
drv->mv[V1K] = OxiGet(eab, 1, NULL, drv->mv[V1K]);
|
|
skip9:
|
|
|
|
if (EaseCheckDoit(eab))
|
|
goto quit;
|
|
|
|
EaseWrite(eab, "R14");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
drv->press[G1] = OxiGet(eab, 1, NULL, drv->press[G1]);
|
|
|
|
if (EaseCheckDoit(eab))
|
|
goto quit;
|
|
|
|
EaseWrite(eab, "R15");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
drv->press[G2] = OxiGet(eab, 1, NULL, drv->press[G2]);
|
|
|
|
if (EaseCheckDoit(eab))
|
|
goto quit;
|
|
|
|
EaseWrite(eab, "R16");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
drv->press[G3] = OxiGet(eab, 1, NULL, drv->press[G3]);
|
|
|
|
if (EaseCheckDoit(eab))
|
|
goto quit;
|
|
|
|
EaseWrite(eab, "R20");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
drv->press[P1] = OxiGet(eab, drv->pdig, &drv->pdig, drv->press[P1]);
|
|
|
|
if (EaseCheckDoit(eab))
|
|
goto quit;
|
|
|
|
EaseWrite(eab, "R21");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
drv->press[P2] = OxiGet(eab, 1, NULL, drv->press[P2]);
|
|
|
|
if (EaseCheckDoit(eab) || drv->extVersion == 0)
|
|
goto quit;
|
|
|
|
drv->pumpoffcnt = 0;
|
|
redo2:
|
|
EaseWrite(eab, "{r}");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
/* analyze */
|
|
if (3 == sscanf(drv->d.b.ans, "?{%d,%d,%d}",
|
|
&l, &up10, &lo10)) {
|
|
switched_off = (drv->v[HE3] == 1 && l == 1);
|
|
drv->pumpoff = l;
|
|
drv->upperN2 = 0.1 * up10;
|
|
drv->lowerN2 = 0.1 * lo10;
|
|
} else {
|
|
drv->pumpoff = PAR_LNAN;
|
|
drv->upperN2 = PAR_NAN;
|
|
drv->lowerN2 = PAR_NAN;
|
|
}
|
|
if (!switched_off) goto quit;
|
|
if (drv->extVersion == 2) {
|
|
ParPrintf(eab, eLogError,
|
|
"ERROR: overpressure after 3He pump (IGNORED!)");
|
|
goto quit;
|
|
}
|
|
/* verify pump control */
|
|
EaseWrite(eab, "X");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
if (!IghStatus(drv)) goto redo2;
|
|
drv->pumpoffcnt++;
|
|
if (drv->pumpoffcnt < 3) goto redo2;
|
|
if (drv->v[HE3] == 0) goto quit; /* switched off intentionally */
|
|
/* overpressure switch activated: we switch pump control off */
|
|
EaseWrite(eab, "C3");
|
|
drv->remote = 2;
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
EaseWrite(eab, "P49");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
EaseWrite(eab, "C0");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
drv->remote = 0;
|
|
ParPrintf(eab, eLogError,
|
|
"ERROR: overpressure after 3He pump (switched off)");
|
|
eab->errCode = EASE_FAULT;
|
|
|
|
quit:
|
|
ParLog(drv);
|
|
fsm_quit:return 0;
|
|
} /* FSM END ********************************* */
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static long IghStart(long pc, void *object)
|
|
{
|
|
Igh *drv = ParCast(&ighClass, object);
|
|
EaseBase *eab = object;
|
|
char msg[128];
|
|
|
|
switch (pc) {
|
|
default: /* FSM BEGIN ****************************** */
|
|
EasePchk(drv);
|
|
EaseWrite(eab, "V");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
if (0 != strncmp(eab->version, "IGH", 3)) {
|
|
snprintf(msg, sizeof msg,
|
|
"unknown gas handling system version: %s", eab->version);
|
|
EaseStop(eab, msg);
|
|
goto quit;
|
|
}
|
|
if (strstr(eab->version, "2.01") != NULL) {
|
|
eab->syntax = OLDIGH; /* includes communication error correction */
|
|
} else {
|
|
eab->syntax = 0;
|
|
}
|
|
ParPrintf(drv, eLog, "connected to %s", eab->version);
|
|
FsmCall(IghRead);
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
|
|
quit:
|
|
return 0;
|
|
} /* FSM END ******************************************* */
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static long IghSet(long pc, void *object)
|
|
{
|
|
Igh *drv = ParCast(&ighClass, object);
|
|
EaseBase *eab = object;
|
|
char buf[8];
|
|
int a;
|
|
int upd;
|
|
int i;
|
|
float mp;
|
|
double now, deadline;
|
|
|
|
switch (pc) {
|
|
default: /* FSM BEGIN ****************************** */
|
|
EasePchk(drv);
|
|
EaseWrite(eab, "C3");
|
|
drv->remote = 2;
|
|
loop:
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
if (drv->opentime > 0) {
|
|
now = DoubleTime();
|
|
deadline = drv->opentime + (double)drv->closedelay;
|
|
if (now > deadline) goto close_valve;
|
|
if (now > deadline - 1) goto loop;
|
|
}
|
|
upd = EaseNextUpdate(drv);
|
|
if (upd >= VALVE_FLAGS)
|
|
goto set_valve;
|
|
if (upd >= MOT_FLAGS)
|
|
goto set_mot;
|
|
if (upd == EASE_RUN)
|
|
goto set_temp;
|
|
if (upd == SORBS_FLAG)
|
|
goto set_sorb_temp;
|
|
if (upd == MIXP_FLAG)
|
|
goto set_mix_pow;
|
|
if (upd == MAXP_FLAG)
|
|
goto set_max_pow;
|
|
if (upd == STILL_FLAG)
|
|
goto set_still_pow;
|
|
if (upd == SORBP_FLAG)
|
|
goto set_sorb_pow;
|
|
goto finish;
|
|
|
|
set_sorb_temp:
|
|
if (drv->sorbS == 0) {
|
|
drv->sorbP = 0;
|
|
goto set_sorb_pow;
|
|
}
|
|
OxiSet(eab, "K", drv->sorbS, 1);
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
redo1:
|
|
EaseWrite(eab, "X");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
if (!IghStatus(drv)) goto redo1;
|
|
if (drv->o == 2 || drv->o == 3)
|
|
goto loop;
|
|
if (drv->o % 2) {
|
|
EaseWrite(eab, "O3");
|
|
} else {
|
|
EaseWrite(eab, "O2");
|
|
}
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
goto loop;
|
|
|
|
set_sorb_pow:
|
|
redo2:
|
|
EaseWrite(eab, "X");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
if (!IghStatus(drv)) goto redo2;
|
|
if (drv->o <= 1)
|
|
goto skipSetO;
|
|
if (drv->o % 2) {
|
|
EaseWrite(eab, "O1");
|
|
drv->o = 1;
|
|
} else {
|
|
EaseWrite(eab, "O0");
|
|
drv->o = 0;
|
|
}
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
skipSetO:
|
|
OxiSet(eab, "B", drv->sorbP, 3);
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
if (drv->sorbP == 0.0 || drv->o >= 4)
|
|
goto loop;
|
|
if (drv->o % 2) {
|
|
EaseWrite(eab, "O5");
|
|
} else {
|
|
EaseWrite(eab, "O4");
|
|
}
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
goto loop;
|
|
|
|
set_still_pow:
|
|
OxiSet(eab, "S", drv->stillP, 1);
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
redo3:
|
|
EaseWrite(eab, "X");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
if (!IghStatus(drv)) goto redo3;
|
|
snprintf(buf, sizeof buf, "O%d", drv->o | 1);
|
|
EaseWrite(eab, buf);
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
goto loop;
|
|
|
|
set_mix_pow:
|
|
EaseWrite(eab, "A0");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
if (drv->e <= 1)
|
|
goto skipe;
|
|
EaseWrite(eab, "E1");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
|
|
skipe:
|
|
if (drv->mixP > 0) {
|
|
drv->e = IghPower2Range(drv->mixP);
|
|
mp = drv->mixP / IghRange2Max(drv->e) * 2000;
|
|
if (mp < 2001 && mp > 1999) {
|
|
mp = 1999;
|
|
}
|
|
} else {
|
|
mp = 0; /* range unchanged for external heater signal */
|
|
}
|
|
OxiSet(eab, "M", mp, 0);
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
if (drv->e == 0)
|
|
goto seta0;
|
|
snprintf(buf, sizeof buf, "E%d", drv->e);
|
|
EaseWrite(eab, buf);
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
EaseWrite(eab, "A1");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
goto loop;
|
|
|
|
set_max_pow:
|
|
if (drv->e == 0)
|
|
goto seta0;
|
|
snprintf(buf, sizeof buf, "E%d", drv->e);
|
|
EaseWrite(eab, buf);
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
if (drv->hrSync > 0) {
|
|
SyncedDecr(drv->hrSync);
|
|
drv->hrSync = 0;
|
|
}
|
|
if (drv->a == 2) goto loop;
|
|
EaseWrite(eab, "A1");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
EaseWrite(eab, "M0");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
goto loop;
|
|
|
|
seta0:
|
|
EaseWrite(eab, "A0");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
goto loop;
|
|
|
|
set_temp:
|
|
EaseWrite(eab, "A2");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
if (drv->d.targetValue < 0)
|
|
drv->d.targetValue = 0;
|
|
if (drv->d.targetValue > 1.999)
|
|
drv->d.targetValue = 1.999;
|
|
drv->setT = drv->d.targetValue;
|
|
OxiSet(eab, "T", drv->d.targetValue, 4);
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
goto loop;
|
|
|
|
set_valve:
|
|
i = upd - VALVE_FLAGS;
|
|
if (drv->closedelay > 0) {
|
|
if (drv->v[i]) {
|
|
if (drv->opentime == 0) {
|
|
drv->opentime = DoubleTime();
|
|
drv->closevalve = i;
|
|
}
|
|
} else if (drv->closevalve == i) {
|
|
/* early close by command */
|
|
drv->opentime = 0;
|
|
drv->closedelay = 0;
|
|
}
|
|
}
|
|
snprintf(buf, sizeof buf, "P%d", i * 2 + 3 - drv->v[i]);
|
|
EaseWrite(eab, buf);
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
goto loop;
|
|
|
|
close_valve:
|
|
drv->opentime = 0;
|
|
drv->closedelay = 0;
|
|
drv->v[drv->closevalve] = 0;
|
|
snprintf(buf, sizeof buf, "P%d", drv->closevalve * 2 + 3); /* close cmd */
|
|
EaseWrite(eab, buf);
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
goto loop;
|
|
|
|
set_mot:
|
|
i = upd - MOT_FLAGS;
|
|
if (drv->mv[i] > 99.9) {
|
|
drv->mv[i] = 99.9;
|
|
} else if (drv->mv[i] < 0) {
|
|
drv->mv[i] = 0;
|
|
}
|
|
OxiSet(eab, motorCommands[i], drv->mv[i], 1);
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
goto loop;
|
|
|
|
finish:
|
|
EaseWrite(eab, "C0");
|
|
return __LINE__;
|
|
case __LINE__: /**********************************/
|
|
drv->remote = 0;
|
|
quit:
|
|
return 0;
|
|
} /* FSM END ******************************************* */
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
static int IghInit(SConnection * con, int argc, char *argv[], int dynamic)
|
|
{
|
|
/* args:
|
|
MakeObject objectname igh <rs232>
|
|
MakeObject objectname igh <host> <port>
|
|
*/
|
|
Igh *drv;
|
|
|
|
drv = EaseMakeDriv(con, &ighClass, argc, argv, dynamic, MAX_FLAG,
|
|
IghParDef, OxiHandler, IghStart, NULL, IghRead,
|
|
IghSet);
|
|
if (drv == NULL)
|
|
return 0;
|
|
drv->opentime = 0;
|
|
drv->badcnt = 0;
|
|
drv->pumpoffcnt = 0;
|
|
return 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
void IghStartup(void)
|
|
{
|
|
ParMakeClass(&ighClass, EaseDrivClass());
|
|
MakeDriver("IGH", IghInit, 0, "OI Gas Handling System");
|
|
}
|