From bc2c9e5a3ebbfab067693a36358179e12f054606 Mon Sep 17 00:00:00 2001 From: zolliker Date: Thu, 2 Sep 2010 11:41:31 +0000 Subject: [PATCH] - added general binary scriptcontext protocoll - improved some drivers --- arrobj.c | 4 +- binprot.c | 477 +++++++++++++++++++++++++++++++++++++++++++++++++++ ease.c | 4 + euro2kdriv.c | 2 +- ipsdriv.c | 10 +- lsc370driv.c | 41 +++-- make_gen | 2 +- modbus.c | 2 +- pardef.c | 12 +- psi.c | 1 + 10 files changed, 528 insertions(+), 27 deletions(-) create mode 100644 binprot.c diff --git a/arrobj.c b/arrobj.c index 5b2c657..7b6f3ba 100644 --- a/arrobj.c +++ b/arrobj.c @@ -267,10 +267,10 @@ static void ArrayObjParDef(void *object) v = ""; } if (strchr(v, '\n') != NULL) { - fprintf(saveFile, " %s makeitem %s {%s} \"%s\"\n", arr->p.name, + fprintf(saveFile, "%s makeitem %s {%s} \"%s\"\n", arr->p.name, item->name, v, u); } else { - fprintf(saveFile, " %s makeitem %s \"%s\" \"%s\"\n", arr->p.name, + fprintf(saveFile, "%s makeitem %s \"%s\" \"%s\"\n", arr->p.name, item->name, v, u); } if (saveObjects) { diff --git a/binprot.c b/binprot.c new file mode 100644 index 0000000..04965a9 --- /dev/null +++ b/binprot.c @@ -0,0 +1,477 @@ +#include +#include +#include "ascon.h" +#include "ascon.i" +#include "dynstring.h" + +/* + * this is a (scriptcontext) general binary protocol driver + * + * Markus Zolliker Aug 2010 + * + * conversion to and from binary + * + * Syntax: + * space separated items, the command first, a slash and then the read format + * + * commandItem ... / formatItem ... + * + * where a commandItem one of the following + * + * a number converted according to the choosen format, i1 is default + * int changing the format to byte integers + * hex changing the format to hexadecimal (1 byte at a time) + * float changing the format to 4 byte ieee float + * crc send crc + * + * and formatItem is one of the follwing + * + * skip skip one byte + * skip skip bytes + * code returned function code, when bit7 is set, the response is + * recogized as an error message and the response is dumped + * the result + * int convert bytes to integer (most significant byte first) + * and append the (decimal coded) number to the result + * if is omitted, = 1 is assumed + * hex convert 1 byte to hexadecimal coded integer + * and append it to the response + * float convert 4 bytes from ieee float + * and append the number to the response + * crc check crc (if wrong, "badCRC" is added to the response) + * + * multiple items in the response are space separated + * + * Usage example: Modbus read (float) + * command: address 250, function 3, start-address 8, size 2, crc + * response: address, function, byte-count, float, crc + * + * sct send 250 3 int2 10 2 crc / skip code skip float crc + */ + +typedef enum {intType, hexType, floatType, + skipType, codeType, crcType, dumpType, errorType} BinDataType; +// dumpType, errorType must be the last items + +typedef struct { + char *crcAlgorithm; + pDynString inp; + char *nextFmt; + pDynString result; + int expectedChars; + BinDataType type; + long iValue; + int dumpFrom; +} BinPrivate; + +/*-------------------------------------------------------------------------*/ +static void double2ieee(double input, char ieee[4]) +{ + +/* convert double to IEEE 32 bit floating number (denormalized numbers are considered as zero) */ + + long mantissa; + int exponent; + + if (input == 0) { + ieee[0] = 0; + ieee[1] = 0; + ieee[2] = 0; + ieee[3] = 0; + } else { + mantissa = 0x1000000 * (frexp(fabs(input), &exponent)); + exponent = exponent - 1 + 127; + if (exponent < 0) { + exponent = 0; + } else if (exponent > 0xFE) { + exponent = 0xFE; + } + if (input < 0) { + ieee[0] = 0x80 | (exponent >> 1); + } else { + ieee[0] = exponent >> 1; + } + ieee[1] = (exponent & 1) << 7 | ((mantissa & 0x7F0000) >> 16); + ieee[2] = (mantissa & 0xFF00) >> 8; + ieee[3] = mantissa & 0xFF; + } + return; +} + +/*-------------------------------------------------------------------------*/ +static double ieee2double(char ieee[4]) +{ + +/* IEEE 32 bit floating number to double (denormalized numbers are considered as zero) */ + + long mantissa; + double output; + int exponent; + + mantissa = ((ieee[1] << 16) & 0x7FFFFF) + | ((ieee[2] << 8) & 0xFF00) + | ((ieee[3]) & 0xFF); + + exponent = (ieee[0] & 0x7F) * 2 + ((ieee[1] >> 7) & 1); /* raw exponent */ + if (exponent == 0 && mantissa == 0) { + return 0.0; + } + output = ldexp(mantissa, -23) + 1.0; + if (ieee[0] & 0x80) { + output = -output; + } + return output * ldexp(1, exponent - 127); +} + +/*----------------------------------------------------------------------------*/ +static int calc_crc(char *inp, int inpLen) +{ + +/* CRC runs cyclic Redundancy Check Algorithm on input inp */ +/* Returns value of 16 bit CRC after completion and */ +/* always adds 2 crc bytes to message */ +/* returns 0 if incoming message has correct CRC */ + + unsigned int crc = 0xffff; + unsigned int next; + int carry; + int n; + + while (inpLen--) { + next = *(unsigned char *) inp; + crc ^= next; + for (n = 0; n < 8; n++) { + carry = crc & 1; + crc >>= 1; + if (carry) { + crc ^= 0xA001; + } + } + inp++; + } + return crc; +} + +/*----------------------------------------------------------------------------*/ +int BinReadItem(Ascon *a) { + BinPrivate *p = a->private; + char item[32]; + int valen; + int size; + + if (sscanf(p->nextFmt, "%30s%n", item, &valen) <= 0) { + if (p->type < dumpType) { + p->dumpFrom = GetDynStringLength(a->rdBuffer); + p->type= dumpType; + } + p->expectedChars = 999; + return 0; + } + + if (strcasecmp(item, "crc") == 0) { + p->type = crcType; + p->expectedChars = 2; + p->nextFmt += valen; + return 1; + } else if (strncasecmp(item, "int", 3) == 0) { + size = 1; + sscanf(item + 3, "%d", &size); + p->expectedChars = size; + p->type = intType; + p->iValue = 0; + } else if (strcasecmp(item, "float") == 0) { + p->expectedChars = 4; + p->type = floatType; + } else if (strcasecmp(item, "hex") == 0) { + p->expectedChars = 1; + p->type = hexType; + } else if (strcasecmp(item, "code") == 0) { + p->type = codeType; + } else if (strncasecmp(item, "skip", 4) == 0) { + size = 1; + sscanf(item + 4, "%d", &size); + p->expectedChars = size; + p->type = skipType; + } else { + return -1; + } + p->nextFmt += valen; + return 1; +} + + +/*----------------------------------------------------------------------------*/ +void BinError(Ascon *a, char *text) { + BinPrivate *p = a->private; + + p->type= errorType; + p->dumpFrom = 0; + p->expectedChars = 1; + DynStringCopy(a->errmsg, "BINERR: "); + DynStringConcat(a->errmsg, text); + a->state = AsconFailed; +} + +/*----------------------------------------------------------------------------*/ +int BinHandler(Ascon *a) { + int res; + char *str; + int len; + int i, l, pos; + unsigned int crc; + pDynString dyn; + char item[32]; + char data[8]; + int size; + int valen; + BinDataType type; + long iValue; + double fValue; + BinPrivate *p = a->private; + + switch (a->state) { + case AsconWriteStart: + /* exchange buffers */ + dyn = p->inp; + p->inp = a->wrBuffer; + a->wrBuffer = dyn; + DynStringClear(dyn); + str = GetCharArray(p->inp); + len = GetDynStringLength(p->inp); + l = 0; + size = 1; + type = intType; + for (pos = 0; pos < len; ) { + if (sscanf(str + pos, "%30s%n", item, &valen) <= 0) { + BinError(a, "missing '/'"); + return 1; + } + pos += valen; + if (strcasecmp(item, "/") == 0) { + break; + } else if (strcasecmp(item, "crc") == 0) { + if (strcasecmp(p->crcAlgorithm, "keller-crc") == 0) { + crc = calc_crc(GetCharArray(dyn), l); + DynStringConcatChar(dyn, crc / 256); + DynStringConcatChar(dyn, crc % 256); + } else { /* modbus-crc */ + crc = calc_crc(GetCharArray(dyn), l); + DynStringConcatChar(dyn, crc / 256); + DynStringConcatChar(dyn, crc % 256); + } + } else if (strncasecmp(item, "int", 3) == 0) { + sscanf(item + 3, "%d", &size); + type = intType; + } else if (strcasecmp(item, "hex") == 0) { + type = hexType; + } else if (strcasecmp(item, "float") == 0) { + type = floatType; + } else { + switch (type) { + case intType: + res = sscanf(item, "%ld", &iValue); + if (res != 1) { + BinError(a, "invalid integer"); + return 1; + } + for (i = size - 1; i >= 0; i--) { + if (i < sizeof data) { + data[i] = iValue % 256; + } + iValue /= 256; + } + for (i = 0; i < size; i++) { + if (i >= sizeof data) { + DynStringConcatChar(dyn, 0); + } else { + DynStringConcatChar(dyn, data[i]); + } + } + l += size; + break; + case hexType: + res = sscanf(item, "%lx", &iValue); + if (res != 1) { + BinError(a, "invalid hex. integer"); + return 1; + } + DynStringConcatChar(dyn, (iValue & 255)); + case floatType: + res = sscanf(item, "%lf", &fValue); + if (res != 1) { + BinError(a, "invalid float"); + return 1; + } + double2ieee(fValue, data); + DynStringConcatChar(dyn, data[0]); + DynStringConcatChar(dyn, data[1]); + DynStringConcatChar(dyn, data[2]); + DynStringConcatChar(dyn, data[3]); + l += 4; + break; + } + } + } + + p->nextFmt = str + pos; + p->type = hexType; /* initialize to anything < dumpType */ + do { + res = BinReadItem(a); + if (res < 0) { + BinError(a, "illegal return format: "); + DynStringConcat(a->errmsg, p->nextFmt); + return 1; + } + } while (res == 1); + p->nextFmt = str + pos; + a->wrPos = 0; + a->state = AsconWriting; + a->lineCount = 0; + return 1; + case AsconReadStart: + DynStringClear(p->result); + p->type = hexType; /* initialize to anything < dumpType */ + BinReadItem(a); + break; + case AsconReading: + res = AsconBaseHandler(a); + if (res == 0) { + if (GetDynStringLength(a->rdBuffer) == 0) { + /* wait for the first byte - or timeout */ + return res; + } + if (p->type >= dumpType) { + l = GetDynStringLength(a->rdBuffer); + str = GetCharArray(a->rdBuffer); + for (i = p->dumpFrom; i < l; i++) { + snprintf(item, sizeof item, "%2.2x ", (str[i] & 255)); + DynStringConcat(p->result, item); + } + if (p->type == errorType) { + DynStringConcat(a->errmsg, GetCharArray(p->result)); + a->state = AsconFailed; + } else { + a->state = AsconReadDone; + } + /* exchange buffers */ + dyn = a->rdBuffer; + a->rdBuffer = p->result; + p->result = dyn; + return 1; + } + return res; + } + /* convert according to type */ + switch (p->type) { + case codeType: + if ((a->lastChar & 255) < 128) { + p->expectedChars = 0; + } else { + DynStringCopy(a->errmsg, "BINERR: "); + p->expectedChars = 2; + p->type = errorType; + p->dumpFrom = 0; + /* skip to end */ + p->nextFmt = ""; + } + break; + case errorType: + if (p->expectedChars > 1) { + p->expectedChars--; + snprintf(item, sizeof item, "error %d / ", (a->lastChar & 255)); + DynStringCopy(p->result, item); + } + break; + case dumpType: + break; + case skipType: + p->expectedChars--; + break; + case intType: + p->expectedChars--; + p->iValue = p->iValue * 256 + (a->lastChar & 255); + if (p->expectedChars <= 0) { + snprintf(item, sizeof item, "%ld ", p->iValue); + DynStringConcat(p->result, item); + } + break; + case hexType: + p->expectedChars--; + if (p->expectedChars <= 0) { + snprintf(item, sizeof item, "%2.2x ", (a->lastChar & 255)); + DynStringConcat(p->result, item); + } + break; + case floatType: + p->expectedChars--; + if (p->expectedChars <= 0) { + str = GetCharArray(a->rdBuffer) + GetDynStringLength(a->rdBuffer) - 4; + fValue = ieee2double(str); + snprintf(item, sizeof item, "%.7g ", fValue); + DynStringConcat(p->result, item); + } + break; + case crcType: + p->expectedChars--; + if (p->expectedChars <= 0) { + str = GetCharArray(a->rdBuffer); + l = GetDynStringLength(a->rdBuffer); + if (strcasecmp(p->crcAlgorithm, "keller-crc") == 0) { + i = str[l-2]; + str[l-2] = str[l-1]; + str[l-1] = i; + } + if (calc_crc(str, l) != 0) { + DynStringConcat(p->result, "badCRC "); + } + } + } + if (p->expectedChars <= 0) { + BinReadItem(a); + } + return res; + } + return AsconBaseHandler(a); +} + +void BinPrivateKill(void *pVoid) { + BinPrivate *p = pVoid; + DeleteDynString(p->inp); + DeleteDynString(p->result); + free(p->crcAlgorithm); + free(p); +} + +static int BinInit(Ascon * a, SConnection * con, int argc, char *argv[]) +{ + BinPrivate *p; + +/* argv[2] may be modbus-crc (default) or keller-crc */ + + p = calloc(sizeof(*p), 1); + a->hostport = strdup(argv[1]); + a->private = p; + p->inp = CreateDynString(60,63); + p->result = CreateDynString(60,63); + if (argc > 2 && strcmp(argv[2], "") != 0) { + p->crcAlgorithm = strdup(argv[2]); + } else { + p->crcAlgorithm = strdup("modbus-crc"); + } + if (argc > 3) { + a->timeout = atof(argv[3]); + } else { + a->timeout = 2.0; /* sec */ + } + return 1; +} + +/*----------------------------------------------------------------------------*/ +void AddBinProtocol() +{ + static AsconProtocol binprot; + binprot.name = "bin"; + binprot.handler = BinHandler; + binprot.init = BinInit; + AsconInsertProtocol(&binprot); +} diff --git a/ease.c b/ease.c index 9edb3b2..8a62496 100644 --- a/ease.c +++ b/ease.c @@ -1004,6 +1004,10 @@ void EaseBasePar(void *object) ParAccess(usUser); ParCmd(EaseRestartWrapper, NULL); + ParName("reconnect"); + ParAccess(usUser); + ParCmd(EaseRestartWrapper, NULL); + ParName("disconnect"); ParAccess(usUser); ParCmd(EaseDisconnectWrapper, NULL); diff --git a/euro2kdriv.c b/euro2kdriv.c index 91730e7..d641e36 100644 --- a/euro2kdriv.c +++ b/euro2kdriv.c @@ -269,7 +269,7 @@ void Euro2kParDef(void *object) } else { f = ""; } - fprintf(saveFile, " %s makepar %s %s%s%d \"%s\" \"%s\"\n", + fprintf(saveFile, "%s makepar %s %s%s%d \"%s\" \"%s\"\n", obj->name, par->name, w, t, par->adr, u, f); } ParName(par->name); diff --git a/ipsdriv.c b/ipsdriv.c index d7ae7a0..fe16009 100644 --- a/ipsdriv.c +++ b/ipsdriv.c @@ -62,6 +62,9 @@ static int IpsOk(Ips * drv) return 1; /* connection not yet confirmed */ if (drv->perswitch) return 1; + if (drv->lastfield == PAR_NAN) { + drv->lastfield = drv->persfield; + } if (fabs(drv->persfield - drv->lastfield) < 1e-5) return 1; if (drv->force != 0) @@ -186,7 +189,7 @@ void IpsParDef(void *object) ParName("lastfield"); ParSave(1); - ParFloat(&drv->lastfield, 0); + ParFloat(&drv->lastfield, PAR_NAN); ParName("confirm"); ParCmd(IpsConfirm, NULL); @@ -232,6 +235,7 @@ static void IpsStatus(Ips * drv) break; case '1': ParPrintf(drv, eError, "magnet quenched"); + drv->lastfield = PAR_NAN; *code = EASE_FAULT; return; case '2': @@ -358,6 +362,7 @@ static long IpsStart(long pc, void *object) FsmCall(IpsRead); return __LINE__; case __LINE__: /**********************************/ + drv->d.targetValue = drv->persfield; quit: return 0; @@ -398,6 +403,9 @@ static long IpsChangeField(long pc, void *object) drv->remote = 2; if (!IpsOk(drv)) goto finish; + if (drv->lastfield == PAR_NAN) { + drv->lastfield = drv->persfield; + } if (fabs(drv->d.targetValue - drv->lastfield) < 1e-5) { ParPrintf(drv, -1, "IPS: we are already at field %f", drv->lastfield); diff --git a/lsc370driv.c b/lsc370driv.c index a824eb9..c6a5a01 100644 --- a/lsc370driv.c +++ b/lsc370driv.c @@ -33,19 +33,19 @@ Markus Zolliker, July 2006 #define PID_FLAG 1 #define RDGRNG_FLAG 2 #define HTRRNG_FLAG 3 -#define MAX_CHAN 3 +#define MAX_CHAN 4 typedef struct { EaseDriv d; float t; float htr; float set; - float res; float prop; float integ; float deriv; float resist; /* Ohm */ float temp[MAX_CHAN]; + float res[MAX_CHAN]; int channel[MAX_CHAN]; int ighHeater; /* IGH heater range (-1 if output is direct) */ int htrRange; @@ -116,13 +116,18 @@ static void Lsc370ParDef(void *object) }; static char *offOn[] = { "off", "on", NULL }; - static char *tNames[] = { "tsample", "tstill", "tmix" }; - static char *cNames[] = { "csample", "cstill", "cmix" }; + static char *tNames[] = { "tsample", "tstill", "tmix", "tplate" }; + static char *rNames[] = { "rsample", "rstill", "rmix", "rplate" }; + static char *cNames[] = { "csample", "cstill", "cmix", "cplate" }; ParName(""); ParTail("K"); ParFloat(&drv->temp[0], PAR_NAN); + ParName("res"); + ParTail("Ohm"); + ParFloat(&drv->res[0], PAR_NAN); + ParName("set"); ParTail("K"); if (EaseUpdate(EASE_RUN)) { @@ -140,16 +145,16 @@ static void Lsc370ParDef(void *object) ParName(tNames[i]); ParTail("K"); ParFloat(&drv->temp[i], PAR_NAN); + + ParName(rNames[i]); + ParTail("Ohm"); + ParFloat(&drv->res[i], PAR_NAN); } ParName(cNames[i]); ParAccess(usUser); ParInt(&drv->channel[i], 0); } - ParName("res"); - ParTail("Ohm"); - ParFloat(&drv->res, PAR_NAN); - ParName("prop"); ParTail("(gain)"); EaseUpdate(PID_FLAG); @@ -270,6 +275,10 @@ static void Lsc370ParDef(void *object) EaseDrivPar(drv, "%.5g", "K"); ParStdDef(); EaseMsgPar(drv); + + ParName("period"); + ParAccess(usUser); + ParInt(&drv->d.b.p.period, 5); } /*----------------------------------------------------------------------------*/ @@ -292,26 +301,28 @@ static long Lsc370Read(long pc, void *object) drv->temp[drv->index] = PAR_NAN; goto noRead; } + snprintf(buf, sizeof buf, "RDGK?%d", drv->channel[drv->index]); EaseWrite(eab, buf); return __LINE__; case __LINE__: /**********************************/ - if (1 == sscanf(eab->ans, "%f", &x)) { drv->temp[drv->index] = x; } + snprintf(buf, sizeof buf, "RDGR?%d", drv->channel[drv->index]); + EaseWrite(eab, buf); + return __LINE__; + case __LINE__: /**********************************/ + if (1 == sscanf(eab->ans, "%f", &x)) { + drv->res[drv->index] = x; + } + noRead: drv->index++; if (drv->index < MAX_CHAN) goto chanLoop; - EaseWrite(eab, "RDGR?1"); - return __LINE__; - case __LINE__: /**********************************/ - if (1 == sscanf(eab->ans, "%f", &x)) { - drv->res = x; - } EaseWrite(eab, "HTR?"); return __LINE__; case __LINE__: /**********************************/ diff --git a/make_gen b/make_gen index 36bceea..4c7be07 100644 --- a/make_gen +++ b/make_gen @@ -29,7 +29,7 @@ OBJ=psi.o buffer.o ruli.o sps.o pimotor.o charbychar.o\ MZOBJ=fsm.o sugar.o pardef.o ease.o strobj.o oxinst.o \ ipsdriv.o ilmdriv.o itcdriv.o ighdriv.o euro2kdriv.o modbus.o arrobj.o \ - lscsupport.o lsc370driv.o linadriv.o haakedriv.o amilevel.o + lscsupport.o lsc370driv.o linadriv.o haakedriv.o amilevel.o binprot.o libpsi.a: $(OBJ) rm -f libpsi.a diff --git a/modbus.c b/modbus.c index 36cd8de..b2acb2b 100644 --- a/modbus.c +++ b/modbus.c @@ -141,7 +141,7 @@ static int calc_crc(char *inp, int inpLen, int addCrc) /* CRC runs cyclic Redundancy Check Algorithm on input inp */ /* Returns value of 16 bit CRC after completion and */ -/* always adds 2 crc bytes to message */ +/* adds 2 crc bytes if addCrc is not 0 */ /* returns 0 if incoming message has correct CRC */ unsigned int crc = 0xffff; diff --git a/pardef.c b/pardef.c index aa0ed73..d7958e2 100644 --- a/pardef.c +++ b/pardef.c @@ -282,11 +282,11 @@ static int ParSaveAll(void *object, char *name, FILE * fil) ctx->saveFile = fil; assert(0 == strcasecmp(o->name, name)); if (o->creationCmd) { - fprintf(fil, "if {[catch { %s }] == 0} {\n", o->creationCmd); + fprintf(fil, "%s\n", o->creationCmd); } ParDo(0, o, PAR_SAVE, NULL); if (o->creationCmd) { - fprintf(fil, " %s endinit\n}\n", name); + fprintf(fil, "%s endinit\n\n", name); } ctx->saveFile = NULL; ret = ctx->returnValue; @@ -940,10 +940,10 @@ ParOp ParWhat(int numeric) } if (ctx->par->saveLog) { if (ctx->par->log) { - fprintf(ctx->saveFile, " %s log %s %s\n", ctx->obj->name, + fprintf(ctx->saveFile, "%s log %s %s\n", ctx->obj->name, ctx->parName, LoggerName(ctx->par->log)); } else { - fprintf(ctx->saveFile, " %s unlog %s\n", ctx->obj->name, + fprintf(ctx->saveFile, "%s unlog %s\n", ctx->obj->name, ctx->parName); } } @@ -1104,10 +1104,10 @@ void ParOut(char *buf) break; case PAR_SAVE: if (strchr(buf, '\n') != NULL) { - fprintf(ctx->saveFile, " %s %s {%s}\n", ctx->obj->name, + fprintf(ctx->saveFile, "%s %s {%s}\n", ctx->obj->name, ctx->parName, buf); } else { - fprintf(ctx->saveFile, " %s %s %s\n", ctx->obj->name, + fprintf(ctx->saveFile, "%s %s %s\n", ctx->obj->name, ctx->parName, buf); } break; diff --git a/psi.c b/psi.c index 55cbe4e..88dda31 100644 --- a/psi.c +++ b/psi.c @@ -71,6 +71,7 @@ void SiteInit(void) INIT(AddPhytronProtocoll); INIT(AddSLSEchoProtocoll); INIT(AddCharByCharProtocoll); + INIT(AddBinProtocol); }