diff --git a/binprot.c b/binprot.c index c3a3c6b..886c793 100644 --- a/binprot.c +++ b/binprot.c @@ -48,14 +48,21 @@ * response: address, function, byte-count, float, crc * * sct send 250 3 int2 10 2 crc / skip code skip float crc + * + * different crc's might be used (argv[2] opf BinInit): + * modbus-crc: CRC-16-IBM, order: lo,hi + * keller-crc: CRC-16-IBM, order: hi,lo + * sycon-crc: sort of mod 256 checksum, byte stuffing included (no float allowed) */ typedef enum {intType, hexType, floatType, skipType, codeType, crcType, dumpType, errorType} BinDataType; // dumpType, errorType must be the last items +typedef enum {modbusCrc, kellerCrc, syconCrc} CrcAlgorithm; + typedef struct { - char *crcAlgorithm; + CrcAlgorithm crcAlgorithm; pDynString inp; char *nextFmt; pDynString result; @@ -63,16 +70,20 @@ typedef struct { BinDataType type; long iValue; int dumpFrom; + int syconState; + unsigned char chksum; } BinPrivate; /*----------------------------------------------------------------------------*/ 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 */ +/** CRC-16-IBM Algorithm + * crc calculation: + * returns the 16bit CRC value of a message + * crc check: + * returns 0 when the crc appended to the message (lo byte first) + * is correct + */ unsigned int crc = 0xffff; unsigned int next; @@ -154,6 +165,42 @@ void BinError(Ascon *a, char *text) { a->state = AsconFailed; } +/*----------------------------------------------------------------------------*/ +void BinToSycon(pDynString dyn) { + char *str = strdup(GetCharArray(dyn)); + int l = GetDynStringLength(dyn); + unsigned char sum, byte; + int i; + + DynStringClear(dyn); + DynStringConcat(dyn, "\x02\x10\x80"); /* STX ADDR CMD */ + sum = 0x10 + 0x80; + for (i=0; icrcAlgorithm, "keller-crc") == 0) { + switch (p->crcAlgorithm) { + case kellerCrc: crc = calc_crc(GetCharArray(dyn), l); DynStringConcatChar(dyn, crc / 256); DynStringConcatChar(dyn, crc % 256); - } else { /* modbus-crc */ + break; + case modbusCrc: crc = calc_crc(GetCharArray(dyn), l); - DynStringConcatChar(dyn, crc / 256); DynStringConcatChar(dyn, crc % 256); + DynStringConcatChar(dyn, crc / 256); + break; } } else if (strncasecmp(item, "int", 3) == 0) { sscanf(item + 3, "%d", &size); @@ -238,6 +288,7 @@ int BinHandler(Ascon *a) { return 1; } DynStringConcatChar(dyn, (iValue & 255)); + break; case floatType: res = sscanf(item, "%lf", &fValue); if (res != 1) { @@ -255,6 +306,10 @@ int BinHandler(Ascon *a) { } } + if (p->crcAlgorithm == syconCrc) { + BinToSycon(dyn); + } + p->nextFmt = str + pos; p->type = hexType; /* initialize to anything < dumpType */ do { @@ -274,6 +329,7 @@ int BinHandler(Ascon *a) { DynStringClear(p->result); p->type = hexType; /* initialize to anything < dumpType */ BinReadItem(a); + p->syconState = 0; break; case AsconReading: res = AsconBaseHandler(a); @@ -283,12 +339,12 @@ int BinHandler(Ascon *a) { 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); - } + 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; @@ -297,12 +353,58 @@ int BinHandler(Ascon *a) { } /* exchange buffers */ dyn = a->rdBuffer; - a->rdBuffer = p->result; - p->result = dyn; + a->rdBuffer = p->result; + p->result = dyn; return 1; } return res; } + if (p->crcAlgorithm == syconCrc) { + switch (p->syconState) { + case 0: /* wait for STX */ + if (a->lastChar == 0x02) { + p->syconState = 1; + p->chksum = 0; + } + return res; + case 1: /* skip address */ + case 2: /* skip cmd_rsp */ + p->syconState++; + p->chksum += a->lastChar; + return res; + case 3: /* detect stuffed bytes */ + if (a->lastChar == 0x07) { + p->syconState = 4; + return res; + } + p->chksum += a->lastChar; + break; + case 4: /* last byte was 0x07 */ + switch (a->lastChar) { + case '0': + a->lastChar = 0x02; + break; + case '1': + a->lastChar = 0x0d; + break; + case '2': + a->lastChar = 0x07; + break; + } + p->chksum += a->lastChar; + p->syconState = 3; + break; + case 5: /* expect 0x0d */ + if (a->lastChar != 0x0d) { + DynStringConcat(p->result, "noCR "); + } + p->syconState = 6; + p->dumpFrom++; /* skip for dump */ + case 6: /* skip everything else */ + return res; + } + } + /* convert according to type */ switch (p->type) { case codeType: @@ -311,16 +413,16 @@ int BinHandler(Ascon *a) { } else { DynStringCopy(a->errmsg, "BINERR: "); p->expectedChars = 2; - p->type = errorType; - p->dumpFrom = 0; + p->type = errorType; + p->dumpFrom = 0; /* skip to end */ - p->nextFmt = ""; + p->nextFmt = ""; } break; case errorType: if (p->expectedChars > 1) { p->expectedChars--; - snprintf(item, sizeof item, "error %d / ", (a->lastChar & 255)); + snprintf(item, sizeof item, "error %d / ", (a->lastChar & 255)); DynStringCopy(p->result, item); } break; @@ -344,7 +446,7 @@ int BinHandler(Ascon *a) { DynStringConcat(p->result, item); } break; - case floatType: + case floatType: /* does not work with sycon when stuffed */ p->expectedChars--; if (p->expectedChars <= 0) { str = GetCharArray(a->rdBuffer) + GetDynStringLength(a->rdBuffer) - 4; @@ -358,14 +460,28 @@ int BinHandler(Ascon *a) { if (p->expectedChars <= 0) { str = GetCharArray(a->rdBuffer); l = GetDynStringLength(a->rdBuffer); - if (strcasecmp(p->crcAlgorithm, "keller-crc") == 0) { + switch (p->crcAlgorithm) { + case syconCrc: /* ignore crc check */ + /* subtract CRC char (undo the addition) and subtract crc higher four bits */ + p->chksum -= a->lastChar + (a->lastChar & 0x0f); + p->syconState = 5; + if (p->chksum != 0) { + DynStringConcat(p->result, "badCRC "); + } + break; + case kellerCrc: i = str[l-2]; str[l-2] = str[l-1]; str[l-1] = i; + /* fall through */ + case modbusCrc: + if (calc_crc(str, l) != 0) { + DynStringConcat(p->result, "badCRC "); + } } - if (calc_crc(str, l) != 0) { - DynStringConcat(p->result, "badCRC "); - } + } else if (p->crcAlgorithm == syconCrc) { + /* subtract CRC char (undo the addition) and subtract crc higher four bits */ + p->chksum -= a->lastChar + (a->lastChar & 0x0f) * 16; } } if (p->expectedChars <= 0) { @@ -376,11 +492,10 @@ int BinHandler(Ascon *a) { return AsconBaseHandler(a); } -void BinPrivateKill(void *pVoid) { +static void BinPrivateKill(void *pVoid) { BinPrivate *p = pVoid; DeleteDynString(p->inp); DeleteDynString(p->result); - free(p->crcAlgorithm); free(p); } @@ -388,18 +503,30 @@ static int BinInit(Ascon * a, SConnection * con, int argc, char *argv[]) { BinPrivate *p; -/* argv[2] may be modbus-crc (default) or keller-crc */ +/* argv[2] may be modbus-crc (default), keller-crc or sycon-crc */ + if (argc < 2) { + return 0; + } p = calloc(sizeof(*p), 1); - a->hostport = strdup(argv[1]); a->private = p; + a->killPrivate = BinPrivateKill; + p->crcAlgorithm = modbusCrc; + if (argc > 2 && strcmp(argv[2], "") != 0) { + if (strcasecmp(argv[2], "keller-crc") == 0) { + p->crcAlgorithm = kellerCrc; + } else if (strcasecmp(argv[2], "sycon-crc") == 0) { + p->crcAlgorithm = syconCrc; + } else if (strcasecmp(argv[2], "modbus-crc") != 0) { + SCPrintf(con, eError, "ERROR: unknown crc-algorithm %s", argv[2]); + a->private = NULL; + free(p); + return 0; + } + } + a->hostport = strdup(argv[1]); 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 { diff --git a/ipsdriv.c b/ipsdriv.c index 7c7ce40..be69586 100644 --- a/ipsdriv.c +++ b/ipsdriv.c @@ -46,6 +46,9 @@ typedef struct { float perslimit; /* field limit for activating persistent mode workaround (Tesla) */ float voltage; /* voltage */ float measured; /* measured current */ + float inductance; /* induction (read only on startup) */ + float ampRamp; /* ramp in amps (read only on startup) */ + char *startScript; /* script to be called on startup */ int persmode; /* 0: delayed persistant mode, 1: go to persistant mode, 2: leave switch on */ int persdelay; /* wait time for delayed persistant mode */ int perswitch; /* state of switch */ @@ -234,6 +237,24 @@ void IpsParDef(void *object) ParSave(1); ParFloat(&drv->lastfield, PAR_NAN); + ParName("ampRamp"); + ParFmt("%g"); + ParTail("A"); + ParList(""); + ParFloat(&drv->ampRamp, 0.0); + + ParName("inductance"); + ParFmt("%g"); + ParTail("Henry"); + ParList(""); + ParFloat(&drv->inductance, 0.0); + + ParName("startScript"); + ParAccess(usUser); + ParList(""); + ParSave(1); + ParStr(&drv->startScript, "0"); + ParName("confirm"); ParCmd(IpsConfirm, NULL); @@ -519,7 +540,10 @@ static long IpsStart(long pc, void *object) { Ips *drv = ParCast(&ipsClass, object); EaseBase *eab = object; - + float value; + Tcl_Interp *pTcl = NULL; + int iRet; + switch (pc) { default: /* FSM BEGIN ****************************** */ EaseWrite(eab, "V"); @@ -532,7 +556,7 @@ static long IpsStart(long pc, void *object) } else { snprintf(eab->msg, sizeof eab->msg, "unknown power supply version: %s", eab->version); - ParPrintf(drv, eError, "ERROR: %s", eab->msg); + ParPrintf(drv, eLogError, "ERROR: %s", eab->msg); EaseStop(eab); goto quit; } @@ -547,7 +571,64 @@ static long IpsStart(long pc, void *object) return __LINE__; case __LINE__: /**********************************/ drv->d.targetValue = drv->persfield; + + if (eab->syntax == 0) goto quit; + + EaseWrite(eab, "R24"); + return __LINE__; + case __LINE__: + drv->inductance = OxiGet(eab, 1, NULL, 0.0); + + if (drv->ramp == 0) { + goto ramp_read; + } + + EaseWrite(eab, "R9"); + return __LINE__; + case __LINE__: + value = OxiGet(eab, 3, NULL, drv->ramp); + if (fabs(value - drv->ramp) == 0) goto ramp_ok; + + EaseWrite(eab, "C3"); + drv->remote = 1; /* remote state */ + return __LINE__; + case __LINE__: /**********************************/ + OxiSet(eab, "T", drv->ramp, 3); + return __LINE__; + case __LINE__: /**********************************/ + + EaseWrite(eab, "C0"); + drv->remote = 0; /* local state */ + return __LINE__; + case __LINE__: /**********************************/ + + ramp_read: + EaseWrite(eab, "R9"); + return __LINE__; + case __LINE__: + drv->ramp = OxiGet(eab, 3, NULL, drv->ramp); + + ramp_ok: + + EaseWrite(eab, "R6"); + return __LINE__; + case __LINE__: + drv->ampRamp = OxiGet(eab, 1, NULL, 0.0); + + if (drv->startScript && drv->startScript[0] != '\0' + && 0 != strcmp(drv->startScript, "0")) { + pTcl = InterpGetTcl(pServ->pSics); + iRet = Tcl_Eval(pTcl, drv->startScript); + if (iRet != TCL_OK) { + snprintf(eab->msg, sizeof eab->msg, "%s", pTcl->result); + ParPrintf(drv, eLogError, "ERROR: %s", eab->msg); + EaseStop(eab); + goto quit; + } + eab->msg[0]='\0'; + } + quit: return 0; } /* FSM END ******************************************* */ diff --git a/make_gen b/make_gen index 6fc935a..0092e0d 100644 --- a/make_gen +++ b/make_gen @@ -30,7 +30,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 binprot.o \ - cnvrt.o + cnvrt.o dumprot.o libpsi.a: $(OBJ) rm -f libpsi.a diff --git a/pardef.c b/pardef.c index 374e074..1f64012 100644 --- a/pardef.c +++ b/pardef.c @@ -444,9 +444,17 @@ void ParSaveConn(void *object, SConnection * con) rights = SCGetRights(con); if (rights >= usMugger && rights <= usUser && con->sockHandle >= 0) { if (o->conn != NULL) { - SCDeleteConnection(o->conn); + if (o->conn->ident != con->ident) { + SCDeleteConnection(o->conn); + o->conn = SCCopyConnection(con); + } + } else { + o->conn = SCCopyConnection(con); + } + SCsetMacro(o->conn, 0); + if (o->conn->write != SCNormalWrite) { + o->conn->write = SCNormalWrite; } - o->conn = SCCopyConnection(con); } } diff --git a/pardef.h b/pardef.h index 03288be..819af17 100644 --- a/pardef.h +++ b/pardef.h @@ -129,7 +129,7 @@ void ParSave(int save); /* save on status file (0: do not svae, 1: save, void ParEnum(char *list[]); /* automatic keyword to number conversion */ void ParList(char *group); /* ParList may be repeated with several group arguments, to appear on a list subcommand. Give NULL - for std list. */ + for std list, "" for no list */ void ParTail(char *tail); /* comment to appear after list entry (e.g. units). If ParList is not called, ParTail will force to appear in standard list. */ diff --git a/psi.c b/psi.c index 3ed746e..e039068 100644 --- a/psi.c +++ b/psi.c @@ -73,6 +73,7 @@ void SiteInit(void) INIT(AddSLSEchoProtocoll); INIT(AddCharByCharProtocoll); INIT(AddBinProtocol); + INIT(AddDumProtocol); } diff --git a/sinqhttpopt.c b/sinqhttpopt.c index b327a9f..cc10c95 100644 --- a/sinqhttpopt.c +++ b/sinqhttpopt.c @@ -157,7 +157,7 @@ static void sendPost(pHttpProt pHttp, char *path, char *data) snprintf(buffer,1024,"POST %s HTTP/1.1\r\nHost: %s\r\nConnection: keep-alive\r\n", path, hostname); ANETwrite(pHttp->sockHandle, buffer,strlen(buffer)); - snprintf(buffer,1024,"Content-Length: %d\r\n", strlen(data)); + snprintf(buffer,1024,"Content-Length: %d\r\n", (int)strlen(data)); ANETwrite(pHttp->sockHandle, buffer,strlen(buffer)); sendAuth(pHttp); ANETwrite(pHttp->sockHandle,data,strlen(data));