diff --git a/site_ansto/hardsup/aqp_opalstatus.c b/site_ansto/hardsup/aqp_opalstatus.c new file mode 100644 index 00000000..cf8ea1c0 --- /dev/null +++ b/site_ansto/hardsup/aqp_opalstatus.c @@ -0,0 +1,147 @@ +/* @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 +#include + +#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; + +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 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 = OPAL_Tx; + OPAL_Protocol->handleInput = OPAL_Rx; + OPAL_Protocol->killPrivate = NULL; + OPAL_Protocol->handleEvent = OPAL_Ev; + OPAL_Protocol->prepareTxn = OPAL_PrepareTxn; + } +} + diff --git a/site_ansto/hardsup/aqp_opalstatus.h b/site_ansto/hardsup/aqp_opalstatus.h new file mode 100644 index 00000000..c690fa7c --- /dev/null +++ b/site_ansto/hardsup/aqp_opalstatus.h @@ -0,0 +1,4 @@ +#ifndef AQP_OPALSTATUS_H +#define AQP_OPALSTATUS_H +void OpalStatusInitProtocol(SicsInterp *pSics); +#endif diff --git a/site_ansto/hardsup/makefile b/site_ansto/hardsup/makefile index 5915f951..1876cabd 100644 --- a/site_ansto/hardsup/makefile +++ b/site_ansto/hardsup/makefile @@ -34,6 +34,7 @@ HOBJ += sct_lfprot.o HOBJ += camera.o HOBJ += cameradriver.o HOBJ += sct_asyncqueue.o +HOBJ += aqp_opalstatus.o libhlib.a: $(HOBJ) rm -f libhlib.a diff --git a/site_ansto/instrument/config/source/reactor_status.sct b/site_ansto/instrument/config/source/reactor_status.sct index 858a5307..b4ece185 100644 --- a/site_ansto/instrument/config/source/reactor_status.sct +++ b/site_ansto/instrument/config/source/reactor_status.sct @@ -12,8 +12,8 @@ driver reactor_status = { var status = { type = text; priv = spy; - readable = 10; - read_command = 'GET /Bragg/proposal/reactor.jsp?type=ALL HTTP/1.0'; + readable = 30; + read_command = 'GET /Bragg/proposal/reactor.jsp?type=ALL'; read_function = rdAll; fetch_function = getState; data = false; diff --git a/site_ansto/instrument/config/source/sct_reactor_status.tcl b/site_ansto/instrument/config/source/sct_reactor_status.tcl index 5fdbc749..40e5b5c5 100644 --- a/site_ansto/instrument/config/source/sct_reactor_status.tcl +++ b/site_ansto/instrument/config/source/sct_reactor_status.tcl @@ -252,7 +252,7 @@ proc ::scobj::reactor_status::mk_sct_reactor_status { sct_controller name } { hsetprop ${scobj_hpath}/power nxalias "${name}_power" hfactory ${scobj_hpath}/status plain spy text - hsetprop ${scobj_hpath}/status read ${ns}::getState ${scobj_hpath} rdAll {GET /Bragg/proposal/reactor.jsp?type=ALL HTTP/1.0} + hsetprop ${scobj_hpath}/status read ${ns}::getState ${scobj_hpath} rdAll {GET /Bragg/proposal/reactor.jsp?type=ALL} hsetprop ${scobj_hpath}/status rdAll ${ns}::rdAll ${scobj_hpath} hsetprop ${scobj_hpath}/status control false hsetprop ${scobj_hpath}/status data false @@ -289,7 +289,7 @@ proc ::scobj::reactor_status::mk_sct_reactor_status { sct_controller name } { hsetprop ${scobj_hpath} data "true" if {[SplitReply [opal_simulation]]=="false"} { - ${sct_controller} poll ${scobj_hpath}/status 10 + ${sct_controller} poll ${scobj_hpath}/status 30 } hsetprop ${scobj_hpath} klass NXsource # hook code starts diff --git a/site_ansto/instrument/config/source/source.tcl b/site_ansto/instrument/config/source/source.tcl index 898d92a9..3aca40ae 100644 --- a/site_ansto/instrument/config/source/source.tcl +++ b/site_ansto/instrument/config/source/source.tcl @@ -1,10 +1,7 @@ fileeval $cfPath(source)/sct_reactor_status.tcl if {[SplitReply [opal_simulation]]=="false"} { - MakeAsyncProtocol std - std sendterminator \r\n\r\n - std replyterminator 0x03 - MakeAsyncQueue aqreactor std portal.nbi.ansto.gov.au 80 + MakeAsyncQueue aqreactor OPALSTAT neutron.ansto.gov.au 80 aqreactor timeout 2000 } add_reactor_status source aqadapter aqreactor diff --git a/site_ansto/instrument/server_config.tcl b/site_ansto/instrument/server_config.tcl index dee2ee3f..425e685b 100644 --- a/site_ansto/instrument/server_config.tcl +++ b/site_ansto/instrument/server_config.tcl @@ -16,7 +16,7 @@ set quieckport 60004 # icsval column = settings when running on the Instrument Control Server (ie SICS_SIMULATION not defined) # fakedev column = settings for test platforms (ie SICS_SIMULATION=fakedev) foreach {simflag icsval fakedev} { - opal_simulation true true + opal_simulation false true detector_simulation false true hmm_simulation false true environment_simulation false true diff --git a/site_ansto/site_ansto.c b/site_ansto/site_ansto.c index 0ec14b47..1f77076d 100644 --- a/site_ansto/site_ansto.c +++ b/site_ansto/site_ansto.c @@ -57,6 +57,7 @@ #include "lssmonitor.h" #include "beamstopaction.h" #include "cameradriver.h" +#include "aqp_opalstatus.h" /*@observer@*//*@null@*/ pCounterDriver CreateMonCounter(/*@observer@*/SConnection *pCon, /*@observer@*/char *name, char *params); @@ -351,6 +352,7 @@ static void AddCommands(SicsInterp *pInter) ORHVPSInitProtocol(pInter); LS340InitProtocol(pInter); CameraInitProtocol(pInter); + OpalStatusInitProtocol(pInter); AddCommand(pInter,"InstallProtocolHandler", InstallProtocol,NULL,NULL); AddCommand(pInter,"hostnam",hostNamCmd,NULL,NULL); AddCommand(pInter,"portnum",portNumCmd,NULL,NULL);