- modified and improved various env. drivers
- implemented string array object
This commit is contained in:
281
arrobj.c
Normal file
281
arrobj.c
Normal 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
73
ease.c
@ -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
1
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);
|
||||
|
280
euro2kdriv.c
280
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 <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
16
fsm.c
@ -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) {
|
||||
|
31
ighdriv.c
31
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__: /**********************************/
|
||||
|
@ -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);
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
248
itcdriv.c
248
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) {
|
||||
@ -322,12 +421,79 @@ static long ItcRead(long pc, void *object) {
|
||||
return __LINE__; case __LINE__: /**********************************/
|
||||
skip0:
|
||||
|
||||
if (!drv->remote) goto skiprmt;
|
||||
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:
|
||||
|
||||
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__: /**********************************/
|
||||
@ -361,6 +522,7 @@ static long ItcRead(long pc, void *object) {
|
||||
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;
|
||||
}
|
||||
|
70
logreader.c
70
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<argc; i++) {
|
||||
for (i=iarg; i<argc; i++) {
|
||||
startim = from;
|
||||
t = 0;
|
||||
lastt = 0;
|
||||
|
6
make_gen
6
make_gen
@ -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
106
modbus.c
@ -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);
|
||||
}
|
||||
}
|
||||
|
5
modbus.h
5
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
|
||||
|
21
oxinst.c
21
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) {
|
||||
|
9
pardef.h
9
pardef.h
@ -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
4
psi.c
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
3
strobj.c
3
strobj.c
@ -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) {
|
||||
|
22
sugar.c
22
sugar.c
@ -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) {
|
||||
|
21
tecsdriv.c
21
tecsdriv.c
@ -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,6 +94,7 @@
|
||||
pEVDriver pD;
|
||||
pTecsDriv pMe;
|
||||
float fVal;
|
||||
Buffer buffer;
|
||||
|
||||
self = (pEVControl)pData;
|
||||
assert(self);
|
||||
@ -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);
|
||||
|
Reference in New Issue
Block a user