/*-------------------------------------------------------------------------- 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 #include #include #include #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); GetScanVar(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 != NULL) { 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; }