From aa9ab52528e15ab3671164a1ba3b87c5ecef39a7 Mon Sep 17 00:00:00 2001 From: cvs Date: Wed, 17 Nov 2004 11:32:05 +0000 Subject: [PATCH] - extended evcontroller - remote objects - new ev drivers for oxford IPS,ITC,ILM and LC M.Z. --- eve.c | 1008 ++++++++++++++++++++++++++++++++++++ eve.h | 137 +++++ fsm.c | 117 +++++ fsm.h | 66 +++ ilmdriv.c | 145 ++++++ ipsdriv.c | 1137 ++++++++++++++--------------------------- itcdriv.c | 272 ++++++++++ lcdriv.c | 184 +++++++ logger.c | 352 +++++++++++++ logger.h | 19 + make_gen | 4 +- oicom.c | 128 +++++ oicom.h | 16 + psi.c | 35 +- remob.c | 785 ++++++++++++++++++++++++++++ remob.h | 19 + tecs/didi | 13 +- tecs/make_crv.tcsh | 2 +- tecs/make_gen | 4 + tecs/myc_buf.c | 37 +- tecs/pg_plus/xwdriv.c | 9 +- tecs/six.c | 20 +- tecs/tecs.c | 87 ++-- tecs/tecs_client.f | 3 +- tecs/tecs_plot.f | 44 +- tecs/term.c | 8 +- 26 files changed, 3772 insertions(+), 879 deletions(-) create mode 100644 eve.c create mode 100644 eve.h create mode 100644 fsm.c create mode 100644 fsm.h create mode 100644 ilmdriv.c create mode 100644 itcdriv.c create mode 100644 lcdriv.c create mode 100644 logger.c create mode 100644 logger.h create mode 100644 oicom.c create mode 100644 oicom.h create mode 100644 remob.c create mode 100644 remob.h diff --git a/eve.c b/eve.c new file mode 100644 index 0000000..b310be3 --- /dev/null +++ b/eve.c @@ -0,0 +1,1008 @@ +/*--------------------------------------------------------------------------- +eve.c + +extended environment controller utilities + +Markus Zolliker, Sept 2004 +---------------------------------------------------------------------------- +*/ + +#include +#include +#include +#include +#include +#include +#include "sics.h" +#include "rs232controller.h" +#include "obpar.h" +#include "evcontroller.h" +#include "evcontroller.i" +#include "evdriver.i" +#include "eve.h" +#include "fsm.h" +#include "logger.h" + +#define ILLNUM -1456 +#define ILLARGC -1457 +#define AMBIGUOS -1458 +#define UNCHANGEABLE -1459 +#define ILLPRIV -1460 +#define BADLOG -1461 + +typedef enum { + cntAction, iniAction, parAction, listAction, + logAction, logSwitchAction, saveAction +} EveAction; +typedef enum { noOp, fmtOp, setOp } ArgOp; + +struct EveParArg { + EveAction action; + int argc; + char **argv; + int ret; /* return value */ + SConnection *pCon; + pEVControl evc; + time_t now; + int period; + int idx; + FILE *fil; +}; + +struct EvePar { + char *name; + Logger *log; +}; + +/*--------------------------------------------------------------------------*/ +char *EveArg2Text(int argc, char *argv[], char *res, int maxsize) { + int i, l; + char *p; + + if (res == NULL) { + maxsize = 0; + for (i=0; ierrMsg[0] = '\0'; + if (eve->evc != NULL) { + pCon = SCLoad(&eve->evc->conn); + if (pCon != NULL) { + if (iOut < 0) { + if (-iOut > eve->verbose) return 0; + iOut=eStatus; + } + return SCWrite(pCon, buf, iOut); + } + } + if (iOut == eError) { + snprintf(eve->errMsg, sizeof eve->errMsg, "%s", buf); + } + return 1; +} +/*--------------------------------------------------------------------------*/ +int EveText2Int(char *list[], char *text) { + int num = 0; + char *endp; + + while (list[num] != NULL) { + if (strcasecmp(list[num],text) == 0) { + return num; + } + num++; + } + num = strtol(text, &endp, 0); + if (endp == text) return -1; + return num; +} +/*--------------------------------------------------------------------------*/ +char *EveInt2Text(char *list[], int num) { + int i; + static char buf[12]; + + for (i = 0; i <= num; i++) { + if (list[i] == NULL) { + snprintf(buf, sizeof buf, "%d", num); + return buf; + } + } + return list[num]; +} +/*----------------------------------------------------------------------------*/ +int EveCheckRights(EveParArg *arg, int access) { + + if (access == usInternal) { + arg->ret = UNCHANGEABLE; + } else if (SCMatchRights(arg->pCon,access)) { + return 1; + } else { + arg->ret = ILLPRIV; + } + return 0; +} +/*--------------------------------------------------------------------------*/ +void EveMakePar(Eve *eve) { + EveParArg arg; + int i; + + if (eve->par == NULL) { + arg.action = cntAction; + arg.pCon = NULL; + arg.evc = eve->evc; + arg.idx = 0; + eve->pardef(eve, &arg); /* first time: count */ + eve->npar = arg.idx; + + eve->par = calloc(arg.idx, sizeof *eve->par); + for (i=0; ipar[i].log = NULL; + eve->par[i].name = NULL; + } + + arg.action = iniAction; + arg.idx = 0; + eve->pardef(eve, &arg); /* second time: start default loggers */ + } +} +/*--------------------------------------------------------------------------*/ +EvePar *EveThisPar(EveParArg *arg, char *name, int flags) { + Eve *eve = arg->evc->pDriv->pPrivate; + EvePar *par; + + if (!eve->par) return NULL; + assert(arg->idx < eve->npar); + par = eve->par + arg->idx; + /* arg->idx ++ */ + if (par->name == NULL) { + par->name = name; + if (flags & 2) { /* first time: default logger */ + EveSwitchLog(eve, par, 1); + } + } else { + assert(par->name == name); + } + return par; +} +/*--------------------------------------------------------------------------*/ +void EveLog(Eve *eve) { + EveParArg arg; + + if (!eve->par) { + EveMakePar(eve); + } + arg.now = time(NULL); + if (arg.now >= (eve->logtime / eve->period + 1) * eve->period) { + arg.action = logAction; + arg.pCon = NULL; + arg.evc = eve->evc; + arg.argc = 0; + arg.idx = 0; + arg.period = eve->period; + eve->pardef(eve, &arg); + eve->logtime = arg.now; + } +} +/*----------------------------------------------------------------------------*/ +int EveSwitchLog(Eve *eve, EvePar *par, int on) { + char buf[80]; + + if (on) { + if (par->log == NULL) { + if (par->name[0] == '\0') { + par->log = LoggerMake(eve->evc->pName, eve->period); + } else { + snprintf(buf, sizeof buf, "%s.%s", eve->evc->pName, par->name); + par->log = LoggerMake(buf, eve->period); + } + if (par->log == NULL) { + return BADLOG; + } + } + } else { + if (par->log != NULL) { + LoggerKill(par->log); + par->log = NULL; + } + } + return 1; +} +/*----------------------------------------------------------------------------*/ +ArgOp EveOp(EveParArg *arg, char *name, char **fmt, int access, int flags) { + static char buf[80]; + char *sp; + int l; + EvePar *par; + ArgOp op; + + switch (arg->action) { + case cntAction: + arg->idx ++; + return noOp; + case iniAction: + EveThisPar(arg, name, flags); + arg->idx ++; + return noOp; + case listAction: + if (flags & 1) { + return fmtOp; + } + return noOp; + case logAction: + if (flags & 1) { + op = fmtOp; + break; /* reduce fmt */ + } + arg->idx++; + return noOp; + case logSwitchAction: + if (arg->argc > 2) { + arg->ret = ILLARGC; + return noOp; + } + if (0==strcasecmp(name, arg->argv[1])) { + if (arg->ret) { + arg->ret = AMBIGUOS; + return noOp; + } + par = EveThisPar(arg, name, 0); + EveSwitchLog(arg->evc->pDriv->pPrivate, par, toupper(arg->argv[0][0]) == 'L'); + } + arg->idx ++; + return noOp; + case parAction: + if (0==strcasecmp(name, arg->argv[0])) { + if (arg->ret) { + arg->ret = AMBIGUOS; + return noOp; + } + arg->ret = 1; + if (arg->argc == 1) { + op = fmtOp; + break; /* reduce fmt */ + } + if (!EveCheckRights(arg, access)) return noOp; + op = setOp; + break; + } + return noOp; + case saveAction: + if (flags & 4) { + op = fmtOp; + break; /* reduce fmt */ + } + return noOp; + default: + return noOp; + } + + if (fmt != NULL) { + /* skip fmt after tab */ + sp = strchr(*fmt, '\t'); + if (sp != NULL) { + l = sp - *fmt; + if (l >= sizeof buf) l = sizeof buf - 1; + strncpy(buf, *fmt, l); + buf[l]='\0'; + *fmt = buf; + } + } + return op; +} +/*----------------------------------------------------------------------------*/ +void EveOut(EveParArg *arg, char *name, char *buf) { + EvePar *par; + int l, i, j, m, ln, lp; + char *p, *q, *tab; + + switch (arg->action) { + case listAction: + p = buf; + while (*p == ' ') p++; /* skip blanks */ + i = 0; + if (p[i] == '-') i++; + j = i; + while (p[i] >= '0' && p[i] <='9') i++; + tab = strchr(p, '\t'); + if (tab) { + l = tab - p; + *tab = ' '; + } else { + l = strlen(p); + } + ln = strlen(name); + if (i != j && (buf[i] == '.' || buf[i] <= ' ')) { + l += 16 - i - ln; /* decimal point or end of number at least 16 chars after object name */ + if (tab) { + *tab = '\0'; + q = tab + 1; + } else { + q = ""; + } + lp = strlen(p); + if (l < lp) l = lp; + m = 22 - l - ln; /* unit/comment at least 22 chars after object name */ + if (m < 1) m = 1; + m += strlen(q); + } else { + l = 16 - ln; + q = ""; + m = 0; + } + if (l <= 0) l = 1; + SCPrintf(arg->pCon, eStatus, "%s %s %*s%*s", arg->evc->pName, name, l, p, m, q); + break; + case parAction: + SCPrintf(arg->pCon, eValue, "%s %s = %s", arg->evc->pName, name, buf); + break; + case logAction: + par = EveThisPar(arg, name, 0); + arg->idx ++; + if (par->log) { + LoggerWrite(par->log, arg->now, arg->period, buf); + } + break; + case saveAction: + fprintf(arg->fil, "%s %s %s\n", arg->evc->pName, name, buf); + break; + } +} +/*----------------------------------------------------------------------------*/ +void EveFloatPar(EveParArg *arg, char *name, float *value, char *fmt, + int access, int flags) { + char *endp; + float f; + char buf[132]; + + switch (EveOp(arg, name, &fmt, access, flags)) { + case setOp: + if (arg->argc > 2) { + arg->ret = ILLARGC; + return; + } + f = strtod(arg->argv[1], &endp); + if (endp == arg->argv[1]) { + arg->ret = ILLNUM; + break; + } + *value = f; + /* fall through */ + case fmtOp: + snprintf(buf, sizeof buf, fmt, *value); + EveOut(arg, name, buf); + break; + } +} +/*----------------------------------------------------------------------------*/ +void EveIntPar(EveParArg *arg, char *name, int *value, int access, int flags) { + char *endp; + int i; + char buf[132]; + + switch (EveOp(arg, name, NULL, access, flags)) { + case setOp: + if (arg->argc > 2) { + arg->ret = ILLARGC; + return; + } + i = strtol(arg->argv[1], &endp, 0); + if (endp == arg->argv[1]) { + arg->ret = ILLNUM; + break; + } + *value = i; + /* fall through */ + case fmtOp: + snprintf(buf, sizeof buf, "%d", *value); + EveOut(arg, name, buf); + break; + } +} +/*----------------------------------------------------------------------------*/ +void EveStrPar(EveParArg *arg, char *name, char **value, int maxsize, int access, int flags) { + static char *empty=""; + + switch (EveOp(arg, name, NULL, access, flags)) { + case setOp: + if (maxsize == 0) { /* dynamic string */ + if (*value != NULL) free(*value); + *value = EveArg2Text(arg->argc-1, arg->argv+1, NULL, 0); + } else { /* fixed string */ + EveArg2Text(arg->argc, arg->argv, *value, maxsize); + } + /* fall through */ + case fmtOp: + if (*value == NULL) value = ∅ + EveOut(arg, name, *value); + break; + } +} +/*----------------------------------------------------------------------------*/ +void EveObPar(EveParArg *arg, int index, char *fmt, int flags) { + char *name; + char *endp; + char buf[132]; + float f; + + name = arg->evc->pParam[index].name; + switch (EveOp(arg, name, &fmt, arg->evc->pParam[index].iCode, flags)) { + case setOp: + if (arg->argc > 2) { + arg->ret = ILLARGC; + return; + } + f = strtod(arg->argv[1], &endp); + if (endp == arg->argv[1]) { + arg->ret = ILLNUM; + } else { + arg->evc->pParam[index].fVal = f; + } + /* fall through */ + case fmtOp: + snprintf(buf, sizeof buf, fmt, arg->evc->pParam[index].fVal); + EveOut(arg, name, buf); + break; + } +} +/*----------------------------------------------------------------------------*/ +void EveObParEnum(EveParArg *arg, int index, char *list[], int flags) { + char *name; + int i; + char buf[132]; + char *fmt="%d\t(%s)"; + + name=arg->evc->pParam[index].name; + switch (EveOp(arg, name, &fmt, arg->evc->pParam[index].iCode, flags)) { + case setOp: + if (arg->argc > 2) { + arg->ret = ILLARGC; + return; + } + i = EveText2Int(list, arg->argv[1]); + if (i<0) { + arg->ret = ILLNUM; + } else { + arg->evc->pParam[index].fVal = i; + } + /* fall through */ + case fmtOp: + i = (int)ObVal(arg->evc->pParam, index); + snprintf(buf, sizeof buf, fmt, i, EveInt2Text(list, i)); + EveOut(arg, name, buf); + break; + } +} +/*----------------------------------------------------------------------------*/ +void EveEnumPar(EveParArg *arg, char *name, int *value, char *list[], int access, int flags) { + int i; + char buf[132]; + char *fmt="%d\t(%s)"; + + switch (EveOp(arg, name, &fmt, access, flags)) { + case setOp: + if (arg->argc > 2) { + arg->ret = ILLARGC; + return; + } + i = EveText2Int(list, arg->argv[1]); + if (i<0) { + arg->ret = ILLNUM; + } else { + *value = i; + } + /* fall through */ + case fmtOp: + snprintf(buf, sizeof buf, fmt, *value, EveInt2Text(list, *value)); + EveOut(arg, name, buf); + break; + } +} +/*----------------------------------------------------------------------------*/ +void EveCmd(EveParArg *arg, char *name, EveSubCmd subcmd, int access) { + + if (arg->action == parAction) { + if (0==strcasecmp(name, arg->argv[0])) { + if (arg->ret) { + arg->ret = AMBIGUOS; + return; + } + if (!EveCheckRights(arg, access)) return; + arg->ret=subcmd(arg->pCon, arg->evc, arg->argc, arg->argv); + } + } +} +/*----------------------------------------------------------------------------*/ +#define A EVE_ACTPAR +#define L EVE_LOGPAR +#define S EVE_SAVEPAR + +void EveStdPar(EveParArg *arg) { + static char *errList[]={"noop", "pause", "interrupt", "safeValue", "script", NULL }; + static char *intList[]={"continue", "abortOp", "abortScan", "abortBatch", NULL }; + float value; + int eh; + + EveObPar(arg, UPLIMIT, "%.5g\tK", A + S); + EveObPar(arg, LOWLIMIT, "%.5g\tK", A + S); + EveObPar(arg, TOLERANCE, "%.5g\tK", A + S); + EveObParEnum(arg, ERRORHANDLER, errList, A + S); + eh = (int)ObVal(arg->evc->pParam, ERRORHANDLER); + EveObParEnum(arg, INTERRUPT, intList, (eh == 2) * A + S); + EveObPar(arg, SAFEVALUE, "%.5g\tK", (eh == 3) * A + S); + EveStrPar(arg, "errorScript", &arg->evc->errorScript, 0, usUser, (eh == 4) * A + S); + EveObPar(arg, MAXWAIT, "%.0f\tsec", A + S); + EveObPar(arg, SETTLE, "%.0f\tsec", A + S); +} +/*----------------------------------------------------------------------------*/ +void EveStdParEnd(EveParArg *arg, char *fmt, int targetFlag) { + static char *accessList[]={"internal", "manager", "user", "spy", NULL }; + float value; + pEVControl evc = arg->evc; + Eve *eve = evc->pDriv->pPrivate; + + EveIntPar(arg, "verbose", &eve->verbose, usUser, S); + EveIntPar(arg, "period", &eve->period, usUser, S); + EveObParEnum(arg, ACCESS, accessList, A+S); + EveStrPar(arg, "driver", &evc->driverName, 0, usInternal, A); + EveFloatPar(arg, "targetValue", &evc->fTarget, fmt, usInternal, targetFlag); + EveFloatPar(arg, "", &eve->value, fmt, usInternal, A+L); +} +/*----------------------------------------------------------------------------*/ +SConnection *EveArgConn(EveParArg *arg) { + return arg->pCon; +} +/*----------------------------------------------------------------------------*/ +int EveWrapper(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]) { + pEVControl evc = pData; + EveParArg arg; + Eve *eve = evc->pDriv->pPrivate; + + if (eve->state == lostState) { + SCPrintf(pCon, eError, "%s does not respond", evc->pDes->name); + return -1; + } + arg.pCon = pCon; + arg.evc = evc; + arg.ret = 0; + if (argc == 2 && 0==strcasecmp(argv[1], "list")) { + arg.action = listAction; + eve->pardef(evc->pDriv->pPrivate, &arg); + return 1; + } + if (argc == 3 && (0 == strcasecmp(argv[1], "log") + || 0 == strcasecmp(argv[1], "unlog"))) { + if (!eve->par) EveMakePar(eve); + arg.action = logSwitchAction; + arg.argc = argc - 1; + arg.argv = argv + 1; + arg.idx = 0; + eve->pardef(eve, &arg); + } else { + arg.action = parAction; + arg.argc = argc - 1; + arg.argv = argv + 1; + if (argc > 1) eve->pardef(eve, &arg); + if (arg.ret == 0) { /* forward to standard EVController */ + return EVControlWrapper(pCon,pSics,pData,argc,argv); + } + } +error: + switch (arg.ret) { + case AMBIGUOS: + SCPrintf(pCon, eError, "ERROR: doubly defined parameter %s.%s", evc->pName, argv[1]); + break; + case UNCHANGEABLE: + SCPrintf(pCon, eError, "ERROR: %s.%s is not changeable", evc->pName, argv[1]); + break; + case ILLPRIV: + SCPrintf(pCon, eError, "ERROR: Insufficient privilege to change %s.%s", evc->pName, argv[1]); + break; + case ILLNUM: + SCPrintf(pCon, eError, "ERROR: illegal value", evc->pName, argv[2]); + break; + case ILLARGC: + SCPrintf(pCon, eError, "ERROR: illegal number of arguments for %s %s", evc->pName, argv[1]); + break; + case BADLOG: + SCPrintf(pCon, eError, "ERROR: can not create log directory for %s %s", evc->pName, argv[1]); + break; + default: + return arg.ret; + } + return -1; +} +/*----------------------------------------------------------------------------*/ +void EveWriteError(Eve *eve) { + switch (eve->errCode) { + case NOTCONNECTED: + EvePrintf(eve, eError, "terminalserver for %s not connected", eve->evc->pName); + break; + case FAILEDCONNECT: + EvePrintf(eve, eError, "can not connect to %s:%d", eve->ser->pHost, eve->ser->iPort); + break; + case TIMEOUT: + EvePrintf(eve, eError, "timeout on %s", eve->evc->pName); + break; + case INCOMPLETE: + EvePrintf(eve, eError, "incomplete answer %s from %s", eve->ans, eve->evc->pName); + break; + case EVE_ILL_ANS: + EvePrintf(eve, eError, "illegal answer %s from %s (cmd: %*s)", + eve->ans, eve->evc->pName, strlen(eve->cmd)-1, eve->cmd); + break; + case EVE_DEV_CHANGED: + EvePrintf(eve, eError, "controller was exchanged on %s", eve->evc->pName); + break; + case EVE_FAULT: + EvePrintf(eve, eError, "error on %s", eve->evc->pName); + break; + default: + EvePrintf(eve, eError, "error code %d on %s", eve->errCode, eve->evc->pName); + break; + } +} +/*----------------------------------------------------------------------------*/ +void EveWrite(Eve *eve, char *cmd) { + int iRet; + char trash[64]; + int l, iret; + + if (eve->errCode || eve->state == expectState) return; + while (availableRS232(eve->ser) == 1) { + l=sizeof(trash); + iret = readRS232TillTerm(eve->ser, trash, &l); + EvePrintf(eve, -2, "trash: %s\n", trash); + } + snprintf(eve->cmd, sizeof(eve->cmd), "%s\n", cmd); + iRet = writeRS232(eve->ser, eve->cmd, strlen(eve->cmd)); + EvePrintf(eve, -2, "cmd: %s", cmd); + eve->state = expectState; + eve->cmdtime = time(NULL); +} +/*----------------------------------------------------------------------------*/ +void EveWaitRead(Eve *eve) { + int cnt=0; + FsmPause(eve->task, 1); + while (eve->state == expectState) { + TaskYield(pServ->pTasker); /* wait for handling the last message */ + cnt++; + } + FsmPause(eve->task, 0); + /* if (cnt>1) printf("TaskYield %d\n", cnt); */ +} +/*----------------------------------------------------------------------------*/ +int EveHandler(Eve *eve) { + + if (eve->state == expectState) return 0; + if (eve->errCode) { + eve->hwstate = HWFault; + EveWriteError(eve); + eve->errCode = 0; + FsmStop(eve->task, eve->run); + return 0; + } + if (eve->state == lostState) { + if (FsmStop(eve->task, eve->run)) { + EvePrintf(eve, -1, "stop %s caused by timeout", eve->evc->pName); + } + return 0; + } + if (eve->evc->iStop && eve->hwstate == HWBusy) { + if (FsmStop(eve->task, eve->run)) { + EvePrintf(eve, -1, "%s stopped", eve->evc->pName); + return 0; + } + } + return 1; +} +/*----------------------------------------------------------------------------*/ +int EveIdle(long pc, Eve *eve) { + FsmFunc todo; + struct timeval tm; + FSM_BEGIN + + idle: + if (!eve->todo) goto rd; + doit: + todo = eve->todo; + eve->todo = NULL; + FSM_CALL(todo); + + rd: + if (eve->hwstate == HWBusy) eve->hwstate = HWIdle; + FSM_CALL(eve->read); + EveLog(eve); + if (eve->logtime == 0) eve->logtime = 1; + if (eve->todo) goto doit; + /* + gettimeofday(&tm, NULL); + printf("stop %s %f\n", eve->evc->pName, tm.tv_usec / 1e6); + */ + FSM_WAIT(1) + /* + gettimeofday(&tm, NULL); + printf("start %s %f\n", eve->evc->pName, tm.tv_usec / 1e6); + */ + goto idle; + + /* never return */ + FSM_END +} +/*----------------------------------------------------------------------------*/ +static int EveGet(pEVDriver driver, float *fPos) { + Eve *eve = driver->pPrivate; + + assert(driver); + assert(eve); + + *fPos=eve->value; + return 1; +} +/*----------------------------------------------------------------------------*/ +int EveRun(pEVDriver driver, float fVal) { + Eve *eve = driver->pPrivate; + + assert(driver && eve); + + if (! eve->run) { + EvePrintf(eve, -1, "can not run %s", eve->evc->pName); + return 0; + } + if (FsmStop(eve->task, eve->run)) { + EvePrintf(eve, -1, "running %s cancelled", eve->evc->pName); + } + eve->todo = eve->run; + eve->hwstate = HWBusy; + return 1; +} +/*--------------------------------------------------------------------------*/ +int EveSend(pEVDriver driver, char *pCommand, char *pReply, int iLen) { + Eve *eve = driver->pPrivate; + int iRet; + + assert(driver && eve); + + EveWaitRead(eve); + if (eve->errCode) { + EveWriteError(eve); + return 0; + } + EvePrintf(eve, -2, "cmd: %s", pCommand); + iRet = transactRS232(eve->ser, pCommand, strlen(pCommand), pReply, iLen); + EvePrintf(eve, -2, "ans: %s", pReply); + if(iRet < 0) + { + eve->errCode = iRet; + EveWriteError(eve); + return 0; + } + return 1; +} +/*-------------------------------------------------------------------------*/ +int EveCheckStatus(void *evcVoid, SConnection *pCon) { + pEVControl evc=evcVoid; + pEVDriver driver; + Eve *eve; + SConnection *con; + + assert(evc); + driver = evc->pDriv; + assert(driver); + eve = driver->pPrivate; + + con = SCLoad(&evc->conn); + if (con != pCon) { /* not sure if this is the case in any situation */ + if (con) { + SCWrite(con, "no more infos", eWarning); + } + SCWrite(pCon, "infos now here", eWarning); + SCSave(&evc->conn, pCon); + } + return eve->hwstate; +} +/*-------------------------------------------------------------------------*/ +EVMode EveGetMode(void *data) { + /* EveGetMode is called in the SICS task loop as long as evc lives + and is not been explicitely unregistered */ + pEVControl evc = data; + pEVDriver driver; + Eve *eve = evc->pDriv->pPrivate; + + if (eve->task != NULL) { + FsmTaskHandler(eve->task); + } + return evc->eMode; +} +/*-------------------------------------------------------------------------*/ +int EveClose(pEVDriver driver) { + /* empty routine */ + return 1; +} +/*-------------------------------------------------------------------------*/ +int EveAlwaysOk(void *data) { + return 1; +} +/*-------------------------------------------------------------------------*/ +int EveDontFix(pEVDriver driver, int iError) { + return(DEVFAULT); /* severe */ +} +/*-------------------------------------------------------------------------*/ +int EveSaveStatus(void *data, char *name, FILE *fil) +{ + pEVControl evc = data; + Eve *eve = evc->pDriv->pPrivate; + EveParArg arg; + + EVSaveStatus(data, name, fil); + arg.action = saveAction; + arg.pCon = NULL; + arg.evc = evc; + arg.fil = fil; + eve->pardef(eve, &arg); + return 1; +} +/*-------------------------------------------------------------------------*/ +void EveKill(void *pData) { + Eve *eve = pData; + EvePar *p; + Logger *log; + int i; + + assert(eve); + KillRS232(eve->ser); + for (i=0; inpar; i++) { + LoggerKill(eve->par[i].log); + eve->par[i].log = NULL; + } + free(eve); +} +/*--------------------------------------------------------------------------*/ +int EveGetError(pEVDriver driver, int *iCode, char *error, int iErrLen) { + Eve *eve = driver->pPrivate; + + *iCode = 1; /* severe */ + strncpy(error, eve->errMsg, iErrLen); + error[iErrLen-1]='\0'; + eve->errMsg[0]='\0'; + return 1; +} +/*----------------------------------------------------------------------------*/ +int EveInit(pEVDriver driver) { + Eve *eve; + int iRet; + char *res, buf[128]; + pExeList exe; + + assert(driver); + eve = driver->pPrivate; + eve->errCode = 0; + eve->state = idleState; + eve->version[0] = '\0'; + eve->errMsg[0]='\0'; + + iRet = initRS232(eve->ser); + if (iRet != 1) { + eve->errCode = iRet; + EveWriteError(eve); + return -1; + } + setRS232ReplyTerminator(eve->ser,"\r"); + setRS232SendTerminator(eve->ser,"\r"); + setRS232Timeout(eve->ser,1000); /* milliseconds */ + setRS232Debug(eve->ser,0); + + return 1; +} +/*----------------------------------------------------------------------------*/ +pEVControl MakeEveEVC(int argc, char *argv[], Eve *eve, SConnection *pCon) { + + /* args: + + + */ + pEVDriver driver = NULL; + int port; + rs232 *ser; + pEVControl evc; + + if (argc < 3 || argc > 4) { + SCWrite(pCon, "illegal number of arguments", eError); + goto error; + } + driver = CreateEVDriver(0,NULL); /* arguments obsolete */ + if(!driver || !eve) { + SCWrite(pCon, "ERROR: out of memory", eError); + goto error; + } + + driver->pPrivate = eve; + driver->KillPrivate = EveKill; + + /* initalise IpsDriver */ + eve->evc = NULL; + eve->hwstate = HWIdle; + eve->task = NULL; + eve->run = NULL; + eve->logtime = 0; + eve->period = 5; + eve->par = NULL; + + if (argc == 4) { + port=atoi(argv[3]); + if (port==0) { + SCWrite(pCon, "ERROR: illegal port number", eError); + goto error; + } + ser = createRS232(argv[2], port); + if (ser == NULL) { + SCWrite(pCon, "out of memory", eError); + goto error; + } + } else { + ser = FindCommandData(pServ->pSics, argv[2], "RS232 Controller"); + if (ser == NULL) { + SCWrite(pCon, "ERROR: rs232 not found", eError); + goto error; + } + } + eve->ser = ser; + + /* initialise function pointers */ + driver->GetValue = EveGet; + driver->SetValue = EveRun; + driver->Send = EveSend; + driver->GetError = EveGetError; + driver->TryFixIt = EveDontFix; + driver->Init = EveInit; + driver->Close = EveClose; + + evc = MakeEVController(driver, pCon, EveWrapper, argc, argv); + if (!evc) return NULL; + + eve->evc=evc; + eve->hwstate = HWIdle; + eve->verbose = 1; + SCSave(&eve->evc->conn, pCon); + eve->checkStatus = evc->pDrivInt->CheckStatus; + evc->pDrivInt->CheckStatus = EveCheckStatus; + evc->pEnvir->GetMode = EveGetMode; + return evc; + +error: + if (driver) { + free(driver); + driver = NULL; + } + /* write out error message */ + return MakeEVController(driver, pCon, EveWrapper, argc, argv); +} +/*----------------------------------------------------------------------------*/ diff --git a/eve.h b/eve.h new file mode 100644 index 0000000..82c09fb --- /dev/null +++ b/eve.h @@ -0,0 +1,137 @@ +/*--------------------------------------------------------------------------- +eve.h + +extended environment controller utilities + +Markus Zolliker, Sept 2004 +----------------------------------------------------------------------------*/ + +#ifndef EVE_H +#define EVE_H + +#include "fsm.h" +#include "evcontroller.h" +#include "rs232controller.h" + +typedef enum { idleState, readState, expectState, lostState } EveState; + +typedef struct EveParArg EveParArg; +typedef struct EvePar EvePar; + +/* the parameter definition function may call any parameter function (see below) */ +typedef void (*EveParDef)(void *private, EveParArg *arg); + +typedef int (*EveSubCmd)(SConnection *pCon, pEVControl evc, int argc, char *argv[]); + +/* Eve must always be the first member of the EVCs private struct */ + +typedef struct Eve { + EveParDef pardef; + rs232 *ser; + Fsm *task; /* a pointer to the task */ + FsmFunc todo; + FsmFunc run; + FsmFunc read; + int hwstate; + pEVControl evc; + int errCode; /* error code of last operation. not changed on success */ + int verbose; + EveState state; + time_t cmdtime; + float value; + int lost; + int syntax; /* not used in Eve, may be used by the driver. used by OiConn */ + char cmd[32]; + char ans[64]; + char version[64]; + int (*checkStatus)(void *self, SConnection *pCon); /* original CheckStatus function */ + EvePar *par; + int npar; + time_t logtime; + int period; + char errMsg[128]; +} Eve; + +#define EVE_ACTPAR 1 +#define EVE_LOGPAR 2 +#define EVE_SAVEPAR 4 + +/* parameter functions (pfs) +* ------------------------- +* there are some restrictions: +* +* - pfs may only be called from within the pardef function +* - the order and number of pfs must not change at runtime +* +* Arguments: +* +* arg: just the arg Argument in pardef +* name: parameter name, must be static and never changed +* (usually a string literal) +* value: a pointer to the corr. member of the drivers private struct +* fmt: a format. if it contains a blank, the content after the blank is +* skipped when not listing +* access: a SICS access mode (usInternal, usMugger, usUser, usSpy) +* flags: the sum of some flags values: +* EVE_ACTPAR: parameter is active +* EVE_LOGPAR: parameter is logged by default +* EVE_SAVEPAR: parameter is saved on sics exit +* maxsize: the maximum size of a fixed size string, or 0 for a dynamic string +* index: the ObPar index +* list: a NULL terminated list of value names +* subcmd: a function for handling the subcommand +*/ +void EveFloatPar(EveParArg *arg, char *name, float *value, char *fmt, + int access, int flags); +void EveIntPar(EveParArg *arg, char *name, int *value, + int access, int flags); +void EveStrPar(EveParArg *arg, char *name, char **value, int maxsize, + int access, int flags); +void EveObPar(EveParArg *arg, int index, char *fmt, int flags); +void EveObParEnum(EveParArg *arg, int index, char *list[], int flags); +void EveEnumPar(EveParArg *arg, char *name, int *value, char *list[], + int access, int flags); +void EveCmd(EveParArg *arg, char *name, EveSubCmd subcmd, int access); + +/* a collection of parameters from the standard EVController +* (limits, tolerance, drive handling, out of tolerance handling) +* normally appearing at the top +*/ +void EveStdPar(EveParArg *arg); + +/* some even more standard values (should always be used) +* appearing at the end of the list +*/ +void EveStdParEnd(EveParArg *arg, char *fmt, int targetFlag); + +/* return the connection related to the parameter request */ +SConnection *EveArgConn(EveParArg *arg); + +/* write to the actual (last driving) connection */ +int EvePrintf(Eve *eve, int iOut, char *fmt, ...); + +void EveWriteError(Eve *eve); +void EveWrite(Eve *eve, char *cmd); +void EveWaitRead(Eve *eve); +int EveHandler(Eve *eve); +int EveIdle(long pc, Eve *eve); +int EveRun(pEVDriver driver, float fVal); +int EveSend(pEVDriver driver, char *pCommand, char *pReply, int iLen); +int EveCheckStatus(void *evcVoid, SConnection *pCon); +EVMode EveGetMode(void *data); +int EveClose(pEVDriver driver); +int EveAlwaysOk(void *data); +int EveDontFix(pEVDriver driver, int iError); +void EveKill(void *pData); +int EveGetError(pEVDriver driver, int *iCode, char *error, int iErrLen); +int EveInit(pEVDriver driver); +pEVDriver MakeEveDriver(int argc, char *argv[], Eve *eve, SConnection *pCon); +int EveWrapper(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); +pEVControl MakeEveEVC(int argc, char *argv[], Eve *eve, SConnection *pCon); + +#define EVE_ILL_ANS -3000 +#define EVE_FAULT -3001 +#define EVE_DEV_CHANGED -3002 + +#endif diff --git a/fsm.c b/fsm.c new file mode 100644 index 0000000..d281c5d --- /dev/null +++ b/fsm.c @@ -0,0 +1,117 @@ +/* ---------------------------------------------------------------------------- +fsm.c + +a finite state machine within sics + +M. Zolliker, Aug 2004 +---------------------------------------------------------------------------- */ + +#include +#include +#include +#include "fsm.h" + +#define MAXSTACK 8 + +typedef struct { + long pc; + FsmFunc func; +} StackItem; + +struct Fsm { + void *obj; + FsmHandler handler; + long pc; + FsmFunc func; + time_t till; + int pause; + int sp; + StackItem stack[MAXSTACK]; +}; + + +static Fsm *fsm = NULL; + +void FsmWait(long delay) { + assert(fsm); + fsm->till = time(NULL) + delay; +} + +int FsmTaskHandler(Fsm *this) { + long line; + + if (this->pause) { + this->handler(this->obj); + return 1; + } + if (this->pc >= 0) { /* this->pc < 0 means stop current function */ + if (this->till != 0) { + if (time(NULL) < this->till) return 1; /* wait */ + this->till = 0; + } + if (this->handler(this->obj) == 0) { + return 1; /* wait for answer */ + } + fsm = this; + this->pc = this->func(this->pc, this->obj); + fsm = NULL; + } + if (this->pc <= 0) { + if (this->sp == 0) return 0; + this->sp--; + this->pc = this->stack[this->sp].pc; + this->func = this->stack[this->sp].func; + } + return 1; +} + +void FsmKill(void *data) { + free(data); +} + +Fsm *FsmStartTask(void *obj, FsmHandler handler, FsmFunc func) { + Fsm *new; + + new=malloc(sizeof *new); + new->obj = obj; + new->pc = 0; + new->func = func; + new->handler = handler; + new->sp = 0; + new->till = 0; + return new; +} + +int FsmStop(Fsm *this, FsmFunc func) { + int i; + + if (this == NULL) this = fsm; + assert(this); + for (i=0; i < this->sp; i++) { + if (func == this->stack[i].func) { + break; + } + } + if (i == this->sp) { + if (func != this->func) return 0; + } else { + this->sp = i; + } + this->pc = -1; + return 1; +} + +void FsmPause(Fsm *this, int pause) { + this->pause = pause; +} + +long FsmCall(long pc, FsmFunc func) { + assert(fsm); + assert(fsm->sp < MAXSTACK); + fsm->stack[fsm->sp].pc = pc; + fsm->stack[fsm->sp].func = fsm->func; + fsm->sp++; + fsm->func = func; + fsm->pc = 0; + return fsm->func(fsm->pc, fsm->obj); +} diff --git a/fsm.h b/fsm.h new file mode 100644 index 0000000..5856211 --- /dev/null +++ b/fsm.h @@ -0,0 +1,66 @@ +/* ---------------------------------------------------------------------------- +fsm.h + +a finite state machine + +M. Zolliker, Aug 2004 +---------------------------------------------------------------------------- */ + +#ifndef FSM_H +#define FSM_H + +typedef struct Fsm Fsm; + +typedef long (*FsmFunc)(long pc, void *obj); +/* the prototype for a task function + a task function body has the following form: + + int Func(long pc, Object *obj) { + + BEGIN + ... + RETURN + } + + The ellipsis might be replaced by any code containing fsm macros. + Loops and conditional statements containing fsm macros are not + allowed, goto statements may be used instead. +*/ + +#define FSM_BEGIN switch (pc) { default: +#define FSM_END fsm_quit: return 0; } + +/* fsm macros: */ + +#define FSM_NEXT return __LINE__; case __LINE__: +/* waiting for response */ + +#define FSM_WAIT(DELTA) FsmWait(DELTA); return __LINE__; case __LINE__: +/* waiting DELTA seconds */ + +#define FSM_CALL(FUNC) return FsmCall(__LINE__, (FsmFunc)FUNC); case __LINE__: +/* call a task subfunction */ + +typedef int (*FsmHandler)(void *obj); +/* the prototype for the handler. Should return 0 when waiting for an answer + or 1 when result is o.k. */ + +Fsm *FsmStartTask(void *obj, FsmHandler handler, FsmFunc func); +/* start a task and return a pointer to it */ + +int FsmTaskHandler(Fsm *task); +/* this is the task handler. + the argument should be the pointer obtained from FsmStartTask + returns 0 when finished, 1 when still running */ + +int FsmStop(Fsm *task, FsmFunc func); +/* stop a function. returns to the caller next time */ + +void FsmPause(Fsm *this, int pause); +/* pause=1: pause task, pause=0: continue task */ + +long FsmCall(long pc, FsmFunc func); +void FsmWait(long delay); +/* these functions are used in fsm macros and must not be called directly */ + +#endif diff --git a/ilmdriv.c b/ilmdriv.c new file mode 100644 index 0000000..c03f0c1 --- /dev/null +++ b/ilmdriv.c @@ -0,0 +1,145 @@ +/*--------------------------------------------------------------------------- +ilmdriv.c + +Driver for the Oxford Instruments ILM503/ILM4 temperature controller +and for the Oxford lambda 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 "oicom.h" +#include "fsm.h" + +typedef struct { + Eve eve; + float lev2, lev3; + int cod1, cod2, cod3; +} IlmDriv; + +char *fmts[10]={"unused", "%.1f\t%% N2", "%.1f\t%% He","%.1f\t%% He","", + "","","","","error"}; + +/*----------------------------------------------------------------------------*/ +#define A EVE_ACTPAR +#define L EVE_LOGPAR +#define S EVE_EVE_SAVEPAR + +void IlmPars(IlmDriv *me, EveParArg *arg) { + EveFloatPar(arg, "chan2", &me->lev2, fmts[me->cod2], + usInternal, (me->cod2 > 0) * A + L); + EveFloatPar(arg, "chan3", &me->lev2, fmts[me->cod3], + usInternal, (me->cod3 > 0) * A + L); + EveStdParEnd(arg, fmts[me->cod1], A+L); +} +/*----------------------------------------------------------------------------*/ +void IlmStatus(IlmDriv *me) { + char *ans; + int *code; + Eve *eve=&me->eve; + int i; + + if (eve->state != readState) return; + ans=eve->ans; + code=&eve->errCode; + if (ans[0] != 'X' || ans[4] != 'S' || ans[11] != 'R') { + EvePrintf(eve, eError, "illegal status response"); + *code = EVE_FAULT; + return; + } + for (i=1; i<3; i++) { + if (ans[i]<'0' || ans[i] > '9') ans[i]='9'; + } + me->cod1 = ans[1]-'0'; + me->cod2 = ans[2]-'0'; + me->cod3 = ans[3]-'0'; + return; +} +/*----------------------------------------------------------------------------*/ +static int IlmRead(long pc, IlmDriv *me) { + Eve *eve=&me->eve; + + FSM_BEGIN + EveWrite(eve, "X"); + FSM_NEXT + IlmStatus(me); /* check for errors */ + EveWrite(eve, "R1"); /* read sensor 1 */ + FSM_NEXT + me->eve.value = OiGetFlt(eve, 1, NULL); + if (me->cod2 == 0) goto skip2; + EveWrite(eve, "R2"); /* read sensor 1 */ + FSM_NEXT + me->lev2 = OiGetFlt(eve, 1, NULL); + + skip2: + if (me->cod3 == 0) goto skip3; + EveWrite(eve, "R3"); /* read sensor 1 */ + FSM_NEXT + me->lev3 = OiGetFlt(eve, 1, NULL); + + skip3: + FSM_END +} +/*----------------------------------------------------------------------------*/ +static int IlmStart(long pc, IlmDriv *me) { + Eve *eve=&me->eve; + + FSM_BEGIN + EveWrite(eve, "V"); + FSM_NEXT + if (0 == strncmp(eve->version, "ILM", 3)) { + me->eve.syntax = 0; + } else { + EvePrintf(eve, eError, "unknown level meter version: %s", eve->version); + goto quit; + } + EvePrintf(eve, eStatus, "connected to %s", eve->version); + FSM_CALL(IlmRead); + + quit: + FSM_END +} +/*------------------------------------------------------------------------*/ +pEVControl IlmMakeEVC(SConnection *pCon, int argc, char *argv[]) { + /* args: + temperature ilm + + */ + Eve *eve; + pEVControl evc; + IlmDriv *me = NULL; + + evc = MakeEveEVC(argc, argv, calloc(1, sizeof *me), pCon); + if (!evc) return NULL; + + me = evc->pDriv->pPrivate; + eve=&me->eve; + + eve->run = NULL; /* no run possible */ + eve->read = (FsmFunc)IlmRead; + eve->pardef = (EveParDef)IlmPars; + eve->todo = (FsmFunc)IlmStart; + eve->task = FsmStartTask(me, (FsmHandler)OiHandler, (FsmFunc)EveIdle); + + evc->pEnvir->IsInTolerance = EveAlwaysOk; + + return evc; +} diff --git a/ipsdriv.c b/ipsdriv.c index 4a0367a..ffe25a0 100644 --- a/ipsdriv.c +++ b/ipsdriv.c @@ -1,10 +1,9 @@ /*--------------------------------------------------------------------------- - I P S D R I V . C +ipsdriv.c Driver for the Oxford Instruments IPS/PS magnet power supply. - -Markus Zolliker, June 2004 - + +Markus Zolliker, Sept 2004 ----------------------------------------------------------------------------*/ #include #include @@ -26,819 +25,437 @@ Markus Zolliker, June 2004 #include #include #include - -typedef enum { - IPS_INIT, - IPS_IDLE, - IPS_START, - IPS_WAIT, - IPS_UP, - IPS_STAB1, - IPS_START_RAMP, - IPS_RAMP, - IPS_STAB2, - IPS_DOWN -} rampState; +#include "oicom.h" +#include "fsm.h" typedef struct { - rs232 *ser; /* serial connection */ - int errCode; - int isPS; /* is an old PS-120 instead of an IPS-120 */ - rampState state; - float target; /* target field */ - float field; /* actual field */ - float ramp; /* actual ramp rate */ + Eve eve; + float current; /* current (in Tesla) */ + float persfield; /* persistent field from IPS (in Tesla) */ + float lastfield; /* persistent field from last drive */ + float ramp; /* actual ramp rate (Telsa/min) */ int persmode; /* 0: leave switch on, 1: go to persistant mode */ int perswitch; /* state of switch */ - int force; /* flag: put heater switch even when stored field not matched */ - float forcedfield; /* field user thinks is in magnet */ - int verbose; /* verbosity 0..2 */ - int settle; /* settling time/4 */ - int stabilize; /* do we need to stabilize ? */ - time_t tim; /* time when last switching the heater */ - float voltage[4]; /* voltage history */ - char xstat[32]; /* status response */ - char msg[2048]; /* a message to return */ + int remote; /* 0: local, 1: remote, do not check, 2: remote, check */ + int heaterFault; + int force; /* force = 2: put heater switch even when stored field does not match */ + time_t swtim; /* time when last switching the heater */ + time_t tim; } IpsDriv; -#define OX_ILL_ANS -3000 -#define OX_ILL_FLD -3001 - /*----------------------------------------------------------------------------*/ -void IpsSay(IpsDriv *me, int verbosity, char *fmt, ...) { - va_list ap; - int iRet, l; +static int IpsOk(IpsDriv *me, SConnection *pCon) { + float dif; + Eve *eve=&me->eve; - if (verbosity <= me->verbose) { - l=strlen(me->msg); - if (l > 0 && l < sizeof(me->msg)-1) { - strcat(me->msg, "\n"); - l++; - } - va_start(ap, fmt); - vsnprintf(me->msg+l, sizeof(me->msg)-l, fmt, ap); - va_end(ap); + if (!pCon) pCon = SCLoad(&eve->evc->conn); + if (me->perswitch) return 1; + if (fabs(me->persfield - me->lastfield) < 1e-5) { + return 1; } -} -/*----------------------------------------------------------------------------*/ -static void IpsWriteError(IpsDriv *me) { - switch (me->errCode) { - case NOTCONNECTED: - IpsSay(me, 0, "terminalserver for IPS not connected"); - break; - case FAILEDCONNECT: - IpsSay(me, 0, "can not connect to IPS"); - break; - case TIMEOUT: - IpsSay(me, 0, "IPS not properly connected"); - break; - case INCOMPLETE: - IpsSay(me, 0, "incomplete answer from IPS"); - break; - case OX_ILL_ANS: - IpsSay(me, 0, "illegal answer from IPS"); - break; - default: - IpsSay(me, 0, "error code %d", me->errCode); - break; + if (me->force == 2) { + return 1; } -} -/*----------------------------------------------------------------------------*/ -static char *IpsCmd(IpsDriv *me, char *cmd, int *ret) { - int iret; - static char buf[32]; - *ret=transactRS232(me->ser, cmd, strlen(cmd), buf, sizeof(buf)); - IpsSay(me, 2, "command: %s, answer: %s", cmd, buf); - if (*ret != 1) { - if (*ret == 0) { - *ret == 1; - IpsSay(me, 0, "IPS: unknown RS232 error"); - } else { - IpsWriteError(me); - } - return NULL; - } - if (buf[0] != cmd[0]) { - IpsSay(me, 0, "command: %s, answer: %s", cmd, buf); - *ret=OX_ILL_ANS; - IpsWriteError(me); - } else { - *ret=0; - } - return buf; -} -/*----------------------------------------------------------------------------*/ -static float IpsRead(IpsDriv *me, char *cmd, int fmt, int *ret) { - char *buf; - float val; - - buf=IpsCmd(me, cmd, ret); - if (*ret) return 0.0; - if (me->isPS) { /* no decimal point expected */ - val=atoi(buf+1); - for (; fmt>0; fmt--) val=val*0.1; - } else { - val=atof(buf+1); - } - return val; -} -/*----------------------------------------------------------------------------*/ -static char *IpsStatus(IpsDriv *me, int *ret) { - char *ans; - ans=IpsCmd(me, "X", ret); - if (*ret) return me->xstat; - strncpy(me->xstat, ans, sizeof(me->xstat)); - me->xstat[sizeof(me->xstat)-1]='\0'; - return me->xstat; -} -/*----------------------------------------------------------------------------*/ -static int IpsCheckField(IpsDriv *me, char *name, int *ret) { - float fld; - if (strstr(me->xstat, "H1")==NULL) { - me->perswitch=0; - fld=IpsRead(me, "R18", 3, ret); /* read persistant field */ - if (fabs(fld - me->field) >= 1e-5) { - IpsSay(me, 0, "\nit is not sure which field is in the magnet\n" + if (fabs(me->persfield - me->lastfield) < 1e-5 + || me->force == 2) return 1; + eve->errCode = EVE_FAULT; + SCPrintf(pCon, eWarning, + "\nit is not sure which field is in the magnet\n" "value stored in power supply: %f\n" - " in sics: %f\n" + " in software: %f\n" "use command\n \n %s confirm ...\n \n" "to specify the persistent field\n \n" - , fld, me->field, name); - return -1; - } - return 0; - } - me->perswitch=1; - fld=IpsRead(me, "R7", 3, ret); /* read actual field */ - me->field=fld; - return 1; -} -/*----------------------------------------------------------------------------*/ -static void IpsSet(IpsDriv *me, char *cmd, float val, int fmt, int *ret) { - char buf[64]; - - if (me->isPS) { - for (;fmt>0;fmt--) val=val*10; - snprintf(buf, sizeof(buf), "%s%05d", cmd, val); - } else { - snprintf(buf, sizeof(buf), "%s%f", cmd, val); - } - IpsCmd(me, buf, ret); -} -/*----------------------------------------------------------------------------*/ -static int IpsIsStable(IpsDriv *me) { -/* returns 1 when 4 subsequent readings within 0.01 Volts. - the timeinterval for the readings is specified with me->settle */ - - time_t now; - float v, vmin, vmax; - int i; - int *ret; - - assert(me); - ret=&me->errCode; - time(&now); - now = now / me->settle; - v = IpsRead(me, "R1", 2, ret); /* voltage */ - if (*ret) return 0; - i = now % 4; - me->voltage[i] = v; - vmin=me->voltage[0]; - vmax=vmin; - for (i=1; i<4; i++) { - if (me->voltage[i] < vmin) vmin = me->voltage[i]; - if (me->voltage[i] > vmax) vmax = me->voltage[i]; - } - return (fabs(vmax-vmin) < 0.015); -} -/*----------------------------------------------------------------------------*/ -static int IpsWait(IpsDriv *me) { - time_t now; - time(&now); - if (now < me->tim + 30) { /* we have to wait for stabilizing the switch heater */ - IpsSay(me, 2, "waiting %d sec", me->tim + 30 - now); - if (strstr(me->xstat, "H5")!=NULL && now > me->tim+5) { - IpsSay(me, 0, "IPS: switch heater is not connected"); - me->state=IPS_IDLE; - return HWFault; - } - if (now < me->tim+30) return HWBusy; - } + , me->persfield, me->lastfield, eve->evc->pName); + me->force = 0; return 0; } /*----------------------------------------------------------------------------*/ -static int IpsStepper(void *evcV, SConnection *pCon) { - pEVControl evc; - pEVDriver self; - IpsDriv *me; - int *ret; +#define A EVE_ACTPAR +#define L EVE_LOGPAR +#define S EVE_SAVEPAR + +void IpsPars(IpsDriv *me, EveParArg *arg) { + IpsOk(me, EveArgConn(arg)); + EveIntPar(arg, "persmode", &me->persmode, usUser, A+S); + EveIntPar(arg, "perswitch", &me->perswitch, usInternal, A); + EveObPar(arg, UPLIMIT, "%.5g\tT", A+S); + EveFloatPar(arg, "ramp", &me->ramp, "%.5g\tT/min", usUser, A+S); + EveStdParEnd(arg, "%.5g\tT", A+L+S); +} +/*----------------------------------------------------------------------------*/ +void IpsStatus(IpsDriv *me) { + char *ans; + int *code; + Eve *eve=&me->eve; + int swi; + + if (eve->state != readState) return; + ans=eve->ans; + code=&eve->errCode; + if (ans[0] != 'X' || + ans[3] != 'A' || + ans[5] != 'C' || + ans[7] != 'H' || + ans[9] != 'M') { + EvePrintf(eve, eError, "illegal status response"); + *code = EVE_FAULT; + return; + } + switch (ans[1]) { + case '0': break; + case '1': EvePrintf(eve, eError, "magnet quenched"); *code = EVE_FAULT; return; + case '2': EvePrintf(eve, eError, "IPS overheated"); *code = EVE_FAULT; return; + case '4': EvePrintf(eve, eError, "IPS warming up"); *code = EVE_FAULT; return; + case '8': EvePrintf(eve, eError, "IPS fault"); *code = EVE_FAULT; return; + default: + EvePrintf(eve, eError, "illegal status response"); + *code = EVE_FAULT; + return; + } + if (ans[6] != '3' && me->remote == 2) { + EvePrintf(eve, eError, "IPS switched to local"); + *code = EVE_FAULT; + me->remote = 1; + return; + } + if (ans[8] == '5') { + me->heaterFault = 1; + return; + } + if (ans[8] == '1') { + swi = 1; + } else { + swi = 0; + } + if (swi != me->perswitch || me->swtim == 0) { + me->swtim = time(NULL); + me->perswitch = swi; + } +} +/*----------------------------------------------------------------------------*/ +static void IpsSetField(IpsDriv *me, float val) { + char buf[128]; + if (me->eve.value != val && me->eve.evc != NULL) { + snprintf(buf, sizeof(buf), "%s = %g", me->eve.evc->pName, val); + InvokeCallBack(me->eve.evc->pCall, VALUECHANGE, buf); + } + if (me->perswitch) { + me->current = val; + me->lastfield = val; + me->persfield = val; + } else if (me->force == 2) { + me->lastfield = val; + } else { + me->persfield = val; + } + me->eve.value = val; +} +/*----------------------------------------------------------------------------*/ +static int IpsRead(long pc, IpsDriv *me) { + Eve *eve=&me->eve; + + FSM_BEGIN + EveWrite(eve, "X"); + FSM_NEXT + IpsStatus(me); /* check for errors and get perswitch */ + if (!me->remote) goto rd; + EveWrite(eve, "C0"); + me->remote = 0; + FSM_NEXT + + rd: + EveWrite(eve, "R7"); /* read current (in Tesla) */ + FSM_NEXT + me->current = OiGetFlt(eve, 3, NULL); + if (me->perswitch) { + IpsSetField(me, me->current); + goto quit; + } + EveWrite(eve, "R18"); /* read persistant field (in Tesla) */ + FSM_NEXT + IpsSetField(me, OiGetFlt(eve, 3, NULL)); + + quit: + FSM_END +} +/*----------------------------------------------------------------------------*/ +static int IpsStart(long pc, IpsDriv *me) { + Eve *eve=&me->eve; + + FSM_BEGIN + EveWrite(eve, "V"); + FSM_NEXT + if (0 == strncmp(eve->version, "IPS120", 6)) { + me->eve.syntax = 1; + } else if (0 == strncmp(eve->version, "PS", 2)) { + me->eve.syntax = 0; + } else { + EvePrintf(eve, eError, "unknown power supply version: %s", eve->version); + goto quit; + } + EvePrintf(eve, eStatus, "connected to %s", eve->version); + FSM_CALL(IpsRead); + + quit: + FSM_END +} +/*----------------------------------------------------------------------------*/ +static int IpsChangeField(long pc, IpsDriv *me) { + Eve *eve=&me->eve; + pEVControl evc=eve->evc; float fld; float step; float ramp; - int i; - int swi; - int hwstate; - char *ans; - time_t now; + time_t delay; - evc=evcV; - assert(evc); - self=evc->pDriv; - assert(self); - me = (IpsDriv *)self->pPrivate; - assert(me); - - me->msg[0]='\0'; - me->errCode=0; - ret=&me->errCode; - - /* check status */ - if (me->state == IPS_IDLE) { - hwstate = HWIdle; - } else { - hwstate = HWBusy; - ans = IpsStatus(me, ret); - if (*ret) goto error; - if (strstr(ans, "X00") != ans - || strchr(ans, 'A') == NULL - || strchr(ans, 'C') == NULL - || strchr(ans, 'H') == NULL - || strchr(ans, 'M') == NULL - || strchr(ans, 'P') == NULL) { - IpsSay(me, 0, "IPS illegal status: %s", ans); - goto error; - } - if (strstr(ans, "C3") == NULL && me->state > IPS_START) { - IpsSay(me, 0, "IPS switched to local - stopped"); - IpsCmd(me, "C0", ret); - goto error; - } - if (evc->iStop) { - IpsSay(me, 0, "IPS stopped"); - IpsCmd(me, "C0", ret); - me->state = IPS_IDLE; - hwstate = HWIdle; - } - } - - switch (me->state) { - case IPS_START: - swi=IpsCheckField(me, evc->pName, ret); - if (*ret) goto error; - if (swi < 0) { - *ret=1; - goto error; - } - if (fabs(evc->fTarget - me->field) < 1e-5 && me->perswitch != me->persmode) { - IpsSay(me, 1, "IPS: we are already at field %f", me->field); - me->state = IPS_IDLE; - hwstate = HWIdle; - break; - } - IpsCmd(me, "C3", ret); - if (*ret) goto error; - IpsCmd(me, "F7", ret); /* show current in Tesla */ - if (*ret) goto error; - IpsCmd(me, "A0", ret); /* hold */ - if (*ret) goto error; - if (swi < 0) { - *ret=OX_ILL_FLD; - goto error; - } - me->stabilize=0; - if (!me->perswitch) { - fld=IpsRead(me, "R7", 3, ret); /* read actual current (in Tesla) */ - if (*ret) goto error; - if (fabs(fld - me->field) >= 1e-5) { - me->stabilize=1; - time(&now); - if (now < me->tim+30) { - IpsSay(me, 1, "IPS: wait until heat switch is open"); - } - } - } - me->state=IPS_WAIT; - /* fall through */ - - case IPS_WAIT: - if (me->stabilize) { - i=IpsWait(me); - if (i) { hwstate=i; break; } - IpsSet(me, "J", me->field, 3, ret); /* set point */ - if (*ret) goto error; - IpsSay(me, 1, "IPS: ramp to current for %f Tesla", me->field); - IpsCmd(me, "A1", ret); /* go to setpoint */ - if (*ret) goto error; - for (i=0; i<4; i++) { /* initialize voltage history */ - me->voltage[i] = 10*i; /* just some dirty values */ - } - } - me->state = IPS_UP; - /* fall through */ - - case IPS_UP: - fld=IpsRead(me, "R7", 3, ret); /* read actual field */ - if (fabs(fld - me->field) > 1e-5) break; - me->state = IPS_STAB1; - if (me->stabilize) { - IpsSay(me, 1, "IPS: stabilize"); - } - - case IPS_STAB1: - if (me->stabilize && ! IpsIsStable(me)) break; - - me->state=IPS_START_RAMP; - if (strstr(me->xstat, "H1")==NULL) { - if (me->force==2) { - IpsCmd(me, "H2", ret); + FSM_BEGIN + EveWrite(eve, "C3"); + me->remote = 1; + FSM_NEXT + EveWrite(eve, "F7"); /* switch to tesla on display */ + FSM_NEXT + EveWrite(eve, "A0"); /* hold */ + FSM_NEXT + FSM_CALL(IpsRead); + me->remote = 2; + if (!IpsOk(me, NULL)) goto finish; + if (fabs(evc->fTarget - me->lastfield) < 1e-5) { + EvePrintf(eve, -1, "IPS: we are already at field %f", me->lastfield); + if (me->persmode) { + if (!me->perswitch) goto finish; + goto target_reached; } else { - IpsCmd(me, "H1", ret); + if (me->perswitch) goto finish; } - if (*ret) goto error; - me->perswitch = 1; - me->force = 0; - time(&me->tim); - IpsSay(me, 1, "IPS: wait until heat switch is open"); - break; } + if (fabs(me->current - me->lastfield) < 1e-5) { + goto switch_on; + } + OiSet(eve, "J", me->lastfield, 3); /* set point */ + FSM_NEXT + EveWrite(eve, "A1"); + EvePrintf(eve, -1, "IPS: ramp to current for %f Tesla", me->lastfield); + FSM_NEXT + me->tim = time(NULL); + + stab1: + EveWrite(eve, "X"); + FSM_NEXT + IpsStatus(me); /* just check for errors */ + EveWrite(eve, "R7"); /* read current (in Tesla) */ + FSM_NEXT + me->current = OiGetFlt(eve, 3, NULL); + if (fabs(me->current - me->lastfield) > 1e-5) goto stab1; + + stab2: + FSM_WAIT(1) + EveWrite(eve, "X"); + FSM_NEXT + IpsStatus(me); + if (time(NULL) < me->tim + 3) goto stab2; /* stabilize */ + + switch_on: + if (me->perswitch) goto wait_open; + if (me->force == 2) { + EveWrite(eve, "H2"); + } else { + EveWrite(eve, "H1"); + } + me->force = 0; + FSM_NEXT me->perswitch = 1; - me->force=0; - /* fall through */ + me->swtim = time(NULL); - case IPS_START_RAMP: - i=IpsWait(me); - if (i) { hwstate=i; break; } - IpsSet(me, "T", me->ramp, 3, ret); - if (*ret) goto error; - IpsSay(me, 1, "IPS: ramp to %f Tesla", evc->fTarget); + wait_open: + delay = me->swtim + 30 - time(NULL); + if (delay > 0) + EvePrintf(eve, -1, "IPS: wait %d sec to open switch", delay); - IpsCmd(me, "A1", ret); - if (*ret) goto error; - me->state=IPS_RAMP; - /* fall through */ - - case IPS_RAMP: - ramp=IpsRead(me, "R9", 3, ret); /* read ramp rate */ - if (*ret) goto error; - me->field=IpsRead(me, "R7", 3, ret); /* read "current" in Tesla */ - if (*ret) goto error; + start_ramp: + FSM_WAIT(1) + EveWrite(eve, "X"); + FSM_NEXT + IpsStatus(me); /* check for errors */ + if (me->heaterFault) { + if (time(NULL) > me->swtim + 3) { + EvePrintf(eve, eError, "IPS heater fault"); + eve->errCode = EVE_FAULT; + goto off_finish; + } + me->heaterFault = 0; + } + if (time(NULL) < me->swtim + 30) goto start_ramp; /* wait */ + OiSet(eve, "T", me->ramp, 3); + FSM_NEXT + OiSet(eve, "J", me->current, 3); /* put set point to actual value */ + FSM_NEXT + EveWrite(eve, "A1"); /* go to setpoint (do not yet run) */ + FSM_NEXT + EvePrintf(eve, -1, "IPS: ramp to %f Tesla", evc->fTarget); + + ramping: + FSM_WAIT(1) + EveWrite(eve, "R7"); /* read "current" in Tesla */ + FSM_NEXT + IpsSetField(me, OiGetFlt(eve, 3, NULL)); /* set me->current and callback */ + EveWrite(eve, "X"); + FSM_NEXT + IpsStatus(me); /* just check for errors */ + EveWrite(eve, "R9"); /* read back ramp rate (may be sweep limited) */ + FSM_NEXT + ramp=OiGetFlt(eve, 3, NULL); step=ramp/20; /* step = ramp * 3sec */ if (step < 0.001) step=0.001; - if (evc->fTarget > me->field + step) { - fld=me->field + step; - } else if (evc->fTarget < me->field - step) { - fld=me->field - step; + if (evc->fTarget > me->current + step) { + fld=me->current + step; + } else if (evc->fTarget < me->current - step) { + fld=me->current - step; } else { fld=evc->fTarget; - if (fabs(me->field - evc->fTarget) < 1e-5) { - IpsCmd(me, "A0", ret); - if (!me->persmode) { - IpsCmd(me, "C0", ret); - if (*ret) goto error; - me->state = IPS_IDLE; - hwstate = HWIdle; - break; - } - for (i=0; i<4; i++) { /* initialize voltage history */ - me->voltage[i]=10*i; /* just some dirty values */ - } - me->state = IPS_STAB2; - IpsSay(me, 1, "IPS: stabilize"); - } + if (fabs(me->current - evc->fTarget) < 1e-5) goto target_reached; } - IpsSet(me, "J", fld, 3, ret); - if (*ret) goto error; - break; - - case IPS_STAB2: - evc->eMode = EVMonitor; - if (!me->persmode || IpsIsStable(me)) { - IpsSay(me, 1, "IPS: wait until heat switch is closed"); - IpsCmd(me, "H0", ret); - if (*ret) goto error; - me->perswitch = 0; - time(&me->tim); - me->state = IPS_DOWN; - } - hwstate = HWIdle; - break; - - case IPS_DOWN: - hwstate = HWIdle; - i=IpsWait(me); - if (i) { - if (i == HWFault) { - hwstate = HWFault; - } - } else { - IpsSay(me, 1, "IPS: ramp current down"); - IpsCmd(me, "A2", ret); - if (*ret) goto error; - IpsCmd(me, "C0", ret); - if (*ret) goto error; - me->state = IPS_IDLE; - } - break; - } -error: - if (*ret) { - me->state = IPS_IDLE; - hwstate=HWFault; - } - if (me->msg[0] != '\0') { - if (pCon != NULL) { - SCWrite(pCon, me->msg, eWarning); - } else { - ServerWriteGlobal(me->msg, eWarning); - } - me->msg[0]='\0'; - } - return hwstate; -} -/*-------------------------------------------------------------------------*/ -int IpsWrapper(SConnection *pCon, SicsInterp *pSics, void *pData, - int argc, char *argv[]) { - pEVControl self = NULL; - char cmd[256], result[256], *res; - int iRet, *ret; - pEVDriver pD; - IpsDriv *me; - float fVal, fVal2, pf; + OiSet(eve, "J", fld, 3); + FSM_NEXT + goto ramping; - self = (pEVControl)pData; - assert(self); - assert(pCon); - assert(pSics); + target_reached: + eve->hwstate = HWIdle; + EveWrite(eve, "A0"); /* hold */ + FSM_NEXT + evc->eMode = EVMonitor; /* we are at field, drive has finished */ + if (!me->persmode) goto hold_finish; + /* but we continue in the background */ + me->tim = time(NULL); - if (argc < 2) { - return EVControlWrapper(pCon,pSics,pData,argc,argv); - } - pD=self->pDriv; assert(pD); - me=pD->pPrivate; assert(me); - me->msg[0]='\0'; - ret=&me->errCode; + stab3: + FSM_WAIT(1) + EveWrite(eve, "X"); + FSM_NEXT + IpsStatus(me); /* just check for errors */ + if (time(NULL) < me->tim + 3) goto stab3; /* stabilize */ + + EveWrite(eve, "H0"); + me->perswitch = 0; + me->swtim = time(NULL); + me->lastfield = me->current; + FSM_NEXT + EvePrintf(eve, -1, "IPS: wait 30 sec to close switch"); + + wait_closed: + FSM_WAIT(1) + EveWrite(eve, "X"); + FSM_NEXT + IpsStatus(me); + if (time(NULL) < me->swtim + 30) goto wait_closed; /* wait */ + + if (me->current == 0) goto finish; + EveWrite(eve, "A2"); /* goto zero */ + EvePrintf(eve, -1, "IPS: ramp current to 0"); + FSM_NEXT + goto finish; - if (strlen(argv[1]) >= sizeof(cmd)) { - return EVControlWrapper(pCon,pSics,pData,argc,argv); - } - strcpy(cmd, argv[1]); - strtolower(cmd); - if (0==strcmp(cmd, "ramp")) { - if (argc > 2) { - me->ramp=atof(argv[2]); + hold_finish: + EveWrite(eve, "A0"); + FSM_NEXT + goto finish; + + off_finish: + if (me->perswitch) { + me->lastfield = me->current; + me->swtim = time(NULL); } - sprintf(result, "%f", me->ramp); - } else if (0==strcmp(cmd, "limit")) { - if (argc == 2) { - fVal=ObVal(self->pParam, UPLIMIT); - fVal2=ObVal(self->pParam, LOWLIMIT); - if (-fVal2 > fVal) fVal=fVal2; - } else { - fVal=atof(argv[2]); - iRet = EVCSetPar(self, "upperlimit", fabs(fVal),pCon); - if (!iRet) { *ret=1; goto error; } - iRet = EVCSetPar(self, "lowerlimit", fVal,pCon); - if (!iRet) { *ret=1; goto error; } - } - sprintf(result, "%f", fVal); - } else if (0==strcmp(cmd, "persmode")) { - if (argc > 2) { - me->persmode = atoi(argv[2]); - } - sprintf(result, "%d", me->persmode); - } else if (0==strcmp(cmd, "verbose")) { - if (argc > 2) { - me->verbose = atoi(argv[2]); - } - sprintf(result, "%d", me->verbose); - } else if (0==strcmp(cmd, "list")) { - IpsStatus(me, ret); - if (*ret) goto error; - IpsCheckField(me, self->pName, ret); - if (*ret) goto error; - IpsSay(me, 0, "%s.%s = %.0f", self->pName, "access", ObVal(self->pParam, ACCESS)); - IpsSay(me, 0, "%s.%s = %.0f", self->pName, "ErrorHandler", ObVal(self->pParam, ERRORHANDLER)); - IpsSay(me, 0, "%s.%s = %.0f", self->pName, "interrupt", ObVal(self->pParam, INTERRUPT)); - IpsSay(me, 0, "%s.%s = %d", self->pName, "persmode", me->persmode); - IpsSay(me, 0, "%s.%s = %d", self->pName, "perswitch", me->perswitch); - IpsSay(me, 0, "%s.%s = %d", self->pName, "verbose", me->verbose); - fVal=ObVal(self->pParam, UPLIMIT); - fVal2=ObVal(self->pParam, LOWLIMIT); - if (-fVal2 > fVal) fVal=fVal2; - IpsSay(me, 0, "%s.%s = %f", self->pName, "limit", fVal); - IpsSay(me, 0, "%s.%s = %f", self->pName, "ramp", me->ramp); - IpsSay(me, 0, "%s.%s = %f", self->pName, "CurrentValue", me->field); - IpsSay(me, 0, "%s.%s = %f", self->pName, "TargetValue", self->fTarget); - IpsSay(me, 0, "%s.driver = %s", self->pName, self->driverName); - if (self->errorScript != NULL) { - IpsSay(me, 0, "%s.errorScript = %s", self->pName, self->errorScript); - } else { - IpsSay(me, 0, "%s.errorScript = UNDEFINED", self->pName); - } - result[0]='\0'; - } else if (0==strcmp(cmd, "confirm")) { - if (argc > 2) { - if (argc > 3) { - IpsSay(me, 0, "Too many arguments"); - goto error; - } - fVal=atof(argv[2]); - if (fVal < ObVal(self->pParam, LOWLIMIT) || - fVal > ObVal(self->pParam, UPLIMIT)) { - IpsSay(me, 0, "Field outside limit"); - goto error; - } - res=IpsStatus(me, ret); - if (*ret) goto error; - if (NULL!=strstr(res, "H1")) { - pf=IpsRead(me, "R7", 3, ret); /* read actual field */ - if (*ret) goto error; - IpsSay(me, 0, "switch heater is on - field is %f", pf); - goto error; - } - pf=IpsRead(me, "R18", 3, ret); /* read persistant field */ - if (*ret) goto error; - if (fabs(fVal - me->forcedfield) > 1e-5) { - me->force=0; - } - if (me->force==0) { - if (fabs(fVal - pf) > 1e-5 && fabs(fVal - me->field) > 1e-5) { - IpsSay(me, 0, "Be aware that this does neither match the stored" - " field in sics\nnor the field stored in power supply."); - } - IpsSay(me, 0, "Please repeat this command, to confirm again" - " the persistent field of\n %f Tesla.", fVal); - me->force=1; - result[0]='\0'; - } else if (me->force=1) { - me->force=2; - me->field=fVal; - sprintf(result, "%f", me->field); - } - me->forcedfield = fVal; - } else { - IpsStatus(me, ret); - if (*ret) goto error; - IpsCheckField(me, self->pName, ret); - if (*ret) goto error; - sprintf(result, "%f", me->field); - } - } else { - return EVControlWrapper(pCon,pSics,pData,argc,argv); - } - if (result[0] != '\0') { - IpsSay(me, 0, "%s.%s = %s", self->pName, argv[1], result); - } -error: - if (me->msg[0] != '\0') { - SCWrite(pCon, me->msg, eWarning); - me->msg[0]='\0'; - } - if (*ret) { - return 0; - } else { - return 1; - } + EveWrite(eve, "H0"); + FSM_NEXT + + finish: + EveWrite(eve, "C0"); + me->remote = 0; + eve->hwstate = HWIdle; + FSM_NEXT + + FSM_END } /*----------------------------------------------------------------------------*/ -static int IpsGet(pEVDriver self, float *fPos) { - IpsDriv *me = NULL; - int *ret; - time_t now; +int IpsConfirm(SConnection *pCon, pEVControl evc, int argc, char *argv[]) { float fld; - - assert(self); - me = (IpsDriv *)self->pPrivate; - assert(me); - - ret=&me->errCode; - IpsStatus(me, ret); - if (!*ret) { - IpsCheckField(me, "magfield", ret); - } - *fPos=me->field; - if(*ret < 0) { - return 0; - } - return 1; -} -/*----------------------------------------------------------------------------*/ -static int IpsRun(pEVDriver self, float fVal) { IpsDriv *me; - int *ret; - assert(self); - me = (IpsDriv *)self->pPrivate; - assert(me); - - ret=&me->errCode; - IpsStatus(me, ret); - if (*ret) return 0; - me->state=IPS_START; - return 1; -} -/*--------------------------------------------------------------------------*/ -int IpsError(pEVDriver self, int *iCode, char *error, int iErrLen) { - IpsDriv *me = NULL; + me=evc->pDriv->pPrivate; assert(me); - assert(self); - me = (IpsDriv *)self->pPrivate; - assert(me); - - *iCode = 1; /* severe */ - if (me->msg[0]=='\0') { - strncpy(error, "undefined error", iErrLen); - } else { - strncpy(error, me->msg, iErrLen); - } - error[iErrLen-1]='\0'; - return 1; -} -/*---------------------------------------------------------------------------*/ -static int IpsFix(pEVDriver self, int iError) { - IpsDriv *me = NULL; - int iRet; - - assert(self); - me = (IpsDriv *)self->pPrivate; - assert(me); - - return(DEVFAULT); /* severe */ - - /* never used: return(DEVREDO); */ -} -/*--------------------------------------------------------------------------*/ -static int IpsSend(pEVDriver self, char *pCommand, char *pReply, int iLen) { - IpsDriv *me = NULL; - int iRet; - - assert(self); - me = (IpsDriv *)self->pPrivate; - assert(me); - - iRet = transactRS232(me->ser, pCommand, strlen(pCommand), pReply, iLen); - if(iRet < 0) - { - me->errCode = iRet; - IpsWriteError(me); - return 0; - } - return 1; -} -/*--------------------------------------------------------------------------*/ -static int IpsInit(pEVDriver self) { - IpsDriv *me = NULL; - int iRet; - char *res, buf[128]; - pExeList exe; - SConnection *con; - - assert(self); - me = (IpsDriv *)self->pPrivate; - assert(me); - - iRet = initRS232(me->ser); - if (iRet != 1) { - me->errCode = iRet; - IpsWriteError(me); - return 0; - } - setRS232ReplyTerminator(me->ser,"\r"); - setRS232SendTerminator(me->ser,"\r"); - setRS232Timeout(me->ser,1000); /* microseconds ? milliseconds ? */ - setRS232Debug(me->ser,0); - - iRet=transactRS232(me->ser, "V", 1, buf, sizeof(buf)); - if (iRet != 1) { - if (iRet == 0) { - me->errCode = 1; - IpsSay(me, 0, "IPS: unknown RS232 error"); - } else { - me->errCode = iRet; - IpsWriteError(me); + if (argc > 1) { + if (argc > 2) { + SCPrintf(pCon, eError, "Too many arguments"); + return -1; + } + fld=atof(argv[1]); + if (fld < ObVal(evc->pParam, UPLIMIT)) { + SCPrintf(pCon, eError, "Field outside limit"); + return -1; + } + if (me->perswitch) { + SCPrintf(pCon, eWarning, "switch heater is on - field is %f", me->current); + return -1; + } + if (fabs(fld - me->persfield) > 1e-5 && fabs(fld - me->lastfield) > 1e-5) { + SCPrintf(pCon, eWarning, "Be aware that this does neither match the field" + " stored in software\nnor the field stored in power supply."); + me->force = 0; + } + if (me->force == 0) { + SCPrintf(pCon, eWarning, "Please repeat this command, to confirm again" + " the persistent field of\n %f Tesla.", fld); + IpsSetField(me, fld); + me->force=1; + } else { + me->force=2; + IpsSetField(me, fld); + SCPrintf(pCon, eValue, "%s.%s = %f", evc->pName, argv[1], fld); } - return 0; - } - - if (0==strncmp(buf, "IPS120", 6)) { - me->isPS=0; - } else if (0==strncmp(buf, "PS120", 5)) { - me->isPS=1; } else { - IpsSay(me, 0, "unknown power supply version: %s", buf); - return 0; + SCPrintf(pCon, eValue, "%s.%s = %f", evc->pName, argv[1], me->eve.value); } - - IpsStatus(me, &iRet); - me->msg[0]='\0'; - IpsCheckField(me, "magfield", &iRet); - me->state = IPS_IDLE; - return 1; -} -/*--------------------------------------------------------------------------*/ -static int IpsClose(pEVDriver self) { -/* - seems not to be needed - - IpsDriv *me = NULL; - int iRet; - - assert(self); - me = (IpsDriv *)self->pPrivate; - assert(me); - - me->pData=NULL; -*/ - return 1; -} -/*--------------------------------------------------------------------------*/ -static int IpsHalt(pEVDriver *self) { - assert(self); - /* to be implemented */ return 1; } /*------------------------------------------------------------------------*/ -void IpsKill(void *pData) { - IpsDriv *me = NULL; - - me = (IpsDriv *)pData; - assert(me); - KillRS232(me->ser); - free(me); +static int IpsIsOk(void *data) { + /* always in tolerance (here we may implement what to do in case of a quench) */ + return 1; } /*------------------------------------------------------------------------*/ -pEVDriver CreateIpsDriver(int argc, char *argv[]) { - pEVDriver new = NULL; - IpsDriv *me = NULL; - int port; +pEVControl IpsMakeEVC(SConnection *pCon, int argc, char *argv[]) { + /* args: + ips + ips + */ + IpsDriv *me; + Eve *eve; + pEVControl evc; + + evc = MakeEveEVC(argc, argv, calloc(1, sizeof *me), pCon); + if (!evc) return NULL; - if (argc < 2) { - return NULL; - } - new = CreateEVDriver(argc,argv); - me = (IpsDriv *)malloc(sizeof(IpsDriv)); - memset(me,0,sizeof(IpsDriv)); - if(!new || !me) return NULL; + me = evc->pDriv->pPrivate; + eve=&me->eve; - new->pPrivate = me; - new->KillPrivate = IpsKill; - - /* initalise IpsDriver */ - /* me->lastError = NULL; */ - me->verbose = 0; - me->field = 0; + me->current = 0; + me->persfield = 0; + me->lastfield = 0; me->persmode = 1; me->perswitch = 0; me->force = 0; me->tim = 0; - me->settle = 1; - me->state=IPS_INIT; + me->swtim = 0; me->ramp=0.1; - me->isPS=0; - port=atoi(argv[1]); - if (port==0) return NULL; - - me->ser=createRS232(argv[0], port); - if (me->ser == NULL) return NULL; + eve->run = (FsmFunc)IpsChangeField; + eve->read = (FsmFunc)IpsRead; + eve->pardef = (EveParDef)IpsPars; + eve->todo = (FsmFunc)IpsStart; + eve->task = FsmStartTask(me, (FsmHandler)OiHandler, (FsmFunc)EveIdle); - /* initialise function pointers */ - new->SetValue = IpsRun; - new->GetValue = IpsGet; - new->Send = IpsSend; - new->GetError = IpsError; - new->TryFixIt = IpsFix; - new->Init = IpsInit; - new->Close = IpsClose; + evc->pEnvir->IsInTolerance = IpsIsOk; + EVCSetPar(evc,"upperlimit",14.9,pCon); + EVCSetPar(evc,"lowerlimit",-14.9,pCon); - return new; -} -/*------------------------------------------------------------------------*/ -static int IpsWatcher(void *data) { - pEVControl self; - pExeList exe; - SConnection *con; - int iRet; - - assert(data); - self= (pEVControl)data; - exe = GetExecutor(); - con = GetExeOwner(exe); - iRet = IpsStepper(self, con); - return 1; -} -/*------------------------------------------------------------------------*/ -void IpsCustomize(SConnection *pCon, pEVControl pEvc) { -/* customize tecs driver */ - IpsDriv *me; - - me=pEvc->pDriv->pPrivate; - assert(me); - pEvc->pDrivInt->CheckStatus=IpsStepper; - pEvc->pEnvir->IsInTolerance=IpsWatcher; - EVCSetPar(pEvc,"upperlimit",14.9,pCon); - EVCSetPar(pEvc,"lowerlimit",-14.9,pCon); - if (me->msg[0]!='\0') { /* write message from IpsInit */ - SCWrite(pCon, me->msg, eWarning); - } + return evc; } diff --git a/itcdriv.c b/itcdriv.c new file mode 100644 index 0000000..5bffa51 --- /dev/null +++ b/itcdriv.c @@ -0,0 +1,272 @@ +/*--------------------------------------------------------------------------- +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 coldvalve; + int sampleChan; + int controlChan; + int gas; + int remote; + int h; /* actual heater channel */ + int a; /* actual auto mode */ +} ItcDriv; + +/*----------------------------------------------------------------------------*/ +#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"}; + + 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; + EveFloatPar(arg, "htr", &me->htr, "%.1f\t%%", usInternal, flag*A + L); + flag = me->gas > 0; + EveFloatPar(arg, "coldvalve", &me->coldvalve, "%.1f\t%%", usInternal, 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, "gas", &me->gas, 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 int 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); + + skip0: + EveWrite(eve, "R5"); /* read heater */ + FSM_NEXT + me->htr = OiGetFlt(eve, 1, NULL); + if (!me->gas < 0) goto skipgas; + EveWrite(eve, "R7"); /* read gas flow */ + FSM_NEXT + me->coldvalve = OiGetFlt(eve, 1, NULL); + + skipgas: + me->eve.value = me->t[me->sampleChan]; + FSM_END +} +/*----------------------------------------------------------------------------*/ +static int 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 int 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->gas == 2) a = 3; + if (me->h == me->controlChan && me->a == a) goto skipa; + if (me->gas == 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 +} +/*------------------------------------------------------------------------*/ +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; + 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; +} diff --git a/lcdriv.c b/lcdriv.c new file mode 100644 index 0000000..5832cf9 --- /dev/null +++ b/lcdriv.c @@ -0,0 +1,184 @@ +/*--------------------------------------------------------------------------- +lcdriv.c + +Driver for the Oxford Instruments Teslatron lambda 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 "oicom.h" +#include "fsm.h" + +typedef struct { + Eve eve; + float t[4]; /* set t. & 3 temperatures */ + int dig[4]; /* format for these */ + float coldvalve; + int gas; + int remote; + int hot; +} LcDriv; + +/*----------------------------------------------------------------------------*/ +#define A EVE_ACTPAR +#define L EVE_LOGPAR +#define S EVE_SAVEPAR + +void LcPars(LcDriv *me, EveParArg *arg) { + char fmt[80]; + + sprintf(fmt, "%%.%df\tK", me->dig[2]); + EveFloatPar(arg, "t2", &me->t[2], fmt, usInternal, (me->dig[2] >= 0) * A + L); + + sprintf(fmt, "%%.%df\tK", me->dig[3]); + EveFloatPar(arg, "t3", &me->t[3], fmt, usInternal, (me->dig[3] >= 0) * A + L); + + EveFloatPar(arg, "coldvalve", &me->coldvalve, "%.1f\t%%", usInternal, 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); + + sprintf(fmt, "%%.%df\tmbar", me->dig[1]); + EveStdParEnd(arg, fmt, 0); +} +/*----------------------------------------------------------------------------*/ +void LcStatus(LcDriv *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; + } + if (ans[6] != '3' && me->remote == 2) { + EvePrintf(eve, eError, "LC switched to local"); + *code = EVE_FAULT; + me->remote = 1; + return; + } +} +/*----------------------------------------------------------------------------*/ +static int LcRead(long pc, LcDriv *me) { + Eve *eve=&me->eve; + char *p; + int l; + + FSM_BEGIN + EveWrite(eve, "X"); + FSM_NEXT + LcStatus(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], NULL); + me->eve.value = me->t[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], NULL); + skip2: + if (me->dig[3] < 0) goto skip3; + EveWrite(eve, "R3"); /* read sensor 3 */ + FSM_NEXT + me->t[3] = OiGetFlt(eve, me->dig[3], NULL); + skip3: + EveWrite(eve, "R7"); /* read gas flow */ + FSM_NEXT + me->coldvalve = OiGetFlt(eve, 1, NULL); + quit: + FSM_END +} +/*----------------------------------------------------------------------------*/ +static int LcStart(long pc, LcDriv *me) { + Eve *eve=&me->eve; + + FSM_BEGIN + EveWrite(eve, "V"); + FSM_NEXT + if (0 == strncmp(eve->version, "TESLATRON", 9)) { + me->eve.syntax = 0; + me->dig[1] = 1; + me->dig[2] = 2; + me->dig[3] = 1; + } else { + EvePrintf(eve, eError, "unknown lambda controller version: %s", eve->version); + goto quit; + } + EvePrintf(eve, eStatus, "connected to %s", eve->version); + FSM_CALL(LcRead); + + quit: + FSM_END +} +/*----------------------------------------------------------------------------*/ +static int LcSetTemp(long pc, LcDriv *me) { + Eve *eve=&me->eve; + pEVControl evc=eve->evc; + float fld; + float step; + float ramp; + char buf[4]; + SConnection *pCon; + + FSM_BEGIN + FSM_END +} +/*------------------------------------------------------------------------*/ +pEVControl LcMakeEVC(SConnection *pCon, int argc, char *argv[]) { + /* args: + lc + + */ + Eve *eve; + pEVControl evc; + LcDriv *me = NULL; + + evc = MakeEveEVC(argc, argv, calloc(1, sizeof *me), pCon); + if (!evc) return NULL; + + me = evc->pDriv->pPrivate; + eve=&me->eve; + + eve->run = (FsmFunc)LcSetTemp; + eve->read = (FsmFunc)LcRead; + eve->pardef = (EveParDef)LcPars; + eve->todo = (FsmFunc)LcStart; + eve->task = FsmStartTask(me, (FsmHandler)OiHandler, (FsmFunc)EveIdle); + + return evc; +} diff --git a/logger.c b/logger.c new file mode 100644 index 0000000..380250a --- /dev/null +++ b/logger.c @@ -0,0 +1,352 @@ +/*--------------------------------------------------------------------------- +logger.c + +Markus Zolliker, Sept 2004 +---------------------------------------------------------------------------- +*/ + +#include +#include +#include +#include +#include +#include +#include +#include "sics.h" +#include "logger.h" + +#define LOGGER_NAN -999999. + +struct Logger { + char *name; + char old[132]; + int period; + time_t last; +}; + +static char *dir = NULL; + +/*--------------------------------------------------------------------------*/ +void LoggerWrite(Logger *log, time_t now, int period, char *value) { + char path[256], stim[32], buf[32]; + struct tm *tm; + int yday, isdst; + int l; + int newday; + FILE *fil; + + if (dir == NULL) return; + if (now == 0) { + printf("now==0\n"); + } + tm = localtime(&log->last); + yday = tm->tm_yday; + tm = localtime(&now); + if (tm->tm_yday != yday) { + log->period = 0; + } else if (0 == strncmp(value, log->old, sizeof(log->old))) { /* value has not changed */ + return; + } + log->last = now; + snprintf(path, sizeof path, "%s/%s/", dir, log->name); + l = strlen(path); + + strftime(path + l, sizeof path - l, "%m-%d.log", tm); + fil = fopen(path, "a+"); + if (fil == NULL) return; + fseek(fil, 0, SEEK_SET); + fgets(buf, sizeof buf, fil); + + strftime(stim, sizeof stim, "#%Y-%m-%d %H:%M:%S\n", tm); + if (0 != strncmp(buf, stim, 11)) { + fclose(fil); + fil=fopen(path, "w+"); /* overwrite old logfile */ + if (fil == NULL) return; + fputs(stim, fil); + } else { + fseek(fil, 0, SEEK_END); /* set position to end */ + } + if (period != log->period) { + log->period = period; + snprintf(buf, sizeof buf, "\t%d", period); + } else { + buf[0]='\0'; + } + strftime(stim, sizeof stim,"%H:%M:%S", tm); + fprintf(fil, "%s\t%s%s\n", stim, value, buf); + l = strlen(value); + if (l >= sizeof(log->old)) { + l = sizeof(log->old) - 1; + } + strncpy(log->old, value, l); + log->old[l] = '\0'; + fclose(fil); +} +/*--------------------------------------------------------------------------*/ +void LoggerKill(Logger *log) { + if (!log) return; + LoggerWrite(log, time(NULL), 0, ""); + free(log->name); + free(log); +} +/*--------------------------------------------------------------------------*/ +char *LoggerGetDir(void) { + if (dir == NULL) { + dir = IFindOption(pSICSOptions, "LoggerDir"); + } + return dir; +} +/*--------------------------------------------------------------------------*/ +Logger *LoggerMake(char *name, int period) { + Logger *log, *p; + char path[256]; + struct stat st; + int i; + char *dir; + + dir = LoggerGetDir(); + if (dir == NULL) return NULL; + snprintf(path, sizeof path, "%s/%s", dir, name); + i = stat(path, &st); + if (i >= 0) { + if (((st.st_mode >> 12) & 15) != 4) { /* exists, but is no directory */ + return NULL; + } + } else { + i = mkdir(path, S_IRWXU+S_IRGRP+S_IXGRP+S_IROTH+S_IXOTH); + if (i < 0) return NULL; /* mkdir failed */ + } + log = malloc(sizeof *log); + if (log == NULL) return NULL; + log->name = strdup(name); + if (log->name == NULL) { + free(log); + return NULL; + } + log->period = 0; + log->old[0] = '\0'; + log->last = 0; + LoggerWrite(log, time(NULL) - 1, period, ""); + return log; +} +/*--------------------------------------------------------------------------*/ +typedef struct { + SConnection *pCon; + time_t step; + time_t t0, tmin, tmax; + time_t tlast; + float ymin, ymax; + float ylast; + long cnt; +} Compressor; + +static void LoggerInit(Compressor *c, SConnection *pCon, time_t step) { + c->pCon = pCon; + c->step = step; + c->tmin = -1; + c->tmax = 0; + c->tlast = 0; + c->t0 = 0; + c->ylast = LOGGER_NAN; +} + +static void LoggerOut(Compressor *c, time_t t, float y) { + char line[80]; + + /* printf("out %ld %g\n", t, y); */ + if (y != c->ylast) { + c->ylast = y; + if (y == LOGGER_NAN) { + snprintf(line, sizeof line, "%ld\n", t - c->tlast); + } else { + snprintf(line, sizeof line, "%ld %g\n", t - c->tlast, y); + } + /* printf("-%s\n", line); */ + c->cnt--; + c->tlast = t; + SCWrite(c->pCon, line, eStatus); + } +} + +static void LoggerSum(Compressor *c) { + if (c->tmin < 0 || c->tmin==0 && c->tmax==0) { + /* printf("nos %ld %ld %f %f\n", c->tmin, c->tmax, c->ymin, c->ymax); */ + LoggerOut(c, c->t0, LOGGER_NAN); + c->tmin = -1; + } else { + /* printf("sum %ld %ld %f %f\n", c->tmin, c->tmax, c->ymin, c->ymax); */ + if (c->tmin > c->tmax) { + if (c->tmax >= c->t0) { + LoggerOut(c, c->tmax, c->ymax); + } + LoggerOut(c, c->tmin, c->ymin); + } else if (c->tmin < c->tmax) { + if (c->tmin >= c->t0) { + LoggerOut(c, c->tmin, c->ymin); + } + LoggerOut(c, c->tmax, c->ymax); + } else { + LoggerOut(c, c->tmax, c->ymax); + } + if (c->ylast != LOGGER_NAN) { + c->ymin = c->ylast; + c->ymax = c->ylast; + c->tmin = 0; + c->tmax = 0; + } else { + c->tmin = -1; + } + /* printf("end %ld %ld %f %f\n", c->tmin, c->tmax, c->ymin, c->ymax); */ + } +} + +static void LoggerPut(Compressor *c, time_t t, float y) { + /* printf("put %ld %g\n", t, y); */ + if (t >= c->t0 + c->step) { + LoggerSum(c); + c->t0 = t; + } + if (y == LOGGER_NAN) return; + if (c->tmin < 0) { + c->tmin = t; + c->tmax = t; + c->ymin = y; + c->ymax = y; + } else if (y <= c->ymin) { + c->ymin = y; + c->tmin = t; + } else if (y >= c->ymax) { + c->ymax = y; + c->tmax = t; + } +} +/*--------------------------------------------------------------------------*/ +int LoggerGraph(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]) { + time_t from, to, step, xs, lastx, now; + char *p; + int i, l, yday, iret, loss; + time_t tim, tr; + struct tm tm; + char path[256], line[80]; + char *lin, *val, *stp; + FILE *fil; + Compressor c; + float yy, lasty; + + if (argc < 4) { + SCWrite(pCon, "illegal number of arguments", eError); + return 0; + } + now = time(NULL); + from = strtol(argv[1], &p, 0); /* unix time, not year 2038 safe */ + if (p == argv[1]) goto illarg; + to = strtol(argv[2], NULL, 0); + if (p == argv[2]) goto illarg; + step = strtol(argv[3], NULL, 0); + if (p == argv[3]) goto illarg; + if (from <= 0) from += now; + if (to <= 0) to += now; + if (step <= 0) step = 1; + + dir = LoggerGetDir(); + if (dir == NULL) { + SCWrite(pCon, "LoggerDir not found", eError); + return 0; + } + + loss = 0; + for (i=4; i= tim) { + if (lastx != 0) { + lastx += xs; + while (lastx < tr) { + LoggerPut(&c, lastx, lasty); + lastx += xs; + } + } + LoggerPut(&c, tr, yy); + } + lastx = tr; + lasty = yy; + } + } + if (lin == NULL) { + tm.tm_hour = 24; /* try next day */ + tm.tm_min = 0; + tm.tm_sec = 0; + tm.tm_isdst = -1; + tim=mktime(&tm); + continue; + } + } + c.ylast = LOGGER_NAN; + LoggerSum(&c); + } + snprintf(line, sizeof line, "*%d\n", loss); + SCWrite(pCon, line, eStatus); + return 1; +illarg: + SCWrite(pCon, "illegal argument", eError); + return 0; +} diff --git a/logger.h b/logger.h new file mode 100644 index 0000000..3b3b4ec --- /dev/null +++ b/logger.h @@ -0,0 +1,19 @@ +/*--------------------------------------------------------------------------- +logger.c + +Markus Zolliker, Sept 2004 +---------------------------------------------------------------------------- +*/ + +#ifndef LOGGER_H +#define LOGGER_H + +#include + +typedef struct Logger Logger; + +Logger *LoggerMake(char *name, int period); +void LoggerKill(Logger *log); +void LoggerWrite(Logger *log, time_t now, int period, char *value); + +#endif diff --git a/make_gen b/make_gen index 602ebb7..010ba97 100644 --- a/make_gen +++ b/make_gen @@ -18,7 +18,9 @@ OBJ=psi.o buffer.o ruli.o dmc.o nxsans.o nextrics.o sps.o pimotor.o \ bruker.o ltc11.o A1931.o dilludriv.o eurodriv.o slsmagnet.o \ el755driv.o amorscan.o serial.o scontroller.o t_update.o \ t_rlp.o t_conv.o el737hpdriv.o dornier2.o el734hp.o \ - el737hpv2driv.o swmotor2.o ipsdriv.o tricssupport.o + el737hpv2driv.o swmotor2.o tricssupport.o \ + oicom.o fsm.o remob.o eve.o logger.o \ + ipsdriv.o itcdriv.o ilmdriv.o lcdriv.o libpsi.a: $(OBJ) rm -f libpsi.a diff --git a/oicom.c b/oicom.c new file mode 100644 index 0000000..ccabde3 --- /dev/null +++ b/oicom.c @@ -0,0 +1,128 @@ +/*--------------------------------------------------------------------------- +oicom.c + +Communication routines for Oxford Instruments equipment + +Markus Zolliker, Aug 2004 +---------------------------------------------------------------------------- + +there is no error return value, eve->errCode is used. On success, eve->errCode +is not changed, i.e. an existing errCode is not overwritten. +*/ + +#include +#include +#include +#include +#include +#include "sics.h" +#include "rs232controller.h" +#include "oicom.h" + + +/*----------------------------------------------------------------------------*/ +int OiHandler(Eve *eve) { + int iret, l; + + if (availableNetRS232(eve->ser)) { + l = sizeof(eve->ans); + iret = readRS232TillTerm(eve->ser, eve->ans, &l); + if (eve->state < expectState) { + if (iret == 1) { + EvePrintf(eve, eError, "unexpected answer: %s", eve->ans); + } + goto quit; + } + if (iret == 1) { + EvePrintf(eve, -2, "ans: %s", eve->ans); + if (strcmp(eve->ans, "?ck") == 0) { + if (eve->state == lostState) { + EveWrite(eve, "V"); + goto quit; + } + } else if (eve->state == lostState) { + goto quit; + } else if (eve->cmd[0] == 'V') { + if (strcmp(eve->ans, eve->version) == 0) { + /* we are still connected with the same device */ + } else if (*eve->version == '\0') { + strncat(eve->version, eve->ans, sizeof(eve->version)-1); + } else { /* version (and therefore device) changed */ + eve->errCode = EVE_DEV_CHANGED; + eve->state = idleState; + goto error; + } + eve->state = idleState; + goto quit; + } else if (eve->cmd[1] == 'k') { /* ck */ + } else if (eve->cmd[0] != eve->ans[0]) { + iret = EVE_ILL_ANS; + } + } + if (iret != 1) { + eve->errCode = iret; + eve->state = idleState; + goto error; + } + eve->state = readState; + } else if (eve->state == expectState) { + if (time(NULL) > eve->cmdtime+60) { + eve->errCode = TIMEOUT; + eve->state = lostState; + } + } else if (eve->state == lostState) { + if (time(NULL) > eve->cmdtime) { + EveWrite(eve, "ck"); + eve->state = lostState; + } + } + goto quit; +error: + EveWriteError(eve); +quit: + return EveHandler(eve); +} + +double OiGetFlt(Eve *eve, int dig, int *pdig) { + char *endp, *p; + double val; + + if (eve->state != readState) { + /* eve->errCode = EVE_ILL_ANS; */ + return 0.0; + } + p = strchr(eve->ans, '.'); + if (p) { + if (pdig != NULL) { + *pdig = strlen(eve->ans) - (p - eve->ans) - 1; + } + val=strtod(eve->ans+1, &endp); + if (*endp != '\0') { + eve->errCode = EVE_ILL_ANS; + return 0.0; + } + } else { + val=strtol(eve->ans+1, &endp, 10); + if (*endp != '\0') { + eve->errCode = EVE_ILL_ANS; + return 0.0; + } + if (eve->syntax == 0) { /* old style format */ + for (; dig > 0; dig--) val=val*0.1; + } + } + return val; +} + +void OiSet(Eve *eve, char *cmd, double val, int dig) { + char buf[64]; + + if (eve->syntax == 0) { + for (;dig>0;dig--) val=val*10; + snprintf(buf, sizeof(buf), "%s%05d", cmd, val); + } else { + snprintf(buf, sizeof(buf), "%s%f", cmd, val); + } + EveWrite(eve, buf); +} + diff --git a/oicom.h b/oicom.h new file mode 100644 index 0000000..29ab58a --- /dev/null +++ b/oicom.h @@ -0,0 +1,16 @@ +/*--------------------------------------------------------------------------- +oicom.h + +Communication routines for Oxford Instruments equipment + +Markus Zolliker, Aug 2004 +----------------------------------------------------------------------------*/ +#include "rs232controller.h" +#include "eve.h" + +int OiHandler(Eve *eve); +double OiGetFlt(Eve *eve, int dig, int *pdig); +void OiSet(Eve *eve, char *cmd, double val, int dig); + + + diff --git a/psi.c b/psi.c index 559a2a7..4989502 100644 --- a/psi.c +++ b/psi.c @@ -39,7 +39,6 @@ #include "tdchm.h" #include "tecsdriv.h" #include "itc4.h" -#include "ipsdriv.h" #include "bruker.h" #include "ltc11.h" #include "A1931.h" @@ -50,10 +49,13 @@ #include "amorscan.h" #include "serial.h" #include "fomerge.h" +#include "remob.h" #include "tricssupport.h" static pSite sitePSI = NULL; +int LoggerGraph(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]); + /*----------------------------------------------------------------------*/ static void AddPsiCommands(SicsInterp *pInter){ AddCommand(pInter,"MakeRuenBuffer",InitBufferSys,NULL,NULL); @@ -77,6 +79,8 @@ static void AddPsiCommands(SicsInterp *pInter){ AddCommand(pInter,"MakePSDFrame",MakeFrameFunc,NULL,NULL); AddCommand(pInter,"SerialInit",SerialInit,NULL,NULL); AddCommand(pInter,"InstallFocusMerge",InstallFocusMerge,NULL,NULL); + AddCommand(pInter,"Remob",RemobCreate,NULL,NULL); + AddCommand(pInter,"Graph",LoggerGraph,NULL,NULL); /* AddCommand(pInter,"MakeDifrac",MakeDifrac,NULL,NULL); */ @@ -317,8 +321,6 @@ static void ConfigureController(char *name, pEVControl pNew, EVCSetPar(pNew,"lowerlimit",1.0,pCon); if(strcmp(name,"tecs") == 0){ TecsCustomize(pCon, pNew); - } else if(strcmp(name,"ips") == 0){ - IpsCustomize(pCon, pNew); } else if(strcmp(name,"euro") == 0){ EVCSetPar(pNew,"upperlimit",750.0,pCon); EVCSetPar(pNew,"lowerlimit",15.0,pCon); @@ -335,7 +337,13 @@ static void ConfigureController(char *name, pEVControl pNew, } /*-------------------------------------------------------------------*/ extern pEVDriver CreateSLSDriv(int argc, char *argv[]); + +pEVControl IpsMakeEVC(SConnection *pCon, int argc, char *argv[]); +pEVControl ItcMakeEVC(SConnection *pCon, int argc, char *argv[]); +pEVControl IlmMakeEVC(SConnection *pCon, int argc, char *argv[]); +pEVControl LcMakeEVC(SConnection *pCon, int argc, char *argv[]); /*------------------------------------------------------------------*/ + static pEVControl InstallPsiEnvironmentController(SicsInterp *pSics, SConnection *pCon, int argc, char *argv[]){ @@ -374,16 +382,13 @@ static pEVControl InstallPsiEnvironmentController(SicsInterp *pSics, } } } else if(strcmp(argv[3],"ips") == 0) { - checkError = 1; - pDriv = CreateIpsDriver(argc-4,&argv[4]); - if(pDriv){ - pNew = CreateEVController(pDriv,argv[2],&status); - if(pNew != NULL){ - AddCommand(pSics,argv[2],IpsWrapper,DeleteEVController, - pNew); - commandInstalled = 1; - } - } + return IpsMakeEVC(pCon, argc-2, argv+2); /* we should organize all devices like this M.Z. */ + } else if(strcmp(argv[3],"itc") == 0) { + return ItcMakeEVC(pCon, argc-2, argv+2); + } else if(strcmp(argv[3],"ilm") == 0) { + return IlmMakeEVC(pCon, argc-2, argv+2); + } else if(strcmp(argv[3],"lc") == 0) { + return LcMakeEVC(pCon, argc-2, argv+2); } else if(strcmp(argv[3],"bruker") == 0){ checkError = 1; pDriv = CreateBrukerDriver(argc-4,&argv[4]); @@ -439,6 +444,10 @@ static pEVControl InstallPsiEnvironmentController(SicsInterp *pSics, if(pDriv != NULL){ pNew = CreateEVController(pDriv,argv[2],&status); } + } else { + sprintf(pBueffel,"ERROR: %s not recognized as a valid driver type", argv[3]); + SCWrite(pCon,pBueffel,eError); + return NULL; } /* if we recognized the driver, check for installation errors */ diff --git a/remob.c b/remob.c new file mode 100644 index 0000000..bb568c9 --- /dev/null +++ b/remob.c @@ -0,0 +1,785 @@ +/*----------------------------------------------------------------------- +remob.c + +implements remote driveable objects living on an other sics server + +M. Zolliker July 04 + +------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include "fortify.h" +#include "sics.h" +#include "devexec.h" +#include "remob.h" +#include "splitter.h" +#include "status.h" +#include "servlog.h" +#include "site.h" +/*-------------------------------------------------------------------------*/ +#define INTERRUPTMODE 0 +#define ACCESSCODE 1 + +/*------------------------------------------------------------------------ */ +typedef struct Remob Remob; + +typedef struct RemServer { + pObjectDescriptor desc; + char *name; + char *host; + int port; + char *user; + char *pass; + mkChannel *chan; + int incomplete; + char line[256]; + Remob *objList; + int matchMap; + int timeout; + int taskActive; + SCStore conn; +} RemServer; + +struct Remob { + pObjectDescriptor desc; + char *name; + ObPar *ParArray; + pIDrivable pDrivInt; + pICallBack pCall; + RemServer *server; + int status; + Remob *next; +}; + +typedef struct { + float fVal; + char *pName; +} RemobCallback; + +typedef struct { + char *pName; + SConnection *pCon; +} RemobInfo; + +/*-------------------------------------------------------------------------*/ +static char *StartsWith(char *line, char *name) { + /* if line does not start with name, return NULL + else return a pointer to the next non-white space character + */ + char *str; + int l; + + l = strlen(name); + if (0 != strncmp(line, name, l)) return NULL; + str = line + l; + while (*str == ' ') { + str++; + } + return str; +} +/*-------------------------------------------------------------------------*/ +static int RemWrite(RemServer *remserver, char *line) { + if (remserver->chan) { + /* printf("> %s\n", line); */ + return NETWrite(remserver->chan, line, strlen(line)); + } else { + return -1; + } +} +/*-------------------------------------------------------------------------*/ +static int RemRead(RemServer *remserver, long tmo) { + int iRet; + + if (remserver->chan == NULL) return 0; /* no data */ + iRet = NETReadTillTermNew(remserver->chan, tmo, "\n", + remserver->line+remserver->incomplete, sizeof(remserver->line)-remserver->incomplete); + if (iRet == 0) { + remserver->incomplete = strlen(remserver->line); /* number of chars already received */ + return 0; /* timeout */ + } else { + remserver->incomplete=0; + } + return iRet; +} +/*-------------------------------------------------------------------------*/ +static int RemHandle(RemServer *remserver) { + char *line, *par, *str; + Remob *remob; + + /* skip whitespace at the beginning */ + line=remserver->line; + while (*line < ' ' && *line != '\0') { + line++; + } + memmove(remserver->line, line, strlen(line)); + + /* handle drivstat messages */ + line = remserver->line; + for (remob = remserver->objList; remob != NULL; remob = remob->next) { + par=StartsWith(line, remob->name); + if (par != NULL) { + if (str = StartsWith(par, "finished")) { + if (*str == '\0') { + remob->status = HWIdle; + } else { + remob->status = HWFault; + } + line[0]='\0'; + return 1; + } + if (str = StartsWith(par, "started")) { + remob->status = HWBusy; + line[0]='\0'; + return 1; + } + } + } + return 0; +} +/*-------------------------------------------------------------------------*/ +static int RemCopy(RemServer *remserver, SConnection *pCon) { + char buf[256]; + if (pCon != NULL && remserver->line[0] != '\0') { + snprintf(buf, sizeof(buf), " %s", remserver->line); + /* snprintf(buf, sizeof(buf), "%s (%s)", remserver->line, remserver->name); */ + SCWrite(pCon, buf, eStatus); + } +} +/*-------------------------------------------------------------------------*/ +static int RemServerTask(void *data) { + RemServer *remserver=data; + int iRet; + SConnection *pCon; + + if (!remserver->taskActive) return 0; /* remove task */ + if (RemRead(remserver, 0) <= 0) return 1; /* continue */ + + /* printf("< %s\n", buf); */ + + if (RemHandle(remserver)) { /* handle drivstat messages */ + return 1; + } + + /* forward oll other messages */ + pCon = SCLoad(&remserver->conn); + if (pCon) { + RemCopy(remserver, pCon); + } + return 1; +} +/*-------------------------------------------------------------------------*/ +static void RemDisconnect(RemServer *remserver) { + if (remserver->chan != NULL) { + NETClosePort(remserver->chan); + free(remserver->chan); + remserver->chan=NULL; + /* printf("disconnected\n"); */ + } +} +/*-------------------------------------------------------------------------*/ +static void RemConnect(RemServer *remserver) { + int iRet; + char buf[256]; + + if (!remserver->chan) { + remserver->timeout = 0; + remserver->chan = NETConnect(remserver->host, remserver->port); + if (!remserver->chan) { + return; + } + snprintf(buf, sizeof(buf), "%s %s\ntransact listexe interest\n" + , remserver->user, remserver->pass); + iRet = RemWrite(remserver, buf); + if (iRet < 0) goto close; + iRet = RemRead(remserver, 1000); + while (iRet > 0) { /* eat login response */ + if (StartsWith(remserver->line, "TRANSACTIONFINISHED")) { + /* printf("connected\n"); */ + return; + } + iRet = RemRead(remserver, 1000); + } + goto close; + } + return; +close: + RemDisconnect(remserver); + return; +} +/*-------------------------------------------------------------------------*/ +static int RemTransact(RemServer *remserver, SConnection *pCon, char *cmd, ...) { + /* the variable arguments are for filtering: + + "" write untreated lines to pCon + */ + char buf[256]; + int iRet; + int i, typ; + char *arg, *val, *endp; + float *f; + va_list ap; + int try; + int argMask; + + try=2; + if (remserver->timeout) { /* eat old responses */ + while (RemRead(remserver, 0) > 0) { + RemHandle(remserver); + } + } +tryagain: + strcpy(buf, "transact "); + strcat(buf, cmd); + strcat(buf,"\n"); + RemConnect(remserver); + iRet = RemWrite(remserver, buf); + if (iRet < 0) goto close; + + iRet = RemRead(remserver, 2000); + if (iRet <= 0) goto close; + while (!StartsWith(remserver->line, "TRANSACTIONFINISHED")) { + RemHandle(remserver); + va_start(ap, cmd); + arg = va_arg(ap, char *); + argMask=1; + remserver->matchMap = 0; + while (arg != NULL) { + if (*arg == '>') { + RemCopy(remserver, pCon); + } else if (*arg == '<') { + f = va_arg(ap, float *); + val = StartsWith(remserver->line, arg+1); + if (val != NULL) { + val = StartsWith(val, "="); + if (val != NULL) { + *f = strtod(val, &endp); + break; + } + } + } else if (*arg == '!') { + if (StartsWith(remserver->line, arg+1)) { + remserver->matchMap |= argMask; + argMask = argMask*2; + break; + } + } else { + printf("unknown argument in RemTransact: %s\n", arg); + assert(0); + } + arg = va_arg(ap, char *); + } + va_end(ap); + iRet = RemRead(remserver, 2000); + if (iRet <= 0) goto close; + } + return 1; +close: + if (iRet == 0) { + snprintf(buf, sizeof(buf), "ERROR: timeout on %s", remserver->name); + SCWrite(pCon,buf,eError); + remserver->timeout = 1; + return iRet; + } + snprintf(buf, sizeof(buf), "ERROR: no connection to %s", remserver->name); + SCWrite(pCon,buf,eError); + RemDisconnect(remserver); + try--; + if (try>0) goto tryagain; + return iRet; +} +/*-------------------------------------------------------------------------*/ +static void *RemobGetInterface(void *pData, int iID) { + Remob *self = pData; + + assert(self); + if(iID == DRIVEID) { + return self->pDrivInt; + } else if(iID == CALLBACKINTERFACE) { + return self->pCall; + } + return NULL; +} +/*------------------------------------------------------------------------*/ +static int RemobHalt(void *self) { + Remob *remob=self; + RemServer *remserver; + char buf[64]; + + assert(remob); + remserver = remob->server; + RemConnect(remserver); + snprintf(buf, sizeof(buf), "stopexe %s\n", remob->name); + return RemWrite(remserver, buf); +} + +/*--------------------------------------------------------------------------*/ +static int RemobLimits(void *self, float fVal, char *error, int iErrLen) { + float fHard; + Remob *remob=self; + + assert(remob); + /* check is done one remote server */ + return 1; +} +/*---------------------------------------------------------------------------*/ +static float RemobGetValue(void *pData, SConnection *pCon) { + Remob *remob=pData; + char buf[80]; + float none, value; + int iRet; + + assert(remob); + + SCSave(&remob->server->conn, pCon); + none = -1.25e6; + value= none; + snprintf(buf, sizeof(buf), "<%s", remob->name); + iRet = RemTransact(remob->server, pCon, remob->name, buf, &value, ">", NULL); + if (iRet <= 0) { + return 0.0; + } + if (value != none) { + return value; + } + snprintf(buf, sizeof(buf), "can not get %s", remob->name); + SCWrite(pCon, buf, eWarning); + return 0.0; +} +/*------------------------------------------------------------------------*/ +static int RemobSaveStatus(void *pData, char *name, FILE *fd) { + Remob *self = pData; + char buf[512]; + + assert(self); + assert(fd); + + /* + data is stored on remote server + */ + return 1; +} +/*------------------------------------------------------------------------*/ +static int RemobStatus(void *pData, SConnection *pCon) { + Remob *remob=pData; + + assert(remob); + + SCSave(&remob->server->conn, pCon); + return remob->status; +} +/*---------------------------------------------------------------------------*/ +static long RemobRun(void *self, SConnection *pCon, float fNew) { + Remob *remob=self; + float fHard; + int i, iRet, iCode; + char buf[512], sBuf[64]; + char pError[132]; + Remob *p; + RemServer *remserver; + long lTime; + float fDelta; + + remserver = remob->server; + SCSave(&remserver->conn, pCon); + assert(remob); + assert(pCon); + + /* check if I'am allowed to move this motor */ + if (!SCMatchRights(pCon,(int)ObVal(remob->ParArray,ACCESSCODE))) { + snprintf(buf,sizeof(buf), "ERROR: You are not authorised to run %s", + remob->name); + SCWrite(pCon,buf,eError); + SCSetInterrupt(pCon,eAbortBatch); + return 0; + } + + remob->status = HWIdle; + snprintf(buf, sizeof(buf), "run %s %f", remob->name, fNew); + iRet = RemTransact(remserver, pCon, buf, "!ERROR: somebody else", "!ERROR: cannot", ">", NULL); + if (iRet <= 0) return 0; + + if (remserver->matchMap & 1) { /* already running, stop first */ + remob->status = HWBusy; + snprintf(sBuf, sizeof(sBuf), "stopexe %s", remob->name, fNew); + iRet = RemTransact(remserver, pCon, sBuf, ">", NULL); + if (iRet <= 0) return 0; + while (remob->status == HWBusy) { + iRet = RemRead(remserver, 1000); + if (iRet <= 0) break; + RemCopy(remserver, pCon); + } + iRet = RemTransact(remserver, pCon, buf, ">", NULL); + if (iRet <= 0) return 0; + } + if (remob->status != HWBusy) { + return 0; + } + return OKOK; +} +/*-----------------------------------------------------------------------*/ +static void KillInfo(void *pData) { + RemobInfo *self = pData; + + assert(self); + if (self->pName) { + free(self->pName); + } + free(self); +} +/*------------------- The CallBack function for interest ------------------*/ +static int InterestCallback(int iEvent, void *pEvent, void *pUser) { + RemobCallback *psCall = pEvent; + RemobInfo *pInfo = pUser; + char buf[80]; + + assert(psCall); + assert(pInfo); + + snprintf(buf, sizeof(buf),"%s.position = %f ", pInfo->pName, psCall->fVal); + SCWrite(pInfo->pCon,buf,eValue); + return 1; +} +/*---------------------------------------------------------------------------*/ +int RemobAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]) { + Remob *remob = pData; + char buf[512]; + TokenList *pList = NULL; + TokenList *pCurrent; + TokenList *pName; + int iRet; + int i; + int pos; + float fValue; + long lID; + char *endp; + ObPar *par; + char acce[128], inte[128]; + + assert(pCon); + assert(pSics); + assert(remob); + + argtolower(argc,argv); + + SCSave(&remob->server->conn, pCon); + if (argc == 1) { + iRet = RemTransact(remob->server, pCon, argv[0], ">", NULL); + } else if (strcmp(argv[1],"list") == 0) { + snprintf(buf, sizeof(buf), "%s list", remob->name); + snprintf(acce, sizeof(acce), "!%s.accesscode", remob->name); + snprintf(inte, sizeof(inte), "!%s.interruptmode", remob->name); + + RemTransact(remob->server, pCon, buf, acce, inte, ">", NULL); + + snprintf(buf, sizeof(buf), "%s = %.0f", acce+1, ObVal(remob->ParArray,ACCESSCODE)); + SCWrite(pCon, buf, eStatus); + snprintf(buf, sizeof(buf), "%s = %.0f", inte+1, ObVal(remob->ParArray,INTERRUPTMODE)); + SCWrite(pCon, buf, eStatus); + iRet=1; + } else { + par=ObParFind(remob->ParArray, argv[1]); + if (par != NULL) { + if (argc == 3) { + fValue = strtod(argv[2], &endp); + if (endp == argv[2]) { + snprintf(buf, sizeof(buf), "number expected instead of %s", argv[2]); + SCWrite(pCon, buf, eError); + return 0; + } + iRet = ObParSet(remob->ParArray,argv[0],argv[1],fValue,pCon); + } + if (iRet) { + snprintf(buf, sizeof(buf), "%s.%s = %.0f", argv[0], argv[1], par->fVal); + SCWrite(pCon, buf, eStatus); + } + } else { + pos=snprintf(buf, sizeof(buf), "%s ", remob->name); + for (i=1; iserver, pCon, buf, ">", NULL); + } + } + return iRet; +} +/*---------------------------------------------------------------------------*/ +int RemServerAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]) { + RemServer *remserver = pData; + char buf[512]; + TokenList *pList = NULL; + TokenList *pCurrent; + TokenList *pName; + int iRet; + int i; + int pos; + float fValue; + long lID; + char *endp; + ObPar *par; + char acce[128], inte[128]; + + assert(pCon); + assert(pSics); + assert(remserver); + + argtolower(argc,argv); + + if (argc == 1) { + snprintf(buf, sizeof(buf), "%s = %s:%d", argv[0], remserver->host, remserver->port); + SCWrite(pCon, buf, eStatus); + } else { + pos=0; + for (i=1; i", NULL); + return iRet; + } + return 1; +} +/*--------------------------------------------------------------------------*/ +static void RemobKill(void *self) { + Remob *remob = self; + Remob *p, **last; + + assert(remob); + + /* remove from object list */ + if (remob->server) { + last = &remob->server->objList; + p = *last; + while (p != remob && p !=NULL) { + last = &p->next; + p = p->next; + } + if (p != NULL) { + *last = p->next; + } + remob->next = NULL; + } + if (remob->name) { + free(remob->name); + } + if (remob->pDrivInt) { + free(remob->pDrivInt); + } + if (remob->pCall) { + DeleteCallBackInterface(remob->pCall); + } + + /* get rid of parameter space */ + if (remob->ParArray) { + ObParDelete(remob->ParArray); + } + + /* kill Descriptor */ + DeleteDescriptor(remob->desc); + + free(remob); +} +/*--------------------------------------------------------------------------*/ +static void RemServerKill(void *self) { + RemServer *remserver = self; + + assert(remserver); + + if (remserver->taskActive) { + remserver->taskActive=0; + /* let the tasker kill me */ + return; + } + remserver = (RemServer *)self; + if (remserver->chan) { + RemDisconnect(remserver); + } + DeleteDescriptor(remserver->desc); + if (remserver->name) free(remserver->name); + if (remserver->host) free(remserver->host); + if (remserver->user) free(remserver->user); + if (remserver->pass) free(remserver->pass); + free(remserver); +} +/*-----------------------------------------------------------------------*/ +static Remob *RemobInit(char *name, RemServer *remserver) { + Remob *remob, *p; + + assert(name); + + /* get memory */ + remob = (Remob *)malloc(sizeof(Remob)); + if(!remob) { + return NULL; + } + + /* create and initialize parameters */ + remob->ParArray = ObParCreate(2); + if (!remob->ParArray) { + free(remob); + return NULL; + } + ObParInit(remob->ParArray,INTERRUPTMODE,"interruptmode",0.0,usUser); + ObParInit(remob->ParArray,ACCESSCODE,"accesscode",(float)usUser,usMugger); + + /* copy arguments */ + remob->server = remserver; + remob->name = strdup(name); + + /* initialise object descriptor */ + remob->desc = CreateDescriptor("Remob"); + if (!remob->desc) { + ObParDelete(remob->ParArray); + free(remob); + return NULL; + } + remob->desc->GetInterface = RemobGetInterface; + remob->desc->SaveStatus = RemobSaveStatus; + + /* initialise Drivable interface */ + remob->pDrivInt = CreateDrivableInterface(); + if (!remob->pDrivInt) { + DeleteDescriptor(remob->desc); + ObParDelete(remob->ParArray); + free(remob); + return NULL; + } + remob->pDrivInt->SetValue = RemobRun; + remob->pDrivInt->CheckLimits = RemobLimits; + remob->pDrivInt->CheckStatus = RemobStatus; + remob->pDrivInt->GetValue = RemobGetValue; + remob->pDrivInt->Halt = RemobHalt; + + /* initialise callback interface */ + remob->pCall = CreateCallBackInterface(); + if(!remob->pCall) { + RemobKill(remob); + return NULL; + } + + /* check if not yet in object list */ + for (p = remserver->objList; p != NULL; p=p->next) { + if (p == remob) break; + } + if (p == NULL) { + remob->next = remserver->objList; + remserver->objList = remob; + } + + if (!remserver->taskActive) { + remserver->taskActive = 1; + TaskRegister(pServ->pTasker, RemServerTask, NULL, RemServerKill, remserver, 1); + } + /* done */ + return remob; +} +/*-----------------------------------------------------------------------*/ +static RemServer *RemServerInit(char *name, char *host, int port, char *user, char *pass) { + RemServer *remserver = NULL; + + assert(name); + + remserver = malloc(sizeof(RemServer)); + if (!remserver) { + return 0; + } + + /* initialise object descriptor */ + remserver->desc = CreateDescriptor("RemServer"); + if (!remserver->desc) { + free(remserver); + return NULL; + } + remserver->taskActive = 0; + remserver->name = strdup(name); + remserver->host = strdup(host); + remserver->port = port; + remserver->user = strdup(user); + remserver->pass = strdup(pass); + remserver->incomplete = 0; + + if (!remserver->name || + !remserver->host || + !remserver->port || + !remserver->pass) { + /* no success, clean up */ + RemServerKill(remserver); + return NULL; + } + return remserver; +} +/*-------------------------------------------------------------------------- + The Factory function for creating a remote driveable object. + + Usage: + Remob server serverName host port user pass + Remob new remobName serverName + Remob del remobName (not yet implemented) + Remob del serverName (not yet implemented) +*/ + +int RemobCreate(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]) { + RemServer *remserver = NULL; + Remob *remob = NULL; + char buf[512]; + int iD, iRet; + Tcl_Interp *pTcl = (Tcl_Interp *)pSics->pTcl; + + assert(pCon); + assert(pSics); + + if (argc <= 5) { + argtolower(argc,argv); + } else { + argtolower(5,argv); + } + if (argc == 7 && strcmp(argv[1], "server") == 0) { + remserver = RemServerInit(argv[2], argv[3], atoi(argv[4]), argv[5], argv[6]); + if (!remserver) { + snprintf(buf, sizeof(buf), "Failure to create remote server connection %s", argv[2]); + SCWrite(pCon, buf, eError); + return 0; + } + /* create the interpreter command */ + iRet = AddCommand(pSics,argv[2],RemServerAction,RemServerKill,remserver); + if (!iRet) { + snprintf(buf, sizeof(buf),"ERROR: duplicate command %s not created",argv[1]); + SCWrite(pCon,buf,eError); + return 0; + } + + return 1; + } else if (argc == 4 && strcmp(argv[1], "new") == 0) { + remserver = FindCommandData(pServ->pSics, argv[3], "RemServer"); + if (!remserver) { + snprintf(buf, sizeof(buf), "remote server %s not found", argv[3]); + SCWrite(pCon, buf, eError); + return 0; + } + remob = RemobInit(argv[2], remserver); + if (!remob) { + snprintf(buf, sizeof(buf), "Failure to create remote driveable object %s", argv[1]); + SCWrite(pCon, buf, eError); + return 0; + } + /* create the interpreter command */ + iRet = AddCommand(pSics,argv[2],RemobAction,RemobKill,remob); + if (!iRet) { + snprintf(buf, sizeof(buf),"ERROR: duplicate command %s not created",argv[1]); + SCWrite(pCon,buf,eError); + return 0; + } + return 1; + } + snprintf(buf, sizeof(buf),"ERROR: illegal arguments for command remob",argv[1]); + SCWrite(pCon,buf,eError); +} + + + diff --git a/remob.h b/remob.h new file mode 100644 index 0000000..fed42c5 --- /dev/null +++ b/remob.h @@ -0,0 +1,19 @@ +/*-------------------------------------------------------------------------- +remote driveable objects + +Markus Zolliker July 04 + +copyright: see implementation file + +----------------------------------------------------------------------------*/ +#ifndef SICSREM +#define SICSREM +#include "Scommon.h" + +/*-------------------------------------------------------------------------*/ + +int RemobCreate(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + +#endif + diff --git a/tecs/didi b/tecs/didi index 15f4a46..fa212fc 100755 --- a/tecs/didi +++ b/tecs/didi @@ -42,7 +42,7 @@ foreach dest ($destlist) endif end -set items=(TecsServer TecsClient six keep_running cfg) +set items=(TecsServer TecsClient six keep_running) echo "" echo " all $items" @@ -70,21 +70,12 @@ if ($this == $0) then endif cd $this -set makeit=1 set obj=../../obj/$SICS_VERSION/psi/tecs foreach dest ($where) alias get 'set d=$'"d_$dest;"'set t=$'"t_$dest" get foreach item ($what) - echo $item D $d T $t - if ($item == cfg) then - if ($makeit) then - make config - set makeit=0 - endif - echo tecs $d - rsync -e ssh -rCtv --delete-excluded $obj/cfg $d - else if ("$t" == "$OSTYPE") then + if ("$t" == "$OSTYPE") then echo $item to $d rsync -e ssh -vt $obj/$item $d endif diff --git a/tecs/make_crv.tcsh b/tecs/make_crv.tcsh index 9a6b0fe..a216fd9 100755 --- a/tecs/make_crv.tcsh +++ b/tecs/make_crv.tcsh @@ -9,7 +9,7 @@ foreach file ($files) echo ' $Q -p$(CFGDIR)' >> src/make_crv echo '' >> src/make_crv end -echo "all_crv: \" >> src/make_crv +echo "all_crv: dev.list \" >> src/make_crv foreach file ($files) set sens=${file:t:s/.inp//} echo ' $(CFGDIR)'"$sens.crv \" >> src/make_crv diff --git a/tecs/make_gen b/tecs/make_gen index 024fdc8..b172806 100644 --- a/tecs/make_gen +++ b/tecs/make_gen @@ -39,6 +39,10 @@ CFGDIR=/afs/psi.ch/project/sinq/common/lib/tecs/cfg/ $(SRC)make_crv: make_crv.tcsh inp/lsc.codes $(ALLINP) $(SRC)make_crv.tcsh $(SRC)inp/lsc.codes +dev.list: + $(SRC)make_list.tcsh $(CFGDIR)*.cfg > $@ + cp $@ $(CFGDIR) + # use target all_crv to make all curves in inp directory TecsServer: $(SERV_OBJ) $(HARDSUPLIB) $(FORTIFYOBJ) diff --git a/tecs/myc_buf.c b/tecs/myc_buf.c index c4b6dec..352488b 100644 --- a/tecs/myc_buf.c +++ b/tecs/myc_buf.c @@ -227,31 +227,38 @@ void StrNLink(StrBuf *buf, char *str, int length) { void flt_to_char4(double f, char buf[4]) { double m; - int e, res, ir; + int e; + long res; - m=frexp(f, &e); - e=e+EXP_OFFS; - if (e<0 || m==0) { - res=0; m=0; + m = frexp(f, &e); + e += EXP_OFFS; + if (e < 0 || m == 0) { + res = 0; m = 0; } else { - if (e>255) { - res=255*TWO_23+(TWO_23-1); /* max. representable number */ + if (e > 255) { + res = 255 * TWO_23 + (TWO_23 - 1); /* max. representable number */ } else { - res=e*TWO_23+(int)(0.5+(fabs(m*2)-1.0)*TWO_23); + res = (long)(0.5 + (fabs(m * 2) - 1.0) * TWO_23); + /* here we may think about the case, where m is just a little less than 1.0: + the mantissa part overflows to bit23, but, the result would be o.k., since this + just increases the exponent by one, and the mantissa bits get all zero. + but what happens when e is already 255 ? the next line handles this */ + if (res == TWO_23 && e == 255) res--; + res += e * TWO_23; } } - buf[0]=res % 256; res=res/256; - buf[1]=res % 256; res=res/256; - buf[2]=res % 256; res=res/256; - if (m<0) { - buf[3]=res-128; + buf[0] = res % 256; res = res / 256; + buf[1] = res % 256; res = res / 256; + buf[2] = res % 256; res = res / 256; + if (m < 0) { + buf[3] = res - 128; } else { - buf[3]=res; + buf[3] = res; } } double flt_from_char4(char buf[4]) { - int s, i, b0, b1, b2, b3; + long i, b0, b1, b2, b3; b0=buf[0]; if (b0<0) b0+=256; b1=buf[1]; if (b1<0) b1+=256; diff --git a/tecs/pg_plus/xwdriv.c b/tecs/pg_plus/xwdriv.c index b2f37c2..733e2ee 100644 --- a/tecs/pg_plus/xwdriv.c +++ b/tecs/pg_plus/xwdriv.c @@ -2195,13 +2195,15 @@ static int xw_read_cursor(xw, mode, posn, ref, pos, key) /* * Discard un-handled ButtonPress, KeyPress and MotionNotify events. */ - if (xw->nofocus) { /* M.Z. */ + /* removed M.Z. + if (xw->nofocus) { while(xw_check_window_event(xw, xw->window, (long) (ButtonPressMask | PointerMotionMask), &event)); } else { while(xw_check_window_event(xw, xw->window, (long) (ButtonPressMask | KeyPressMask | PointerMotionMask), &event)); } + */ if(xw->bad_device) return xw_end_cursor(xw, bc, 1); xw->nofocus=0; /* M.Z. */ @@ -2326,9 +2328,10 @@ static int xw_read_cursor(xw, mode, posn, ref, pos, key) case MotionNotify: /* * Discard all but the last MotionNotify event. - */ + */ while(xw_check_window_event(xw, xw->window, (long)(PointerMotionMask), &event)); + if(xw->bad_device || xw_erase_cursor(xw, bc)) return xw_end_cursor(xw, bc, 1); last.x = event.xmotion.x; @@ -3548,7 +3551,7 @@ static int xw_next_event(xw, event) } /*....................................................................... - * like xw_next_event (see above), but with timeout in decisSecs (M.Z.) + * like xw_next_event (see above), but with timeout in deciSecs (M.Z.) */ #ifdef __STDC__ static int xw_next_event_tmo(XWdev *xw, XEvent *event, int tmo_10) diff --git a/tecs/six.c b/tecs/six.c index 2cce3f4..8a63682 100644 --- a/tecs/six.c +++ b/tecs/six.c @@ -259,18 +259,6 @@ int setrights(int gotolevel) { } else { deflevel=2; } -/* - if (NULL != strstr(instr, "TASP")) { - if (user1[0]=='\0') { - str_copy(user1,"Spy"); - str_copy(pswd1,"007"); - } - if (user2[0]=='\0') { - str_copy(user2,"Spy"); - str_copy(pswd2,"007"); - } - } -*/ if (gotolevel==0) gotolevel=deflevel; if (gotolevel==1) { if (user1[0]=='\0') { @@ -401,6 +389,7 @@ int main (int argc, char *argv[]) { int iret, pos; fd_set mask; int l, i, j, port, skip, gotolevel, sicslogin; + int savehist = 0; char buf[128], lbuf[16], ilow[64]; char stdPrompt[128], prompt[256]; char *sim=""; @@ -527,6 +516,7 @@ int main (int argc, char *argv[]) { pos=0; term_read_hist("six"); + savehist = 1; while (1) { if (*p=='E') { /* Eager to ... */ @@ -589,15 +579,17 @@ int main (int argc, char *argv[]) { assert(fd==iret); ERR_P(p=readWrite(fd,1000,0,"status = ")); if (strcmp(p, "0") == 0) { - printf("\nconnection lost\n"); + term_clear(); + printf("\nconnection lost"); break; } } } - fputs("\n", stdout); + printf("\nexit %s\n", prompt); term_save_hist(1); /* save history without last line */ return 0; OnError: + if (savehist) term_save_hist(0); /* save history with last line */ ErrShow("end"); return 0; } diff --git a/tecs/tecs.c b/tecs/tecs.c index 78c0df8..90d701d 100644 --- a/tecs/tecs.c +++ b/tecs/tecs.c @@ -21,6 +21,7 @@ #endif #define TABLE_FILE "tecs.cfg" +#define DEV_LIST "dev.list" #define LSC_CODES "lsc.codes" #define LOGLIFETIME 24*3600 @@ -168,8 +169,7 @@ static int swRangeOn=0, /* switch heater range on when controller switched it off */ initMaxPower=0, /* set MaxPower for the first time */ lockAlarm, - cntError, - tableTime; /* last time when table was read */ + cntError; int tim, rdTim; /* actual time, read Time */ @@ -536,14 +536,12 @@ int InstalCurve(SensorT *sensor, char *devArg) { return -1; } -int ReadTable(void) { +int ReadTable(void) { /* obsolete */ char nbuf[256]; - if (table!=NULL && tim>tableTime+60) { FREE(table); table=NULL; }; /* clear old table */ - if (table!=NULL) return 0; + if (table!=NULL) { FREE(table); table=NULL; }; str_copy(nbuf, binDir); str_append(nbuf, TABLE_FILE); ERR_P(table=str_read_file(nbuf)); - tableTime=tim; return 1; OnError: return -1; } @@ -574,11 +572,13 @@ int PrepInput(char *label) { } else { str_copy(nam, label); } +again: str_copy(buf, binDir); str_append(buf, nam); str_append(buf, ".cfg"); cfg=str_read_file(buf); if (cfg==NULL) { /* will be obsolete */ + logfileOut(LOG_MAIN, "%s not found, try tecs.cfg\n", buf); ERR_I(ReadTable()); t=strstr(table, label); if (t==NULL) ERR_MSG("device not found"); @@ -586,6 +586,14 @@ int PrepInput(char *label) { if (e==NULL || e>strchr(t,'\n')) ERR_MSG("missing ' or device name in table file"); t=e+1; } + if (cfg && *cfg=='@') { /* alias */ + t=strchr(cfg,'\n'); + if (t) *t='\0'; + str_copy(nam, cfg+1); + str_copy(plug->device, nam); + FREE(cfg); + goto again; + } if (plug==&plug0) { InitSensor(&sensA); InitSensor(&sensB); @@ -694,8 +702,15 @@ int PrepInput(char *label) { str_copy(plug->device, nam); ConcatDevice(); } + if (cfg) { + FREE(cfg); + } return 0; - OnError: return -1; +OnError: + if (cfg) { + FREE(cfg); + } + return -1; } int LoadCache(void) { @@ -1708,12 +1723,17 @@ int ConfigByCode(int plugNr) { } p=fgets(buf, sizeof(buf), fil); } - fclose(fil); - logfileOut(LOG_MAIN+LOG_STAT ,"configure plug%d for %s (code %d)\n", plugNr, nam, plug->code); - str_copy(buf, "'"); - str_append(buf, nam); - str_append(buf, "'"); - ERR_I(PrepInput(buf)); + fclose(fil); + if (plug->code != c1 && plug->code != c2) { + logfileOut(LOG_MAIN+LOG_STAT ,"unknown code %d on plug%d\n", plug->code, plugNr); + return 0; + } else { + logfileOut(LOG_MAIN+LOG_STAT ,"configure plug%d for %s (code %d)\n", plugNr, nam, plug->code); + str_copy(buf, "'"); + str_append(buf, nam); + str_append(buf, "'"); + ERR_I(PrepInput(buf)); + } } settingsFlag=1; return 0; @@ -2606,39 +2626,14 @@ EndStatus: } int DevHelpHdl(int mode, void *base, int fd) { - char *t, *n, *d, *en, *ed; - char line[80], nbuf[256]; - int l, iret; - static int doit=1; + char nbuf[256]; + char *list; - ERR_I(iret=ReadTable()); - if (iret) doit=1; - if (doit) { - doit=0; - t=table; - str_copy(devHelp,"\n"); - while (t!=NULL) { - t++; - n=strchr(t, '\''); - d=strstr(t, "dev=\""); - t=strchr(t, '\n'); - if (n!=NULL && d!=NULL && n < d && d < t) { - en=strchr(n+1, '\''); - ed=strchr(d+5, '"'); - if (en != NULL && en12) l=12; - str_ncpy(line, n+1, l); - str_npad(line, line, 12); - l=ed-d; - if (l>77) l=77; - str_ncpy(line+12, d+5, l); - str_append(line, "\n"); - str_append(devHelp, line); - } - } - } - } + str_copy(nbuf, binDir); + str_append(nbuf, DEV_LIST); + ERR_P(list=str_read_file(nbuf)); + str_copy(devHelp, list); + FREE(list); return 0; OnError: return -1; } @@ -2901,7 +2896,7 @@ int main(int argc, char *argv[]) { CocDefInt(relay, RW); CocHdl(RelayHdl); CocDefInt(manual, RW); CocHdl(ManualHdl); CocDefInt(htrst, RD); - CocDefInt(loop, RD); + CocDefInt(loop, RW); CocDefInt(rdTim, RD); CocDefInt(tim0, RD); CocDefInt(ibuf, RD); diff --git a/tecs/tecs_client.f b/tecs/tecs_client.f index 6ce01e1..278abed 100644 --- a/tecs/tecs_client.f +++ b/tecs/tecs_client.f @@ -73,7 +73,8 @@ l=0 1 if (oneCommand) goto 99 if (nfiles .gt. 0) then - read(luns(idx), '(q,a)', err=22,end=22) l, line + read(luns(idx), '(a)', err=22,end=22) line + call str_trim(line, line, l) print '(x,2a)', prompt(1:promptlen),line(1:max(1,l)) else call sys_rd_line(line, l, prompt(1:promptlen)) diff --git a/tecs/tecs_plot.f b/tecs/tecs_plot.f index 5032d1e..54171cb 100644 --- a/tecs/tecs_plot.f +++ b/tecs/tecs_plot.f @@ -34,6 +34,7 @@ logical yzoom integer winconf(nwin) ! number of windows below actual integer showsets + integer nextfocus real winh integer nticks character key*1 @@ -128,6 +129,7 @@ allpars=allpars(1:l)//' '//parnam(im) enddo showsets=1 + nextfocus=0 1 continue @@ -135,6 +137,10 @@ if (iret .lt. 0) goto 99 tdif=myc_now()-t tdif=tdif-mod(tdif+1800*25, 3600)+1800 ! round to next full hour + if (tdif .gt. 7200 .or. tdif .lt. -7200) then ! a hack + t=myc_now() + tdif=0 + endif if (tdif .ne. 0) then print *,'time difference ',tdif/3600,' h' endif @@ -258,16 +264,18 @@ endif enddo if (j .eq. 0) then - if (.not. yzoom) then + if (nextfocus .ne. 0) then + do is=1,nset + im=imx(is) + if (retLen(is) .gt. 0 .and. unit(im) .eq. 1) focus(im)=.true. + enddo + else if (.not. yzoom) then y1=ymin(1) y2=ymax(1) yzoom=.true. endif -! do is=1,nset -! im=imx(is) -! if (retLen(is) .gt. 0 .and. unit(im) .eq. 1) focus(im)=.true. -! enddo endif + nextfocus=0 if (saveit) goto 9 if (mode .eq. live) then x2=max(tim0,x2)+min(1800., window*0.5) @@ -360,8 +368,8 @@ ey=(ymax(rl)-ymin(rl)) fy=abs(ymax(rl)) - ymax(rl)=ymax(rl)+max(fy*0.0075,ey*0.01) - ymin(rl)=ymin(rl)-max(fy*0.005,ey*0.01) + ymax(rl)=ymax(rl)+max(fy*0.02,ey*0.01) + ymin(rl)=ymin(rl)-max(fy*0.02,ey*0.01) if (mode .eq. live) then ymin(rl)=min(ymin(rl),max(0.0,ylast1-ey*0.4)) ymax(rl)=max(ymax(rl),ylast2+ey*0.4) @@ -628,7 +636,7 @@ elseif (key .eq. 'X') then window=0 mode=0 - yzoom=.true. + yzoom=.false. elseif (key .eq. '+' .or. key .eq. ',') then window=max(winmin,window/2) if (ex .eq. undef) then @@ -759,6 +767,7 @@ goto 9 elseif (key .eq. 'A') then showsets=2 + yzoom=.false. elseif (key .eq. 'C') then ! clear set if (ex .lt. x1) then if (ey .ge. ymin(1) .and. @@ -806,17 +815,28 @@ endif enddo if (n .gt. 1) then - if (j .gt. 4) then ! was "all", set to "default" + if (j .gt. 3) then ! was "all", set to "default" focus(1)=.true. focus(2)=.true. focus(3)=.true. else ! was "default" select 1 focus(1)=.true. endif - else if (j .lt. nset) then ! select next - im=imx(j) + goto 89 + endif + nextfocus=1 + do is=1,nset + im=imx(is) + if (im .gt. j) then ! select next + focus(im)=.true. + goto 89 + endif + enddo + ! select all + do is=1,nset + im=imx(is) focus(im)=.true. - endif ! else select none -> will be all + enddo 89 yzoom=.false. elseif (mode .eq. live) then goto 7 diff --git a/tecs/term.c b/tecs/term.c index f6f387d..854c40f 100644 --- a/tecs/term.c +++ b/tecs/term.c @@ -201,8 +201,7 @@ char *term_fgets(char *buf, int size, FILE *fil) { return ret; } -void term_save_hist(int -trimlast) { +void term_save_hist(int trimlast) { FILE *fil; int i,n; if (filehead[0]=='\0') return; @@ -319,6 +318,11 @@ int term_get_line(char *buf, int size, int *pos, char *prompt, fd_set *mask) { } hist_pos=hist_end; term_save_hist(0); + printf("\r\033[K\n"); + for (i = strlen(prompt) - 1; i > 0; i--) { + printf("-"); + } + printf(" %s", buf); return(STDIN_FILENO); /* normal EXIT */