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
137 lines
3.9 KiB
C
137 lines
3.9 KiB
C
/* @file aqp_opalstatus.c
|
|
* @brief
|
|
* Implements a simple protocol to GET reactor status using an HTTP/1.1 GET.
|
|
* It sets the UserAgent as SICS to avoid re-directs because we don't handle them.
|
|
* If the HTTP status is not OK then it returns the status in the data buffer.
|
|
*/
|
|
#include "../made_config.h"
|
|
#include <sics.h>
|
|
#include <asyncqueue.h>
|
|
|
|
#define HTTP_OK "HTTP/1.1 200 OK"
|
|
#define HTTP11 " HTTP/1.1\r\n"
|
|
#if defined SICS_VERSION && defined SICS_REVISION
|
|
#define USERAGENT "User-Agent: SICS Version = " SICS_VERSION " Revision = " SICS_REVISION "\r\n"
|
|
#else
|
|
#define USERAGENT "User-Agent: SICS\r\n"
|
|
#endif
|
|
#define HOST "Host: neutron.ansto.gov.au\r\n"
|
|
|
|
enum replystates {START, HEADER, CHKHEADEREND, MSG};
|
|
static pAsyncProtocol OPAL_Protocol = NULL;
|
|
|
|
/* 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
|
|
* So we assume that the header is terminated by two consecutive crlf char
|
|
* pairs which are eventually followed by another crlf
|
|
* The message is assumed to be terminated by a crlf pair eventually followed
|
|
* by two more crlf pairs of characters
|
|
* Processing is simplified by discarding cr chars and counting lf chars */
|
|
static int OPAL_Rx(pAsyncProtocol p, pAsyncTxn txn, int ch) {
|
|
int ret = 1;
|
|
static int nlctr = 0;
|
|
static enum replystates state = START;
|
|
|
|
if (ch == '\r') {
|
|
return ret;
|
|
}
|
|
switch (state) {
|
|
case START:
|
|
if (ch == '\n') {
|
|
/* check HTTP status */
|
|
if ( strncmp(txn->inp_buf, HTTP_OK, strlen(HTTP_OK) ) == 0 ) {
|
|
txn->inp_idx = 0;
|
|
nlctr = 0;
|
|
state = HEADER;
|
|
} else
|
|
ret = AQU_POP_CMD;
|
|
} else if (txn->inp_idx < txn->inp_len)
|
|
txn->inp_buf[txn->inp_idx++] = ch;
|
|
else
|
|
ret = AQU_POP_CMD;
|
|
break;
|
|
case HEADER:
|
|
if (ch == '\n') {
|
|
nlctr++;
|
|
state = CHKHEADEREND;
|
|
}
|
|
break;
|
|
case CHKHEADEREND:
|
|
if (nlctr == 1 && ch == '\n')
|
|
nlctr++;
|
|
else if (nlctr == 1 && ch != '\n') {
|
|
txn->inp_idx = 0;
|
|
nlctr = 0;
|
|
state = HEADER;
|
|
} else if (nlctr == 2 && ch == '\n') {
|
|
txn->inp_idx = 0;
|
|
nlctr = 0;
|
|
state = MSG;
|
|
}
|
|
break;
|
|
case MSG:
|
|
if (txn->inp_idx >= txn->inp_len)
|
|
ret = AQU_POP_CMD;
|
|
if (nlctr == 0 && ch != '\n')
|
|
txn->inp_buf[txn->inp_idx++] = ch;
|
|
else if (nlctr == 2 && ch == '\n')
|
|
ret = AQU_POP_CMD;
|
|
else
|
|
nlctr++;
|
|
break;
|
|
}
|
|
if (ret == AQU_POP_CMD) {
|
|
nlctr = 0;
|
|
state = START;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int OPAL_Ev(pAsyncProtocol p, pAsyncTxn pTxn, int event) {
|
|
if (event == AQU_TIMEOUT) {
|
|
pTxn->txn_status = ATX_TIMEOUT;
|
|
return AQU_POP_CMD;
|
|
}
|
|
return AQU_POP_CMD;
|
|
}
|
|
|
|
/* Append HTTP/1.1 and Host: line to message */
|
|
static int OPAL_PrepareTxn(pAsyncProtocol p, pAsyncTxn txn, const char* cmd, int cmd_len, int rsp_len) {
|
|
int msglen;
|
|
|
|
msglen = cmd_len + strlen(HTTP11) + strlen(USERAGENT) + strlen(HOST) + 3;
|
|
txn->out_buf = (char*) malloc(msglen);
|
|
if (txn->out_buf == NULL) {
|
|
SICSLogWrite("ERROR: Out of memory in OPAL_PrepareTxn", eError);
|
|
return 0;
|
|
}
|
|
strcpy(txn->out_buf, cmd);
|
|
strcat(txn->out_buf, HTTP11);
|
|
strcat(txn->out_buf, USERAGENT);
|
|
strcat(txn->out_buf, HOST);
|
|
strcat(txn->out_buf, "\r\n");
|
|
txn->out_len = msglen;
|
|
txn->out_idx = 0;
|
|
if (txn->inp_buf != NULL) {
|
|
free(txn->inp_buf);
|
|
}
|
|
txn->inp_len = rsp_len;
|
|
txn->inp_idx = 0;
|
|
txn->txn_state = 0;
|
|
txn->txn_status = 0;
|
|
return 1;
|
|
}
|
|
|
|
void OpalStatusInitProtocol(SicsInterp *pSics) {
|
|
if (OPAL_Protocol == NULL) {
|
|
OPAL_Protocol = AsyncProtocolCreate(pSics, "OPALSTAT", NULL, NULL);
|
|
OPAL_Protocol->sendCommand = NULL;
|
|
OPAL_Protocol->handleInput = OPAL_Rx;
|
|
OPAL_Protocol->killPrivate = NULL;
|
|
OPAL_Protocol->handleEvent = OPAL_Ev;
|
|
OPAL_Protocol->prepareTxn = OPAL_PrepareTxn;
|
|
}
|
|
}
|
|
|