Files
sicspsi/ease.c

1209 lines
30 KiB
C

/*---------------------------------------------------------------------------
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 <errno.h>
#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]):
<rs232>
<host> <port>
<host>:<port>
*/
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 <driver> <rs232>
<host> <port>
*/
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;
}