/*--------------------------------------------------------------------------- ilmdriv.c Driver for the Oxford Instruments ILM503/ILM4 temperature controller Version 2 (based on ease). Markus Zolliker, April 2005 ------------------------------------------------------------------------------*/ #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" typedef enum { ALWAYSNEW, NEW, MEASURING, NOTYETREAD, OLD } ReadState; typedef enum { UNUSED, N2, PULSED_HE, CONTINOUS_HE, CHANNEL_ERROR = 9 } Usage; typedef struct { EaseBase b; float lev[3]; Usage usage[3]; ReadState readState[3]; } Ilm; static ParClass ilmClass = { "ILM", sizeof(Ilm) }; char *tails[10]={"unused", "% N2", "% He","% He","","","","","","error"}; /*----------------------------------------------------------------------------*/ static void IlmParDef(void *object) { Ilm *drv = ParCast(&ilmClass, object); 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); } /*----------------------------------------------------------------------------*/ static void IlmStatus(Ilm *drv) { char *ans; int *code; int i; int status; 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') { ParPrintf(drv, eError, "illegal status response"); *code = EASE_FAULT; return; } 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; } } return; } /*----------------------------------------------------------------------------*/ static long IlmRead(long pc, void *object) { Ilm *drv = ParCast(&ilmClass, object); EaseBase *eab = object; int i; 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, drv->lev[0]); } 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, drv->lev[1]); if (drv->readState[1] == NOTYETREAD) { drv->readState[1] = NEW; } skip2: if (drv->usage[2] == 0) goto skip3; EaseWrite(eab, "R3"); /* read sensor 3 */ return __LINE__; case __LINE__: /**********************************/ drv->lev[2] = OxiGet(eab, 1, NULL, drv->lev[2]); if (drv->readState[2] == NOTYETREAD) { drv->readState[2] = NEW; } skip3: 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 long IlmStart(long pc, void *object) { Ilm *drv = ParCast(&ilmClass, object); EaseBase *eab = object; 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; } ParPrintf(drv, eStatus, "connected to %s", eab->version); eab->msg[0]='\0'; /* o.k. */ FsmCall(IlmRead); return __LINE__; case __LINE__: /**********************************/ quit: return 0; } /* FSM END ********************************************/ } /*----------------------------------------------------------------------------*/ static int IlmInit(SConnection *con, int argc, char *argv[], int dynamic) { /* args: MakeObject objectname ilm */ Ilm *drv; drv = EaseMakeBase(con, &ilmClass, argc, argv, dynamic, 0, IlmParDef, OxiHandler, IlmStart, NULL, IlmRead); if (drv == NULL) return 0; return 1; } /*----------------------------------------------------------------------------*/ void IlmStartup(void) { ParMakeClass(&ilmClass, EaseBaseClass()); MakeDriver("ILM", IlmInit, 0, "OI Level Meter"); }