/*--------------------------------------------------------------------------- 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); }