Files
sics/amorstat.c
cvs fc6c4acd79 D.Maden. 11-Sep-2000.
Makefiles modified to generate a Linux SICServer.
   Other files modified to get rid of irritating compiler warning messages.
2000-09-11 09:17:43 +00:00

773 lines
21 KiB
C

/*--------------------------------------------------------------------------
A M O R S T A T U S
The implementation file for the amor status display facilitator module. The
reflectometer AMOR needs some advanced feautures for its status display.
These needs are taken care of here.
copyright: see copyright.h
Mark Koennecke, September 1999
--------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <tcl.h>
#include "fortify.h"
#include "sics.h"
#include "counter.h"
#include "HistMem.h"
#include "scan.h"
#include "lld.h"
#include "amorstat.i"
#include "amorstat.h"
/*-------------------------------------------------------------------------
A static which determines if we are in TOF or scan mode.
*/
static int iTOF = 0;
static pHistMem pHMHM = NULL;
/*-------------------------------------------------------------------------*/
static int HMCountStartCallback(int iEvent, void *pEvent, void *pUser)
{
SConnection *pCon = (SConnection *)pUser;
const float *fTime = NULL;
int *iTime = NULL;
int iLength, iRet, i;
assert(pCon);
if(iEvent == COUNTSTART)
{
/* send current time binning */
iTOF = 1;
fTime = GetHistTimeBin(pHMHM,&iLength);
iTime = (int *)malloc((iLength+1)*sizeof(int));
if( (!fTime) || (!iTime))
{
return 0;
}
iTime[0] = htonl(iLength);
for(i = 0 ; i < iLength; i++)
{
iTime[i+1] = htonl((int)(fTime[i]*65536.));
}
/* send new time binning to all clients */
SCWrite(pCon,"TOFClear",eError);
SCWriteUUencoded(pCon,"arrowaxis_time",iTime,
(iLength+1)*sizeof(int));
free(iTime);
}
return 1;
}
/*-------------------------------------------------------------------------*/
static int ScanStartCallback(int iEvent, void *pEvent, void *pUser)
{
float *fAxis = NULL;
int *iAxis = NULL;
int iLength, iRet, i;
char pBueffel[80], pName[40];
SConnection *pCon = (SConnection *)pUser;
pScanData pScan = (pScanData)pEvent;
assert(pCon);
assert(pScan);
if(iEvent == SCANSTART)
{
iTOF = 0;
/* send current axis */
iLength = GetScanNP(pScan);
fAxis = (float *)malloc((iLength+1)*sizeof(float));
iAxis = (int *)malloc((iLength+1)*sizeof(int));
if( (!fAxis) || (!iAxis))
{
return 0;
}
iAxis[0] = htonl(iLength);
GetSoftScanVar(pScan,0,fAxis,iLength);
GetScanVarName(pScan,0,pName,39);
sprintf(pBueffel,"arrowaxis_%s",pName);
for(i = 0 ; i < iLength; i++)
{
iAxis[i+1] = htonl((int)(fAxis[i]*65536.));
}
/* send new axis to client */
SCWrite(pCon,"SCANClear",eError);
SCWriteUUencoded(pCon,pBueffel,iAxis,
(iLength+1)*sizeof(int));
free(iAxis);
free(fAxis);
}
return 1;
}
/*------------------------------------------------------------------------*/
static int ScanPointCallback(int iEvent, void *pEvent, void *pUser)
{
long *lData = NULL;
int *iData = NULL;
int iLength, iRet, i;
SConnection *pCon = (SConnection *)pUser;
pScanData pScan = (pScanData)pEvent;
assert(pCon);
assert(pScan);
if( (iEvent == SCANPOINT) || (iEvent == SCANEND) )
{
/* send current data */
iTOF = 0;
iLength = GetScanNP(pScan);
lData = (long *)malloc((iLength+1)*sizeof(long));
iData = (int *)malloc((iLength+1)*sizeof(int));
if( (!lData) || (!iData))
{
return 0;
}
iData[0] = htonl(iLength);
GetScanCounts(pScan,lData,iLength);
for(i = 0 ; i < iLength; i++)
{
iData[i+1] = htonl((int)(lData[i]));
}
/* send counts to client */
SCWriteUUencoded(pCon,"arrow_spinupup",iData,
(iLength+1)*sizeof(int));
/* send counts for other detector */
GetScanMonitor(pScan,2,lData,iLength);
for(i = 0 ; i < iLength; i++)
{
iData[i+1] = htonl((int)(lData[i]));
}
SCWriteUUencoded(pCon,"arrow_spinuplo",iData,
(iLength+1)*sizeof(int));
/* to do: check for polarization and send spinlo */
free(iData);
free(lData);
}
return 1;
}
/*------------------------------------------------------------------------*/
static int SendLoadedData(pAmorStat self, SConnection *pCon)
{
int i, iRet, *iData = NULL;
char pBueffel[80];
UserData ud;
SCWrite(pCon,"loaded_CLEAR",eValue);
iRet = LLDnodePtr2First(self->iUserList);
while(iRet != 0)
{
LLDnodeDataTo(self->iUserList,&ud);
iData = (int *)malloc((ud.iNP*2 + 1)*sizeof(int));
if(!iData)
{
return 0;
}
iData[0] = htonl(ud.iNP);
for(i = 0; i < ud.iNP; i++)
{
iData[i+1] = htonl((int)(ud.fX[i]*65536));
iData[i+1+ud.iNP] = htonl((int)(ud.fY[i]*65536));
}
sprintf(pBueffel,"loaded_%s",ud.name);
SCWriteUUencoded(pCon,pBueffel,iData,(ud.iNP*2+1)*sizeof(int));
iRet = LLDnodePtr2Next(self->iUserList);
}
}
/*------------------------------------------------------------------------*/
static int LoadCallback(int iEvent, void *pEvent, void *pUser)
{
pAmorStat pAS = NULL;
SConnection *pCon = NULL;
if(iEvent == FILELOADED)
{
pAS = (pAmorStat)pEvent;
pCon = (SConnection *)pUser;
assert(pAS);
assert(pCon);
SendLoadedData(pAS,pCon);
}
return 1;
}
/*-------------------------------------------------------------------------*/
static void ClearUserData(pAmorStat self)
{
int iRet;
UserData ud;
iRet = LLDnodePtr2First(self->iUserList);
while(iRet != 0)
{
LLDnodeDataTo(self->iUserList,&ud);
if(ud.fX != NULL)
free(ud.fX);
if(ud.fY != NULL)
free(ud.fY);
if(ud.name != NULL)
free(ud.name);
iRet = LLDnodePtr2Next(self->iUserList);
}
LLDdelete(self->iUserList);
self->iUserList = LLDcreate(sizeof(UserData));
}
/*----------------------------------------------------------------------*/
void KillAmorStatus(void *pData)
{
pAmorStat self = (pAmorStat)pData;
if(!self)
return;
if(self->iUserList >= 0)
{
ClearUserData(self);
LLDdelete(self->iUserList);
}
if(self->pDes)
DeleteDescriptor(self->pDes);
if(self->pCall)
DeleteCallBackInterface(self->pCall);
free(self);
}
/*------------------------------------------------------------------*/
int AmorStatusFactory(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[])
{
pAmorStat pNew = NULL;
CommandList *pCom = NULL;
char pBueffel[256];
int iRet;
/* check number of arguments */
if(argc < 4)
{
sprintf(pBueffel,"ERROR: insufficient number of arguments to %s",
argv[0]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/* allocate a new data structure */
pNew = (pAmorStat)malloc(sizeof(AmorStat));
if(!pNew)
{
sprintf(pBueffel,"ERROR: out of memory in %s",argv[0]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
memset(pNew,0,sizeof(AmorStat));
pNew->pDes = CreateDescriptor("AmorStatus");
pNew->iUserList = LLDcreate(sizeof(UserData));
pNew->pCall = CreateCallBackInterface();
if( (!pNew->pDes) || (pNew->iUserList < 0) || (!pNew->pCall) )
{
sprintf(pBueffel,"ERROR: out of memory in %s",argv[0]);
SCWrite(pCon,pBueffel,eError);
KillAmorStatus(pNew);
return 0;
}
/* to locate the HM and the scan object */
pCom = FindCommand(pSics,argv[2]);
if(pCom)
{
if(pCom->pData)
{
if(!iHasType(pCom->pData,"ScanObject"))
{
sprintf(pBueffel,"ERROR: %s is NO scan object",argv[2]);
SCWrite(pCon,pBueffel,eError);
KillAmorStatus(pNew);
return 0;
}
}
else
{
sprintf(pBueffel,"ERROR: %s is NO scan object",argv[2]);
SCWrite(pCon,pBueffel,eError);
KillAmorStatus(pNew);
return 0;
}
}
else
{
sprintf(pBueffel,"ERROR: %s NOT found",argv[2]);
SCWrite(pCon,pBueffel,eError);
KillAmorStatus(pNew);
return 0;
}
pNew->pScan = (pScanData)pCom->pData;
pCom = FindCommand(pSics,argv[3]);
if(pCom)
{
if(pCom->pData)
{
if(!iHasType(pCom->pData,"HistMem"))
{
sprintf(pBueffel,"ERROR: %s is NO histogram memory object",
argv[3]);
SCWrite(pCon,pBueffel,eError);
KillAmorStatus(pNew);
return 0;
}
}
else
{
sprintf(pBueffel,"ERROR: %s is NO histogram memory object",
argv[3]);
SCWrite(pCon,pBueffel,eError);
KillAmorStatus(pNew);
return 0;
}
}
else
{
sprintf(pBueffel,"ERROR: %s NOT found",argv[3]);
SCWrite(pCon,pBueffel,eError);
KillAmorStatus(pNew);
return 0;
}
pNew->pHM = (pHistMem)pCom->pData;
pHMHM = (pHistMem)pCom->pData;
/* install command */
iRet = AddCommand(pSics,argv[1],
AmorStatusAction,KillAmorStatus,pNew);
if(!iRet)
{
sprintf(pBueffel,"ERROR: duplicate command %s NOT created",
argv[1]);
SCWrite(pCon,pBueffel,eError);
KillAmorStatus(pNew);
return 0;
}
return 1;
}
/*------------------------------------------------------------------*/
static int RegisterInterest(pAmorStat self, SConnection *pCon)
{
long lID;
pDummy pDum = NULL;
pICallBack pCall = NULL;
assert(self);
assert(pCon);
/* Register all the callbacks. Dependent on the state of
iTOF invoke the apropriate callbacks in order to force
an initial update.
*/
/* file load callback */
lID = RegisterCallback(self->pCall, FILELOADED, LoadCallback,
pCon, NULL);
SCRegister(pCon,pServ->pSics, self->pCall,lID);
SendLoadedData(self,pCon);
/* scan object */
pDum = (pDummy)self->pScan;
pCall = pDum->pDescriptor->GetInterface(pDum,CALLBACKINTERFACE);
if(pCall)
{
lID = RegisterCallback(pCall,SCANSTART,ScanStartCallback,
pCon, NULL);
SCRegister(pCon,pServ->pSics,pCall,lID);
lID = RegisterCallback(pCall,SCANPOINT,ScanPointCallback,
pCon, NULL);
SCRegister(pCon,pServ->pSics,pCall,lID);
lID = RegisterCallback(pCall,SCANEND,ScanPointCallback,
pCon, NULL);
SCRegister(pCon,pServ->pSics,pCall,lID);
if(iTOF == 0)
{
ScanStartCallback(SCANSTART,pDum,pCon);
ScanPointCallback(SCANPOINT,pDum,pCon);
}
}
pDum = (pDummy)self->pHM;
pCall = pDum->pDescriptor->GetInterface(pDum,CALLBACKINTERFACE);
if(pCall)
{
lID = RegisterCallback(pCall,COUNTSTART,HMCountStartCallback,
pCon, NULL);
SCRegister(pCon,pServ->pSics,pCall,lID);
if(iTOF == 1)
{
HMCountStartCallback(COUNTSTART,pDum,pCon);
}
}
return 1;
}
/*-----------------------------------------------------------------*/
static int FileLoad(pAmorStat self, SConnection *pCon,
char *name, double dScale)
{
char pBueffel[256], pDummy[50];
FILE *fd = NULL;
UserData ud;
int iNP, i;
float fDummy;
/* open the file */
fd = fopen(name,"r");
if(!fd)
{
sprintf(pBueffel,"ERROR: cannot open %s for reading",name);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/* skip first line */
if(fgets(pBueffel,255,fd) == NULL)
{
SCWrite(pCon,"ERROR: premature end of file",eError);
fclose(fd);
return 0;
}
/* read number of points in second line */
if(fgets(pBueffel,255,fd) == NULL)
{
SCWrite(pCon,"ERROR: premature end of file",eError);
fclose(fd);
return 0;
}
sscanf(pBueffel,"%s %d",pDummy, &iNP);
/* allocate data */
ud.iNP = iNP;
ud.fX = (float *)malloc(iNP*sizeof(float));
ud.fY = (float *)malloc(iNP*sizeof(float));
ud.name = strdup(name);
/* skip two lines */
if(fgets(pBueffel,255,fd) == NULL)
{
SCWrite(pCon,"ERROR: premature end of file",eError);
fclose(fd);
return 0;
}
if(fgets(pBueffel,255,fd) == NULL)
{
SCWrite(pCon,"ERROR: premature end of file",eError);
fclose(fd);
return 0;
}
/* loop reading data */
for(i = 0; i < iNP; i++)
{
if(fgets(pBueffel,255,fd) == NULL)
{
SCWrite(pCon,"WARNING: premature end of file",eError);
break;
}
sscanf(pBueffel," %f %f %f",&ud.fX[i],&fDummy, &ud.fY[i]);
ud.fY[i] *= dScale;
}
fclose(fd);
/* enter ud into list */
LLDnodeInsertFrom(self->iUserList,&ud);
return 1;
}
/*-----------------------------------------------------------------
Collapse creates a 2D image from the detector by summing all time
channels together in any given detector.
*/
static int Collapse(pAmorStat self, SConnection *pCon)
{
HistInt *lData = NULL;
int i, i2, i3, iDim[MAXDIM], iIdx, iSum;
int *iImage = NULL, *iPtr;
/* get size of our problem */
GetHistDim(self->pHM,iDim,&i3);
assert(i3 == 3);
/* get data */
lData = GetHistogramPointer(self->pHM,pCon);
if(!lData)
{
return 0;
}
/* allocate some data */
iImage = (int *)malloc((2 + iDim[0]*iDim[1])*sizeof(int));
if(iImage == NULL)
{
SCWrite(pCon,"ERROR: failed to allocate memory in Collapse",eError);
return 0;
}
memset(iImage,0,(2 + iDim[0]*iDim[1])*sizeof(int));
/* first two numbers are the dimension of the image */
iImage[0] = htonl(iDim[0]);
iImage[1] = htonl(iDim[1]);
/* loop the loop */
for(i = 0; i < iDim[0]; i++)
{
for(i2 = 0; i2 < iDim[1]; i2++)
{
iPtr = lData + i*iDim[1]*iDim[2] +
i2*iDim[2];
iIdx = i*iDim[1] + i2;
for(i3 = 0, iSum = 0; i3 < iDim[2]; i3++)
{
iSum += iPtr[i3];
}
iImage[iIdx+2] = htonl(iSum);
}
}
/* send image */
SCWriteUUencoded(pCon,"arrow_image",iImage,
(iDim[0]*iDim[1]+2)*sizeof(int));
free(iImage);
return 1;
}
/*-------------------------------------------------------------------
SubSample sums histogram data in the area defined by the rectangle
x1,y1 x2, y2. Summing is along the time axis.
*/
static int SubSample(pAmorStat self, SConnection *pCon,
char *name, int x1, int x2, int y1, int y2)
{
int iDim[MAXDIM], i, i2, i3, *iSum = NULL, iLang, *iPtr;
HistInt *lData = NULL;
int iLimit;
char pBueffel[132];
/* get histogram data */
GetHistDim(self->pHM,iDim,&i3);
assert(i3 == 3);
lData = GetHistogramPointer(self->pHM,pCon);
if(!lData)
{
return 0;
}
/* check limits */
if(x2 < x1)
x2 = x1 + 1;
if(y2 < y1)
y2 = y1 + 1;
iLimit = 0;
if( x1 > iDim[0])
{
iLimit = 1;
x1 = iDim[0] - 1;
}
if(x1 < 0)
{
iLimit = 1;
x1 = 0;
}
if( x2 > iDim[0])
{
iLimit = 2;
x2 = iDim[0] - 1;
}
if(x2 < 0)
{
iLimit = 2;
x2 = 0;
}
if( y1 > iDim[1])
{
iLimit = 3;
y1 = iDim[1] - 1;
}
if(y1 < 0)
{
iLimit = 3;
y1 = 0;
}
if( y2 > iDim[1])
{
iLimit = 4;
y2 = iDim[1] - 1;
}
if(y2 < 0)
{
iLimit = 4;
y2 = 0;
}
if(iLimit != 0)
{
switch(iLimit)
{
case 1:
strcpy(pBueffel,"WARNING: limit violation on x1");
break;
case 2:
strcpy(pBueffel,"WARNING: limit violation on x2");
break;
case 3:
strcpy(pBueffel,"WARNING: limit violation on y1");
break;
case 4:
strcpy(pBueffel,"WARNING: limit violation on y2");
break;
}
SCWrite(pCon,pBueffel,eWarning);
}
/* allocate space for result */
iSum = (int *)malloc((iDim[2]+1)*sizeof(int));
if(!iSum)
{
SCWrite(pCon,"ERROR: out of memory in SubSample",eError);
return 0;
}
memset(iSum,0,(iDim[2]+1)*sizeof(int));
/* do it! */
iSum[0] = iDim[2];
for(i = x1; i < x2; i++)
{
for(i2 = x1; i2 < y2; i2++)
{
iPtr = lData + i*iDim[1]*iDim[2] +
i2*iDim[2];
for(i3 = 0; i3 < iDim[2]; i3++)
{
iSum[i3+1] += iPtr[i3];
}
}
}
/* network byte order */
for(i = 0; i < iDim[2]+1; i++)
{
iSum[i] = htonl(iSum[i]);
}
/* send */
sprintf(pBueffel,"arrowsum_%s",name);
SCWriteUUencoded(pCon,pBueffel,iSum,(iDim[2]+1)*sizeof(int));
free(iSum);
return 1;
}
/*------------------------------------------------------------------*/
int AmorStatusAction(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[])
{
pAmorStat self = (pAmorStat)pData;
char pBueffel[512];
double dScale;
int iRet;
int x1, x2, y1, y2;
assert(self);
if(argc < 2)
{
sprintf(pBueffel,"ERROR: need argument to %s",argv[0]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
strtolower(argv[1]);
if(strcmp(argv[1],"interest") == 0)
{
RegisterInterest(self,pCon);
SCSendOK(pCon);
return 1;
}
else if(strcmp(argv[1],"load") == 0)
{
if(argc < 4)
{
sprintf(pBueffel,
"ERROR: need filename and scale argument to %s load",
argv[0]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = Tcl_GetDouble(pSics->pTcl,argv[3],&dScale);
if(iRet != TCL_OK)
{
sprintf(pBueffel,"ERROR: cannot convert %s to scale factor",
argv[3]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
FileLoad(self,pCon,argv[2],dScale);
InvokeCallBack(self->pCall, FILELOADED,self);
SCSendOK(pCon);
}
else if(strcmp(argv[1],"collapse") == 0)
{
iRet = Collapse(self,pCon);
if(iRet)
{
SCSendOK(pCon);
}
return iRet;
}
else if(strcmp(argv[1],"sample") == 0)
{
if(argc < 7)
{
SCWrite(pCon,"ERROR: insufficent number of arguments to sample",
eError);
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl,argv[3],&x1);
if(iRet != TCL_OK)
{
sprintf(pBueffel,"ERROR: cannot convert %s to int", argv[3]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl,argv[6],&y2);
if(iRet != TCL_OK)
{
sprintf(pBueffel,"ERROR: cannot convert %s to int", argv[6]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl,argv[4],&x2);
if(iRet != TCL_OK)
{
sprintf(pBueffel,"ERROR: cannot convert %s to int", argv[4]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl,argv[5],&y1);
if(iRet != TCL_OK)
{
sprintf(pBueffel,"ERROR: cannot convert %s to int", argv[5]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = SubSample(self,pCon,argv[2],x1,x2,y1,y2);
if(iRet)
SCSendOK(pCon);
return iRet;
}
else if(strcmp(argv[1],"sendloaded") == 0)
{
SendLoadedData(self,pCon);
return 1;
}
else if(strcmp(argv[1],"clear") == 0)
{
ClearUserData(self);
InvokeCallBack(self->pCall, FILELOADED,self);
SCSendOK(pCon);
}
return 1;
}