From b2ce43d55472ad92ddb833eaa58f8ca1b9cb0037 Mon Sep 17 00:00:00 2001 From: Douglas Clowes Date: Mon, 21 Aug 2006 09:47:25 +1000 Subject: [PATCH] Largely comments and splint conformance r1070 | dcl | 2006-08-21 09:47:25 +1000 (Mon, 21 Aug 2006) | 2 lines --- site_ansto/counterdriv.c | 363 ++++++++++++++++++++++++++------------- 1 file changed, 241 insertions(+), 122 deletions(-) diff --git a/site_ansto/counterdriv.c b/site_ansto/counterdriv.c index 31198501..aacea7cc 100644 --- a/site_ansto/counterdriv.c +++ b/site_ansto/counterdriv.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "fortify.h" #include #include @@ -20,17 +21,28 @@ #include #include "anstoutil.h" -#define FAILURE 0 -#define SUCCESS 1 +#ifdef SPLINT +/*@-incondefs@*/ +int gettimeofday(/*@out@*/ struct timeval *restrict tp, + /*@null@*/ void *restrict tzp); +char *strdup(const char *s); +int strcasecmp(const char *s1, const char *s2); +int strncasecmp(const char *s1, const char *s2, size_t n); +unsigned long long int +strtoull(const char *nptr, /*@null@*/ char **endptr, int base); +/*@+incondefs@*/ +#endif /*@-incondefs@*/ /*@observer@*//*@dependent@*/ Tcl_Interp *InterpGetTcl(SicsInterp *pSics); int readRS232(prs232 self, /*@out@*/void *data, /*@out@*/int *dataLen); +int readRS232TillTerm(prs232 self, /*@out@*/void *data, /*@out@*/int *dataLen); void getRS232Error(int iCode, /*@out@*/ char *errorBuffer, int errorBufferLen); /*@observer@*//*@dependent@*/ pCounterDriver CreateCounterDriver(char *name, char *type); void KillRS232(/*@only@ frees pData */ void *pData); /*@+incondefs@*/ +typedef unsigned long long int uint64; typedef struct { int length; @@ -46,17 +58,22 @@ typedef struct { int iPort; float dummy_threshold; BUFFER buffer; - unsigned long long counter_value; + uint64 counter_value; } BeamMon, *pBeamMon; -static int MonSend(CounterDriver *cntrData, char *pText, char *pReply, int iReplyLen); - +/** \brief file logging + * + * Logs text to a debug file. The file is opened and closed for each call. + * + * \param flag character used to distinguish calls + * \param pText pointer to text to be logged + */ static void flog(char flag, char* pText) { FILE* file; file = fopen("flog.txt", "a"); if (file) { struct timeval tv; - gettimeofday(&tv, NULL); + (void) gettimeofday(&tv, NULL); fprintf(file, "%02d:%02d:%02d:%06d::%c::%s", tv.tv_sec % (24 * 3600) / 3600, tv.tv_sec % (3600) / 60, @@ -65,8 +82,8 @@ static void flog(char flag, char* pText) { flag, pText); if (strchr(pText, '\n') == NULL) - fputc('\n', file); - fclose(file); + (void) fputc('\n', file); + (void) fclose(file); } } @@ -75,19 +92,17 @@ static void flog(char flag, char* pText) { * * \param *cntrData provides access to a monitor's data * \param *text pointer to NULL terminated text to send. - * \return - * - SUCCESS - * - FAILURE + * \return SUCCESS or FAILURE */ static int MonWrite(pBeamMon self, char* text) { - int len; + size_t len; int status; len = strlen(text); if (len > 0) flog('>', text); - status = writeRS232(self->controller, text, len); + status = writeRS232(self->controller, text, (int) len); if (status != 1) { self->errorCode = status; return FAILURE; @@ -101,13 +116,12 @@ static int MonWrite(pBeamMon self, char* text) { * \param *cntrData provides access to a monitor's data * \param *text pointer to NULL terminated text to receive. * \param *pLen inout pointer to length of text to receive. - * \return - * - SUCCESS - * - FAILURE + * \return SUCCESS or FAILURE */ -static int MonRead(pBeamMon self, char* text, int *pLen) { +static int MonRead(pBeamMon self, /*@out@*/ char* text, int *pLen) { int i, status, retries=20; + *text = '\0'; for (i=0; icontroller, text, pLen); switch (status) { @@ -129,16 +143,86 @@ static int MonRead(pBeamMon self, char* text, int *pLen) { return FAILURE; } +/** \brief drains any pending input on the RS232 channel + * + * \param *cntrData provides access to a monitor's data + */ +static void MonDrainInput(CounterDriver *cntrData) { + int iRet; + int len; + char reply[1024]; + BeamMon* self = NULL; + self = (BeamMon *) cntrData->pData; + while (availableRS232(self->controller) != 0) { + len = (int) sizeof(reply); + iRet = MonRead(self, reply, &len); + if (iRet == FAILURE) { + return; + } + } +} + +/** \brief sends a command to the monitor and gets the reply + * + * \param cntrData provides access to a monitor's data + * \param pText command to send + * \param pReply space for reply + * \param iReplyLen length of space for reply + * \return SUCCESS or FAILURE + */ +static int MonSend(CounterDriver *cntrData, char *pText, char *pReply, int iReplyLen) { + BeamMon *self = NULL; + int status; + + self = (BeamMon *) cntrData->pData; + MonDrainInput(cntrData); + status = MonWrite(self, pText); + if (status != SUCCESS) + return status; + if ((status = MonRead(self, pReply, &iReplyLen)) == SUCCESS) + { + pReply[iReplyLen] = '\0'; + return SUCCESS; + } + return status; +} + +/** \brief sends a command to the monitor and gets the reply + * + * \param cntrData provides access to a monitor's data + * \param pText command to send + * \param buffer space for reply + * \return SUCCESS or FAILURE + */ +static int MonSendBuffer(CounterDriver *cntrData, char *pText, BUFFER* buffer) { + int status; + buffer->length = 0; + status = MonSend(cntrData, pText, buffer->body, (int) sizeof(buffer->body)); + if (status == SUCCESS) { + buffer->length = (int) strlen(buffer->body); + } + return status; +} +/** \brief parses and acts upon the READ line + * + * \param *cntrData provides access to a monitor's data + * \param bp pointer to buffer containing the text line + * + * This function sets the state of the counter based on state flags reported by + * the monitor. + */ static void HandleReport(CounterDriver *cntrData, BUFFER* bp) { //READ xxxx 00:00:00.000000 0.000000 0 0.00 //0123456789012345678901234567890 BeamMon* self = NULL; + char *cp = NULL; + char *ep = NULL; + char str[100]; self = (BeamMon *) cntrData->pData; /* TODO better than this */ - char* cp = &bp->body[26]; - char* ep; - cntrData->fTime = strtod(cp, &ep); + cp = &bp->body[26]; + cntrData->fTime = (float) strtod(cp, &ep); cp = ep; switch (toupper(bp->body[5])) { case 'I': /* idle */ @@ -151,16 +235,16 @@ static void HandleReport(CounterDriver *cntrData, BUFFER* bp) case 'P': /* paused */ self->state = HWPause; break; - default: + default: /* should not happen */ self->state = HWFault; break; } - if (toupper(bp->body[8] == 'G')) /* Gated */ + if ((self->state == HWBusy || self->state == HWPause) + && (toupper(bp->body[8]) == (int) 'G')) /* Gated */ self->state = HWNoBeam; self->counter_value = strtoull(cp, &ep, 10); - cntrData->fLastCurrent = self->counter_value; - char str[100]; - snprintf(str, sizeof(str), "READ %s, %f, %f, %f\n", + cntrData->fLastCurrent = (float) self->counter_value; + (void) snprintf(str, sizeof(str), "READ %s, %f, %f, %f\n", cntrData->eMode == eTimer ? "eTimer" : cntrData->eMode == ePreset ? "ePreset" : "Unknown", cntrData->fPreset, @@ -169,70 +253,60 @@ static void HandleReport(CounterDriver *cntrData, BUFFER* bp) flog('.', str); } -static int MonDrainInput(CounterDriver *cntrData) { - int iRet, len; - char reply[1024]; +/** \brief handles an input line received on the RS232 channel + * + * \param cntrData provides access to a monitor's data + * \param bp pointer to buffer containing the line of input + * + * This function sets the state of the counter based on events reported by + * the monitor. + */ +static void MonHandleInput(CounterDriver *cntrData, BUFFER* bp) { BeamMon* self = NULL; - self = (BeamMon *) cntrData->pData; - while (availableRS232(self->controller)) { - len = sizeof(reply); - iRet = MonRead(self, reply, &len); - if (iRet == FAILURE) { - return iRet; - } - } - return SUCCESS; -} - -static int MonHandleInput(CounterDriver *cntrData, BUFFER* bp) { - BeamMon* self = NULL; - int iRet, len; - int iLen = 0; - int jLen = 0; - char reply[1024]; - char* pTerm; + const char et[] = "EVENT TERMINAL"; + const char eri[] = "EVENT RANGE IN"; + const char ero[] = "EVENT RANGE OUT"; + const char rpt[] = "READ"; self = (BeamMon *) cntrData->pData; /* TODO handle the line */ - flog('<', bp->body); - const char et[] = "EVENT TERMINAL"; + flog('=', bp->body); if (strncasecmp(bp->body, et, sizeof(et) - 1) == 0) { if (self->state == HWBusy) self->state = HWIdle; } - const char eri[] = "EVENT RANGE IN"; if (strncasecmp(bp->body, eri, sizeof(eri) - 1) == 0) if (self->state == HWPause) self->state = HWBusy; - const char ero[] = "EVENT RANGE OUT"; if (strncasecmp(bp->body, ero, sizeof(ero) - 1) == 0) if (self->state == HWBusy) self->state = HWPause; - const char rpt[] = "READ"; if (strncasecmp(bp->body, rpt, sizeof(rpt) - 1) == 0) { - if (self->state == HWBusy) { HandleReport(cntrData, &self->buffer); - MonWrite(self, "SICS READ"); - } } bp->length = 0; - return 1; } -static int MonLookForInput(CounterDriver *cntrData, int timeout) { +/** \brief look for input on the socket + * + * breaks input into lines terminated by pairs and passes complete lines to MonHandleInput for processing. + * + * \param cntrData provides access to a monitor's data + * \param timeout upper limit on time to wait for data to arrive + */ +static void MonLookForInput(CounterDriver *cntrData, /*@unused@*/ int timeout) { BeamMon* self = NULL; int iRet, len; int iLen = 0; int jLen = 0; char reply[1024]; - char* pTerm; self = (BeamMon *) cntrData->pData; - while (availableRS232(self->controller)) { - len = sizeof(reply); + while (availableRS232(self->controller) != 0) { + len = (int) sizeof(reply); iRet = MonRead(self, reply, &len); if (iRet == FAILURE) { - return iRet; + return; } iLen = 0; while (iLen < len) { @@ -243,7 +317,7 @@ static int MonLookForInput(CounterDriver *cntrData, int timeout) { jLen = len - iLen; strncpy(&self->buffer.body[self->buffer.length], &reply[iLen], - jLen); + (size_t) jLen); self->buffer.length += jLen; self->buffer.body[self->buffer.length] = '\0'; iLen += jLen; @@ -254,7 +328,6 @@ static int MonLookForInput(CounterDriver *cntrData, int timeout) { self->buffer.length = 0; } } - return 1; } /** \brief Returns the counter status, @@ -275,7 +348,7 @@ static int MonGetStatus(CounterDriver *cntrData, float *fControl) { self = (BeamMon *) cntrData->pData; MonLookForInput(cntrData, 0); - status = MonSend(cntrData, "SICS READ", self->buffer.body, sizeof(self->buffer.body)); + status = MonSendBuffer(cntrData, "SICS READ", &self->buffer); if (status == SUCCESS) { /* TODO */ MonHandleInput(cntrData, &self->buffer); @@ -302,11 +375,18 @@ static int MonGetStatus(CounterDriver *cntrData, float *fControl) { /** \brief Starts counting in the current mode and with the current preset * * \param *cntrData provides access to a monitor's data + * \return SUCCESS or FAILURE + * + * This function also sets some of the parameters in the monitor for mode and + * preset. + * + * TODO: check the return from the monitor */ static int MonStart(CounterDriver *cntrData) { BeamMon *self = NULL; + int status; char str[100]; - snprintf(str, sizeof(str), "START %s, %f, %f, %f\n", + (void) snprintf(str, sizeof(str), "START %s, %f, %f, %f\n", cntrData->eMode == eTimer ? "eTimer" : cntrData->eMode == ePreset ? "ePreset" : "Unknown", cntrData->fPreset, @@ -316,32 +396,53 @@ static int MonStart(CounterDriver *cntrData) { self = (BeamMon *) cntrData->pData; MonDrainInput(cntrData); if (cntrData->eMode == eTimer) { - MonSend(cntrData, "SICS SET TE_CHECK=TIMER", - self->buffer.body, sizeof(self->buffer.body)); + status = MonSendBuffer(cntrData, "SICS SET TE_CHECK=TIMER", &self->buffer); + if (status != SUCCESS || strcasecmp(self->buffer.body, "OK") != 0) { + self->errorCode = /* TODO */ 0; + return FAILURE; + } } else { - MonSend(cntrData, "SICS SET TE_CHECK=COUNTER", - self->buffer.body, sizeof(self->buffer.body)); + status = MonSendBuffer(cntrData, "SICS SET TE_CHECK=COUNTER", &self->buffer); + if (status != SUCCESS || strcasecmp(self->buffer.body, "OK") != 0) { + self->errorCode = /* TODO */ 0; + return FAILURE; + } + } + /*@-duplicatequals@ for uint64 */ + /*@-formattype@ for uint64 */ + (void) snprintf(str, sizeof(str), "SICS SET TERMINAL=%llu", + (uint64) cntrData->fPreset); + /*@+formattype@*/ + /*@+duplicatequals@*/ + status = MonSendBuffer(cntrData, str, &self->buffer); + if (status != SUCCESS || strcasecmp(self->buffer.body, "OK") != 0) { + self->errorCode = /* TODO */ 0; + return FAILURE; + } + status = MonSendBuffer(cntrData, "SICS START", &self->buffer); + if (status != SUCCESS || strcasecmp(self->buffer.body, "OK") != 0) { + self->errorCode = /* TODO */ 0; + return FAILURE; } - snprintf(str, sizeof(str), "SICS SET TERMINAL=%llu", - (unsigned long long) cntrData->fPreset); - MonSend(cntrData, str, - self->buffer.body, sizeof(self->buffer.body)); - MonSend(cntrData, "SICS START", - self->buffer.body, sizeof(self->buffer.body)); self->state = HWBusy; return SUCCESS; -} +} /** \brief Pauses a counting operation * * \param *cntrData provides access to a monitor's data + * \return SUCCESS or FAILURE + * + * TODO: check if we should set the state to HWPause or just leave it till we + * get it back from the monitor. */ static int MonPause(CounterDriver *cntrData) { BeamMon *self = NULL; + int status; self = (BeamMon *) cntrData->pData; - if (MonSend(cntrData, "SICS PAUSE", - self->buffer.body, sizeof(self->buffer.body)) == SUCCESS) { + status = MonSendBuffer(cntrData, "SICS PAUSE", &self->buffer); + if (status == SUCCESS) { self->state = HWPause; return SUCCESS; } @@ -351,13 +452,18 @@ static int MonPause(CounterDriver *cntrData) { /* \brief Continues a paused counting operation. * * \param *cntrData provides access to a monitor's data + * \return SUCCESS or FAILURE + * + * TODO: check if we should set the sate to HWBusy or just leave it till we + * get it back from the monitor. */ static int MonContinue(CounterDriver *cntrData) { BeamMon *self = NULL; + int status; self = (BeamMon *) cntrData->pData; - if (MonSend(cntrData, "SICS CONTINUE", - self->buffer.body, sizeof(self->buffer.body)) == SUCCESS) { + status = MonSendBuffer(cntrData, "SICS CONTINUE", &self->buffer); + if (status == SUCCESS) { self->state = HWBusy; return SUCCESS; } @@ -366,14 +472,19 @@ static int MonContinue(CounterDriver *cntrData) { /** \brief Cancels a counting operation. This is an emergency stop used when interrupting an operation. * \param *cntrData provides access to a monitor's data + * \return SUCCESS or FAILURE + * + * TODO: check if we should set the sate to HWIdle or just leave it till we + * get it back from the monitor. */ static int MonHalt(CounterDriver *cntrData) { BeamMon *self = NULL; + int status; self = (BeamMon *) cntrData->pData; - if (MonSend(cntrData, "SICS STOP", - self->buffer.body, sizeof(self->buffer.body)) == SUCCESS) { - self->state = HWBusy; + status = MonSendBuffer(cntrData, "SICS STOP", &self->buffer); + if (status == SUCCESS) { + self->state = HWIdle; return SUCCESS; } return FAILURE; @@ -382,18 +493,21 @@ static int MonHalt(CounterDriver *cntrData) { /** \brief Reads the counter and the monitors in the lCounts array. * * \param *cntrData provides access to a monitor's data + * \return SUCCESS or FAILURE */ static int MonReadValues(CounterDriver *cntrData) { BeamMon *self = NULL; + int status; flog('.', "MonReadValues"); self = (BeamMon *) cntrData->pData; - if (MonSend(cntrData, "SICS READ", - self->buffer.body, sizeof(self->buffer.body)) == SUCCESS) { + status = MonSendBuffer(cntrData, "SICS READ", &self->buffer); + if (status == SUCCESS) { HandleReport(cntrData, &self->buffer); - lCounts[0] = self->counter_value; + cntrData->lCounts[0] = (long) self->counter_value; /* NOTE: truncation */ + return SUCCESS; } - return SUCCESS; + return FAILURE; } /* \brief Called when an error condition is reported by a counter operation. @@ -411,7 +525,7 @@ static int MonGetError(CounterDriver *cntrData, int *iCode, char *error, int iEr self = (BeamMon *) cntrData->pData; /* Allocate iErrLen bytes for error messages */ if (self->errorMsg == NULL) { - self->errorMsg = (char *) malloc(iErrLen); + self->errorMsg = (char *) malloc((size_t) iErrLen); if (self->errorMsg == NULL) { return FAILURE; } @@ -420,7 +534,9 @@ static int MonGetError(CounterDriver *cntrData, int *iCode, char *error, int iEr *iCode = self->errorCode; switch (*iCode) { case 0: - strncpy(error, "UNKNOWN ERROR: counterdriv did not set an errorcode.", iErrLen); + strncpy(error, + "UNKNOWN ERROR: counterdriv did not set an errorcode.", + (size_t) iErrLen); break; case NOTCONNECTED: case TIMEOUT: @@ -430,7 +546,9 @@ static int MonGetError(CounterDriver *cntrData, int *iCode, char *error, int iEr getRS232Error(*iCode, error, iErrLen); break; default: - snprintf(error, iErrLen, "Unknown error code: %d, returned from counterdriv", *iCode); + (void) snprintf(error, (size_t) iErrLen, + "Unknown error code: %d, returned from counterdriv", + *iCode); } self->errorCode = 0; return SUCCESS; @@ -453,8 +571,9 @@ static int MonTryAndFixIt(CounterDriver *cntrData, int iCode) { switch(iCode){ case NOTCONNECTED: - initRS232(self->controller); - return COREDO; + if (initRS232(self->controller) == 1) + return COREDO; + return COTERM; case BADSEND: case TIMEOUT: case BADMEMORY: /* Won't happen if MonConnect sets the send terminator */ @@ -473,7 +592,7 @@ static int MonTryAndFixIt(CounterDriver *cntrData, int iCode) { static int MonSet(CounterDriver *cntrData, char *name, int iCter, float fVal) { BeamMon *self = NULL; char str[100]; - snprintf(str, 100, "MonSet(%s, %d, %f)", name, iCter, fVal); + (void) snprintf(str, 100, "MonSet(%s, %d, %f)", name, iCter, fVal); flog('.', str); self = (BeamMon *) cntrData->pData; @@ -487,6 +606,7 @@ static int MonSet(CounterDriver *cntrData, char *name, int iCter, float fVal) { static int MonGet(CounterDriver *cntrData, char *name, int iCter, float *fVal) { BeamMon *self = NULL; + char str[100]; self = (BeamMon *) cntrData->pData; if(strcasecmp(name,"threshold") == 0){ @@ -495,35 +615,28 @@ static int MonGet(CounterDriver *cntrData, char *name, int iCter, float *fVal) { } /* TODO*/ - char str[100]; - snprintf(str, 100, "MonGet(%s, %d, %f)", name, iCter, *fVal); + (void) snprintf(str, 100, "MonGet(%s, %d, %f)", name, iCter, *fVal); flog('.', str); return SUCCESS; } -static int MonSend(CounterDriver *cntrData, char *pText, char *pReply, int iReplyLen) { - BeamMon *self = NULL; - int status; - - self = (BeamMon *) cntrData->pData; - MonDrainInput(cntrData); - MonWrite(self, pText); - if ((status = MonRead(self, pReply, &iReplyLen)) == SUCCESS) - { - pReply[iReplyLen] = '\0'; - return SUCCESS; - } - return status; -} - -static void KillMon(pCounterDriver cntrData) { - pBeamMon self = NULL; - self = (pBeamMon) cntrData->pData; - if (self) { - if (self->host) - free(self->host); - if (self->errorMsg) - free(self->errorMsg); +static void KillMon(/*@null@*/ pCounterDriver cntrData) { + if (cntrData != NULL) { + if (cntrData->pData != NULL) { + pBeamMon self = (pBeamMon) cntrData->pData; + if (self->host) { + free(self->host); + self->host = NULL; + } + if (self->errorMsg) { + free(self->errorMsg); + self->errorMsg = NULL; + } + KillRS232(self->controller); + free(cntrData->pData); + cntrData->pData = NULL; + } + /* TODO free(cntrData); */ } } @@ -541,17 +654,17 @@ static void KillMon(pCounterDriver cntrData) { controller=createRS232(host,port); if (controller==NULL) { - snprintf(pError, ERRLEN, + (void) snprintf(pError, ERRLEN, "ERROR: failed to create controller for %s at port %d", host, port); - SCWrite(pCon,pError,eError); + (void) SCWrite(pCon,pError,eError); return NULL; } if ( initRS232(controller) != 1) { - snprintf(pError, ERRLEN, + (void) snprintf(pError, ERRLEN, "ERROR: failed to connect to %s at port %d", host, port); - SCWrite(pCon,pError,eError); + (void) SCWrite(pCon,pError,eError); KillRS232(controller); return NULL; } @@ -614,13 +727,19 @@ static void KillMon(pCounterDriver cntrData) { KillMon(pCntDriv); return NULL; } - sscanf(pPtr,"%d", &newCtr->iPort); + (void) sscanf(pPtr,"%d", &newCtr->iPort); + if ((pPtr=getParam(pCon, interp, params,"host",1)) == NULL) { KillMon(pCntDriv); return NULL; } + /*@-mustfreeonly@ host = NULL after BeamMon is created */ newCtr->host = strdup(pPtr); + /*@+mustfreeonly@*/ + + /*@-mustfreeonly@ controller = NULL after BeamMon is created */ newCtr->controller = MonConnect(pCon, newCtr->host, newCtr->iPort); + /*@+mustfreeonly@*/ newCtr->dummy_threshold = 1.7e6; return pCntDriv;