- modified and improved various env. drivers

- implemented string array object
This commit is contained in:
zolliker
2006-06-20 13:29:32 +00:00
parent 8b12033cb2
commit c1bbdb935e
19 changed files with 1495 additions and 499 deletions

281
arrobj.c Normal file
View File

@ -0,0 +1,281 @@
/*---------------------------------------------------------------------------
arrobj.c
a array object based on pardef
Markus Zolliker, Feb 2006
----------------------------------------------------------------------------
*/
#include <stdio.h>
#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 <name> [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);
}

73
ease.c
View File

@ -16,6 +16,7 @@ Markus Zolliker, March 2005
#include <ctype.h>
#include <math.h>
#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;
}

1
ease.h
View File

@ -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);

View File

@ -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 <name> [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;
}
/*----------------------------------------------------------------------------*/

16
fsm.c
View File

@ -10,6 +10,7 @@ M. Zolliker, Aug 2004
#include <assert.h>
#include <time.h>
#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("<fsm>");
}
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) {

View File

@ -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__: /**********************************/

View File

@ -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);
}
/*----------------------------------------------------------------------------*/

252
itcdriv.c
View File

@ -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;
}

View File

@ -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<argc; i++) {
for (i=iarg; i<argc; i++) {
startim = from;
t = 0;
lastt = 0;

View File

@ -8,7 +8,7 @@
OBJ=psi.o buffer.o ruli.o dmc.o nxsans.o nextrics.o sps.o pimotor.o \
pipiezo.o sanswave.o faverage.o fowrite.o amor2t.o nxamor.o \
amorstat.o tasinit.o tasdriveo.o tasutil.o tasscan.o swmotor.o \
amorstat.o tasinit.o tasdrive.o tasutil.o tasscan.o swmotor.o \
polterwrite.o ecb.o frame.o el734driv.o el734dc.o ecbdriv.o \
ecbcounter.o el737driv.o sinqhmdriv.o tdchm.o velodorn.o \
velodornier.o docho.o sanscook.o tecsdriv.o itc4driv.o itc4.o\
@ -19,8 +19,8 @@ OBJ=psi.o buffer.o ruli.o dmc.o nxsans.o nextrics.o sps.o pimotor.o \
$(MZOBJ) amordrive.o amorset.o tcpdornier.o sinqhttp.o\
dgrambroadcast.o sinq.o tabledrive.o tcpdocho.o
MZOBJ=fsm.o logger.o sugar.o pardef.o ease.o strobj.o oxinst.o \
ipsdriv.o ilmdriv.o itcdriv.o ighdriv.o euro2kdriv.o modbus.o
MZOBJ=fsm.o logger.o sugar.o pardef.o ease.o strobj.o oxinst.o logreader.o \
ipsdriv.o ilmdriv.o itcdriv.o ighdriv.o euro2kdriv.o modbus.o arrobj.o
libpsi.a: $(OBJ)
rm -f libpsi.a

106
modbus.c
View File

@ -90,6 +90,21 @@ static unsigned int word2uint(char word[2]) {
return uword[0]*256 + uword[1];
}
/*----------------------------------------------------------------------------*/
static long quad2long(char word[4]) {
unsigned char *uword;
uword = (void *)word;
return ((uword[0]*256 + uword[1])*256 + uword[2])*256 + uword[3];
}
/*----------------------------------------------------------------------------*/
static void long2quad(long val, char word[4]) {
unsigned char *uword;
uword = (void *)word;
uword[3] = val % 256; val = val/256;
uword[2] = val % 256; val = val/256;
uword[1] = val % 256; val = val/256;
uword[0] = val;
}
/*----------------------------------------------------------------------------*/
static void fadr2word(int adr, char word[2]) {
unsigned char *uword;
uword = (void *)word;
@ -140,7 +155,7 @@ void ModBusDump(EaseBase *eab, int iout, char *fmt, char *buffer, int length) {
if (length > 16) length = 16;
for (i=0; i<length; i++) {
snprintf(buf+i*3, 4, " %2.2X", (unsigned int)buffer[i]);
snprintf(buf+i*3, 4, " %2.2X", (unsigned char)buffer[i]);
}
buf[i*3]='\0';
ParPrintf(eab, iout, fmt, buf);
@ -188,16 +203,26 @@ int ModBusHandler(void *object) {
}
if (iret == 1) {
if (eab->cmd[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);
}
}

View File

@ -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

View File

@ -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) {

784
pardef.c

File diff suppressed because it is too large Load Diff

View File

@ -194,6 +194,7 @@ typedef struct ParData {
called inside pardef, when the object is not in the argument
list */
void ParLogReady(ReadyState state); /* set ready state for log */
FILE *ParSaveFile(void); /* get the save-file name when action is PAR_SAVE */
/*
functions to be used outside pardef:
@ -227,8 +228,14 @@ typedef struct ParData {
- PAR_SAVE after a parameter change on any SICS command
- PAR_KILL on RemoveCommand */
char *ParArg2Text(int argc, char *argv[], char *res, int maxsize);
char *ParArg2Str(int argc, char *argv[], char *res, int maxsize);
/* convert args to text. if res==NULL, the result is
allocated and maxsize is ignored */
void ParSaveConn(void *object, SConnection *con);
/* save connection for further use */
void ParInitPar(void *object, char *name);
/* inititalize dynamic parameter */
#endif

4
psi.c
View File

@ -68,12 +68,14 @@ void SiteInit(void) {
/* insert here initialization routines ... */
INIT(IlmStartup);
INIT(IlmStartup);
INIT(IpsStartup);
INIT(ItcStartup);
INIT(IghStartup);
INIT(Euro2kStartup);
INIT(StrObjStartup);
INIT(LogReaderInit);
INIT(ArrayObjStartup);
}

View File

@ -9,6 +9,7 @@ Markus Zolliker, March 2005
#include <stdio.h>
#include "sics.h"
#include "splitter.h"
#include "pardef.h"
#include "initializer.h"
@ -34,7 +35,7 @@ static int StrObjInit(SConnection *con, int argc, char *argv[], int dynamic) {
char *creationCmd = NULL;
if (dynamic) {
creationCmd = ParArg2Text(argc, argv, NULL, 0);
creationCmd = Arg2Tcl(argc, argv, NULL, 0);
}
so = ParMake(con, argv[1], &strObjClass, StrObjParDef, creationCmd);
if (so) {

24
sugar.c
View File

@ -9,6 +9,7 @@ Markus Zolliker, March 2005
#include <stdio.h>
#include "sics.h"
#include "splitter.h"
#include "sugar.h"
#include "pardef.h"
@ -20,12 +21,25 @@ typedef struct {
int SugarCommand(SConnection *con, SicsInterp *sics, void *data, int argc, char *argv[]) {
Sugar *sugar = data;
char value[256], buf[256];
char *cmd;
char **args;
char buf[256];
int i;
assert(sugar);
ParArg2Text(argc-1, argv+1, value, sizeof value);
snprintf(buf, sizeof buf, "%s %s", sugar->alias, value);
return SCInvoke(con, sics, buf);
if (argc < 1) return 0;
args = calloc(argc, sizeof(char *));
if (!args) return 0;
args[0] = sugar->alias;
for (i=1; i<argc; i++) {
args[i] = argv[i];
}
cmd = Arg2Tcl(argc+1, args, buf, sizeof(buf));
free(args);
if (!cmd) return 0;
i = SCInvoke(con, sics, cmd);
if (cmd != buf) free(cmd);
return i;
}
void SugarDelete(void *data) {

View File

@ -72,6 +72,16 @@
char server[256];
} TecsDriv, *pTecsDriv;
typedef struct {
char *buffer;
int size;
} Buffer;
void outFunc(char *str, void *arg) {
Buffer *buffer=arg;
str_ncat(buffer->buffer, str, buffer->size);
str_ncat(buffer->buffer, "\n", buffer->size);
}
/*-------------------------------------------------------------------------*/
@ -84,7 +94,8 @@
pEVDriver pD;
pTecsDriv pMe;
float fVal;
Buffer buffer;
self = (pEVControl)pData;
assert(self);
assert(pCon);
@ -108,6 +119,14 @@
self->fTarget = atof(result);
}
return EVControlWrapper(pCon,pSics,pData,argc,argv);
} else if (0==strcmp(pBueffel," get ")) {
buffer.buffer = result;
buffer.size = sizeof result;
result[0]='\0';
iRet = TeccGetMult(pMe->pData,argc-2,argv+2,outFunc,&buffer);
if (iRet<0) goto Error;
SCWrite(pCon,result,eValue);
return 1;
} else if (0==strcmp(pBueffel," list ")) {
iRet=CocGet(pMe->pData,"set",result); /* get parameter */
if (iRet<0) goto Error;
@ -158,7 +177,7 @@
}
return EVControlWrapper(pCon,pSics,pData,argc,argv);
} else if (NULL!=strstr(
" log send tolerance access errorhandler interrupt interest safevalue currentvalue maxwait settle errorscript driver "
" log send tolerance access errorhandler interrupt interest safevalue currentvalue maxwait settle errorscript runscript driver "
, pBueffel)) {
/* forward to standard handler */
return EVControlWrapper(pCon,pSics,pData,argc,argv);