Reworked AsyncQueue sendCommand processing
Squashed commit of the following: commit 42fb7d3cde591d40060cc740ccbc47f1ae7a5a50 Author: Douglas Clowes <dcl@ansto.gov.au> Date: Tue Aug 26 13:31:11 2014 +1000 Get the MODBUS_AP working commit da785c1434a04c4186d4174eb2dfbaefc850c8e7 Author: Douglas Clowes <dcl@ansto.gov.au> Date: Mon Aug 25 18:01:50 2014 +1000 Bring Modbus protocol closer to Huber, Knauer and Omron commit ef06ed7b6911cb49b35c19fe73e55f7c57cfd049 Author: Douglas Clowes <dcl@ansto.gov.au> Date: Mon Aug 25 18:01:18 2014 +1000 Make Huber, Knauer and Omron protocols more aligned (diffable) commit 3ef1bb06b3f865502ad7dffc4bf5dba4814d9334 Author: Douglas Clowes <dcl@ansto.gov.au> Date: Fri Aug 22 17:47:50 2014 +1000 Get the Huber and Knauer protocols to be more alike commit 2c9932e83f6735e894278648afdcadece654d43b Author: Douglas Clowes <dcl@ansto.gov.au> Date: Fri Aug 22 17:12:31 2014 +1000 Clean up the Knauer dual-mode protocol and refactor commit 333300b19b0e61916e261300ac6ae2b6bab5df09 Author: Douglas Clowes <dcl@ansto.gov.au> Date: Thu Aug 21 15:38:39 2014 +1000 Get the Knauer dual-mode protocol working(-ish) commit b1f9d82f1b9eb8a1ff54694adc3482984b0d3d72 Author: Douglas Clowes <dcl@ansto.gov.au> Date: Thu Aug 21 15:37:44 2014 +1000 Make private functions static (and not duplicated) commit 0b077414eef9e4351956a2b971d7751cced0d3cd Author: Douglas Clowes <dcl@ansto.gov.au> Date: Thu Aug 21 12:46:10 2014 +1000 Knauer moving toward dual protocol commit 13199bea38a1595ce06923e83474b738b10db94d Author: Douglas Clowes <dcl@ansto.gov.au> Date: Thu Aug 21 12:42:48 2014 +1000 Restructure default sendCommand processing in asyncqueue commit 99a8ea3174ca0636503b0ce0cdb6016790315558 Author: Douglas Clowes <dcl@ansto.gov.au> Date: Thu Aug 21 09:48:50 2014 +1000 Add a Modbus Protocol handler derived from sct_tcpmodbus commit 3adf49fb7c8402c8260a0bb20729d551ac88537b Author: Douglas Clowes <dcl@ansto.gov.au> Date: Thu Aug 21 09:43:54 2014 +1000 Leave the free of private data to the asyncqueue mechanism
This commit is contained in:
@ -394,7 +394,16 @@ static int StartCommand(pAsyncQueue self)
|
||||
}
|
||||
|
||||
myCmd->tran->txn_status = ATX_ACTIVE;
|
||||
if (self->protocol->sendCommand) {
|
||||
iRet = self->protocol->sendCommand(self->protocol, myCmd->tran);
|
||||
} else {
|
||||
pAsyncTxn txn = myCmd->tran;
|
||||
iRet = AsyncUnitWrite(txn->unit, txn->out_buf, txn->out_len);
|
||||
if (iRet < 0)
|
||||
iRet = 0;
|
||||
else
|
||||
iRet = 1;
|
||||
}
|
||||
/*
|
||||
* Handle case of no response expected
|
||||
*/
|
||||
|
@ -20,17 +20,6 @@
|
||||
enum replystates {START, HEADER, CHKHEADEREND, MSG};
|
||||
static pAsyncProtocol OPAL_Protocol = NULL;
|
||||
|
||||
static int OPAL_Tx(pAsyncProtocol p, pAsyncTxn txn) {
|
||||
if (txn == NULL) {
|
||||
return 0;
|
||||
}
|
||||
txn->txn_status = ATX_ACTIVE;
|
||||
if (AsyncUnitWrite(txn->unit, txn->out_buf, txn->out_len) < 0) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* The header and message are followed by the character sequences given below,
|
||||
* HEADER cr lf cr lf <msg len> cr lf
|
||||
* MESSAGE cr lf 0x30 cr lf cr lf
|
||||
@ -137,7 +126,7 @@ static int OPAL_PrepareTxn(pAsyncProtocol p, pAsyncTxn txn, const char* cmd, int
|
||||
void OpalStatusInitProtocol(SicsInterp *pSics) {
|
||||
if (OPAL_Protocol == NULL) {
|
||||
OPAL_Protocol = AsyncProtocolCreate(pSics, "OPALSTAT", NULL, NULL);
|
||||
OPAL_Protocol->sendCommand = OPAL_Tx;
|
||||
OPAL_Protocol->sendCommand = NULL;
|
||||
OPAL_Protocol->handleInput = OPAL_Rx;
|
||||
OPAL_Protocol->killPrivate = NULL;
|
||||
OPAL_Protocol->handleEvent = OPAL_Ev;
|
||||
|
@ -183,18 +183,6 @@ static void CAM_Notify(void* context, int event) {
|
||||
return;
|
||||
}
|
||||
|
||||
static int CAM_Tx(pAsyncProtocol p, pAsyncTxn txn) {
|
||||
|
||||
if (txn == NULL) {
|
||||
return 0;
|
||||
}
|
||||
txn->txn_status = ATX_ACTIVE;
|
||||
if (AsyncUnitWrite(txn->unit, txn->out_buf, txn->out_len) < 0) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int defaultHandleInput(pAsyncProtocol p, pAsyncTxn txn, int ch);
|
||||
static int CAM_Rx(pAsyncProtocol p, pAsyncTxn txn, int ch) {
|
||||
int ret = 1;
|
||||
@ -221,7 +209,7 @@ static int CAM_Ev(pAsyncProtocol p, pAsyncTxn pTxn, int event) {
|
||||
void CameraInitProtocol(SicsInterp *pSics) {
|
||||
if (CAM_Protocol == NULL) {
|
||||
CAM_Protocol = AsyncProtocolCreate(pSics, "CAMERA", NULL, NULL);
|
||||
CAM_Protocol->sendCommand = CAM_Tx;
|
||||
CAM_Protocol->sendCommand = NULL;
|
||||
CAM_Protocol->handleInput = CAM_Rx;
|
||||
CAM_Protocol->prepareTxn = NULL;
|
||||
CAM_Protocol->killPrivate = NULL;
|
||||
|
@ -1,80 +1,163 @@
|
||||
#include "huber_asyncprotocol.h"
|
||||
#include "asyncprotocol.h"
|
||||
#include "asyncqueue.h"
|
||||
#include "ascon.i"
|
||||
#include "dynstring.h"
|
||||
#include <errno.h>
|
||||
|
||||
#define PROTOCOL_CONTINUE 0
|
||||
#define PROTOCOL_COMPLETE 1
|
||||
#define PROTOCOL_ERROR (-1)
|
||||
|
||||
/* Sample Messages
|
||||
structure:
|
||||
7B - LEFT BRACE
|
||||
xx - text
|
||||
0D 0A - CR LF
|
||||
*/
|
||||
#define PROTOCOL_NAME "HUBER_AP"
|
||||
#define PROTOCOL_INIT HUBERInitProtocol
|
||||
#define LBRACE '{'
|
||||
#define CR '\r'
|
||||
#define LF '\n'
|
||||
|
||||
/*
|
||||
* Protocol transmit function
|
||||
* Called by AsyncQueue to transmit a line
|
||||
* Protocol Private data block
|
||||
*/
|
||||
static int HUBER_Tx(pAsyncProtocol p, pAsyncTxn pTxn) {
|
||||
int iRet = 1;
|
||||
typedef struct proto_private_t {
|
||||
int state; /**< protocol state machine */
|
||||
int len; /**< length from the protocol */
|
||||
pDynString wrBuffer; /**< transmitted message */
|
||||
pDynString rxBuffer; /**< received message */
|
||||
} ProtoPrivate;
|
||||
|
||||
static ProtoPrivate *makeProtoPrivate()
|
||||
{
|
||||
ProtoPrivate *priv = calloc(sizeof(ProtoPrivate), 1);
|
||||
priv->wrBuffer = CreateDynString(100, 100);
|
||||
priv->rxBuffer = CreateDynString(100, 100);
|
||||
return priv;
|
||||
}
|
||||
|
||||
static ProtoPrivate *Proto_KillPrivate(ProtoPrivate *priv)
|
||||
{
|
||||
if (priv) {
|
||||
if (priv->rxBuffer) {
|
||||
DeleteDynString(priv->rxBuffer);
|
||||
priv->rxBuffer = NULL;
|
||||
}
|
||||
free(priv);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pTxn) {
|
||||
pTxn->txn_status = ATX_ACTIVE;
|
||||
iRet = AsyncUnitWrite(pTxn->unit, pTxn->out_buf, pTxn->out_len);
|
||||
/* TODO handle errors */
|
||||
if (iRet < 0) { /* TODO: EOF */
|
||||
/*
|
||||
iRet = AsyncUnitReconnect(pTxn->unit);
|
||||
if (iRet == 0)
|
||||
* Protocol Specific Support Functions
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
/*
|
||||
* Protocol Prepare Output
|
||||
*/
|
||||
static int Proto_Prepare(ProtoPrivate *priv, pDynString wrBuffer)
|
||||
{
|
||||
DynStringInsert(wrBuffer, "{", 0);
|
||||
DynStringConcatChar(wrBuffer, CR);
|
||||
DynStringConcatChar(wrBuffer, LF);
|
||||
return PROTOCOL_COMPLETE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Protocol receive character - characater by character
|
||||
*/
|
||||
static int HUBER_Rx(pAsyncProtocol p, pAsyncTxn pTxn, int rxchar) {
|
||||
int iRet = 1;
|
||||
|
||||
switch (pTxn->txn_state) {
|
||||
case 0: /* first character */
|
||||
static int Proto_RxChar(ProtoPrivate *priv, int rxchar)
|
||||
{
|
||||
enum RX_STATE {
|
||||
RX_START=0,
|
||||
RX_TEXT=1,
|
||||
RX_LAST=2, /* LF */
|
||||
RX_STOP=99
|
||||
};
|
||||
rxchar &= 0xFF;
|
||||
switch (priv->state) {
|
||||
case RX_START:
|
||||
if (rxchar != LBRACE) {
|
||||
/* TODO: error */
|
||||
pTxn->txn_state = 99;
|
||||
pTxn->txn_status = ATX_COMPLETE;
|
||||
break;
|
||||
priv->state = RX_STOP;
|
||||
return PROTOCOL_ERROR;
|
||||
}
|
||||
/* normal data */
|
||||
pTxn->txn_state = 1;
|
||||
/* note fallthrough */
|
||||
case 1: /* receiving reply */
|
||||
if (pTxn->inp_idx < pTxn->inp_len)
|
||||
pTxn->inp_buf[pTxn->inp_idx++] = rxchar;
|
||||
if (rxchar == CR)
|
||||
pTxn->txn_state = 2;
|
||||
break;
|
||||
case 2: /* receiving LF */
|
||||
if (pTxn->inp_idx < pTxn->inp_len)
|
||||
pTxn->inp_buf[pTxn->inp_idx++] = rxchar;
|
||||
if (rxchar != LF) {
|
||||
/* TODO: error */
|
||||
priv->state = RX_TEXT;
|
||||
return PROTOCOL_CONTINUE;
|
||||
case RX_TEXT:
|
||||
if (rxchar == CR) {
|
||||
priv->state = RX_LAST;
|
||||
return PROTOCOL_CONTINUE;
|
||||
}
|
||||
pTxn->txn_state = 99;
|
||||
pTxn->inp_idx -= 3;
|
||||
memmove(pTxn->inp_buf, pTxn->inp_buf + 1, pTxn->inp_idx);
|
||||
break;
|
||||
DynStringConcatChar(priv->rxBuffer, rxchar);
|
||||
return PROTOCOL_CONTINUE;
|
||||
case RX_LAST:
|
||||
if (rxchar == LF) {
|
||||
priv->state = RX_STOP;
|
||||
return PROTOCOL_COMPLETE;
|
||||
} else {
|
||||
priv->state = RX_STOP;
|
||||
return PROTOCOL_ERROR;
|
||||
}
|
||||
if (pTxn->txn_state == 99) {
|
||||
iRet = 0;
|
||||
|
||||
default:
|
||||
return PROTOCOL_ERROR;
|
||||
}
|
||||
if (iRet == 0) { /* end of command */
|
||||
return PROTOCOL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* AsyncProtocol handling
|
||||
* ======================
|
||||
*/
|
||||
|
||||
static void Async_KillPrivate(pAsyncTxn pTxn)
|
||||
{
|
||||
Proto_KillPrivate((ProtoPrivate *) pTxn->proto_private);
|
||||
pTxn->proto_private = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* AsyncProtocol Receive Character
|
||||
*/
|
||||
static int Async_Rx(pAsyncProtocol p, pAsyncTxn pTxn, int rxchar) {
|
||||
int iRet, str_len;
|
||||
ProtoPrivate *priv = (ProtoPrivate *) pTxn->proto_private;
|
||||
|
||||
iRet = Proto_RxChar(priv, rxchar);
|
||||
/*
|
||||
* Keep inp_buf and inp_idx up-to-date after each character
|
||||
*/
|
||||
str_len = GetDynStringLength(priv->rxBuffer);
|
||||
if (str_len > pTxn->inp_idx && pTxn->inp_idx < pTxn->inp_len) {
|
||||
int xfr_len;
|
||||
char *tgt = &pTxn->inp_buf[pTxn->inp_idx];
|
||||
char *loc = &GetCharArray(priv->rxBuffer)[pTxn->inp_idx];
|
||||
if (str_len > pTxn->inp_len)
|
||||
xfr_len = pTxn->inp_len - pTxn->inp_idx;
|
||||
else
|
||||
xfr_len = str_len - pTxn->inp_idx;
|
||||
memcpy(tgt, loc, xfr_len);
|
||||
pTxn->inp_idx += xfr_len;
|
||||
}
|
||||
|
||||
if (iRet == PROTOCOL_CONTINUE) {
|
||||
return 1; /* Keep Going */
|
||||
}
|
||||
|
||||
if (iRet == PROTOCOL_ERROR) {
|
||||
return -1; /* Error condition */
|
||||
}
|
||||
|
||||
/* Message Complete */
|
||||
return AQU_POP_CMD;
|
||||
}
|
||||
return iRet;
|
||||
}
|
||||
|
||||
/*
|
||||
* AsyncProtocol Event callback
|
||||
*/
|
||||
static int HUBER_Ev(pAsyncProtocol p, pAsyncTxn pTxn, int event) {
|
||||
static int Async_Ev(pAsyncProtocol p, pAsyncTxn pTxn, int event) {
|
||||
if (event == AQU_TIMEOUT) {
|
||||
/* handle command timeout */
|
||||
pTxn->txn_status = ATX_TIMEOUT;
|
||||
@ -83,34 +166,168 @@ static int HUBER_Ev(pAsyncProtocol p, pAsyncTxn pTxn, int event) {
|
||||
return AQU_POP_CMD;
|
||||
}
|
||||
|
||||
static int HUBER_PrepareTxn(pAsyncProtocol p, pAsyncTxn pTxn, const char* cmd, int cmd_len, int rsp_len) {
|
||||
int i, bcc;
|
||||
pTxn->out_buf = (char*) malloc(cmd_len + 3);
|
||||
if (pTxn->out_buf == NULL) {
|
||||
SICSLogWrite("ERROR: Out of memory in HUBER_PrepareTxn", eError);
|
||||
/*
|
||||
* AsyncProtocol Prepare Transaction
|
||||
*/
|
||||
static int Async_PrepareTxn(pAsyncProtocol p, pAsyncTxn pTxn, const char* cmd, int cmd_len, int rsp_len) {
|
||||
ProtoPrivate *priv;
|
||||
priv = makeProtoPrivate();
|
||||
if (priv == NULL) {
|
||||
SICSLogWrite("ERROR: Out of memory in Async_PrepareTxn", eError);
|
||||
return 0;
|
||||
}
|
||||
memcpy(pTxn->out_buf + 1, cmd, cmd_len);
|
||||
pTxn->out_buf[0] = LBRACE;
|
||||
pTxn->out_buf[cmd_len + 1] = CR;
|
||||
pTxn->out_buf[cmd_len + 2] = LF;
|
||||
pTxn->out_len = cmd_len + 3;
|
||||
priv->state = 0;
|
||||
priv->len = 0;
|
||||
DynStringConcatBytes(priv->wrBuffer, cmd, cmd_len);
|
||||
Proto_Prepare(priv, priv->wrBuffer);
|
||||
pTxn->out_len = GetDynStringLength(priv->wrBuffer);
|
||||
pTxn->out_buf = (char*) malloc(pTxn->out_len);
|
||||
if (pTxn->out_buf == NULL) {
|
||||
SICSLogPrintf(eError, "ERROR: Out of memory in %s:%s", __FILE__, __FUNCTION__);
|
||||
Proto_KillPrivate(priv);
|
||||
return 0;
|
||||
}
|
||||
pTxn->proto_private = priv;
|
||||
pTxn->kill_private = Async_KillPrivate;
|
||||
memcpy(pTxn->out_buf, GetCharArray(priv->wrBuffer), pTxn->out_len);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static pAsyncProtocol HUBER_Protocol = NULL;
|
||||
/*
|
||||
* Ascon Protocol handling
|
||||
* =======================
|
||||
*/
|
||||
|
||||
static void Ascon_KillPrivate(void *priv)
|
||||
{
|
||||
Proto_KillPrivate((ProtoPrivate *) priv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ascon Protocol WriteStart
|
||||
*/
|
||||
static int Ascon_Prepare(Ascon *a) {
|
||||
ProtoPrivate *priv = (ProtoPrivate *) a->private;
|
||||
Proto_Prepare(priv, a->wrBuffer);
|
||||
a->wrPos = 0;
|
||||
a->state = AsconWriting;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ascon Protocol Read Poll
|
||||
*/
|
||||
static int Ascon_Rx(Ascon *a) {
|
||||
int ret, status;
|
||||
char chr = '\0';
|
||||
ProtoPrivate *priv = (ProtoPrivate *) a->private;
|
||||
|
||||
ret = AsconReadChar(a->fd, &chr);
|
||||
while (ret > 0) {
|
||||
a->start = DoubleTime();
|
||||
status = Proto_RxChar(priv, chr);
|
||||
if (GetDynStringLength(priv->rxBuffer) > GetDynStringLength(a->rdBuffer)) {
|
||||
int len_rd = GetDynStringLength(a->rdBuffer);
|
||||
int len_rx = GetDynStringLength(priv->rxBuffer);
|
||||
char *loc = &GetCharArray(priv->rxBuffer)[len_rd];
|
||||
DynStringConcatBytes(a->rdBuffer, loc, len_rx - len_rd);
|
||||
}
|
||||
if (status > 0) { /* Complete */
|
||||
a->state = AsconReadDone;
|
||||
return 1;
|
||||
}
|
||||
else if (status < 0) { /* Error */
|
||||
AsconError(a, "Protocol Input Error:", status);
|
||||
/*TODO This hack stops ascon.c:AsconTask() from needlessly closing the connection. Remove this when it's no longer needed */
|
||||
a->lastReconnect = DoubleTime();
|
||||
return 1;
|
||||
}
|
||||
ret = AsconReadChar(a->fd, &chr);
|
||||
}
|
||||
if (ret < 0) {
|
||||
AsconError(a, "AsconReadChar failed:", errno);
|
||||
return 1;
|
||||
}
|
||||
if (a->state != AsconReadDone) {
|
||||
if (a->timeout > 0) {
|
||||
if (DoubleTime() - a->start > a->timeout) {
|
||||
AsconError(a, "read timeout", 0);
|
||||
a->state = AsconTimeout;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ascon Protocol Poll Loop
|
||||
*/
|
||||
static int AsconProtHandler(Ascon *a) {
|
||||
ProtoPrivate *priv = (ProtoPrivate *) a->private;
|
||||
int ret;
|
||||
|
||||
switch(a->state){
|
||||
case AsconWriteStart:
|
||||
ret = Ascon_Prepare(a);
|
||||
return ret;
|
||||
case AsconReadStart:
|
||||
DynStringClear(priv->rxBuffer);
|
||||
a->start = DoubleTime();
|
||||
priv->state = 0;
|
||||
priv->len = 0;
|
||||
ret = AsconStdHandler(a);
|
||||
return ret;
|
||||
case AsconReading:
|
||||
ret = Ascon_Rx(a);
|
||||
return ret;
|
||||
default:
|
||||
ret = AsconStdHandler(a);
|
||||
return ret;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ascon Protocol Connection Init
|
||||
*/
|
||||
static int AsconInit(Ascon *a, SConnection *con, int argc, char *argv[])
|
||||
{
|
||||
int iRet;
|
||||
ProtoPrivate *priv;
|
||||
|
||||
iRet = AsconStdInit(a, con, argc, argv);
|
||||
priv = makeProtoPrivate();
|
||||
a->private = priv;
|
||||
a->killPrivate = Ascon_KillPrivate;
|
||||
return iRet;
|
||||
}
|
||||
|
||||
static AsyncProtocol *My_Async_Protocol = NULL;
|
||||
static AsconProtocol *My_Ascon_Protocol = NULL;
|
||||
|
||||
/*
|
||||
* Protocol Initialisation
|
||||
*/
|
||||
void HUBERInitProtocol(SicsInterp *pSics) {
|
||||
if (HUBER_Protocol == NULL) {
|
||||
HUBER_Protocol = AsyncProtocolCreate(pSics, "HUBER_AP", NULL, NULL);
|
||||
HUBER_Protocol->sendCommand = HUBER_Tx;
|
||||
HUBER_Protocol->handleInput = HUBER_Rx;
|
||||
HUBER_Protocol->handleEvent = HUBER_Ev;
|
||||
HUBER_Protocol->prepareTxn = HUBER_PrepareTxn;
|
||||
HUBER_Protocol->killPrivate = NULL;
|
||||
void PROTOCOL_INIT(SicsInterp *pSics) {
|
||||
if (My_Async_Protocol == NULL) {
|
||||
AsyncProtocol *prot;
|
||||
prot = AsyncProtocolCreate(pSics, PROTOCOL_NAME, NULL, NULL);
|
||||
prot->sendCommand = NULL;
|
||||
prot->handleInput = Async_Rx;
|
||||
prot->handleEvent = Async_Ev;
|
||||
prot->prepareTxn = Async_PrepareTxn;
|
||||
My_Async_Protocol = prot;
|
||||
}
|
||||
|
||||
if (My_Ascon_Protocol == NULL) {
|
||||
AsconProtocol *prot;
|
||||
prot = calloc(sizeof(AsconProtocol), 1);
|
||||
prot->name = strdup(PROTOCOL_NAME);
|
||||
prot->init = AsconInit;
|
||||
prot->handler = AsconProtHandler;
|
||||
AsconInsertProtocol(prot);
|
||||
My_Ascon_Protocol = prot;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,105 +1,175 @@
|
||||
#include "knauer_asyncprotocol.h"
|
||||
#include "asyncprotocol.h"
|
||||
#include "asyncqueue.h"
|
||||
#include "ascon.i"
|
||||
#include "dynstring.h"
|
||||
#include <errno.h>
|
||||
|
||||
#define SYN1 0x55
|
||||
#define SYN2 0xAA
|
||||
#define CR '\r'
|
||||
#define LF '\n'
|
||||
#define PROTOCOL_CONTINUE 0
|
||||
#define PROTOCOL_COMPLETE 1
|
||||
#define PROTOCOL_ERROR (-1)
|
||||
|
||||
/* Sample Messages
|
||||
55 aa 00 08 52 45 4d 4f 54 45 3a 30
|
||||
55 aa 00 16 45 52 52 4f 52 3a 34 38 2c 4e 6f 74 20 73 75 70 70 6f 72 74 65 64
|
||||
55 aa 00 18 45 52 52 4f 52 3a 31 36 2c 49 6e 76 61 6c 69 64 20 63 6f 6d 6d 61 6e 64
|
||||
structure:
|
||||
55 aa - sync bytes
|
||||
00 xx - length of following bytes
|
||||
yy .. zz - count(00 xx) message bytes with no terminator
|
||||
*/
|
||||
typedef struct knauer_private_t Private, *pPrivate;
|
||||
struct knauer_private_t {
|
||||
int len;
|
||||
};
|
||||
#define PROTOCOL_NAME "KNAUER_AP"
|
||||
#define PROTOCOL_INIT KNAUERInitProtocol
|
||||
#define SYN1 0x55
|
||||
#define SYN2 0xAA
|
||||
#define CR '\r'
|
||||
#define LF '\n'
|
||||
|
||||
/*
|
||||
* Protocol transmit function
|
||||
* Called by AsyncQueue to transmit a line
|
||||
* Protocol Private data block
|
||||
*/
|
||||
static int KNAUER_Tx(pAsyncProtocol p, pAsyncTxn pTxn) {
|
||||
int iRet = 1;
|
||||
typedef struct proto_private_t {
|
||||
int state; /**< protocol state machine */
|
||||
int len; /**< length from the protocol */
|
||||
pDynString wrBuffer; /**< transmitted message */
|
||||
pDynString rxBuffer; /**< received message */
|
||||
} ProtoPrivate;
|
||||
|
||||
static ProtoPrivate *makeProtoPrivate()
|
||||
{
|
||||
ProtoPrivate *priv = calloc(sizeof(ProtoPrivate), 1);
|
||||
priv->wrBuffer = CreateDynString(100, 100);
|
||||
priv->rxBuffer = CreateDynString(100, 100);
|
||||
return priv;
|
||||
}
|
||||
|
||||
static ProtoPrivate *Proto_KillPrivate(ProtoPrivate *priv)
|
||||
{
|
||||
if (priv) {
|
||||
if (priv->rxBuffer) {
|
||||
DeleteDynString(priv->rxBuffer);
|
||||
priv->rxBuffer = NULL;
|
||||
}
|
||||
free(priv);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pTxn) {
|
||||
pTxn->txn_status = ATX_ACTIVE;
|
||||
iRet = AsyncUnitWrite(pTxn->unit, pTxn->out_buf, pTxn->out_len);
|
||||
/* TODO handle errors */
|
||||
if (iRet < 0) { /* TODO: EOF */
|
||||
/*
|
||||
iRet = AsyncUnitReconnect(pTxn->unit);
|
||||
if (iRet == 0)
|
||||
* Protocol Specific Support Functions
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
/*
|
||||
* Protocol Prepare Output
|
||||
*/
|
||||
static int Proto_Prepare(ProtoPrivate *priv, pDynString wrBuffer)
|
||||
{
|
||||
DynStringConcatChar(wrBuffer, CR);
|
||||
return PROTOCOL_COMPLETE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Protocol receive character - characater by character
|
||||
*/
|
||||
static int KNAUER_Rx(pAsyncProtocol p, pAsyncTxn pTxn, int rxchar) {
|
||||
int iRet = 1;
|
||||
pPrivate myPriv = (pPrivate) pTxn->proto_private;
|
||||
|
||||
static int Proto_RxChar(ProtoPrivate *priv, int rxchar)
|
||||
{
|
||||
enum RX_STATE {
|
||||
RX_START=0,
|
||||
RX_TEXT=1,
|
||||
RX_SYN2=2,
|
||||
RX_LEN1=3,
|
||||
RX_LEN2=4,
|
||||
RX_STOP=99
|
||||
};
|
||||
rxchar &= 0xFF;
|
||||
switch (pTxn->txn_state) {
|
||||
case 0: /* first SYN byte */
|
||||
switch (priv->state) {
|
||||
case RX_START:
|
||||
if (rxchar != SYN1) {
|
||||
/* TODO: error */
|
||||
pTxn->txn_state = 99;
|
||||
pTxn->txn_status = ATX_COMPLETE;
|
||||
break;
|
||||
priv->state = RX_STOP;
|
||||
return PROTOCOL_ERROR;
|
||||
}
|
||||
pTxn->txn_state = 1;
|
||||
break;
|
||||
case 1: /* second SYN byte */
|
||||
priv->state = RX_SYN2;
|
||||
return PROTOCOL_CONTINUE;
|
||||
case RX_SYN2:
|
||||
if (rxchar != SYN2) {
|
||||
/* TODO: error */
|
||||
pTxn->txn_state = 99;
|
||||
pTxn->txn_status = ATX_COMPLETE;
|
||||
break;
|
||||
priv->state = RX_STOP;
|
||||
return PROTOCOL_ERROR;
|
||||
}
|
||||
pTxn->txn_state = 2;
|
||||
break;
|
||||
case 2: /* MS length byte */
|
||||
myPriv->len = 256 * rxchar;
|
||||
pTxn->txn_state = 3;
|
||||
break;
|
||||
case 3: /* LS length byte */
|
||||
myPriv->len += rxchar;
|
||||
pTxn->txn_state = 4;
|
||||
break;
|
||||
case 4: /* receiving text */
|
||||
if (pTxn->inp_idx < pTxn->inp_len)
|
||||
pTxn->inp_buf[pTxn->inp_idx++] = rxchar;
|
||||
if (pTxn->inp_idx >= myPriv->len) {
|
||||
pTxn->txn_state = 99;
|
||||
pTxn->txn_status = ATX_COMPLETE;
|
||||
priv->state = RX_LEN1;
|
||||
return PROTOCOL_CONTINUE;
|
||||
case RX_LEN1:
|
||||
priv->len = 256 * rxchar;
|
||||
priv->state = RX_LEN2;
|
||||
return PROTOCOL_CONTINUE;
|
||||
case RX_LEN2:
|
||||
priv->len += rxchar;
|
||||
priv->state = RX_TEXT;
|
||||
return PROTOCOL_CONTINUE;
|
||||
case RX_TEXT:
|
||||
DynStringConcatChar(priv->rxBuffer, rxchar);
|
||||
if (GetDynStringLength(priv->rxBuffer) >= priv->len) {
|
||||
priv->state = RX_STOP;
|
||||
return PROTOCOL_COMPLETE;
|
||||
} else {
|
||||
return PROTOCOL_CONTINUE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return PROTOCOL_ERROR;
|
||||
}
|
||||
if (pTxn->txn_state == 99) {
|
||||
iRet = 0;
|
||||
return PROTOCOL_ERROR;
|
||||
}
|
||||
if (iRet == 0) { /* end of command */
|
||||
free(pTxn->proto_private);
|
||||
|
||||
/*
|
||||
* AsyncProtocol handling
|
||||
* ======================
|
||||
*/
|
||||
|
||||
static void Async_KillPrivate(pAsyncTxn pTxn)
|
||||
{
|
||||
Proto_KillPrivate((ProtoPrivate *) pTxn->proto_private);
|
||||
pTxn->proto_private = NULL;
|
||||
return AQU_POP_CMD;
|
||||
}
|
||||
return iRet;
|
||||
|
||||
/*
|
||||
* AsyncProtocol Receive Character
|
||||
*/
|
||||
static int Async_Rx(pAsyncProtocol p, pAsyncTxn pTxn, int rxchar) {
|
||||
int iRet, str_len;
|
||||
ProtoPrivate *priv = (ProtoPrivate *) pTxn->proto_private;
|
||||
|
||||
iRet = Proto_RxChar(priv, rxchar);
|
||||
/*
|
||||
* Keep inp_buf and inp_idx up-to-date after each character
|
||||
*/
|
||||
str_len = GetDynStringLength(priv->rxBuffer);
|
||||
if (str_len > pTxn->inp_idx && pTxn->inp_idx < pTxn->inp_len) {
|
||||
int xfr_len;
|
||||
char *tgt = &pTxn->inp_buf[pTxn->inp_idx];
|
||||
char *loc = &GetCharArray(priv->rxBuffer)[pTxn->inp_idx];
|
||||
if (str_len > pTxn->inp_len)
|
||||
xfr_len = pTxn->inp_len - pTxn->inp_idx;
|
||||
else
|
||||
xfr_len = str_len - pTxn->inp_idx;
|
||||
memcpy(tgt, loc, xfr_len);
|
||||
pTxn->inp_idx += xfr_len;
|
||||
}
|
||||
|
||||
if (iRet == PROTOCOL_CONTINUE) {
|
||||
return 1; /* Keep Going */
|
||||
}
|
||||
|
||||
if (iRet == PROTOCOL_ERROR) {
|
||||
return -1; /* Error condition */
|
||||
}
|
||||
|
||||
/* Message Complete */
|
||||
return AQU_POP_CMD;
|
||||
}
|
||||
|
||||
/*
|
||||
* AsyncProtocol Event callback
|
||||
*/
|
||||
static int KNAUER_Ev(pAsyncProtocol p, pAsyncTxn pTxn, int event) {
|
||||
free(pTxn->proto_private);
|
||||
pTxn->proto_private = NULL;
|
||||
static int Async_Ev(pAsyncProtocol p, pAsyncTxn pTxn, int event) {
|
||||
if (event == AQU_TIMEOUT) {
|
||||
/* handle command timeout */
|
||||
pTxn->txn_status = ATX_TIMEOUT;
|
||||
@ -108,41 +178,168 @@ static int KNAUER_Ev(pAsyncProtocol p, pAsyncTxn pTxn, int event) {
|
||||
return AQU_POP_CMD;
|
||||
}
|
||||
|
||||
static int KNAUER_PrepareTxn(pAsyncProtocol p, pAsyncTxn pTxn, const char* cmd, int cmd_len, int rsp_len) {
|
||||
pPrivate myPriv = (pPrivate) malloc(sizeof(Private));
|
||||
if (myPriv == NULL) {
|
||||
SICSLogWrite("ERROR: Out of memory in KNAUER_PrepareTxn", eError);
|
||||
/*
|
||||
* AsyncProtocol Prepare Transaction
|
||||
*/
|
||||
static int Async_PrepareTxn(pAsyncProtocol p, pAsyncTxn pTxn, const char* cmd, int cmd_len, int rsp_len) {
|
||||
ProtoPrivate *priv;
|
||||
priv = makeProtoPrivate();
|
||||
if (priv == NULL) {
|
||||
SICSLogWrite("ERROR: Out of memory in Async_PrepareTxn", eError);
|
||||
return 0;
|
||||
}
|
||||
myPriv->len = 0;
|
||||
pTxn->out_buf = (char*) malloc(cmd_len + 1);
|
||||
priv->state = 0;
|
||||
priv->len = 0;
|
||||
DynStringConcatBytes(priv->wrBuffer, cmd, cmd_len);
|
||||
Proto_Prepare(priv, priv->wrBuffer);
|
||||
pTxn->out_len = GetDynStringLength(priv->wrBuffer);
|
||||
pTxn->out_buf = (char*) malloc(pTxn->out_len);
|
||||
if (pTxn->out_buf == NULL) {
|
||||
SICSLogWrite("ERROR: Out of memory in KNAUER_PrepareTxn", eError);
|
||||
free(myPriv);
|
||||
SICSLogPrintf(eError, "ERROR: Out of memory in %s:%s", __FILE__, __FUNCTION__);
|
||||
Proto_KillPrivate(priv);
|
||||
return 0;
|
||||
}
|
||||
pTxn->proto_private = myPriv;
|
||||
memcpy(pTxn->out_buf, cmd, cmd_len);
|
||||
pTxn->out_buf[cmd_len] = CR;
|
||||
pTxn->out_len = cmd_len + 1;
|
||||
pTxn->proto_private = priv;
|
||||
pTxn->kill_private = Async_KillPrivate;
|
||||
memcpy(pTxn->out_buf, GetCharArray(priv->wrBuffer), pTxn->out_len);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static pAsyncProtocol KNAUER_Protocol = NULL;
|
||||
/*
|
||||
* Ascon Protocol handling
|
||||
* =======================
|
||||
*/
|
||||
|
||||
static void Ascon_KillPrivate(void *priv)
|
||||
{
|
||||
Proto_KillPrivate((ProtoPrivate *) priv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ascon Protocol WriteStart
|
||||
*/
|
||||
static int Ascon_Prepare(Ascon *a) {
|
||||
ProtoPrivate *priv = (ProtoPrivate *) a->private;
|
||||
Proto_Prepare(priv, a->wrBuffer);
|
||||
a->wrPos = 0;
|
||||
a->state = AsconWriting;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ascon Protocol Read Poll
|
||||
*/
|
||||
static int Ascon_Rx(Ascon *a) {
|
||||
int ret, status;
|
||||
char chr = '\0';
|
||||
ProtoPrivate *priv = (ProtoPrivate *) a->private;
|
||||
|
||||
ret = AsconReadChar(a->fd, &chr);
|
||||
while (ret > 0) {
|
||||
a->start = DoubleTime();
|
||||
status = Proto_RxChar(priv, chr);
|
||||
if (GetDynStringLength(priv->rxBuffer) > GetDynStringLength(a->rdBuffer)) {
|
||||
int len_rd = GetDynStringLength(a->rdBuffer);
|
||||
int len_rx = GetDynStringLength(priv->rxBuffer);
|
||||
char *loc = &GetCharArray(priv->rxBuffer)[len_rd];
|
||||
DynStringConcatBytes(a->rdBuffer, loc, len_rx - len_rd);
|
||||
}
|
||||
if (status > 0) { /* Complete */
|
||||
a->state = AsconReadDone;
|
||||
return 1;
|
||||
}
|
||||
else if (status < 0) { /* Error */
|
||||
AsconError(a, "Protocol Input Error:", status);
|
||||
/*TODO This hack stops ascon.c:AsconTask() from needlessly closing the connection. Remove this when it's no longer needed */
|
||||
a->lastReconnect = DoubleTime();
|
||||
return 1;
|
||||
}
|
||||
ret = AsconReadChar(a->fd, &chr);
|
||||
}
|
||||
if (ret < 0) {
|
||||
AsconError(a, "AsconReadChar failed:", errno);
|
||||
return 1;
|
||||
}
|
||||
if (a->state != AsconReadDone) {
|
||||
if (a->timeout > 0) {
|
||||
if (DoubleTime() - a->start > a->timeout) {
|
||||
AsconError(a, "read timeout", 0);
|
||||
a->state = AsconTimeout;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ascon Protocol Poll Loop
|
||||
*/
|
||||
static int AsconProtHandler(Ascon *a) {
|
||||
ProtoPrivate *priv = (ProtoPrivate *) a->private;
|
||||
int ret;
|
||||
|
||||
switch(a->state){
|
||||
case AsconWriteStart:
|
||||
ret = Ascon_Prepare(a);
|
||||
return ret;
|
||||
case AsconReadStart:
|
||||
DynStringClear(priv->rxBuffer);
|
||||
a->start = DoubleTime();
|
||||
priv->state = 0;
|
||||
priv->len = 0;
|
||||
ret = AsconStdHandler(a);
|
||||
return ret;
|
||||
case AsconReading:
|
||||
ret = Ascon_Rx(a);
|
||||
return ret;
|
||||
default:
|
||||
ret = AsconStdHandler(a);
|
||||
return ret;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ascon Protocol Connection Init
|
||||
*/
|
||||
static int AsconInit(Ascon *a, SConnection *con, int argc, char *argv[])
|
||||
{
|
||||
int iRet;
|
||||
ProtoPrivate *priv;
|
||||
|
||||
iRet = AsconStdInit(a, con, argc, argv);
|
||||
priv = makeProtoPrivate();
|
||||
a->private = priv;
|
||||
a->killPrivate = Ascon_KillPrivate;
|
||||
return iRet;
|
||||
}
|
||||
|
||||
static AsyncProtocol *My_Async_Protocol = NULL;
|
||||
static AsconProtocol *My_Ascon_Protocol = NULL;
|
||||
|
||||
/*
|
||||
* Protocol Initialisation
|
||||
*/
|
||||
void KNAUERInitProtocol(SicsInterp *pSics) {
|
||||
if (KNAUER_Protocol == NULL) {
|
||||
KNAUER_Protocol = AsyncProtocolCreate(pSics, "KNAUER_AP", NULL, NULL);
|
||||
KNAUER_Protocol->sendCommand = KNAUER_Tx;
|
||||
KNAUER_Protocol->handleInput = KNAUER_Rx;
|
||||
KNAUER_Protocol->handleEvent = KNAUER_Ev;
|
||||
KNAUER_Protocol->prepareTxn = KNAUER_PrepareTxn;
|
||||
KNAUER_Protocol->killPrivate = NULL;
|
||||
void PROTOCOL_INIT(SicsInterp *pSics) {
|
||||
if (My_Async_Protocol == NULL) {
|
||||
AsyncProtocol *prot;
|
||||
prot = AsyncProtocolCreate(pSics, PROTOCOL_NAME, NULL, NULL);
|
||||
prot->sendCommand = NULL;
|
||||
prot->handleInput = Async_Rx;
|
||||
prot->handleEvent = Async_Ev;
|
||||
prot->prepareTxn = Async_PrepareTxn;
|
||||
My_Async_Protocol = prot;
|
||||
}
|
||||
|
||||
if (My_Ascon_Protocol == NULL) {
|
||||
AsconProtocol *prot;
|
||||
prot = calloc(sizeof(AsconProtocol), 1);
|
||||
prot->name = strdup(PROTOCOL_NAME);
|
||||
prot->init = AsconInit;
|
||||
prot->handler = AsconProtHandler;
|
||||
AsconInsertProtocol(prot);
|
||||
My_Ascon_Protocol = prot;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,105 +1,186 @@
|
||||
#include "omron_asyncprotocol.h"
|
||||
#include "asyncprotocol.h"
|
||||
#include "asyncqueue.h"
|
||||
#include "ascon.i"
|
||||
#include "dynstring.h"
|
||||
#include <errno.h>
|
||||
|
||||
#define PROTOCOL_CONTINUE 0
|
||||
#define PROTOCOL_COMPLETE 1
|
||||
#define PROTOCOL_ERROR (-1)
|
||||
|
||||
/* Sample Messages
|
||||
* structure:
|
||||
* STX
|
||||
* data
|
||||
* ETX
|
||||
* BCC
|
||||
*/
|
||||
#define PROTOCOL_NAME "OMRON_AP"
|
||||
#define PROTOCOL_INIT OMRONInitProtocol
|
||||
#define STX 2
|
||||
#define ETX 3
|
||||
|
||||
static int calc_bcc(const char* text)
|
||||
/*
|
||||
* Protocol Private data block
|
||||
*/
|
||||
typedef struct proto_private_t {
|
||||
int state; /**< protocol state machine */
|
||||
int len; /**< length from the protocol */
|
||||
pDynString wrBuffer; /**< transmitted message */
|
||||
pDynString rxBuffer; /**< received message */
|
||||
} ProtoPrivate;
|
||||
|
||||
static ProtoPrivate *makeProtoPrivate()
|
||||
{
|
||||
ProtoPrivate *priv = calloc(sizeof(ProtoPrivate), 1);
|
||||
priv->wrBuffer = CreateDynString(100, 100);
|
||||
priv->rxBuffer = CreateDynString(100, 100);
|
||||
return priv;
|
||||
}
|
||||
|
||||
static ProtoPrivate *Proto_KillPrivate(ProtoPrivate *priv)
|
||||
{
|
||||
if (priv) {
|
||||
if (priv->rxBuffer) {
|
||||
DeleteDynString(priv->rxBuffer);
|
||||
priv->rxBuffer = NULL;
|
||||
}
|
||||
free(priv);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Protocol Specific Support Functions
|
||||
*/
|
||||
|
||||
static int calc_bcc(const char* text, int len)
|
||||
{
|
||||
int idx = 0;
|
||||
int bcc = 0;
|
||||
int i = 0;
|
||||
int c;
|
||||
while (i < 1024) {
|
||||
c = text[i] & 0xFF;
|
||||
if (c == STX) {
|
||||
bcc = 0;
|
||||
} else {
|
||||
int c = 0;
|
||||
for (idx = 0; idx < len; ++idx) {
|
||||
c = text[idx] & 0xFF;
|
||||
bcc ^= c;
|
||||
}
|
||||
SICSLogPrintf(eLog, "BCC %02d: char %02X, bcc = %02X", i, c, bcc);
|
||||
if (c == ETX)
|
||||
break;
|
||||
++text;
|
||||
}
|
||||
bcc ^= ETX;
|
||||
return bcc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Protocol transmit function
|
||||
* Called by AsyncQueue to transmit a line
|
||||
* Protocol Prepare Output
|
||||
*/
|
||||
static int OMRON_Tx(pAsyncProtocol p, pAsyncTxn pTxn) {
|
||||
int iRet = 1;
|
||||
|
||||
if (pTxn) {
|
||||
pTxn->txn_status = ATX_ACTIVE;
|
||||
iRet = AsyncUnitWrite(pTxn->unit, pTxn->out_buf, pTxn->out_len);
|
||||
/* TODO handle errors */
|
||||
if (iRet < 0) { /* TODO: EOF */
|
||||
/*
|
||||
iRet = AsyncUnitReconnect(pTxn->unit);
|
||||
if (iRet == 0)
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
static int Proto_Prepare(ProtoPrivate *priv, pDynString wrBuffer)
|
||||
{
|
||||
int bcc;
|
||||
char stx[2] = {STX, '\0'};
|
||||
bcc = calc_bcc(GetCharArray(wrBuffer), GetDynStringLength(wrBuffer));
|
||||
DynStringInsert(wrBuffer, stx, 0);
|
||||
DynStringConcatChar(wrBuffer, ETX);
|
||||
DynStringConcatChar(wrBuffer, bcc);
|
||||
return PROTOCOL_COMPLETE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Protocol receive character - characater by character
|
||||
*/
|
||||
static int OMRON_Rx(pAsyncProtocol p, pAsyncTxn pTxn, int rxchar) {
|
||||
int iRet = 1;
|
||||
|
||||
switch (pTxn->txn_state) {
|
||||
case 0: /* first character */
|
||||
if (rxchar != STX) { /* STX */
|
||||
/* TODO: error */
|
||||
pTxn->txn_state = 99;
|
||||
pTxn->txn_status = ATX_COMPLETE;
|
||||
break;
|
||||
static int Proto_RxChar(ProtoPrivate *priv, int rxchar)
|
||||
{
|
||||
enum RX_STATE {
|
||||
RX_START=0,
|
||||
RX_TEXT=1,
|
||||
RX_LAST=2, /* BCC */
|
||||
RX_STOP=99
|
||||
};
|
||||
int bcc;
|
||||
rxchar &= 0xFF;
|
||||
switch (priv->state) {
|
||||
case RX_START:
|
||||
if (rxchar != STX) {
|
||||
priv->state = RX_STOP;
|
||||
return PROTOCOL_ERROR;
|
||||
}
|
||||
/* normal data */
|
||||
pTxn->txn_state = 1;
|
||||
/* note fallthrough */
|
||||
case 1: /* receiving reply */
|
||||
if (pTxn->inp_idx < pTxn->inp_len)
|
||||
pTxn->inp_buf[pTxn->inp_idx++] = rxchar;
|
||||
if (rxchar == ETX)
|
||||
pTxn->txn_state = 2;
|
||||
break;
|
||||
case 2: /* receiving bcc */
|
||||
if (pTxn->inp_idx < pTxn->inp_len)
|
||||
pTxn->inp_buf[pTxn->inp_idx++] = rxchar;
|
||||
if (calc_bcc(pTxn->inp_buf) != rxchar) {
|
||||
/* TODO: fail bcc */
|
||||
int bcc = calc_bcc(pTxn->inp_buf);
|
||||
priv->state = RX_TEXT;
|
||||
return PROTOCOL_CONTINUE;
|
||||
case RX_TEXT:
|
||||
if (rxchar == ETX) {
|
||||
priv->state = RX_LAST;
|
||||
return PROTOCOL_CONTINUE;
|
||||
}
|
||||
DynStringConcatChar(priv->rxBuffer, rxchar);
|
||||
return PROTOCOL_CONTINUE;
|
||||
case RX_LAST:
|
||||
bcc = calc_bcc(GetCharArray(priv->rxBuffer), GetDynStringLength(priv->rxBuffer));
|
||||
if (bcc == rxchar) {
|
||||
priv->state = RX_STOP;
|
||||
return PROTOCOL_COMPLETE;
|
||||
} else {
|
||||
SICSLogPrintf(eError,
|
||||
"Omron BCC mismatch, expected %02X but received %02X on message:",
|
||||
bcc, rxchar);
|
||||
SICSLogWriteHex(pTxn->inp_buf, pTxn->inp_idx, eError);
|
||||
SICSLogWriteHex(GetCharArray(priv->rxBuffer), GetDynStringLength(priv->rxBuffer), eError);
|
||||
priv->state = RX_STOP;
|
||||
return PROTOCOL_ERROR;
|
||||
}
|
||||
pTxn->txn_state = 99;
|
||||
pTxn->inp_idx -= 3;
|
||||
memmove(pTxn->inp_buf, pTxn->inp_buf + 1, pTxn->inp_idx);
|
||||
break;
|
||||
|
||||
default:
|
||||
return PROTOCOL_ERROR;
|
||||
}
|
||||
if (pTxn->txn_state == 99) {
|
||||
iRet = 0;
|
||||
return PROTOCOL_ERROR;
|
||||
}
|
||||
if (iRet == 0) { /* end of command */
|
||||
|
||||
/*
|
||||
* AsyncProtocol handling
|
||||
* ======================
|
||||
*/
|
||||
|
||||
static void Async_KillPrivate(pAsyncTxn pTxn)
|
||||
{
|
||||
Proto_KillPrivate((ProtoPrivate *) pTxn->proto_private);
|
||||
pTxn->proto_private = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* AsyncProtocol Receive Character
|
||||
*/
|
||||
static int Async_Rx(pAsyncProtocol p, pAsyncTxn pTxn, int rxchar) {
|
||||
int iRet, str_len;
|
||||
ProtoPrivate *priv = (ProtoPrivate *) pTxn->proto_private;
|
||||
|
||||
iRet = Proto_RxChar(priv, rxchar);
|
||||
/*
|
||||
* Keep inp_buf and inp_idx up-to-date after each character
|
||||
*/
|
||||
str_len = GetDynStringLength(priv->rxBuffer);
|
||||
if (str_len > pTxn->inp_idx && pTxn->inp_idx < pTxn->inp_len) {
|
||||
int xfr_len;
|
||||
char *tgt = &pTxn->inp_buf[pTxn->inp_idx];
|
||||
char *loc = &GetCharArray(priv->rxBuffer)[pTxn->inp_idx];
|
||||
if (str_len > pTxn->inp_len)
|
||||
xfr_len = pTxn->inp_len - pTxn->inp_idx;
|
||||
else
|
||||
xfr_len = str_len - pTxn->inp_idx;
|
||||
memcpy(tgt, loc, xfr_len);
|
||||
pTxn->inp_idx += xfr_len;
|
||||
}
|
||||
|
||||
if (iRet == PROTOCOL_CONTINUE) {
|
||||
return 1; /* Keep Going */
|
||||
}
|
||||
|
||||
if (iRet == PROTOCOL_ERROR) {
|
||||
return -1; /* Error condition */
|
||||
}
|
||||
|
||||
/* Message Complete */
|
||||
return AQU_POP_CMD;
|
||||
}
|
||||
return iRet;
|
||||
}
|
||||
|
||||
/*
|
||||
* AsyncProtocol Event callback
|
||||
*/
|
||||
static int OMRON_Ev(pAsyncProtocol p, pAsyncTxn pTxn, int event) {
|
||||
static int Async_Ev(pAsyncProtocol p, pAsyncTxn pTxn, int event) {
|
||||
if (event == AQU_TIMEOUT) {
|
||||
/* handle command timeout */
|
||||
pTxn->txn_status = ATX_TIMEOUT;
|
||||
@ -108,34 +189,168 @@ static int OMRON_Ev(pAsyncProtocol p, pAsyncTxn pTxn, int event) {
|
||||
return AQU_POP_CMD;
|
||||
}
|
||||
|
||||
static int OMRON_PrepareTxn(pAsyncProtocol p, pAsyncTxn pTxn, const char* cmd, int cmd_len, int rsp_len) {
|
||||
int i, bcc;
|
||||
pTxn->out_buf = (char*) malloc(cmd_len + 3);
|
||||
if (pTxn->out_buf == NULL) {
|
||||
SICSLogWrite("ERROR: Out of memory in OMRON_PrepareTxn", eError);
|
||||
/*
|
||||
* AsyncProtocol Prepare Transaction
|
||||
*/
|
||||
static int Async_PrepareTxn(pAsyncProtocol p, pAsyncTxn pTxn, const char* cmd, int cmd_len, int rsp_len) {
|
||||
ProtoPrivate *priv;
|
||||
priv = makeProtoPrivate();
|
||||
if (priv == NULL) {
|
||||
SICSLogWrite("ERROR: Out of memory in Async_PrepareTxn", eError);
|
||||
return 0;
|
||||
}
|
||||
memcpy(pTxn->out_buf + 1, cmd, cmd_len);
|
||||
pTxn->out_buf[0] = STX;
|
||||
pTxn->out_buf[cmd_len + 1] = ETX;
|
||||
pTxn->out_buf[cmd_len + 2] = calc_bcc(pTxn->out_buf);
|
||||
pTxn->out_len = cmd_len + 3;
|
||||
priv->state = 0;
|
||||
priv->len = 0;
|
||||
DynStringConcatBytes(priv->wrBuffer, cmd, cmd_len);
|
||||
Proto_Prepare(priv, priv->wrBuffer);
|
||||
pTxn->out_len = GetDynStringLength(priv->wrBuffer);
|
||||
pTxn->out_buf = (char*) malloc(pTxn->out_len);
|
||||
if (pTxn->out_buf == NULL) {
|
||||
SICSLogPrintf(eError, "ERROR: Out of memory in %s:%s", __FILE__, __FUNCTION__);
|
||||
Proto_KillPrivate(priv);
|
||||
return 0;
|
||||
}
|
||||
pTxn->proto_private = priv;
|
||||
pTxn->kill_private = Async_KillPrivate;
|
||||
memcpy(pTxn->out_buf, GetCharArray(priv->wrBuffer), pTxn->out_len);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static pAsyncProtocol OMRON_Protocol = NULL;
|
||||
/*
|
||||
* Ascon Protocol handling
|
||||
* =======================
|
||||
*/
|
||||
|
||||
static void Ascon_KillPrivate(void *priv)
|
||||
{
|
||||
Proto_KillPrivate((ProtoPrivate *) priv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ascon Protocol WriteStart
|
||||
*/
|
||||
static int Ascon_Prepare(Ascon *a) {
|
||||
ProtoPrivate *priv = (ProtoPrivate *) a->private;
|
||||
Proto_Prepare(priv, a->wrBuffer);
|
||||
a->wrPos = 0;
|
||||
a->state = AsconWriting;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ascon Protocol Read Poll
|
||||
*/
|
||||
static int Ascon_Rx(Ascon *a) {
|
||||
int ret, status;
|
||||
char chr = '\0';
|
||||
ProtoPrivate *priv = (ProtoPrivate *) a->private;
|
||||
|
||||
ret = AsconReadChar(a->fd, &chr);
|
||||
while (ret > 0) {
|
||||
a->start = DoubleTime();
|
||||
status = Proto_RxChar(priv, chr);
|
||||
if (GetDynStringLength(priv->rxBuffer) > GetDynStringLength(a->rdBuffer)) {
|
||||
int len_rd = GetDynStringLength(a->rdBuffer);
|
||||
int len_rx = GetDynStringLength(priv->rxBuffer);
|
||||
char *loc = &GetCharArray(priv->rxBuffer)[len_rd];
|
||||
DynStringConcatBytes(a->rdBuffer, loc, len_rx - len_rd);
|
||||
}
|
||||
if (status > 0) { /* Complete */
|
||||
a->state = AsconReadDone;
|
||||
return 1;
|
||||
}
|
||||
else if (status < 0) { /* Error */
|
||||
AsconError(a, "Protocol Input Error:", status);
|
||||
/*TODO This hack stops ascon.c:AsconTask() from needlessly closing the connection. Remove this when it's no longer needed */
|
||||
a->lastReconnect = DoubleTime();
|
||||
return 1;
|
||||
}
|
||||
ret = AsconReadChar(a->fd, &chr);
|
||||
}
|
||||
if (ret < 0) {
|
||||
AsconError(a, "AsconReadChar failed:", errno);
|
||||
return 1;
|
||||
}
|
||||
if (a->state != AsconReadDone) {
|
||||
if (a->timeout > 0) {
|
||||
if (DoubleTime() - a->start > a->timeout) {
|
||||
AsconError(a, "read timeout", 0);
|
||||
a->state = AsconTimeout;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ascon Protocol Poll Loop
|
||||
*/
|
||||
static int AsconProtHandler(Ascon *a) {
|
||||
ProtoPrivate *priv = (ProtoPrivate *) a->private;
|
||||
int ret;
|
||||
|
||||
switch(a->state){
|
||||
case AsconWriteStart:
|
||||
ret = Ascon_Prepare(a);
|
||||
return ret;
|
||||
case AsconReadStart:
|
||||
DynStringClear(priv->rxBuffer);
|
||||
a->start = DoubleTime();
|
||||
priv->state = 0;
|
||||
priv->len = 0;
|
||||
ret = AsconStdHandler(a);
|
||||
return ret;
|
||||
case AsconReading:
|
||||
ret = Ascon_Rx(a);
|
||||
return ret;
|
||||
default:
|
||||
ret = AsconStdHandler(a);
|
||||
return ret;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ascon Protocol Connection Init
|
||||
*/
|
||||
static int AsconInit(Ascon *a, SConnection *con, int argc, char *argv[])
|
||||
{
|
||||
int iRet;
|
||||
ProtoPrivate *priv;
|
||||
|
||||
iRet = AsconStdInit(a, con, argc, argv);
|
||||
priv = makeProtoPrivate();
|
||||
a->private = priv;
|
||||
a->killPrivate = Ascon_KillPrivate;
|
||||
return iRet;
|
||||
}
|
||||
|
||||
static AsyncProtocol *My_Async_Protocol = NULL;
|
||||
static AsconProtocol *My_Ascon_Protocol = NULL;
|
||||
|
||||
/*
|
||||
* Protocol Initialisation
|
||||
*/
|
||||
void OMRONInitProtocol(SicsInterp *pSics) {
|
||||
if (OMRON_Protocol == NULL) {
|
||||
OMRON_Protocol = AsyncProtocolCreate(pSics, "OMRON_AP", NULL, NULL);
|
||||
OMRON_Protocol->sendCommand = OMRON_Tx;
|
||||
OMRON_Protocol->handleInput = OMRON_Rx;
|
||||
OMRON_Protocol->handleEvent = OMRON_Ev;
|
||||
OMRON_Protocol->prepareTxn = OMRON_PrepareTxn;
|
||||
OMRON_Protocol->killPrivate = NULL;
|
||||
void PROTOCOL_INIT(SicsInterp *pSics) {
|
||||
if (My_Async_Protocol == NULL) {
|
||||
AsyncProtocol *prot;
|
||||
prot = AsyncProtocolCreate(pSics, PROTOCOL_NAME, NULL, NULL);
|
||||
prot->sendCommand = NULL;
|
||||
prot->handleInput = Async_Rx;
|
||||
prot->handleEvent = Async_Ev;
|
||||
prot->prepareTxn = Async_PrepareTxn;
|
||||
My_Async_Protocol = prot;
|
||||
}
|
||||
|
||||
if (My_Ascon_Protocol == NULL) {
|
||||
AsconProtocol *prot;
|
||||
prot = calloc(sizeof(AsconProtocol), 1);
|
||||
prot->name = strdup(PROTOCOL_NAME);
|
||||
prot->init = AsconInit;
|
||||
prot->handler = AsconProtHandler;
|
||||
AsconInsertProtocol(prot);
|
||||
My_Ascon_Protocol = prot;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -786,33 +786,6 @@ static void LS340Notify(void* context, int event)
|
||||
|
||||
static pAsyncProtocol LS340_Protocol = NULL;
|
||||
|
||||
static int LS340_Tx(pAsyncProtocol p, pAsyncTxn ctx)
|
||||
{
|
||||
int iRet = 1;
|
||||
pAsyncTxn myCmd = (pAsyncTxn) ctx;
|
||||
|
||||
if (myCmd) {
|
||||
|
||||
if (strchr(myCmd->out_buf, '?')) {
|
||||
myCmd->txn_status = ATX_ACTIVE;
|
||||
} else {
|
||||
myCmd->txn_status = ATX_COMPLETE;
|
||||
}
|
||||
|
||||
iRet = AsyncUnitWrite(myCmd->unit, myCmd->out_buf, myCmd->out_len);
|
||||
|
||||
/* TODO handle errors */
|
||||
if (iRet < 0) { /* TODO: EOF */
|
||||
/*
|
||||
iRet = AsyncUnitReconnect(myCmd->unit);
|
||||
if (iRet == 0)
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int LS340_Rx(pAsyncProtocol p, pAsyncTxn ctx, int rxchar) {
|
||||
int iRet = 1;
|
||||
pAsyncTxn myCmd = (pAsyncTxn) ctx;
|
||||
@ -856,17 +829,22 @@ static int LS340_PrepareTxn(pAsyncProtocol p, pAsyncTxn txn, const char* cmd, in
|
||||
|
||||
if (txn->out_buf[txn->out_len-1] != '\r') {
|
||||
txn->out_buf[txn->out_len++] = '\r';
|
||||
// txn->out_buf[txn->out_len++] = '\r';
|
||||
}
|
||||
|
||||
// txn->out_buf[txn->out_len++] = '\0';
|
||||
/*
|
||||
* If this message does not contain a Question Mark (?)
|
||||
* Then it does not request a reply
|
||||
*/
|
||||
if (!strchr(cmd, '?'))
|
||||
txn->inp_len = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void LS340InitProtocol(SicsInterp *pSics) {
|
||||
if (LS340_Protocol == NULL) {
|
||||
LS340_Protocol = AsyncProtocolCreate(pSics, "ls340", NULL, NULL);
|
||||
LS340_Protocol->sendCommand = LS340_Tx;
|
||||
LS340_Protocol->sendCommand = NULL;
|
||||
LS340_Protocol->handleInput = LS340_Rx;
|
||||
LS340_Protocol->handleEvent = LS340_Ev;
|
||||
LS340_Protocol->prepareTxn = LS340_PrepareTxn;
|
||||
|
@ -97,23 +97,6 @@ mxml_node_t *tree;
|
||||
|
||||
static int LSS_GetState(void *pData, char *param, LSS_STATUS *retState);
|
||||
|
||||
static int LSS_Tx(pAsyncProtocol p, pAsyncTxn myCmd)
|
||||
{
|
||||
int iRet = 1;
|
||||
|
||||
if (myCmd) {
|
||||
myCmd->txn_status = ATX_ACTIVE;
|
||||
iRet = AsyncUnitWrite(myCmd->unit, myCmd->out_buf, myCmd->out_len);
|
||||
/* TODO handle errors */
|
||||
if (iRet < 0) { /* TODO: EOF */
|
||||
iRet = AsyncUnitReconnect(myCmd->unit);
|
||||
if (iRet == 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int LSS_Rx(pAsyncProtocol p, pAsyncTxn myCmd, int rxchar)
|
||||
{
|
||||
int iRet = 1;
|
||||
@ -512,7 +495,7 @@ static void LSS_Kill(void* pData)
|
||||
void LSSInitProtocol(SicsInterp *pSics) {
|
||||
if (LSS_Protocol == NULL) {
|
||||
LSS_Protocol = AsyncProtocolCreate(pSics, "LSS", NULL, NULL);
|
||||
LSS_Protocol->sendCommand = LSS_Tx;
|
||||
LSS_Protocol->sendCommand = NULL;
|
||||
LSS_Protocol->handleInput = LSS_Rx;
|
||||
LSS_Protocol->handleEvent = LSS_Ev;
|
||||
LSS_Protocol->prepareTxn = NULL;
|
||||
|
@ -933,25 +933,6 @@ static int motCreep(pDMC2280Driv self, double target) {
|
||||
return target_steps;
|
||||
}
|
||||
|
||||
static int DMC_Tx(pAsyncProtocol p, pAsyncTxn ctx) {
|
||||
int iRet = 1;
|
||||
pAsyncTxn myCmd = (pAsyncTxn) ctx;
|
||||
|
||||
if (myCmd) {
|
||||
myCmd->txn_status = ATX_ACTIVE;
|
||||
iRet = AsyncUnitWrite(myCmd->unit, myCmd->out_buf, myCmd->out_len);
|
||||
/* TODO handle errors */
|
||||
if (iRet < 0) { /* TODO: EOF */
|
||||
/*
|
||||
iRet = AsyncUnitReconnect(myCmd->unit);
|
||||
if (iRet == 0)
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int DMC_Rx(pAsyncProtocol p, pAsyncTxn ctx, int rxchar) {
|
||||
int iRet = 1;
|
||||
pAsyncTxn myCmd = (pAsyncTxn) ctx;
|
||||
@ -6367,7 +6348,7 @@ int DMC2280Action(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
void DMC2280InitProtocol(SicsInterp *pSics) {
|
||||
if (DMC2280_Protocol == NULL) {
|
||||
DMC2280_Protocol = AsyncProtocolCreate(pSics, "DMC2280", NULL, NULL);
|
||||
DMC2280_Protocol->sendCommand = DMC_Tx;
|
||||
DMC2280_Protocol->sendCommand = NULL;
|
||||
DMC2280_Protocol->handleInput = DMC_Rx;
|
||||
DMC2280_Protocol->handleEvent = DMC_Ev;
|
||||
DMC2280_Protocol->prepareTxn = NULL;
|
||||
|
@ -778,28 +778,6 @@ static void ORHVPSKillPrivate(void *pData) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Protocol transmit function
|
||||
* Called by AsyncQueue to transmit a line
|
||||
*/
|
||||
static int ORHVPS_Tx(pAsyncProtocol p, pAsyncTxn myCmd) {
|
||||
int iRet = 1;
|
||||
|
||||
if (myCmd) {
|
||||
myCmd->txn_status = ATX_ACTIVE;
|
||||
iRet = AsyncUnitWrite(myCmd->unit, myCmd->out_buf, myCmd->out_len);
|
||||
/* TODO handle errors */
|
||||
if (iRet < 0) { /* TODO: EOF */
|
||||
/*
|
||||
iRet = AsyncUnitReconnect(myCmd->unit);
|
||||
if (iRet == 0)
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Protocol receive character - characater by character
|
||||
*/
|
||||
@ -907,7 +885,7 @@ static pAsyncProtocol ORHVPS_Protocol = NULL;
|
||||
void ORHVPSInitProtocol(SicsInterp *pSics) {
|
||||
if (ORHVPS_Protocol == NULL) {
|
||||
ORHVPS_Protocol = AsyncProtocolCreate(pSics, "ORHVPS", NULL, NULL);
|
||||
ORHVPS_Protocol->sendCommand = ORHVPS_Tx;
|
||||
ORHVPS_Protocol->sendCommand = NULL;
|
||||
ORHVPS_Protocol->handleInput = ORHVPS_Rx;
|
||||
ORHVPS_Protocol->handleEvent = ORHVPS_Ev;
|
||||
ORHVPS_Protocol->prepareTxn = ORHVPS_PrepareTxn;
|
||||
|
@ -77,23 +77,6 @@ struct __SafetyPLCController {
|
||||
|
||||
static int PLC_GetState(void *pData, char *param, PLC_STATUS *retState);
|
||||
|
||||
static int PLC_Tx(pAsyncProtocol p, pAsyncTxn myCmd)
|
||||
{
|
||||
int iRet = 1;
|
||||
|
||||
if (myCmd) {
|
||||
myCmd->txn_status = ATX_ACTIVE;
|
||||
iRet = AsyncUnitWrite(myCmd->unit, myCmd->out_buf, myCmd->out_len);
|
||||
/* TODO handle errors */
|
||||
if (iRet < 0) { /* TODO: EOF */
|
||||
iRet = AsyncUnitReconnect(myCmd->unit);
|
||||
if (iRet == 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int PLC_Rx(pAsyncProtocol p, pAsyncTxn myCmd, int rxchar)
|
||||
{
|
||||
int iRet = 1;
|
||||
@ -477,7 +460,7 @@ static void PLC_Kill(void* pData)
|
||||
void SafetyPLCInitProtocol(SicsInterp *pSics) {
|
||||
if (PLC_Protocol == NULL) {
|
||||
PLC_Protocol = AsyncProtocolCreate(pSics, "SafetyPLC", NULL, NULL);
|
||||
PLC_Protocol->sendCommand = PLC_Tx;
|
||||
PLC_Protocol->sendCommand = NULL;
|
||||
PLC_Protocol->handleInput = PLC_Rx;
|
||||
PLC_Protocol->handleEvent = PLC_Ev;
|
||||
PLC_Protocol->prepareTxn = NULL;
|
||||
|
Reference in New Issue
Block a user