diff --git a/site_ansto/hardsup/makefile b/site_ansto/hardsup/makefile index 1876cabd..312c73a4 100644 --- a/site_ansto/hardsup/makefile +++ b/site_ansto/hardsup/makefile @@ -35,6 +35,7 @@ HOBJ += camera.o HOBJ += cameradriver.o HOBJ += sct_asyncqueue.o HOBJ += aqp_opalstatus.o +HOBJ += omron_asyncprotocol.o libhlib.a: $(HOBJ) rm -f libhlib.a diff --git a/site_ansto/hardsup/omron_asyncprotocol.c b/site_ansto/hardsup/omron_asyncprotocol.c new file mode 100644 index 00000000..05d6556c --- /dev/null +++ b/site_ansto/hardsup/omron_asyncprotocol.c @@ -0,0 +1,144 @@ +#include +#include +#include + +#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 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 + */ +static int OMRON_Rx(pAsyncProtocol p, pAsyncTxn ctx, int rxchar) { + int iRet = 1; + pAsyncTxn myCmd = (pAsyncTxn) ctx; + + switch (myCmd->txn_state) { + case 0: /* first character */ + if (rxchar != STX) { /* STX */ + /* TODO: error */ + myCmd->txn_state = 99; + myCmd->txn_status = ATX_COMPLETE; + break; + } + /* normal data */ + myCmd->txn_state = 1; + /* note fallthrough */ + case 1: /* receiving reply */ + if (myCmd->inp_idx < myCmd->inp_len) + myCmd->inp_buf[myCmd->inp_idx++] = rxchar; + if (rxchar == ETX) + myCmd->txn_state = 2; + break; + case 2: /* receiving bcc */ + if (myCmd->inp_idx < myCmd->inp_len) + myCmd->inp_buf[myCmd->inp_idx++] = rxchar; + if (calc_bcc(myCmd->inp_buf) != rxchar) { + /* TODO: fail bcc */ + int bcc = calc_bcc(myCmd->inp_buf); + SICSLogPrintf(eError, + "Omron BCC mismatch, expected %02X but received %02X on message:", + bcc, rxchar); + SICSLogWriteHex(myCmd->inp_buf, myCmd->inp_idx, eError); + } + myCmd->txn_state = 99; + myCmd->inp_idx -= 3; + memmove(myCmd->inp_buf, myCmd->inp_buf + 1, myCmd->inp_idx); + break; + } + if (myCmd->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 txn, const char* cmd, int cmd_len, int rsp_len) { + int i, bcc; + txn->out_buf = (char*) malloc(cmd_len + 3); + if (txn->out_buf == NULL) { + SICSLogWrite("ERROR: Out of memory in OMRON_PrepareTxn", eError); + return 0; + } + memcpy(txn->out_buf + 1, cmd, cmd_len); + txn->out_buf[0] = STX; + txn->out_buf[cmd_len + 1] = ETX; + txn->out_buf[cmd_len + 2] = calc_bcc(txn->out_buf); + txn->out_buf[cmd_len + 3] = 0x0D; + txn->out_buf[cmd_len + 4] = 0x0A; + txn->out_len = cmd_len + 5; + return 1; +} + +static pAsyncProtocol OMRON_Protocol = NULL; + +/* + * Protocol Initialisation + */ +void OMRONInitProtocol(SicsInterp *pSics) { + if (OMRON_Protocol == NULL) { + OMRON_Protocol = AsyncProtocolCreate(pSics, "OMRON", 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; + } +} + diff --git a/site_ansto/site_ansto.c b/site_ansto/site_ansto.c index 7f837185..4681c798 100644 --- a/site_ansto/site_ansto.c +++ b/site_ansto/site_ansto.c @@ -353,6 +353,7 @@ static void AddCommands(SicsInterp *pInter) LS340InitProtocol(pInter); CameraInitProtocol(pInter); OpalStatusInitProtocol(pInter); + OMRONInitProtocol(pInter); AddCommand(pInter,"InstallProtocolHandler", InstallProtocol,NULL,NULL); AddCommand(pInter,"hostnam",hostNamCmd,NULL,NULL); AddCommand(pInter,"portnum",portNumCmd,NULL,NULL);