new version of drivers (based on ease instead of eve)

This commit is contained in:
zolliker
2005-09-05 08:00:35 +00:00
parent 22fa164b76
commit 2cca4ba7f0
4 changed files with 1415 additions and 635 deletions

540
ighdriv.c Normal file
View File

@ -0,0 +1,540 @@
/*---------------------------------------------------------------------------
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 <servlog.h>
#include <sicsvar.h>
#include <evdriver.i>
#include <rs232controller.h>
#include "oxinst.h"
#include "fsm.h"
#include "initializer.h"
#define SORBS_FLAG 1
#define MIXP_FLAG 2
#define STILL_FLAG 3
#define SORBP_FLAG 4
#define MOT_FLAGS 5
#define VALVE_FLAGS 8
#define MAX_FLAG 31
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;
static char *closedOrOpen[]={"closed", "open", NULL};
typedef struct {
EaseDriv d;
float sorbS;
float mixT;
float onekT;
float sorbT;
float mixP;
float stillP;
float sorbP;
float press[n_PRESS];
float mv[n_MOTOR];
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;
} Igh;
static ParClass ighClass = { "IGH", sizeof(Igh) };
static long IghSet(long pc, void *object);
/*----------------------------------------------------------------------------*/
static void IghParDef(void *object) {
Igh *drv = ParCast(&ighClass, object);
EaseBase *eab = object;
int i, flag, l, changed;
char *vPos;
char fmt[8], vList[80];
ParName("TsorbSet");
EaseUpdate(SORBS_FLAG); ParTail("K"); ParFmt("%.1f");
ParFloat(&drv->sorbS, PAR_NAN);
ParName("Tmix");
ParTail("K"); ParFmt("%.3f");
ParFloat(&drv->mixT, PAR_NAN);
ParName("T1K");
ParTail("K"); ParFmt("%.3f");
ParFloat(&drv->onekT, PAR_NAN);
ParName("Tsorb");
ParTail("K"); ParFmt("%.1f");
ParFloat(&drv->sorbT, PAR_NAN);
ParName("Pmix");
if (drv->e < 1 || drv->e > 5) drv->e=1;
if (drv->e == 5) {
strcpy(fmt, "%.0f");
} else {
snprintf(fmt, sizeof fmt, "%%.%df", 4 - drv->e);
}
EaseUpdate(MIXP_FLAG); ParTail("uW"); ParFmt(fmt);
ParFloat(&drv->mixP, PAR_NAN);
ParName("Pstill");
EaseUpdate(STILL_FLAG); ParTail("mW"); ParFmt("%.3f");
ParFloat(&drv->stillP, PAR_NAN);
ParName("Psorb");
EaseUpdate(SORBP_FLAG); ParTail("W"); ParFmt("%.1f");
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]);
ParTail("%");
if (i == V1K) ParList("all");
ParFloat(&drv->mv[i], PAR_NAN);
EaseUpdate(flag); flag++;
}
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);
}
EaseBasePar(drv);
EaseSendPar(drv);
ParStdDef();
EaseMsgPar(eab);
}
/*----------------------------------------------------------------------------*/
void IghStatus(Igh *drv) {
char *ans;
int *code;
long mask, p;
int i;
if (drv->d.b.state != EASE_read) return;
ans=drv->d.b.ans;
code=&drv->d.b.errCode;
if (ans[0] != 'X' ||
ans[2] != 'A' ||
ans[4] != 'C' ||
ans[6] != 'P' ||
ans[15] != 'S' ||
ans[17] != 'O' ||
ans[19] != 'E') {
ParPrintf(drv, eError, "illegal status response");
*code = EASE_FAULT;
return;
}
if (sscanf(ans+7, "%lx", &mask) <= 0) {
ParPrintf(drv, eError, "illegal valve status response");
*code = EASE_FAULT;
return;
}
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=p*2;
}
}
drv->a = ans[3] - '0';
drv->s = ans[16] - '0';
drv->o = ans[18] - '0';
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;
}
}
/*----------------------------------------------------------------------------*/
static long IghRead(long pc, void *object) {
Igh *drv = ParCast(&ighClass, object);
EaseBase *eab = object;
char *p;
int l;
time_t thisPeriod;
switch (pc) { default: /* FSM BEGIN *******************************/
EaseWrite(eab, "X");
return __LINE__; case __LINE__: /**********************************/
IghStatus(drv);
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__: /**********************************/
drv->sorbS = OxiGet(eab, 1, NULL);
skip0:
if (EaseCheckDoit(eab)) goto quit;
EaseWrite(eab, "R1");
return __LINE__; case __LINE__: /**********************************/
drv->sorbT = OxiGet(eab, 1, NULL);
if (EaseCheckDoit(eab)) goto quit;
EaseWrite(eab, "R2");
return __LINE__; case __LINE__: /**********************************/
drv->onekT = OxiGet(eab, 3, NULL);
if (EaseCheckDoit(eab)) goto quit;
EaseWrite(eab, "R3");
return __LINE__; case __LINE__: /**********************************/
drv->mixT = OxiGet(eab, 3, NULL);
if (EaseCheckDoit(eab)) goto quit;
if (EaseGetUpdate(drv, MIXP_FLAG)) goto skip4;
EaseWrite(eab, "R4");
return __LINE__; case __LINE__: /**********************************/
drv->mixP = OxiGet(eab, 5 - drv->e, NULL) * 10;
skip4:
if (EaseCheckDoit(eab)) goto quit;
if (EaseGetUpdate(drv, STILL_FLAG)) goto skip5;
EaseWrite(eab, "R5");
return __LINE__; case __LINE__: /**********************************/
drv->stillP = OxiGet(eab, 1, NULL);
skip5:
if (EaseCheckDoit(eab)) goto quit;
if (EaseGetUpdate(drv, SORBP_FLAG)) goto skip6;
EaseWrite(eab, "R6");
return __LINE__; case __LINE__: /**********************************/
drv->sorbP = OxiGet(eab, 3, NULL);
skip6:
if (EaseCheckDoit(eab)) goto quit;
if (EaseGetUpdate(drv, MOT_FLAGS+V6)) goto skip7;
EaseWrite(eab, "R7");
return __LINE__; case __LINE__: /**********************************/
drv->mv[V6] = OxiGet(eab, 1, NULL);
skip7:
if (EaseCheckDoit(eab)) goto quit;
if (EaseGetUpdate(drv, MOT_FLAGS+V12A)) goto skip8;
EaseWrite(eab, "R8");
return __LINE__; case __LINE__: /**********************************/
drv->mv[V12A] = OxiGet(eab, 1, NULL);
skip8:
if (EaseCheckDoit(eab)) goto quit;
if (EaseGetUpdate(drv, MOT_FLAGS+V1K)) goto skip9;
EaseWrite(eab, "R9");
return __LINE__; case __LINE__: /**********************************/
drv->mv[V1K] = OxiGet(eab, 1, NULL);
skip9:
if (EaseCheckDoit(eab)) goto quit;
EaseWrite(eab, "R14");
return __LINE__; case __LINE__: /**********************************/
drv->press[G1] = OxiGet(eab, 1, NULL);
if (EaseCheckDoit(eab)) goto quit;
EaseWrite(eab, "R15");
return __LINE__; case __LINE__: /**********************************/
drv->press[G2] = OxiGet(eab, 1, NULL);
if (EaseCheckDoit(eab)) goto quit;
EaseWrite(eab, "R16");
return __LINE__; case __LINE__: /**********************************/
drv->press[G3] = OxiGet(eab, 1, NULL);
if (EaseCheckDoit(eab)) goto quit;
EaseWrite(eab, "R20");
return __LINE__; case __LINE__: /**********************************/
drv->press[P1] = OxiGet(eab, drv->pdig, &drv->pdig);
if (EaseCheckDoit(eab)) goto quit;
EaseWrite(eab, "R21");
return __LINE__; case __LINE__: /**********************************/
drv->press[P2] = OxiGet(eab, 1, NULL);
quit:
ParLog(drv);
fsm_quit: return 0; } /* FSM END **********************************/
}
/*----------------------------------------------------------------------------*/
static long IghStart(long pc, void *object) {
Igh *drv = ParCast(&ighClass, object);
EaseBase *eab = object;
switch (pc) { default: /* FSM BEGIN *******************************/
EaseWrite(eab, "V");
return __LINE__; case __LINE__: /**********************************/
if (0 != strncmp(eab->version, "IGH", 3)) {
snprintf(eab->msg, sizeof eab->msg, "unknown gas handling system version: %s", eab->version);
ParPrintf(drv, eError, "ERROR: %s", eab->msg);
EaseStop(eab);
goto quit;
}
ParPrintf(drv, eStatus, "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;
switch (pc) { default: /* FSM BEGIN *******************************/
EaseWrite(eab, "C3");
drv->remote=2;
loop:
return __LINE__; case __LINE__: /**********************************/
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 == 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__: /**********************************/
EaseWrite(eab, "X");
return __LINE__; case __LINE__: /**********************************/
IghStatus(drv);
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:
EaseWrite(eab, "X");
return __LINE__; case __LINE__: /**********************************/
IghStatus(drv);
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__: /**********************************/
EaseWrite(eab, "X");
return __LINE__; case __LINE__: /**********************************/
IghStatus(drv);
snprintf(buf, sizeof buf, "O%d", drv->o | 1);
EaseWrite(eab, buf);
return __LINE__; case __LINE__: /**********************************/
goto loop;
set_mix_pow:
EaseWrite(eab, "E1");
return __LINE__; case __LINE__: /**********************************/
if (drv->mixP > 0) {
mp = drv->mixP * 0.1;
for (i=2; i<6; i++) {
if (mp > 199) {
break;
}
mp = mp * 10;
}
if (mp > 1999) mp = 1999;
drv->e = 7-i;
} else {
mp = 0;
}
OxiSet(eab, "M", mp, 0);
return __LINE__; case __LINE__: /**********************************/
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_temp:
/* unknown yet */
goto loop;
return __LINE__; case __LINE__: /**********************************/
goto loop;
set_valve:
i = upd - VALVE_FLAGS;
snprintf(buf, sizeof buf, "P%d", i * 2 + 3 - drv->v[i]);
EaseWrite(eab, buf);
return __LINE__; case __LINE__: /**********************************/
goto loop;
set_mot:
i = upd - MOT_FLAGS;
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;
ParPrintf(drv, eValue, "OI Gas Handling System");
return 1;
}
/*----------------------------------------------------------------------------*/
void IghStartup(void) {
ParMakeClass(&ighClass, EaseDrivClass());
MakeDriver("IGH", IghInit, 0);
}

215
ilmdriv.c
View File

@ -2,10 +2,10 @@
ilmdriv.c ilmdriv.c
Driver for the Oxford Instruments ILM503/ILM4 temperature controller Driver for the Oxford Instruments ILM503/ILM4 temperature controller
and for the Oxford lambda controller Version 2 (based on ease).
Markus Zolliker, Sept 2004 Markus Zolliker, April 2005
----------------------------------------------------------------------------*/ ------------------------------------------------------------------------------*/
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -20,126 +20,169 @@ Markus Zolliker, Sept 2004
#include <nserver.h> #include <nserver.h>
#include <interrupt.h> #include <interrupt.h>
#include <emon.h> #include <emon.h>
#include <evcontroller.h>
#include <evcontroller.i>
#include <servlog.h> #include <servlog.h>
#include <sicsvar.h> #include <sicsvar.h>
#include <evdriver.i>
#include <rs232controller.h> #include <rs232controller.h>
#include "oicom.h" #include "oxinst.h"
#include "fsm.h" #include "fsm.h"
#include "initializer.h"
typedef enum { ALWAYSNEW, NEW, MEASURING, NOTYETREAD, OLD } ReadState;
typedef enum { UNUSED, N2, PULSED_HE, CONTINOUS_HE, CHANNEL_ERROR = 9 } Usage;
typedef struct { typedef struct {
Eve eve; EaseBase b;
float lev2, lev3; float lev[3];
int cod1, cod2, cod3; Usage usage[3];
} IlmDriv; ReadState readState[3];
} Ilm;
char *fmts[10]={"unused", "%.1f\t%% N2", "%.1f\t%% He","%.1f\t%% He","", static ParClass ilmClass = { "ILM", sizeof(Ilm) };
"","","","","error"};
char *tails[10]={"unused", "% N2", "% He","% He","","","","","","error"};
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
#define A EVE_ACTPAR static void IlmParDef(void *object) {
#define L EVE_LOGPAR Ilm *drv = ParCast(&ilmClass, object);
#define S EVE_EVE_SAVEPAR
void IlmPars(IlmDriv *me, EveParArg *arg) { ParName("");
EveFloatPar(arg, "chan2", &me->lev2, fmts[me->cod2], if (drv->usage[0]) {
usInternal, (me->cod2 > 0) * A + L); ParFmt("%.1f"); ParTail(tails[drv->usage[0]]);
EveFloatPar(arg, "chan3", &me->lev2, fmts[me->cod3], }
usInternal, (me->cod3 > 0) * A + L); if (drv->readState[0] == NEW) {
EveStdParEnd(arg, fmts[me->cod1], A+L); ParLogReady(PAR_NOW_READY);
}
ParFloat(&drv->lev[0], PAR_NAN);
ParName("lev2");
if (drv->usage[1]) {
ParFmt("%.1f"); ParTail(tails[drv->usage[1]]);
};
if (drv->readState[1] == NEW) ParLogReady(PAR_NOW_READY);
ParFloat(&drv->lev[1], PAR_NAN);
ParName("lev3");
if (drv->usage[2]) {
ParFmt("%.1f"); ParTail(tails[drv->usage[2]]);
}
if (drv->readState[2] == NEW) ParLogReady(PAR_NOW_READY);
ParFloat(&drv->lev[2], PAR_NAN);
EaseBasePar(drv);
EaseSendPar(drv);
ParStdDef();
EaseMsgPar(drv);
} }
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
void IlmStatus(IlmDriv *me) { static void IlmStatus(Ilm *drv) {
char *ans; char *ans;
int *code; int *code;
Eve *eve=&me->eve;
int i; int i;
int status;
if (eve->state != readState) return; if (drv->b.state != EASE_read) return;
ans=eve->ans; ans=drv->b.ans;
code=&eve->errCode; code=&drv->b.errCode;
if (ans[0] != 'X' || ans[4] != 'S' || ans[11] != 'R') { if (ans[0] != 'X' || ans[4] != 'S' || ans[11] != 'R') {
EvePrintf(eve, eError, "illegal status response"); ParPrintf(drv, eError, "illegal status response");
*code = EVE_FAULT; *code = EASE_FAULT;
return; return;
} }
for (i=1; i<3; i++) { for (i=0; i<3; i++) {
if (ans[i]<'0' || ans[i] > '9') ans[i]='9'; if (ans[i+1]<'0' || ans[i+1] > '9') {
ans[i+1]='9';
}
drv->usage[i] = ans[i+1] - '0';
if (drv->usage[i] == PULSED_HE) {
sscanf(ans+6+2*i, "%1x", &status);
if (status & 1) { /* measuring */
drv->readState[i] = MEASURING;
} else if (drv->readState[i] == MEASURING) { /* new value */
drv->readState[i] = NOTYETREAD;
}
} else {
drv->readState[i] = ALWAYSNEW;
}
} }
me->cod1 = ans[1]-'0';
me->cod2 = ans[2]-'0';
me->cod3 = ans[3]-'0';
return; return;
} }
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
static int IlmRead(long pc, IlmDriv *me) { static long IlmRead(long pc, void *object) {
Eve *eve=&me->eve; Ilm *drv = ParCast(&ilmClass, object);
EaseBase *eab = object;
int i;
FSM_BEGIN switch (pc) { default: /* FSM BEGIN *******************************/
EveWrite(eve, "X"); EaseWrite(eab, "X");
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
IlmStatus(me); /* check for errors */ IlmStatus(drv); /* check for errors */
EveWrite(eve, "R1"); /* read sensor 1 */ EaseWrite(eab, "R1"); /* read sensor 1 */
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
me->eve.value = OiGetFlt(eve, 1, NULL); if (drv->readState[0] != MEASURING) drv->lev[0] = OxiGet(eab, 1, NULL);
if (me->cod2 == 0) goto skip2; if (drv->readState[0] == NOTYETREAD) drv->readState[0] = NEW;
EveWrite(eve, "R2"); /* read sensor 1 */
FSM_NEXT if (drv->usage[1] == 0) goto skip2;
me->lev2 = OiGetFlt(eve, 1, NULL); EaseWrite(eab, "R2"); /* read sensor 2 */
return __LINE__; case __LINE__: /**********************************/
drv->lev[1] = OxiGet(eab, 1, NULL);
if (drv->readState[1] == NOTYETREAD) drv->readState[1] = NEW;
skip2: skip2:
if (me->cod3 == 0) goto skip3; if (drv->usage[2] == 0) goto skip3;
EveWrite(eve, "R3"); /* read sensor 1 */ EaseWrite(eab, "R3"); /* read sensor 3 */
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
me->lev3 = OiGetFlt(eve, 1, NULL); drv->lev[2] = OxiGet(eab, 1, NULL);
if (drv->readState[2] == NOTYETREAD) drv->readState[2] = NEW;
skip3: skip3:
FSM_END if (ParLog(drv) >= 0) { /* logging was done */
for (i=0; i<3; i++) {
if (drv->readState[i] == NEW) {
drv->readState[i] = OLD;
}
}
}
return 0; } /* FSM END ********************************************/
} }
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
static int IlmStart(long pc, IlmDriv *me) { static long IlmStart(long pc, void *object) {
Eve *eve=&me->eve; Ilm *drv = ParCast(&ilmClass, object);
EaseBase *eab = object;
FSM_BEGIN switch (pc) { default: /* FSM BEGIN *******************************/
EveWrite(eve, "V"); EaseWrite(eab, "V");
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
if (0 == strncmp(eve->version, "ILM", 3)) { if (0 != strncmp(eab->version, "ILM", 3)) {
me->eve.syntax = 0; snprintf(eab->msg, sizeof eab->msg, "unknown level meter version: %s", eab->version);
} else { ParPrintf(drv, eError, "ERROR: %s", eab->msg);
EvePrintf(eve, eError, "unknown level meter version: %s", eve->version); EaseStop(eab);
goto quit; goto quit;
} }
EvePrintf(eve, eStatus, "connected to %s", eve->version); ParPrintf(drv, eStatus, "connected to %s", eab->version);
FSM_CALL(IlmRead); eab->msg[0]='\0'; /* o.k. */
FsmCall(IlmRead);
return __LINE__; case __LINE__: /**********************************/
quit: quit:
FSM_END return 0; } /* FSM END ********************************************/
} }
/*------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
pEVControl IlmMakeEVC(SConnection *pCon, int argc, char *argv[]) { static int IlmInit(SConnection *con, int argc, char *argv[], int dynamic) {
/* args: /* args:
temperature ilm <rs232> MakeObject objectname ilm <rs232>
<host> <port> <host> <port>
*/ */
Eve *eve; Ilm *drv;
pEVControl evc;
IlmDriv *me = NULL;
evc = MakeEveEVC(argc, argv, calloc(1, sizeof *me), pCon); drv = EaseMakeBase(con, &ilmClass, argc, argv, dynamic, 0,
if (!evc) return NULL; IlmParDef, OxiHandler, IlmStart, NULL, IlmRead);
if (drv == NULL) return 0;
me = evc->pDriv->pPrivate; ParPrintf(drv, eValue, "OI Level Meter");
eve=&me->eve; return 1;
}
eve->run = NULL; /* no run possible */ /*----------------------------------------------------------------------------*/
eve->read = (FsmFunc)IlmRead; void IlmStartup(void) {
eve->pardef = (EveParDef)IlmPars; ParMakeClass(&ilmClass, EaseBaseClass());
eve->todo = (FsmFunc)IlmStart; MakeDriver("ILM", IlmInit, 0);
eve->task = FsmStartTask(me, (FsmHandler)OiHandler, (FsmFunc)EveIdle);
evc->pEnvir->IsInTolerance = EveAlwaysOk;
return evc;
} }

673
ipsdriv.c
View File

@ -1,9 +1,10 @@
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
ipsdriv.c ips2driv.c
Driver for the Oxford Instruments IPS/PS magnet power supply. Driver for the Oxford Instruments IPS/PS magnet power supply.
Version 2 (based on ease).
Markus Zolliker, Sept 2004 Markus Zolliker, May 2005
----------------------------------------------------------------------------*/ ----------------------------------------------------------------------------*/
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
@ -26,103 +27,185 @@ Markus Zolliker, Sept 2004
#include <sicsvar.h> #include <sicsvar.h>
#include <evdriver.i> #include <evdriver.i>
#include <rs232controller.h> #include <rs232controller.h>
#include "oicom.h" #include "oxinst.h"
#include "fsm.h" #include "fsm.h"
#include "initializer.h"
typedef struct { typedef struct {
Eve eve; EaseDriv d;
float current; /* current (in Tesla) */ float current; /* current (in Tesla) */
float persfield; /* persistent field from IPS (in Tesla) */ float persfield; /* persistent field from IPS (in Tesla) */
float lastfield; /* persistent field from last drive */ float lastfield; /* persistent field from last drive */
float confirmfield; /* field confirmed in 1st step */ float confirmfield; /* field confirmed in 1st step */
float ramp; /* actual ramp rate (Telsa/min) */ float ramp; /* actual ramp rate (Tesla/min) */
float maxlimit; /* hard field limit */
int persmode; /* 0: leave switch on, 1: go to persistant mode */ int persmode; /* 0: leave switch on, 1: go to persistant mode */
int perswitch; /* state of switch */ int perswitch; /* state of switch */
int remote; /* 0: local, 1: remote, do not check, 2: remote, check */ int remote; /* 0: local, 1: remote, do not check, 2: remote, check */
int heaterFault; int heaterFault;
char *fmt; /* fmt for field */
int force; /* force = 2: put heater switch even when stored field does not match */ int force; /* force = 2: put heater switch even when stored field does not match */
time_t swtim; /* time when last switching the heater */ time_t swtim; /* time when last switching the heater */
time_t tim; time_t tim;
} IpsDriv; } Ips;
static ParClass ipsClass = { "IPS", sizeof(Ips) };
static char *onOff[] = { "off", "on", NULL };
int IpsConfirm(SConnection *pCon, pEVControl evc, int argc, char *argv[]);
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
static int IpsOk(IpsDriv *me, SConnection *pCon) { static int IpsOk(Ips *drv) {
float dif; float dif;
Eve *eve=&me->eve;
if (me->eve.version[0]=='\0') return 1; /* connection not yet confirmed */ if (drv->d.b.msg[0] != '\0') return 1; /* connection not yet confirmed */
if (me->perswitch) return 1; if (drv->perswitch) return 1;
if (fabs(me->persfield - me->lastfield) < 1e-5) return 1; if (fabs(drv->persfield - drv->lastfield) < 1e-5) return 1;
if (me->force != 0) return 1; if (drv->force != 0) return 1;
eve->errCode = EVE_FAULT; ParPrintf(drv, eWarning,
if (!pCon) pCon = SCLoad(&eve->evc->conn);
SCPrintf(pCon, eWarning,
"\nit is not sure which field is in the magnet\n" "\nit is not sure which field is in the magnet\n"
"value stored in power supply: %f\n" "value stored in power supply: %f\n"
" in software: %f\n" " in software: %f\n"
"use command\n \n %s confirm ...\n \n" "use command\n \n %s confirm ...\n \n"
"to specify the persistent field\n \n" "to specify the persistent field\n \n"
, me->persfield, me->lastfield, eve->evc->pName); , drv->persfield, drv->lastfield, drv->d.b.p.name);
me->force = 0; drv->force = 0;
return 0; return 0;
} }
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
#define A EVE_ACTPAR static int IpsConfirm(void *object, void *userarg, int argc, char *argv[])
#define L EVE_LOGPAR {
#define S EVE_SAVEPAR Ips *drv = ParCast(&ipsClass, object);
float fld;
void IpsPars(IpsDriv *me, EveParArg *arg) {
EveIntPar(arg, "persmode", &me->persmode, usUser, A+S); assert(drv);
EveIntPar(arg, "perswitch", &me->perswitch, usInternal, A); if (argc > 0) {
EveObPar(arg, UPLIMIT, "%.5g\tTesla", A+S); if (argc > 1) {
EveFloatPar(arg, "ramp", &me->ramp, "%.5g\tTesla/min", usUser, A+S); ParPrintf(object, eError, "Too many arguments");
EveFloatPar(arg, "current", &me->current, "%.5g\tTesla", usInternal, A+L); return 0;
EveFloatPar(arg, "lastfield", &me->lastfield, "%.5g\tTesla", usInternal, S); }
EveCmd(arg, "confirm", IpsConfirm, usUser); fld=atof(argv[0]);
EveStdParEnd(arg, "%.5g\tTesla", A+L+S); if (fld > drv->d.upperLimit || fld < drv->d.lowerLimit) {
if (EveUserAction(arg)) { ParPrintf(object, eError, "Field outside limit");
IpsOk(me, EveArgConn(arg)); return 0;
}
if (drv->perswitch) {
ParPrintf(object, eWarning, "switch heater is on - field is %f", drv->current);
return 0;
}
if (fabs(fld - drv->persfield) > 1e-5 && fabs(fld - drv->lastfield) > 1e-5) {
ParPrintf(object, eWarning, "Be aware that this does neither match the field"
" stored in software\nnor the field stored in power supply.");
}
if (drv->force && fld != drv->confirmfield) drv->force = 0;
if (drv->force == 0) {
ParPrintf(object, eWarning, "Please repeat this command, to confirm again"
" the persistent field of\n %f Tesla.", fld);
drv->confirmfield = fld;
drv->force=1;
} else {
drv->force=2;
drv->lastfield=fld;
EaseParHasChanged();
ParPrintf(object, eValue, "%s confirm = %f", drv->d.b.p.name, fld);
}
} else {
ParPrintf(object, eValue, "%s lastfield = %f", drv->d.b.p.name, drv->lastfield);
} }
return 1;
} }
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
void IpsStatus(IpsDriv *me) { void IpsParDef(void *object) {
Ips *drv = ParCast(&ipsClass, object);
ParName(""); ParFmt(drv->fmt); ParTail("Tesla");
ParFloat(&drv->persfield, PAR_NAN);
ParName("persmode"); ParAccess(usUser); ParEnum(onOff); ParList(0);
ParInt(&drv->persmode, 1);
ParName("perswitch"); ParEnum(onOff); ParList(0);
ParInt(&drv->perswitch, PAR_NAN);
ParName("maxlimit"); ParSave(1); ParFloat(&drv->maxlimit, 0.0);
ParName("limit"); ParAccess(usUser); ParFmt(drv->fmt); ParTail("Tesla");
ParFloat(&drv->d.upperLimit, 0.0);
if (ParActionIs(PAR_SET) > 0) {
if (drv->maxlimit == 0) { /* first time: set maxlimit */
drv->maxlimit = drv->d.upperLimit;
} else if (drv->d.upperLimit > drv->maxlimit) {
drv->d.upperLimit= drv->maxlimit;
ParPrintf(drv, eWarning, "limit is too high, set back to %.5g\n", drv->maxlimit);
}
drv->d.lowerLimit = - drv->d.upperLimit;
}
ParName("ramp"); ParAccess(usUser); ParFmt(drv->fmt); ParTail("Tesla/min");
ParFloat(&drv->ramp, 1.0);
ParName("current"); ParFmt(drv->fmt); ParTail("Tesla equivalent");
ParFloat(&drv->current, PAR_NAN);
ParName("lastfield");
ParSave(1);
ParFloat(&drv->lastfield, 0);
ParName("confirm"); ParCmd(IpsConfirm, NULL);
EaseBasePar(drv);
EaseSendPar(drv);
ParStdDef();
ParName("targetValue"); ParFmt(drv->fmt); ParTail("Tesla");
ParFloat(&drv->d.targetValue, PAR_NAN);
if (ParActionIs(PAR_LIST) || ParActionIs(PAR_SET) || ParActionIs(PAR_SHOW)) {
IpsOk(drv);
}
EaseMsgPar(drv);
}
/*----------------------------------------------------------------------------*/
static void IpsStatus(Ips *drv) {
char *ans; char *ans;
int *code; int *code;
Eve *eve=&me->eve;
int swi; int swi;
if (eve->state != readState) return; if (drv->d.b.state != EASE_read) return;
ans=eve->ans; ans=drv->d.b.ans;
code=&eve->errCode; code=&drv->d.b.errCode;
if (ans[0] != 'X' || if (ans[0] != 'X' ||
ans[3] != 'A' || ans[3] != 'A' ||
ans[5] != 'C' || ans[5] != 'C' ||
ans[7] != 'H' || ans[7] != 'H' ||
ans[9] != 'M') { ans[9] != 'M') {
EvePrintf(eve, eError, "illegal status response"); ParPrintf(drv, eError, "illegal status response");
*code = EVE_FAULT; *code = EASE_FAULT;
return; return;
} }
switch (ans[1]) { switch (ans[1]) {
case '0': break; case '0': break;
case '1': EvePrintf(eve, eError, "magnet quenched"); *code = EVE_FAULT; return; case '1': ParPrintf(drv, eError, "magnet quenched"); *code = EASE_FAULT; return;
case '2': EvePrintf(eve, eError, "IPS overheated"); *code = EVE_FAULT; return; case '2': ParPrintf(drv, eError, "IPS overheated"); *code = EASE_FAULT; return;
case '4': EvePrintf(eve, eError, "IPS warming up"); *code = EVE_FAULT; return; case '4': ParPrintf(drv, eError, "IPS warming up"); *code = EASE_FAULT; return;
case '8': EvePrintf(eve, eError, "IPS fault"); *code = EVE_FAULT; return; case '8': ParPrintf(drv, eError, "IPS fault"); *code = EASE_FAULT; return;
default: default:
EvePrintf(eve, eError, "illegal status response"); ParPrintf(drv, eError, "illegal status response");
*code = EVE_FAULT; *code = EASE_FAULT;
return; return;
} }
if (ans[6] != '3' && me->remote == 2) { if (ans[6] != '3') {
EvePrintf(eve, eError, "IPS switched to local"); if (drv->remote == 2) {
*code = EVE_FAULT; ParPrintf(drv, eError, "IPS switched to local");
me->remote = 1; *code = EASE_FAULT;
return; drv->remote = 1;
return;
}
if (drv->d.hwstate == HWBusy && drv->d.b.doit == NULL) {
drv->d.hwstate = HWIdle;
drv->d.stopped = 0;
}
} }
if (ans[8] == '5') { if (ans[8] == '5') {
me->heaterFault = 1; drv->heaterFault = 1;
return; return;
} }
if (ans[8] == '1') { if (ans[8] == '1') {
@ -130,346 +213,292 @@ void IpsStatus(IpsDriv *me) {
} else { } else {
swi = 0; swi = 0;
} }
if (swi != me->perswitch || me->swtim == 0) { if (swi != drv->perswitch || drv->swtim == 0) {
me->swtim = time(NULL); drv->swtim = time(NULL);
me->perswitch = swi; drv->perswitch = swi;
} }
} }
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
static void IpsSetField(IpsDriv *me, float val) { static void IpsSetField(Ips *drv, float val) {
char buf[128]; ParLog(drv);
SConnection *pCon; if (drv->perswitch) {
drv->current = val;
if (me->eve.value != val && me->eve.evc != NULL) { drv->lastfield = val;
snprintf(buf, sizeof(buf), "%s = %g", me->eve.evc->pName, val); drv->persfield = val;
InvokeCallBack(me->eve.evc->pCall, VALUECHANGE, buf); EaseParHasChanged();
pCon = SCLoad(&me->eve.evc->conn);
if (pCon) SCparChange(pCon);
}
if (me->perswitch) {
me->current = val;
me->lastfield = val;
me->persfield = val;
} else if (me->force == 2) {
me->lastfield = val;
} else { } else {
me->persfield = val; drv->persfield = val;
} }
me->eve.value = val;
} }
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
static int IpsRead(long pc, IpsDriv *me) { static long IpsRead(long pc, void *object) {
Eve *eve=&me->eve; Ips *drv = ParCast(&ipsClass, object);
EaseBase *eab = object;
FSM_BEGIN
EveWrite(eve, "X"); switch (pc) { default: /* FSM BEGIN *******************************/
FSM_NEXT EaseWrite(eab, "X");
IpsStatus(me); /* check for errors and get perswitch */ return __LINE__; case __LINE__: /**********************************/
/* IpsStatus(drv);
if (!me->remote) goto rd;
EveWrite(eve, "C0");
me->remote = 0;
FSM_NEXT
*/
rd: rd:
EveWrite(eve, "R7"); /* read current (in Tesla) */ EaseWrite(eab, "R7"); /* read current (in Tesla) */
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
me->current = OiGetFlt(eve, 3, NULL); drv->current = OxiGet(eab, 3, NULL);
if (me->perswitch) { if (drv->perswitch) {
IpsSetField(me, me->current); IpsSetField(drv, drv->current);
goto quit; goto quit;
} }
EveWrite(eve, "R18"); /* read persistant field (in Tesla) */ EaseWrite(eab, "R18"); /* read persistant field (in Tesla) */
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
IpsSetField(me, OiGetFlt(eve, 3, NULL)); IpsSetField(drv, OxiGet(eab, 3, NULL));
quit: quit:
EveLog(eve); ParLog(drv);
FSM_END return 0; } /* FSM END ********************************************/
} }
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
static int IpsStart(long pc, IpsDriv *me) { static long IpsStart(long pc, void *object) {
Eve *eve=&me->eve; Ips *drv = ParCast(&ipsClass, object);
EaseBase *eab = object;
FSM_BEGIN switch (pc) { default: /* FSM BEGIN *******************************/
EveWrite(eve, "V"); EaseWrite(eab, "V");
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
if (0 == strncmp(eve->version, "IPS120", 6)) { if (0 == strncmp(eab->version, "IPS120", 6)) {
me->eve.syntax = 1; eab->syntax = 1;
} else if (0 == strncmp(eve->version, "PS", 2)) { } else if (0 == strncmp(eab->version, "PS", 2)) {
me->eve.syntax = 0; eab->syntax = 0;
} else { } else {
EvePrintf(eve, eError, "unknown power supply version: %s", eve->version); snprintf(eab->msg, sizeof eab->msg, "unknown power supply version: %s", eab->version);
ParPrintf(drv, eError, "ERROR: %s", eab->msg);
EaseStop(eab);
goto quit; goto quit;
} }
EvePrintf(eve, eStatus, "connected to %s", eve->version); ParPrintf(drv, eStatus, "connected to %s", eab->version);
FSM_CALL(IpsRead); if (eab->syntax) {
drv->fmt = "%.4f";
} else {
drv->fmt = "%.3f";
}
FsmCall(IpsRead);
return __LINE__; case __LINE__: /**********************************/
quit: quit:
FSM_END return 0; } /* FSM END ********************************************/
} }
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
static int IpsChangeField(long pc, IpsDriv *me) { static long IpsChangeField(long pc, void *object) {
Eve *eve=&me->eve; Ips *drv = ParCast(&ipsClass, object);
pEVControl evc=eve->evc; EaseBase *eab = object;
float fld; float fld;
float step; float step;
float ramp; float ramp;
time_t delay; time_t delay;
FSM_BEGIN switch (pc) { default: /* FSM BEGIN *******************************/
EveWrite(eve, "C3"); EaseSetUpdate(eab, EASE_RUN, 0);
me->remote = 1; EaseWrite(eab, "C3");
FSM_NEXT drv->remote = 1;
EveWrite(eve, "F7"); /* switch to tesla on display */ return __LINE__; case __LINE__: /**********************************/
FSM_NEXT EaseWrite(eab, "F7"); /* switch to tesla on display */
EveWrite(eve, "A0"); /* hold */ return __LINE__; case __LINE__: /**********************************/
FSM_NEXT EaseWrite(eab, "A0"); /* hold */
FSM_CALL(IpsRead); return __LINE__; case __LINE__: /**********************************/
me->remote = 2; FsmCall(IpsRead);
if (!IpsOk(me, NULL)) goto finish; return __LINE__; case __LINE__: /**********************************/
if (fabs(evc->fTarget - me->lastfield) < 1e-5) { drv->remote = 2;
EvePrintf(eve, -1, "IPS: we are already at field %f", me->lastfield); if (!IpsOk(drv)) goto finish;
if (me->persmode) { if (fabs(drv->d.targetValue - drv->lastfield) < 1e-5) {
if (!me->perswitch) goto finish; ParPrintf(drv, -1, "IPS: we are already at field %f", drv->lastfield);
if (drv->persmode) {
if (!drv->perswitch) goto finish;
goto target_reached; goto target_reached;
} else { } else {
if (me->perswitch) goto finish; if (drv->perswitch) goto finish;
} }
} }
if (fabs(me->current - me->lastfield) < 1e-5) { if (fabs(drv->current - drv->lastfield) < 1e-5) {
goto switch_on; goto switch_on;
} }
OiSet(eve, "J", me->lastfield, 3); /* set point */ OxiSet(eab, "J", drv->lastfield, 3); /* set point */
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
EveWrite(eve, "A1"); EaseWrite(eab, "A1");
EvePrintf(eve, -1, "IPS: ramp to current for %f Tesla", me->lastfield); ParPrintf(drv, -1, "IPS: ramp to current for %f Tesla", drv->lastfield);
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
me->tim = time(NULL); drv->tim = time(NULL);
stab1: stab1:
EveWrite(eve, "X"); EaseWrite(eab, "X");
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
IpsStatus(me); /* just check for errors */ IpsStatus(drv); /* just check for errors */
EveWrite(eve, "R7"); /* read current (in Tesla) */ EaseWrite(eab, "R7"); /* read current (in Tesla) */
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
me->current = OiGetFlt(eve, 3, NULL); drv->current = OxiGet(eab, 3, NULL);
EveLog(eve); ParLog(drv);
if (fabs(me->current - me->lastfield) > 1e-5) goto stab1; if (fabs(drv->current - drv->lastfield) > 1e-5) goto stab1;
stab2: stab2:
FSM_WAIT(1) FsmWait(1);
EveWrite(eve, "X"); return __LINE__; case __LINE__: /**********************************/
FSM_NEXT EaseWrite(eab, "X");
IpsStatus(me); return __LINE__; case __LINE__: /**********************************/
if (time(NULL) < me->tim + 10) goto stab2; /* stabilize */ IpsStatus(drv);
if (time(NULL) < drv->tim + 10) goto stab2; /* stabilize */
switch_on: switch_on:
if (me->perswitch) goto wait_open; if (drv->perswitch) goto wait_open;
if (me->force == 2) { if (drv->force == 2) {
EveWrite(eve, "H2"); EaseWrite(eab, "H2");
} else { } else {
EveWrite(eve, "H1"); EaseWrite(eab, "H1");
} }
me->force = 0; drv->force = 0;
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
me->perswitch = 1; drv->perswitch = 1;
me->swtim = time(NULL); drv->swtim = time(NULL);
wait_open: wait_open:
delay = me->swtim + 30 - time(NULL); delay = drv->swtim + 30 - time(NULL);
if (delay > 0) if (delay > 0)
EvePrintf(eve, -1, "IPS: wait %d sec to open switch", delay); ParPrintf(drv, -1, "IPS: wait %d sec to open switch", delay);
start_ramp: start_ramp:
FSM_WAIT(1) FsmWait(1);
EveWrite(eve, "X"); return __LINE__; case __LINE__: /**********************************/
FSM_NEXT EaseWrite(eab, "X");
IpsStatus(me); /* check for errors */ return __LINE__; case __LINE__: /**********************************/
if (me->heaterFault) { IpsStatus(drv); /* check for errors */
if (time(NULL) > me->swtim + 3) { if (drv->heaterFault) {
EvePrintf(eve, eError, "IPS heater fault"); if (time(NULL) > drv->swtim + 3) {
eve->errCode = EVE_FAULT; ParPrintf(drv, eError, "IPS heater fault");
eab->errCode = EASE_FAULT;
goto off_finish; goto off_finish;
} }
me->heaterFault = 0; drv->heaterFault = 0;
} }
if (time(NULL) < me->swtim + 30) goto start_ramp; /* wait */ if (time(NULL) < drv->swtim + 30) goto start_ramp; /* wait */
OiSet(eve, "T", me->ramp, 3); OxiSet(eab, "T", drv->ramp, 3);
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
OiSet(eve, "J", me->current, 3); /* put set point to actual value */ OxiSet(eab, "J", drv->current, 3); /* put set point to actual value */
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
EveWrite(eve, "A1"); /* go to setpoint (do not yet run) */ EaseWrite(eab, "A1"); /* go to setpoint (do not yet run) */
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
EvePrintf(eve, -1, "IPS: ramp to %f Tesla", evc->fTarget); ParPrintf(drv, -1, "IPS: ramp to %f Tesla", drv->d.targetValue);
ramping: ramping:
FSM_WAIT(1) FsmWait(1);
EveWrite(eve, "R7"); /* read "current" in Tesla */ return __LINE__; case __LINE__: /**********************************/
FSM_NEXT EaseWrite(eab, "R7"); /* read "current" in Tesla */
IpsSetField(me, OiGetFlt(eve, 3, NULL)); /* set me->current and callback */ return __LINE__; case __LINE__: /**********************************/
EveWrite(eve, "X"); IpsSetField(drv, OxiGet(eab, 3, NULL)); /* set drv->current and callback */
FSM_NEXT EaseWrite(eab, "X");
IpsStatus(me); /* just check for errors */ return __LINE__; case __LINE__: /**********************************/
EveWrite(eve, "R9"); /* read back ramp rate (may be sweep limited) */ IpsStatus(drv); /* just check for errors */
FSM_NEXT EaseWrite(eab, "R9"); /* read back ramp rate (may be sweep limited) */
ramp=OiGetFlt(eve, 3, NULL); return __LINE__; case __LINE__: /**********************************/
ramp=OxiGet(eab, 3, NULL);
step=ramp/20; /* step = ramp * 3sec */ step=ramp/20; /* step = ramp * 3sec */
if (step < 0.001) step=0.001; if (step < 0.001) step=0.001;
if (evc->fTarget > me->current + step) { if (drv->d.targetValue > drv->current + step) {
fld=me->current + step; fld=drv->current + step;
} else if (evc->fTarget < me->current - step) { } else if (drv->d.targetValue < drv->current - step) {
fld=me->current - step; fld=drv->current - step;
} else { } else {
fld=evc->fTarget; fld=drv->d.targetValue;
if (fabs(me->current - evc->fTarget) < 1e-5) goto target_reached; if (fabs(drv->current - drv->d.targetValue) < 1e-5) goto target_reached;
} }
OiSet(eve, "J", fld, 3); OxiSet(eab, "J", fld, 3);
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
EveLog(eve); ParLog(drv);
goto ramping; goto ramping;
target_reached: target_reached:
eve->hwstate = HWIdle; drv->d.hwstate = HWIdle;
evc->eMode = EVMonitor; drv->d.eMode = EVMonitor; /* we are at field, drive has finished */
/* we are at field, drive has finished, but we continue in the background */ if (!drv->persmode) goto hold_finish;
me->tim = time(NULL); /* but we continue in the background */
drv->tim = time(NULL);
stab3: stab3:
FSM_WAIT(1) FsmWait(1);
EveWrite(eve, "R18"); /* read persistant field in Tesla */ return __LINE__; case __LINE__: /**********************************/
FSM_NEXT EaseWrite(eab, "X");
IpsSetField(me, OiGetFlt(eve, 3, NULL)); return __LINE__; case __LINE__: /**********************************/
me->lastfield = me->persfield; IpsStatus(drv); /* just check for errors */
EveWrite(eve, "X"); if (time(NULL) < drv->tim + 10) goto stab3; /* stabilize */
FSM_NEXT
IpsStatus(me); /* just check for errors */ EaseWrite(eab, "A0"); /* hold */
if (time(NULL) < me->tim + 10) goto stab3; /* stabilize */ return __LINE__; case __LINE__: /**********************************/
EaseWrite(eab, "H0");
EveWrite(eve, "A0"); /* hold */ drv->perswitch = 0;
FSM_NEXT drv->swtim = time(NULL);
if (!me->persmode) goto finish; drv->lastfield = drv->current;
EaseParHasChanged();
EveWrite(eve, "H0"); return __LINE__; case __LINE__: /**********************************/
me->perswitch = 0; ParPrintf(drv, -1, "IPS: wait 30 sec to close switch");
me->swtim = time(NULL);
me->lastfield = me->current;
FSM_NEXT
EvePrintf(eve, -1, "IPS: wait 30 sec to close switch");
wait_closed: wait_closed:
EveWrite(eve, "R18"); /* read persistant field in Tesla */ FsmWait(1);
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
IpsSetField(me, OiGetFlt(eve, 3, NULL)); EaseWrite(eab, "R18"); /* read persistent field in Tesla */
me->lastfield = me->persfield; return __LINE__; case __LINE__: /**********************************/
FSM_WAIT(1) fld = OxiGet(eab, 3, NULL);
EveWrite(eve, "X"); if (fld != drv->lastfield) {
FSM_NEXT IpsSetField(drv, fld); /* set drv->current and callback */
IpsStatus(me); drv->lastfield = fld;
if (time(NULL) < me->swtim + 30) goto wait_closed; /* wait */ EaseParHasChanged();
}
EaseWrite(eab, "X");
return __LINE__; case __LINE__: /**********************************/
IpsStatus(drv);
if (time(NULL) < drv->swtim + 30) goto wait_closed; /* wait */
if (me->current == 0) goto finish; if (drv->current == 0) goto finish;
EveWrite(eve, "A2"); /* goto zero */ EaseWrite(eab, "A2"); /* goto zero */
EvePrintf(eve, -1, "IPS: ramp current to 0"); ParPrintf(drv, -1, "IPS: ramp current to 0");
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
goto finish; goto finish;
hold_finish:
EaseWrite(eab, "A0");
return __LINE__; case __LINE__: /**********************************/
goto finish;
off_finish: off_finish:
if (me->perswitch) { if (drv->perswitch) {
me->lastfield = me->current; drv->lastfield = drv->current;
me->swtim = time(NULL); drv->swtim = time(NULL);
} }
EveWrite(eve, "H0"); EaseWrite(eab, "H0");
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
finish: finish:
EveWrite(eve, "C0"); EaseWrite(eab, "C0");
me->remote = 0; drv->remote = 0;
eve->hwstate = HWIdle; drv->d.hwstate = HWIdle;
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
FSM_END return 0; } /* FSM END ********************************************/
} }
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
int IpsConfirm(SConnection *pCon, pEVControl evc, int argc, char *argv[]) { static int IpsInit(SConnection *con, int argc, char *argv[], int dynamic) {
float fld;
IpsDriv *me;
me=evc->pDriv->pPrivate; assert(me);
if (argc > 1) {
if (argc > 2) {
SCPrintf(pCon, eError, "Too many arguments");
return -1;
}
fld=atof(argv[1]);
if (fld > ObVal(evc->pParam, UPLIMIT)) {
SCPrintf(pCon, eError, "Field outside limit");
return -1;
}
if (me->perswitch) {
SCPrintf(pCon, eWarning, "switch heater is on - field is %f", me->current);
return -1;
}
if (fabs(fld - me->persfield) > 1e-5 && fabs(fld - me->lastfield) > 1e-5) {
SCPrintf(pCon, eWarning, "Be aware that this does neither match the field"
" stored in software\nnor the field stored in power supply.");
}
if (me->force && fld != me->confirmfield) me->force = 0;
if (me->force == 0) {
SCPrintf(pCon, eWarning, "Please repeat this command, to confirm again"
" the persistent field of\n %f Tesla.", fld);
me->confirmfield = fld;
me->force=1;
} else {
me->force=2;
IpsSetField(me, fld);
SCPrintf(pCon, eValue, "%s.%s = %f", evc->pName, argv[1], fld);
}
} else {
SCPrintf(pCon, eValue, "%s.%s = %f", evc->pName, argv[1], me->eve.value);
}
return 1;
}
/*------------------------------------------------------------------------*/
static int IpsIsOk(void *data) {
/* always in tolerance (here we may implement what to do in case of a quench) */
return 1;
}
/*------------------------------------------------------------------------*/
pEVControl IpsMakeEVC(SConnection *pCon, int argc, char *argv[]) {
/* args: /* args:
<objectname> ips <rs232> MakeObject objectname ips <rs232>
<objectname> ips <host> <port> <host> <port>
*/ */
IpsDriv *me; Ips *drv;
Eve *eve;
pEVControl evc;
evc = MakeEveEVC(argc, argv, calloc(1, sizeof *me), pCon); drv = EaseMakeDriv(con, &ipsClass, argc, argv, dynamic, 7,
if (!evc) return NULL; IpsParDef, OxiHandler, IpsStart, NULL, IpsRead,
IpsChangeField);
me = evc->pDriv->pPrivate; if (drv == NULL) return 0;
eve=&me->eve; ParPrintf(drv, eValue, "OI Power Supply");
drv->d.maxwait = 999999;
me->current = 0; return 1;
me->persfield = 0; }
me->lastfield = 0; /*----------------------------------------------------------------------------*/
me->persmode = 1; void IpsStartup(void) {
me->perswitch = 0; ParMakeClass(&ipsClass, EaseDrivClass());
me->force = 0; MakeDriver("IPS", IpsInit, 0);
me->tim = 0;
me->swtim = 0;
me->ramp=0.1;
eve->run = (FsmFunc)IpsChangeField;
eve->read = (FsmFunc)IpsRead;
eve->pardef = (EveParDef)IpsPars;
eve->todo = (FsmFunc)IpsStart;
eve->task = FsmStartTask(me, (FsmHandler)OiHandler, (FsmFunc)EveIdle);
evc->pEnvir->IsInTolerance = IpsIsOk;
EVCSetPar(evc,"upperlimit",14.9,pCon);
EVCSetPar(evc,"lowerlimit",-14.9,pCon);
return evc;
} }

622
itcdriv.c
View File

@ -2,8 +2,9 @@
itcdriv.c itcdriv.c
Driver for the Oxford Instruments ITC503/ITC4 temperature controller Driver for the Oxford Instruments ITC503/ITC4 temperature controller
Version 2 (based on ease).
Markus Zolliker, Sept 2004
Markus Zolliker, May 2005
----------------------------------------------------------------------------*/ ----------------------------------------------------------------------------*/
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
@ -26,15 +27,22 @@ Markus Zolliker, Sept 2004
#include <sicsvar.h> #include <sicsvar.h>
#include <evdriver.i> #include <evdriver.i>
#include <rs232controller.h> #include <rs232controller.h>
#include "oicom.h" #include "oxinst.h"
#include "fsm.h" #include "fsm.h"
#include "initializer.h"
#define TESLATRON -1
#define ITC_SETHTR 1
#define ITC_SETGAS 2
typedef struct { typedef struct {
Eve eve; EaseDriv d;
float t[4]; /* temperatures (0 unused) */ float t[4]; /* temperatures (0 is set point) */
int dig[4]; /* format for these */ int dig[4]; /* format for these */
float htr; float htr;
float gas; float gas;
float autoGasLimit;
float setGas;
int sampleChan; int sampleChan;
int controlChan; int controlChan;
int gasMode; int gasMode;
@ -42,310 +50,470 @@ typedef struct {
int remote; int remote;
int h; /* actual heater channel */ int h; /* actual heater channel */
int a; /* actual auto mode */ int a; /* actual auto mode */
} ItcDriv; } Itc;
static ParClass itcClass = { "ITC", sizeof(Itc) };
static long ItcSetGas(long pc, void *obj);
static long ItcSetHtr(long pc, void *obj);
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
#define A EVE_ACTPAR static void ItcParDef(void *object) {
#define L EVE_LOGPAR Itc *drv = ParCast(&itcClass, object);
#define S EVE_SAVEPAR EaseBase *eab = object;
void ItcPars(ItcDriv *me, EveParArg *arg) {
char fmt[8]=""; char fmt[8]="";
int i; int i;
int flag; static char *ti[4] = {"setp","t1","t2","t3"};
char *ti[4] = {"setp","t1","t2","t3"};
static char *modeList[]={"off", "manual", "auto", NULL }; static char *modeList[]={"off", "manual", "auto", NULL };
EveStdPar(arg); ParName("sampleChan");
if (eab->syntax != TESLATRON) ParAccess(usUser);
flag = me->controlChan != 0 && fabsf(me->eve.evc->fTarget - me->t[0]) > 9e-4; ParInt(&drv->sampleChan, 1);
sprintf(fmt, "%%.%df\tK", me->dig[me->controlChan]); if (ParActionIs(PAR_SET) > 0) {
EveFloatPar(arg, ti[0], &me->t[0], fmt, usInternal, flag*A + L); if (drv->sampleChan < 1 || drv->sampleChan > 3) {
drv->sampleChan = 1;
}
}
if (eab->syntax != TESLATRON) {
ParName("controlChan");
ParAccess(usUser);
ParInt(&drv->controlChan, 0);
if (ParActionIs(PAR_SET) > 0) {
if (drv->controlChan < 0 || drv->controlChan > 3) {
drv->controlChan = 1;
}
}
}
ParName("");
if (eab->syntax == TESLATRON) {
ParTail("mbar");
} else {
ParTail("K");
}
ParFloat(&drv->t[drv->sampleChan], PAR_NAN);
ParName("dig1"); ParAccess(usUser); ParLogAs(NULL); ParInt(&drv->dig[1], -1);
ParName("dig2"); ParAccess(usUser); ParLogAs(NULL); ParInt(&drv->dig[2], -1);
ParName("dig3"); ParAccess(usUser); ParLogAs(NULL); ParInt(&drv->dig[3], -1);
if (eab->syntax != TESLATRON) {
ParName(ti[0]);
if (drv->controlChan != 0) {
snprintf(fmt, sizeof fmt, "%%.%df", drv->dig[drv->controlChan]);
ParFmt(fmt);
if (fabsf(drv->d.targetValue - drv->t[0]) < 9e-4) {
ParList("");
}
} else {
ParList("");
}
ParTail("K");
ParFloat(&drv->t[0], PAR_NAN);
}
for (i=1; i<=3; i++) { for (i=1; i<=3; i++) {
flag = (me->dig[i] >= 0) && (me->sampleChan != i);
sprintf(fmt, "%%.%df\tK", me->dig[i]); ParName(ti[i]);
EveFloatPar(arg, ti[i], &me->t[i], fmt, usInternal, flag*A + L); if (drv->dig[i] >= 0 && drv->sampleChan != i) {
snprintf(fmt, sizeof fmt, "%%.%df", drv->dig[i]);
ParFmt(fmt);
ParTail("K");
} else {
ParList("");
}
ParFloat(&drv->t[i], PAR_NAN);
} }
flag = me->controlChan != 0 || me->htr != 0; if (eab->syntax != TESLATRON) {
EveEnumPar(arg, "htrMode", &me->htrMode, modeList, usUser, A+S); ParName("htrMode");
EveFloatCmd(arg, "htr", &me->htr, "%.1f\t%%", ItcSetHtr, usUser, flag*A + L); if (drv->controlChan == 0 && drv->htr == 0) {
EveEnumPar(arg, "gasMode", &me->gasMode, modeList, usUser, A+S); ParList("");
flag = me->gasMode > 0; }
EveFloatCmd(arg, "gas", &me->gas, "%.1f\t%%", ItcSetGas, usUser, flag*A + L); ParEnum(modeList); ParSave(1);
EveIntPar(arg, "dig1", &me->dig[1], usUser, S); ParInt(&drv->htrMode, 2);
EveIntPar(arg, "dig2", &me->dig[2], usUser, S);
EveIntPar(arg, "dig3", &me->dig[3], usUser, S); ParName("htr");
EveIntPar(arg, "sampleChan", &me->sampleChan, usUser, A+S); ParFmt("%.1f"); ParTail("%");
EveIntPar(arg, "controlChan", &me->controlChan, usUser, A+S); ParSave(1);
sprintf(fmt, "%%.%df\tK", me->dig[me->sampleChan]); EaseUpdate(ITC_SETHTR);
EveStdParEnd(arg, fmt, A+L); ParFloat(&drv->htr, PAR_NAN);
}
ParName("gasMode");
ParAccess(usUser); ParEnum(modeList);
if (eab->syntax == TESLATRON) {
ParInt(&drv->gasMode, 1);
} else {
ParList(""); ParInt(&drv->gasMode, 1);
}
ParName("gas");
ParFmt("%.1f"); ParTail("%");
if (drv->gasMode < 1) {
ParList("");
}
ParFloat(&drv->gas, PAR_NAN);
ParName("setGas");
ParFmt("%.1f"); ParTail("%");
if (drv->gasMode < 1) {
ParList("");
}
EaseUpdate(ITC_SETGAS); ParSave(1);
ParFloat(&drv->setGas, 20.0);
if (eab->syntax != TESLATRON) {
ParName("autoGasLimit");
ParAccess(usUser); ParFmt("%.1f"); ParTail("K"); ParSave(1);
if (drv->gasMode != 2) {
ParList("");
}
ParFloat(&drv->autoGasLimit, 3.0);
}
if (drv->controlChan == 0) {
i = drv->sampleChan;
} else {
i = drv->controlChan;
}
if (drv->dig[i] < 0) {
snprintf(fmt, sizeof fmt, "%s", "%.3f");
} else {
snprintf(fmt, sizeof fmt, "%s.%df", "%", drv->dig[i]);
}
EaseBasePar(drv);
EaseSendPar(drv);
if (eab->syntax != TESLATRON) {
EaseDrivPar(drv, fmt, "K");
}
ParStdDef();
EaseMsgPar(drv);
} }
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
void ItcStatus(ItcDriv *me) { void ItcStatus(Itc *drv) {
char *ans; char *ans;
int *code; int *code;
Eve *eve=&me->eve;
if (eve->state != readState) return; if (drv->d.b.state != EASE_read) return;
ans=eve->ans; ans=drv->d.b.ans;
code=&eve->errCode; code=&drv->d.b.errCode;
if (ans[0] != 'X' || if (ans[0] != 'X' ||
ans[2] != 'A' || ans[2] != 'A' ||
ans[4] != 'C' || ans[4] != 'C' ||
ans[6] != 'S') { ans[6] != 'S') {
EvePrintf(eve, eError, "illegal status response"); ParPrintf(drv, eError, "illegal status response");
*code = EVE_FAULT; *code = EASE_FAULT;
return; return;
} }
me->a = ans[3] - '0'; drv->a = ans[3] - '0';
if (ans[9] == 'H') { if (ans[9] == 'H') {
me->h = ans[10] - '0'; drv->h = ans[10] - '0';
} else { } else {
me->h = me->controlChan; drv->h = drv->controlChan;
} }
if (ans[6] != '3' && me->remote == 2) { if (ans[6] != '3' && drv->remote == 2) {
EvePrintf(eve, eError, "ITC switched to local"); ParPrintf(drv, eError, "ITC switched to local");
*code = EVE_FAULT; *code = EASE_FAULT;
me->remote = 1; drv->remote = 1;
return; return;
} }
} }
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
static long ItcRead(long pc, ItcDriv *me) { static long ItcRead(long pc, void *object) {
Eve *eve=&me->eve; Itc *drv = ParCast(&itcClass, object);
EaseBase *eab = object;
char *p; char *p;
int l; int l;
char buf[4];
FSM_BEGIN switch (pc) { default: /* FSM BEGIN *******************************/
EveWrite(eve, "X"); EaseWrite(eab, "X");
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
ItcStatus(me); /* check for errors */ ItcStatus(drv); /* check for errors */
if (!me->remote) goto skiprmt;
EveWrite(eve, "C0"); if (drv->dig[1] < 0) goto skip1;
me->remote = 0; EaseWrite(eab, "R1"); /* read sensor 1 */
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
drv->t[1] = OxiGet(eab, drv->dig[1], &drv->dig[1]);
skiprmt:
if (me->dig[1] < 0) goto skip1;
EveWrite(eve, "R1"); /* read sensor 1 */
FSM_NEXT
me->t[1] = OiGetFlt(eve, me->dig[1], &me->dig[1]);
skip1: skip1:
if (me->dig[2] < 0) goto skip2; if (drv->dig[2] < 0) goto skip2;
EveWrite(eve, "R2"); /* read sensor 2 */ EaseWrite(eab, "R2"); /* read sensor 2 */
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
me->t[2] = OiGetFlt(eve, me->dig[2], &me->dig[2]); drv->t[2] = OxiGet(eab, drv->dig[2], &drv->dig[2]);
skip2: skip2:
if (me->dig[3] < 0) goto skip3; if (drv->dig[3] < 0) goto skip3;
EveWrite(eve, "R3"); /* read sensor 3 */ EaseWrite(eab, "R3"); /* read sensor 3 */
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
me->t[3] = OiGetFlt(eve, me->dig[3], &me->dig[3]); drv->t[3] = OxiGet(eab, drv->dig[3], &drv->dig[3]);
skip3: skip3:
me->eve.value = me->t[me->sampleChan]; if (drv->controlChan == 0 || drv->a == 0) {
if (me->controlChan == 0 || me->a) { drv->t[0] = drv->d.targetValue;
me->t[0] = me->eve.evc->fTarget;
goto skip0; goto skip0;
} }
EveWrite(eve, "R0"); /* read control T */ EaseWrite(eab, "R0"); /* read control T */
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
me->t[0] = OiGetFlt(eve, me->dig[me->controlChan], NULL); drv->t[0] = OxiGet(eab, drv->dig[drv->controlChan], NULL);
if (drv->gasMode == 2) {
if (me->htrMode != 2 && me->a % 2 == 0) goto skiphtr; if (drv->t[drv->controlChan] > drv->autoGasLimit + 1.0) {
if (drv->a < 2) {
drv->a |= 2; /* switch gas to auto */
ParPrintf(drv, eWarning, "switch to auto needle valve");
} else {
goto skip0;
}
} else {
if (drv->a >= 2) {
if (drv->t[drv->controlChan] < drv->autoGasLimit) {
drv->a &= 1; /* switch gas to manual */
ParPrintf(drv, eWarning, "switch to manual needle valve (%f %%)",
drv->setGas);
} else {
goto skip0;
}
}
if (drv->setGas != drv->gas) {
EaseSetUpdate(drv, ITC_SETGAS, 1);
}
}
} else if (drv->a < 2) {
goto skip0;
} else {
drv->a &= 1; /* switch gas to manual */
}
EaseWrite(eab, "C3");
return __LINE__; case __LINE__: /**********************************/
drv->remote = 2;
snprintf(buf, sizeof buf, "A%d", drv->a);
EaseWrite(eab, buf);
return __LINE__; case __LINE__: /**********************************/
skip0: skip0:
EveWrite(eve, "R5"); /* read heater */
FSM_NEXT if (!drv->remote) goto skiprmt;
me->htr = OiGetFlt(eve, 1, NULL); EaseWrite(eab, "C0");
skiphtr: drv->remote = 0;
if (me->gasMode != 2 && me->a < 2) goto skipgas; return __LINE__; case __LINE__: /**********************************/
EveWrite(eve, "R7"); /* read gas flow */ skiprmt:
FSM_NEXT
me->gas = OiGetFlt(eve, 1, NULL);
if (EaseGetUpdate(drv, ITC_SETHTR)) goto skiphtr;
EaseWrite(eab, "R5"); /* read heater */
return __LINE__; case __LINE__: /**********************************/
if (EaseGetUpdate(drv, ITC_SETHTR)) goto skiphtr;
drv->htr = OxiGet(eab, 1, NULL);
skiphtr:
EaseWrite(eab, "R7"); /* read gas flow */
return __LINE__; case __LINE__: /**********************************/
drv->gas = OxiGet(eab, 1, NULL);
skipgas: skipgas:
me->eve.value = me->t[me->sampleChan];
EveLog(eve); ParLog(drv);
FSM_END fsm_quit: return 0; } /* FSM END *********************************/
} }
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
static long ItcStart(long pc, ItcDriv *me) { static long ItcStart(long pc, void *object) {
Eve *eve=&me->eve; Itc *drv = ParCast(&itcClass, object);
EaseBase *eab = object;
FSM_BEGIN switch (pc) { default: /* FSM BEGIN *******************************/
EveWrite(eve, "V"); EaseWrite(eab, "V");
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
if (0 == strncmp(eve->version, "ITC503", 6)) { if (eab->syntax == TESLATRON) {
me->eve.syntax = 3; if (0 != strncmp(eab->version, "TESLATRON", 9)) {
} else if (0 == strncmp(eve->version, "ITC4", 4)) { snprintf(eab->msg, sizeof eab->msg, "unknown teslatron version: %s",
me->eve.syntax = 0; eab->version);
ParPrintf(drv, eError, "ERROR: %s", eab->msg);
EaseStop(eab);
goto quit;
}
} else { } else {
EvePrintf(eve, eError, "unknown temperature controller version: %s", eve->version); if (0 == strncmp(eab->version, "ITC503", 6)) {
goto quit; eab->syntax = 3;
} else if (0 == strncmp(eab->version, "ITC4", 4)) {
eab->syntax = 0;
} else {
snprintf(eab->msg, sizeof eab->msg, "unknown temperature controller version: %s",
eab->version);
ParPrintf(drv, eError, "ERROR: %s", eab->msg);
EaseStop(eab);
goto quit;
}
} }
EvePrintf(eve, eStatus, "connected to %s", eve->version); ParPrintf(drv, eStatus, "connected to %s", eab->version);
if (me->controlChan == 0 && me->h >= 1 && me->h <= 3) { if (drv->controlChan == 0 && drv->h >= 1 && drv->h <= 3) {
me->controlChan = me->h; drv->controlChan = drv->h;
} }
FSM_CALL(ItcRead); FsmCall(ItcRead);
return __LINE__; case __LINE__: /**********************************/
quit: quit:
FSM_END return 0; } /* FSM END ********************************************/
} }
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
static long ItcSetTemp(long pc, ItcDriv *me) { static long ItcSetTemp(long pc, void *object) {
Eve *eve=&me->eve; Itc *drv = ParCast(&itcClass, object);
pEVControl evc=eve->evc; EaseBase *eab = object;
float fld;
float step;
float ramp;
char buf[4]; char buf[4];
SConnection *pCon;
int a; int a;
FSM_BEGIN switch (pc) { default: /* FSM BEGIN *******************************/
if (me->controlChan == 0) { if (drv->controlChan == 0) {
EvePrintf(eve, eError, "no control channel selected"); ParPrintf(drv, eError, "no control channel selected");
goto quit; goto quit;
} }
EveWrite(eve, "C3"); if (drv->h == drv->controlChan) goto skiph;
FSM_NEXT EaseWrite(eab, "A0"); /* heater off */
if (me->h == me->controlChan) goto skiph; return __LINE__; case __LINE__: /**********************************/
EveWrite(eve, "A0"); /* heater off */ drv->remote = 2;
FSM_NEXT snprintf(buf, sizeof buf, "H%d", drv->controlChan);
me->remote = 2; EaseWrite(eab, buf); /* set heater to channel */
snprintf(buf, sizeof buf, "H%d", me->controlChan); return __LINE__; case __LINE__: /**********************************/
EveWrite(eve, buf); /* set heater to channel */
FSM_NEXT
skiph: skiph:
OiSet(eve, "T", evc->fTarget, me->dig[me->controlChan]); /* set point */ OxiSet(eab, "T", drv->d.targetValue, drv->dig[drv->controlChan]); /* set point */
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
a = 1; EaseWrite(eab, "L1"); /* 'auto' pid on */
if (me->gasMode == 2) a = 3; return __LINE__; case __LINE__: /**********************************/
if (me->h == me->controlChan && me->a == a) goto skipa; a = 1; /* auto heater */
me->htrMode = 2; /* heater auto */ if (drv->a >= 2) a = 3; /* auto gas & heater */
if (me->gasMode == 2) { if (drv->d.targetValue == 0.0) {
EveWrite(eve, "A3"); /* auto gas & heater */ drv->htrMode = 0;
a = 0;
if (drv->setGas != drv->gas) {
EaseSetUpdate(drv, ITC_SETGAS, 1);
}
} else { } else {
EveWrite(eve, "A1"); /* auto heater */ drv->htrMode = 2; /* heater auto */
} }
FSM_NEXT if (drv->h == drv->controlChan && drv->a == a) goto skipa;
snprintf(buf, sizeof buf, "A%d", a);
drv->a = a;
EaseWrite(eab, buf);
return __LINE__; case __LINE__: /**********************************/
skipa: skipa:
EveWrite(eve, "C0");
FSM_NEXT if (drv->a != 0) goto quit;
me->remote = 0; EaseWrite(eab, "O0"); /* switch off heater */
wait: return __LINE__; case __LINE__: /**********************************/
pCon = SCLoad(&evc->conn);
eve->hwstate = eve->checkStatus(evc, pCon);
if (eve->hwstate != HWBusy) goto quit;
FSM_CALL(ItcRead);
goto wait;
quit: quit:
FSM_END return 0; } /* FSM END ********************************************/
} }
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
static long ItcSetGas(long pc, void *obj) { static long ItcSetGas(long pc, void *object) {
ItcDriv *me = obj; Itc *drv = ParCast(&itcClass, object);
Eve *eve=&me->eve; EaseBase *eab = object;
pEVControl evc=eve->evc;
float fld;
float step;
float ramp;
char buf[4]; char buf[4];
SConnection *pCon;
int a;
FSM_BEGIN switch (pc) { default: /* FSM BEGIN *******************************/
EveWrite(eve, "C3"); if (drv->gasMode != 1 && drv->gasMode != 2) {
FSM_NEXT ParPrintf(drv, eError, "gasMode must be set to manual or auto");
if (me->gasMode != 1) {
EvePrintf(eve, eError, "gasMode must be set to manual");
goto quit; goto quit;
} }
FSM_NEXT if (drv->a == 2) {
if (me->a == 2) { EaseWrite(eab, "A0");
EveWrite(eve, "A0"); } else if (drv->a == 3) {
} else if (me->a == 3) { EaseWrite(eab, "A1");
EveWrite(eve, "A1");
} else { } else {
goto skipmode; goto skipmode;
} }
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
skipmode: skipmode:
OiSet(eve, "G", me->gas, 1); /* cold valve setting */ OxiSet(eab, "G", drv->setGas, 1); /* cold valve setting */
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
EveWrite(eve, "C0"); EaseWrite(eab, "R7"); /* read gas flow */
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
me->remote = 0; drv->gas = OxiGet(eab, 1, NULL);
if (drv->a < 2) goto quit;
snprintf(buf, sizeof buf, "A%d", drv->a);
EaseWrite(eab, buf);
return __LINE__; case __LINE__: /**********************************/
quit: quit:
FSM_END return 0; } /* FSM END ********************************************/
} }
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
static long ItcSetHtr(long pc, void *obj) { static long ItcSetHtr(long pc, void *object) {
ItcDriv *me = obj; Itc *drv = ParCast(&itcClass, object);
Eve *eve=&me->eve; EaseBase *eab = object;
pEVControl evc=eve->evc;
float fld;
float step;
float ramp;
char buf[4]; char buf[4];
SConnection *pCon;
int a;
FSM_BEGIN switch (pc) { default: /* FSM BEGIN *******************************/
EveWrite(eve, "C3"); if (drv->a == 0) goto skipmode;
FSM_NEXT EaseWrite(eab, "A0");
if (me->htrMode != 1) { return __LINE__; case __LINE__: /**********************************/
EvePrintf(eve, eError, "htrMode must be set to manual");
goto quit;
}
if (me->a == 0) goto skipmode;
EveWrite(eve, "A0");
FSM_NEXT
skipmode: skipmode:
OiSet(eve, "O", me->htr, 1); /* manual heater setting */ OxiSet(eab, "O", drv->htr, 1); /* manual heater setting */
FSM_NEXT return __LINE__; case __LINE__: /**********************************/
EveWrite(eve, "C0"); if (drv->a == 0) goto quit;
FSM_NEXT snprintf(buf, sizeof buf, "A%d", drv->a);
me->remote = 0; EaseWrite(eab, buf);
return __LINE__; case __LINE__: /**********************************/
quit: quit:
FSM_END return 0; } /* FSM END ********************************************/
} }
/*------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
pEVControl ItcMakeEVC(SConnection *pCon, int argc, char *argv[]) { static long ItcSet(long pc, void *object) {
Itc *drv = ParCast(&itcClass, object);
EaseBase *eab = object;
int upd;
switch (pc) { default: /* FSM BEGIN *******************************/
EaseWrite(eab, "C3");
loop:
return __LINE__; case __LINE__: /**********************************/
upd = EaseNextUpdate(drv);
switch (upd) {
case EASE_RUN: FsmCall(ItcSetTemp); goto loop;
case ITC_SETHTR: FsmCall(ItcSetHtr); goto loop;
case ITC_SETGAS: FsmCall(ItcSetGas); goto loop;
default: break;
}
EaseWrite(eab, "C0");
return __LINE__; case __LINE__: /**********************************/
drv->remote = 0;
quit:
return 0; } /* FSM END ********************************************/
}
/*----------------------------------------------------------------------------*/
static int ItcInit(SConnection *con, int argc, char *argv[], int dynamic) {
/* args: /* args:
temperature itc <rs232> MakeObject objectname itc <rs232>
<host> <port> MakeObject objectname itc <host> <port>
*/ */
Eve *eve; Itc *drv;
pEVControl evc;
ItcDriv *me = NULL;
evc = MakeEveEVC(argc, argv, calloc(1, sizeof *me), pCon); drv = EaseMakeDriv(con, &itcClass, argc, argv, dynamic, 7,
if (!evc) return NULL; ItcParDef, OxiHandler, ItcStart, NULL, ItcRead,
ItcSet);
me = evc->pDriv->pPrivate; if (drv == NULL) return 0;
me->sampleChan = 1; drv->d.b.syntax = 0;
me->gasMode = 1; ParPrintf(drv, eValue, "OI Temperature Controller");
me->htrMode = 1; return 1;
eve=&me->eve; }
/*----------------------------------------------------------------------------*/
eve->run = (FsmFunc)ItcSetTemp; static int ItcInitLc(SConnection *con, int argc, char *argv[], int dynamic) {
eve->read = (FsmFunc)ItcRead; /* args:
eve->pardef = (EveParDef)ItcPars; MakeObject objectname lc <rs232>
eve->todo = (FsmFunc)ItcStart; MakeObject objectname lc <host> <port>
eve->task = FsmStartTask(me, (FsmHandler)OiHandler, (FsmFunc)EveIdle); */
Itc *drv;
/* evc->pEnvir->IsInTolerance not changed */
EVCSetPar(evc,"upperlimit",310.0,pCon); drv = EaseMakeDriv(con, &itcClass, argc, argv, dynamic, 7,
EVCSetPar(evc,"lowerlimit",1.0,pCon); ItcParDef, OxiHandler, ItcStart, NULL, ItcRead,
ItcSet);
return evc; if (drv == NULL) return 0;
drv->d.b.syntax = TESLATRON;
ParPrintf(drv, eValue, "OI Lambda Controller");
return 1;
}
/*----------------------------------------------------------------------------*/
void ItcStartup(void) {
ParMakeClass(&itcClass, EaseDrivClass());
MakeDriver("ITC", ItcInit, 0);
MakeDriver("LC", ItcInitLc, 0);
} }