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/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/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); +}