diff --git a/ighdriv.c b/ighdriv.c new file mode 100644 index 0000000..4c34350 --- /dev/null +++ b/ighdriv.c @@ -0,0 +1,540 @@ +/*--------------------------------------------------------------------------- +ighdriv.c + +Driver for the Oxford Instruments IGH Intelligent gas handling system +(based on ease). + +Markus Zolliker, May 2005 +----------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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; ipdig); + 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; imv[i], PAR_NAN); + EaseUpdate(flag); flag++; + } + assert(flag == VALVE_FLAGS); + l = 0; + for (i=0; iv[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; iv[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 + MakeObject objectname igh + */ + 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); +} diff --git a/ilmdriv.c b/ilmdriv.c index c03f0c1..87f2a40 100644 --- a/ilmdriv.c +++ b/ilmdriv.c @@ -2,10 +2,10 @@ ilmdriv.c 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 #include #include @@ -20,126 +20,169 @@ Markus Zolliker, Sept 2004 #include #include #include -#include -#include #include #include -#include #include -#include "oicom.h" +#include "oxinst.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 { - Eve eve; - float lev2, lev3; - int cod1, cod2, cod3; -} IlmDriv; + EaseBase b; + float lev[3]; + Usage usage[3]; + ReadState readState[3]; +} Ilm; -char *fmts[10]={"unused", "%.1f\t%% N2", "%.1f\t%% He","%.1f\t%% He","", - "","","","","error"}; +static ParClass ilmClass = { "ILM", sizeof(Ilm) }; + +char *tails[10]={"unused", "% N2", "% He","% He","","","","","","error"}; /*----------------------------------------------------------------------------*/ -#define A EVE_ACTPAR -#define L EVE_LOGPAR -#define S EVE_EVE_SAVEPAR +static void IlmParDef(void *object) { + Ilm *drv = ParCast(&ilmClass, object); -void IlmPars(IlmDriv *me, EveParArg *arg) { - EveFloatPar(arg, "chan2", &me->lev2, fmts[me->cod2], - usInternal, (me->cod2 > 0) * A + L); - EveFloatPar(arg, "chan3", &me->lev2, fmts[me->cod3], - usInternal, (me->cod3 > 0) * A + L); - EveStdParEnd(arg, fmts[me->cod1], A+L); + ParName(""); + if (drv->usage[0]) { + ParFmt("%.1f"); ParTail(tails[drv->usage[0]]); + } + if (drv->readState[0] == NEW) { + 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; int *code; - Eve *eve=&me->eve; int i; + int status; - if (eve->state != readState) return; - ans=eve->ans; - code=&eve->errCode; + if (drv->b.state != EASE_read) return; + ans=drv->b.ans; + code=&drv->b.errCode; if (ans[0] != 'X' || ans[4] != 'S' || ans[11] != 'R') { - EvePrintf(eve, eError, "illegal status response"); - *code = EVE_FAULT; + ParPrintf(drv, eError, "illegal status response"); + *code = EASE_FAULT; return; } - for (i=1; i<3; i++) { - if (ans[i]<'0' || ans[i] > '9') ans[i]='9'; + for (i=0; i<3; i++) { + 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; } /*----------------------------------------------------------------------------*/ -static int IlmRead(long pc, IlmDriv *me) { - Eve *eve=&me->eve; +static long IlmRead(long pc, void *object) { + Ilm *drv = ParCast(&ilmClass, object); + EaseBase *eab = object; + int i; - FSM_BEGIN - EveWrite(eve, "X"); - FSM_NEXT - IlmStatus(me); /* check for errors */ - EveWrite(eve, "R1"); /* read sensor 1 */ - FSM_NEXT - me->eve.value = OiGetFlt(eve, 1, NULL); - if (me->cod2 == 0) goto skip2; - EveWrite(eve, "R2"); /* read sensor 1 */ - FSM_NEXT - me->lev2 = OiGetFlt(eve, 1, NULL); + switch (pc) { default: /* FSM BEGIN *******************************/ + EaseWrite(eab, "X"); + return __LINE__; case __LINE__: /**********************************/ + IlmStatus(drv); /* check for errors */ + EaseWrite(eab, "R1"); /* read sensor 1 */ + return __LINE__; case __LINE__: /**********************************/ + if (drv->readState[0] != MEASURING) drv->lev[0] = OxiGet(eab, 1, NULL); + if (drv->readState[0] == NOTYETREAD) drv->readState[0] = NEW; + + if (drv->usage[1] == 0) goto skip2; + 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: - if (me->cod3 == 0) goto skip3; - EveWrite(eve, "R3"); /* read sensor 1 */ - FSM_NEXT - me->lev3 = OiGetFlt(eve, 1, NULL); + if (drv->usage[2] == 0) goto skip3; + EaseWrite(eab, "R3"); /* read sensor 3 */ + return __LINE__; case __LINE__: /**********************************/ + drv->lev[2] = OxiGet(eab, 1, NULL); + if (drv->readState[2] == NOTYETREAD) drv->readState[2] = NEW; 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) { - Eve *eve=&me->eve; +static long IlmStart(long pc, void *object) { + Ilm *drv = ParCast(&ilmClass, object); + EaseBase *eab = object; - FSM_BEGIN - EveWrite(eve, "V"); - FSM_NEXT - if (0 == strncmp(eve->version, "ILM", 3)) { - me->eve.syntax = 0; - } else { - EvePrintf(eve, eError, "unknown level meter version: %s", eve->version); + switch (pc) { default: /* FSM BEGIN *******************************/ + EaseWrite(eab, "V"); + return __LINE__; case __LINE__: /**********************************/ + if (0 != strncmp(eab->version, "ILM", 3)) { + snprintf(eab->msg, sizeof eab->msg, "unknown level meter version: %s", eab->version); + ParPrintf(drv, eError, "ERROR: %s", eab->msg); + EaseStop(eab); goto quit; } - EvePrintf(eve, eStatus, "connected to %s", eve->version); - FSM_CALL(IlmRead); + ParPrintf(drv, eStatus, "connected to %s", eab->version); + eab->msg[0]='\0'; /* o.k. */ + FsmCall(IlmRead); + return __LINE__; case __LINE__: /**********************************/ 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: - temperature ilm - + MakeObject objectname ilm + */ - Eve *eve; - pEVControl evc; - IlmDriv *me = NULL; + Ilm *drv; - evc = MakeEveEVC(argc, argv, calloc(1, sizeof *me), pCon); - if (!evc) return NULL; - - me = evc->pDriv->pPrivate; - eve=&me->eve; - - eve->run = NULL; /* no run possible */ - eve->read = (FsmFunc)IlmRead; - eve->pardef = (EveParDef)IlmPars; - eve->todo = (FsmFunc)IlmStart; - eve->task = FsmStartTask(me, (FsmHandler)OiHandler, (FsmFunc)EveIdle); - - evc->pEnvir->IsInTolerance = EveAlwaysOk; - - return evc; + drv = EaseMakeBase(con, &ilmClass, argc, argv, dynamic, 0, + IlmParDef, OxiHandler, IlmStart, NULL, IlmRead); + if (drv == NULL) return 0; + ParPrintf(drv, eValue, "OI Level Meter"); + return 1; +} +/*----------------------------------------------------------------------------*/ +void IlmStartup(void) { + ParMakeClass(&ilmClass, EaseBaseClass()); + MakeDriver("ILM", IlmInit, 0); } diff --git a/ipsdriv.c b/ipsdriv.c index 5395364..95c10d3 100644 --- a/ipsdriv.c +++ b/ipsdriv.c @@ -1,9 +1,10 @@ /*--------------------------------------------------------------------------- -ipsdriv.c +ips2driv.c Driver for the Oxford Instruments IPS/PS magnet power supply. +Version 2 (based on ease). -Markus Zolliker, Sept 2004 +Markus Zolliker, May 2005 ----------------------------------------------------------------------------*/ #include #include @@ -26,103 +27,185 @@ Markus Zolliker, Sept 2004 #include #include #include -#include "oicom.h" +#include "oxinst.h" #include "fsm.h" +#include "initializer.h" typedef struct { - Eve eve; + EaseDriv d; float current; /* current (in Tesla) */ float persfield; /* persistent field from IPS (in Tesla) */ float lastfield; /* persistent field from last drive */ 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 perswitch; /* state of switch */ int remote; /* 0: local, 1: remote, do not check, 2: remote, check */ int heaterFault; + char *fmt; /* fmt for field */ 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 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; - Eve *eve=&me->eve; - if (me->eve.version[0]=='\0') return 1; /* connection not yet confirmed */ - if (me->perswitch) return 1; - if (fabs(me->persfield - me->lastfield) < 1e-5) return 1; - if (me->force != 0) return 1; - eve->errCode = EVE_FAULT; - if (!pCon) pCon = SCLoad(&eve->evc->conn); - SCPrintf(pCon, eWarning, + if (drv->d.b.msg[0] != '\0') return 1; /* connection not yet confirmed */ + if (drv->perswitch) return 1; + if (fabs(drv->persfield - drv->lastfield) < 1e-5) return 1; + if (drv->force != 0) return 1; + ParPrintf(drv, eWarning, "\nit is not sure which field is in the magnet\n" "value stored in power supply: %f\n" " in software: %f\n" "use command\n \n %s confirm ...\n \n" "to specify the persistent field\n \n" - , me->persfield, me->lastfield, eve->evc->pName); - me->force = 0; + , drv->persfield, drv->lastfield, drv->d.b.p.name); + drv->force = 0; return 0; } /*----------------------------------------------------------------------------*/ -#define A EVE_ACTPAR -#define L EVE_LOGPAR -#define S EVE_SAVEPAR - -void IpsPars(IpsDriv *me, EveParArg *arg) { - EveIntPar(arg, "persmode", &me->persmode, usUser, A+S); - EveIntPar(arg, "perswitch", &me->perswitch, usInternal, A); - EveObPar(arg, UPLIMIT, "%.5g\tTesla", A+S); - EveFloatPar(arg, "ramp", &me->ramp, "%.5g\tTesla/min", usUser, A+S); - EveFloatPar(arg, "current", &me->current, "%.5g\tTesla", usInternal, A+L); - EveFloatPar(arg, "lastfield", &me->lastfield, "%.5g\tTesla", usInternal, S); - EveCmd(arg, "confirm", IpsConfirm, usUser); - EveStdParEnd(arg, "%.5g\tTesla", A+L+S); - if (EveUserAction(arg)) { - IpsOk(me, EveArgConn(arg)); +static int IpsConfirm(void *object, void *userarg, int argc, char *argv[]) +{ + Ips *drv = ParCast(&ipsClass, object); + float fld; + + assert(drv); + if (argc > 0) { + if (argc > 1) { + ParPrintf(object, eError, "Too many arguments"); + return 0; + } + fld=atof(argv[0]); + if (fld > drv->d.upperLimit || fld < drv->d.lowerLimit) { + ParPrintf(object, eError, "Field outside limit"); + 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; int *code; - Eve *eve=&me->eve; int swi; - if (eve->state != readState) return; - ans=eve->ans; - code=&eve->errCode; + if (drv->d.b.state != EASE_read) return; + ans=drv->d.b.ans; + code=&drv->d.b.errCode; if (ans[0] != 'X' || ans[3] != 'A' || ans[5] != 'C' || ans[7] != 'H' || ans[9] != 'M') { - EvePrintf(eve, eError, "illegal status response"); - *code = EVE_FAULT; + ParPrintf(drv, eError, "illegal status response"); + *code = EASE_FAULT; return; } switch (ans[1]) { case '0': break; - case '1': EvePrintf(eve, eError, "magnet quenched"); *code = EVE_FAULT; return; - case '2': EvePrintf(eve, eError, "IPS overheated"); *code = EVE_FAULT; return; - case '4': EvePrintf(eve, eError, "IPS warming up"); *code = EVE_FAULT; return; - case '8': EvePrintf(eve, eError, "IPS fault"); *code = EVE_FAULT; return; + case '1': ParPrintf(drv, eError, "magnet quenched"); *code = EASE_FAULT; return; + case '2': ParPrintf(drv, eError, "IPS overheated"); *code = EASE_FAULT; return; + case '4': ParPrintf(drv, eError, "IPS warming up"); *code = EASE_FAULT; return; + case '8': ParPrintf(drv, eError, "IPS fault"); *code = EASE_FAULT; return; default: - EvePrintf(eve, eError, "illegal status response"); - *code = EVE_FAULT; + ParPrintf(drv, eError, "illegal status response"); + *code = EASE_FAULT; return; } - if (ans[6] != '3' && me->remote == 2) { - EvePrintf(eve, eError, "IPS switched to local"); - *code = EVE_FAULT; - me->remote = 1; - return; + if (ans[6] != '3') { + if (drv->remote == 2) { + ParPrintf(drv, eError, "IPS switched to local"); + *code = EASE_FAULT; + 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') { - me->heaterFault = 1; + drv->heaterFault = 1; return; } if (ans[8] == '1') { @@ -130,346 +213,292 @@ void IpsStatus(IpsDriv *me) { } else { swi = 0; } - if (swi != me->perswitch || me->swtim == 0) { - me->swtim = time(NULL); - me->perswitch = swi; + if (swi != drv->perswitch || drv->swtim == 0) { + drv->swtim = time(NULL); + drv->perswitch = swi; } } /*----------------------------------------------------------------------------*/ -static void IpsSetField(IpsDriv *me, float val) { - char buf[128]; - SConnection *pCon; - - if (me->eve.value != val && me->eve.evc != NULL) { - snprintf(buf, sizeof(buf), "%s = %g", me->eve.evc->pName, val); - InvokeCallBack(me->eve.evc->pCall, VALUECHANGE, buf); - 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; +static void IpsSetField(Ips *drv, float val) { + ParLog(drv); + if (drv->perswitch) { + drv->current = val; + drv->lastfield = val; + drv->persfield = val; + EaseParHasChanged(); } else { - me->persfield = val; + drv->persfield = val; } - me->eve.value = val; } /*----------------------------------------------------------------------------*/ -static int IpsRead(long pc, IpsDriv *me) { - Eve *eve=&me->eve; - - FSM_BEGIN - EveWrite(eve, "X"); - FSM_NEXT - IpsStatus(me); /* check for errors and get perswitch */ -/* - if (!me->remote) goto rd; - EveWrite(eve, "C0"); - me->remote = 0; - FSM_NEXT -*/ +static long IpsRead(long pc, void *object) { + Ips *drv = ParCast(&ipsClass, object); + EaseBase *eab = object; + + switch (pc) { default: /* FSM BEGIN *******************************/ + EaseWrite(eab, "X"); + return __LINE__; case __LINE__: /**********************************/ + IpsStatus(drv); rd: - EveWrite(eve, "R7"); /* read current (in Tesla) */ - FSM_NEXT - me->current = OiGetFlt(eve, 3, NULL); - if (me->perswitch) { - IpsSetField(me, me->current); + EaseWrite(eab, "R7"); /* read current (in Tesla) */ + return __LINE__; case __LINE__: /**********************************/ + drv->current = OxiGet(eab, 3, NULL); + if (drv->perswitch) { + IpsSetField(drv, drv->current); goto quit; } - EveWrite(eve, "R18"); /* read persistant field (in Tesla) */ - FSM_NEXT - IpsSetField(me, OiGetFlt(eve, 3, NULL)); + EaseWrite(eab, "R18"); /* read persistant field (in Tesla) */ + return __LINE__; case __LINE__: /**********************************/ + IpsSetField(drv, OxiGet(eab, 3, NULL)); quit: - EveLog(eve); - FSM_END + ParLog(drv); + return 0; } /* FSM END ********************************************/ + } /*----------------------------------------------------------------------------*/ -static int IpsStart(long pc, IpsDriv *me) { - Eve *eve=&me->eve; +static long IpsStart(long pc, void *object) { + Ips *drv = ParCast(&ipsClass, object); + EaseBase *eab = object; - FSM_BEGIN - EveWrite(eve, "V"); - FSM_NEXT - if (0 == strncmp(eve->version, "IPS120", 6)) { - me->eve.syntax = 1; - } else if (0 == strncmp(eve->version, "PS", 2)) { - me->eve.syntax = 0; + switch (pc) { default: /* FSM BEGIN *******************************/ + EaseWrite(eab, "V"); + return __LINE__; case __LINE__: /**********************************/ + if (0 == strncmp(eab->version, "IPS120", 6)) { + eab->syntax = 1; + } else if (0 == strncmp(eab->version, "PS", 2)) { + eab->syntax = 0; } 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; } - EvePrintf(eve, eStatus, "connected to %s", eve->version); - FSM_CALL(IpsRead); - + ParPrintf(drv, eStatus, "connected to %s", eab->version); + if (eab->syntax) { + drv->fmt = "%.4f"; + } else { + drv->fmt = "%.3f"; + } + FsmCall(IpsRead); + return __LINE__; case __LINE__: /**********************************/ + quit: - FSM_END + return 0; } /* FSM END ********************************************/ + } /*----------------------------------------------------------------------------*/ -static int IpsChangeField(long pc, IpsDriv *me) { - Eve *eve=&me->eve; - pEVControl evc=eve->evc; +static long IpsChangeField(long pc, void *object) { + Ips *drv = ParCast(&ipsClass, object); + EaseBase *eab = object; float fld; float step; float ramp; time_t delay; - FSM_BEGIN - EveWrite(eve, "C3"); - me->remote = 1; - FSM_NEXT - EveWrite(eve, "F7"); /* switch to tesla on display */ - FSM_NEXT - EveWrite(eve, "A0"); /* hold */ - FSM_NEXT - FSM_CALL(IpsRead); - me->remote = 2; - if (!IpsOk(me, NULL)) goto finish; - if (fabs(evc->fTarget - me->lastfield) < 1e-5) { - EvePrintf(eve, -1, "IPS: we are already at field %f", me->lastfield); - if (me->persmode) { - if (!me->perswitch) goto finish; + switch (pc) { default: /* FSM BEGIN *******************************/ + EaseSetUpdate(eab, EASE_RUN, 0); + EaseWrite(eab, "C3"); + drv->remote = 1; + return __LINE__; case __LINE__: /**********************************/ + EaseWrite(eab, "F7"); /* switch to tesla on display */ + return __LINE__; case __LINE__: /**********************************/ + EaseWrite(eab, "A0"); /* hold */ + return __LINE__; case __LINE__: /**********************************/ + FsmCall(IpsRead); + return __LINE__; case __LINE__: /**********************************/ + drv->remote = 2; + if (!IpsOk(drv)) goto finish; + if (fabs(drv->d.targetValue - drv->lastfield) < 1e-5) { + ParPrintf(drv, -1, "IPS: we are already at field %f", drv->lastfield); + if (drv->persmode) { + if (!drv->perswitch) goto finish; goto target_reached; } 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; } - OiSet(eve, "J", me->lastfield, 3); /* set point */ - FSM_NEXT - EveWrite(eve, "A1"); - EvePrintf(eve, -1, "IPS: ramp to current for %f Tesla", me->lastfield); - FSM_NEXT - me->tim = time(NULL); + OxiSet(eab, "J", drv->lastfield, 3); /* set point */ + return __LINE__; case __LINE__: /**********************************/ + EaseWrite(eab, "A1"); + ParPrintf(drv, -1, "IPS: ramp to current for %f Tesla", drv->lastfield); + return __LINE__; case __LINE__: /**********************************/ + drv->tim = time(NULL); stab1: - EveWrite(eve, "X"); - FSM_NEXT - IpsStatus(me); /* just check for errors */ - EveWrite(eve, "R7"); /* read current (in Tesla) */ - FSM_NEXT - me->current = OiGetFlt(eve, 3, NULL); - EveLog(eve); - if (fabs(me->current - me->lastfield) > 1e-5) goto stab1; + EaseWrite(eab, "X"); + return __LINE__; case __LINE__: /**********************************/ + IpsStatus(drv); /* just check for errors */ + EaseWrite(eab, "R7"); /* read current (in Tesla) */ + return __LINE__; case __LINE__: /**********************************/ + drv->current = OxiGet(eab, 3, NULL); + ParLog(drv); + if (fabs(drv->current - drv->lastfield) > 1e-5) goto stab1; stab2: - FSM_WAIT(1) - EveWrite(eve, "X"); - FSM_NEXT - IpsStatus(me); - if (time(NULL) < me->tim + 10) goto stab2; /* stabilize */ + FsmWait(1); + return __LINE__; case __LINE__: /**********************************/ + EaseWrite(eab, "X"); + return __LINE__; case __LINE__: /**********************************/ + IpsStatus(drv); + if (time(NULL) < drv->tim + 10) goto stab2; /* stabilize */ switch_on: - if (me->perswitch) goto wait_open; - if (me->force == 2) { - EveWrite(eve, "H2"); + if (drv->perswitch) goto wait_open; + if (drv->force == 2) { + EaseWrite(eab, "H2"); } else { - EveWrite(eve, "H1"); + EaseWrite(eab, "H1"); } - me->force = 0; - FSM_NEXT - me->perswitch = 1; - me->swtim = time(NULL); + drv->force = 0; + return __LINE__; case __LINE__: /**********************************/ + drv->perswitch = 1; + drv->swtim = time(NULL); wait_open: - delay = me->swtim + 30 - time(NULL); + delay = drv->swtim + 30 - time(NULL); 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: - FSM_WAIT(1) - EveWrite(eve, "X"); - FSM_NEXT - IpsStatus(me); /* check for errors */ - if (me->heaterFault) { - if (time(NULL) > me->swtim + 3) { - EvePrintf(eve, eError, "IPS heater fault"); - eve->errCode = EVE_FAULT; + FsmWait(1); + return __LINE__; case __LINE__: /**********************************/ + EaseWrite(eab, "X"); + return __LINE__; case __LINE__: /**********************************/ + IpsStatus(drv); /* check for errors */ + if (drv->heaterFault) { + if (time(NULL) > drv->swtim + 3) { + ParPrintf(drv, eError, "IPS heater fault"); + eab->errCode = EASE_FAULT; goto off_finish; } - me->heaterFault = 0; + drv->heaterFault = 0; } - if (time(NULL) < me->swtim + 30) goto start_ramp; /* wait */ - OiSet(eve, "T", me->ramp, 3); - FSM_NEXT - OiSet(eve, "J", me->current, 3); /* put set point to actual value */ - FSM_NEXT - EveWrite(eve, "A1"); /* go to setpoint (do not yet run) */ - FSM_NEXT - EvePrintf(eve, -1, "IPS: ramp to %f Tesla", evc->fTarget); + if (time(NULL) < drv->swtim + 30) goto start_ramp; /* wait */ + OxiSet(eab, "T", drv->ramp, 3); + return __LINE__; case __LINE__: /**********************************/ + OxiSet(eab, "J", drv->current, 3); /* put set point to actual value */ + return __LINE__; case __LINE__: /**********************************/ + EaseWrite(eab, "A1"); /* go to setpoint (do not yet run) */ + return __LINE__; case __LINE__: /**********************************/ + ParPrintf(drv, -1, "IPS: ramp to %f Tesla", drv->d.targetValue); ramping: - FSM_WAIT(1) - EveWrite(eve, "R7"); /* read "current" in Tesla */ - FSM_NEXT - IpsSetField(me, OiGetFlt(eve, 3, NULL)); /* set me->current and callback */ - EveWrite(eve, "X"); - FSM_NEXT - IpsStatus(me); /* just check for errors */ - EveWrite(eve, "R9"); /* read back ramp rate (may be sweep limited) */ - FSM_NEXT - ramp=OiGetFlt(eve, 3, NULL); + FsmWait(1); + return __LINE__; case __LINE__: /**********************************/ + EaseWrite(eab, "R7"); /* read "current" in Tesla */ + return __LINE__; case __LINE__: /**********************************/ + IpsSetField(drv, OxiGet(eab, 3, NULL)); /* set drv->current and callback */ + EaseWrite(eab, "X"); + return __LINE__; case __LINE__: /**********************************/ + IpsStatus(drv); /* just check for errors */ + EaseWrite(eab, "R9"); /* read back ramp rate (may be sweep limited) */ + return __LINE__; case __LINE__: /**********************************/ + ramp=OxiGet(eab, 3, NULL); step=ramp/20; /* step = ramp * 3sec */ if (step < 0.001) step=0.001; - if (evc->fTarget > me->current + step) { - fld=me->current + step; - } else if (evc->fTarget < me->current - step) { - fld=me->current - step; + if (drv->d.targetValue > drv->current + step) { + fld=drv->current + step; + } else if (drv->d.targetValue < drv->current - step) { + fld=drv->current - step; } else { - fld=evc->fTarget; - if (fabs(me->current - evc->fTarget) < 1e-5) goto target_reached; + fld=drv->d.targetValue; + if (fabs(drv->current - drv->d.targetValue) < 1e-5) goto target_reached; } - OiSet(eve, "J", fld, 3); - FSM_NEXT - EveLog(eve); + OxiSet(eab, "J", fld, 3); + return __LINE__; case __LINE__: /**********************************/ + ParLog(drv); goto ramping; target_reached: - eve->hwstate = HWIdle; - evc->eMode = EVMonitor; - /* we are at field, drive has finished, but we continue in the background */ - me->tim = time(NULL); + drv->d.hwstate = HWIdle; + drv->d.eMode = EVMonitor; /* we are at field, drive has finished */ + if (!drv->persmode) goto hold_finish; + /* but we continue in the background */ + drv->tim = time(NULL); stab3: - FSM_WAIT(1) - EveWrite(eve, "R18"); /* read persistant field in Tesla */ - FSM_NEXT - IpsSetField(me, OiGetFlt(eve, 3, NULL)); - me->lastfield = me->persfield; - EveWrite(eve, "X"); - FSM_NEXT - IpsStatus(me); /* just check for errors */ - if (time(NULL) < me->tim + 10) goto stab3; /* stabilize */ - - EveWrite(eve, "A0"); /* hold */ - FSM_NEXT - if (!me->persmode) goto finish; - - EveWrite(eve, "H0"); - me->perswitch = 0; - me->swtim = time(NULL); - me->lastfield = me->current; - FSM_NEXT - EvePrintf(eve, -1, "IPS: wait 30 sec to close switch"); + FsmWait(1); + return __LINE__; case __LINE__: /**********************************/ + EaseWrite(eab, "X"); + return __LINE__; case __LINE__: /**********************************/ + IpsStatus(drv); /* just check for errors */ + if (time(NULL) < drv->tim + 10) goto stab3; /* stabilize */ + + EaseWrite(eab, "A0"); /* hold */ + return __LINE__; case __LINE__: /**********************************/ + EaseWrite(eab, "H0"); + drv->perswitch = 0; + drv->swtim = time(NULL); + drv->lastfield = drv->current; + EaseParHasChanged(); + return __LINE__; case __LINE__: /**********************************/ + ParPrintf(drv, -1, "IPS: wait 30 sec to close switch"); wait_closed: - EveWrite(eve, "R18"); /* read persistant field in Tesla */ - FSM_NEXT - IpsSetField(me, OiGetFlt(eve, 3, NULL)); - me->lastfield = me->persfield; - FSM_WAIT(1) - EveWrite(eve, "X"); - FSM_NEXT - IpsStatus(me); - if (time(NULL) < me->swtim + 30) goto wait_closed; /* wait */ + FsmWait(1); + return __LINE__; case __LINE__: /**********************************/ + EaseWrite(eab, "R18"); /* read persistent field in Tesla */ + return __LINE__; case __LINE__: /**********************************/ + fld = OxiGet(eab, 3, NULL); + if (fld != drv->lastfield) { + IpsSetField(drv, fld); /* set drv->current and callback */ + drv->lastfield = fld; + 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; - EveWrite(eve, "A2"); /* goto zero */ - EvePrintf(eve, -1, "IPS: ramp current to 0"); - FSM_NEXT + if (drv->current == 0) goto finish; + EaseWrite(eab, "A2"); /* goto zero */ + ParPrintf(drv, -1, "IPS: ramp current to 0"); + return __LINE__; case __LINE__: /**********************************/ goto finish; + hold_finish: + EaseWrite(eab, "A0"); + return __LINE__; case __LINE__: /**********************************/ + goto finish; + off_finish: - if (me->perswitch) { - me->lastfield = me->current; - me->swtim = time(NULL); + if (drv->perswitch) { + drv->lastfield = drv->current; + drv->swtim = time(NULL); } - EveWrite(eve, "H0"); - FSM_NEXT + EaseWrite(eab, "H0"); + return __LINE__; case __LINE__: /**********************************/ finish: - EveWrite(eve, "C0"); - me->remote = 0; - eve->hwstate = HWIdle; - FSM_NEXT + EaseWrite(eab, "C0"); + drv->remote = 0; + drv->d.hwstate = HWIdle; + return __LINE__; case __LINE__: /**********************************/ - FSM_END + return 0; } /* FSM END ********************************************/ + } /*----------------------------------------------------------------------------*/ -int IpsConfirm(SConnection *pCon, pEVControl evc, int argc, char *argv[]) { - 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[]) { +static int IpsInit(SConnection *con, int argc, char *argv[], int dynamic) { /* args: - ips - ips - */ - IpsDriv *me; - Eve *eve; - pEVControl evc; + MakeObject objectname ips + + */ + Ips *drv; - evc = MakeEveEVC(argc, argv, calloc(1, sizeof *me), pCon); - if (!evc) return NULL; - - me = evc->pDriv->pPrivate; - eve=&me->eve; - - me->current = 0; - me->persfield = 0; - me->lastfield = 0; - me->persmode = 1; - me->perswitch = 0; - me->force = 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; + drv = EaseMakeDriv(con, &ipsClass, argc, argv, dynamic, 7, + IpsParDef, OxiHandler, IpsStart, NULL, IpsRead, + IpsChangeField); + if (drv == NULL) return 0; + ParPrintf(drv, eValue, "OI Power Supply"); + drv->d.maxwait = 999999; + return 1; +} +/*----------------------------------------------------------------------------*/ +void IpsStartup(void) { + ParMakeClass(&ipsClass, EaseDrivClass()); + MakeDriver("IPS", IpsInit, 0); } diff --git a/itcdriv.c b/itcdriv.c index c12a18e..d52350e 100644 --- a/itcdriv.c +++ b/itcdriv.c @@ -2,8 +2,9 @@ itcdriv.c Driver for the Oxford Instruments ITC503/ITC4 temperature controller - -Markus Zolliker, Sept 2004 +Version 2 (based on ease). + +Markus Zolliker, May 2005 ----------------------------------------------------------------------------*/ #include #include @@ -26,15 +27,22 @@ Markus Zolliker, Sept 2004 #include #include #include -#include "oicom.h" +#include "oxinst.h" #include "fsm.h" +#include "initializer.h" + +#define TESLATRON -1 +#define ITC_SETHTR 1 +#define ITC_SETGAS 2 typedef struct { - Eve eve; - float t[4]; /* temperatures (0 unused) */ + EaseDriv d; + float t[4]; /* temperatures (0 is set point) */ int dig[4]; /* format for these */ float htr; float gas; + float autoGasLimit; + float setGas; int sampleChan; int controlChan; int gasMode; @@ -42,310 +50,470 @@ typedef struct { int remote; int h; /* actual heater channel */ 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 -#define L EVE_LOGPAR -#define S EVE_SAVEPAR +static void ItcParDef(void *object) { + Itc *drv = ParCast(&itcClass, object); + EaseBase *eab = object; -void ItcPars(ItcDriv *me, EveParArg *arg) { char fmt[8]=""; int i; - int flag; - char *ti[4] = {"setp","t1","t2","t3"}; + static char *ti[4] = {"setp","t1","t2","t3"}; static char *modeList[]={"off", "manual", "auto", NULL }; - EveStdPar(arg); - - flag = me->controlChan != 0 && fabsf(me->eve.evc->fTarget - me->t[0]) > 9e-4; - sprintf(fmt, "%%.%df\tK", me->dig[me->controlChan]); - EveFloatPar(arg, ti[0], &me->t[0], fmt, usInternal, flag*A + L); - + ParName("sampleChan"); + if (eab->syntax != TESLATRON) ParAccess(usUser); + ParInt(&drv->sampleChan, 1); + if (ParActionIs(PAR_SET) > 0) { + 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++) { - flag = (me->dig[i] >= 0) && (me->sampleChan != i); - sprintf(fmt, "%%.%df\tK", me->dig[i]); - EveFloatPar(arg, ti[i], &me->t[i], fmt, usInternal, flag*A + L); + + ParName(ti[i]); + 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; - EveEnumPar(arg, "htrMode", &me->htrMode, modeList, usUser, A+S); - EveFloatCmd(arg, "htr", &me->htr, "%.1f\t%%", ItcSetHtr, usUser, flag*A + L); - EveEnumPar(arg, "gasMode", &me->gasMode, modeList, usUser, A+S); - flag = me->gasMode > 0; - EveFloatCmd(arg, "gas", &me->gas, "%.1f\t%%", ItcSetGas, usUser, flag*A + L); - EveIntPar(arg, "dig1", &me->dig[1], usUser, S); - EveIntPar(arg, "dig2", &me->dig[2], usUser, S); - EveIntPar(arg, "dig3", &me->dig[3], usUser, S); - EveIntPar(arg, "sampleChan", &me->sampleChan, usUser, A+S); - EveIntPar(arg, "controlChan", &me->controlChan, usUser, A+S); - sprintf(fmt, "%%.%df\tK", me->dig[me->sampleChan]); - EveStdParEnd(arg, fmt, A+L); + if (eab->syntax != TESLATRON) { + ParName("htrMode"); + if (drv->controlChan == 0 && drv->htr == 0) { + ParList(""); + } + ParEnum(modeList); ParSave(1); + ParInt(&drv->htrMode, 2); + + ParName("htr"); + ParFmt("%.1f"); ParTail("%"); + ParSave(1); + EaseUpdate(ITC_SETHTR); + 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; int *code; - Eve *eve=&me->eve; - if (eve->state != readState) return; - ans=eve->ans; - code=&eve->errCode; + 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] != 'S') { - EvePrintf(eve, eError, "illegal status response"); - *code = EVE_FAULT; + ParPrintf(drv, eError, "illegal status response"); + *code = EASE_FAULT; return; } - me->a = ans[3] - '0'; + drv->a = ans[3] - '0'; if (ans[9] == 'H') { - me->h = ans[10] - '0'; + drv->h = ans[10] - '0'; } else { - me->h = me->controlChan; + drv->h = drv->controlChan; } - if (ans[6] != '3' && me->remote == 2) { - EvePrintf(eve, eError, "ITC switched to local"); - *code = EVE_FAULT; - me->remote = 1; + if (ans[6] != '3' && drv->remote == 2) { + ParPrintf(drv, eError, "ITC switched to local"); + *code = EASE_FAULT; + drv->remote = 1; return; } } /*----------------------------------------------------------------------------*/ -static long ItcRead(long pc, ItcDriv *me) { - Eve *eve=&me->eve; +static long ItcRead(long pc, void *object) { + Itc *drv = ParCast(&itcClass, object); + EaseBase *eab = object; char *p; int l; + char buf[4]; - FSM_BEGIN - EveWrite(eve, "X"); - FSM_NEXT - ItcStatus(me); /* check for errors */ - if (!me->remote) goto skiprmt; - EveWrite(eve, "C0"); - me->remote = 0; - FSM_NEXT - - 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]); + switch (pc) { default: /* FSM BEGIN *******************************/ + EaseWrite(eab, "X"); + return __LINE__; case __LINE__: /**********************************/ + ItcStatus(drv); /* check for errors */ + + if (drv->dig[1] < 0) goto skip1; + EaseWrite(eab, "R1"); /* read sensor 1 */ + return __LINE__; case __LINE__: /**********************************/ + drv->t[1] = OxiGet(eab, drv->dig[1], &drv->dig[1]); skip1: - if (me->dig[2] < 0) goto skip2; - EveWrite(eve, "R2"); /* read sensor 2 */ - FSM_NEXT - me->t[2] = OiGetFlt(eve, me->dig[2], &me->dig[2]); + if (drv->dig[2] < 0) goto skip2; + EaseWrite(eab, "R2"); /* read sensor 2 */ + return __LINE__; case __LINE__: /**********************************/ + drv->t[2] = OxiGet(eab, drv->dig[2], &drv->dig[2]); skip2: - if (me->dig[3] < 0) goto skip3; - EveWrite(eve, "R3"); /* read sensor 3 */ - FSM_NEXT - me->t[3] = OiGetFlt(eve, me->dig[3], &me->dig[3]); + if (drv->dig[3] < 0) goto skip3; + EaseWrite(eab, "R3"); /* read sensor 3 */ + return __LINE__; case __LINE__: /**********************************/ + drv->t[3] = OxiGet(eab, drv->dig[3], &drv->dig[3]); skip3: - me->eve.value = me->t[me->sampleChan]; - if (me->controlChan == 0 || me->a) { - me->t[0] = me->eve.evc->fTarget; + if (drv->controlChan == 0 || drv->a == 0) { + drv->t[0] = drv->d.targetValue; goto skip0; } - EveWrite(eve, "R0"); /* read control T */ - FSM_NEXT - me->t[0] = OiGetFlt(eve, me->dig[me->controlChan], NULL); - - if (me->htrMode != 2 && me->a % 2 == 0) goto skiphtr; + EaseWrite(eab, "R0"); /* read control T */ + return __LINE__; case __LINE__: /**********************************/ + drv->t[0] = OxiGet(eab, drv->dig[drv->controlChan], NULL); + if (drv->gasMode == 2) { + 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: - EveWrite(eve, "R5"); /* read heater */ - FSM_NEXT - me->htr = OiGetFlt(eve, 1, NULL); - skiphtr: - if (me->gasMode != 2 && me->a < 2) goto skipgas; - EveWrite(eve, "R7"); /* read gas flow */ - FSM_NEXT - me->gas = OiGetFlt(eve, 1, NULL); + + if (!drv->remote) goto skiprmt; + EaseWrite(eab, "C0"); + drv->remote = 0; + return __LINE__; case __LINE__: /**********************************/ + skiprmt: + 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: - me->eve.value = me->t[me->sampleChan]; - EveLog(eve); - FSM_END + + ParLog(drv); + fsm_quit: return 0; } /* FSM END *********************************/ } /*----------------------------------------------------------------------------*/ -static long ItcStart(long pc, ItcDriv *me) { - Eve *eve=&me->eve; +static long ItcStart(long pc, void *object) { + Itc *drv = ParCast(&itcClass, object); + EaseBase *eab = object; - FSM_BEGIN - EveWrite(eve, "V"); - FSM_NEXT - if (0 == strncmp(eve->version, "ITC503", 6)) { - me->eve.syntax = 3; - } else if (0 == strncmp(eve->version, "ITC4", 4)) { - me->eve.syntax = 0; + switch (pc) { default: /* FSM BEGIN *******************************/ + EaseWrite(eab, "V"); + return __LINE__; case __LINE__: /**********************************/ + if (eab->syntax == TESLATRON) { + if (0 != strncmp(eab->version, "TESLATRON", 9)) { + snprintf(eab->msg, sizeof eab->msg, "unknown teslatron version: %s", + eab->version); + ParPrintf(drv, eError, "ERROR: %s", eab->msg); + EaseStop(eab); + goto quit; + } } else { - EvePrintf(eve, eError, "unknown temperature controller version: %s", eve->version); - goto quit; + if (0 == strncmp(eab->version, "ITC503", 6)) { + 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); - if (me->controlChan == 0 && me->h >= 1 && me->h <= 3) { - me->controlChan = me->h; + ParPrintf(drv, eStatus, "connected to %s", eab->version); + if (drv->controlChan == 0 && drv->h >= 1 && drv->h <= 3) { + drv->controlChan = drv->h; } - FSM_CALL(ItcRead); + FsmCall(ItcRead); + return __LINE__; case __LINE__: /**********************************/ quit: - FSM_END + return 0; } /* FSM END ********************************************/ } /*----------------------------------------------------------------------------*/ -static long ItcSetTemp(long pc, ItcDriv *me) { - Eve *eve=&me->eve; - pEVControl evc=eve->evc; - float fld; - float step; - float ramp; +static long ItcSetTemp(long pc, void *object) { + Itc *drv = ParCast(&itcClass, object); + EaseBase *eab = object; char buf[4]; - SConnection *pCon; int a; - FSM_BEGIN - if (me->controlChan == 0) { - EvePrintf(eve, eError, "no control channel selected"); + switch (pc) { default: /* FSM BEGIN *******************************/ + if (drv->controlChan == 0) { + ParPrintf(drv, eError, "no control channel selected"); goto quit; } - EveWrite(eve, "C3"); - FSM_NEXT - if (me->h == me->controlChan) goto skiph; - EveWrite(eve, "A0"); /* heater off */ - FSM_NEXT - me->remote = 2; - snprintf(buf, sizeof buf, "H%d", me->controlChan); - EveWrite(eve, buf); /* set heater to channel */ - FSM_NEXT + if (drv->h == drv->controlChan) goto skiph; + EaseWrite(eab, "A0"); /* heater off */ + return __LINE__; case __LINE__: /**********************************/ + drv->remote = 2; + snprintf(buf, sizeof buf, "H%d", drv->controlChan); + EaseWrite(eab, buf); /* set heater to channel */ + return __LINE__; case __LINE__: /**********************************/ skiph: - OiSet(eve, "T", evc->fTarget, me->dig[me->controlChan]); /* set point */ - FSM_NEXT - a = 1; - if (me->gasMode == 2) a = 3; - if (me->h == me->controlChan && me->a == a) goto skipa; - me->htrMode = 2; /* heater auto */ - if (me->gasMode == 2) { - EveWrite(eve, "A3"); /* auto gas & heater */ + OxiSet(eab, "T", drv->d.targetValue, drv->dig[drv->controlChan]); /* set point */ + return __LINE__; case __LINE__: /**********************************/ + EaseWrite(eab, "L1"); /* 'auto' pid on */ + return __LINE__; case __LINE__: /**********************************/ + a = 1; /* auto heater */ + if (drv->a >= 2) a = 3; /* auto gas & heater */ + if (drv->d.targetValue == 0.0) { + drv->htrMode = 0; + a = 0; + if (drv->setGas != drv->gas) { + EaseSetUpdate(drv, ITC_SETGAS, 1); + } } 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: - EveWrite(eve, "C0"); - FSM_NEXT - me->remote = 0; - wait: - pCon = SCLoad(&evc->conn); - eve->hwstate = eve->checkStatus(evc, pCon); - if (eve->hwstate != HWBusy) goto quit; - FSM_CALL(ItcRead); - goto wait; + + if (drv->a != 0) goto quit; + EaseWrite(eab, "O0"); /* switch off heater */ + return __LINE__; case __LINE__: /**********************************/ + quit: - FSM_END + return 0; } /* FSM END ********************************************/ } /*----------------------------------------------------------------------------*/ -static long ItcSetGas(long pc, void *obj) { - ItcDriv *me = obj; - Eve *eve=&me->eve; - pEVControl evc=eve->evc; - float fld; - float step; - float ramp; +static long ItcSetGas(long pc, void *object) { + Itc *drv = ParCast(&itcClass, object); + EaseBase *eab = object; char buf[4]; - SConnection *pCon; - int a; - FSM_BEGIN - EveWrite(eve, "C3"); - FSM_NEXT - if (me->gasMode != 1) { - EvePrintf(eve, eError, "gasMode must be set to manual"); + switch (pc) { default: /* FSM BEGIN *******************************/ + if (drv->gasMode != 1 && drv->gasMode != 2) { + ParPrintf(drv, eError, "gasMode must be set to manual or auto"); goto quit; } - FSM_NEXT - if (me->a == 2) { - EveWrite(eve, "A0"); - } else if (me->a == 3) { - EveWrite(eve, "A1"); + if (drv->a == 2) { + EaseWrite(eab, "A0"); + } else if (drv->a == 3) { + EaseWrite(eab, "A1"); } else { goto skipmode; } - FSM_NEXT + return __LINE__; case __LINE__: /**********************************/ skipmode: - OiSet(eve, "G", me->gas, 1); /* cold valve setting */ - FSM_NEXT - EveWrite(eve, "C0"); - FSM_NEXT - me->remote = 0; + OxiSet(eab, "G", drv->setGas, 1); /* cold valve setting */ + return __LINE__; case __LINE__: /**********************************/ + EaseWrite(eab, "R7"); /* read gas flow */ + return __LINE__; case __LINE__: /**********************************/ + 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: - FSM_END + return 0; } /* FSM END ********************************************/ } /*----------------------------------------------------------------------------*/ -static long ItcSetHtr(long pc, void *obj) { - ItcDriv *me = obj; - Eve *eve=&me->eve; - pEVControl evc=eve->evc; - float fld; - float step; - float ramp; +static long ItcSetHtr(long pc, void *object) { + Itc *drv = ParCast(&itcClass, object); + EaseBase *eab = object; char buf[4]; - SConnection *pCon; - int a; - FSM_BEGIN - EveWrite(eve, "C3"); - FSM_NEXT - if (me->htrMode != 1) { - EvePrintf(eve, eError, "htrMode must be set to manual"); - goto quit; - } - if (me->a == 0) goto skipmode; - EveWrite(eve, "A0"); - FSM_NEXT + switch (pc) { default: /* FSM BEGIN *******************************/ + if (drv->a == 0) goto skipmode; + EaseWrite(eab, "A0"); + return __LINE__; case __LINE__: /**********************************/ skipmode: - OiSet(eve, "O", me->htr, 1); /* manual heater setting */ - FSM_NEXT - EveWrite(eve, "C0"); - FSM_NEXT - me->remote = 0; + OxiSet(eab, "O", drv->htr, 1); /* manual heater setting */ + return __LINE__; case __LINE__: /**********************************/ + if (drv->a == 0) goto quit; + snprintf(buf, sizeof buf, "A%d", drv->a); + EaseWrite(eab, buf); + return __LINE__; case __LINE__: /**********************************/ 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: - temperature itc - + MakeObject objectname itc + MakeObject objectname itc */ - Eve *eve; - pEVControl evc; - ItcDriv *me = NULL; + Itc *drv; - evc = MakeEveEVC(argc, argv, calloc(1, sizeof *me), pCon); - if (!evc) return NULL; - - me = evc->pDriv->pPrivate; - me->sampleChan = 1; - me->gasMode = 1; - me->htrMode = 1; - eve=&me->eve; - - eve->run = (FsmFunc)ItcSetTemp; - eve->read = (FsmFunc)ItcRead; - eve->pardef = (EveParDef)ItcPars; - eve->todo = (FsmFunc)ItcStart; - eve->task = FsmStartTask(me, (FsmHandler)OiHandler, (FsmFunc)EveIdle); - - /* evc->pEnvir->IsInTolerance not changed */ - EVCSetPar(evc,"upperlimit",310.0,pCon); - EVCSetPar(evc,"lowerlimit",1.0,pCon); - - return evc; + drv = EaseMakeDriv(con, &itcClass, argc, argv, dynamic, 7, + ItcParDef, OxiHandler, ItcStart, NULL, ItcRead, + ItcSet); + if (drv == NULL) return 0; + drv->d.b.syntax = 0; + ParPrintf(drv, eValue, "OI Temperature Controller"); + return 1; +} +/*----------------------------------------------------------------------------*/ +static int ItcInitLc(SConnection *con, int argc, char *argv[], int dynamic) { + /* args: + MakeObject objectname lc + MakeObject objectname lc + */ + Itc *drv; + + drv = EaseMakeDriv(con, &itcClass, argc, argv, dynamic, 7, + ItcParDef, OxiHandler, ItcStart, NULL, ItcRead, + ItcSet); + 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); }