MJL 16/3/07 Added transitional statuses, removed blocking code, improved performance under error conditions.
r1664 | mle | 2007-03-16 16:57:36 +1100 (Fri, 16 Mar 2007) | 2 lines
This commit is contained in:
committed by
Douglas Clowes
parent
f62af28efb
commit
4da6d932fb
@@ -21,7 +21,7 @@
|
||||
#include <ghttp.h>
|
||||
#include <stptok.h>
|
||||
#include <countdriv.h>
|
||||
#include <zlib.h>
|
||||
#include <nserver.h>
|
||||
|
||||
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;retries<MAX_STATUS_READ_RETRIES&&(initialentry||retcode!=requiredstate);retries++)
|
||||
int retries=0,initialentry=1,bad_status_requests=0;
|
||||
int retcode,runloop;
|
||||
do
|
||||
{
|
||||
retcode=AnstoHttpStatus(self,pCon);
|
||||
usleep(STATUS_READ_DELAY_US);
|
||||
int extrastatus;
|
||||
// Request current status from the histogram server.
|
||||
// The server usually responds within milliseconds.
|
||||
retcode=AnstoHttpStatus_Base(self,pCon,&extrastatus);
|
||||
retries++;
|
||||
bad_status_requests+=(extrastatus==ANSTO_HS_STATUS_INVALID);
|
||||
runloop=(retries<MAX_STATUS_READ_RETRIES)&&(initialentry||extrastatus!=requiredstate)
|
||||
&&(bad_status_requests<MAX_BAD_STATUS_REQUESTS);
|
||||
// Retry after a delay if status hasn't changed yet
|
||||
// (DAE takes time to start up / shut down)
|
||||
if (runloop) // Only wait if we're going to loop, otherwise drop out immediately
|
||||
{
|
||||
long long start_time_us=get_localtime_us();
|
||||
do // make sure the yield in this loop gets called at least once
|
||||
{
|
||||
// Service other SICS tasks while we wait.
|
||||
pTaskMan pTasker = GetTasker();
|
||||
if (pTasker)
|
||||
TaskYield(pTasker);
|
||||
} while(get_localtime_us()<(start_time_us+STATUS_READ_DELAY_USEC));
|
||||
}
|
||||
initialentry=0;
|
||||
}
|
||||
} while(runloop);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
@@ -452,7 +531,7 @@ static int AnstoHttpStart(pHistDriver self, SConnection *pCon){
|
||||
if(status != 1){
|
||||
return HWFault;
|
||||
}
|
||||
AnstoHttpStatusWithRetries(self,HWBusy,pCon);
|
||||
AnstoHttpStatusWithRetries(self,ANSTO_HS_STATUS_STARTED,pCon);
|
||||
return OKOK;
|
||||
}
|
||||
/*---------------------------------------------------------------------*/
|
||||
@@ -468,7 +547,7 @@ static int AnstoHttpHalt(pHistDriver self){ // hmm, why isn't there a pCon like
|
||||
return HWFault;
|
||||
}
|
||||
|
||||
AnstoHttpStatusWithRetries(self,HWIdle,NULL); // no pCon available :(
|
||||
AnstoHttpStatusWithRetries(self,ANSTO_HS_STATUS_STOPPED,NULL); // no pCon available :(
|
||||
|
||||
return OKOK;
|
||||
}
|
||||
@@ -486,7 +565,7 @@ static int AnstoHttpPause(pHistDriver self,SConnection *pCon){
|
||||
}
|
||||
pPriv->pause = 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 */
|
||||
|
||||
Reference in New Issue
Block a user