From c1bbdb935e5b05ba9a10056db4bd08af38a35a1a Mon Sep 17 00:00:00 2001 From: zolliker Date: Tue, 20 Jun 2006 13:29:32 +0000 Subject: [PATCH] - modified and improved various env. drivers - implemented string array object --- arrobj.c | 281 ++++++++++++++++++ ease.c | 73 +++-- ease.h | 1 + euro2kdriv.c | 282 ++++++++++++++++-- fsm.c | 16 +- ighdriv.c | 31 +- ipsdriv.c | 3 + itcdriv.c | 252 ++++++++++++++--- logreader.c | 70 +++-- make_gen | 6 +- modbus.c | 106 ++++++- modbus.h | 5 + oxinst.c | 21 +- pardef.c | 784 +++++++++++++++++++++++++++++---------------------- pardef.h | 9 +- psi.c | 4 +- strobj.c | 3 +- sugar.c | 24 +- tecsdriv.c | 23 +- 19 files changed, 1495 insertions(+), 499 deletions(-) create mode 100644 arrobj.c diff --git a/arrobj.c b/arrobj.c new file mode 100644 index 0000000..5e1eb39 --- /dev/null +++ b/arrobj.c @@ -0,0 +1,281 @@ +/*--------------------------------------------------------------------------- +arrobj.c + +a array object based on pardef + +Markus Zolliker, Feb 2006 +---------------------------------------------------------------------------- +*/ + +#include +#include "sics.h" +#include "splitter.h" +#include "pardef.h" +#include "initializer.h" + +typedef struct ArrayItem { + struct ArrayItem *next; + char *name; + char *value; + char *unit; +} ArrayItem; + +typedef struct { + ParData p; + ArrayItem *items, *freeItems; + char *saveFile; +} ArrayObj; + +static ParClass arrayObjClass = { "array", sizeof(ArrayObj) }; + + +typedef struct WrtObjContext { + FILE *file; + char filename[PATH_MAX]; +} WrtObjContext; + +/*-----------------------------------------------------------------------*/ +int WrtObjOpen(WrtObjContext *ctx, char *fileName) { + + int iret; + + /* create a temporary file first */ + iret = snprintf(ctx->filename, sizeof(ctx->filename), ".%s", fileName); + if (iret < 0 || iret >= sizeof(ctx->filename)) { + return 0; + } + remove(ctx->filename); /* remove already existing temporary file */ + ctx->file = fopen(ctx->filename,"w"); + return ctx->file != NULL; +} +/*-----------------------------------------------------------------------*/ +void WrtObj(WrtObjContext *ctx, char *objectName) { + CommandList *pCom = NULL; + Dummy *pDum = NULL; + + if (ctx) { + pCom = FindCommand(pServ->pSics, objectName); + if (pCom == NULL) { + return; + } + pDum = pCom->pData; + if (pDum != NULL) { + pDum->pDescriptor->SaveStatus(pCom->pData,pCom->pName,ctx->file); + } + } +} +/*-----------------------------------------------------------------------*/ +void WrtObjClose(WrtObjContext *ctx) { + if (ctx) { + fclose(ctx->file); + rename(ctx->filename, ctx->filename+1); + } +} +/*----------------------------------------------------------------------------*/ +static int ArrayExists(void *object, void *arg, int argc, char *argv[]) { + ArrayObj *arr = ParCast(&arrayObjClass, object); + ArrayItem *item; + + assert(arr); + if (argc == 1) { + for (item = arr->items; item != NULL; item = item->next) { + if (strcasecmp(argv[0], item->name) == 0) { + ParPrintf(object, eValue, "1"); + return 1; + } + } + } + ParPrintf(object, eValue, "0"); + return 1; +} +/*----------------------------------------------------------------------------*/ +static int ArrayItems(void *object, void *arg, int argc, char *argv[]) { + ArrayObj *arr = ParCast(&arrayObjClass, object); + ArrayItem *item; + int l; + char *result, *p; + + assert(arr); + l = 1; + for (item = arr->items; item != NULL; item = item->next) { + l += strlen(item->name); l++; + } + result = calloc(l, 1); + if (result) { + p = result; + for (item = arr->items; item != NULL; item = item->next) { + strcpy(p, item->name); p+=strlen(item->name); + *p = ' '; p++; + } + if (p > result) p--; + *p='\0'; + ParPrintf(object, eValue, result); + free(result); + } + return 1; +} +/*----------------------------------------------------------------------------*/ +static int ArrayMakeItem(void *object, void *delete, int argc, char *argv[]) { + ArrayObj *arr = ParCast(&arrayObjClass, object); + ArrayItem *item, **last; + int iarg; + + assert(arr); + if (argc < 1) goto Usage; + last = &arr->items; + for (item = arr->items; item != NULL; item = item->next) { + if (strcasecmp(argv[0], item->name) == 0) { + if (delete) { + *last = item->next; /* remove item from list */ + item->next = arr->freeItems; + arr->freeItems = item; + return 1; + } + break; + } + last = &item->next; + } + if (delete) { + ParPrintf(object, eError, "ERROR: %s.%s not found", arr->p.name, argv[0]); + return 0; + } + if (item == NULL) { + if (arr->freeItems) { + item = arr->freeItems; + arr->freeItems = item->next; + if (item->name) { + free(item->name); item->name = NULL; + } + item->next = NULL; + *last = item; + } else { + item = calloc(1, sizeof(ArrayItem)); + if (item == NULL) return 0; + *last = item; + item->next = NULL; + item->unit = NULL; + item->value = NULL; + } + } + if (item->unit) { + free(item->unit); item->unit=NULL; + } + if (item->value) { + free(item->value); item->value=NULL; + } + if (item->name != NULL) { + if (0 != strcmp(item->name, argv[0])) { + free(item->name); + item->name = strdup(argv[0]); + } + } else { + item->name = strdup(argv[0]); + } + iarg = 1; + if (iarg < argc) { + if (argv[iarg] && argv[iarg][0]) { + item->value = argv[iarg]; + } + iarg++; + if (iarg < argc) { + if (argv[iarg] && argv[iarg][0]) { + item->unit = argv[iarg]; + } + iarg++; + if (iarg < argc) goto Usage; + } + } + if (item->unit) item->unit = strdup(item->unit); + if (item->value) item->value = strdup(item->value); + ParInitPar(object, item->name); + SCparChange(SCLoad(&arr->p.conn)); + + return 1; + Usage: + ParPrintf(object, eError, "Usage: %s makeitem [value] [unit]" + , arr->p.name); + return 0; +} +/*----------------------------------------------------------------------------*/ +static void ArrayObjParDef(void *object) { + ArrayObj *arr = ParCast(&arrayObjClass, object); + FILE *saveFile; + ArrayItem *item, *next; + char *u; + WrtObjContext context; + static int doNotNest = 0; + int saveObjects; + + saveFile = ParSaveFile(); + if (!doNotNest && saveFile && arr->saveFile && *arr->saveFile) { + saveObjects = WrtObjOpen(&context, arr->saveFile); + } else { + saveObjects = 0; + } + for (item = arr->items; item != NULL; item = item->next) { + if (saveFile) { + if (item->unit) { + u = item->unit; + } else { + u = ""; + } + fprintf(saveFile, " %s makeitem %s \"%s\" \"%s\"\n", arr->p.name, item->name, item->value, u); + if (saveObjects) { + WrtObj(&context, item->name); + } + } + ParName(item->name); ParAccess(usUser); + if (item->unit) { + ParTail(item->unit); + } else { + ParList(NULL); + } + ParStr(&item->value, ""); + } + if (saveObjects) { + doNotNest = 1; + WrtObj(&context, arr->p.name); + doNotNest = 0; + WrtObjClose(&context); + } + ParName("makeitem"); ParAccess(usUser); ParCmd(ArrayMakeItem, NULL); + ParName("deleteitem"); ParAccess(usUser); ParCmd(ArrayMakeItem, "del"); + ParName("exists"); ParAccess(usSpy); ParCmd(ArrayExists, NULL); + ParName("items"); ParAccess(usSpy); ParCmd(ArrayItems, NULL); + ParName("saveFile"); ParAccess(usUser); ParStr(&arr->saveFile, ""); + ParStdDef(); + if (ParActionIs(PAR_KILL)) { + for (item = arr->items; item != NULL; item = next) { + next = item->next; + if (item->name) free(item->name); + if (item->unit) free(item->unit); + if (item->value) free(item->value); + free(item); + } + for (item = arr->freeItems; item != NULL; item = next) { + next = item->next; + if (item->name) free(item->name); + if (item->unit) free(item->unit); + if (item->value) free(item->value); + free(item); + } + } +} +/*----------------------------------------------------------------------------*/ +static int ArrayObjInit(SConnection *con, int argc, char *argv[], int dynamic) { + ArrayObj *arr = NULL; + char *creationCmd = NULL; + + if (dynamic) { + creationCmd = Arg2Tcl(argc, argv, NULL, 0); + } + arr = ParMake(con, argv[1], &arrayObjClass, ArrayObjParDef, creationCmd); + arr->freeItems = NULL; + arr->items = NULL; + return arr != NULL; +} +/*----------------------------------------------------------------------------*/ +void ArrayObjStartup(void) { + ParMakeClass(&arrayObjClass, NULL); + MakeDriver("array", ArrayObjInit, 0); +} diff --git a/ease.c b/ease.c index 837f3a4..e516fbb 100644 --- a/ease.c +++ b/ease.c @@ -16,6 +16,7 @@ Markus Zolliker, March 2005 #include #include #include "sics.h" +#include "splitter.h" #include "ease.h" #define EASE_FLAGBITS (8*sizeof(long)) @@ -149,6 +150,27 @@ void EaseSavePars(void) { } } /*----------------------------------------------------------------------------*/ +static int EaseRestart(EaseBase *eab) { + int iRet; + + 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; + } + snprintf(eab->msg, sizeof eab->msg, + "connecting to %s:%d", eab->ser->pHost, eab->ser->iPort); + return 0; +} +/*----------------------------------------------------------------------------*/ int EaseHandler(EaseBase *eab) { EaseDriv *ead = EaseDrivCast(eab);; int iret; @@ -192,6 +214,10 @@ int EaseHandler(EaseBase *eab) { } } if (eab->errCode) { + if (eab->errCode == BADSEND) { + EaseRestart(eab); + return 0; + } EaseWriteError(eab); eab->errCode = 0; if (ead) { @@ -284,7 +310,6 @@ static long EaseIdle(long pc, void *object) { 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); @@ -381,7 +406,7 @@ static long EaseRun(void *obj, SConnection *pCon, float fVal) { assert(ead ); - SCSave(&eab->p.conn, pCon); + ParSaveConn(eab, pCon); if (! eab->doit) { ParPrintf(ead, eError, "ERROR: missing run function %s", eab->p.name); return 0; @@ -458,7 +483,7 @@ static int EaseCheckStatus(void *obj, SConnection *pCon) { time_t now, t; assert(ead); - SCSave(&ead->b.p.conn, pCon); + ParSaveConn(ead, pCon); if (ead->stopped) { return HWIdle; } @@ -517,27 +542,6 @@ static int EaseCheckLimits(void *obj, float fVal, char *error, int errLen) { return 1; } /*----------------------------------------------------------------------------*/ -static int EaseRestart(EaseBase *eab) { - int iRet; - - 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; - } - 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, @@ -663,7 +667,7 @@ void *EaseMakeBase(SConnection *con, void *class, int argc, char *argv[], char *creationCmd = NULL; if (dynamic) { - creationCmd = ParArg2Text(argc, argv, NULL, 0); + creationCmd = Arg2Tcl(argc, argv, NULL, 0); } eab = ParMake(con, argv[1], class, pardef, creationCmd); if (!eab) return NULL; @@ -691,7 +695,7 @@ void *EaseMakeDriv(SConnection *con, void *class, int argc, char *argv[], assert(run); if (dynamic) { - creationCmd = ParArg2Text(argc, argv, NULL, 0); + creationCmd = Arg2Tcl(argc, argv, NULL, 0); } ead = ParMake(con, argv[1], class, pardef, creationCmd); if (!ead) return NULL; @@ -781,7 +785,7 @@ int EaseSend(void *object, void *userarg, int argc, char *argv[]) { iret = EaseWaitRead(eab); if (iret >= 0) { - eab->sendCmd = ParArg2Text(argc, argv, NULL, 0); + eab->sendCmd = ParArg2Str(argc, argv, NULL, 0); ParPrintf(eab, -2, "ans: %s", ans); ParPrintf(eab, eValue, "%s", ans); @@ -798,6 +802,15 @@ void EaseSendPar(void *object) { return; } /*----------------------------------------------------------------------------*/ +void EaseKillDriv(EaseDriv *ead) { + if (ead->drivInt) { + free(ead->drivInt); + } + if (ead->evInt) { + free(ead->evInt); + } +} +/*----------------------------------------------------------------------------*/ void EaseDrivPar(void *object, char *fmt, char *unit) { EaseDriv *ead; @@ -816,7 +829,7 @@ void EaseDrivPar(void *object, char *fmt, char *unit) { ParName("tolerance"); ParFmt(fmt); ParTail(unit); ParAccess(usUser); ParSave(1); - ParFloat(&ead->tolerance, 0.0); + ParFloat(&ead->tolerance, 1.0); ParName("maxwait"); if (ead->maxwait < 0) { @@ -835,8 +848,8 @@ void EaseDrivPar(void *object, char *fmt, char *unit) { ParFmt(fmt); ParTail(unit); ParFloat(&ead->targetValue, PAR_NAN); - if (ParActionIs(PAR_KILL) && ead->drivInt) { - free(ead->drivInt); + if (ParActionIs(PAR_KILL)) { + EaseKillDriv(ead); } return; } diff --git a/ease.h b/ease.h index 366a27b..3798713 100644 --- a/ease.h +++ b/ease.h @@ -82,6 +82,7 @@ int EaseHandler(EaseBase *eab); void EaseBasePar(void *object); void EaseSendPar(void *object); void EaseMsgPar(void *object); +void EaseKillDriv(EaseDriv *ead); void EaseDrivPar(void *object, char *fmt, char *unit); void EaseParHasChanged(void); void EaseStop(EaseBase *eab); diff --git a/euro2kdriv.c b/euro2kdriv.c index b85386a..636e5e6 100644 --- a/euro2kdriv.c +++ b/euro2kdriv.c @@ -1,7 +1,7 @@ /*--------------------------------------------------------------------------- euro2kdriv.c -Driver for the EuroTherm 2000 controllers (ModBus protocoll) +Driver for the EuroTherm 2000 controllers (ModBus protocol) Markus Zolliker, August 2005 ----------------------------------------------------------------------------*/ @@ -30,64 +30,273 @@ Markus Zolliker, August 2005 #include "fsm.h" #include "initializer.h" +#define EURO2K_SET 1 +#define EURO2K_MODE 2 + +typedef enum {read_only, settable, to_set} Euro2kAccess; + +typedef struct Euro2kPar { + struct Euro2kPar *next; + char *name; + char *unit; + char *fmt; + int adr; + ModBusType type; /* 0: float, 1: int, 2: time */ + Euro2kAccess set; /* 0: read-only; 1: settable; 2: to be set */ + float par; +} Euro2kPar; + typedef struct { EaseDriv d; + char *unit; + int mode, manual; + char *script; + int warned; float temperature; float output; float setpoint; - int adr; - float par; + Euro2kPar *pars, *readPar; } Euro2k; static ParClass euro2kClass = { "EURO2K", sizeof(Euro2k) }; +/*----------------------------------------------------------------------------*/ +static int Euro2kMakePar(void *object, void *userarg, int argc, char *argv[]) +{ + Euro2k *drv = ParCast(&euro2kClass, object); + Euro2kPar *par, **last; + int iarg; + + assert(drv); + if (argc < 1) goto Usage; + last = &drv->pars; + for (par = drv->pars; par != NULL; par = par->next) { + if (strcasecmp(argv[0], par->name) == 0) { + break; + } + last = &par->next; + } + if (par == NULL) { + par = calloc(1, sizeof(Euro2kPar)); + if (par == NULL) return 0; + *last = par; + par->unit = NULL; + par->fmt = NULL; + } else { + if (par->unit) { + free(par->unit); par->unit=NULL; + } + if (par->fmt) { + free(par->fmt); par->fmt=NULL; + } + } + par->name = strdup(argv[0]); + iarg = 1; + if (strcasecmp(argv[iarg],"w") == 0) { /* writeable */ + par->set = settable; + iarg++; + } else { + par->set = read_only; + } + par->type = modBusFloat; + if (iarg>=argc) goto Usage; + if (strcasecmp(argv[iarg],"int") == 0) { + par->type = modBusInt; iarg++; + par->fmt = "%.0f"; + } else if (strcasecmp(argv[iarg],"time") == 0) { + par->type = modBusTime; iarg++; + par->unit = "sec"; + par->fmt = "%.4g"; + } else { + par->type = modBusFloat; + } + if (iarg >= argc) goto Usage; + par->adr = atoi(argv[iarg]); + iarg++; + if (iarg < argc) { + if (argv[iarg] && argv[iarg][0]) { + par->unit = argv[iarg]; + } + iarg++; + if (iarg < argc) { + if (argv[iarg] && argv[iarg][0]) { + par->fmt = argv[iarg]; + } + iarg++; + if (iarg < argc) goto Usage; + } + } + if (par->unit) par->unit = strdup(par->unit); + if (par->fmt) par->fmt = strdup(par->fmt); + ParInitPar(object, par->name); + EaseParHasChanged(); + return 1; + Usage: + ParPrintf(object, eError, "Usage: %s makepar [w] [int|time] adr [unit] [fmt]" + , drv->d.b.p.name); + return 0; +} /*----------------------------------------------------------------------------*/ void Euro2kParDef(void *object) { Euro2k *drv = ParCast(&euro2kClass, object); + ParData *obj = object; + Euro2kPar *par, *next; + FILE *saveFile; + char *w, *t, *u, *f; - ParName(""); ParTail("C"); + static char *modeList[]={"auto", "manual", NULL }; + + ParName(""); ParTail(drv->unit); ParFloat(&drv->temperature, PAR_NAN); + ParName("unit"); ParAccess(usUser); ParLogAs(NULL); + ParStr(&drv->unit, "C"); + + ParName("mode"); ParEnum(modeList); ParList(0); EaseUpdate(EURO2K_MODE); + ParInt(&drv->mode, 1); + + ParName("manual"); ParEnum(modeList); + ParInt(&drv->manual, 1); + ParName("output"); ParTail("%"); ParFloat(&drv->output, PAR_NAN); - ParName("setpoint"); ParTail("C"); + ParName("set"); ParTail(drv->unit); EaseUpdate(EURO2K_SET); ParFloat(&drv->setpoint, PAR_NAN); - ParName("adr"); ParAccess(usUser); ParList(NULL); - ParInt(&drv->adr, 0); + ParName("task"); ParAccess(usUser); ParList(NULL); ParSave(1); + ParStr(&drv->script, "0"); - if (drv->adr > 0) { - ParName("par"); ParList(NULL); - ParFloat(&drv->par, PAR_NAN); + saveFile = ParSaveFile(); + for (par = drv->pars; par != NULL; par = par->next) { + if (par->adr > 0) { + if (saveFile) { + if (par->set) { + w="w "; + } else { + w=""; + } + if (par->type == modBusInt) { + t = "int "; + } else if (par->type == modBusTime) { + t = "time "; + } else { + t = ""; + } + if (par->unit) { + u = par->unit; + } else { + u = ""; + } + if (par->fmt) { + f = par->fmt; + } else { + f = ""; + } + fprintf(saveFile, " %s makepar %s %s%s%d \"%s\" \"%s\"\n", obj->name, par->name, + w, t, par->adr, u, f); + } + ParName(par->name); + if (par->unit) { + ParTail(par->unit); + } else { + ParList(NULL); + } + if (par->fmt) { + ParFmt(par->fmt); + } + if (par->set >= settable) { + if (EaseUpdate(EURO2K_SET)) { + par->set = to_set; + } + } + ParFloat(&par->par, PAR_NAN); + } } + + ParName("makepar"); ParAccess(usUser); ParCmd(Euro2kMakePar, NULL); EaseBasePar(drv); - EaseDrivPar(drv, "%#.5g", "C"); + EaseDrivPar(drv, "%#.5g", drv->unit); ParStdDef(); EaseMsgPar(drv); + if (ParActionIs(PAR_KILL)) { + next = drv->pars; + for (par = next; par != NULL; par = next) { + next= par->next; + if (par->name) { + free(par->name); + par->name = NULL; + } + if (par->unit) { + free(par->unit); + par->unit = NULL; + } + if (par->fmt) { + free(par->fmt); + par->fmt = NULL; + } + free(par); + } + drv->pars = NULL; + } } /*----------------------------------------------------------------------------*/ static long Euro2kRead(long pc, void *object) { Euro2k *drv = ParCast(&euro2kClass, object); EaseBase *eab = object; + Euro2kPar *par; + Tcl_Interp *pTcl = NULL; char *p; - int l; + int l, m, iRet; + float dif; char buf[4]; switch (pc) { default: /* FSM BEGIN *******************************/ + if (drv->script && drv->script[0] != '\0' && 0 != strcmp(drv->script, "0")) { + pTcl = InterpGetTcl(pServ->pSics); + iRet = Tcl_Eval(pTcl,drv->script); + if (iRet == TCL_OK) { + if (drv->warned > 0) drv->warned--; + } else if (drv->warned<3) { + drv->warned++; + ParPrintf(drv, eError, "ERROR: %s in %s.task '%s'", pTcl->result, eab->p.name, drv->script); + } + } + ModBusRequestValue(eab, 273); /* get manual or auto */ + return __LINE__; case __LINE__: /**********************************/ + m = ModBusGetValue(eab, modBusInt); + if (m != drv->manual) { /* mode changed manually */ + drv->mode = m; + } + drv->manual= m; ModBusRequestFloats(eab, 1, 3); return __LINE__; case __LINE__: /**********************************/ drv->temperature = ModBusGetFloat(eab, 1); - drv->setpoint = ModBusGetFloat(eab, 2); + if (!EaseGetUpdate(drv, EURO2K_SET)) { + drv->setpoint = ModBusGetFloat(eab, 2); + } drv->output = ModBusGetFloat(eab, 3); - - if (drv->adr == 0) goto noPar; - ModBusRequestFloats(eab, drv->adr, 3); + par = drv->pars; + loop: + if (par == NULL) goto finish; + if (par->adr == 0 || par->set == to_set) goto skipPar; + ModBusRequestValue(eab, par->adr); + drv->readPar = par; return __LINE__; case __LINE__: /**********************************/ - drv->par = ModBusGetFloat(eab, drv->adr); - noPar: - + par = drv->readPar; + if (par->set != to_set) { + par->par = ModBusGetValue(eab, par->type); + } + skipPar: + par = par->next; + goto loop; + + finish: + if (eab->p.verbose >= 3) { + eab->p.verbose--; + if (eab->p.verbose < 3) eab->p.verbose=0; + } ParLog(drv); fsm_quit: return 0; } /* FSM END *********************************/ } @@ -95,13 +304,40 @@ static long Euro2kRead(long pc, void *object) { static long Euro2kSet(long pc, void *object) { Euro2k *drv = ParCast(&euro2kClass, object); EaseBase *eab = object; + Euro2kPar *par; char *p; int l; + int upd; char buf[4]; switch (pc) { default: /* FSM BEGIN *******************************/ - ModBusPutFloats(eab, 2, 1, &drv->d.targetValue); + loop: + upd = EaseNextUpdate(drv); + if (upd == EASE_RUN) { + drv->setpoint = drv->d.targetValue; + goto run; + } + if (upd == EURO2K_MODE) goto mode; + if (upd == EURO2K_SET) goto run; + for (par = drv->pars; par != NULL; par = par->next) { + if (par->set == to_set) { + ModBusPutValue(eab, par->adr, par->type, par->par); + par->set = settable; + goto setIt; + } + } + goto fsm_quit; + run: + ModBusPutFloats(eab, 2, 1, &drv->setpoint); return __LINE__; case __LINE__: /**********************************/ + if (drv->mode == 0) goto loop; + drv->mode = 0; + mode: + drv->manual = drv->mode; + ModBusPutValue(eab, 273, 1, drv->manual); /* set manual to 0 */ + setIt: + return __LINE__; case __LINE__: /**********************************/ + goto loop; fsm_quit: return 0; } /* FSM END *********************************/ } @@ -111,9 +347,9 @@ static long Euro2kStart(long pc, void *object) { EaseBase *eab = object; switch (pc) { default: /* FSM BEGIN *******************************/ - ModBusRequestFloats(eab, 1, 1); + ModBusRequestValue(eab, 1); return __LINE__; case __LINE__: /**********************************/ - if (0 == ModBusGetFloat(eab, 1)) { + if (0 == ModBusGetValue(eab, modBusFloat)) { ParPrintf(drv, eError, "bad or no response on ModBus"); goto quit; } @@ -136,8 +372,10 @@ static int Euro2kInit(SConnection *con, int argc, char *argv[], int dynamic) { Euro2kParDef, ModBusHandler, Euro2kStart, NULL, Euro2kRead, Euro2kSet); if (drv == NULL) return 0; + drv->pars = NULL; setRS232ReplyTerminator(drv->d.b.ser,""); setRS232SendTerminator(drv->d.b.ser,""); + ParPrintf(drv, eValue, "Eurotherm 2xxx"); return 1; } /*----------------------------------------------------------------------------*/ diff --git a/fsm.c b/fsm.c index 46cf878..b96b2e1 100644 --- a/fsm.c +++ b/fsm.c @@ -10,6 +10,7 @@ M. Zolliker, Aug 2004 #include #include #include "fsm.h" +#include "statistics.h" #define MAXSTACK 8 @@ -32,6 +33,7 @@ struct Fsm { static Fsm *fsm = NULL; static FsmFunc callFunc = NULL; +static Statistics *taskStat = NULL; void FsmWait(long delay) { assert(fsm); @@ -45,17 +47,27 @@ void FsmSpeed(Fsm *task) { int FsmTaskHandler(Fsm *task) { long line; + Statistics *old; + if (taskStat == NULL) { + taskStat=StatisticsNew(""); + } + old = StatisticsBegin(taskStat); if (task->pause) { task->handler(task->obj); + StatisticsEnd(old); return 1; } if (task->pc >= 0) { /* task->pc < 0 means stop current function */ if (task->till != 0) { - if (time(NULL) < task->till) return 1; /* wait */ + if (time(NULL) < task->till) { + StatisticsEnd(old); + return 1; /* wait */ + } task->till = 0; } if (task->handler(task->obj) == 0) { + StatisticsEnd(old); return 1; /* wait for answer */ } fsm = task; @@ -72,6 +84,7 @@ int FsmTaskHandler(Fsm *task) { } fsm = NULL; } + StatisticsEnd(old); if (task->pc <= 0) { if (task->sp == 0) { return (task->obj != NULL); /* finish task only when explicitely stopped */ @@ -111,6 +124,7 @@ int FsmStop(Fsm *task, FsmFunc func) { int i; if (task == NULL) task = fsm; + if (func == NULL) return 0; assert(task); for (i=0; i < task->sp; i++) { if (func == task->stack[i].func) { diff --git a/ighdriv.c b/ighdriv.c index f8eae58..40a0ed3 100644 --- a/ighdriv.c +++ b/ighdriv.c @@ -31,6 +31,7 @@ Markus Zolliker, May 2005 #include "fsm.h" #include "initializer.h" +#define OLDIGH -8 #define SORBS_FLAG 1 #define MIXP_FLAG 2 #define STILL_FLAG 3 @@ -93,11 +94,11 @@ static void IghParDef(void *object) { ParFloat(&drv->sorbS, PAR_NAN); ParName("Tmix"); - ParTail("K"); ParFmt("%.3f"); + ParTail("K"); ParFmt("%.4f"); ParFloat(&drv->mixT, PAR_NAN); ParName("T1K"); - ParTail("K"); ParFmt("%.3f"); + ParTail("K"); ParFmt("%.4f"); ParFloat(&drv->onekT, PAR_NAN); ParName("Tsorb"); @@ -270,6 +271,20 @@ static long IghRead(long pc, void *object) { if (EaseCheckDoit(eab)) goto quit; + if (eab->syntax == OLDIGH) { + EaseWrite(eab, "R3"); + } else { + EaseWrite(eab, "R32"); + } + return __LINE__; case __LINE__: /**********************************/ + if (eab->syntax == OLDIGH) { + drv->mixT = OxiGet(eab, 3, NULL, drv->mixT); + } else { + drv->mixT = OxiGet(eab, 4, NULL, drv->mixT); + if (drv->mixT < 0) drv->mixT += 6.5536; /* correct a bug in firmware < 3.03 */ + } + if (EaseCheckDoit(eab)) goto quit; + EaseWrite(eab, "R1"); return __LINE__; case __LINE__: /**********************************/ drv->sorbT = OxiGet(eab, 1, NULL, drv->sorbT); @@ -282,12 +297,6 @@ static long IghRead(long pc, void *object) { if (EaseCheckDoit(eab)) goto quit; - EaseWrite(eab, "R3"); - return __LINE__; case __LINE__: /**********************************/ - drv->mixT = OxiGet(eab, 3, NULL, drv->mixT); - - if (EaseCheckDoit(eab)) goto quit; - if (EaseGetUpdate(drv, MIXP_FLAG)) goto skip4; EaseWrite(eab, "R4"); return __LINE__; case __LINE__: /**********************************/ @@ -382,7 +391,11 @@ static long IghStart(long pc, void *object) { EaseStop(eab); goto quit; } - eab->syntax = -8; /* special value for communication error correction */ + if (strstr(eab->version, "2.01") != NULL) { + eab->syntax = OLDIGH; /* includes communication error correction */ + } else { + eab->syntax = 0; + } ParPrintf(drv, eStatus, "connected to %s", eab->version); FsmCall(IghRead); return __LINE__; case __LINE__: /**********************************/ diff --git a/ipsdriv.c b/ipsdriv.c index 7aa5e2b..d85e87b 100644 --- a/ipsdriv.c +++ b/ipsdriv.c @@ -161,6 +161,9 @@ void IpsParDef(void *object) { if (ParActionIs(PAR_LIST) || ParActionIs(PAR_SET) || ParActionIs(PAR_SHOW)) { IpsOk(drv); } + if (ParActionIs(PAR_KILL)) { + EaseKillDriv(&drv->d); + } EaseMsgPar(drv); } /*----------------------------------------------------------------------------*/ diff --git a/itcdriv.c b/itcdriv.c index e018f9d..7ad248e 100644 --- a/itcdriv.c +++ b/itcdriv.c @@ -47,7 +47,13 @@ typedef struct { float gas; float autoGasLimit; float setGas; - float prop, integ, deriv; + float travelTime; /* travel time for needle valve [sec/100%] */ + /* control parameters: for ITC / for TESLATRON */ + float prop; /* proportional value / for slow loop [mbar/K] */ + float integ; /* integration time / for slow loop [sec] */ + float deriv; /* deriv. time / int. for pressure [sec] */ + float prop2; /* TESLATRON only: prop. for pressure [%/mbar] */ + float lambdaTarget; /* TESLATRON only: lambda stage target temperature */ int pidMode; int sampleChan; int controlChan; @@ -56,6 +62,8 @@ typedef struct { int remote; int h; /* actual heater channel */ int a; /* actual auto mode */ + time_t lastCtrl; + float lastTdiff, lastPdiff; } Itc; static ParClass itcClass = { "ITC", sizeof(Itc) }; @@ -69,6 +77,7 @@ static void ItcParDef(void *object) { int i; static char *ti[4] = {"setp","t1","t2","t3"}; static char *modeList[]={"off", "manual", "auto", NULL }; + static char *progressList[]={"off", "cooling", "ok", NULL }; static char *pidList[]={"default", "manual", "auto", NULL }; ParName("sampleChan"); @@ -97,6 +106,13 @@ static void ItcParDef(void *object) { } else { ParTail("K"); } + i = drv->sampleChan; + if (drv->dig[i] < 0) { + snprintf(fmt, sizeof fmt, "%s", "%.3f"); + } else { + snprintf(fmt, sizeof fmt, "%s.%df", "%", drv->dig[i]); + } + ParFmt(fmt); ParFloat(&drv->t[drv->sampleChan], PAR_NAN); ParName("dig1"); ParAccess(usUser); ParLogAs(NULL); ParInt(&drv->dig[1], -1); @@ -145,14 +161,17 @@ static void ItcParDef(void *object) { ParSave(1); EaseUpdate(ITC_SETHTR); ParFloat(&drv->htr, PAR_NAN); - } - - ParName("gasMode"); - ParAccess(usUser); ParEnum(modeList); - if (eab->syntax == TESLATRON) { + + ParName("gasMode"); + ParAccess(usUser); ParEnum(modeList); + ParList(NULL); ParInt(&drv->gasMode, 1); + } else { - ParList(""); ParInt(&drv->gasMode, 1); + ParName("progress"); + ParAccess(usUser); ParEnum(progressList); + ParList(NULL); ParSave(1); + ParInt(&drv->gasMode, 0); } ParName("gas"); @@ -170,6 +189,11 @@ static void ItcParDef(void *object) { EaseUpdate(ITC_SETGAS); ParSave(1); ParFloat(&drv->setGas, 20.0); + ParName("travelTime"); ParFmt("%.0f"); ParTail("sec"); + ParList(""); + ParAccess(usUser); ParSave(1); + ParFloat(&drv->travelTime, 100.0); + if (eab->syntax != TESLATRON) { ParName("autoGasLimit"); ParAccess(usUser); ParFmt("%.1f"); ParTail("K"); ParSave(1); @@ -195,28 +219,62 @@ static void ItcParDef(void *object) { if (drv->pidMode == 1) ParList(""); EaseUpdate(ITC_DERIV); ParFloat(&drv->deriv, PAR_NAN); + } else { + ParName("lambdaTarget"); ParFmt("%.2f"); ParTail("K"); + if (drv->gasMode == 0) ParList(""); + ParAccess(usUser); ParSave(1); + ParFloat(&drv->lambdaTarget, 2.2); + + ParName("prop"); ParFmt("%.1f"); ParTail("mbar/K"); + ParList(""); + ParAccess(usUser); ParSave(1); + ParFloat(&drv->prop, 300); + + ParName("int"); ParFmt("%.1f"); ParTail("mbar/K/min"); + ParList(""); + ParAccess(usUser); ParSave(1); + ParFloat(&drv->integ, 3.0); + + ParName("prop2"); ParFmt("%.1f"); ParTail("%/mbar"); + ParList(""); + ParAccess(usUser); ParSave(1); + ParFloat(&drv->prop2, 1.0); + + ParName("int2"); ParFmt("%.1f"); ParTail("%/mbar/min"); + ParList(""); + ParAccess(usUser); ParSave(1); + ParFloat(&drv->deriv, 2.0); } if (drv->controlChan == 0) { - i = drv->sampleChan; + i = drv->dig[drv->sampleChan]; } else { - i = drv->controlChan; + i = drv->dig[drv->controlChan]; } - if (drv->dig[i] < 0) { + if (i < 0) { snprintf(fmt, sizeof fmt, "%s", "%.3f"); } else { - snprintf(fmt, sizeof fmt, "%s.%df", "%", drv->dig[i]); + if (eab->syntax == TESLATRON) i+=2; + snprintf(fmt, sizeof fmt, "%s.%df", "%", i); } EaseBasePar(drv); EaseSendPar(drv); if (eab->syntax != TESLATRON) { EaseDrivPar(drv, fmt, "K"); + } else { + EaseDrivPar(drv, fmt, "mbar"); } ParStdDef(); EaseMsgPar(drv); } /*----------------------------------------------------------------------------*/ +static void ItcLcParDef(void *object) { + EaseBase *eab = object; + eab->syntax = TESLATRON; + ItcParDef(object); +} +/*----------------------------------------------------------------------------*/ void ItcStatus(Itc *drv) { char *ans; int *code; @@ -241,7 +299,7 @@ void ItcStatus(Itc *drv) { } else { drv->h = drv->controlChan; } - if (ans[6] != '3' && drv->remote == 2) { + if (ans[5] != '3' && drv->remote == 2) { ParPrintf(drv, eError, "ITC switched to local"); *code = EASE_FAULT; drv->remote = 1; @@ -249,12 +307,48 @@ void ItcStatus(Itc *drv) { } } /*----------------------------------------------------------------------------*/ +float controlPropInt( + float diff, /* input (soll-ist for negative loop, ist-soll for positive) */ + float prop, /* prop (gain) units: [out]/[inp] */ + float intd, /* int*delta (reset) units: [out]/[inp] */ + float bandP, /* prop deadband units: [inp] */ + float bandi, /* integral deadband units: [inp] */ + float *buffer) /* a buffer to store last diff */ { + + float d, d0; + + bandP = bandP * 0.5; + d0 = *buffer; + if (fabs(diff) < bandi * 1.01) { + intd = 0; + } + if (diff > d0 + bandP) { + d = diff - bandP; + } else if (diff < d0 - bandP) { + d = diff + bandP; + } else { + d = d0; + } + *buffer = d; + return prop * (d - d0) + intd * diff; +} +/*----------------------------------------------------------------------------*/ +void controlLimits(float *inp, float min, float max) { + if (*inp > max) { + *inp = max; + } else if (*inp < min) { + *inp = min; + } +} +/*----------------------------------------------------------------------------*/ static long ItcRead(long pc, void *object) { Itc *drv = ParCast(&itcClass, object); EaseBase *eab = object; char *p; int l; + time_t now, delta; char buf[4]; + float gas, band; switch (pc) { default: /* FSM BEGIN *******************************/ EaseWrite(eab, "X"); @@ -286,7 +380,7 @@ static long ItcRead(long pc, void *object) { EaseWrite(eab, "R0"); /* read control T */ return __LINE__; case __LINE__: /**********************************/ drv->t[0] = OxiGet(eab, drv->dig[drv->controlChan], NULL, drv->t[0]); - if (drv->gasMode == 2) { + if (drv->gasMode == 2 && eab->syntax != TESLATRON) { if (drv->t[drv->controlChan] > drv->autoGasLimit + 1.0) { if (drv->a < 2) { drv->a |= 2; /* switch gas to auto */ @@ -303,9 +397,14 @@ static long ItcRead(long pc, void *object) { } else { goto skip0; } - } - if (drv->setGas != drv->gas) { - EaseSetUpdate(drv, ITC_SETGAS, 1); + if (drv->setGas != drv->gas) { + EaseSetUpdate(drv, ITC_SETGAS, 1); + } + } else { + if (drv->setGas != drv->gas) { + EaseSetUpdate(drv, ITC_SETGAS, 1); + } + goto skip0; } } } else if (drv->a < 2) { @@ -321,13 +420,80 @@ static long ItcRead(long pc, void *object) { EaseWrite(eab, buf); return __LINE__; case __LINE__: /**********************************/ skip0: + + EaseWrite(eab, "R7"); /* read gas flow */ + return __LINE__; case __LINE__: /**********************************/ + gas = OxiGet(eab, 1, NULL, drv->gas); + + time(&now); + delta = now - drv->lastCtrl; + drv->lastCtrl = now; + + if (drv->gas == PAR_NAN) { + drv->gas = gas; + } else { + if (drv->travelTime < 1) drv->travelTime = 1; + if (drv->gas < gas) { + drv->gas += delta * 100.0 / drv->travelTime; + if (drv->gas > gas) drv->gas = gas; + } else { + drv->gas -= delta * 100.0 / drv->travelTime; + if (drv->gas < gas) drv->gas = gas; + } + } + + if (eab->syntax != TESLATRON || drv->gasMode <= 0) goto skipFlow; + if (delta > 10) delta=10; + + if (drv->prop <= 0) { + band = 0.1; + } else { + band = (drv->d.upperLimit - drv->d.lowerLimit) / drv->prop; + } + if (drv->t[2] - drv->lambdaTarget > band) { + drv->gasMode = 1; + } + if (drv->gasMode == 1) { + drv->d.targetValue = drv->d.upperLimit; + if (drv->t[2] <= drv->lambdaTarget + 0.001) { + drv->gasMode = 2; + drv->d.targetValue = drv->d.lowerLimit; + } + } else { + drv->d.targetValue += + controlPropInt(drv->t[2] - drv->lambdaTarget, + drv->prop, drv->integ*delta/60.0, 0.01, 0.01, &drv->lastTdiff); + band = 0.01 * drv->prop; + controlLimits(&drv->d.targetValue, + drv->d.lowerLimit - band, drv->d.upperLimit + band); + } + + drv->setGas += + controlPropInt(drv->d.targetValue - drv->t[1], + drv->prop2, drv->deriv*delta/60.0, drv->d.tolerance, 0.1, &drv->lastPdiff); + controlLimits(&drv->setGas, 0.0, 99.9); + + if (fabsf(drv->setGas - gas) < 0.1) goto skipFlow; + EaseParHasChanged(); + + if (drv->remote == 2) goto skipActive; + EaseWrite(eab, "C3"); + return __LINE__; case __LINE__: /**********************************/ + drv->remote = 2; + skipActive: - if (!drv->remote) goto skiprmt; + OxiSet(eab, "G", drv->setGas, 1); /* cold valve setting */ + return __LINE__; case __LINE__: /**********************************/ + skipFlow: + + if (!drv->remote || eab->syntax == TESLATRON) goto skiprmt; EaseWrite(eab, "C0"); drv->remote = 0; return __LINE__; case __LINE__: /**********************************/ skiprmt: + if (eab->syntax == TESLATRON) goto skipctrl; + if (EaseGetUpdate(drv, ITC_SETHTR)) goto skiphtr; EaseWrite(eab, "R5"); /* read heater */ return __LINE__; case __LINE__: /**********************************/ @@ -335,11 +501,6 @@ static long ItcRead(long pc, void *object) { drv->htr = OxiGet(eab, 1, NULL, drv->htr); skiphtr: - EaseWrite(eab, "R7"); /* read gas flow */ - return __LINE__; case __LINE__: /**********************************/ - drv->gas = OxiGet(eab, 1, NULL, drv->gas); - skipgas: - if (EaseGetUpdate(drv, ITC_PROP)) goto skipprop; EaseWrite(eab, "R9"); /* read prop */ return __LINE__; case __LINE__: /**********************************/ @@ -360,7 +521,8 @@ static long ItcRead(long pc, void *object) { if (EaseGetUpdate(drv, ITC_DERIV)) goto skipderiv; drv->deriv = OxiGet(eab, 1, NULL, drv->deriv); skipderiv: - + + skipctrl: ParLog(drv); fsm_quit: return 0; } /* FSM END *********************************/ } @@ -418,7 +580,6 @@ static long ItcSetTemp(long pc, void *object) { if (drv->h == drv->controlChan) goto skiph; EaseWrite(eab, "A0"); /* heater off */ return __LINE__; case __LINE__: /**********************************/ - drv->remote = 2; snprintf(buf, sizeof buf, "H%d", drv->controlChan); EaseWrite(eab, buf); /* set heater to channel */ return __LINE__; case __LINE__: /**********************************/ @@ -481,7 +642,7 @@ static long ItcSetGas(long pc, void *object) { return __LINE__; case __LINE__: /**********************************/ EaseWrite(eab, "R7"); /* read gas flow */ return __LINE__; case __LINE__: /**********************************/ - drv->gas = OxiGet(eab, 1, NULL, drv->gas); + drv->setGas = OxiGet(eab, 1, NULL, drv->setGas); if (drv->a < 2) goto quit; snprintf(buf, sizeof buf, "A%d", drv->a); EaseWrite(eab, buf); @@ -519,24 +680,28 @@ static long ItcSet(long pc, void *object) { EaseWrite(eab, "C3"); loop: return __LINE__; case __LINE__: /**********************************/ + drv->remote = 2; upd = EaseNextUpdate(drv); - switch (upd) { - case EASE_RUN: FsmCall(ItcSetTemp); goto loop; - case ITC_SETHTR: FsmCall(ItcSetHtr); goto loop; - case ITC_SETGAS: FsmCall(ItcSetGas); goto loop; - case ITC_PIDMODE: - if (drv->pidMode == 1) { - EaseWrite(eab, "L0"); - } else { - EaseWrite(eab, "L1"); - drv->pidMode = 2; - } - goto loop; - case ITC_PROP: OxiSet(eab, "P", drv->prop, 1); goto loop; - case ITC_INTEG: OxiSet(eab, "I", drv->prop, 1); goto loop; - case ITC_DERIV: OxiSet(eab, "D", drv->prop, 1); goto loop; - default: break; + if (eab->syntax != TESLATRON) { + switch (upd) { + case EASE_RUN: FsmCall(ItcSetTemp); goto loop; + case ITC_SETHTR: FsmCall(ItcSetHtr); goto loop; + case ITC_SETGAS: FsmCall(ItcSetGas); goto loop; + case ITC_PIDMODE: + if (drv->pidMode == 1) { + EaseWrite(eab, "L0"); + } else { + EaseWrite(eab, "L1"); + drv->pidMode = 2; + } + goto loop; + case ITC_PROP: OxiSet(eab, "P", drv->prop, 1); goto loop; + case ITC_INTEG: OxiSet(eab, "I", drv->prop, 1); goto loop; + case ITC_DERIV: OxiSet(eab, "D", drv->prop, 1); goto loop; + default: break; + } } + if (eab->syntax == TESLATRON && drv->gasMode > 0) goto quit; EaseWrite(eab, "C0"); return __LINE__; case __LINE__: /**********************************/ drv->remote = 0; @@ -568,10 +733,13 @@ static int ItcInitLc(SConnection *con, int argc, char *argv[], int dynamic) { Itc *drv; drv = EaseMakeDriv(con, &itcClass, argc, argv, dynamic, 7, - ItcParDef, OxiHandler, ItcStart, NULL, ItcRead, + ItcLcParDef, OxiHandler, ItcStart, NULL, ItcRead, ItcSet); if (drv == NULL) return 0; drv->d.b.syntax = TESLATRON; + drv->lastCtrl = 0; + drv->lastTdiff = 0; + drv->lastPdiff = 0; ParPrintf(drv, eValue, "OI Lambda Controller"); return 1; } diff --git a/logreader.c b/logreader.c index 5781473..227202f 100644 --- a/logreader.c +++ b/logreader.c @@ -24,6 +24,7 @@ typedef struct { char slast[256]; char set[256]; int np; + char *none; } Compressor; static char *dir = NULL; @@ -59,10 +60,14 @@ static void OutFloat(Compressor *c, time_t t, float y) { char line[80]; /* printf("out %ld %g\n", t, y); */ - if (y != c->ylast || !c->exact) { + if (y != c->ylast || (!c->exact && t != c->tlast)) { c->ylast = y; if (y == LOGGER_NAN) { - snprintf(line, sizeof line, "%ld\n", (long)(t - c->tlast)); + if (c->none) { + snprintf(line, sizeof line, "%ld %s\n", (long)(t - c->tlast), c->none); + } else { + snprintf(line, sizeof line, "%ld\n", (long)(t - c->tlast)); + } } else { snprintf(line, sizeof line, "%ld %g\n", (long)(t - c->tlast), y); } @@ -163,7 +168,7 @@ static int LogReader(SConnection *pCon, SicsInterp *pSics, void *pData, time_t from, to, step, xs, lastt, now; long lxs; char *p; - int i, iarg0, l, iret, loss, np; + int i, iarg, l, iret, loss, np; int inRange; int yday=0; time_t t, startim; @@ -171,7 +176,7 @@ static int LogReader(SConnection *pCon, SicsInterp *pSics, void *pData, char stim[32], path[256], line[256], lastval[256]; char *lin, *val, *stp; FILE *fil; - Compressor c; + Compressor c={0}; float yy, lasty; CompType type0; DIR *dr; @@ -184,7 +189,7 @@ static int LogReader(SConnection *pCon, SicsInterp *pSics, void *pData, 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); + to = strtol(argv[2], &p, 0); if (p == argv[2]) goto illarg; if (from < ONE_YEAR) { from += now; @@ -192,29 +197,44 @@ static int LogReader(SConnection *pCon, SicsInterp *pSics, void *pData, if (to < ONE_YEAR) { to += now; } - iarg0 = 4; - if (strcasecmp(argv[3],"text") == 0) { /* non-numeric values */ - step = 1; - type0 = TEXT; - np = from - to + 2; - } else if (strcasecmp(argv[3],"np") == 0) { /* max. number of points */ - type0 = NUMERIC; - iarg0 = 5; - np = strtol(argv[4], NULL, 0); - if (to <= from) { + iarg = 3; + while (1) { + if (iarg>=argc) goto illarg; + if (strcasecmp(argv[iarg],"text") == 0) { /* non-numeric values */ + iarg++; step = 1; - } else if (np <= 2) { - step = to - from; + type0 = TEXT; + np = from - to + 2; + break; + } else if (strcasecmp(argv[iarg],"none") == 0) { /* none */ + iarg++; + if (iarg >= argc) goto illarg; + c.none = argv[iarg]; + iarg++; + } else if (strcasecmp(argv[iarg],"np") == 0) { /* max. number of points */ + iarg++; + if (iarg >= argc) goto illarg; + type0 = NUMERIC; + np = strtol(argv[iarg], &p, 0); + if (p == argv[iarg]) goto illarg; + iarg++; + if (to <= from) { + step = 1; + } else if (np <= 2) { + step = to - from; + } else { + step = (to - from) / (np - 2) + 1; + } + break; } else { - step = (to - from) / (np - 2) + 1; + step = strtol(argv[iarg], &p, 0); + if (p == argv[iarg]) goto illarg; + iarg++; + if (step <= 0) step = 1; + type0 = NUMERIC; + np = (from - to) / step + 2; } - } else { - step = strtol(argv[3], NULL, 0); - if (step <= 0) step = 1; - type0 = NUMERIC; - np = (from - to) / step + 2; } - if (p == argv[3]) goto illarg; if (step <= 0) step = 1; snprintf(line, sizeof line, "%ld\n", (long)now); @@ -235,7 +255,7 @@ static int LogReader(SConnection *pCon, SicsInterp *pSics, void *pData, loss = 0; overflow = 0; - for (i=iarg0; i 16) length = 16; for (i=0; icmd[0] != eab->ans[0] || eab->cmd[1] != (eab->ans[1] & 0x7F)) { - iret = EASE_ILL_ANS; - } - if (eab->ans[1] & 0x80) { - iret = EASE_ILL_ANS; + iret = EASE_FAULT; + ModBusDump(eab, eError, "bad answer: %s", eab->ans, l); + } else if (eab->ans[1] & 0x80) { + iret = EASE_FAULT; + if (eab->ans[2] == 2) { + ParPrintf(eab, eError, "ERROR: illegal address"); + } else if (eab->ans[2] == 3) { + ParPrintf(eab, eError, "ERROR: illegal data"); + } else { + ModBusDump(eab, eError, "bad answer: %s", eab->ans, l); + }; } else if (eab->ans[1] == 16) { /* answer from write n words */ l=3; /* finish response */ iret = readRS232TillTerm(eab->ser, eab->ans+5, &l); l+=5; } else if (eab->ans[1] == 3) { /* answer for read n words */ l = eab->ans[2]; /* bytes to read */ + if (l<0 || l >= sizeof(eab->ans)-5) { + l=32; + } iret = readRS232TillTerm(eab->ser, eab->ans+5, &l); l+=5; } else if (eab->ans[1] == 8) { /* loopback info */ @@ -270,7 +295,6 @@ void ModBusPutFloats(EaseBase *eab, int adr, int npar, float val[]) { } /*----------------------------------------------------------------------------*/ void ModBusRequestFloats(EaseBase *eab, int adr, int npar) { - int l; assert(npar <= 14); @@ -281,6 +305,23 @@ void ModBusRequestFloats(EaseBase *eab, int adr, int npar) { ModBusWrite(eab, 6); } /*----------------------------------------------------------------------------*/ +static double ModBus2double(char ieee[4]) { + long t; + /* convert 32 bit values by guessing the type. + will not work when a floating point value is a very low positive number + (below 2^-125) or when a time is divisible by 65536 ms */ + if (ieee[0]) { /* guess its a float */ + return ieee2double(ieee); + } + if (ieee[1] != 0 && ieee[2] == 0 && ieee[3] == 0) { + /* guess its an int, a float 0 will also be returned correctly */ + return word2uint(ieee); + } + /* guess its a time */ + t = word2uint(ieee); + return (t * 65536 + word2uint(ieee+2)) * 0.001; +} +/*----------------------------------------------------------------------------*/ float ModBusGetFloat(EaseBase *eab, int adr) { int startAdr; int i; @@ -295,3 +336,56 @@ float ModBusGetFloat(EaseBase *eab, int adr) { } return ieee2double(eab->ans + 3 + i * 4); } +/*----------------------------------------------------------------------------*/ +void ModBusRequestValue(EaseBase *eab, int adr) { + + eab->cmd[0] = 1; /* device address */ + eab->cmd[1] = 3; /* read n words */ + fadr2word(adr, eab->cmd + 2); + uint2word(2, eab->cmd + 4); + ModBusWrite(eab, 6); +} +/*----------------------------------------------------------------------------*/ +void ModBusPutValue(EaseBase *eab, int adr, int type, float val) { + int l; + + eab->cmd[0] = 1; /* device address */ + eab->cmd[1] = 16; /* write n words */ + if (type == modBusTime+9) { + uint2word(adr, eab->cmd + 2); + eab->cmd[4] = 2; + eab->cmd[5] = 0; + eab->cmd[6] = 1; + eab->cmd[7] = (int)(val) / 256; + eab->cmd[8] = (int)(val) % 256; + ModBusWrite(eab, 9); + return; + } + fadr2word(adr, eab->cmd + 2); + uint2word(2, eab->cmd + 4); + eab->cmd[6] = 4; /* number of bytes */ + if (type == modBusFloat) { + double2ieee(val, eab->cmd+7); + } else if (type == modBusTime) { + long2quad((long)(val * 1000. + 0.5), eab->cmd+7); + } else { + uint2word((int)(val + 0.5), eab->cmd+7); + eab->cmd[9] = 0; + eab->cmd[10] = 0; + } + ModBusWrite(eab, 11); +} +/*----------------------------------------------------------------------------*/ +float ModBusGetValue(EaseBase *eab, int type) { + + if (eab->state != EASE_read) { + return 0.0; + } + if (type == modBusFloat) { + return ieee2double(eab->ans + 3); + } else if (type == modBusTime) { + return quad2long(eab->ans+3) * 0.001; + } else { + return word2uint(eab->ans+3); + } +} diff --git a/modbus.h b/modbus.h index ff89a4a..618f8dc 100644 --- a/modbus.h +++ b/modbus.h @@ -13,9 +13,14 @@ Markus Zolliker, Aug 2005 #define MODBUS_BAD_CRC -3090 +typedef enum {modBusFloat, modBusInt, modBusTime} ModBusType; + int ModBusHandler(void *eab); void ModBusPutFloats(EaseBase *eab, int adr, int npar, float val[]); void ModBusRequestFloats(EaseBase *eab, int adr, int npar); float ModBusGetFloat(EaseBase *eab, int adr); +void ModBusRequestValue(EaseBase *eab, int adr); +float ModBusGetValue(EaseBase *eab, int type); +void ModBusPutValue(EaseBase *eab, int adr, int type, float val); #endif diff --git a/oxinst.c b/oxinst.c index 3b9839d..8e05e7b 100644 --- a/oxinst.c +++ b/oxinst.c @@ -30,6 +30,7 @@ char *OxiCorrect(char *str) { static char buf[32]; char *result = NULL; + if (str[0] == '?') return NULL; for (i=0; i<=24; i++, str++) { chr = *str; if (chr == 0) return result; @@ -39,7 +40,7 @@ char *OxiCorrect(char *str) { } else { chr -= 0x40; } - snprintf(buf, sizeof buf, "%2.2x->%2.2x (%c)", *str, chr, chr); + snprintf(buf, sizeof buf, "%2.2x->%2.2x (%c)", (unsigned char)*str, chr, chr); *str = chr; result = buf; } @@ -69,12 +70,6 @@ int OxiHandler(void *object) { goto quit; } if (iret == 1) { - if (eab->syntax <= -8) { - corr = OxiCorrect(eab->ans); - if (corr) { - ParPrintf(eab, eWarning, "corrected bad response from IGH: %s", corr); - } - } ParPrintf(eab, -2, "ans: %s", eab->ans); if (strcmp(eab->ans, "??ck") == 0) { if (eab->state == EASE_lost) { @@ -96,8 +91,16 @@ int OxiHandler(void *object) { eab->state = EASE_idle; goto quit; } else if (eab->cmd[2] == 'k') { /* ?ck */ - } else if (eab->cmd[0] != eab->ans[0]) { - iret = EASE_ILL_ANS; + } else { + if (eab->syntax <= -8) { + corr = OxiCorrect(eab->ans); + if (corr) { + ParPrintf(eab, eWarning, "corrected bad response from IGH: %s", corr); + } + } + if (eab->cmd[0] != eab->ans[0]) { + iret = EASE_ILL_ANS; + } } } if (iret != 1) { diff --git a/pardef.c b/pardef.c index 2735efe..6082fc1 100644 --- a/pardef.c +++ b/pardef.c @@ -3,9 +3,6 @@ pardef.c my way to define and handle object parameters -What is a bit unusual, is the long list of static variables in this -module. This design allows short argument lists. - Markus Zolliker, March 2005 ---------------------------------------------------------------------------- */ @@ -30,30 +27,38 @@ Markus Zolliker, March 2005 typedef enum { NO_OP, FMT_OP, SET_OP, GET_OP, INIT_OP } ParOp; -static ParData *obj = NULL; -static ParAct act; -static ParAct action; -static char *parName; -static int cmdArgc; -static char **cmdArgs; -static char *thisPar; -static int returnValue; -static SConnection *sicsConnection; -static char *outputFormat; -static int access; -static FILE *saveFile; -static int doit; -static char *listTail; -static char **enumList; -static char *logName; -static time_t now; -static ParInfo *par; -static float floatValue; -static char combiName[80]; -static char *grpFmt; +/* Context holds all the information needed during the pardef function */ +typedef struct Context { + struct Context *next; + ParData *obj; + ParAct act; + ParAct action; + char *parName; + int argc; + char **argv; + char *thisPar; + int returnValue; + SConnection *con; + char *fmt; + int access; + FILE *saveFile; + int doit; + char *listTail; + char **enumList; + char *logName; + time_t now; + ParInfo *par; + float value; + char combiName[80]; + char *grpFmt; + int exact; +} Context; + static char *loggerDir = NULL; static int showTime = 0; -static int exact; +static void *initObj; /* this object is in initialization mode */ + +static Context *ctx=NULL, *freeContexts=NULL; void ParKill(void *object); @@ -116,23 +121,22 @@ int ParPrintf(void *object, int iOut, const char *fmt, ...) { ParData *pobj = object; con = NULL; - if (pobj == NULL) { - if (obj) { - if (sicsConnection) { - con = sicsConnection; - } else { - pobj = obj; - } + if (pobj) { + if (ctx && pobj == ctx->obj && ctx->con) { + con = ctx->con; + } else { + con = SCLoad(&pobj->conn); } + } else if (ctx) { + con = ctx->con; } - if (!con && pobj) { - con = SCLoad(&pobj->conn); - if (!con && iOut < 0) return 0; - } - if (iOut < 0 && (!pobj || -iOut > pobj->verbose)) return 0; - - if (iOut<0) iOut=eStatus; + if (iOut < 0) { + if (!con) return 0; /* no connection, no verbose output */ + if (-iOut > pobj->verbose) return 0; /* check verbosity level */ + iOut = eStatus; + } + va_start(ap, fmt); l = vsnprintf(buf0, sizeof(buf0), fmt, ap); va_end(ap); @@ -159,83 +163,124 @@ int ParPrintf(void *object, int iOut, const char *fmt, ...) { return 1; } /*-------------------------------------------------------------------------*/ -static void ParDo(SConnection *con, ParData *o, ParAct a, char *parName) { - act = a; - action = a; - sicsConnection = con; - if (parName && strcmp(parName, "*") == 0) { - thisPar = ""; +static void ParBegin(void) { + Context *p; + + if (freeContexts) { + p = freeContexts; + freeContexts = p->next; } else { - thisPar = parName; + p = calloc(1,sizeof(*ctx)); + assert(p); } - returnValue = 0; - par = NULL; - grpFmt = NULL; - assert(obj==NULL); - obj = o; - obj->pardef(obj); - obj = NULL; + p->next = ctx; + ctx = p; +} +/*-------------------------------------------------------------------------*/ +static void ParEnd(void) { + Context *p; + + assert(ctx); + p = ctx->next; + ctx->next = freeContexts; + freeContexts = ctx; + ctx = p; +} +/*-------------------------------------------------------------------------*/ +static void ParDo(SConnection *con, ParData *o, ParAct a, char *parName) { + ctx->act = a; + ctx->action = a; + ctx->con = con; + if (parName && strcmp(parName, "*") == 0) { + ctx->thisPar = ""; + } else { + ctx->thisPar = parName; + } + ctx->returnValue = 0; + ctx->par = NULL; + ctx->grpFmt = NULL; + ctx->obj = o; + o->pardef(o); } /*--------------------------------------------------------------------------*/ -char *ParArg2Text(int argc, char *argv[], char *res, int maxsize) { - int i, l; - char *p; +char *ParArg2Str(int argc, char *argv[], char *result, int maxsize) { + int i, argsize; + char *p, *res; - if (res == NULL) { - maxsize = 0; + argsize = 0; + if (result == NULL) { + maxsize = INT_MAX; for (i=0; i maxsize) { + argc = i; + res = NULL; + break; + } } - res=malloc(maxsize); - if (!res) return NULL; } - maxsize--; - *res='\0'; - if (argv[0]) { - strncat(res, argv[0], maxsize); - } - p = res; - for (i=1; i 0) { + *p=' '; + p++; + } + strcpy(p, argv[i]); + p += strlen(argv[i]); } return res; } /*-------------------------------------------------------------------------*/ static int ParSaveAll(void *object, char *name, FILE *fil) { ParData *o = ParCheck(&parClass, object); + int ret; - saveFile = fil; + ParBegin(); + ctx->saveFile = fil; assert(0==strcasecmp(o->name, name)); if (o->creationCmd) { fprintf(fil, "if {[catch { %s }] == 0} {\n", o->creationCmd); } ParDo(0, o, PAR_SAVE, NULL); if (o->creationCmd) { - fprintf(fil, "}\n"); + fprintf(fil, " %s endinit\n}\n", name); } - return returnValue; + ctx->saveFile = NULL; + ret = ctx->returnValue; + ParEnd(); + return ret; +} +/*--------------------------------------------------------------------------*/ +FILE *ParSaveFile(void) { + if (ctx) { + return ctx->saveFile; + } + return NULL; } /*--------------------------------------------------------------------------*/ int ParLog(void *object) { ParData *o = ParCheck(&parClass, object); int next; - now = time(NULL); - next = now - (o->logTime / o->period + 1) * o->period; + ParBegin(); + ctx->now = time(NULL); + next = ctx->now - (o->logTime / o->period + 1) * o->period; if (next >= 0) { showTime = 1; ParDo(0, o, PAR_LOG, NULL); - o->logTime = now; + o->logTime = ctx->now; o->logPending = 0; } + ParEnd(); return next; } /*-------------------------------------------------------------------------*/ @@ -254,24 +299,24 @@ static int ParCallBack(int event, void *eventData, void *userData, } /*----------------------------------------------------------------------------*/ static int ParOutError(SConnection *con, ParData *o) { - switch (returnValue) { + switch (ctx->returnValue) { case AMBIGUOS: - SCPrintf(con, eError, "ERROR: doubly defined parameter %s.%s", o->name, thisPar); + SCPrintf(con, eError, "ERROR: doubly defined parameter %s.%s", o->name, ctx->thisPar); break; case ILLPRIV: - SCPrintf(con, eError, "ERROR: insufficient privilege to change %s.%s", o->name, thisPar); + SCPrintf(con, eError, "ERROR: insufficient privilege for %s.%s", o->name, ctx->thisPar); break; case ILLNUM: - SCPrintf(con, eError, "ERROR: illegal value", o->name, cmdArgs[0]); + SCPrintf(con, eError, "ERROR: illegal value", o->name, ctx->argv[0]); break; case ILLARGC: - SCPrintf(con, eError, "ERROR: illegal number of arguments for %s %s", o->name, thisPar); + SCPrintf(con, eError, "ERROR: illegal number of arguments for %s %s", o->name, ctx->thisPar); break; case BADLOG: - SCPrintf(con, eError, "ERROR: can not create log directory for %s %s", o->name, thisPar); + SCPrintf(con, eError, "ERROR: can not create log directory for %s %s", o->name, ctx->thisPar); break; case UNKPAR: - SCPrintf(con, eError, "ERROR: %s %s is unknown", o->name, thisPar); + SCPrintf(con, eError, "ERROR: %s %s is unknown", o->name, ctx->thisPar); break; /* case BUSY: @@ -279,7 +324,7 @@ static int ParOutError(SConnection *con, ParData *o) { break; */ default: - if (returnValue < 0) { + if (ctx->returnValue < 0) { return -1; } else { return 1; @@ -311,6 +356,16 @@ static void ParListSugar(SConnection *con, ParData *o) { SCWrite(con, buf, eStatus); } /*----------------------------------------------------------------------------*/ +void ParSaveConn(void *object, SConnection *con) { + ParData *o = ParCheck(&parClass, object); + int rights; + + rights = SCGetRights(con); + if (rights >= usMugger && rights <= usUser && con->pSock != NULL) { + SCSave(&o->conn, con); + } +} +/*----------------------------------------------------------------------------*/ static int ParExecute(SConnection *con, SicsInterp *sics, void *object, int argc, char *argv[]) { static char *empty[1]={""}; long id; @@ -318,39 +373,39 @@ static int ParExecute(SConnection *con, SicsInterp *sics, void *object, int argc ParData *o = ParCheck(&parClass, object); char *setArgv[2]; - if (SCGetRights(con) <= usUser) { - SCSave(&o->conn, con); - } - - if (argc>1) thisPar = argv[1]; + ParBegin(); + ParSaveConn(o, con); + + if (argc>1) ctx->thisPar = argv[1]; if (argc >= 2 && 0==strcasecmp(argv[1], "list")) { - cmdArgc = argc - 2; - cmdArgs = argv + 2; + ctx->argc = argc - 2; + ctx->argv = argv + 2; ParDo(con, o, PAR_LIST, NULL); + ParEnd(); return 1; } if (argc == 1) { /* no args */ ParDo(con, o, PAR_SHOW, ""); - if (returnValue == 0) { + if (ctx->returnValue == 0) { SCSendOK(con); - returnValue = 1; + ctx->returnValue = 1; } } else if ((0 == strcasecmp(argv[1], "log") || 0 == strcasecmp(argv[1], "unlog"))) { if (argc < 3) { - returnValue = ILLARGC; - thisPar = argv[1]; + ctx->returnValue = ILLARGC; + ctx->thisPar = argv[1]; } else { - cmdArgc = argc - 3; - cmdArgs = argv + 3; - doit = toupper(argv[1][0]) != 'U'; - exact = 1; + ctx->argc = argc - 3; + ctx->argv = argv + 3; + ctx->doit = toupper(argv[1][0]) != 'U'; + ctx->exact = 1; ParDo(con, o, PAR_LOGSWITCH, argv[2]); } } else if ((0 == strcasecmp(argv[1], "save") || 0 == strcasecmp(argv[1], "unsave"))) { if (argc != 3) { - returnValue = ILLARGC; + ctx->returnValue = ILLARGC; } else { - doit = toupper(argv[1][0]) != 'U'; + ctx->doit = toupper(argv[1][0]) != 'U'; ParDo(con, o, PAR_SAVESWITCH, argv[2]); } SCparChange(con); @@ -362,52 +417,56 @@ static int ParExecute(SConnection *con, SicsInterp *sics, void *object, int argc id = RegisterCallback(o->pCall, SCGetContext(con),VALUECHANGE, ParCallBack, con, NULL); SCRegister(con, pServ->pSics, o->pCall, id); SCSendOK(con); + ParEnd(); return 1; } else if (strcmp(argv[1],"uninterest") == 0) { if (o->pCall) { RemoveCallback2(o->pCall, con); } SCSendOK(con); + ParEnd(); return 1; } else if (strcmp(argv[1],"sugar") == 0) { ParListSugar(con, o); + ParEnd(); return 1; } else { if (strcmp(argv[1], "=") == 0) { - cmdArgc = argc - 2; - cmdArgs = argv + 2; + ctx->argc = argc - 2; + ctx->argv = argv + 2; ParDo(con, o, PAR_SET, ""); logIt = 1; } else { if (argc == 2) { ParDo(con, o, PAR_SHOW, argv[1]); } else { - cmdArgc = argc - 2; - cmdArgs = argv + 2; + ctx->argc = argc - 2; + ctx->argv = argv + 2; ParDo(con, o, PAR_SET, argv[1]); logIt = 1; } /* parameter not found, try to use args as set value for pure object not a very good idea: a typo in a parameter name will change pure value --> use always '=' - if (returnValue == 0) { - cmdArgc = argc - 1; - cmdArgs = argv + 1; - errPar = thisPar; + if (ctx->returnValue == 0) { + ctx->argc = argc - 1; + ctx->argv = argv + 1; + errPar = ctx->thisPar; ParDo(con, o, PAR_SET, ""); - if (returnValue <= 0) { - thisPar = errPar; - returnValue = UNKPAR; + if (ctx->returnValue <= 0) { + ctx->thisPar = errPar; + ctx->returnValue = UNKPAR; } } */ } } - if (returnValue == 0) { - returnValue = UNKPAR; + if (ctx->returnValue == 0) { + ctx->returnValue = UNKPAR; } iret = ParOutError(con, o); if (logIt) ParLog(o); /* log changes */ + ParEnd(); return iret; } /*----------------------------------------------------------------------------*/ @@ -425,12 +484,12 @@ static void KillLogger(ParInfo *par) { int ParSwitchLog(int on, char *name) { char buf[80], alias[80]; - KillLogger(par); + KillLogger(ctx->par); if (on) { - if (par->name[0] == '\0') { - snprintf(buf, sizeof buf, "%s", obj->name); + if (ctx->par->name[0] == '\0') { + snprintf(buf, sizeof buf, "%s", ctx->obj->name); } else { - snprintf(buf, sizeof buf, "%s.%s", obj->name, par->name); + snprintf(buf, sizeof buf, "%s.%s", ctx->obj->name, ctx->par->name); } if (name == NULL) { name = buf; @@ -440,13 +499,13 @@ int ParSwitchLog(int on, char *name) { if (loggerDir == NULL) loggerDir="./"; LoggerSetDir(loggerDir); } - par->log = LoggerMake(name, obj->period, exact); - if (par->log == NULL) { + ctx->par->log = LoggerMake(name, ctx->obj->period, ctx->exact); + if (ctx->par->log == NULL) { return BADLOG; } - if (par->sugarStatus == 0 && name != buf && strcmp(name,buf) != 0) { - snprintf(alias, sizeof alias, "%s %s", obj->name, par->name); - par->sugarStatus = SugarMake(name, alias); + if (ctx->par->sugarStatus == 0 && name != buf && strcmp(name,buf) != 0) { + snprintf(alias, sizeof alias, "%s %s", ctx->obj->name, ctx->par->name); + ctx->par->sugarStatus = SugarMake(name, alias); } } return 1; @@ -455,26 +514,26 @@ int ParSwitchLog(int on, char *name) { void ParFind(void) { ParInfo *p, **last, **endList; - assert(obj); - if (par == NULL) { - last = &obj->infoList; - par = *last; + assert(ctx); + if (ctx->par == NULL) { + last = &ctx->obj->infoList; + ctx->par = *last; } else { - last = &par->next; + last = &ctx->par->next; } - if (par) { + if (ctx->par) { /* start search after the actual parameter */ - p = par->next; - while (p != NULL && 0 != strcmp(p->name, parName)) { + p = ctx->par->next; + while (p != NULL && 0 != strcmp(p->name, ctx->parName)) { p = p->next; } } else { p = NULL; } if (p == NULL) { /* not found: search again from list head */ - p = obj->infoList; - while (p != NULL && 0 != strcmp(p->name, parName)) { - if (p == par) { + p = ctx->obj->infoList; + while (p != NULL && 0 != strcmp(p->name, ctx->parName)) { + if (p == ctx->par) { p = NULL; break; } @@ -483,7 +542,7 @@ void ParFind(void) { if (p == NULL) { p = calloc(1, sizeof *p); if (p == NULL) return; - p->name = parName; + p->name = ctx->parName; p->log = NULL; p->saveIt = 0; p->saveLog = 0; @@ -492,7 +551,7 @@ void ParFind(void) { *last = p; } } - par = p; + ctx->par = p; } /*--------------------------------------------------------------------------*/ long ParText2Int(char *text) { @@ -501,9 +560,9 @@ long ParText2Int(char *text) { if (strcasecmp(text, "undefined") == 0) { return PAR_LNAN; } - if (enumList) { - while (enumList[num] != NULL) { - if (strcasecmp(enumList[num],text) == 0) { + if (ctx->enumList) { + while (ctx->enumList[num] != NULL) { + if (strcasecmp(ctx->enumList[num],text) == 0) { return num; } num++; @@ -519,73 +578,73 @@ char *ParInt2Text(int num) { if (num == PAR_LNAN) { return "undefined"; } - if (! enumList) return NULL; + if (! ctx->enumList) return NULL; for (i = 0; i <= num; i++) { - if (enumList[i] == NULL) { + if (ctx->enumList[i] == NULL) { return NULL; } } - return enumList[num]; + return ctx->enumList[num]; } /*----------------------------------------------------------------------------*/ void ParGroup(char *groupFmt) { - grpFmt = groupFmt; + ctx->grpFmt = groupFmt; } /*----------------------------------------------------------------------------*/ void ParName(char *name) { - if (grpFmt && *grpFmt) { - snprintf(combiName, sizeof combiName, grpFmt, name); - parName = combiName; + if (ctx->grpFmt && *ctx->grpFmt) { + snprintf(ctx->combiName, sizeof ctx->combiName, ctx->grpFmt, name); + ctx->parName = ctx->combiName; } else { - parName = name; + ctx->parName = name; } ParFind(); - outputFormat = NULL; - action = act; + ctx->fmt = NULL; + ctx->action = ctx->act; - assert(obj); - switch (act) { + assert(ctx); + switch (ctx->act) { case PAR_SHOW: case PAR_SET: - enumList = NULL; - if (0==strcasecmp(name, thisPar)) { - access = -1; + ctx->enumList = NULL; + if (0==strcasecmp(name, ctx->thisPar)) { + ctx->access = -1; } else { - action = PAR_NOOP; + ctx->action = PAR_NOOP; } return; case PAR_LIST: - enumList = NULL; - listTail = NULL; - doit = -1; + ctx->enumList = NULL; + ctx->listTail = NULL; + ctx->doit = -1; return; case PAR_LOG: return; case PAR_LOGSWITCH: - if (0==strcasecmp(name, thisPar)) { - access = -1; + if (0==strcasecmp(name, ctx->thisPar)) { + ctx->access = -1; } else { - action = PAR_NOOP; + ctx->action = PAR_NOOP; } return; case PAR_SAVESWITCH: - if (0==strcasecmp(name, thisPar)) { - access = -1; + if (0==strcasecmp(name, ctx->thisPar)) { + ctx->access = -1; } else { - action = PAR_NOOP; + ctx->action = PAR_NOOP; } return; case PAR_INIT: /* for save: use -1 as default value */ - access = -1; - doit = -1; - logName = ""; /* log by default */ - exact = 1; /* exact by default */ + ctx->access = -1; + ctx->doit = -1; + ctx->logName = ""; /* log by default */ + ctx->exact = 1; /* exact by default */ return; case PAR_GET: - if (0 != strcasecmp(name, thisPar)) { - action = PAR_NOOP; + if (0 != strcasecmp(name, ctx->thisPar)) { + ctx->action = PAR_NOOP; } return; case PAR_SAVE: @@ -596,7 +655,12 @@ void ParName(char *name) { } /*----------------------------------------------------------------------------*/ static int RestoreMode(void) { - return (pServ->pReader && (SCGetRights(sicsConnection) <= usInternal)); + assert(ctx); + if (initObj == ctx->obj) { + return 1; + } + initObj = NULL; + return 0; } /*----------------------------------------------------------------------------*/ ParOp ParWhat(int numeric) { @@ -606,137 +670,137 @@ ParOp ParWhat(int numeric) { ParOp op; int on; - assert(obj); - switch (action) { + assert(ctx); + switch (ctx->action) { case PAR_LIST: - if (doit < 0) { - if (listTail && cmdArgc == 0) { - doit = 1; + if (ctx->doit < 0) { + if (ctx->listTail && ctx->argc == 0) { + ctx->doit = 1; } else { - doit = 0; + ctx->doit = 0; } } - if (doit || (cmdArgc > 0 && 0 == strcasecmp(cmdArgs[0], "all"))) return FMT_OP; + if (ctx->doit || (ctx->argc > 0 && 0 == strcasecmp(ctx->argv[0], "all"))) return FMT_OP; break; case PAR_LOG: - if (par && par->log) { + if (ctx->par && ctx->par->log) { return FMT_OP; } break; case PAR_LOGSWITCH: - if (cmdArgc > 1) { - returnValue = ILLARGC; + if (ctx->argc > 1) { + ctx->returnValue = ILLARGC; break; } - if (returnValue) { - returnValue = AMBIGUOS; + if (ctx->returnValue) { + ctx->returnValue = AMBIGUOS; break; } - if (par) { - returnValue = 1; - if (cmdArgc > 0) { - lname = cmdArgs[0]; + if (ctx->par) { + ctx->returnValue = 1; + if (ctx->argc > 0) { + lname = ctx->argv[0]; } else { lname = NULL; } - par->saveLog = 1; - ParSwitchLog(doit, lname); - LoggerSetNumeric(par->log, numeric); - SCparChange(sicsConnection); + ctx->par->saveLog = 1; + ParSwitchLog(ctx->doit, lname); + LoggerSetNumeric(ctx->par->log, numeric); + SCparChange(ctx->con); return NO_OP; } break; case PAR_SAVESWITCH: - if (cmdArgc > 1) { - returnValue = ILLARGC; + if (ctx->argc > 1) { + ctx->returnValue = ILLARGC; break; } - if (returnValue) { - returnValue = AMBIGUOS; + if (ctx->returnValue) { + ctx->returnValue = AMBIGUOS; break; } - if (par) { - returnValue = 1; - par->saveIt = doit; + if (ctx->par) { + ctx->returnValue = 1; + ctx->par->saveIt = ctx->doit; return NO_OP; } break; case PAR_INIT: if (! RestoreMode()) { - if (access < 0) { - access = usInternal; + if (ctx->access < 0) { + ctx->access = usInternal; } - if (doit < 0) { - if (access == usInternal) { - doit = 0; + if (ctx->doit < 0) { + if (ctx->access == usInternal) { + ctx->doit = 0; } else { - doit = 1; + ctx->doit = 1; } } - if (doit) { /* set save flag */ - if (par) { - par->saveIt = 1; + if (ctx->doit) { /* set save flag */ + if (ctx->par) { + ctx->par->saveIt = 1; } } } - if (logName) { /* set log */ - if (par) { - if (logName[0] != '\0') { - lname = logName; + if (ctx->logName) { /* set log */ + if (ctx->par) { + if (ctx->logName[0] != '\0') { + lname = ctx->logName; } else { lname = NULL; } ParSwitchLog(1, lname); - LoggerSetNumeric(par->log, numeric); + LoggerSetNumeric(ctx->par->log, numeric); } } return INIT_OP; case PAR_SHOW: - if (returnValue) { - returnValue = AMBIGUOS; + if (ctx->returnValue) { + ctx->returnValue = AMBIGUOS; break; } - returnValue = 1; + ctx->returnValue = 1; return FMT_OP; case PAR_SET: - if (returnValue) { - returnValue = AMBIGUOS; + if (ctx->returnValue) { + ctx->returnValue = AMBIGUOS; break; } - if (access < 0) { - access = usInternal; + if (ctx->access < 0) { + ctx->access = usInternal; } - if (access < SCGetRights(sicsConnection)) { - returnValue = ILLPRIV; + if (ctx->access < SCGetRights(ctx->con) && !RestoreMode()) { + ctx->returnValue = ILLPRIV; break; } - returnValue = 1; + ctx->returnValue = 1; return SET_OP; case PAR_SAVE: - if (parName[0] == '\0') { - parName = "*"; + if (ctx->parName[0] == '\0') { + ctx->parName = "*"; } - if (par->saveLog) { - if (par->log) { - fprintf(saveFile, " %s log %s %s\n", obj->name, parName, LoggerName(par->log)); + if (ctx->par->saveLog) { + if (ctx->par->log) { + fprintf(ctx->saveFile, " %s log %s %s\n", ctx->obj->name, ctx->parName, LoggerName(ctx->par->log)); } else { - fprintf(saveFile, " %s unlog %s\n", obj->name, parName); + fprintf(ctx->saveFile, " %s unlog %s\n", ctx->obj->name, ctx->parName); } } - if (par && par->saveIt) { + if (ctx->par && ctx->par->saveIt) { return FMT_OP; } break; case PAR_GET: - if (returnValue) { - returnValue = AMBIGUOS; + if (ctx->returnValue) { + ctx->returnValue = AMBIGUOS; break; } return GET_OP; default: return NO_OP; } - action = PAR_NOOP; /* for the result of ParActionIs */ + ctx->action = PAR_NOOP; /* for the result of ParActionIs */ return NO_OP; } /*----------------------------------------------------------------------------*/ @@ -750,23 +814,23 @@ void ParOut(char *buf) { char *saved, *logged; time_t last; - assert(obj); - assert(outputFormat==NULL); - switch (action) { + assert(ctx); + assert(ctx->fmt==NULL); + switch (ctx->action) { case PAR_LIST: - if (par->log) { - snprintf(buffer, sizeof buffer, "%s", LoggerName(par->log)); + if (ctx->par->log) { + snprintf(buffer, sizeof buffer, "%s", LoggerName(ctx->par->log)); } else { - if (parName[0] != '\0') { - snprintf(buffer, sizeof buffer, "%s.%s", obj->name, parName); + if (ctx->parName[0] != '\0') { + snprintf(buffer, sizeof buffer, "%s.%s", ctx->obj->name, ctx->parName); } else { - snprintf(buffer, sizeof buffer, "%s", obj->name); + snprintf(buffer, sizeof buffer, "%s", ctx->obj->name); } } - if (enumList) { + if (ctx->enumList) { i = strtol(buf, &endp, 0); if (endp != buf) { - listTail = ParInt2Text(i); /* overwrite listTail */ + ctx->listTail = ParInt2Text(i); /* overwrite ctx->listTail */ } } p = buf; @@ -777,7 +841,7 @@ void ParOut(char *buf) { j = i; while (p[i] >= '0' && p[i] <='9') i++; l = strlen(p); - ln = strlen(buffer) - strlen(obj->name); + ln = strlen(buffer) - strlen(ctx->obj->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 */ lp = strlen(p); @@ -789,122 +853,122 @@ void ParOut(char *buf) { m = 23 - l - ln; } if (m < 1) m = 1; - if (listTail == NULL) listTail = ""; - m += strlen(listTail); + if (ctx->listTail == NULL) ctx->listTail = ""; + m += strlen(ctx->listTail); if (l <= 0) l = 1; saved = ""; logged = ""; - if (cmdArgc > 0 && 0 == strcasecmp(cmdArgs[0], "all")) { - if (!par->log) { + if (ctx->argc > 0 && 0 == strcasecmp(ctx->argv[0], "all")) { + if (!ctx->par->log) { logged = " (not logged)"; } - if (par->saveIt) { + if (ctx->par->saveIt) { saved = " (saved)"; } } - ParPrintf(NULL, eStatus, "%s %*s%*s%s%s", buffer, l, p, m, listTail, logged, saved); + ParPrintf(NULL, eWarning, "%s %*s%*s%s%s", buffer, l, p, m, ctx->listTail, logged, saved); break; case PAR_SHOW: - if (parName[0]) { p=" "; } else { p=""; } - ParPrintf(NULL, eValue, "%s%s%s = %s", obj->name, p, parName, buf); + if (ctx->parName[0]) { p=" "; } else { p=""; } + ParPrintf(NULL, eValue, "%s%s%s = %s", ctx->obj->name, p, ctx->parName, buf); break; case PAR_SET: - if (parName[0]) { p=" "; } else { p=""; } - ParPrintf(NULL, eValue, "%s%s%s = %s", obj->name, p, parName, buf); - if (!obj->logPending) { - obj->logPending = 1; - TaskRegister(pServ->pTasker, ParLog, NULL, NULL, obj, 0); /* schedule ParLog */ + if (ctx->parName[0]) { p=" "; } else { p=""; } + ParPrintf(NULL, eValue, "%s%s%s = %s", ctx->obj->name, p, ctx->parName, buf); + if (!ctx->obj->logPending) { + ctx->obj->logPending = 1; + TaskRegister(pServ->pTasker, ParLog, NULL, NULL, ctx->obj, 0); /* schedule ParLog */ } break; case PAR_LOG: - if (par->log) { - if (par->state == PAR_NOW_READY) { - par->state = PAR_NOT_READY; - last = LoggerLastTime(par->log); - if (last != 0 && now - obj->period > last) { - LoggerWrite(par->log, now - obj->period, obj->period, buf); + if (ctx->par->log) { + if (ctx->par->state == PAR_NOW_READY) { + ctx->par->state = PAR_NOT_READY; + last = LoggerLastTime(ctx->par->log); + if (last != 0 && ctx->now - ctx->obj->period > last) { + LoggerWrite(ctx->par->log, ctx->now - ctx->obj->period, ctx->obj->period, buf); } - } else if (par->state != PAR_ALWAYS_READY) { + } else if (ctx->par->state != PAR_ALWAYS_READY) { break; } - if (showTime && obj->pCall) { - snprintf(buffer, sizeof buffer, "