diff --git a/binprot.c b/binprot.c new file mode 100644 index 00000000..f0ce52f8 --- /dev/null +++ b/binprot.c @@ -0,0 +1,589 @@ +#include +#include +#include "ascon.h" +#include "ascon.i" +#include "dynstring.h" +#include "cnvrt.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 + * + * 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, rsportCrc, syconCrc} CrcAlgorithm; + +typedef struct { + CrcAlgorithm crcAlgorithm; + pDynString inp; + char *nextFmt; + pDynString result; + int expectedChars; + BinDataType type; + long iValue; + int dumpFrom; + int syconState; + unsigned char chksum; +} BinPrivate; + +/*----------------------------------------------------------------------------*/ +static int calc_crc(char *inp, int inpLen) +{ +/** 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; + 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; +} +/*----------------------------------------------------------------------------*/ +static int calc_crc8(char *inp, int inpLen) +{ +/** CRC-8 (x8+x5+x4+1) Algorithm + * crc calculation: + * returns the 8bit CRC value of a message + * crc check: + * returns 0 when the crc appended to the message is correct + */ + + unsigned char crc = 0; + unsigned char data; + int n; + + while (inpLen--) { + data = *(unsigned char *) inp; + for (n = 0; n < 8; n++) { + if ((crc ^ data) & 1) { + crc ^= 0x18; + crc >>= 1; + crc |= 0x80; + } else { + crc >>= 1; + crc &= 0x7f; + } + data >>= 1; + } + 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; +} + +/*----------------------------------------------------------------------------*/ +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; iprivate; + + 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) { + switch (p->crcAlgorithm) { + case kellerCrc: + crc = calc_crc(GetCharArray(dyn), l); + DynStringConcatChar(dyn, crc / 256); + DynStringConcatChar(dyn, crc % 256); + break; + case modbusCrc: + crc = calc_crc(GetCharArray(dyn), l); + DynStringConcatChar(dyn, crc % 256); + DynStringConcatChar(dyn, crc / 256); + break; + case rsportCrc: + crc = calc_crc8(GetCharArray(dyn), l); + DynStringConcatChar(dyn, crc); + break; + } + } 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)); + break; + 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; + } + } + } + + if (p->crcAlgorithm == syconCrc) { + BinToSycon(dyn); + } + + 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; + if (GetDynStringLength(a->wrBuffer) == 0) { + /* prevent to swallow "garbage" */ + a->state = AsconWriteDone; + } else { + a->state = AsconWriting; + } + a->lineCount = 0; + return 1; + case AsconReadStart: + DynStringClear(p->result); + p->type = hexType; /* initialize to anything < dumpType */ + BinReadItem(a); + p->syconState = 0; + 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; + } + 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: + 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: /* does not work with sycon when stuffed */ + 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); + 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: + case rsportCrc: + 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) { + BinReadItem(a); + } + return res; + } + return AsconBaseHandler(a); +} + +static void BinPrivateKill(void *pVoid) { + BinPrivate *p = pVoid; + DeleteDynString(p->inp); + DeleteDynString(p->result); + free(p); +} + +static int BinInit(Ascon * a, SConnection * con, int argc, char *argv[]) +{ + BinPrivate *p; + +/* argv[2] may be modbus-crc (default), keller-crc, rsport-crc or sycon-crc */ + + if (argc < 2) { + return 0; + } + p = calloc(sizeof(*p), 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], "rsport-crc") == 0) { + p->crcAlgorithm = rsportCrc; + } 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 > 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/charbychar.c b/charbychar.c new file mode 100644 index 00000000..a4ea1453 --- /dev/null +++ b/charbychar.c @@ -0,0 +1,73 @@ +/* + * charbychar.c + * + * This is a variation of the standard AsonHandler which implements + * a char by char mode while sending. This means, that the protocol + * handler waits for the echoed character from the device before sending + * the next character. + * + * Created on: Apr 1, 2010 + * Author: koennecke + */ +#include +#include +#include + +/*----------------------------------------------------------- + * I am abusing the echo field as a flag if we are reading + * an echo char or not +-----------------------------------------------------------*/ +static int CharByCharHandler(Ascon *a) +{ + int ret; + char chr; + + switch(a->state){ + case AsconWriting: + if(a->wrPos < GetDynStringLength(a->wrBuffer)){ + ret = AsconWriteChars(a->fd,GetCharArray(a->wrBuffer)+a->wrPos,1); + if (ret < 0) { + AsconError(a, "ASC4", errno); /* sets state to AsconFailed */ + return 0; + } else { + a->wrPos++; + a->private = (void *)1; + a->state = AsconReading; + a->start = DoubleTime(); + } + break; + } else { + a->private = NULL; + a->state = AsconWriteDone; + } + break; + case AsconReading: + /** + * Here I rely on the fact that the base + * handler, in AsconReadStart, clears the + * rdBuffer of amassed echo characters. + */ + ret = AsconStdHandler(a); + if(ret == 1){ + if(a->private != NULL){ + a->state = AsconWriting; + } + } + return ret; + break; + default: + return AsconStdHandler(a); + } + return 1; +} +/*------------------------------------------------------------------------*/ +void AddCharByCharProtocoll() +{ + AsconProtocol *prot = NULL; + + prot = calloc(sizeof(AsconProtocol), 1); + prot->name = strdup("charbychar"); + prot->init = AsconStdInit; + prot->handler = CharByCharHandler; + AsconInsertProtocol(prot); +} diff --git a/cnvrt.c b/cnvrt.c new file mode 100644 index 00000000..0a1f040c --- /dev/null +++ b/cnvrt.c @@ -0,0 +1,105 @@ +#include +#include +#include +#include "sics.h" + +/* + * conversions: + * hex2float + * float2hex + * + * Markus Zolliker Aug 2010 + */ + +/*-------------------------------------------------------------------------*/ +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; +} + +/*-------------------------------------------------------------------------*/ +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); +} + +/*-------------------------------------------------------------------------*/ +int CnvrtAction(SConnection *con, SicsInterp *sics, void *data, + int argc, char *argv[]) { + double f; + char ieee[4]; + char result[32]; + + if (argc != 3) goto Usage; + if (strcasecmp(argv[1], "float2xieee") == 0) { + double2ieee(atof(argv[2]), ieee); + SCPrintf(con, eValue, "%2.2x%2.2x%2.2x%2.2x", + ieee[0] & 0xFF, ieee[1] & 0xFF, ieee[2] & 0xFF, ieee[3] & 0xFF); + return 1; + } else if (strcasecmp(argv[1], "xieee2float") == 0) { + ieee[0]=0; + ieee[1]=0; + ieee[2]=0; + ieee[3]=0; + sscanf(argv[2], "%2hhx%2hhx%2hhx%2hhx", + ieee, ieee+1, ieee+2, ieee+3); + snprintf(result, sizeof result, "%.7g", ieee2double(ieee)); + if (strchr(result, '.') == NULL && strchr(result, 'e') == NULL) { + SCPrintf(con, eValue, "%s.", result); + } else { + SCWrite(con, result, eValue); + } + return 1; + } + Usage: + SCPrintf(con, eError, "ERROR: Usage: cnvrt float2xieee "); + SCPrintf(con, eError, " cnvrt xieee2float "); + return 0; +} diff --git a/cnvrt.h b/cnvrt.h new file mode 100644 index 00000000..e1f6df27 --- /dev/null +++ b/cnvrt.h @@ -0,0 +1,6 @@ +/* convert double to IEEE 32 bit floating number and vice versa + (denormalized numbers are considered as zero) */ + +void double2ieee(double input, char ieee[4]); +double ieee2double(char ieee[4]); + diff --git a/macro.c b/macro.c index 4e5ac5e1..a61e58c5 100644 --- a/macro.c +++ b/macro.c @@ -1095,44 +1095,3 @@ int TransactAction(SConnection * pCon, SicsInterp * pSics, void *pData, SCWrite(pCon, "TRANSACTIONFINISHED", eLog); return iRet; } -/*-----------------------------------------------------------------------------*/ -int CaptureAction(SConnection *pCon, SicsInterp * pSics, void *pData, - int argc, char *argv[]) -{ - SConnection *comCon = NULL; - char buffer[1024]; - char *command; - int status; - pDynString reply = NULL; - - if (argc < 2) { - SCWrite(pCon, "ERROR: insufficient arguments to capture", eError); - return 0; - } - - comCon = SCCopyConnection(pCon); - if (comCon == NULL) { - SCWrite(pCon, "ERROR: out of memory in capture", eError); - return 0; - } - /* - * This line is required to support nested captures - */ - comCon->data = NULL; - - memset(buffer, 0, sizeof(buffer)); - command = Arg2Tcl(argc - 1, &argv[1], buffer, sizeof buffer); - if (!command) { - SCWrite(pCon, "ERROR: no more memory", eError); - return 0; - } - SCStartBuffering(comCon); - status = InterpExecute(pSics, comCon, command); - if (command != buffer) - free(command); - reply = SCEndBuffering(comCon); - SCWrite(pCon,GetCharArray(reply), eValue); - SCDeleteConnection(comCon); - return status; - -} diff --git a/make_gen b/make_gen index 55ee30b8..1c875842 100644 --- a/make_gen +++ b/make_gen @@ -46,7 +46,8 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \ rwpuffer.o asynnet.o background.o countersec.o hdbtable.o velosec.o \ histmemsec.o sansbc.o sicsutil.o strlutil.o genbinprot.o trace.o\ singlebinb.o taskobj.o sctcomtask.o tasmono.o multicountersec.o \ - messagepipe.o sicsget.o remoteobject.o + messagepipe.o sicsget.o remoteobject.o pmacprot.o charbychar.o binprot.o \ + cnvrt.o MOTOROBJ = motor.o simdriv.o COUNTEROBJ = countdriv.o simcter.o counter.o diff --git a/nxdict.c b/nxdict.c index f080d2c0..23ec3629 100644 --- a/nxdict.c +++ b/nxdict.c @@ -1,7 +1,6 @@ - /*--------------------------------------------------------------------------- Nexus Dictionary API implementation file. @@ -696,6 +695,18 @@ static void NXDIAttValue(ParDat * sStat) sStat->pToken[0] = *(sStat->pPtr); sStat->pPtr++; return; + } else if(*(sStat->pPtr) == '"') { + sStat->pPtr++; + sStat->iToken = DWORD; + i= 0; + while(*(sStat->pPtr) != '"') { + sStat->pToken[i] = *(sStat->pPtr); + sStat->pPtr++; + i++; + } + sStat->pToken[i] = '\0'; + sStat->pPtr++; + return; } else { sStat->iToken = DWORD; /* copy word to pToken */ @@ -820,6 +831,10 @@ static int NXDIParseAttr(ParDat * pParse, int iList) } strcpy(sAtt.name, pParse->pToken); + if(strstr(sAtt.name,"offset") != NULL){ + printf("%s \n",sAtt.name); + } + /* a , is expected */ NXDIDefToken(pParse); if (pParse->iToken != DKOMMA) { diff --git a/ofac.c b/ofac.c index 88867250..e7a9ffd2 100644 --- a/ofac.c +++ b/ofac.c @@ -46,6 +46,9 @@ static void InitGeneral(void) INIT(AddTestProt); INIT(AddGenBinProtocoll); INIT(AddSyncedProt); + INIT(AddBinProtocol); + INIT(AddPMACProtocoll); + INIT(AddCharByCharProtocoll); INIT(MakeTrace); INIT(InitTaskOBJ); INIT(RemoteObjectInit); @@ -72,7 +75,6 @@ static void InitIniCommands(SicsInterp * pInter) /* permanent commands in alphabetic order */ PCMD("alias", MakeAlias); PCMD("broadcast", Broadcast); - PCMD("Capture", CaptureAction); PCMD("ClientPut", ClientPut); PCMD("ClientLog", ClientLog); PCMD("config", ConfigCon); diff --git a/pmacprot.c b/pmacprot.c new file mode 100644 index 00000000..7d645c10 --- /dev/null +++ b/pmacprot.c @@ -0,0 +1,224 @@ +/** + * This is an asynchronous protocol driver for the Delta-Tau PMAC + * series of controllers, connected via TCP/IP. The PMAC needs its + * commands in a special purpose data structure, describe below. + * As responses, it can send any of the following formats: + * datadatadata>CR> + * ERRxxx + * data + * There can be multiple data and errors in a string. However, I wish to + * restrict this to processing one command at any time. This driver owes + * some insight and little code to the EPICS driver by + * Pete Leicester, Diamond. + * + * ** Before this can be used, I3=2 and I6=1 must be set on the PMAC ** + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, December 2008 + * + * Introduced a delay on read in order to throttle requests + * + * Mark Koennecke, June 2011 + */ +#include +#include +#include +#include + +#define ETHERNET_DATA_SIZE 1492 +#define INPUT_SIZE (ETHERNET_DATA_SIZE+1) /* +1 to allow space to add terminating ACK */ +#define STX '\2' +#define CTRLB '\2' +#define CTRLC '\3' +#define ACK '\6' +#define CTRLF '\6' +#define BELL '\7' +#define CTRLG '\7' +#define CTRLP '\16' +#define CTRLV '\22' +#define CTRLX '\24' + +/* PMAC ethernet command structure */ +#pragma pack(1) +typedef struct tagEthernetCmd { + unsigned char RequestType; + unsigned char Request; + unsigned short wValue; + unsigned short wIndex; + unsigned short wLength; /* length of bData */ + unsigned char bData[ETHERNET_DATA_SIZE]; +} ethernetCmd; +#pragma pack() + +#define ETHERNET_CMD_HEADER ( sizeof(ethernetCmd) - ETHERNET_DATA_SIZE ) + +/* PMAC ethernet commands - RequestType field */ +#define VR_UPLOAD 0xC0 +#define VR_DOWNLOAD 0x40 + +/* PMAC ethernet commands - Request field */ +#define VR_PMAC_SENDLINE 0xB0 +#define VR_PMAC_GETLINE 0xB1 +#define VR_PMAC_FLUSH 0xB3 +#define VR_PMAC_GETMEM 0xB4 +#define VR_PMAC_SETMEN 0xB5 +#define VR_PMAC_SETBIT 0xBA +#define VR_PMAC_SETBITS 0xBB +#define VR_PMAC_PORT 0xBE +#define VR_PMAC_GETRESPONSE 0xBF +#define VR_PMAC_READREADY 0xC2 +#define VR_CTRL_RESPONSE 0xC4 +#define VR_PMAC_GETBUFFER 0xC5 +#define VR_PMAC_WRITEBUFFER 0xC6 +#define VR_PMAC_WRITEERROR 0xC7 +#define VR_FWDOWNLOAD 0xCB +#define VR_IPADDRESS 0xE0 + +/*--------------------------------------------------------------------------- + * a private data structurli to keep track of the PMAC + *---------------------------------------------------------------------------*/ +typedef struct { + ethernetCmd cmd; + char *ptr; + int bytesToWrite; + int expectACK; + double startTime; +} PMACPrivate, *pPMACPrivate; +/*---------------------------------------------------------------------------* +* wait period before read + ----------------------------------------------------------------------------*/ +#define READDELAY .05 +/*---------------------------------------------------------------------------*/ +static int PMACHandler(Ascon * a) +{ + char *data = NULL; + int ret, l; + char chr; + pPMACPrivate priv = NULL; + + priv = a->private; + + switch (a->state) { + case AsconWriteStart: + data = GetCharArray(a->wrBuffer); + memset(priv, 0, sizeof(PMACPrivate)); + priv->cmd.RequestType = VR_DOWNLOAD; + priv->cmd.Request = VR_PMAC_GETRESPONSE; + priv->cmd.wValue = 0; + priv->cmd.wIndex = 0; + priv->cmd.wLength = htons(strlen(data)); /* may be one more */ + priv->bytesToWrite = strlen(data) + 1 + ETHERNET_CMD_HEADER; + strcpy((char *) priv->cmd.bData, data); + priv->expectACK = 1; + priv->ptr = (char *) &priv->cmd; + a->state = AsconWriting; + a->wrPos = 0; + break; + case AsconWriting: + AsconReadGarbage(a->fd); + l = priv->bytesToWrite - a->wrPos; + ret = AsconWriteChars(a->fd, priv->ptr, l); + if (ret < 0) { + if (errno != EINTR && errno != EAGAIN) { + AsconError(a, "send failed:", errno); + } + /* + * Ooops: which state shall we go to after a write fail? + * This seems to retry. + */ + } else { + a->wrPos += ret; + if (a->wrPos >= priv->bytesToWrite) { + a->state = AsconWriteDone; + priv->startTime = DoubleTime(); + } else { + priv->ptr += ret; + } + } + break; + case AsconReadStart: + DynStringClear(a->rdBuffer); + if(DoubleTime() > priv->startTime + READDELAY){ + a->start = DoubleTime(); + a->state = AsconReading; + } + break; + case AsconReading: + ret = AsconReadChar(a->fd, &chr); + if (ret < 0) { + /* EINTR means we must retry */ + if (errno != EINTR && errno != EAGAIN) { + AsconError(a, "AsconReadChar failed:", errno); + } + return 1; + } else if (ret > 0) { + a->start = DoubleTime(); + if (chr == STX || chr == BELL) { + priv->expectACK = 0; + return 1; + } + if (priv->expectACK && chr == ACK) { + if (GetDynStringLength(a->rdBuffer) == 0) { + DynStringConcat(a->rdBuffer, "ACK"); + } + DynStringConcatChar(a->rdBuffer, '\0'); + a->state = AsconReadDone; + break; + } + if (priv->expectACK == 0 && chr == '\r') { + DynStringConcatChar(a->rdBuffer, '\0'); + a->state = AsconReadDone; + break; + } + if (DynStringConcatChar(a->rdBuffer, chr) == 0) { + AsconError(a, "DynStringConcatChar failed:", ENOMEM); + break; + } + } else if (ret == 0) { + if (a->timeout > 0) { + if (DoubleTime() - a->start > a->timeout) { + AsconError(a, "read timeout", 0); + a->state = AsconTimeout; + } + } + return 0; + } + break; + default: + return AsconStdHandler(a); + } + return 1; +} + +/*------------------------------------------------------------------------*/ +static int PMACInit(Ascon * a, SConnection * con, int argc, char *argv[]) +{ + pPMACPrivate priv = NULL; + + priv = calloc(sizeof(PMACPrivate), 1); + a->fd = -1; + a->state = AsconConnectStart; + a->reconnectInterval = 10; + a->hostport = strdup(argv[1]); + if (argc > 2) { + a->timeout = atof(argv[2]); + } else { + a->timeout = 2.0; /* sec */ + } + a->private = priv; + a->killPrivate = free; + return 1; +} + +/*------------------------------------------------------------------------*/ +void AddPMACProtocoll() +{ + AsconProtocol *prot = NULL; + + prot = calloc(sizeof(AsconProtocol), 1); + prot->name = strdup("pmac"); + prot->init = PMACInit; + prot->handler = PMACHandler; + AsconInsertProtocol(prot); +} diff --git a/protocol.c b/protocol.c index 73ddbc71..9891913d 100644 --- a/protocol.c +++ b/protocol.c @@ -21,7 +21,7 @@ #define MAXMSG 1024 #define INIT_STR_SIZE 256 #define STR_RESIZE_LENGTH 256 -#define NUMPROS 7 +#define NUMPROS 6 #define PROLISTLEN 8 typedef struct __Protocol { pObjectDescriptor pDes; /* required as first field */ @@ -97,7 +97,6 @@ pProtocol CreateProtocol(void) char *pPros[] = { "default", "normal", "withcode", - "sycamore", "json", "act", "all", @@ -282,19 +281,15 @@ static int ProtocolSet(SConnection * pCon, Protocol * pPro, char *pProName) SCSetWriteFunc(pCon, SCWriteWithOutcode); break; - case 3: /* sycamore */ - SCSetWriteFunc(pMaster, SCWriteSycamore); - SCSetWriteFunc(pCon, SCWriteSycamore); - break; - case 4: /* json */ + case 3: /* json */ SCSetWriteFunc(pCon, SCWriteJSON_String); SCSetWriteFunc(pMaster, SCWriteJSON_String); break; - case 5: /* ACT */ + case 4: /* ACT */ SCSetWriteFunc(pMaster, SCACTWrite); SCSetWriteFunc(pCon, SCACTWrite); break; - case 6: + case 5: SCSetWriteFunc(pMaster, SCAllWrite); SCSetWriteFunc(pCon, SCAllWrite); break; @@ -340,9 +335,8 @@ int ProtocolGet(SConnection * pCon, void *pData, char *pProName, int len) case 0: /* default = psi_sics */ case 1: /* normal (connection start default) */ case 2: /* outcodes */ - case 3: /* sycamore */ - case 4: /* json */ - case 5: /* act */ + case 3: /* json */ + case 4: /* act */ pProName = pPro->pProList[Index]; return 1; break; @@ -451,133 +445,7 @@ static int InitDefaultProtocol(SConnection * pCon, Protocol * pPro) } return pPro->isDefaultSet; } - -/*---------------------------------------------------------------------*/ -void sycformat(char *tag, OutCode msgFlag, pDynString msgString, - pDynString msgOut) -{ - DynStringConcat(msgOut, " "); - switch (msgFlag) { - eEvent: - break; - eFinish: - break; - default: - DynStringConcat(msgOut, tag); - DynStringConcat(msgOut, "={"); - DynStringConcat(msgOut, GetCharArray(msgString)); - DynStringConcat(msgOut, "}"); - break; - } -} -int SCWriteSycamore(SConnection * pCon, char *pBuffer, int iOut) -{ - int iRet; - char pBueffel[MAXMSG]; - long taskID = 0; -/* char pPrefix[40];*/ - pDynString pMsg = NULL; - pDynString pMsgString = NULL; - commandContext comCon; - - - if (strlen(pBuffer) == 0) { - return 0; - } - - if (!SCVerifyConnection(pCon)) { - return 0; - } - - /* log it for any case */ - if (pCon->pSock) { - iRet = pCon->pSock->sockid; - } else { - iRet = 0; - } - snprintf(pBueffel,sizeof(pBueffel)-1, "Next line intended for socket: %d", iRet); - SICSLogWrite(pBueffel, eInternal); - SICSLogWrite(pBuffer, iOut); - - /* write to commandlog if user or manager privilege */ - if (SCGetRights(pCon) <= usUser) { - WriteToCommandLogId(NULL, iRet, pBuffer); - } - - /* put it into the interpreter if present */ - if (SCinMacro(pCon)) { - InterpWrite(pServ->pSics, pBuffer); - /* print it to client if error message */ - /* FIXME should report errors via sycamore - if((iOut== eError) || (iOut == eWarning) ) - iRet = SCDoSockWrite(pCon,GetCharArray(pMsgOut)); */ - } else { /* not in interpreter, normal logic */ - - comCon = SCGetContext(pCon); - - /* Return 0 without dying if no message data */ - if (pBuffer == NULL) { - return 0; - } - - taskID = comCon.transID; - - pMsg = CreateDynString(INIT_STR_SIZE, STR_RESIZE_LENGTH); - pMsgString = CreateDynString(INIT_STR_SIZE, STR_RESIZE_LENGTH); - pBueffel[0] = '\0'; - - snprintf(pBueffel,sizeof(pBueffel)-1, "[con%4.4d:", (int) pCon->ident); /* field 1: connID */ - DynStringConcat(pMsg, pBueffel); - snprintf(pBueffel,sizeof(pBueffel)-1, "t%6.6d:", (int) taskID); /* field 2: taskID */ - DynStringConcat(pMsg, pBueffel); - /* deviceID */ - DynStringConcat(pMsg, comCon.deviceID); - DynStringConcatChar(pMsg, ':'); - - /* msgFlag */ - switch (iOut) { - case 5: /* eValue */ - DynStringConcat(pMsg, "out"); - break; - default: - DynStringConcat(pMsg, pCode[iOut]); - break; - } - DynStringConcatChar(pMsg, ']'); - if (iOut == eStart) { - DynStringConcat(pMsgString, comCon.deviceID); - } - - if (iOut == eEvent) { - DynStringConcat(pMsgString, " type="); - /* Default type to VALUECHANGE if conEventType not set */ - if (-1 == pCon->conEventType) - DynStringConcat(pMsgString, pEventType[0]); - else - DynStringConcat(pMsgString, pEventType[pCon->conEventType]); -/* DynStringConcat(pMsgString, " status="); - DynStringConcat(pMsgString, pStatus[pCon->conStatus]);*/ - DynStringConcat(pMsgString, ","); - } - DynStringConcat(pMsgString, " "); - DynStringConcat(pMsgString, pBuffer); - sycformat(comCon.deviceID, iOut, pMsgString, pMsg); - - /* is this really to be printed ? */ - if (iOut < pCon->iOutput) { - if (pMsg != NULL) - DeleteDynString(pMsg); - return 0; - } - /* first the socket */ - /*strcat(pMsg, pBueffel); */ - iRet = SCDoSockWrite(pCon, GetCharArray(pMsg)); - } - if (pMsg != NULL) - DeleteDynString(pMsg); - return 1; -} - +/*--------------------------------------------------------------------------*/ /* Only work for hipadaba commands, hlist, hset, hget, hnotify * A multiline string (ie have crnl) will be converted to an array. * Strings with '=' will be converted to name value pairs @@ -763,8 +631,7 @@ char *GetProtocolName(SConnection * pCon) case 0: /* default = psi_sics */ case 1: /* normal (connection start default) */ case 2: /* outcodes */ - case 3: /* sycamore */ - case 4: /* json */ + case 3: /* json */ return strdup(pPro->pProList[pCon->iProtocolID]); break; default: @@ -790,13 +657,10 @@ writeFunc GetProtocolWriteFunc(SConnection * pCon) case 2: /* outcodes */ return SCWriteWithOutcode; break; - case 3: /* sycamore */ - return SCWriteSycamore; - break; - case 4: /* json */ + case 3: /* json */ return SCWriteJSON_String; break; - case 5: + case 4: return SCACTWrite; break; default: diff --git a/protocol.h b/protocol.h index 53537abc..4151b4f7 100644 --- a/protocol.h +++ b/protocol.h @@ -24,9 +24,6 @@ void MakeProtocol(void); /*--------------------- operations --------------------------------------*/ int ProtocolAction(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]); -/*--------------------- implement protocol sycamore ---------------------*/ -int SCWriteSycamore(SConnection * pCon, char *pBuffer, int iOut); - /*--------------------- implement protocol API -----------------------*/ char *GetProtocolName(SConnection * pCon); int GetProtocolID(SConnection * pCon); diff --git a/simindex.c b/simindex.c index 97aa4b19..0a5fce25 100644 --- a/simindex.c +++ b/simindex.c @@ -167,6 +167,88 @@ static int RunIndexCmd(pSICSOBJ self, SConnection * pCon, pHdb commandNode, return status; } +/*----------------------------------------------------------------------*/ +static void InternalOutFunc(void *data, char *text) +{ + pDynString tData = (pDynString) data; + if (tData!= NULL) { + DynStringConcat(tData, text); + } +} +/*-------------------------------------------------------------------------*/ +static int RunIntIndexCmd(pSICSOBJ self, SConnection * pCon, pHdb commandNode, + pHdb par[], int nPar) +{ + int i, j, status, err; + pSingleDiff diffi; + pSICSOBJ reflist; + double ang[5], z1[3]; + IndexSolution is; + MATRIX ub; + pHdb nSol = NULL; + pDynString tData; + char fString[512]; + + tData = CreateDynString(256,256); + + SimIdxSetLambda(SXGetLambda()); + SimIdxSetCell((double *) SXGetCell()); + SimIdxSetSpacegroup(SXGetSpaceGroup()); + SimIdxOutput(tData, InternalOutFunc, 10); + + reflist = SXGetReflectionList(); + diffi = SXGetDiffractometer(); + SimIdxClearReflection(); + for (i = 0; i < ReflectionListCount(reflist); i++) { + GetRefAngles(reflist, i, ang); + diffi->calcZ1(diffi, GetRefName(reflist, i), z1); + SimIdxAddReflection(z1); + } + + nSol = GetHipadabaNode(self->objectNode,"nsolutions"); + assert(nSol != NULL); + + status = SimIdxRun(); + filterSolutions(); + if (status == 1) { + if (SimIdxGetNSolutions() < 1) { + DynStringConcat(tData,"No solutions were found\n"); + UpdateHipadabaPar(nSol,MakeHdbInt(0), pCon); + return 0; + } + DynStringConcat(tData, "Indexing Suggestions:\n"); + UpdateHipadabaPar(nSol,MakeHdbInt(SimIdxGetNSolutions()), pCon); + for (i = 0; i < SimIdxGetNSolutions(); i++) { + is = SimIdxGetSolution(i); + + snprintf(fString,sizeof(fString), "Solution No : %d, GOF = %6.3f\n", i, + is.diff * 100); + DynStringConcat(tData,fString); + for (j = 0; j < 3; j++) { + if (is.originalID[j] != 999) { + snprintf(fString,sizeof(fString)," Ref = %2d, HKL = %4d %4d %4d \n", + is.originalID[j], is.h[j], is.k[j], is.l[j]); + DynStringConcat(tData,fString); + } + } + SCPrintf(pCon,eLog," UB:"); + DynStringConcat(tData," UB\n"); + ub = calcUBForSolution(is,&err); + if(ub != NULL) { /* should never happen, as filtered */ + for(j = 0; j < 3; j++){ + snprintf(fString,sizeof(fString)," %8.5f %8.5f %8.5f\n", + ub[j][0], ub[j][1], ub[j][2]); + DynStringConcat(tData,fString); + } + } + } + } + + SCWrite(pCon,GetCharArray(tData),eValue); + DeleteDynString(tData); + return status; +} + /*-----------------------------------------------------------------------*/ static int ChooseCmd(pSICSOBJ self, SConnection * pCon, pHdb commandNode, pHdb par[], int nPar) @@ -315,6 +397,9 @@ void InitSimpleIndex(SConnection * pCon, SicsInterp * pSics) cmd = AddSICSHdbPar(pNew->objectNode, "run", usUser, MakeSICSFunc(RunIndexCmd)); + cmd = AddSICSHdbPar(pNew->objectNode, "runint", usUser, + MakeSICSFunc(RunIntIndexCmd)); + cmd = AddSICSHdbPar(pNew->objectNode, "choose", usUser, MakeSICSFunc(ChooseCmd)); cmd = AddSICSHdbPar(cmd, "solution", usUser, MakeHdbInt(0));