/*--------------------------------------------------------------------------- ease.c basics for (ea)sy implementable (s)ample (e)nvironment devices. handles background activity and connections over rs232. Markus Zolliker, March 2005 ---------------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #include "sics.h" #include "splitter.h" #include "ease.h" #include "sicshipadaba.h" #define EASE_FLAGBITS (8*sizeof(long)) static ParClass easeBaseClass = { "EaseBase", sizeof(EaseBase) }; static ParClass easeDrivClass = { "EaseDriv", sizeof(EaseDriv) }; static int parameterChange = 0; /*----------------------------------------------------------------------------*/ ParClass *EaseBaseClass(void) { return ParMakeClass(&easeBaseClass, NULL); } /*----------------------------------------------------------------------------*/ ParClass *EaseDrivClass(void) { return ParMakeClass(&easeDrivClass, EaseBaseClass()); } /*----------------------------------------------------------------------------*/ EaseBase *EaseBaseCast(void *object) { return ParCast(&easeBaseClass, object); } /*----------------------------------------------------------------------------*/ EaseDriv *EaseDrivCast(void *object) { return ParCast(&easeDrivClass, object); } /*----------------------------------------------------------------------------*/ void EaseStop(EaseBase * eab, char *reason) { if (eab->state >= EASE_idle) { FsmStop(eab->task, eab->idle); closeRS232(eab->ser); } if (reason != NULL) { snprintf(eab->msg, sizeof eab->msg, "offline (%s)", reason); ParPrintf(eab, eLogError, "ERROR: %s", eab->msg); } eab->state = EASE_offline; } /*----------------------------------------------------------------------------*/ void EaseWriteError(EaseBase * eab) { int l; switch (eab->errCode) { case NOTCONNECTED: ParPrintf(eab, eError, "ERROR: unconnected socket for %s", eab->p.name); break; case FAILEDCONNECT: ParPrintf(eab, eError, "ERROR: can not connect to %s:%d (terminalserver off or no ethernet connection)", eab->ser->pHost, eab->ser->iPort); break; case TIMEOUT: ParPrintf(eab, eError, "ERROR: timeout on %s\ncmd: %s\nans: %s", eab->p.name, eab->cmd, eab->ans); break; case INCOMPLETE: ParPrintf(eab, eError, "ERROR: incomplete answer %s from %s", eab->ans, eab->p.name); break; case EASE_ILL_ANS: if (eab->p.verbose < 1) break; l = strlen(eab->cmd); if (l > 0 && eab->cmd[l - 1] < ' ') { l--; } ParPrintf(eab, eError, "ERROR: illegal answer %s from %s (cmd: %*s)", eab->ans, eab->p.name, l, eab->cmd); break; case EASE_DEV_CHANGED: ParPrintf(eab, eError, "ERROR: controller was exchanged on %s", eab->p.name); EaseStop(eab, "controller exchanged"); break; case EASE_FAULT: ParPrintf(eab, eError, "ERROR: error on %s", eab->p.name); break; default: ParPrintf(eab, eError, "ERROR: error code %d on %s", eab->errCode, eab->p.name); break; } } /*----------------------------------------------------------------------------*/ void EaseWrite(EaseBase * eab, char *cmd) { /* cmd==NULL: repeat the same command */ int iRet; char trash[64]; int l; if (eab->errCode) { FsmStop(eab->task, eab->idle); eab->state = EASE_abort; return; } if (eab->state == EASE_expect || eab->state == EASE_abort) return; while (availableRS232(eab->ser) == 1) { l = sizeof(trash); iRet = readRS232TillTerm(eab->ser, trash, &l); if (iRet < 0) break; ParPrintf(eab, -2, "trash: %s\n", trash); } if (cmd) { snprintf(eab->cmd, sizeof(eab->cmd), "%s%s", cmd, eab->ser->sendTerminator); } iRet = writeRS232(eab->ser, eab->cmd, strlen(eab->cmd)); if (iRet < 0) { FsmStop(eab->task, eab->idle); snprintf(eab->msg, sizeof eab->msg, "offline (connection to %s:%d lost)", eab->ser->pHost, eab->ser->iPort); ParPrintf(eab, eError, "ERROR: %s", eab->msg); closeRS232(eab->ser); eab->state = EASE_notconnected; eab->errCode = iRet; return; } if (cmd) { ParPrintf(eab, -2, "cmd: %s", cmd); } else { ParPrintf(eab, -2, "cmd: %s", eab->cmd); } eab->state = EASE_expect; eab->cmdtime = time(NULL); eab->chktime = time(NULL) + 5; } /*----------------------------------------------------------------------------*/ int EaseWaitRead(EaseBase * eab) { int cnt = 0; time_t start; if (eab->state < EASE_idle) { return NOTCONNECTED; } FsmPause(eab->task, 1); time(&start); while (eab->state == EASE_expect) { /* TaskYield(pServ->pTasker); does not work (pardef is not recursive) */ FsmTaskHandler(eab->task); cnt++; if (time(NULL) > start + 5) { eab->ans[0] = '\0'; eab->state = EASE_read; return TIMEOUT; } } FsmPause(eab->task, 0); /* if (cnt>1) ParPrintf(eab, eError, "TaskYield %d\n", cnt); */ return 1; } /*----------------------------------------------------------------------------*/ void EaseParHasChanged(void) { parameterChange = 1; } /*----------------------------------------------------------------------------*/ void EasePchk(void *drv) { int pc = FsmPc(); if (pc > 0) { ParPrintf(drv, eError, "ERROR: illegal line in fsm %d", pc); } } /*----------------------------------------------------------------------------*/ void EaseSavePars(void) { char *pFile = NULL; if (parameterChange) { parameterChange = 0; assert(pServ->pSics); pFile = IFindOption(pSICSOptions, "statusfile"); if (pFile) { WriteSicsStatus(pServ->pSics, pFile, 0); } } } /*----------------------------------------------------------------------------*/ static int EaseRestart(EaseBase * eab) { int iRet; eab->errCode = 0; if (eab->task) { FsmStop(eab->task, eab->idle); FsmRestartTask(eab->task, eab->idle); } eab->startOk = 0; eab->todo = eab->start; eab->state = EASE_connecting; iRet = initRS232WithFlags(eab->ser, 3); if (iRet != 1) { eab->errCode = iRet; EaseWriteError(eab); return -1; } if (eab->cmdtime == 0) { snprintf(eab->msg, sizeof eab->msg, "connecting to %s:%d", eab->ser->pHost, eab->ser->iPort); } return 0; } /*----------------------------------------------------------------------------*/ void EaseUpdateHwstate(void *object, int drivStatus) { EaseDriv *ead = EaseDrivCast(object); int is_running = drivStatus == HWBusy; ead->hwstate = drivStatus; if (ead->is_running != is_running) { ead->is_running = is_running; ParUpdateAll(ead); } } /*----------------------------------------------------------------------------*/ int EaseHandler(EaseBase * eab) { EaseDriv *ead = EaseDrivCast(eab); int iret; EaseSavePars(); if (ead && ead->stopped && ead->hwstate == HWBusy) { ead->stopped = 0; EaseUpdateHwstate(ead, HWIdle); if (FsmStop(eab->task, eab->doit)) { ParPrintf(eab, eWarning, "%s stopped", eab->p.name); return 0; } } if (eab->state == EASE_offline) { return 0; } if (eab->state == EASE_expect) { if (eab->cmdtime != 0 && time(NULL) > eab->cmdtime + eab->p.period) { snprintf(eab->msg, sizeof eab->msg, "no response"); } return 0; } if (eab->state == EASE_lost) { snprintf(eab->msg, sizeof eab->msg, "no response"); } if (eab->state == EASE_notconnected) { if (time(0) >= eab->cmdtime + 10) { EaseRestart(eab); } return 0; } if (eab->state == EASE_connecting) { iret = initRS232Finished(eab->ser); if (iret == 0) return 0; /* waiting for connection */ if (iret < 0) { if (errno == ECONNREFUSED) { snprintf(eab->msg, sizeof eab->msg, "Connection refused"); } else { snprintf(eab->msg, sizeof eab->msg, "Connection failed (%s)", strerror(errno)); } if (eab->cmdtime == 0) { ParPrintf(eab, eError, "%s: %s", eab->p.name, eab->msg); } closeRS232(eab->ser); eab->state = EASE_notconnected; eab->cmdtime = time(0); return 0; } else { if (eab->tmo > 20) { eab->tmo = 20; } eab->msg[0] = '\0'; eab->state = EASE_idle; } } if (eab->errCode) { if (eab->errCode == BADSEND) { eab->cmdtime = 0; /* means: this is not a repeated restart */ EaseRestart(eab); return 0; } if (eab->state != EASE_abort) { EaseWriteError(eab); } eab->errCode = 0; if (ead) { EaseUpdateHwstate(ead, HWFault); FsmStop(eab->task, eab->doit); } return 0; } if (ead) { if (eab->state == EASE_lost) { if (FsmStop(eab->task, eab->doit)) { ParPrintf(eab, eWarning, "stop %s caused by timeout", eab->p.name); } return 0; } } else { if (eab->state == EASE_lost) { return 0; } } return 1; } /*----------------------------------------------------------------------------*/ int EaseNextFullRead(EaseBase * eab) { time_t thisPeriod; thisPeriod = time(NULL) / eab->p.period; if (thisPeriod != eab->readPeriod) { eab->readPeriod = thisPeriod; return 1; } return 0; } /*----------------------------------------------------------------------------*/ static long EaseSendIt(long pc, void *object) { EaseBase *eab = EaseBaseCast(object); switch (pc) { default: /* FSM BEGIN ****************************** */ EasePchk(eab); EaseWrite(eab, eab->sendCmd); ParPrintf(eab, eWarning, "send cmd> %s", eab->sendCmd); eab->sendCmd = NULL; return __LINE__; case __LINE__: /**********************************/ ParPrintf(eab, eWarning, "response> %s", eab->ans); return 0; } /* FSM END ******************************************* */ } /*----------------------------------------------------------------------------*/ int EaseCheckDoit(EaseBase * eab) { int i, n; if (eab->todo == NULL) { if (eab->sendCmd != NULL) { eab->todo = EaseSendIt; return 1; } n = eab->maxflag / EASE_FLAGBITS; for (i = 0; i <= n; i++) { if (eab->updateFlags[i]) { eab->todo = eab->doit; return 1; } } } return eab->todo != NULL; } /*----------------------------------------------------------------------------*/ static long EaseIdle(long pc, void *object) { EaseBase *eab = EaseBaseCast(object); EaseDriv *ead = EaseDrivCast(object); struct timeval tm; FsmFunc todo; switch (pc) { default: /* FSM BEGIN ****************************** */ EasePchk(eab); if (eab->state == EASE_abort) { eab->state = EASE_idle; } idle: if (!EaseCheckDoit(eab)) goto rd; doit: todo = eab->todo; eab->todo = NULL; FsmCall(todo); return __LINE__; case __LINE__: /**********************************/ eab->startOk = 1; rd: /* rd: */ /* if (eab->state == EASE_lost) { snprintf(eab->msg, sizeof eab->msg, "no response from %s", eab->p.type->name); } */ FsmCall(eab->read); return __LINE__; case __LINE__: /**********************************/ if (EaseCheckDoit(eab)) goto doit; /* gettimeofday(&tm, NULL); printf("stop %s %f\n", eab->evc->pName, tm.tv_usec / 1e6); */ /* FsmWait(1); do we really need that? -- remove for faster response to send */ return __LINE__; case __LINE__: /**********************************/ /* gettimeofday(&tm, NULL); printf("start %s %f\n", eab->evc->pName, tm.tv_usec / 1e6); */ goto idle; /* never return */ return 0; } /* FSM END ******************************************* */ } /*----------------------------------------------------------------------------*/ static float EaseGetValue(void *obj, SConnection * pCon) { float val; EaseBase *eab; assert(eab = EaseBaseCast(obj)); ParGetFloat(pCon, eab, "", &val); return val; } /*----------------------------------------------------------------------------*/ int EaseUpdate(int flag) { EaseBase *eab = EaseBaseCast(ParObject()); ParAccess(usUser); ParSave(0); if (ParActionIs(PAR_SET) > 0) { assert(flag >= 0); assert(flag <= eab->maxflag); eab->updateFlags[flag / EASE_FLAGBITS] |= (unsigned long)1 << (flag % EASE_FLAGBITS); if (eab->task) FsmSpeed(eab->task); return 1; } return 0; } /*----------------------------------------------------------------------------*/ int EaseNextUpdate(void *object) { EaseBase *eab = EaseBaseCast(object); unsigned long mask, p; int i, n, flag; n = eab->maxflag / EASE_FLAGBITS; for (i = 0; i <= n; i++) { mask = eab->updateFlags[i]; p = 1; flag = 0; /* find first */ while (flag < EASE_FLAGBITS) { if (mask & p) { eab->updateFlags[i] &= ~p; return flag + i * EASE_FLAGBITS; } p <<= 1; flag++; } } return -1; } /*----------------------------------------------------------------------------*/ int EaseGetUpdate(void *object, int flag) { EaseBase *eab = EaseBaseCast(object); int i; assert(flag >= 0); assert(flag <= eab->maxflag); i = flag / EASE_FLAGBITS; if (((unsigned long)1 << (flag % EASE_FLAGBITS)) & eab->updateFlags[i]) { return 1; } return 0; } /*----------------------------------------------------------------------------*/ void EaseSetUpdate(void *object, int flag, int state) { EaseBase *eab = EaseBaseCast(object); assert(flag >= 0); assert(flag <= eab->maxflag); if (state) { eab->updateFlags[flag / EASE_FLAGBITS] |= (unsigned long)1 << (flag % EASE_FLAGBITS); } else { eab->updateFlags[flag / EASE_FLAGBITS] &= ~((unsigned long)1 << (flag % EASE_FLAGBITS)); } } /*----------------------------------------------------------------------------*/ static long EaseRun(void *obj, SConnection * pCon, float fVal) { EaseBase *eab = EaseBaseCast(obj); EaseDriv *ead = EaseDrivCast(obj); int canc; assert(ead); ParSaveConn(eab, pCon); if (!eab->doit) { ParPrintf(ead, eError, "ERROR: missing run function %s", eab->p.name); return 0; } if (!eab->startOk) { ParPrintf(ead, eError, "ERROR: %s is not ready to run", eab->p.name); return 0; } if (FsmStop(eab->task, eab->doit)) { canc = 1; ParPrintf(ead, eWarning, "running %s cancelled", eab->p.name); } else { canc = 0; } if (eab->todo) { ParPrintf(ead, eError, "ERROR: %s busy", eab->p.name); return 0; } ead->targetValue = fVal; EaseParHasChanged(); /* assume that targetValue has to be saved */ ead->stopped = 0; /* eab->todo = eab->doit; */ EaseSetUpdate(eab, EASE_RUN, 1); ead->is_running = -1; /* force update of is_running even when not changed */ EaseUpdateHwstate(ead, HWBusy); if (ead->maxwait >= 0) { ead->timeout = time(NULL) + ead->maxwait; } else { ead->maxwait = -1; ead->timeout = time(NULL) + 9999999; /* approx. infinite */ } ead->finish = 0; ead->usedSettle = 0; ead->tolState = EASE_outOfTolerance; if (canc) { ParPrintf(ead, eWarning, "rerun %s", eab->p.name); } return 1; } /*----------------------------------------------------------------------------*/ static int EaseHalt(void *obj) { EaseDriv *ead; assert(ead = EaseDrivCast(obj)); ead->stopped = 1; return 1; } /*----------------------------------------------------------------------------*/ static int EaseIsInTol(void *obj) { EaseDriv *ead = EaseDrivCast(obj); float f; f = EaseGetValue(ead, NULL) - ead->targetValue; if (ead->tolState == EASE_outOfTolerance) { if (fabsf(f) < ead->tolerance) { ParPrintf(obj, eWarning, "%s is within tolerance", ead->b.p.name); ead->tolState = EASE_inTolerance; return 1; } return 0; } else { if (fabsf(f) > ead->tolerance * 1.11) { if (ead->tolState == EASE_inTolerance) { ParPrintf(obj, eWarning, "%s is out of tolerance by %f", ead->b.p.name, f); } ead->tolState = EASE_outOfTolerance; return 0; } return 1; } } /*----------------------------------------------------------------------------*/ static int EaseErrHandler(void *obj) { /* to be implemented */ return 1; } /*----------------------------------------------------------------------------*/ static int EaseCheckStatus(void *obj, SConnection * pCon) { EaseDriv *ead = EaseDrivCast(obj); time_t now, t; assert(ead); ParSaveConn(ead, pCon); if (ead->stopped) { return HWIdle; } else if (!ead->is_running) { ead->stopped = 1; return HWIdle; } now = time(NULL); if (now > ead->timeout) { ParPrintf(obj, eWarning, "maxwait expired when driving %s", ead->b.p.name); EaseUpdateHwstate(ead, HWIdle); } else if (EaseIsInTol(obj)) { if (ead->finish == 0) { ead->finish = now - ead->usedSettle; if (now < ead->finish + ead->settle) { ParPrintf(obj, eWarning, "settle %s for %ld sec", ead->b.p.name, (long) (ead->finish + ead->settle - now)); } } if (now > ead->finish + ead->settle && ead->hwstate != HWIdle) { ParPrintf(obj, eWarning, "%s has reached target", ead->b.p.name); EaseUpdateHwstate(ead, HWIdle); } } else if (ead->finish != 0) { ead->usedSettle = now - ead->finish; ead->finish = 0; } return ead->hwstate; } /*----------------------------------------------------------------------------*/ static EVMode EaseGetMode(void *obj) { EaseDriv *ead = EaseDrivCast(obj); assert(ead); if (ead->hwstate == HWBusy) { return EVDrive; } if (ead->tolState == EASE_notMonitored) { return EVIdle; } return EVMonitor; } /*----------------------------------------------------------------------------*/ static int EaseCheckLimits(void *obj, float fVal, char *error, int errLen) { EaseDriv *ead; assert(ead = EaseDrivCast(obj)); /* lower limit */ if (fVal < ead->lowerLimit) { snprintf(error, errLen, "ERROR: %g violates lower limit of device", fVal); return 0; } /* upper limit */ if (fVal > ead->upperLimit) { snprintf(error, errLen, "ERROR: %g violates upper limit of device", fVal); return 0; } return 1; } /*----------------------------------------------------------------------------*/ static int EaseStdHandler(void *object) { int iret, l; EaseBase *eab = EaseBaseCast(object); char *corr; assert(eab); if (eab->state < EASE_idle) goto quit; if (availableNetRS232(eab->ser) || availableRS232(eab->ser)) { if (strncmp(eab->msg, "ERROR:", 6) != 0) { eab->msg[0] = '\0'; } l = sizeof(eab->ans); iret = readRS232TillTerm(eab->ser, eab->ans, &l); if (eab->state != EASE_expect && eab->state != EASE_lost) { if (iret == 1) { ParPrintf(eab, eError, "unexpected answer: %s", eab->ans); } goto quit; } if (iret == 1) { ParPrintf(eab, -2, "ans: %s", eab->ans); if (eab->state == EASE_lost) { goto quit; } else { eab->tmo = 120; } } if (iret != 1) { eab->errCode = iret; eab->state = EASE_idle; goto error; } eab->state = EASE_read; } else if (eab->state == EASE_expect) { if (time(NULL) > eab->cmdtime + eab->tmo) { eab->state = EASE_lost; } } else if (eab->state == EASE_lost) { } goto quit; error: /* EaseWriteError(eab); */ quit: return EaseHandler(eab); } /*----------------------------------------------------------------------------*/ static int EaseInit(SConnection * pCon, EaseBase * eab, int argc, char *argv[], int maxflag, FsmHandler handler, FsmFunc start, FsmFunc idle, FsmFunc read) { /* args (starting from argv[0]): : */ int port, iRet, i; rs232 *ser; char *colon, *host; char buf[64]; if (handler == NULL) { handler = EaseStdHandler; } assert(eab); assert(start); assert(read || idle); eab->handler = handler; eab->start = start; eab->read = read; if (idle) { eab->idle = idle; } else { eab->idle = EaseIdle; } if (argc < 1 || argc > 2) { SCWrite(pCon, "illegal number of arguments", eError); return 0; } colon = strchr(argv[0], ':'); if (!colon && argc == 1) { /* use a rs232 object */ ser = FindCommandData(pServ->pSics, argv[0], "RS232 Controller"); if (ser == NULL) { SCWrite(pCon, "ERROR: rs232 not found", eError); return 0; } } else { if (argc == 1) { /* host:port syntax */ port = atoi(colon + 1); i = colon - argv[0]; if (i >= sizeof buf) { SCWrite(pCon, "ERROR: host name too long", eError); return 0; } strncpy(buf, argv[0], i); buf[i] = '\0'; host = buf; } else if (argc == 2) { /* host port syntax */ host = argv[0]; port = atoi(argv[1]); } if (port == 0) { SCWrite(pCon, "ERROR: illegal port number", eError); return 0; } ser = createRS232(host, port); if (ser == NULL) { SCWrite(pCon, "out of memory", eError); return 0; } } eab->ser = ser; eab->startOk = 0; eab->errCode = 0; eab->version[0] = '\0'; eab->maxflag = maxflag; eab->sendCmd = NULL; eab->tmo = 20; eab->updateFlags = calloc(maxflag / EASE_FLAGBITS + 1, sizeof(*eab->updateFlags)); if (eab->updateFlags == NULL) { SCWrite(pCon, "out of memory", eError); return 0; } setRS232ReplyTerminator(eab->ser, "\r"); setRS232SendTerminator(eab->ser, "\r"); setRS232Timeout(eab->ser, 5000); /* milliseconds */ setRS232Debug(eab->ser, 0); eab->task = NULL; eab->cmdtime = 0; /* means: this is not a repeated restart */ if (EaseRestart(eab) < 0) return -1; eab->task = FsmStartTask(eab, eab->handler, eab->idle, eab->p.name); TaskRegisterN(pServ->pTasker,"ease", (TaskFunc) FsmTaskHandler, NULL, FsmKill, eab->task, TASK_PRIO_LOW); return 1; } /*----------------------------------------------------------------------------*/ static void *EaseGetInterface(void *obj, int iCode) { EaseBase *eab = EaseBaseCast(obj); EaseDriv *ead = EaseDrivCast(obj); assert(eab); if (iCode == DRIVEID) { if (ead) { return ead->drivInt; } else { return NULL; } } else if (iCode == ENVIRINTERFACE) { return ead->evInt; } return NULL; } /*----------------------------------------------------------------------------*/ void *EaseMakeBase(SConnection * con, void *class, int argc, char *argv[], int dynamic, int maxflag, ParDef pardef, FsmHandler handler, FsmFunc start, FsmFunc idle, FsmFunc read) { /* args (starting from argv[0]): MakeObject objectname */ EaseBase *eab; char *creationCmd = NULL; if (dynamic) { creationCmd = Arg2Tcl(argc, argv, NULL, 0); } eab = ParMake(con, argv[1], class, pardef, creationCmd); if (!eab) return NULL; ParCheck(&easeBaseClass, eab); if (!EaseInit(con, eab, argc - 3, argv + 3, maxflag, handler, start, idle, read)) { RemoveCommand(pServ->pSics, argv[1]); return NULL; } return eab; } /*----------------------------------------------------------------------------*/ void *EaseMakeDriv(SConnection * con, void *class, int argc, char *argv[], int dynamic, int maxflag, ParDef pardef, FsmHandler handler, FsmFunc start, FsmFunc idle, FsmFunc read, FsmFunc run) { int iret; EaseDriv *ead; char *creationCmd = NULL; assert(run); if (dynamic) { creationCmd = Arg2Tcl(argc, argv, NULL, 0); } ead = ParMake(con, argv[1], class, pardef, creationCmd); if (!ead) return NULL; ParCheck(&easeDrivClass, ead); ead->b.doit = run; ead->evInt = CreateEVInterface(); ead->drivInt = CreateDrivableInterface(); ead->b.p.desc->GetInterface = EaseGetInterface; if (!ead->evInt || !ead->drivInt || !EaseInit(con, (EaseBase *) ead, argc - 3, argv + 3, maxflag, handler, start, idle, read)) { RemoveCommand(pServ->pSics, argv[1]); return NULL; } ead->evInt->GetMode = EaseGetMode; ead->evInt->IsInTolerance = EaseIsInTol; ead->evInt->HandleError = EaseErrHandler; ead->drivInt->Halt = EaseHalt; ead->drivInt->CheckLimits = EaseCheckLimits; ead->drivInt->SetValue = EaseRun; ead->drivInt->CheckStatus = EaseCheckStatus; ead->drivInt->GetValue = EaseGetValue; ead->maxwait = -1; ead->lowerLimit = 0; ead->upperLimit = 1000; ead->settle = 0; ead->tolerance = 1; ead->targetValue = 0; ead->is_running = 0; EaseUpdateHwstate(ead, HWIdle); /* EMon interface to be implemented */ return ead; } /*----------------------------------------------------------------------------*/ void EaseMsgPar(void *object) { EaseBase *eab = EaseBaseCast(object); assert(eab); ParName("status"); ParAccess(usUser); ParLogAs(NULL); if (eab->msg[0] == '\0') { ParList(""); /* do not list when empty */ } else { ParList(NULL); } ParFixedStr(eab->msg, sizeof eab->msg, NULL); return; } /*----------------------------------------------------------------------------*/ int EaseRestartWrapper(void *object, void *userarg, int argc, char *argv[]) { EaseBase *eab = EaseBaseCast(object); char *colon; char *hostpos; int port, i; char host[64], hostport[80]; char *cCmd; /* short string with length 0 or 1: connect to previous host/port */ if (argc > 0 && strlen(argv[0]) > 1) { colon = strchr(argv[0], ':'); if (!colon || argc > 1) { ParPrintf(object, eError, "ERROR: illegal syntax for: %s restart", eab->p.name); return 0; } port = atoi(colon + 1); i = colon - argv[0]; if (i >= sizeof host) { ParPrintf(object, eError, "ERROR: host name too long"); return 0; } strncpy(host, argv[0], i); host[i] = '\0'; if (eab->p.creationCmd != NULL) { hostpos = strstr(eab->p.creationCmd, eab->ser->pHost); if (hostpos != NULL) { /* replace the second part of creationCmd with new host/port */ snprintf(hostport, sizeof hostport, "%s:%d", host, port); hostpos[0]='\0'; cCmd = calloc(1, strlen(eab->p.creationCmd) + strlen(hostport) + 1); strcpy(cCmd, eab->p.creationCmd); strcat(cCmd, hostport); free(eab->p.creationCmd); eab->p.creationCmd = cCmd; } } if (eab->ser->pHost != NULL) { free(eab->ser->pHost); } eab->ser->pHost = strdup(host); eab->ser->iPort = port; } if (eab->task) { EaseStop(eab, NULL); } eab->cmdtime = 0; /* means: this is not a repeated restart */ EaseRestart(eab); return 1; } /*----------------------------------------------------------------------------*/ int EaseDisconnectWrapper(void *object, void *userarg, int argc, char *argv[]) { EaseBase *eab = EaseBaseCast(object); snprintf(eab->msg, sizeof eab->msg, "disconnected"); ParPrintf(object, eWarning, "%s", eab->msg); EaseStop(eab, NULL); eab->state = EASE_offline; return 1; } /*----------------------------------------------------------------------------*/ void EaseBasePar(void *object) { EaseBase *eab = EaseBaseCast(object); assert(eab); ParName("restart"); ParAccess(usUser); ParCmd(EaseRestartWrapper, NULL); ParName("reconnect"); ParAccess(usUser); ParCmd(EaseRestartWrapper, NULL); ParName("disconnect"); ParAccess(usUser); ParCmd(EaseDisconnectWrapper, NULL); if (ParActionIs(PAR_KILL)) { if (eab->ser) { KillRS232(eab->ser); free(eab->ser); eab->ser = NULL; } if (pServ->pTasker && eab->task) { FsmStopTask(eab->task); } if (eab->updateFlags) { free(eab->updateFlags); eab->updateFlags = NULL; } } return; } /*----------------------------------------------------------------------------*/ int EaseSend(void *object, void *userarg, int argc, char *argv[]) { EaseBase *eab = EaseBaseCast(object); int iret; char cmd[32]; char ans[64]; char *term; iret = EaseWaitRead(eab); if (iret >= 0) { eab->sendCmd = ParArg2Str(argc, argv, NULL, 0); /* ParPrintf(eab, -2, "ans: %s", ans); ParPrintf(eab, eValue, "%s", ans); */ } if (iret < 0) { eab->errCode = iret; EaseWriteError(eab); } return 1; } /*----------------------------------------------------------------------------*/ void EaseSendPar(void *object) { ParName("send"); ParAccess(usUser); ParCmd(EaseSend, NULL); return; } /*----------------------------------------------------------------------------*/ void EaseKillDriv(EaseDriv * ead) { if (ead->drivInt) { free(ead->drivInt); } if (ead->evInt) { free(ead->evInt); } } /*----------------------------------------------------------------------------*/ void EaseRunPar(void *object) { EaseDriv *ead; assert(ead = EaseDrivCast(object)); ParName("is_running"); ParAccess(usUser); ParInt(&ead->is_running, 0); if (ParActionIs(PAR_SET) > 0) { if (!ead->is_running) { EaseHalt(ead); } } } /*----------------------------------------------------------------------------*/ void EaseDrivPar(void *object, char *fmt, char *unit) { EaseDriv *ead; assert(ead = EaseDrivCast(object)); ParName("upperLimit"); ParFmt(fmt); ParTail(unit); ParAccess(usUser); ParSave(1); ParFloat(&ead->upperLimit, 310.); ParName("lowerLimit"); if (ead->lowerLimit != 0) { ParFmt(fmt); ParTail(unit); }; ParAccess(usUser); ParSave(1); ParFloat(&ead->lowerLimit, 0.0); ParName("tolerance"); ParFmt(fmt); ParTail(unit); ParAccess(usUser); ParSave(1); ParFloat(&ead->tolerance, 1.0); ParName("maxwait"); if (ead->maxwait < 0) { ParTail("disabled"); } else { ParTail("sec"); } ParAccess(usUser); ParSave(1); ParInt(&ead->maxwait, 7200); ParName("settle"); ParTail("sec"); ParAccess(usUser); ParSave(1); ParInt(&ead->settle, 0); ParName("targetValue"); ParFmt(fmt); ParTail(unit); ParFloat(&ead->targetValue, PAR_NAN); EaseRunPar(ead); if (ParActionIs(PAR_KILL)) { EaseKillDriv(ead); } return; }