Files
sicspsi/sinqhttp.c
koennecke 32baca27f3 - Introduced a state filed into first generation objects
- Fixed some issues with error returns not being properly handled in devexec
- Fixed a bug in motorlist which caused limit checks to fail
- Fixed an issue with the TDCHM not properly updating the counter
  values on finish
- Readded getHipadabaPar in ChainCallback as this caused a problem in ei
- Made tasdrive ignore sgu, sgl when out of plane not allowed
2013-05-23 08:54:55 +00:00

757 lines
20 KiB
C

/*
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
----------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <HistDriv.i>
#include <tcl.h>
#include <ghttp.h>
#include <stptok.h>
#include <countdriv.h>
#include <trace.h>
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" };
static char subsample[] = { "/admin/processhmdata.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
#define HMNOMEMORY -709
#define BADSUBSAMPLE -710
/*=====================================================================
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;
int tricsswap;
} sinqHttp, *pSinqHttp;
/*------------------------------------------------------------------*/
static int sinqHttpGetPrepare(pSinqHttp 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 sinqHttpCheckResponse(pSinqHttp self)
{
char *pPtr = NULL;
int len;
self->failCount = 0;
pPtr = ghttp_get_body(self->syncRequest);
if (pPtr == NULL) {
return 1;
}
len = ghttp_get_body_len(self->syncRequest);
if (len > 511) {
len = 510;
}
if (strstr(pPtr, "ERROR") != NULL) {
memset(self->hmError, 0, 512 * sizeof(char));
strlcpy(self->hmError, pPtr, sizeof(self->hmError));
self->errorCode = HTTPERROR;
return 0;
} else if (strstr(pPtr, "Authentication Error") != NULL) {
memset(self->hmError, 0, 512 * sizeof(char));
strlcpy(self->hmError, pPtr, sizeof(self->hmError));
self->errorCode = BADAUTH;
return 0;
}
return 1;
}
/*-------------------------------------------------------------------*/
static int sinqHttpGet(pSinqHttp self, char *request)
{
ghttp_status httpStatus;
char *pPtr = NULL;
if (!sinqHttpGetPrepare(self, request)) {
return 0;
}
/*
* try two times: a reconnect is no error
*/
ghttp_prepare(self->syncRequest);
traceIO(self->hmAddress,"OUT:%s",request);
httpStatus = ghttp_process(self->syncRequest);
if (httpStatus != ghttp_done) {
ghttp_close(self->syncRequest);
sinqHttpGetPrepare(self, request);
ghttp_prepare(self->syncRequest);
httpStatus = ghttp_process(self->syncRequest);
}
if (httpStatus != ghttp_done) {
strlcpy(self->hmError, "Reconnect", 511);
self->errorCode = SERVERERROR;
return 0;
} else {
traceIO(self->hmAddress,"IN:%s",request);
return sinqHttpCheckResponse(self);
}
return 1;
}
/*====================================================================*/
static int SinqHttpConfigure(pHistDriver self, SConnection * pCon,
pStringDict pOpt, SicsInterp * pSics)
{
char hmname[512], buffer[132];
char confCommand[512], url[512];
pSinqHttp pPriv = NULL;
int status, iInit;
float fVal;
int i;
char *confData = NULL;
ghttp_status httpStatus;
pPriv = (pSinqHttp) 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;
}
}
status = StringDictGet(pOpt,"tricsswap", buffer, sizeof(buffer));
if(status == 1){
pPriv->tricsswap = atoi(buffer);
}
/*
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);
/* puts(confData); */
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;
}
/*---------------------------------------------------------------------*/
static int SinqHttpPreset(pHistDriver self, SConnection * pCon, int val)
{
pSinqHttp pPriv = NULL;
int status;
char command[512];
pPriv = (pSinqHttp) self->pPriv;
assert(pPriv != NULL);
snprintf(command, 512, "%s?value=%d", preset, val);
status = sinqHttpGet(pPriv, command);
if (status != 1) {
return HWFault;
}
return 1;
}
/*--------------------------------------------------------------------*/
static int SinqHttpStart(pHistDriver self, SConnection * pCon)
{
pSinqHttp pPriv = NULL;
int status;
pPriv = (pSinqHttp) self->pPriv;
assert(pPriv != NULL);
status = sinqHttpGet(pPriv, startdaq);
if (status != 1) {
return HWFault;
}
return 1;
}
/*---------------------------------------------------------------------*/
static int SinqHttpHalt(pHistDriver self)
{
pSinqHttp pPriv = NULL;
int status;
pPriv = (pSinqHttp) self->pPriv;
assert(pPriv != NULL);
status = sinqHttpGet(pPriv, stopdaq);
if (status != 1) {
return HWFault;
}
return 1;
}
/*---------------------------------------------------------------------*/
static int SinqHttpPause(pHistDriver self, SConnection * pCon)
{
pSinqHttp pPriv = NULL;
int status;
pPriv = (pSinqHttp) self->pPriv;
assert(pPriv != NULL);
status = sinqHttpGet(pPriv, pausedaq);
if (status != 1) {
return HWFault;
}
pPriv->pause = 1;
return 1;
}
/*---------------------------------------------------------------------*/
static int SinqHttpContinue(pHistDriver self, SConnection * pCon)
{
pSinqHttp pPriv = NULL;
int status;
pPriv = (pSinqHttp) self->pPriv;
assert(pPriv != NULL);
status = sinqHttpGet(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];
pSinqHttp self = NULL;
char *daqPtr = NULL, *daqValPtr = NULL;
self = (pSinqHttp) pDriv->pPriv;
assert(self != NULL);
pPtr = ghttp_get_body(self->syncRequest);
if (pPtr == NULL) {
strlcpy(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 SinqHttpStatus(pHistDriver self, SConnection * pCon)
{
pSinqHttp pPriv = NULL;
ghttp_status httpStatus;
char daqStatus[20];
int status, len;
char *pPtr = NULL;
pPriv = (pSinqHttp) self->pPriv;
assert(pPriv != NULL);
if (pPriv->pause == 1) {
return HWPause;
}
if (pPriv->asyncRunning == 0) {
status = sinqHttpGetPrepare(pPriv, statusdaq);
traceIO(pPriv->hmAddress,"OUT:%s", 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);
sinqHttpGetPrepare(pPriv, statusdaq);
ghttp_prepare(pPriv->syncRequest);
httpStatus = ghttp_process(pPriv->syncRequest);
if (httpStatus != ghttp_done) {
strlcpy(pPriv->hmError, "Reconnect", 511);
pPriv->errorCode = SERVERERROR;
pPriv->asyncRunning = 0;
return HWFault;
}
break;
case ghttp_not_done:
return HWBusy;
break;
case ghttp_done:
pPriv->asyncRunning = 0;
status = sinqHttpCheckResponse(pPriv);
if (status != 1) {
return HWFault;
}
traceIO(pPriv->hmAddress,"IN:%s", statusdaq);
break;
}
status = readStatus(self);
if (status != 1) {
return HWFault;
}
if (StringDictGet(self->pOption, "daq", daqStatus, 20) != 1) {
pPriv->errorCode = BADSTATUS;
strlcpy(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 SinqHttpError(pHistDriver self, int *code,
char *error, int errLen)
{
pSinqHttp pPriv = NULL;
int status;
pPriv = (pSinqHttp) self->pPriv;
assert(pPriv != NULL);
strlcpy(error, pPriv->hmError, errLen);
*code = pPriv->errorCode;
return 1;
}
/*--------------------------------------------------------------------*/
static int SinqHttpFixIt(pHistDriver self, int code)
{
pSinqHttp pPriv = NULL;
pPriv = (pSinqHttp) 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 SinqHttpGetData(pHistDriver self, SConnection * pCon)
{
/*
* do noting, monitors are with the counter, histogram memory
* caching and retrieval is handled via GetHistogram
*/
return 1;
}
/*-------------------------------------------------------------------
* This is an ugly hack to swap TRICS data into the
* correct order.
*/
static void swapTrics(HistInt *data, pHMdata hmdata, int length)
{
int x,y, xdim, ydim;
HistInt *tmpData = NULL, val;
/*
* do nothing if no match
*/
xdim = hmdata->iDim[0];
ydim = hmdata->iDim[1];
if(xdim*ydim < length){
return;
}
tmpData = malloc(length*sizeof(HistInt));
if(tmpData == NULL){
return;
}
memcpy(tmpData, data, length*sizeof(HistInt));
for(y = 0; y < ydim; y++){
for(x = 0; x < xdim; x++){
val = tmpData[x*ydim + y];
data[y*xdim+x] = val;
}
}
free(tmpData);
}
/*-------------------------------------------------------------------*/
static int SinqHttpGetHistogram(pHistDriver self, SConnection * pCon,
int bank, int start, int end,
HistInt * data)
{
char command[256];
HistInt *hmdata;
pSinqHttp pPriv = NULL;
int status, len, i;
long dataSum = 0;
pPriv = (pSinqHttp) self->pPriv;
assert(pPriv != NULL);
snprintf(command, 255, "%s?bank=%d&start=%d&end=%d", gethm, bank,
start, end);
/* printf("SinqHttpGetHistogram:%d-%d\n", start,end); */
status = sinqHttpGet(pPriv, command);
if (status != 1) {
return HWFault;
}
len = ghttp_get_body_len(pPriv->syncRequest);
if (len < (end - start) * sizeof(int)) {
pPriv->errorCode = BODYSHORT;
strlcpy(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]);
dataSum += data[i];
}
/* printf("Read %ld counts from HM\n", dataSum); */
if(pPriv->tricsswap == 1){
swapTrics(data, self->data, end-start);
} else if(pPriv->tricsswap == 2) {
memcpy(data,hmdata,(end-start)*sizeof(HistInt));
}
return 1;
}
/*-------------------------------------------------------------------*/
static HistInt *SinqHttpSubSample(pHistDriver self, SConnection * pCon,
int bank, char *hmcommand)
{
char command[1024];
HistInt *hmdata = NULL;
HistInt *resultdata = NULL;
pSinqHttp pPriv = NULL;
int status, len, i;
pPriv = (pSinqHttp) self->pPriv;
assert(pPriv != NULL);
snprintf(command, 1023, "%s?bank=%d&command=%s", subsample, bank,
hmcommand);
status = sinqHttpGet(pPriv, command);
if (status != 1) {
if(pCon != NULL){
SCPrintf(pCon,eError,"ERROR: subsampling failed with %s", pPriv->hmError);
}
return NULL;
}
len = ghttp_get_body_len(pPriv->syncRequest);
if (len <= 0) {
strlcpy(pPriv->hmError, "ERROR: no data returned from subsampling",
511);
pPriv->errorCode = BADSUBSAMPLE;
return NULL;
}
resultdata = malloc(len + 4);
if (resultdata == NULL) {
strlcpy(pPriv->hmError,
"ERROR: failed to allocate buffer for subsampling results",
511);
pPriv->errorCode = HMNOMEMORY;
return NULL;
}
resultdata[0] = len / sizeof(HistInt);
hmdata = (HistInt *) ghttp_get_body(pPriv->syncRequest);
for (i = 0; i < len / sizeof(HistInt); i++) {
resultdata[i + 1] = ntohl(hmdata[i]);
}
return resultdata;
}
/*--------------------------------------------------------------------*/
static int SinqHttpSetHistogram(pHistDriver self, SConnection * pCon,
int bank, int start, int end,
HistInt * data)
{
pSinqHttp pPriv = NULL;
pPriv = (pSinqHttp) self->pPriv;
assert(pPriv != NULL);
pPriv->errorCode = NOTIMPLEMENTED;
strlcpy(pPriv->hmError, "Not implemented", 511);
return HWFault;
}
/*---------------------------------------------------------------------*/
static long SinqHttpGetMonitor(pHistDriver self, int i, SConnection * pCon)
{
return 0;
}
/*---------------------------------------------------------------------*/
static float SinqHttpGetTime(pHistDriver self, SConnection * pCon)
{
return -999.99;
}
/*---------------------------------------------------------------------*/
static int SinqHttpFreePrivate(pHistDriver self)
{
pSinqHttp pPriv = NULL;
pPriv = (pSinqHttp) self->pPriv;
if (pPriv == NULL) {
return 1;
}
if (pPriv->syncRequest != NULL) {
ghttp_request_destroy(pPriv->syncRequest);
}
free(pPriv);
return 1;
}
/*-------------------------------------------------------------------*/
pHistDriver CreateSinqHttpDriver(pStringDict pOption)
{
pHistDriver pNew = NULL;
pSinqHttp 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 = (pSinqHttp) malloc(sizeof(sinqHttp));
if (!pInternal) {
free(pNew);
return NULL;
}
memset(pInternal, 0, sizeof(sinqHttp));
pNew->pPriv = pInternal;
pInternal->syncRequest = ghttp_request_new();
if (pInternal->syncRequest == NULL) {
free(pNew);
free(pInternal);
return NULL;
}
/* configure all those functions */
pNew->Configure = SinqHttpConfigure;
pNew->Start = SinqHttpStart;
pNew->Halt = SinqHttpHalt;
pNew->GetCountStatus = SinqHttpStatus;
pNew->GetError = SinqHttpError;
pNew->TryAndFixIt = SinqHttpFixIt;
pNew->GetData = SinqHttpGetData;
pNew->GetHistogram = SinqHttpGetHistogram;
pNew->GetHistogram = SinqHttpGetHistogram;
pNew->SubSample = SinqHttpSubSample;
pNew->GetMonitor = SinqHttpGetMonitor;
pNew->GetTime = SinqHttpGetTime;
pNew->Preset = SinqHttpPreset;
pNew->FreePrivate = SinqHttpFreePrivate;
pNew->Pause = SinqHttpPause;
pNew->Continue = SinqHttpContinue;
return pNew;
}
/*-------------------------------------------------------------------------*/
int isSINQHTTP(pHistDriver self){
if(self->Start == SinqHttpStart){
return 1;
} else {
return 0;
}
}