/* This is a histogram memory driver for the 2005-6 version of the histogram memory software based on RTAI-Linux and an embedded WWW-server for communications. For all http work the ghttp library from the gnome project is used. This HM is meant to be used in conjunction with a counter module chained through the hmcontrol module. No need to handle counters here when hmcontrol can do the chaining. copyright: see file COPYRIGHT Mark Koennecke, January 2005 (original SINQ version) Mark Lesha, 9 October 2006 (ANSTO version) ----------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include extern char *trim(char *); /*=================================================================== The request strings to append to the computer address ====================================================================*/ static char startdaq[] = {"/admin/startdaq.egi"}; static char stopdaq[] = {"/admin/stopdaq.egi"}; static char pausedaq[] = {"/admin/pausedaq.egi"}; static char continuedaq[] = {"/admin/continuedaq.egi"}; static char statusdaq[] = {"/admin/textstatus.egi"}; static char gethm[] = {"/admin/readhmdata.egi"}; static char configure[] = {"/admin/configure.egi"}; static char preset[] = {"/admin/presethm.egi"}; /*==================================================================== error codes ======================================================================*/ #define BADURL -701 #define HTTPERROR -702 #define NOBODY -703 #define BODYSHORT -704 #define NOTIMPLEMENTED -705 #define SERVERERROR -706 #define BADSTATUS -707 #define BADAUTH -708 /*===================================================================== our driver private data structure ======================================================================*/ typedef struct { ghttp_request *syncRequest; char hmAddress[512]; char userName[132]; char passWord[132]; char hmError[512]; int errorCode; int pause; int failCount; int asyncRunning; // Keep a local copy of the dictionary pointer in our internal data structure. // We initialize this pointer with the one passed in when the object is created. // This is used to allow certain functions (like AnstoHttpGetHistogram) to access // the dictionary, even though a pointer to the dictionary isn't passed in. // Hopefully this will not have any side effects. pStringDict pOption; }anstoHttp, *pAnstoHttp; /*------------------------------------------------------------------*/ static int anstoHttpGetPrepare(pAnstoHttp self, char *request){ char url[512]; ghttp_status httpStatus; if(self->asyncRunning){ while((httpStatus = ghttp_process(self->syncRequest)) == ghttp_not_done){ } self->asyncRunning = 0; } self->errorCode = 0; ghttp_clean(self->syncRequest); memset(self->hmError,0,512*sizeof(char)); snprintf(url,511,"%s%s",self->hmAddress,request); ghttp_set_type(self->syncRequest,ghttp_type_get); ghttp_set_header(self->syncRequest,"connection","keep-alive"); if(ghttp_set_uri(self->syncRequest,url) < 0){ self->errorCode = BADURL; return 0; } ghttp_set_authinfo(self->syncRequest,self->userName, self->passWord); ghttp_set_sync(self->syncRequest,ghttp_sync); return 1; } /*-------------------------------------------------------------------*/ static int anstoHttpCheckResponse(pAnstoHttp self){ char *pPtr = NULL; int len; self->failCount = 0; pPtr = ghttp_get_body(self->syncRequest); if(pPtr == NULL) // MJL check ghttp_get_body for NULL return return 1; // empty response is okay len = ghttp_get_body_len(self->syncRequest); if(len > 511){ len = 510; } if(strstr(pPtr,"ERROR") != NULL){ memset(self->hmError,0,512*sizeof(char)); strncpy(self->hmError,pPtr, len); self->errorCode = HTTPERROR; return 0; } else if(strstr(pPtr,"Authentication Error") != NULL){ memset(self->hmError,0,512*sizeof(char)); strncpy(self->hmError,pPtr, len); self->errorCode = BADAUTH; return 0; } return 1; } /*-------------------------------------------------------------------*/ static int anstoHttpGet(pAnstoHttp self, char *request){ ghttp_status httpStatus; char *pPtr = NULL; if(!anstoHttpGetPrepare(self,request)){ return 0; } /* * try two times: a reconnect is no error */ ghttp_prepare(self->syncRequest); httpStatus = ghttp_process(self->syncRequest); if(httpStatus != ghttp_done){ ghttp_close(self->syncRequest); if (!anstoHttpGetPrepare(self,request)) return 0; // MJL return here if failed ghttp_prepare(self->syncRequest); // MJL be sure to call ghttp_prepare before each ghttp_process httpStatus = ghttp_process(self->syncRequest); } if(httpStatus != ghttp_done){ strncpy(self->hmError,"Reconnect", 511); self->errorCode = SERVERERROR; return 0; } else { return anstoHttpCheckResponse(self); } return 1; } /*====================================================================*/ static int AnstoHttpConfigure(pHistDriver self, SConnection *pCon, pStringDict pOpt, SicsInterp *pSics){ char hmname[512]; char confCommand[512], url[512]; pAnstoHttp pPriv = NULL; int status, iInit; float fVal; int i; char *confData = NULL; ghttp_status httpStatus; pPriv = (pAnstoHttp)self->pPriv; assert(pPriv != NULL); /* * The HM computer address */ if(StringDictGet(pOpt,"hmaddress",pPriv->hmAddress, 511) != 1){ SCWrite(pCon, "ERROR: required configuration parameter hmaddress not found", eError); return 0; } /* * looser credentials */ if(StringDictGet(pOpt,"username",pPriv->userName, 131) != 1){ SCWrite(pCon, "ERROR: required configuration parameter username not found", eError); return 0; } if(StringDictGet(pOpt,"password",pPriv->passWord, 131) != 1){ SCWrite(pCon, "ERROR: required configuration parameter password not found", eError); return 0; } /* actual configuration. Check for flag INIT in options. We do not need to configure, if the HM has configured itself already. What is does, these days. */ status = StringDictGetAsNumber(pOpt,"init",&fVal); iInit = 0; if(status == 1) { if(fVal > 0.9 ) { iInit = 1; } } /* actually do configure */ if(iInit == 1){ for(i = 0; i < 2; i++){ memset(confCommand,0,512*sizeof(char)); if(StringDictGet(pOpt,"hmconfigscript",confCommand,511) != 1){ SCWrite(pCon, "ERROR: required parameter hmconfigscript not found!", eError); return 0; } status = Tcl_Eval(pSics->pTcl,confCommand); if(status != TCL_OK){ snprintf(confCommand,511, "ERROR: Tcl reported %s while evaluating hmconfigscript", Tcl_GetStringResult(pSics->pTcl)); SCWrite(pCon,confCommand,eError); return 0; } else { /* uplod new configuration to HM */ ghttp_clean(pPriv->syncRequest); snprintf(url,511,"%s%s",pPriv->hmAddress,configure); status = ghttp_set_uri(pPriv->syncRequest,url); if(status < 0){ SCWrite(pCon,"ERROR: invalid URI for HM request",eError); return 0; } status = ghttp_set_type(pPriv->syncRequest,ghttp_type_post); confData = (char *)Tcl_GetStringResult(pSics->pTcl); status = ghttp_set_body(pPriv->syncRequest,confData, strlen(confData)); ghttp_set_authinfo(pPriv->syncRequest, pPriv->userName, pPriv->passWord); ghttp_set_sync(pPriv->syncRequest,ghttp_sync); status = ghttp_prepare(pPriv->syncRequest); httpStatus = ghttp_process(pPriv->syncRequest); confData = (char *)ghttp_get_body(pPriv->syncRequest); if(httpStatus != ghttp_done){ /* we may need to reconnect..... */ if(i == 0){ ghttp_close(pPriv->syncRequest); continue; } /* * no we have a real error */ confData = (char *)ghttp_get_error(pPriv->syncRequest); snprintf(confCommand,511,"ERROR: http error %s occurred", confData); SCWrite(pCon,confCommand,eError); return 0; } else if(confData != NULL){ if(strstr(confData,"ERROR") != NULL){ snprintf(confCommand,511,"%s",confData); SCWrite(pCon,confCommand,eError); return 0; } if(strstr(confData,"Authentication Error") != NULL){ snprintf(confCommand,511,"%s",confData); SCWrite(pCon,confCommand,eError); return 0; } return 1; } } } } // MJL NOTE: Added extra init parameters here, these get committed // regardless of whether we are doing the first init or not // (i.e. will get committed even if init=1). // Need to do init on the histogram object (e.g. 'hm init') // in order to commit changed settings during operation. // Specifically, this is important if FAT settings need to be // modified during operation. To do this, the command // 'hm configure FAT_Xxxx vvv' needs to be performed, // where Xxxx is the name of the item in the FAT, and vvv is the desired value. // If the requested FAT variable doesn't exist or cannot be modified // during operation, the set fails but no indication is given. // // Now, to find out what entries are FAT_Xxxx format, /// by traversing the dictionary list. char pValue[256]; const char *pItem=NULL; do { pItem=StringDictGetNext(pOpt,pValue,256); if (pItem) { if (strncasecmp(pItem,"FAT_",4)==0) { // Try committing the setting to the histogram server // Make special http request to set the FAT parameter char modify_FAT_http_request[1024]; sprintf(modify_FAT_http_request, "/admin/selectdynamicfatmodify.egi?dynamicFATmodifyparamname=%s&dynamicFATmodifyparamvalue=%s", pItem+4,pValue); // Send the request. When one doesn't work, drop out of the loop. int status = anstoHttpGet(pPriv,modify_FAT_http_request); if(status != 1) return 0; } } } while(pItem); return 1; } /*--------------------------------------------------------------------*/ static int readStatus(pHistDriver pDriv){ char *pPtr = NULL, *pLinePtr; char line[132]; char name[80], value[80]; pAnstoHttp self = NULL; char *daqPtr = NULL, *daqValPtr = NULL; self = (pAnstoHttp)pDriv->pPriv; assert(self != NULL); pPtr = ghttp_get_body(self->syncRequest); if(pPtr == NULL){ strncpy(self->hmError,"No body in status response",131); self->errorCode = NOBODY; return 0; } pPtr = stptok(pPtr,line,132,"\n"); while(pPtr != NULL){ pLinePtr = line; pLinePtr = stptok(pLinePtr,name,80,":"); pLinePtr = stptok(pLinePtr,value,80,":"); strtolower(name); if(StringDictExists(pDriv->pOption,trim(name)) == 1){ StringDictUpdate(pDriv->pOption,trim(name),trim(value)); } else { StringDictAddPair(pDriv->pOption,trim(name),trim(value)); } pPtr = stptok(pPtr,line,131,"\n"); } return 1; } /*---------------------------------------------------------------------*/ // The status code now allows pCon==NULL to be passed in. // 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. // // 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); // MJL for the ANSTO histogram server we STILL need status checking to occur // even when in paused mode (our pause mode has a different functionality). // So the code below is removed. /// if(pPriv->pause == 1){ /// return HWPause; /// } if(pPriv->asyncRunning == 0){ status = anstoHttpGetPrepare(pPriv,statusdaq); 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; } httpStatus = ghttp_process(pPriv->syncRequest); switch(httpStatus){ case ghttp_error: ghttp_close(pPriv->syncRequest); anstoHttpGetPrepare(pPriv,statusdaq); ghttp_prepare(pPriv->syncRequest); httpStatus = ghttp_process(pPriv->syncRequest); 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; } break; case ghttp_not_done: // MJL this is not a problem, the server is just slow. // return HWRedo not HWBusy (original) or falut return HWRedo; break; case ghttp_done: pPriv->asyncRunning = 0; status = anstoHttpCheckResponse(pPriv); if(status != 1){ if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_INVALID; return HWFault; } break; } 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){ if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_STARTED; return last_known_status=HWBusy; } else if(strstr(daqStatus,"Paused") != NULL){ if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_PAUSED; return last_known_status=HWIdle; } else if(strstr(daqStatus,"Stopped") != NULL){ 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; } 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 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=0,initialentry=1,bad_status_requests=0; int retcode,runloop; do { 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=(retriespPriv; assert(pPriv != NULL); status = anstoHttpGet(pPriv,startdaq); if(status != 1){ return HWFault; } AnstoHttpStatusWithRetries(self,ANSTO_HS_STATUS_STARTED,pCon); return OKOK; } /*---------------------------------------------------------------------*/ static int AnstoHttpHalt(pHistDriver self){ // hmm, why isn't there a pCon like all the other ones...? pAnstoHttp pPriv = NULL; int status; char checkstatus[20]="false"; int i; pPriv = (pAnstoHttp)self->pPriv; assert(pPriv != NULL); status = anstoHttpGet(pPriv,stopdaq); if(status != 1){ return HWFault; } //TODO check statuscheck flag StringDictGet(self->pOption,"statuscheck",checkstatus,20); if (strcmp(checkstatus,"true") == 0) { AnstoHttpStatusWithRetries(self,ANSTO_HS_STATUS_STOPPED,NULL); // no pCon available :( } return OKOK; } /*---------------------------------------------------------------------*/ static int AnstoHttpPause(pHistDriver self,SConnection *pCon){ pAnstoHttp pPriv = NULL; int status; pPriv = (pAnstoHttp)self->pPriv; assert(pPriv != NULL); status = anstoHttpGet(pPriv,pausedaq); if(status != 1){ return HWFault; } pPriv->pause = 1; AnstoHttpStatusWithRetries(self,ANSTO_HS_STATUS_PAUSED,pCon); return OKOK; } /*---------------------------------------------------------------------*/ static int AnstoHttpContinue(pHistDriver self, SConnection *pCon){ pAnstoHttp pPriv = NULL; int status; pPriv = (pAnstoHttp)self->pPriv; assert(pPriv != NULL); status = anstoHttpGet(pPriv,continuedaq); // which is the same as restarting if(status != 1){ return HWFault; } pPriv->pause = 0; AnstoHttpStatusWithRetries(self,ANSTO_HS_STATUS_STARTED,pCon); return OKOK; } /*---------------------------------------------------------------------*/ static int AnstoHttpError(pHistDriver self, int *code, char *error, int errLen){ pAnstoHttp pPriv = NULL; int status; pPriv = (pAnstoHttp)self->pPriv; assert(pPriv != NULL); strncpy(error,pPriv->hmError, errLen); *code = pPriv->errorCode; return OKOK; } /*--------------------------------------------------------------------*/ static int AnstoHttpFixIt(pHistDriver self, int code){ pAnstoHttp pPriv = NULL; pPriv = (pAnstoHttp)self->pPriv; assert(pPriv != NULL); /* * not much to fix here: ghttplib already tries hard to fix * connection problems... But abort any pending transactions... */ ghttp_close(pPriv->syncRequest); if(code == SERVERERROR){ pPriv->failCount++; if(pPriv->failCount > 2){ return COTERM; } else { return COREDO; } } return COTERM; } /*--------------------------------------------------------------------*/ static int AnstoHttpGetData(pHistDriver self,SConnection *pCon){ /* * do noting, monitors are with the counter, histogram memory * caching and retrieval is handled via GetHistogram */ return OKOK; } /*-------------------------------------------------------------------*/ static int AnstoHttpGetHistogram(pHistDriver self, SConnection *pCon, int bank, int start, int end, HistInt *data){ char command[1024]; // can be quite long now, if read_data_xxx options are appended HistInt *hmdata; pAnstoHttp pPriv = NULL; int status, len, i; // For the ANSTO Histogram Server, the transfer size may be large // and this can lead to transmission of the data from the server in chunks. // This is apparent from the presence of 'xxxxx; chunk length nnnnnn' in the // data when the transfer size is greater than 128K. // e.g. a request for 64K elements is split into two chunks, // and each has the header '20000; chunk length 131072'. // However for some reason ghttp_get_body_len returns only the data size, // even though there are header(s) added to the data. // So, for the time being we play it safe and divide the transfer // into chunks of less than 128KB. // // MJL 22/11/06: Found that AppWeb 2.1.0 supports HTTP 1.1 chunking, // but this can be turned off by specifying HttpChunking off in the AppWeb // config file, which is what we do currently, so the transfer size limitation code below // is no longer needed. I've left it in with a much larger size restriction, // just in case it's required later on for any reason (to improve transfer reliability?). // Apparently the AppWeb 2.1.0 HTTP chunking feature is broken, because when the // data is opened directly from the web server using an editor like KHexEdit, the open // stalls for large data sizes unless chunking is disabled. This shows it is // an AppWeb problem, not a ghttp problem. // For AppWeb versions before 2.1.0, HTTP chunking is not available anyway. pPriv = (pAnstoHttp)self->pPriv; assert(pPriv != NULL); // How this limit is set in the server is not obvious... anyway, it should not change. // MJL 22/11/06: Turned HTTP 1.1 chunking off at the histogram server, so we no longer // need a size restriction. Leave the code in just in case it's needed for other reasons, // but set a larger maximum request size. // MJL 19/3/07 Because some clients now perform requests without valid start and end parameters, // the code below won't work properly in some cases. As a temporary fix, effectively disable it // by setting MAX_HTTP_REQUEST_BYTES to a very large value (4GB = 1Gint). // Note, actual transfer of such large data sizes in one hit may fail, not recommended. //#define MAX_HTTP_REQUEST_BYTES 131072 //#define MAX_HTTP_REQUEST_BYTES 1048576 #define MAX_HTTP_REQUEST_BYTES (((long long)4096)*1048576) // max transfer size 4GB (but your mileage may vary) // Do the HTTP data transfer in bite sized pieces while(end>start) { int size=((end-start)>(MAX_HTTP_REQUEST_BYTES/sizeof(int))) ?(MAX_HTTP_REQUEST_BYTES/sizeof(int)):(end-start); // Send traditional SICS bank,start,end parameters to the server // bank is now ignored by the server though, and start and end // may be overridden by supplementary settings (see below). int ncommand=snprintf(command,1023,"%s?bank=%d&start=%d&end=%d",gethm,bank, start,start+size); // Now add specific items read_data_xxxx in the string dictionary // to the HTTP request. These act to selectively override the // default read-data configuration at the server, so we can select // different dataypes and formats. // We use the internally-stored dictionary pointer for this purpose, // since one isn't provided in the argument list. char *pcommand_build=command+ncommand; char pValue[256]; const char *pItem=NULL; do { pItem=StringDictGetNext(pPriv->pOption,pValue,256); if (pItem) { if (strncasecmp(pItem,"read_data_",10)==0) { pcommand_build+=sprintf(pcommand_build,"&%s=%s",pItem,pValue); } } } while(pItem); // Send our request status = anstoHttpGet(pPriv,command); if(status != 1){ return HWFault; } len = ghttp_get_body_len(pPriv->syncRequest); if(len < size*sizeof(int)){ pPriv->errorCode = BODYSHORT; strncpy(pPriv->hmError,"Not enough data received from HM",511); return HWFault; } hmdata = (HistInt *)ghttp_get_body(pPriv->syncRequest); if(hmdata == NULL){ // MJL check ghttp_get_body for NULL return pPriv->errorCode = NOBODY; strncpy(pPriv->hmError,"No body in HM data response",511); return HWFault; } // MJL removed the ntohl, our histogram server doesn't apply htonl, // so the data arrives in LE format. (Would have to buffer data // at the server otherwise...) // Doubt this will raise any conpatibility issues. for(i = 0; i < size; i++){ //data[i] = ntohl(hmdata[i]); data[i] = hmdata[i]; } data+=size; start+=size; } return OKOK; } /*--------------------------------------------------------------------*/ static int AnstoHttpSetHistogram(pHistDriver self, SConnection *pCon, int bank, int start, int end, HistInt *data){ pAnstoHttp pPriv = NULL; pPriv = (pAnstoHttp)self->pPriv; assert(pPriv != NULL); pPriv->errorCode = NOTIMPLEMENTED; strncpy(pPriv->hmError,"Not implemented",511); return HWFault; } /*---------------------------------------------------------------------*/ static long AnstoHttpGetMonitor(pHistDriver self, int i, SConnection *pCon){ return 0; } /*---------------------------------------------------------------------*/ static float AnstoHttpGetTime(pHistDriver self, SConnection *pCon){ return -999.99; } /*---------------------------------------------------------------------*/ static int AnstoHttpPreset(pHistDriver self, SConnection *pCon, int val){ pAnstoHttp pPriv = NULL; int status; char command[512]; pPriv = (pAnstoHttp)self->pPriv; assert(pPriv != NULL); snprintf(command,512,"%s?value=%d",preset,val); status = anstoHttpGet(pPriv,command); if(status != 1){ return HWFault; } return 1; } /*---------------------------------------------------------------------*/ static int AnstoHttpFreePrivate(pHistDriver self){ pAnstoHttp pPriv = NULL; pPriv = (pAnstoHttp)self->pPriv; if(pPriv == NULL){ return 1; } if(pPriv->syncRequest != NULL){ ghttp_request_destroy(pPriv->syncRequest); } free(pPriv); return 1; } /*-------------------------------------------------------------------*/ pHistDriver CreateAnstoHttpDriver(pStringDict pOption){ pHistDriver pNew = NULL; pAnstoHttp pInternal = NULL; /* create the general driver */ pNew = CreateHistDriver(pOption); if(!pNew){ return NULL; } /* add our options */ StringDictAddPair(pOption,"hmaddress","http://localhost:8080"); StringDictAddPair(pOption,"hmconfigurescript","anstohm_full.xml"); StringDictAddPair(pOption,"statuscheck","false"); /* initialise our private data structure */ pInternal = (pAnstoHttp)malloc(sizeof(anstoHttp)); if(!pInternal){ free(pNew); return NULL; } memset(pInternal,0,sizeof(anstoHttp)); pNew->pPriv = pInternal; pInternal->syncRequest = ghttp_request_new(); if(pInternal->syncRequest == NULL){ free(pNew); free(pInternal); return NULL; } // Save a pointer to the string dictionary internally, // for the use of those functions that require it and // don't get a pOption passed in via the argument list. pInternal->pOption=pOption; /* configure all those functions */ pNew->Configure = AnstoHttpConfigure; pNew->Start = AnstoHttpStart; pNew->Halt = AnstoHttpHalt; pNew->GetCountStatus = AnstoHttpStatus; pNew->GetError = AnstoHttpError; pNew->TryAndFixIt = AnstoHttpFixIt; pNew->GetData = AnstoHttpGetData; pNew->GetHistogram = AnstoHttpGetHistogram; pNew->SetHistogram = AnstoHttpSetHistogram; pNew->GetMonitor = AnstoHttpGetMonitor; pNew->GetTime = AnstoHttpGetTime; pNew->Preset = AnstoHttpPreset; pNew->FreePrivate = AnstoHttpFreePrivate; pNew->Pause = AnstoHttpPause; pNew->Continue = AnstoHttpContinue; return pNew; }