diff --git a/site_ansto/anstohttp.c b/site_ansto/anstohttp.c index 84328c42..cdd96f49 100644 --- a/site_ansto/anstohttp.c +++ b/site_ansto/anstohttp.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include extern char *trim(char *); /*=================================================================== @@ -38,19 +38,17 @@ static char preset[] = {"/admin/presethm.egi"}; /*==================================================================== error codes ======================================================================*/ -#define BADURL -701 -#define HTTPERROR -702 -#define NOBODY -703 -#define BODYSHORT -704 +#define BADURL -701 +#define HTTPERROR -702 +#define NOBODY -703 +#define BODYSHORT -704 #define NOTIMPLEMENTED -705 -#define SERVERERROR -706 -#define BADSTATUS -707 -#define BADAUTH -708 -#define IMMEDFAIL -709 +#define SERVERERROR -706 +#define BADSTATUS -707 +#define BADAUTH -708 /*===================================================================== our driver private data structure ======================================================================*/ -#define MAXSTRLEN 512 typedef struct { ghttp_request *syncRequest; char hmAddress[512]; @@ -343,13 +341,26 @@ static int readStatus(pHistDriver pDriv){ // This allows the status to be checked from all the start, stop, pause // and continue callbacks, so we can wait for the server to actually // change to the correct operating state before continuing. -static int AnstoHttpStatus(pHistDriver self,SConnection *pCon){ // pCon=NULL allowed +// +// Define codes for more detailed status info +// (returned via pextrastatus instead of retcode which is just HWBusy or HWIdle). +// These are needed so we can tell when a start/stop/pause operation actually completes. +#define ANSTO_HS_STATUS_INVALID 0 // e.g. couldn't retrieve a status because server is down +#define ANSTO_HS_STATUS_STARTED 1 +#define ANSTO_HS_STATUS_PAUSED 2 +#define ANSTO_HS_STATUS_STOPPED 3 +#define ANSTO_HS_STATUS_STARTING 4 +#define ANSTO_HS_STATUS_PAUSING 5 +#define ANSTO_HS_STATUS_STOPPING 6 +// +static int AnstoHttpStatus_Base(pHistDriver self,SConnection *pCon,int *pextrastatus){ // pCon=NULL allowed pAnstoHttp pPriv = NULL; ghttp_status httpStatus; char daqStatus[20]; int status, len; char *pPtr = NULL; - + static int last_known_status=HWIdle; // assume idle initially + pPriv = (pAnstoHttp)self->pPriv; assert(pPriv != NULL); @@ -365,6 +376,7 @@ static int AnstoHttpStatus(pHistDriver self,SConnection *pCon){ // pCon=NULL all ghttp_set_sync(pPriv->syncRequest,ghttp_async); ghttp_prepare(pPriv->syncRequest); if(status != 1){ + if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_INVALID; return HWFault; } pPriv->asyncRunning = 1; @@ -379,8 +391,9 @@ static int AnstoHttpStatus(pHistDriver self,SConnection *pCon){ // pCon=NULL all if(httpStatus != ghttp_done){ strncpy(pPriv->hmError,"Reconnect", 511); pPriv->errorCode = SERVERERROR; + if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_INVALID; + pPriv->asyncRunning = 0; // MJL bug fix 9/03/07 return HWFault; - pPriv->asyncRunning = 0; } break; case ghttp_not_done: @@ -392,6 +405,7 @@ static int AnstoHttpStatus(pHistDriver self,SConnection *pCon){ // pCon=NULL all pPriv->asyncRunning = 0; status = anstoHttpCheckResponse(pPriv); if(status != 1){ + if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_INVALID; return HWFault; } break; @@ -400,22 +414,53 @@ static int AnstoHttpStatus(pHistDriver self,SConnection *pCon){ // pCon=NULL all status = readStatus(self); if(status != 1){ + if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_INVALID; return HWFault; } if(StringDictGet(self->pOption,"daq",daqStatus,20) != 1){ pPriv->errorCode = BADSTATUS; strncpy(pPriv->hmError,"ERROR: status does not contain DAQ field",511); + if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_INVALID; return HWFault; } ///if (pCon) SCWrite(pCon,daqStatus,eError); // MJL DEBUG + // + // Basically we just diagnose whether the DAQ is running or not, + // but also return more detailed status via pextrastatus if supplied. if(strstr(daqStatus,"Started") != NULL){ - return HWBusy; + if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_STARTED; + return last_known_status=HWBusy; } else if(strstr(daqStatus,"Paused") != NULL){ - return HWIdle; + if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_PAUSED; + return last_known_status=HWIdle; } else if(strstr(daqStatus,"Stopped") != NULL){ - return HWIdle; + if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_STOPPED; + return last_known_status=HWIdle; + // + // The following are extra statuses which may + // (in the next histogram server version) be reported + // by the server, when the DAQ state is changing. + // As some DAE types are slow to start up, this + // is a valuable feature. + // + // Try to distinguish the HWBusy and HWIdle states + // based on the last known status. For example, + // when Stopping from Paused state it should report + // HWBusy if it was in Started state to begin with, + // otherwise HWIdle if it was in Paused or Stopped states. + } else if(strstr(daqStatus,"Starting") != NULL){ + if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_STARTING; + return last_known_status; // if started already, is already HWBusy + } else if(strstr(daqStatus,"Stopping") != NULL){ + if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_PAUSING; + return last_known_status; // return HWBusy only if it was started before + } else if(strstr(daqStatus,"Pausing") != NULL){ + if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_STOPPING; + return last_known_status; // return HWBusy if it was started before + // bad or missing status?? } else { + if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_INVALID; pPriv->errorCode = BADSTATUS; snprintf(pPriv->hmError,511,"ERROR: invalid DAQ status %s",daqStatus); return HWFault; @@ -423,19 +468,53 @@ static int AnstoHttpStatus(pHistDriver self,SConnection *pCon){ // pCon=NULL all return HWFault; // shouldn't get here } +// +static int AnstoHttpStatus(pHistDriver self,SConnection *pCon){ // pCon=NULL allowed + return AnstoHttpStatus_Base(self,pCon,NULL); // pCon=NULL allowed +} -#define MAX_STATUS_READ_RETRIES 150 -#define STATUS_READ_DELAY_US 200000 + +#define STATUS_READ_DELAY_USEC 200000 // re-check once per 0.2 second if possible +#define MAX_STATUS_READ_RETRIES 150 // wait up to 30 secs for status to change to desired state +#define MAX_BAD_STATUS_REQUESTS 3 // don't wait too long if too many bad status requests (probably server is down) +// +long long get_localtime_us() +// Get the time in us not in the US ;) +{ + struct timeval tv; + gettimeofday(&tv,NULL); + return ((long long)tv.tv_sec)*1000000+tv.tv_usec; +} // static int AnstoHttpStatusWithRetries(pHistDriver self, int requiredstate,SConnection *pCon) // pCon=NULL allowed { - int retries,retcode,initialentry=1; - for(retries=0;retriespause = 1; - AnstoHttpStatusWithRetries(self,HWIdle,pCon); + AnstoHttpStatusWithRetries(self,ANSTO_HS_STATUS_PAUSED,pCon); return OKOK; } @@ -498,12 +577,12 @@ static int AnstoHttpContinue(pHistDriver self, SConnection *pCon){ pPriv = (pAnstoHttp)self->pPriv; assert(pPriv != NULL); - status = anstoHttpGet(pPriv,continuedaq); + status = anstoHttpGet(pPriv,continuedaq); // which is the same as restarting if(status != 1){ return HWFault; } pPriv->pause = 0; - AnstoHttpStatusWithRetries(self,HWBusy,pCon); + AnstoHttpStatusWithRetries(self,ANSTO_HS_STATUS_STARTED,pCon); return OKOK; } /*---------------------------------------------------------------------*/ @@ -517,7 +596,7 @@ static int AnstoHttpError(pHistDriver self, int *code, strncpy(error,pPriv->hmError, errLen); *code = pPriv->errorCode; - return OKOK; + return OKOK; } /*--------------------------------------------------------------------*/ static int AnstoHttpFixIt(pHistDriver self, int code){ @@ -550,60 +629,7 @@ static int AnstoHttpGetData(pHistDriver self,SConnection *pCon){ return OKOK; } /*-------------------------------------------------------------------*/ -/** \brief Reads histogram data from a zipped file produced by the - * histogram memory server - * - * \param self (r) provides access to the histogram data structure - * \param bank number n maps to a HDS_Pn file. - */ -static int GetHMfromFile(pHistDriver self, SConnection *pCon, - int bank, int start, int end, HistInt *data){ - HistInt *hmdata; - pAnstoHttp pPriv = NULL; - int status, len, i, size; - int errMsgLen; - FILE *fp; - - char command[256]; - char hmDataPath[MAXSTRLEN]; - char DAQdir[MAXSTRLEN]; - char DSfilepath[MAXSTRLEN]; - char scanpoint[32]; - memset(command, 0, sizeof(command)); - memset(hmDataPath, 0, sizeof(hmDataPath)); - memset(DAQdir, 0, sizeof(DAQdir)); - memset(DSfilepath, 0, sizeof(DSfilepath)); - memset(scanpoint, 0, sizeof(scanpoint)); - - pPriv = (pAnstoHttp)self->pPriv; - assert(pPriv != NULL); - errMsgLen = sizeof(pPriv->hmError); - if (bank < 0) { - snprintf(pPriv->hmError,errMsgLen,"Negative bank numbers are not supported when reading from the filesystem"); - pPriv->errorCode = IMMEDFAIL; - return HWFault; - } - StringDictGet(self->pOption, "daq_dirname",DAQdir, sizeof(DAQdir)-1); - StringDictGet(self->pOption, "hmdatapath",hmDataPath, sizeof(hmDataPath)-1); - StringDictGet(self->pOption, "scanpoint",scanpoint, sizeof(scanpoint)-1); - snprintf(DSfilepath,sizeof(DSfilepath),"%s/%s/DATASET_%s/HDS_P%d",hmDataPath,DAQdir,scanpoint,bank); - - if ((fp=gzopen(DSfilepath, "rb")) == NULL) { - snprintf(pPriv->hmError,errMsgLen,"Failed to open %s", DSfilepath); - pPriv->errorCode = IMMEDFAIL; - return HWFault; - } - size = end - start; - gzread(fp, data, size*sizeof(HistInt)); - data+=size; - start+=size; - gzclose(fp); - return OKOK; -} - -/**\brief Gets histogram data directly from the histogram memory http server. - */ -static int GetHMfromSocket(pHistDriver self, SConnection *pCon, +static int AnstoHttpGetHistogram(pHistDriver self, SConnection *pCon, int bank, int start, int end, HistInt *data){ char command[256]; HistInt *hmdata; @@ -683,17 +709,6 @@ static int GetHMfromSocket(pHistDriver self, SConnection *pCon, } return OKOK; } - -static int AnstoHttpGetHistogram(pHistDriver self, SConnection *pCon, - int bank, int start, int end, HistInt *data){ - char direct[2]; - - StringDictGet(self->pOption, "direct",direct, 2); - if (strcmp(direct,"1") == 0) - return GetHMfromSocket(self, pCon, bank, start, end, data); - else - return GetHMfromFile(self, pCon, bank, start, end, data); -} /*--------------------------------------------------------------------*/ static int AnstoHttpSetHistogram(pHistDriver self, SConnection *pCon, int bank, int start, int end, HistInt *data){ @@ -758,8 +773,8 @@ pHistDriver CreateAnstoHttpDriver(pStringDict pOption){ } /* add our options */ - StringDictAddPair(pOption,"hmaddress","http://unknown.psi.ch:9090"); - StringDictAddPair(pOption,"hmconfigurescript","hmconfigure"); + StringDictAddPair(pOption,"hmaddress","http://localhost:8080"); + StringDictAddPair(pOption,"hmconfigurescript","anstohm_full.xml"); /* initialise our private data structure */ pInternal = (pAnstoHttp)malloc(sizeof(anstoHttp)); @@ -770,17 +785,11 @@ pHistDriver CreateAnstoHttpDriver(pStringDict pOption){ memset(pInternal,0,sizeof(anstoHttp)); pNew->pPriv = pInternal; pInternal->syncRequest = ghttp_request_new(); - memset(pInternal->hmError,0,sizeof(pInternal->hmError)); if(pInternal->syncRequest == NULL){ free(pNew); free(pInternal); return NULL; } - /* direct = 0 Get HM from data files - * direct = 1 Get HM from http server */ - StringDictAddPair(pOption, "direct", "1"); - StringDictAddPair(pOption, "hmdatapath", "../HMData"); - StringDictAddPair(pOption, "scanpoint", "0"); /* configure all those functions */