Files
sics/site_ansto/hardsup/omron_asyncprotocol.c
2014-08-20 13:05:29 +10:00

142 lines
3.4 KiB
C

#include "omron_asyncprotocol.h"
#include "asyncprotocol.h"
#include "asyncqueue.h"
#define STX 2
#define ETX 3
static int calc_bcc(const char* text)
{
int bcc = 0;
int i = 0;
int c;
while (i < 1024) {
c = text[i] & 0xFF;
if (c == STX) {
bcc = 0;
} else {
bcc ^= c;
}
SICSLogPrintf(eLog, "BCC %02d: char %02X, bcc = %02X", i, c, bcc);
if (c == ETX)
break;
++text;
}
return bcc;
}
/*
* Protocol transmit function
* Called by AsyncQueue to transmit a line
*/
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;
}
/*
* 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;
}
/* 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);
SICSLogPrintf(eError,
"Omron BCC mismatch, expected %02X but received %02X on message:",
bcc, rxchar);
SICSLogWriteHex(pTxn->inp_buf, pTxn->inp_idx, eError);
}
pTxn->txn_state = 99;
pTxn->inp_idx -= 3;
memmove(pTxn->inp_buf, pTxn->inp_buf + 1, pTxn->inp_idx);
break;
}
if (pTxn->txn_state == 99) {
iRet = 0;
}
if (iRet == 0) { /* end of command */
return AQU_POP_CMD;
}
return iRet;
}
/*
* AsyncProtocol Event callback
*/
static int OMRON_Ev(pAsyncProtocol p, pAsyncTxn pTxn, int event) {
if (event == AQU_TIMEOUT) {
/* handle command timeout */
pTxn->txn_status = ATX_TIMEOUT;
return AQU_POP_CMD;
}
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);
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;
return 1;
}
static pAsyncProtocol OMRON_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;
}
}