- Removed defunct capture command

- Moved some protocolls from sicspsi to kernel as discussed at ANSTO
This commit is contained in:
2015-04-20 09:08:34 +02:00
parent c2f08097da
commit e577d9c313
5 changed files with 889 additions and 42 deletions

589
binprot.c Normal file
View File

@ -0,0 +1,589 @@
#include <ctype.h>
#include <math.h>
#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<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
*
* 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; i<l; i++) {
byte = str[i];
sum += byte;
switch (byte) {
case 0x02:
DynStringConcatChar(dyn, 0x07);
DynStringConcatChar(dyn, '0');
break;
case 0x0d:
DynStringConcatChar(dyn, 0x07);
DynStringConcatChar(dyn, '1');
break;
case 0x07:
DynStringConcatChar(dyn, 0x07);
DynStringConcatChar(dyn, '2');
break;
default:
DynStringConcatChar(dyn, byte);
}
}
DynStringConcatChar(dyn, 0x30 + (sum / 16));
DynStringConcatChar(dyn, 0x30 + (sum % 16));
DynStringConcatChar(dyn, 0x0d);
free(str);
}
/*----------------------------------------------------------------------------*/
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) {
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);
}

73
charbychar.c Normal file
View File

@ -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 <errno.h>
#include <ascon.h>
#include <ascon.i>
/*-----------------------------------------------------------
* 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);
}

41
macro.c
View File

@ -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;
}

4
ofac.c
View File

@ -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);

224
pmacprot.c Normal file
View File

@ -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:
* data<CR>data<CR>data>CR><ACK>
* <BELL>ERRxxx<CR>
* <STX>data<CR>
* 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 <errno.h>
#include <ascon.h>
#include <ascon.i>
#include <dynstring.h>
#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);
}