diff --git a/site_ansto/anstohttp.c b/site_ansto/anstohttp.c new file mode 100644 index 00000000..d87bf9a0 --- /dev/null +++ b/site_ansto/anstohttp.c @@ -0,0 +1,595 @@ +/* + 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 + +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; +}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); + 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); + anstoHttpGetPrepare(self,request); + 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; + 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 == 0){ + 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){ + confData = (char *)ghttp_get_error(pPriv->syncRequest); + snprintf(confCommand,511,"ERROR: http error %s occurred", + confData); + SCWrite(pCon,confCommand,eError); + return 0; + } else { + 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; +} +/*--------------------------------------------------------------------*/ +static int AnstoHttpStart(pHistDriver self, SConnection *pCon){ + pAnstoHttp pPriv = NULL; + int status; + + pPriv = (pAnstoHttp)self->pPriv; + assert(pPriv != NULL); + + status = anstoHttpGet(pPriv,startdaq); + if(status != 1){ + return HWFault; + } + return 1; +} +/*---------------------------------------------------------------------*/ +static int AnstoHttpHalt(pHistDriver self){ + pAnstoHttp pPriv = NULL; + int status; + + pPriv = (pAnstoHttp)self->pPriv; + assert(pPriv != NULL); + + status = anstoHttpGet(pPriv,stopdaq); + if(status != 1){ + return HWFault; + } + return 1; +} +/*---------------------------------------------------------------------*/ +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; + return 1; +} +/*---------------------------------------------------------------------*/ +static int AnstoHttpContinue(pHistDriver self, SConnection *pCon){ + pAnstoHttp pPriv = NULL; + int status; + + pPriv = (pAnstoHttp)self->pPriv; + assert(pPriv != NULL); + + status = anstoHttpGet(pPriv,continuedaq); + if(status != 1){ + return HWFault; + } + pPriv->pause = 0; + 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; +} +/*---------------------------------------------------------------------*/ +static int AnstoHttpStatus(pHistDriver self,SConnection *pCon){ + pAnstoHttp pPriv = NULL; + ghttp_status httpStatus; + char daqStatus[20]; + int status, len; + char *pPtr = NULL; + + pPriv = (pAnstoHttp)self->pPriv; + assert(pPriv != NULL); + + 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){ + 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; + return HWFault; + pPriv->asyncRunning = 0; + } + break; + case ghttp_not_done: + return HWBusy; + break; + case ghttp_done: + pPriv->asyncRunning = 0; + status = anstoHttpCheckResponse(pPriv); + if(status != 1){ + return HWFault; + } + break; + } + + + status = readStatus(self); + if(status != 1){ + return HWFault; + } + +// TO BE REMOVED!!! + // MJL DEBUG + return HWIdle; + + + if(StringDictGet(self->pOption,"daq",daqStatus,20) != 1){ + pPriv->errorCode = BADSTATUS; + strncpy(pPriv->hmError,"ERROR: status does not contain DAQ field",511); + return HWFault; + } + if(strstr(daqStatus,"1") != NULL){ + return HWBusy; + } else if(strstr(daqStatus,"0") != NULL){ + return HWIdle; + } else { + pPriv->errorCode = BADSTATUS; + snprintf(pPriv->hmError,511,"ERROR: invalid DAQ status %s",daqStatus); + return HWFault; + } + + return HWIdle; +} +/*---------------------------------------------------------------------*/ +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 1; +} +/*--------------------------------------------------------------------*/ +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 1; +} +/*-------------------------------------------------------------------*/ +static int AnstoHttpGetHistogram(pHistDriver self, SConnection *pCon, + int bank, int start, int end, HistInt *data){ + char command[256]; + HistInt *hmdata; + pAnstoHttp pPriv = NULL; + int status, len, i; + + pPriv = (pAnstoHttp)self->pPriv; + assert(pPriv != NULL); + + snprintf(command,255,"%s?bank=%d&start=%d&end=%d",gethm,bank, + start,end); + + status = anstoHttpGet(pPriv,command); + if(status != 1){ + return HWFault; + } + + len = ghttp_get_body_len(pPriv->syncRequest); + if(len < (end-start)*sizeof(int)){ + pPriv->errorCode = BODYSHORT; + strncpy(pPriv->hmError,"Not enough data received from HM",511); + return HWFault; + } + hmdata = (HistInt *)ghttp_get_body(pPriv->syncRequest); + for(i = 0; i < (end - start); i++){ + data[i] = ntohl(hmdata[i]); + } + return 1; +} +/*--------------------------------------------------------------------*/ +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://unknown.psi.ch:9090"); + StringDictAddPair(pOption,"hmconfigurescript","hmconfigure"); + + /* 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; + } + + + /* 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; +} diff --git a/site_ansto/anstohttp.h b/site_ansto/anstohttp.h new file mode 100644 index 00000000..291a3a40 --- /dev/null +++ b/site_ansto/anstohttp.h @@ -0,0 +1,23 @@ +/* + This is a histogram mmeory driver for the 2005-6 version of the + histogram mmeory 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)fs + +----------------------------------------------------------------------*/ +#ifndef SINQHTTP_H_ +#define SINQHTTP_H_ +#include + +pHistDriver CreateAnstoHttpDriver(pStringDict pOption); + +#endif /*SINQHTTP_H_*/