- added general binary scriptcontext protocoll

- improved some drivers
This commit is contained in:
zolliker
2010-09-02 11:41:31 +00:00
parent 1e9f9d408c
commit bc2c9e5a3e
10 changed files with 528 additions and 27 deletions

477
binprot.c Normal file
View File

@ -0,0 +1,477 @@
#include <ctype.h>
#include <math.h>
#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<n> changing the format to <n> 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<n> skip <n> 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<n> convert <n> bytes to integer (most significant byte first)
* and append the (decimal coded) number to the result
* if <n> is omitted, <n> = 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);
}

4
ease.c
View File

@ -1004,6 +1004,10 @@ void EaseBasePar(void *object)
ParAccess(usUser); ParAccess(usUser);
ParCmd(EaseRestartWrapper, NULL); ParCmd(EaseRestartWrapper, NULL);
ParName("reconnect");
ParAccess(usUser);
ParCmd(EaseRestartWrapper, NULL);
ParName("disconnect"); ParName("disconnect");
ParAccess(usUser); ParAccess(usUser);
ParCmd(EaseDisconnectWrapper, NULL); ParCmd(EaseDisconnectWrapper, NULL);

View File

@ -62,6 +62,9 @@ static int IpsOk(Ips * drv)
return 1; /* connection not yet confirmed */ return 1; /* connection not yet confirmed */
if (drv->perswitch) if (drv->perswitch)
return 1; return 1;
if (drv->lastfield == PAR_NAN) {
drv->lastfield = drv->persfield;
}
if (fabs(drv->persfield - drv->lastfield) < 1e-5) if (fabs(drv->persfield - drv->lastfield) < 1e-5)
return 1; return 1;
if (drv->force != 0) if (drv->force != 0)
@ -186,7 +189,7 @@ void IpsParDef(void *object)
ParName("lastfield"); ParName("lastfield");
ParSave(1); ParSave(1);
ParFloat(&drv->lastfield, 0); ParFloat(&drv->lastfield, PAR_NAN);
ParName("confirm"); ParName("confirm");
ParCmd(IpsConfirm, NULL); ParCmd(IpsConfirm, NULL);
@ -232,6 +235,7 @@ static void IpsStatus(Ips * drv)
break; break;
case '1': case '1':
ParPrintf(drv, eError, "magnet quenched"); ParPrintf(drv, eError, "magnet quenched");
drv->lastfield = PAR_NAN;
*code = EASE_FAULT; *code = EASE_FAULT;
return; return;
case '2': case '2':
@ -358,6 +362,7 @@ static long IpsStart(long pc, void *object)
FsmCall(IpsRead); FsmCall(IpsRead);
return __LINE__; return __LINE__;
case __LINE__: /**********************************/ case __LINE__: /**********************************/
drv->d.targetValue = drv->persfield;
quit: quit:
return 0; return 0;
@ -398,6 +403,9 @@ static long IpsChangeField(long pc, void *object)
drv->remote = 2; drv->remote = 2;
if (!IpsOk(drv)) if (!IpsOk(drv))
goto finish; goto finish;
if (drv->lastfield == PAR_NAN) {
drv->lastfield = drv->persfield;
}
if (fabs(drv->d.targetValue - drv->lastfield) < 1e-5) { if (fabs(drv->d.targetValue - drv->lastfield) < 1e-5) {
ParPrintf(drv, -1, "IPS: we are already at field %f", ParPrintf(drv, -1, "IPS: we are already at field %f",
drv->lastfield); drv->lastfield);

View File

@ -33,19 +33,19 @@ Markus Zolliker, July 2006
#define PID_FLAG 1 #define PID_FLAG 1
#define RDGRNG_FLAG 2 #define RDGRNG_FLAG 2
#define HTRRNG_FLAG 3 #define HTRRNG_FLAG 3
#define MAX_CHAN 3 #define MAX_CHAN 4
typedef struct { typedef struct {
EaseDriv d; EaseDriv d;
float t; float t;
float htr; float htr;
float set; float set;
float res;
float prop; float prop;
float integ; float integ;
float deriv; float deriv;
float resist; /* Ohm */ float resist; /* Ohm */
float temp[MAX_CHAN]; float temp[MAX_CHAN];
float res[MAX_CHAN];
int channel[MAX_CHAN]; int channel[MAX_CHAN];
int ighHeater; /* IGH heater range (-1 if output is direct) */ int ighHeater; /* IGH heater range (-1 if output is direct) */
int htrRange; int htrRange;
@ -116,13 +116,18 @@ static void Lsc370ParDef(void *object)
}; };
static char *offOn[] = { "off", "on", NULL }; static char *offOn[] = { "off", "on", NULL };
static char *tNames[] = { "tsample", "tstill", "tmix" }; static char *tNames[] = { "tsample", "tstill", "tmix", "tplate" };
static char *cNames[] = { "csample", "cstill", "cmix" }; static char *rNames[] = { "rsample", "rstill", "rmix", "rplate" };
static char *cNames[] = { "csample", "cstill", "cmix", "cplate" };
ParName(""); ParName("");
ParTail("K"); ParTail("K");
ParFloat(&drv->temp[0], PAR_NAN); ParFloat(&drv->temp[0], PAR_NAN);
ParName("res");
ParTail("Ohm");
ParFloat(&drv->res[0], PAR_NAN);
ParName("set"); ParName("set");
ParTail("K"); ParTail("K");
if (EaseUpdate(EASE_RUN)) { if (EaseUpdate(EASE_RUN)) {
@ -140,16 +145,16 @@ static void Lsc370ParDef(void *object)
ParName(tNames[i]); ParName(tNames[i]);
ParTail("K"); ParTail("K");
ParFloat(&drv->temp[i], PAR_NAN); ParFloat(&drv->temp[i], PAR_NAN);
ParName(rNames[i]);
ParTail("Ohm");
ParFloat(&drv->res[i], PAR_NAN);
} }
ParName(cNames[i]); ParName(cNames[i]);
ParAccess(usUser); ParAccess(usUser);
ParInt(&drv->channel[i], 0); ParInt(&drv->channel[i], 0);
} }
ParName("res");
ParTail("Ohm");
ParFloat(&drv->res, PAR_NAN);
ParName("prop"); ParName("prop");
ParTail("(gain)"); ParTail("(gain)");
EaseUpdate(PID_FLAG); EaseUpdate(PID_FLAG);
@ -270,6 +275,10 @@ static void Lsc370ParDef(void *object)
EaseDrivPar(drv, "%.5g", "K"); EaseDrivPar(drv, "%.5g", "K");
ParStdDef(); ParStdDef();
EaseMsgPar(drv); 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; drv->temp[drv->index] = PAR_NAN;
goto noRead; goto noRead;
} }
snprintf(buf, sizeof buf, "RDGK?%d", drv->channel[drv->index]); snprintf(buf, sizeof buf, "RDGK?%d", drv->channel[drv->index]);
EaseWrite(eab, buf); EaseWrite(eab, buf);
return __LINE__; return __LINE__;
case __LINE__: /**********************************/ case __LINE__: /**********************************/
if (1 == sscanf(eab->ans, "%f", &x)) { if (1 == sscanf(eab->ans, "%f", &x)) {
drv->temp[drv->index] = 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: noRead:
drv->index++; drv->index++;
if (drv->index < MAX_CHAN) if (drv->index < MAX_CHAN)
goto chanLoop; goto chanLoop;
EaseWrite(eab, "RDGR?1");
return __LINE__;
case __LINE__: /**********************************/
if (1 == sscanf(eab->ans, "%f", &x)) {
drv->res = x;
}
EaseWrite(eab, "HTR?"); EaseWrite(eab, "HTR?");
return __LINE__; return __LINE__;
case __LINE__: /**********************************/ case __LINE__: /**********************************/

View File

@ -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 \ 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 \ 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) libpsi.a: $(OBJ)
rm -f libpsi.a rm -f libpsi.a

View File

@ -141,7 +141,7 @@ static int calc_crc(char *inp, int inpLen, int addCrc)
/* CRC runs cyclic Redundancy Check Algorithm on input inp */ /* CRC runs cyclic Redundancy Check Algorithm on input inp */
/* Returns value of 16 bit CRC after completion and */ /* 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 */ /* returns 0 if incoming message has correct CRC */
unsigned int crc = 0xffff; unsigned int crc = 0xffff;

View File

@ -282,11 +282,11 @@ static int ParSaveAll(void *object, char *name, FILE * fil)
ctx->saveFile = fil; ctx->saveFile = fil;
assert(0 == strcasecmp(o->name, name)); assert(0 == strcasecmp(o->name, name));
if (o->creationCmd) { if (o->creationCmd) {
fprintf(fil, "if {[catch { %s }] == 0} {\n", o->creationCmd); fprintf(fil, "%s\n", o->creationCmd);
} }
ParDo(0, o, PAR_SAVE, NULL); ParDo(0, o, PAR_SAVE, NULL);
if (o->creationCmd) { if (o->creationCmd) {
fprintf(fil, " %s endinit\n}\n", name); fprintf(fil, "%s endinit\n\n", name);
} }
ctx->saveFile = NULL; ctx->saveFile = NULL;
ret = ctx->returnValue; ret = ctx->returnValue;

1
psi.c
View File

@ -71,6 +71,7 @@ void SiteInit(void)
INIT(AddPhytronProtocoll); INIT(AddPhytronProtocoll);
INIT(AddSLSEchoProtocoll); INIT(AddSLSEchoProtocoll);
INIT(AddCharByCharProtocoll); INIT(AddCharByCharProtocoll);
INIT(AddBinProtocol);
} }