/*--------------------------------------------------------------------------- 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 "oxinst.h" #include "fsm.h" #include "initializer.h" #include "syncedprot.h" #define OLDIGH -8 #define SORBS_FLAG 1 #define MIXP_FLAG 2 #define MAXP_FLAG 3 #define STILL_FLAG 4 #define SORBP_FLAG 5 #define MOT_FLAGS 6 #define VALVE_FLAGS 9 #define MAX_FLAG 32 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; typedef struct { EaseDriv d; float setT; float sorbS; float mixT; float onekT; float sorbT; float mixP; float stillP; float sorbP; float press[n_PRESS]; float mv[n_MOTOR]; float v6pos; time_t v6time; 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; long hrSync; float closedelay; /* if > 0: next valve command is a pulsed opening */ int closevalve; /* number of valve to be closed */ double opentime; /* time when valve was opened */ /* extensions (ext_watchdog Arduino) */ int extVersion; /* 0 for no extension, else extension version */ int pumpoff; /* pump signal after overpressure switch */ float upperN2; /* LN2 trap sensor */ float lowerN2; char lastans[64]; int badcnt; int maxtry; int pumpoffcnt; } Igh; static ParClass ighClass = { "IGH", sizeof(Igh) }; static long IghSet(long pc, void *object); /*----------------------------------------------------------------------------*/ static int IghPower2Range(float p) { int e; if (p <= 0) return 0; for (e = 1; e < 5; e++) { if (p < 1.9994e-3) break; p /= 10; } return e; } /*----------------------------------------------------------------------------*/ static float IghRange2Max(int e) { static float elist[] = { 0, 0.002, 0.02, 0.2, 2.0, 20.0 }; if (e < 0) { e = 0; } else if (e > 5) { e = 5; } return elist[e]; } /*----------------------------------------------------------------------------*/ static void IghParDef(void *object) { Igh *drv = ParCast(&ighClass, object); EaseBase *eab = object; int i, flag, l, changed; char *vPos, *val; char fmt[8], vList[80]; static char *na = NULL; float maxP; static char *heaterList[] = { "off", "2uW", "20uW", "200uW", "2mW", "20mW", NULL }; static char *closedOrOpen[] = { "closed", "open", NULL }; ParName(""); ParTail("K"); ParFmt("%.4f"); ParFloat(&drv->mixT, PAR_NAN); ParName("Tset"); ParTail("K"); ParFmt("%.4f"); if (eab->syntax == OLDIGH) { ParList("all"); drv->setT = -1; ParFloat(&drv->setT, -1); } else { if (drv->setT < 0) drv->setT = 0; ParFloat(&drv->setT, PAR_NAN); } ParName("TsorbSet"); EaseUpdate(SORBS_FLAG); ParTail("K"); ParFmt("%.1f"); ParFloat(&drv->sorbS, PAR_NAN); ParName("Tmix"); ParTail("K"); ParFmt("%.4f"); ParFloat(&drv->mixT, PAR_NAN); ParName("T1K"); ParTail("K"); ParFmt("%.4f"); ParFloat(&drv->onekT, PAR_NAN); ParName("Tsorb"); ParTail("K"); ParFmt("%.1f"); ParFloat(&drv->sorbT, PAR_NAN); ParName("Pmix"); EaseUpdate(MIXP_FLAG); ParTail("mW"); ParFmt("%.5g"); ParFloat(&drv->mixP, PAR_NAN); ParName("Pmax"); ParTail("mW"); ParFmt("%.5g"); maxP = IghRange2Max(drv->e); ParFloat(&maxP, PAR_NAN); ParName("HtrRange"); EaseUpdate(MAXP_FLAG); ParEnum(heaterList); ParList(NULL); ParInt(&drv->e, PAR_NAN); if (ParActionIs(PAR_SET) > 0) { drv->mixP = 0; if (drv->hrSync == 0) { drv->hrSync=SyncedIncr(0); } } ParName("Pstill"); EaseUpdate(STILL_FLAG); ParTail("mW"); ParFmt("%.3f"); ParFloat(&drv->stillP, PAR_NAN); ParName("Psorb"); EaseUpdate(SORBP_FLAG); ParTail("W"); ParFmt("%.3f"); ParFloat(&drv->sorbP, PAR_NAN); for (i = 0; i < n_PRESS; i++) { if (gauges[i][0] != '\0') { ParName(gauges[i]); ParTail("mbar"); if (i == P1) { snprintf(fmt, sizeof fmt, "%%.%df", drv->pdig); 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; i < n_MOTOR; i++) { ParName(motorValves[i]); ParFmt("%.1f"); ParTail("%"); if (i == V1K) ParList("all"); EaseUpdate(flag); flag++; ParFloat(&drv->mv[i], PAR_NAN); } ParName("v6pos"); ParFmt("%.1f"); ParTail("%"); ParFloat(&drv->v6pos, PAR_NAN); assert(flag == VALVE_FLAGS); l = 0; for (i = 0; i < n_VALVES; i++) { if (valves[i][0] == ' ') { ParName(valves[i] + 1); changed = 0; } else { ParName(valves[i]); changed = EaseUpdate(flag); } ParEnum(closedOrOpen); ParInt(&drv->v[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); } ParName("closedelay"); ParAccess(usUser); ParSave(1); ParFloat(&drv->closedelay, 0); ParName("extVersion"); ParAccess(usUser); ParSave(1); ParInt(&drv->extVersion, PAR_LNAN); ParName("pumpoff"); if (drv->extVersion != 0) ParTail(""); ParInt(&drv->pumpoff, PAR_LNAN); ParName("upperN2"); ParFmt("%.1f"); if (drv->extVersion != 0) ParTail("K"); ParFloat(&drv->upperN2, PAR_NAN); ParName("lowerN2"); ParFmt("%.1f"); if (drv->extVersion != 0) ParTail("K"); ParFloat(&drv->lowerN2, PAR_NAN); ParName("maxtry"); ParAccess(usUser); ParSave(1); ParInt(&drv->maxtry, 0); EaseBasePar(drv); EaseSendPar(drv); if (eab->syntax != OLDIGH) { EaseDrivPar(drv, "%.5g", "K"); } ParStdDef(); EaseMsgPar(eab); } /*----------------------------------------------------------------------------*/ int IghStatus(Igh * drv) { char *ans; int *code; long mask, p; int i; if (drv->d.b.state != EASE_read) return 1; if (drv->opentime > 0 && DoubleTime() > drv->opentime + (double)drv->closedelay - 1) { /* force a call to IghSet */ drv->d.b.todo = drv->d.b.doit; } code = &drv->d.b.errCode; ans = drv->d.b.ans; if (drv->maxtry > 0 && strcmp(ans, drv->lastans) != 0) { strlcpy(drv->lastans, ans, sizeof(drv->lastans)); drv->badcnt++; if (drv->badcnt >= drv->maxtry) { drv->badcnt = 0; ParPrintf(drv, eError, "inconsistent status response: %s", ans); *code = EASE_FAULT; return 1; } return 0; /* try again */ } strlcpy(drv->lastans, ans, sizeof(drv->lastans)); if (ans[0] != 'X' || ans[2] != 'A' || ans[4] != 'C' || ans[6] != 'P' || ans[15] != 'S' || ans[17] != 'O' || ans[19] != 'E') { drv->badcnt++; if (drv->badcnt < drv->maxtry) { return 0; /* try again */ } ParPrintf(drv, eError, "illegal status response (dil maxtry 10 might help): %s", ans); *code = EASE_FAULT; return 1; } if (sscanf(ans + 7, "%lx", &mask) <= 0) { drv->badcnt++; if (drv->badcnt < drv->maxtry) { return 0; /* try again */ } ParPrintf(drv, eError, "illegal valve status response"); *code = EASE_FAULT; return 1; } if (drv->badcnt > drv->maxtry / 2) { ParPrintf(drv, eError, "needed %d retries for getting dil status", drv->badcnt); } drv->badcnt = 0; p = 1; for (i = 0; i < n_VALVES; i++) { if (!EaseGetUpdate(drv, VALVE_FLAGS + i)) { if (mask & p) { drv->v[i] = 1; } else { drv->v[i] = 0; } } p *= 2; } drv->a = ans[3] - '0'; drv->s = ans[16] - '0'; drv->o = ans[18] - '0'; if (EaseGetUpdate(drv, MAXP_FLAG) == 0) { if (drv->a == 0) { drv->e = 0; } else { 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 1; } */ return 1; } /*----------------------------------------------------------------------------*/ static long IghRead(long pc, void *object) { Igh *drv = ParCast(&ighClass, object); EaseBase *eab = object; char *p; int l; int switched_off; time_t now; float delta; int up10, lo10; if (eab->state == EASE_abort) { eab->state = EASE_idle; FsmRestartTask(eab->task, eab->idle); return 0; } switch (pc) { default: /* FSM BEGIN ****************************** */ EasePchk(drv); redo1: EaseWrite(eab, "X"); return __LINE__; case __LINE__: /**********************************/ if (!IghStatus(drv)) goto redo1; 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__: /**********************************/ if (EaseGetUpdate(drv, SORBS_FLAG)) goto skip0; drv->sorbS = OxiGet(eab, 1, NULL, drv->sorbS); skip0: if (EaseCheckDoit(eab)) goto quit; if (eab->syntax == OLDIGH) { EaseWrite(eab, "R3"); } else { EaseWrite(eab, "R32"); } return __LINE__; case __LINE__: /**********************************/ if (eab->syntax == OLDIGH) { drv->mixT = OxiGet(eab, 3, NULL, drv->mixT); } else { drv->mixT = OxiGet(eab, 4, NULL, drv->mixT); if (drv->mixT < 0) drv->mixT += 6.5536; /* correct a bug in firmware < 3.03 */ } if (EaseCheckDoit(eab)) goto quit; if (eab->syntax == OLDIGH) goto noSetTemp; EaseWrite(eab, "R33"); return __LINE__; case __LINE__: /**********************************/ drv->setT = OxiGet(eab, 4, NULL, drv->setT); noSetTemp: EaseWrite(eab, "R1"); return __LINE__; case __LINE__: /**********************************/ drv->sorbT = OxiGet(eab, 1, NULL, drv->sorbT); if (EaseCheckDoit(eab)) goto quit; EaseWrite(eab, "R2"); return __LINE__; case __LINE__: /**********************************/ drv->onekT = OxiGet(eab, 3, NULL, drv->onekT); if (EaseCheckDoit(eab)) goto quit; if (drv->e == 0) { drv->mixP = 0; goto skip4; } if (EaseGetUpdate(drv, MIXP_FLAG) || EaseGetUpdate(drv, MAXP_FLAG)) goto skip4; EaseWrite(eab, "R4"); return __LINE__; case __LINE__: /**********************************/ if (EaseGetUpdate(drv, MIXP_FLAG) || EaseGetUpdate(drv, MAXP_FLAG)) goto skip4; drv->mixP = OxiGet(eab, 5 - drv->e, NULL, drv->mixP * 100) * 0.01; skip4: if (EaseCheckDoit(eab)) goto quit; if (EaseGetUpdate(drv, STILL_FLAG)) goto skip5; EaseWrite(eab, "R5"); return __LINE__; case __LINE__: /**********************************/ if (EaseGetUpdate(drv, STILL_FLAG)) goto skip5; drv->stillP = OxiGet(eab, 1, NULL, drv->stillP); skip5: if (EaseCheckDoit(eab)) goto quit; if (EaseGetUpdate(drv, SORBP_FLAG)) goto skip6; EaseWrite(eab, "R6"); return __LINE__; case __LINE__: /**********************************/ if (EaseGetUpdate(drv, SORBP_FLAG)) goto skip6; drv->sorbP = OxiGet(eab, 3, NULL, drv->sorbP); skip6: if (EaseCheckDoit(eab)) goto quit; if (EaseGetUpdate(drv, MOT_FLAGS + V6)) goto skip7; EaseWrite(eab, "R7"); return __LINE__; case __LINE__: /**********************************/ if (EaseGetUpdate(drv, MOT_FLAGS + V6)) goto skip7; drv->mv[V6] = OxiGet(eab, 1, NULL, drv->mv[V6]); time(&now); delta = (now - drv->v6time) / 2.64; /* speed: 1/2.64 %/sec */ drv->v6time = now; if (drv->v6pos > drv->mv[V6] + delta) { if (drv->v6pos > 99.9) { drv->v6pos = 99.9; } drv->v6pos -= delta; } else if (drv->v6pos < drv->mv[V6] - delta) { if (drv->v6pos < 0) { drv->v6pos = 0; } drv->v6pos += delta; } else { drv->v6pos = drv->mv[V6]; } skip7: if (EaseCheckDoit(eab)) goto quit; if (EaseGetUpdate(drv, MOT_FLAGS + V12A)) goto skip8; EaseWrite(eab, "R8"); return __LINE__; case __LINE__: /**********************************/ if (EaseGetUpdate(drv, MOT_FLAGS + V12A)) goto skip8; drv->mv[V12A] = OxiGet(eab, 1, NULL, drv->mv[V12A]); skip8: if (EaseCheckDoit(eab)) goto quit; if (EaseGetUpdate(drv, MOT_FLAGS + V1K)) goto skip9; EaseWrite(eab, "R9"); return __LINE__; case __LINE__: /**********************************/ if (EaseGetUpdate(drv, MOT_FLAGS + V1K)) goto skip9; drv->mv[V1K] = OxiGet(eab, 1, NULL, drv->mv[V1K]); skip9: if (EaseCheckDoit(eab)) goto quit; EaseWrite(eab, "R14"); return __LINE__; case __LINE__: /**********************************/ drv->press[G1] = OxiGet(eab, 1, NULL, drv->press[G1]); if (EaseCheckDoit(eab)) goto quit; EaseWrite(eab, "R15"); return __LINE__; case __LINE__: /**********************************/ drv->press[G2] = OxiGet(eab, 1, NULL, drv->press[G2]); if (EaseCheckDoit(eab)) goto quit; EaseWrite(eab, "R16"); return __LINE__; case __LINE__: /**********************************/ drv->press[G3] = OxiGet(eab, 1, NULL, drv->press[G3]); if (EaseCheckDoit(eab)) goto quit; EaseWrite(eab, "R20"); return __LINE__; case __LINE__: /**********************************/ drv->press[P1] = OxiGet(eab, drv->pdig, &drv->pdig, drv->press[P1]); if (EaseCheckDoit(eab)) goto quit; EaseWrite(eab, "R21"); return __LINE__; case __LINE__: /**********************************/ drv->press[P2] = OxiGet(eab, 1, NULL, drv->press[P2]); if (EaseCheckDoit(eab) || drv->extVersion == 0) goto quit; drv->pumpoffcnt = 0; redo2: EaseWrite(eab, "{r}"); return __LINE__; case __LINE__: /**********************************/ /* analyze */ if (3 == sscanf(drv->d.b.ans, "?{%d,%d,%d}", &l, &up10, &lo10)) { switched_off = (drv->v[HE3] == 1 && l == 1); drv->pumpoff = l; drv->upperN2 = 0.1 * up10; drv->lowerN2 = 0.1 * lo10; } else { drv->pumpoff = PAR_LNAN; drv->upperN2 = PAR_NAN; drv->lowerN2 = PAR_NAN; } if (!switched_off) goto quit; if (drv->extVersion == 2) { ParPrintf(eab, eLogError, "ERROR: overpressure after 3He pump (IGNORED!)"); goto quit; } /* verify pump control */ EaseWrite(eab, "X"); return __LINE__; case __LINE__: /**********************************/ if (!IghStatus(drv)) goto redo2; drv->pumpoffcnt++; if (drv->pumpoffcnt < 3) goto redo2; if (drv->v[HE3] == 0) goto quit; /* switched off intentionally */ /* overpressure switch activated: we switch pump control off */ EaseWrite(eab, "C3"); drv->remote = 2; return __LINE__; case __LINE__: /**********************************/ EaseWrite(eab, "P49"); return __LINE__; case __LINE__: /**********************************/ EaseWrite(eab, "C0"); return __LINE__; case __LINE__: /**********************************/ drv->remote = 0; ParPrintf(eab, eLogError, "ERROR: overpressure after 3He pump (switched off)"); eab->errCode = EASE_FAULT; quit: ParLog(drv); fsm_quit:return 0; } /* FSM END ********************************* */ } /*----------------------------------------------------------------------------*/ static long IghStart(long pc, void *object) { Igh *drv = ParCast(&ighClass, object); EaseBase *eab = object; char msg[128]; switch (pc) { default: /* FSM BEGIN ****************************** */ EasePchk(drv); EaseWrite(eab, "V"); return __LINE__; case __LINE__: /**********************************/ if (0 != strncmp(eab->version, "IGH", 3)) { snprintf(msg, sizeof msg, "unknown gas handling system version: %s", eab->version); EaseStop(eab, msg); goto quit; } if (strstr(eab->version, "2.01") != NULL) { eab->syntax = OLDIGH; /* includes communication error correction */ } else { eab->syntax = 0; } ParPrintf(drv, eLog, "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; double now, deadline; switch (pc) { default: /* FSM BEGIN ****************************** */ EasePchk(drv); EaseWrite(eab, "C3"); drv->remote = 2; loop: return __LINE__; case __LINE__: /**********************************/ if (drv->opentime > 0) { now = DoubleTime(); deadline = drv->opentime + (double)drv->closedelay; if (now > deadline) goto close_valve; if (now > deadline - 1) goto loop; } 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 == MAXP_FLAG) goto set_max_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__: /**********************************/ redo1: EaseWrite(eab, "X"); return __LINE__; case __LINE__: /**********************************/ if (!IghStatus(drv)) goto redo1; 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: redo2: EaseWrite(eab, "X"); return __LINE__; case __LINE__: /**********************************/ if (!IghStatus(drv)) goto redo2; 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__: /**********************************/ redo3: EaseWrite(eab, "X"); return __LINE__; case __LINE__: /**********************************/ if (!IghStatus(drv)) goto redo3; snprintf(buf, sizeof buf, "O%d", drv->o | 1); EaseWrite(eab, buf); return __LINE__; case __LINE__: /**********************************/ goto loop; set_mix_pow: EaseWrite(eab, "A0"); return __LINE__; case __LINE__: /**********************************/ if (drv->e <= 1) goto skipe; EaseWrite(eab, "E1"); return __LINE__; case __LINE__: /**********************************/ skipe: if (drv->mixP > 0) { drv->e = IghPower2Range(drv->mixP); mp = drv->mixP / IghRange2Max(drv->e) * 2000; if (mp < 2001 && mp > 1999) { mp = 1999; } } else { mp = 0; /* range unchanged for external heater signal */ } OxiSet(eab, "M", mp, 0); return __LINE__; case __LINE__: /**********************************/ if (drv->e == 0) goto seta0; 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_max_pow: if (drv->e == 0) goto seta0; snprintf(buf, sizeof buf, "E%d", drv->e); EaseWrite(eab, buf); return __LINE__; case __LINE__: /**********************************/ if (drv->hrSync > 0) { SyncedDecr(drv->hrSync); drv->hrSync = 0; } if (drv->a == 2) goto loop; EaseWrite(eab, "A1"); return __LINE__; case __LINE__: /**********************************/ EaseWrite(eab, "M0"); return __LINE__; case __LINE__: /**********************************/ goto loop; seta0: EaseWrite(eab, "A0"); return __LINE__; case __LINE__: /**********************************/ goto loop; set_temp: EaseWrite(eab, "A2"); return __LINE__; case __LINE__: /**********************************/ if (drv->d.targetValue < 0) drv->d.targetValue = 0; if (drv->d.targetValue > 1.999) drv->d.targetValue = 1.999; drv->setT = drv->d.targetValue; OxiSet(eab, "T", drv->d.targetValue, 4); return __LINE__; case __LINE__: /**********************************/ goto loop; set_valve: i = upd - VALVE_FLAGS; if (drv->closedelay > 0) { if (drv->v[i]) { if (drv->opentime == 0) { drv->opentime = DoubleTime(); drv->closevalve = i; } } else if (drv->closevalve == i) { /* early close by command */ drv->opentime = 0; drv->closedelay = 0; } } snprintf(buf, sizeof buf, "P%d", i * 2 + 3 - drv->v[i]); EaseWrite(eab, buf); return __LINE__; case __LINE__: /**********************************/ goto loop; close_valve: drv->opentime = 0; drv->closedelay = 0; drv->v[drv->closevalve] = 0; snprintf(buf, sizeof buf, "P%d", drv->closevalve * 2 + 3); /* close cmd */ EaseWrite(eab, buf); return __LINE__; case __LINE__: /**********************************/ goto loop; set_mot: i = upd - MOT_FLAGS; if (drv->mv[i] > 99.9) { drv->mv[i] = 99.9; } else if (drv->mv[i] < 0) { drv->mv[i] = 0; } 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; drv->opentime = 0; drv->badcnt = 0; drv->pumpoffcnt = 0; return 1; } /*----------------------------------------------------------------------------*/ void IghStartup(void) { ParMakeClass(&ighClass, EaseDrivClass()); MakeDriver("IGH", IghInit, 0, "OI Gas Handling System"); }