- ascon.c: bug fix
- binprot.c: enhancements - devser.c, scriptcontext.c: introduced specifiaction of start time in poll
This commit is contained in:
252
binprot.c
252
binprot.c
@@ -22,8 +22,18 @@
|
||||
* 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
|
||||
* float<o> changing the format to 4 byte ieee float
|
||||
* order <o>:
|
||||
* 0: normal (may be omitted)
|
||||
* 1: exchange bytes within words
|
||||
* 2: exchange words
|
||||
* 3: invert order
|
||||
* str<n> string nul terminated or with exactly n characters
|
||||
* (encode space by underscore)
|
||||
* crc<t><i> send crc
|
||||
* <t> is the type of crc
|
||||
* (m: modbus, k: keller, r: rs_port, s: sycon, c: checksum)
|
||||
* <i> index from where to start counting (default 0)
|
||||
*
|
||||
* and formatItem is one of the follwing
|
||||
*
|
||||
@@ -38,11 +48,14 @@
|
||||
* 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
|
||||
* float<o> convert 4 bytes from ieee float (<o> see above)
|
||||
* str<n> string (length n or nul terminated)
|
||||
* (spaces are encoded by underscore)
|
||||
* dump read all bytes in read buffer as hex (only for tests)
|
||||
* crc check crc (if wrong, "badCRC" is added to the response)
|
||||
*
|
||||
* crc<t><i> check crc (if wrong, "badCRC" is added to the response)
|
||||
* <t> is the type of crc
|
||||
* (m: modbus, k: keller, r: rs_port, s: sycon, c: checksum)
|
||||
* <i> index from where to start counting (default 0)
|
||||
* multiple items in the response are space separated
|
||||
*
|
||||
* Usage example: Modbus read (float)
|
||||
@@ -58,25 +71,50 @@
|
||||
* chksum-crc: simple 8bit checksum
|
||||
*/
|
||||
|
||||
typedef enum {intType, hexType, floatType, skipType, codeType, checkType,
|
||||
crcType, dumpType, endType, errorType} BinDataType;
|
||||
// dumpType, endType, errorType must be the last items
|
||||
typedef enum {intType, hexType, floatType, strType,
|
||||
skipType, codeType, checkType, crcType,
|
||||
dumpType, endType, errorType} BinDataType; // items on this line stay at end
|
||||
|
||||
typedef enum {modbusCrc, kellerCrc, rsportCrc, syconCrc, chksumCrc} CrcAlgorithm;
|
||||
|
||||
typedef struct {
|
||||
CrcAlgorithm crcAlgorithm;
|
||||
CrcAlgorithm algo;
|
||||
int crcStart;
|
||||
pDynString inp;
|
||||
char *nextFmt; // position of next format token
|
||||
pDynString result;
|
||||
int expectedChars;
|
||||
BinDataType type;
|
||||
int order;
|
||||
int done;
|
||||
long iValue;
|
||||
int dumpFrom;
|
||||
int syconState;
|
||||
unsigned char chksum;
|
||||
pDynString data;
|
||||
} BinPrivate;
|
||||
|
||||
#define MAXDUMP 999
|
||||
#define NUL_TERMINATED 9999
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static int parseAlgo(char *inp, BinPrivate *p) {
|
||||
int index = 0;
|
||||
|
||||
p->algo = p->crcAlgorithm;
|
||||
switch (*inp) {
|
||||
case 'm': p->algo = modbusCrc; break;
|
||||
case 'k': p->algo = kellerCrc; break;
|
||||
case 'r': p->algo = rsportCrc; break;
|
||||
case 's': p->algo = syconCrc; break;
|
||||
case 'c': p->algo = chksumCrc; break;
|
||||
}
|
||||
while (*inp > '9') inp++;
|
||||
sscanf(inp, "%d", &index);
|
||||
return index;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static int calc_crc(char *inp, int inpLen)
|
||||
{
|
||||
@@ -156,25 +194,66 @@ static int calc_chksum(char *inp, int inpLen)
|
||||
return crc;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
int BinGetItem(char *str, char *item, size_t item_size) {
|
||||
int cntcurly = 0;
|
||||
char *p, *res;
|
||||
int l;
|
||||
|
||||
p = str;
|
||||
while (*p == ' ') p++;
|
||||
if (*p == '{') {
|
||||
cntcurly++;
|
||||
p++;
|
||||
}
|
||||
if (!*p) return -1;
|
||||
res = p;
|
||||
while (*p) {
|
||||
if (*p == '{') {
|
||||
cntcurly++;
|
||||
} else if (*p == '}') {
|
||||
cntcurly--;
|
||||
if (cntcurly == 0) {
|
||||
l = p - str - 1;
|
||||
break;
|
||||
}
|
||||
} else if (*p == ' ' && cntcurly == 0) {
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
l = p - res;
|
||||
if (l >= item_size) {
|
||||
l = item_size - 1;
|
||||
}
|
||||
strncpy(item, res, l);
|
||||
item[l] = '\0';
|
||||
return p - str;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
int BinReadItem(Ascon *a) {
|
||||
BinPrivate *p = a->private;
|
||||
char item[32];
|
||||
int valen;
|
||||
int size;
|
||||
|
||||
if (sscanf(p->nextFmt, "%30s%n", item, &valen) <= 0) {
|
||||
CrcAlgorithm algo;
|
||||
|
||||
valen = BinGetItem(p->nextFmt, item, sizeof item);
|
||||
if (valen < 0) {
|
||||
if (p->type < dumpType) {
|
||||
p->dumpFrom = GetDynStringLength(a->rdBuffer);
|
||||
p->type = endType;
|
||||
}
|
||||
p->expectedChars = 999;
|
||||
p->expectedChars = MAXDUMP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcasecmp(item, "crc") == 0) {
|
||||
if (strncasecmp(item, "crc", 3) == 0) {
|
||||
p->type = crcType;
|
||||
if (p->crcAlgorithm == chksumCrc) {
|
||||
p->expectedChars = 2;
|
||||
p->crcStart = parseAlgo(item + 3, p);
|
||||
if (p->algo == chksumCrc) {
|
||||
p->expectedChars = 1;
|
||||
} else {
|
||||
p->expectedChars = 2;
|
||||
@@ -187,9 +266,22 @@ int BinReadItem(Ascon *a) {
|
||||
p->expectedChars = size;
|
||||
p->type = intType;
|
||||
p->iValue = 0;
|
||||
} else if (strcasecmp(item, "float") == 0) {
|
||||
} else if (strncasecmp(item, "float", 5) == 0) {
|
||||
p->order = 0;
|
||||
sscanf(item + 5, "%d", &p->order);
|
||||
p->expectedChars = 4;
|
||||
p->type = floatType;
|
||||
DynStringClear(p->data);
|
||||
} else if (strncasecmp(item, "str", 3) == 0) {
|
||||
size = 1;
|
||||
sscanf(item + 3, "%d", &size);
|
||||
if (size == 0) {
|
||||
size = NUL_TERMINATED;
|
||||
}
|
||||
p->expectedChars = size;
|
||||
p->type = strType;
|
||||
p->done = 0;
|
||||
DynStringClear(p->data);
|
||||
} else if (strcasecmp(item, "hex") == 0) {
|
||||
p->expectedChars = 1;
|
||||
p->type = hexType;
|
||||
@@ -205,12 +297,17 @@ int BinReadItem(Ascon *a) {
|
||||
p->type = skipType;
|
||||
} else {
|
||||
p->iValue = 0;
|
||||
if (1 == sscanf(item, "%ld", &p->iValue)) {
|
||||
p->expectedChars = 1;
|
||||
p->type = checkType;
|
||||
if (strncasecmp(item, "0x", 2) == 0) {
|
||||
if (1 != sscanf(item + 2, "%lx", &p->iValue)) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
if (1 != sscanf(item, "%ld", &p->iValue)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
p->expectedChars = 1;
|
||||
p->type = checkType;
|
||||
}
|
||||
p->nextFmt += valen;
|
||||
return 1;
|
||||
@@ -265,17 +362,39 @@ void BinToSycon(pDynString dyn) {
|
||||
free(str);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void BinShuffle(char *input, int order) {
|
||||
/* order may be 0: no shuffle, 1: change within words, 2: change words, 3: invert*/
|
||||
char ch;
|
||||
|
||||
switch (order) {
|
||||
case 1:
|
||||
ch = input[0]; input[0] = input[1]; input[1] = ch;
|
||||
ch = input[2]; input[2] = input[3]; input[3] = ch;
|
||||
break;
|
||||
case 2:
|
||||
ch = input[0]; input[0] = input[2]; input[2] = ch;
|
||||
ch = input[1]; input[1] = input[3]; input[3] = ch;
|
||||
break;
|
||||
case 3:
|
||||
ch = input[0]; input[0] = input[3]; input[3] = ch;
|
||||
ch = input[1]; input[1] = input[2]; input[2] = ch;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
int BinHandler(Ascon *a) {
|
||||
int res;
|
||||
char *str;
|
||||
int len;
|
||||
int i, l, pos;
|
||||
int i, l, ls, pos;
|
||||
int start;
|
||||
unsigned int crc;
|
||||
pDynString dyn;
|
||||
char item[32];
|
||||
char data[8];
|
||||
int size;
|
||||
int order;
|
||||
int valen;
|
||||
BinDataType type;
|
||||
long iValue;
|
||||
@@ -293,44 +412,52 @@ int BinHandler(Ascon *a) {
|
||||
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) {
|
||||
valen = BinGetItem(str + pos, item, sizeof item);
|
||||
if (valen < 0) {
|
||||
BinError(a, "missing '/'");
|
||||
return 1;
|
||||
}
|
||||
pos += valen;
|
||||
if (strcasecmp(item, "/") == 0) {
|
||||
break;
|
||||
} else if (strcasecmp(item, "crc") == 0) {
|
||||
switch (p->crcAlgorithm) {
|
||||
} else if (strncasecmp(item, "crc", 3) == 0) {
|
||||
start = parseAlgo(item + 3, p);
|
||||
switch (p->algo) {
|
||||
case kellerCrc:
|
||||
crc = calc_crc(GetCharArray(dyn), l);
|
||||
crc = calc_crc(GetCharArray(dyn)+start, l-start);
|
||||
DynStringConcatChar(dyn, crc / 256);
|
||||
DynStringConcatChar(dyn, crc % 256);
|
||||
break;
|
||||
case modbusCrc:
|
||||
crc = calc_crc(GetCharArray(dyn), l);
|
||||
crc = calc_crc(GetCharArray(dyn)+start, l-start);
|
||||
DynStringConcatChar(dyn, crc % 256);
|
||||
DynStringConcatChar(dyn, crc / 256);
|
||||
break;
|
||||
case chksumCrc:
|
||||
crc = calc_chksum(GetCharArray(dyn), l);
|
||||
crc = calc_chksum(GetCharArray(dyn)+start, l-start);
|
||||
DynStringConcatChar(dyn, crc % 256);
|
||||
break;
|
||||
case rsportCrc:
|
||||
crc = calc_crc8(GetCharArray(dyn), l);
|
||||
crc = calc_crc8(GetCharArray(dyn)+start, l-start);
|
||||
DynStringConcatChar(dyn, crc);
|
||||
break;
|
||||
}
|
||||
} else if (strncasecmp(item, "int", 3) == 0) {
|
||||
size = 1;
|
||||
sscanf(item + 3, "%d", &size);
|
||||
type = intType;
|
||||
} else if (strcasecmp(item, "hex") == 0) {
|
||||
type = hexType;
|
||||
} else if (strcasecmp(item, "float") == 0) {
|
||||
} else if (strncasecmp(item, "float", 5) == 0) {
|
||||
order = 0;
|
||||
sscanf(item + 5, "%d", &order);
|
||||
type = floatType;
|
||||
} else if (strncasecmp(item, "str", 3) == 0) {
|
||||
size = NUL_TERMINATED;
|
||||
sscanf(item + 3, "%d", &size);
|
||||
type = strType;
|
||||
} else {
|
||||
switch (type) {
|
||||
case intType:
|
||||
@@ -339,6 +466,9 @@ int BinHandler(Ascon *a) {
|
||||
BinError(a, "invalid integer");
|
||||
return 1;
|
||||
}
|
||||
if (iValue < 0) {
|
||||
printf("%ld\n", iValue);
|
||||
}
|
||||
uValue = iValue;
|
||||
for (i = size - 1; i >= 0; i--) {
|
||||
if (i < sizeof data) {
|
||||
@@ -362,6 +492,7 @@ int BinHandler(Ascon *a) {
|
||||
return 1;
|
||||
}
|
||||
DynStringConcatChar(dyn, (iValue & 255));
|
||||
l += 1;
|
||||
break;
|
||||
case floatType:
|
||||
res = sscanf(item, "%lf", &fValue);
|
||||
@@ -370,12 +501,26 @@ int BinHandler(Ascon *a) {
|
||||
return 1;
|
||||
}
|
||||
double2ieee(fValue, data);
|
||||
DynStringConcatChar(dyn, data[0]);
|
||||
DynStringConcatChar(dyn, data[1]);
|
||||
DynStringConcatChar(dyn, data[2]);
|
||||
DynStringConcatChar(dyn, data[3]);
|
||||
BinShuffle(data, order);
|
||||
DynStringConcatBytes(dyn, data, 4);
|
||||
l += 4;
|
||||
break;
|
||||
case strType:
|
||||
ls = strlen(item);
|
||||
if (ls > size) {
|
||||
item[size] = '\0';
|
||||
}
|
||||
DynStringConcat(dyn, item);
|
||||
if (size == NUL_TERMINATED) {
|
||||
DynStringConcatChar(dyn, 0);
|
||||
l += ls + 1;
|
||||
} else {
|
||||
for (i = ls; i < size; i++) {
|
||||
DynStringConcatChar(dyn, 0);
|
||||
}
|
||||
l += size;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -530,21 +675,42 @@ int BinHandler(Ascon *a) {
|
||||
DynStringConcat(p->result, item);
|
||||
}
|
||||
break;
|
||||
case floatType: /* does not work with sycon when stuffed */
|
||||
case floatType:
|
||||
p->expectedChars--;
|
||||
DynStringConcatChar(p->data, a->lastChar);
|
||||
if (p->expectedChars <= 0) {
|
||||
str = GetCharArray(a->rdBuffer) + GetDynStringLength(a->rdBuffer) - 4;
|
||||
fValue = ieee2double(str);
|
||||
char *shuffle = GetCharArray(p->data);
|
||||
BinShuffle(shuffle, p->order);
|
||||
fValue = ieee2double(shuffle);
|
||||
snprintf(item, sizeof item, "%.7g ", fValue);
|
||||
DynStringConcat(p->result, item);
|
||||
}
|
||||
break;
|
||||
case strType:
|
||||
if (a->lastChar) {
|
||||
if (!p->done) {
|
||||
DynStringConcatChar(p->data, a->lastChar);
|
||||
}
|
||||
} else {
|
||||
p->done = 1;
|
||||
if (p->expectedChars == NUL_TERMINATED) {
|
||||
DynStringConcat(p->result, GetCharArray(p->data));
|
||||
p->expectedChars = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
p->expectedChars--;
|
||||
if (p->expectedChars <= 0) {
|
||||
DynStringConcat(p->result, GetCharArray(p->data));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case crcType:
|
||||
p->expectedChars--;
|
||||
if (p->expectedChars <= 0) {
|
||||
str = GetCharArray(a->rdBuffer);
|
||||
l = GetDynStringLength(a->rdBuffer);
|
||||
switch (p->crcAlgorithm) {
|
||||
switch (p->algo) {
|
||||
case syconCrc: /* ignore crc check */
|
||||
/* subtract CRC char (undo the addition) and subtract crc higher four bits */
|
||||
p->chksum -= a->lastChar + (a->lastChar & 0x0f);
|
||||
@@ -554,7 +720,7 @@ int BinHandler(Ascon *a) {
|
||||
}
|
||||
break;
|
||||
case chksumCrc:
|
||||
if (calc_chksum(str, l-1) != (unsigned char)str[l-1]) {
|
||||
if (calc_chksum(str+p->crcStart, l-1-p->crcStart) != (unsigned char)str[l-1]) {
|
||||
DynStringConcat(p->result, "badCRC ");
|
||||
}
|
||||
break;
|
||||
@@ -565,7 +731,7 @@ int BinHandler(Ascon *a) {
|
||||
/* fall through */
|
||||
case modbusCrc:
|
||||
case rsportCrc:
|
||||
if (calc_crc(str, l) != 0) {
|
||||
if (calc_crc(str+p->crcStart, l-p->crcStart) != 0) {
|
||||
DynStringConcat(p->result, "badCRC ");
|
||||
}
|
||||
}
|
||||
@@ -576,8 +742,10 @@ int BinHandler(Ascon *a) {
|
||||
break;
|
||||
case checkType:
|
||||
p->expectedChars--;
|
||||
if ((a->lastChar & 255) != p->iValue) {
|
||||
DynStringCopy(a->errmsg, "BINERR: mismatch ");
|
||||
if ((unsigned char)a->lastChar != p->iValue) {
|
||||
i = GetDynStringLength(a->rdBuffer) - 1;
|
||||
snprintf(item, sizeof item, "BINERR: response[%d]==%2.2x != %2.2x ", i, (unsigned char)a->lastChar, (unsigned char)p->iValue);
|
||||
DynStringCopy(a->errmsg, item);
|
||||
p->type = errorType;
|
||||
p->dumpFrom = 0;
|
||||
/* skip to end */
|
||||
@@ -596,6 +764,7 @@ static void BinPrivateKill(void *pVoid) {
|
||||
BinPrivate *p = pVoid;
|
||||
DeleteDynString(p->inp);
|
||||
DeleteDynString(p->result);
|
||||
DeleteDynString(p->data);
|
||||
free(p);
|
||||
}
|
||||
|
||||
@@ -631,6 +800,7 @@ static int BinInit(Ascon * a, SConnection * con, int argc, char *argv[])
|
||||
a->hostport = strdup(argv[1]);
|
||||
p->inp = CreateDynString(60,63);
|
||||
p->result = CreateDynString(60,63);
|
||||
p->data = CreateDynString(60,63);
|
||||
if (argc > 3) {
|
||||
a->timeout = atof(argv[3]);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user