From 64a47de78c972179799366bd495368a01a0001cb Mon Sep 17 00:00:00 2001 From: Ferdi Franceschini Date: Fri, 6 Mar 2015 11:52:41 +1100 Subject: [PATCH] SICS-128: The reactor status protocol now just searches for a line containing "Power:" and returns it as the reactor status. --- site_ansto/hardsup/aqp_opalstatus.c | 112 ++++++++++++++++++---------- 1 file changed, 73 insertions(+), 39 deletions(-) diff --git a/site_ansto/hardsup/aqp_opalstatus.c b/site_ansto/hardsup/aqp_opalstatus.c index b0de390b..73c2c502 100644 --- a/site_ansto/hardsup/aqp_opalstatus.c +++ b/site_ansto/hardsup/aqp_opalstatus.c @@ -2,7 +2,36 @@ * @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. + * If the HTTP status is not OK or if the driver fails to find a line that + * contains the "Power:" field then it returns the unprocessed reply + * characters in the data buffer. + * + * The reply is expected to have a form similar to the following, + * HTTP/1.1 200 OK + * Date: Thu, 26 Feb 2015 01:27:30 GMT + * Server: Oracle-Application-Server-10g/10.1.3.5.0 Oracle-HTTP-Server + * Content-Location: /reactor.jsp + * Content-Type: text/plain; charset=UTF-8 + * Set-Cookie: JSESSIONID=74646fa7cf3cdf53a371694a33ab760cd649631d758f416d916c6d1b496a477b.e34Pc3qNbh4RaO0Ma3yMbxaRaN0Ke0; path=/Bragg + * Connection: close + * Transfer-Encoding: chunked + * + * 4f + * Power: 19.381588; CNS Out: 25.76; TG123: 1; CG123: 1; TG4: Open; HB1: 0; HB2: 1 + * + * 0 + * + * It should have no more than 512 characters excluding the HTTP OK status. + * Each line is expected to be terminated with a \r\n. + * The reply is expected to begin with "HTTP/1.1 200 OK" + * A line is identified as the status message if and only if it includes + * "Power:" regardless of case. + * The reply is expected to end with 0\r\n\r\n + * + * Processing lines is simplified by discarding \r characters and then just + * checking for \n. + * NOTE: This implies that \n should not be used in the status line as a + * delimiter. */ #include "../made_config.h" #include @@ -16,73 +45,78 @@ #define USERAGENT "User-Agent: SICS\r\n" #endif #define HOST "Host: neutron.ansto.gov.au\r\n" +/* Assume that the first field in the reactor status starts with "Power" */ +#define PWR_FLD "Power" +#define PWR_FLD_LEN 5 -enum replystates {START, HEADER, CHKHEADEREND, MSG}; +enum replystates {START, CHK_PWR_FLD, MSG, END_MSG, DRAIN_REPLY}; static pAsyncProtocol OPAL_Protocol = NULL; -/* 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 +/* The message is assumed to start with "Power:" and terminated with crlf. * by two more crlf pairs of characters - * Processing is simplified by discarding cr chars and counting lf chars */ + * Processing of line terminators is simplified by discarding cr chars */ static int OPAL_Rx(pAsyncProtocol p, pAsyncTxn txn, int ch) { + char *fldptr; int ret = 1; - static int nlctr = 0; + static int char_ctr = 0, newline_ctr = 0; static enum replystates state = START; + if (char_ctr++ >= txn->inp_len) { + char_ctr = 0; + newline_ctr = 0; + state = START; + return AQU_POP_CMD; + } if (ch == '\r') { return ret; } switch (state) { case START: if (ch == '\n') { - /* check HTTP status */ + /* check HTTP status is OK before proceeding */ if ( strncmp(txn->inp_buf, HTTP_OK, strlen(HTTP_OK) ) == 0 ) { txn->inp_idx = 0; - nlctr = 0; - state = HEADER; + state = CHK_PWR_FLD; } else ret = AQU_POP_CMD; - } else if (txn->inp_idx < txn->inp_len) + } else txn->inp_buf[txn->inp_idx++] = ch; - else - ret = AQU_POP_CMD; break; - case HEADER: + case CHK_PWR_FLD: 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; + } else if (ch == ':') { + if ( txn->inp_idx >= PWR_FLD_LEN ) { + /* Check for "Power" field anywhere in status line */ + fldptr = &txn->inp_buf[txn->inp_idx - PWR_FLD_LEN]; + if ( strncasecmp(fldptr, PWR_FLD, PWR_FLD_LEN) == 0 ) { + state = MSG; + } + } } + txn->inp_buf[txn->inp_idx++] = ch; break; case MSG: - if (txn->inp_idx >= txn->inp_len) - ret = AQU_POP_CMD; - if (nlctr == 0 && ch != '\n') + if (ch == '\n') { + state = END_MSG; + } else { txn->inp_buf[txn->inp_idx++] = ch; - else if (nlctr == 2 && ch == '\n') + } + break; + case END_MSG: + if (ch == '0') { + state = DRAIN_REPLY; + } + break; + case DRAIN_REPLY: + newline_ctr++; + if (newline_ctr >= 2) ret = AQU_POP_CMD; - else - nlctr++; break; } if (ret == AQU_POP_CMD) { - nlctr = 0; + char_ctr = 0; + newline_ctr = 0; state = START; } return ret; @@ -116,7 +150,7 @@ static int OPAL_PrepareTxn(pAsyncProtocol p, pAsyncTxn txn, const char* cmd, int if (txn->inp_buf != NULL) { free(txn->inp_buf); } - txn->inp_len = rsp_len; + txn->inp_len = 512; txn->inp_idx = 0; txn->txn_state = 0; txn->txn_status = 0;