new modules
This commit is contained in:
819
ease.c
Normal file
819
ease.c
Normal file
@ -0,0 +1,819 @@
|
||||
/*---------------------------------------------------------------------------
|
||||
ease.c
|
||||
|
||||
basics for (ea)sy implementable (s)ample (e)nvironment devices.
|
||||
handles background activity and connections over rs232.
|
||||
|
||||
Markus Zolliker, March 2005
|
||||
----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <fortify.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include "sics.h"
|
||||
#include "ease.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) {
|
||||
FsmStop(eab->task, eab->idle);
|
||||
eab->state = EASE_notconnected;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
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:
|
||||
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);
|
||||
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) {
|
||||
int iRet;
|
||||
char trash[64];
|
||||
int l;
|
||||
|
||||
if (eab->errCode || eab->state == EASE_expect) 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);
|
||||
}
|
||||
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,
|
||||
"connection to %s:%d lost", eab->ser->pHost, eab->ser->iPort);
|
||||
ParPrintf(eab, eError, "ERROR: %s", eab->msg);
|
||||
eab->state = EASE_notconnected;
|
||||
eab->errCode = iRet;
|
||||
return;
|
||||
}
|
||||
ParPrintf(eab, -2, "cmd: %s", cmd);
|
||||
eab->state = EASE_expect;
|
||||
eab->cmdtime = time(NULL);
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
int EaseWaitRead(EaseBase *eab) {
|
||||
int cnt=0;
|
||||
|
||||
if (eab->state < EASE_idle) {
|
||||
return NOTCONNECTED;
|
||||
}
|
||||
FsmPause(eab->task, 1);
|
||||
while (eab->state == EASE_expect) {
|
||||
/* TaskYield(pServ->pTasker); does not work (pardef is not recursive) */
|
||||
FsmTaskHandler(eab->task);
|
||||
cnt++;
|
||||
}
|
||||
FsmPause(eab->task, 0);
|
||||
/* if (cnt>1) printf("TaskYield %d\n", cnt); */
|
||||
return 1;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void EaseParHasChanged(void) {
|
||||
parameterChange = 1;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void EaseSavePars(void) {
|
||||
char *pFile = NULL;
|
||||
|
||||
if (parameterChange) {
|
||||
parameterChange = 0;
|
||||
|
||||
assert(pServ->pSics);
|
||||
|
||||
pFile = IFindOption(pSICSOptions,"statusfile");
|
||||
if (pFile) {
|
||||
WriteSicsStatus(pServ->pSics,pFile,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
int EaseHandler(EaseBase *eab) {
|
||||
EaseDriv *ead;
|
||||
int iret;
|
||||
|
||||
ead = EaseDrivCast(eab);
|
||||
|
||||
EaseSavePars();
|
||||
if (eab->state == EASE_expect) {
|
||||
if (eab->cmdtime !=0 && time(NULL) > eab->cmdtime + eab->p.period*2) {
|
||||
snprintf(eab->msg, sizeof eab->msg, "no response since %d sec",
|
||||
(int)(time(NULL) - eab->cmdtime));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (eab->state == EASE_lost) {
|
||||
snprintf(eab->msg, sizeof eab->msg, "no response");
|
||||
}
|
||||
if (eab->state == EASE_notconnected) {
|
||||
return 0;
|
||||
}
|
||||
if (eab->state == EASE_connecting) {
|
||||
iret = initRS232Finished(eab->ser);
|
||||
if (iret == 0) return 0; /* waiting for connection */
|
||||
if (iret < 0) {
|
||||
snprintf(eab->msg, sizeof eab->msg,
|
||||
"connection for %s failed", eab->p.name);
|
||||
ParPrintf(eab, eError, "%s", eab->msg);
|
||||
eab->state = EASE_notconnected;
|
||||
return 0;
|
||||
} else {
|
||||
snprintf(eab->msg, sizeof eab->msg,
|
||||
"get a first answer from %s", eab->p.name);
|
||||
eab->state = EASE_idle;
|
||||
}
|
||||
}
|
||||
if (eab->errCode) {
|
||||
EaseWriteError(eab);
|
||||
eab->errCode = 0;
|
||||
if (ead) {
|
||||
ead->hwstate = HWFault;
|
||||
FsmStop(eab->task, eab->doit);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (ead) {
|
||||
if (eab->state == EASE_lost) {
|
||||
if (FsmStop(eab->task, eab->doit)) {
|
||||
ParPrintf(eab, -1, "stop %s caused by timeout", eab->p.name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (ead->stopped && ead->hwstate == HWBusy) {
|
||||
ead->stopped = 0;
|
||||
ead->hwstate = HWIdle;
|
||||
if (FsmStop(eab->task, eab->doit)) {
|
||||
ParPrintf(eab, -1, "%s stopped", 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;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
int EaseCheckDoit(EaseBase *eab) {
|
||||
int i, n;
|
||||
|
||||
if (eab->todo == NULL) {
|
||||
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 *******************************/
|
||||
|
||||
idle:
|
||||
if (! EaseCheckDoit(eab)) goto rd;
|
||||
doit:
|
||||
todo = eab->todo;
|
||||
eab->todo = NULL;
|
||||
FsmCall(todo);
|
||||
return __LINE__; case __LINE__: /**********************************/
|
||||
|
||||
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__: /**********************************/
|
||||
|
||||
ParLog(eab); /* just for the case ParLog was not included in the read function */
|
||||
if (EaseCheckDoit(eab)) goto doit;
|
||||
/*
|
||||
gettimeofday(&tm, NULL);
|
||||
printf("stop %s %f\n", eab->evc->pName, tm.tv_usec / 1e6);
|
||||
*/
|
||||
FsmWait(1);
|
||||
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] |= 1 << (flag % EASE_FLAGBITS);
|
||||
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 < 32) {
|
||||
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 ((1 << (flag % EASE_FLAGBITS)) & eab->updateFlags[i]) {
|
||||
return flag;
|
||||
}
|
||||
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] |= 1 << (flag % EASE_FLAGBITS);
|
||||
} else {
|
||||
eab->updateFlags[flag / EASE_FLAGBITS] &= ~ (1 << (flag % EASE_FLAGBITS));
|
||||
}
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static long EaseRun(void *obj, SConnection *pCon, float fVal) {
|
||||
EaseBase *eab = EaseBaseCast(obj);
|
||||
EaseDriv *ead = EaseDrivCast(obj);
|
||||
|
||||
assert(ead );
|
||||
|
||||
if (! eab->doit) {
|
||||
ParPrintf(ead, -1, "missing run function %s", eab->p.name);
|
||||
return 0;
|
||||
}
|
||||
if (FsmStop(eab->task, eab->doit)) {
|
||||
ParPrintf(ead, -1, "running %s cancelled", eab->p.name);
|
||||
}
|
||||
if (eab->todo) {
|
||||
ParPrintf(ead, -1, "%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->hwstate = 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;
|
||||
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);
|
||||
SCSave(&ead->b.p.conn, pCon);
|
||||
now = time(NULL);
|
||||
if (now > ead->timeout) {
|
||||
ParPrintf(obj, eWarning, "maxwait expired when driving %s", ead->b.p.name);
|
||||
ead->hwstate = 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);
|
||||
ead->hwstate = 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 EaseRestart(EaseBase *eab) {
|
||||
int iRet;
|
||||
|
||||
if (eab->task) {
|
||||
FsmStop(eab->task, eab->idle);
|
||||
FsmRestartTask(eab->task, eab->idle);
|
||||
}
|
||||
eab->todo = eab->start;
|
||||
eab->state = EASE_connecting;
|
||||
iRet = initRS232WithFlags(eab->ser, 3);
|
||||
if (iRet != 1) {
|
||||
eab->errCode = iRet;
|
||||
EaseWriteError(eab);
|
||||
return -1;
|
||||
}
|
||||
snprintf(eab->msg, sizeof eab->msg,
|
||||
"connecting to %s:%d", eab->ser->pHost, eab->ser->iPort);
|
||||
return 0;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
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]):
|
||||
<rs232>
|
||||
<host> <port>
|
||||
<host>:<port>
|
||||
*/
|
||||
int port, iRet, i;
|
||||
rs232 *ser;
|
||||
char *colon, *host;
|
||||
char buf[64];
|
||||
|
||||
assert(eab); assert(handler); 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->errCode = 0;
|
||||
eab->cmdtime = 0;
|
||||
eab->version[0] = '\0';
|
||||
eab->maxflag = maxflag;
|
||||
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,10000); /* milliseconds */
|
||||
setRS232Debug(eab->ser,0);
|
||||
|
||||
eab->task = NULL;
|
||||
if (EaseRestart(eab) < 0) return -1;
|
||||
eab->task = FsmStartTask(eab, eab->handler, eab->idle);
|
||||
|
||||
TaskRegister(pServ->pTasker, (TaskFunc)FsmTaskHandler, NULL, FsmKill,
|
||||
eab->task, 0);
|
||||
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 <driver> <rs232>
|
||||
<host> <port>
|
||||
*/
|
||||
EaseBase *eab;
|
||||
char *creationCmd = NULL;
|
||||
|
||||
if (dynamic) {
|
||||
creationCmd = ParArg2Text(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 = ParArg2Text(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->hwstate = HWIdle;
|
||||
ead->drivInt->Halt = EaseHalt;
|
||||
ead->drivInt->CheckLimits = EaseCheckLimits;
|
||||
ead->drivInt->SetValue = EaseRun;
|
||||
ead->drivInt->CheckStatus = EaseCheckStatus;
|
||||
ead->drivInt->GetValue = EaseGetValue;
|
||||
|
||||
/* EMon interface to be implemented */
|
||||
return ead;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void EaseMsgPar(void *object) {
|
||||
EaseBase *eab = EaseBaseCast(object);
|
||||
|
||||
assert(eab);
|
||||
|
||||
ParName("status");
|
||||
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);
|
||||
|
||||
EaseRestart(eab);
|
||||
return 0;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void EaseBasePar(void *object) {
|
||||
EaseBase *eab = EaseBaseCast(object);
|
||||
|
||||
assert(eab);
|
||||
|
||||
ParName("restart"); ParAccess(usUser); ParCmd(EaseRestartWrapper, 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) {
|
||||
term = eab->ser->sendTerminator;
|
||||
ParArg2Text(argc, argv, cmd, sizeof(cmd) - strlen(term));
|
||||
ParPrintf(eab, -2, "cmd: %s", cmd);
|
||||
strcat(cmd, term);
|
||||
iret = transactRS232(eab->ser, cmd, strlen(cmd),
|
||||
ans, sizeof ans);
|
||||
ParPrintf(eab, -2, "ans: %s", ans);
|
||||
ParPrintf(eab, eValue, "%s", ans);
|
||||
}
|
||||
if (iret < 0) {
|
||||
eab->errCode = iret;
|
||||
EaseWriteError(eab);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void EaseSendPar(void *object) {
|
||||
ParName("send"); ParAccess(usUser); ParCmd(EaseSend, NULL);
|
||||
return;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
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, 0.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);
|
||||
|
||||
if (ParActionIs(PAR_KILL) && ead->drivInt) {
|
||||
free(ead->drivInt);
|
||||
}
|
||||
return;
|
||||
}
|
Reference in New Issue
Block a user