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 */