/*--------------------------------------------------------------------------- itcdriv.c Driver for the Oxford Instruments ITC503/ITC4 temperature controller Markus Zolliker, Sept 2004 ----------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "oicom.h" #include "fsm.h" typedef struct { Eve eve; float t[4]; /* temperatures (0 unused) */ int dig[4]; /* format for these */ float htr; float gas; int sampleChan; int controlChan; int gasMode; int htrMode; int remote; int h; /* actual heater channel */ int a; /* actual auto mode */ } ItcDriv; 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 void ItcPars(ItcDriv *me, EveParArg *arg) { char fmt[8]=""; int i; int flag; 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); 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); } 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); } /*----------------------------------------------------------------------------*/ void ItcStatus(ItcDriv *me) { char *ans; int *code; Eve *eve=&me->eve; if (eve->state != readState) return; ans=eve->ans; code=&eve->errCode; if (ans[0] != 'X' || ans[2] != 'A' || ans[4] != 'C' || ans[6] != 'S') { EvePrintf(eve, eError, "illegal status response"); *code = EVE_FAULT; return; } me->a = ans[3] - '0'; if (ans[9] == 'H') { me->h = ans[10] - '0'; } else { me->h = me->controlChan; } if (ans[6] != '3' && me->remote == 2) { EvePrintf(eve, eError, "ITC switched to local"); *code = EVE_FAULT; me->remote = 1; return; } } /*----------------------------------------------------------------------------*/ static long ItcRead(long pc, ItcDriv *me) { Eve *eve=&me->eve; char *p; int l; 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]); 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]); 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]); skip3: me->eve.value = me->t[me->sampleChan]; if (me->controlChan == 0 || me->a) { me->t[0] = me->eve.evc->fTarget; 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; 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); skipgas: me->eve.value = me->t[me->sampleChan]; EveLog(eve); FSM_END } /*----------------------------------------------------------------------------*/ static long ItcStart(long pc, ItcDriv *me) { Eve *eve=&me->eve; 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; } else { EvePrintf(eve, eError, "unknown temperature controller version: %s", eve->version); goto quit; } EvePrintf(eve, eStatus, "connected to %s", eve->version); if (me->controlChan == 0 && me->h >= 1 && me->h <= 3) { me->controlChan = me->h; } FSM_CALL(ItcRead); quit: FSM_END } /*----------------------------------------------------------------------------*/ static long ItcSetTemp(long pc, ItcDriv *me) { Eve *eve=&me->eve; pEVControl evc=eve->evc; float fld; float step; float ramp; char buf[4]; SConnection *pCon; int a; FSM_BEGIN if (me->controlChan == 0) { EvePrintf(eve, 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 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 */ } else { EveWrite(eve, "A1"); /* auto heater */ } FSM_NEXT 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; quit: 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; 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"); goto quit; } FSM_NEXT if (me->a == 2) { EveWrite(eve, "A0"); } else if (me->a == 3) { EveWrite(eve, "A1"); } else { goto skipmode; } FSM_NEXT skipmode: OiSet(eve, "G", me->gas, 1); /* cold valve setting */ FSM_NEXT EveWrite(eve, "C0"); FSM_NEXT me->remote = 0; quit: 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; 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 skipmode: OiSet(eve, "O", me->htr, 1); /* manual heater setting */ FSM_NEXT EveWrite(eve, "C0"); FSM_NEXT me->remote = 0; quit: FSM_END } /*------------------------------------------------------------------------*/ pEVControl ItcMakeEVC(SConnection *pCon, int argc, char *argv[]) { /* args: temperature itc */ Eve *eve; pEVControl evc; ItcDriv *me = NULL; 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; }