/*--------------------------------------------------------------------------- itcdriv.c Driver for the Oxford Instruments ITC503/ITC4 temperature controller Version 2 (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 "oxinst.h" #include "fsm.h" #include "initializer.h" #define TESLATRON -1 #define ITC_SETHTR 1 #define ITC_SETGAS 2 #define ITC_PIDMODE 3 #define ITC_PROP 4 #define ITC_INTEG 5 #define ITC_DERIV 6 #define ITC_MAXVOLT 7 typedef struct { EaseDriv d; float t[4]; /* temperatures (0 is set point) */ int dig[4]; /* format for these */ float htr; float gas; float autoGasLimit; float setGas; float travelTime; /* travel time for needle valve [sec/100%] */ /* control parameters: for ITC / for TESLATRON */ float prop; /* proportional value / for slow loop [mbar/K] */ float integ; /* integration time / for slow loop [sec] */ float deriv; /* deriv. time / int. for pressure [sec] */ float prop2; /* TESLATRON only: prop. for pressure [%/mbar] */ float lambdaTarget; /* TESLATRON only: lambda stage target temperature */ float power; float resist; float htrVolt; float maxVolt; float maxPower; int cntVolt; int readMaxVolt; int pidMode; int sampleChan; int controlChan; int gasMode; int htrMode; int remote; int h; /* actual heater channel */ int a; /* actual auto mode */ time_t lastCtrl; float lastTdiff, lastPdiff; } Itc; static ParClass itcClass = { "ITC", sizeof(Itc) }; /*----------------------------------------------------------------------------*/ static void ItcParDef(void *object) { Itc *drv = ParCast(&itcClass, object); EaseBase *eab = object; char fmt[8] = ""; int i; static char *ti[4] = { "setp", "t1", "t2", "t3" }; static char *modeList[] = { "off", "manual", "auto", NULL }; static char *progressList[] = { "off", "cooling", "ok", NULL }; static char *pidList[] = { "default", "manual", "auto", NULL }; 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"); } i = drv->sampleChan; if (drv->dig[i] < 0) { snprintf(fmt, sizeof fmt, "%s", "%.3f"); } else { snprintf(fmt, sizeof fmt, "%s.%df", "%", drv->dig[i]); } ParFmt(fmt); 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++) { 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); } 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); ParList(NULL); ParInt(&drv->gasMode, 1); ParName("heaterMode"); ParInt(&drv->a, 0); } else { ParName("progress"); ParAccess(usUser); ParEnum(progressList); ParList(NULL); ParSave(1); ParInt(&drv->gasMode, 0); } 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); if (drv->setGas > 99.9) drv->setGas = 99.9; if (drv->setGas < 0) drv->setGas = 0; ParFloat(&drv->setGas, 20.0); ParName("travelTime"); ParFmt("%.0f"); ParTail("sec"); ParList(""); ParAccess(usUser); ParSave(1); ParFloat(&drv->travelTime, 100.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); ParName("pidMode"); ParEnum(pidList); EaseUpdate(ITC_PIDMODE); ParSave(1); ParInt(&drv->pidMode, 0); ParName("prop"); ParFmt("%.3f"); ParTail("K"); if (drv->pidMode == 1) ParList(""); EaseUpdate(ITC_PROP); ParFloat(&drv->prop, PAR_NAN); ParName("int"); ParFmt("%.1f"); ParTail("min"); if (drv->pidMode == 1) ParList(""); EaseUpdate(ITC_INTEG); ParFloat(&drv->integ, PAR_NAN); ParName("deriv"); ParFmt("%.2f"); ParTail("min"); if (drv->pidMode == 1) ParList(""); EaseUpdate(ITC_DERIV); ParFloat(&drv->deriv, PAR_NAN); ParName("maxPower"); ParFmt("%.4g"); ParTail("W"); EaseUpdate(ITC_MAXVOLT); ParFloat(&drv->maxPower, PAR_NAN); if (ParActionIs(PAR_SET) > 0) { if (drv->maxPower < 0) { drv->readMaxVolt = 1; drv->maxPower = PAR_NAN; drv->maxVolt = PAR_NAN; } else { drv->readMaxVolt = 0; if (drv->resist < 0) { drv->resist = 0; } drv->maxVolt = sqrt(drv->maxPower * drv->resist); if (drv->maxVolt > 47.9) { drv->maxVolt = 47.9; } } } ParName("resist"); ParFmt("%g"); ParAccess(usUser); ParTail("Ohm"); ParList(""); ParFloat(&drv->resist, 80.0); ParName("power"); ParFmt("%g"); ParTail("W"); ParFloat(&drv->power, PAR_NAN); } else { ParName("lambdaTarget"); ParFmt("%.2f"); ParTail("K"); if (drv->gasMode == 0) ParList(""); ParAccess(usUser); ParSave(1); ParFloat(&drv->lambdaTarget, 2.2); ParName("prop"); ParFmt("%.1f"); ParTail("mbar/K"); ParList(""); ParAccess(usUser); ParSave(1); ParFloat(&drv->prop, 300); ParName("int"); ParFmt("%.1f"); ParTail("mbar/K/min"); ParList(""); ParAccess(usUser); ParSave(1); ParFloat(&drv->integ, 3.0); ParName("prop2"); ParFmt("%.1f"); ParTail("%/mbar"); ParList(""); ParAccess(usUser); ParSave(1); ParFloat(&drv->prop2, 1.0); ParName("int2"); ParFmt("%.1f"); ParTail("%/mbar/min"); ParList(""); ParAccess(usUser); ParSave(1); ParFloat(&drv->deriv, 2.0); } if (drv->controlChan == 0) { i = drv->dig[drv->sampleChan]; } else { i = drv->dig[drv->controlChan]; } if (i < 0) { snprintf(fmt, sizeof fmt, "%s", "%.3f"); } else { if (eab->syntax == TESLATRON) i += 2; snprintf(fmt, sizeof fmt, "%s.%df", "%", i); } EaseBasePar(drv); EaseSendPar(drv); if (eab->syntax != TESLATRON) { EaseDrivPar(drv, fmt, "K"); } else { EaseDrivPar(drv, fmt, "mbar"); } ParStdDef(); EaseMsgPar(drv); } /*----------------------------------------------------------------------------*/ static void ItcLcParDef(void *object) { EaseBase *eab = object; eab->syntax = TESLATRON; ItcParDef(object); } /*----------------------------------------------------------------------------*/ void ItcStatus(Itc * drv) { char *ans; int *code; 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') { ParPrintf(drv, eError, "illegal status response"); *code = EASE_FAULT; return; } drv->a = ans[3] - '0'; if (ans[9] == 'H') { drv->h = ans[10] - '0'; if (ans[11] == 'L' && drv->pidMode != 0 && !EaseGetUpdate(drv, ITC_PIDMODE)) { drv->pidMode = ans[12] - '0' + 1; } } else { drv->h = drv->controlChan; } if (ans[5] != '3' && drv->remote == 2) { ParPrintf(drv, eError, "ITC switched to local"); *code = EASE_FAULT; drv->remote = 1; return; } } /*----------------------------------------------------------------------------*/ float controlPropInt(float diff, /* input (soll-ist for negative loop, ist-soll for positive) */ float prop, /* prop (gain) units: [out]/[inp] */ float intd, /* int*delta (reset) units: [out]/[inp] */ float bandP, /* prop deadband units: [inp] */ float bandi, /* integral deadband units: [inp] */ float *buffer) { /* a buffer to store last diff */ float d, d0; bandP = bandP * 0.5; d0 = *buffer; if (fabs(diff) < bandi * 1.01) { intd = 0; } if (diff > d0 + bandP) { d = diff - bandP; } else if (diff < d0 - bandP) { d = diff + bandP; } else { d = d0; } *buffer = d; return prop * (d - d0) + intd * diff; } /*----------------------------------------------------------------------------*/ void controlLimits(float *inp, float min, float max) { if (*inp > max) { *inp = max; } else if (*inp < min) { *inp = min; } } /*----------------------------------------------------------------------------*/ static long ItcRead(long pc, void *object) { Itc *drv = ParCast(&itcClass, object); EaseBase *eab = object; char *p; int l; time_t now, delta; char buf[4]; float gas, band, v1, v2, h; switch (pc) { default: /* FSM BEGIN ****************************** */ EasePchk(drv); 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], drv->t[1]); skip1: 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], drv->t[2]); skip2: 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], drv->t[3]); skip3: if (drv->controlChan == 0 || drv->a == 0) { drv->t[0] = drv->d.targetValue; goto skip0; } EaseWrite(eab, "R0"); /* read control T */ return __LINE__; case __LINE__: /**********************************/ drv->t[0] = OxiGet(eab, drv->dig[drv->controlChan], NULL, drv->t[0]); if (drv->gasMode == 2 && eab->syntax != TESLATRON) { if (drv->t[drv->controlChan] > drv->autoGasLimit + 1.0) { if (drv->a < 2) { drv->a |= 2; /* switch gas to auto */ ParPrintf(drv, eWarning, "needle valve switched to ITC control (AutoGas)"); } 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, "needle valve switched to software control"); } else { goto skip0; } if (drv->setGas != drv->gas) { EaseSetUpdate(drv, ITC_SETGAS, 1); } } else { if (drv->setGas != drv->gas) { EaseSetUpdate(drv, ITC_SETGAS, 1); } goto skip0; } } } 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: EaseWrite(eab, "R7"); /* read gas flow */ return __LINE__; case __LINE__: /**********************************/ gas = OxiGet(eab, 1, NULL, drv->gas); time(&now); delta = now - drv->lastCtrl; drv->lastCtrl = now; if (drv->gas == PAR_NAN) { drv->gas = gas; } else { if (drv->travelTime < 1) drv->travelTime = 1; if (drv->gas < gas) { drv->gas += delta * 100.0 / drv->travelTime; if (drv->gas > gas) drv->gas = gas; } else { drv->gas -= delta * 100.0 / drv->travelTime; if (drv->gas < gas) drv->gas = gas; } } if (eab->syntax != TESLATRON || drv->gasMode <= 0) goto skipFlow; if (delta > 10) delta = 10; if (drv->prop <= 0) { band = 0.1; } else { band = (drv->d.upperLimit - drv->d.lowerLimit) / drv->prop; } if (drv->t[2] - drv->lambdaTarget > band) { drv->gasMode = 1; } if (drv->gasMode == 1) { drv->d.targetValue = drv->d.upperLimit; if (drv->t[2] <= drv->lambdaTarget + 0.001) { drv->gasMode = 2; drv->d.targetValue = drv->d.lowerLimit; } } else { drv->d.targetValue += controlPropInt(drv->t[2] - drv->lambdaTarget, drv->prop, drv->integ * delta / 60.0, 0.01, 0.01, &drv->lastTdiff); band = 0.01 * drv->prop; controlLimits(&drv->d.targetValue, drv->d.lowerLimit - band, drv->d.upperLimit + band); } drv->setGas += controlPropInt(drv->d.targetValue - drv->t[1], drv->prop2, drv->deriv * delta / 60.0, drv->d.tolerance, 0.1, &drv->lastPdiff); controlLimits(&drv->setGas, 0.0, 99.9); if (fabsf(drv->setGas - gas) < 0.1) goto skipFlow; EaseParHasChanged(); if (drv->remote == 2) goto skipActive; EaseWrite(eab, "C3"); return __LINE__; case __LINE__: /**********************************/ drv->remote = 2; skipActive: OxiSet(eab, "G", drv->setGas, 1); /* cold valve setting */ return __LINE__; case __LINE__: /**********************************/ skipFlow: if (!drv->remote || eab->syntax == TESLATRON) goto skiprmt; EaseWrite(eab, "C0"); drv->remote = 0; return __LINE__; case __LINE__: /**********************************/ skiprmt: if (eab->syntax == TESLATRON) goto skipctrl; if (EaseGetUpdate(drv, ITC_MAXVOLT)) goto skiphtr; EaseWrite(eab, "R5"); /* read heater percent */ return __LINE__; case __LINE__: /**********************************/ if (EaseGetUpdate(drv, ITC_MAXVOLT)) goto skiphtr; drv->htr = OxiGet(eab, 1, NULL, drv->htr); if (drv->readMaxVolt == 0) { drv->htrVolt = drv->htr * 0.01 * drv->maxVolt; goto skiphtr; } EaseWrite(eab, "R6"); /* read heater voltage */ return __LINE__; case __LINE__: /**********************************/ drv->htrVolt = OxiGet(eab, 1, NULL, drv->htrVolt); if (drv->readMaxVolt) { h = drv->htr; if (h > 1.0) { v1 = 0.1 * (int) (drv->htrVolt * 1000 / (h + 0.099) - 0.5); v2 = 0.1 * (int) (drv->htrVolt * 1000 / (h - 0.05) + 0.99); if (drv->maxVolt > v2) { drv->cntVolt++; if (drv->cntVolt > drv->readMaxVolt) { drv->maxVolt = v2; drv->cntVolt = 0; drv->readMaxVolt++; } } else if (drv->maxVolt < v1) { drv->cntVolt--; if (drv->cntVolt < -drv->readMaxVolt) { drv->maxVolt = v1; drv->cntVolt = 0; drv->readMaxVolt++; } } else { drv->cntVolt = 0; } } } if (drv->maxVolt != PAR_NAN) { drv->htrVolt = h * 0.01 * drv->maxVolt; } skiphtr: if (drv->resist <= 1) drv->resist = 80.0; if (drv->maxVolt != PAR_NAN) { drv->maxPower = drv->maxVolt * drv->maxVolt / drv->resist; } if (drv->htrVolt != PAR_NAN) { drv->power = drv->htrVolt * drv->htrVolt / drv->resist; } if (EaseGetUpdate(drv, ITC_PROP)) goto skipprop; EaseWrite(eab, "R8"); /* read prop */ return __LINE__; case __LINE__: /**********************************/ if (EaseGetUpdate(drv, ITC_PROP)) goto skipprop; drv->prop = OxiGet(eab, 1, NULL, drv->prop); skipprop: if (EaseGetUpdate(drv, ITC_INTEG)) goto skipint; EaseWrite(eab, "R9"); /* read int */ return __LINE__; case __LINE__: /**********************************/ if (EaseGetUpdate(drv, ITC_INTEG)) goto skipint; drv->integ = OxiGet(eab, 1, NULL, drv->integ); skipint: if (EaseGetUpdate(drv, ITC_DERIV)) goto skipderiv; EaseWrite(eab, "R10"); /* read deriv */ return __LINE__; case __LINE__: /**********************************/ if (EaseGetUpdate(drv, ITC_DERIV)) goto skipderiv; drv->deriv = OxiGet(eab, 1, NULL, drv->deriv); skipderiv: skipctrl: ParLog(drv); fsm_quit:return 0; } /* FSM END ******************************** */ } /*----------------------------------------------------------------------------*/ static long ItcStart(long pc, void *object) { Itc *drv = ParCast(&itcClass, object); EaseBase *eab = object; char msg[256]; switch (pc) { default: /* FSM BEGIN ****************************** */ EasePchk(drv); EaseWrite(eab, "V"); return __LINE__; case __LINE__: /**********************************/ if (eab->syntax == TESLATRON) { if (0 != strncmp(eab->version, "TESLATRON", 9)) { snprintf(msg, sizeof msg, "unknown teslatron version: %s", eab->version); EaseStop(eab, msg); goto quit; } } else { if (0 == strncmp(eab->version, "ITC503", 6)) { eab->syntax = 3; } else if (0 == strncmp(eab->version, "ITC4", 4)) { eab->syntax = 0; } else { snprintf(msg, sizeof msg, "unknown temperature controller version: %s", eab->version); EaseStop(eab, msg); goto quit; } } ParPrintf(drv, eLog, "connected to %s", eab->version); FsmCall(ItcRead); return __LINE__; case __LINE__: /**********************************/ if (drv->controlChan == 0 && drv->h >= 1 && drv->h <= 3) { drv->controlChan = drv->h; } drv->d.targetValue = drv->t[0]; quit: return 0; } /* FSM END ******************************************* */ } /*----------------------------------------------------------------------------*/ static long ItcSetTemp(long pc, void *object) { Itc *drv = ParCast(&itcClass, object); EaseBase *eab = object; char buf[4]; int a; switch (pc) { default: /* FSM BEGIN ****************************** */ EasePchk(drv); if (drv->controlChan == 0) { ParPrintf(drv, eError, "no control channel selected"); goto quit; } if (drv->h == drv->controlChan) goto skiph; EaseWrite(eab, "A0"); /* heater off */ return __LINE__; case __LINE__: /**********************************/ snprintf(buf, sizeof buf, "H%d", drv->controlChan); EaseWrite(eab, buf); /* set heater to channel */ return __LINE__; case __LINE__: /**********************************/ skiph: OxiSet(eab, "T", drv->d.targetValue, drv->dig[drv->controlChan]); /* set point */ return __LINE__; case __LINE__: /**********************************/ if (drv->pidMode != 0) goto skipPidMode; EaseWrite(eab, "L1"); /* 'auto' pid on */ return __LINE__; case __LINE__: /**********************************/ skipPidMode: 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 { drv->htrMode = 2; /* heater auto */ } 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: if (drv->a != 0) goto quit; EaseWrite(eab, "O0"); /* switch off heater */ return __LINE__; case __LINE__: /**********************************/ quit: return 0; } /* FSM END ******************************************* */ } /*----------------------------------------------------------------------------*/ static long ItcSetGas(long pc, void *object) { Itc *drv = ParCast(&itcClass, object); EaseBase *eab = object; char buf[4]; switch (pc) { default: /* FSM BEGIN ****************************** */ EasePchk(drv); if (drv->gasMode != 1 && drv->gasMode != 2) { ParPrintf(drv, eError, "gasMode must be set to manual or auto"); goto quit; } if (drv->a == 2) { EaseWrite(eab, "A0"); } else if (drv->a == 3) { EaseWrite(eab, "A1"); } else { goto skipmode; } return __LINE__; case __LINE__: /**********************************/ skipmode: OxiSet(eab, "G", drv->setGas, 1); /* cold valve setting */ return __LINE__; case __LINE__: /**********************************/ EaseWrite(eab, "R7"); /* read gas flow */ return __LINE__; case __LINE__: /**********************************/ if (!EaseGetUpdate(drv, ITC_SETGAS)) { drv->setGas = OxiGet(eab, 1, NULL, drv->setGas); } if (drv->a < 2) goto quit; snprintf(buf, sizeof buf, "A%d", drv->a); EaseWrite(eab, buf); return __LINE__; case __LINE__: /**********************************/ quit: return 0; } /* FSM END ******************************************* */ } /*----------------------------------------------------------------------------*/ static long ItcSetHtr(long pc, void *object) { Itc *drv = ParCast(&itcClass, object); EaseBase *eab = object; char buf[4]; switch (pc) { default: /* FSM BEGIN ****************************** */ EasePchk(drv); if (drv->a == 0) goto skipmode; EaseWrite(eab, "A0"); return __LINE__; case __LINE__: /**********************************/ skipmode: 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: return 0; } /* FSM END ******************************************* */ } /*----------------------------------------------------------------------------*/ static long ItcSet(long pc, void *object) { Itc *drv = ParCast(&itcClass, object); EaseBase *eab = object; int upd; switch (pc) { default: /* FSM BEGIN ****************************** */ EasePchk(drv); EaseWrite(eab, "C3"); loop: return __LINE__; case __LINE__: /**********************************/ drv->remote = 2; upd = EaseNextUpdate(drv); if (eab->syntax != TESLATRON) { switch (upd) { case EASE_RUN: FsmCall(ItcSetTemp); goto loop; case ITC_SETHTR: FsmCall(ItcSetHtr); goto loop; case ITC_SETGAS: FsmCall(ItcSetGas); goto loop; case ITC_PIDMODE: if (drv->pidMode == 1) { EaseWrite(eab, "L0"); } else { EaseWrite(eab, "L1"); drv->pidMode = 2; } goto loop; case ITC_PROP: OxiSet(eab, "P", drv->prop, 1); goto loop; case ITC_INTEG: OxiSet(eab, "I", drv->integ, 1); goto loop; case ITC_DERIV: OxiSet(eab, "D", drv->deriv, 1); goto loop; case ITC_MAXVOLT: OxiSet(eab, "M", drv->maxVolt, 1); goto loop; default: break; } } if (eab->syntax == TESLATRON && drv->gasMode > 0) goto quit; 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: MakeObject objectname itc MakeObject objectname itc */ 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 = 0; drv->cntVolt = 0; drv->maxVolt = PAR_NAN; drv->htrVolt = PAR_NAN; drv->readMaxVolt = 1; 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, ItcLcParDef, OxiHandler, ItcStart, NULL, ItcRead, ItcSet); if (drv == NULL) return 0; drv->d.b.syntax = TESLATRON; drv->lastCtrl = 0; drv->lastTdiff = 0; drv->lastPdiff = 0; return 1; } /*----------------------------------------------------------------------------*/ void ItcStartup(void) { ParMakeClass(&itcClass, EaseDrivClass()); MakeDriver("ITC", ItcInit, 0, "OI Temperature Controller"); MakeDriver("LC", ItcInitLc, 0, "OI Lambda Controller"); }