/*------------------------------------------------------------------- diffscan is an operator which can perform a fast differential scan while a motor is running. copyright: see file COPYRIGHT Mark Koennecke, November 2004 ---------------------------------------------------------------------*/ #include #include #include #include "fortify.h" #include "sics.h" #include "diffscan.h" #include "drive.h" #include "counter.h" #define DIFFMONITOR 0 #define SKIP 1 /*-------------------------------------------------------------------*/ static void KillDiffScan(void *data){ pDiffScan self = (pDiffScan)data; if(self == NULL){ return; } if(self->pDes != NULL){ DeleteDescriptor(self->pDes); } if(self->parArray != NULL){ ObParDelete(self->parArray); } free(self); } /*---------------------------------------------------------------------*/ static int SaveDiffScan(void *data, char *name, FILE *fd){ pDiffScan self = (pDiffScan)data; if(self == NULL){ return 0; } fprintf(fd,"%s monitor %f\n",name,ObVal(self->parArray,DIFFMONITOR)); fprintf(fd,"%s skip %f\n",name,ObVal(self->parArray,SKIP)); return 1; } /*----------------------------------------------------------------------*/ int MakeDiffScan(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ pDiffScan pNew = NULL; int status; pNew = (pDiffScan)malloc(sizeof(DiffScan)); if(pNew == NULL){ SCWrite(pCon,"ERROR: out of memory creating differential scan", eError); return 0; } memset(pNew,0,sizeof(DiffScan)); pNew->pDes = CreateDescriptor("DiffScan"); pNew->parArray = ObParCreate(2); if(!pNew->pDes || !pNew->parArray){ SCWrite(pCon,"ERROR: out of memory creating differential scan", eError); KillDiffScan(pNew); return 0; } ObParInit(pNew->parArray, DIFFMONITOR,"monitor",4.0,usUser); ObParInit(pNew->parArray, SKIP,"skip",.0,usUser); pNew->pDes->SaveStatus = SaveDiffScan; if(argc > 1) { status = AddCommand(pSics,argv[1], DiffScanWrapper, KillDiffScan, pNew); } else { status = AddCommand(pSics,"diffscan", DiffScanWrapper, KillDiffScan, pNew); } if(status != 1){ SCWrite(pCon,"ERROR: duplicate diffscan not created",eError); return 0; } return 1; } /*----------------------------------------------------------------------*/ int DiffScanWrapper(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ pDiffScan self = NULL; pScanData pScan = NULL; ObPar *par = NULL; char pBueffel[255]; int status; self = (pDiffScan)pData; assert(self); if(argc < 2){ SCWrite(pCon,"ERROR: need arguments to diffscan",eError); return 0; } if(!SCMatchRights(pCon,usUser)){ return 0; } /* first try to find a scan object and to run */ strtolower(argv[1]); pScan = (pScanData)FindCommandData(pSics,argv[1],"ScanObject"); if(pScan != NULL && argc > 2){ status = RunDiffScan(self,pScan,pCon, atof(argv[2])); return status; } /* if we end here we are treating variables */ if(argc > 2){ /* set case */ return ObParSet(self->parArray,argv[0],argv[1],atof(argv[2]),pCon); } else { /* get case */ par = ObParFind(self->parArray,argv[1]); if(par != NULL){ snprintf(pBueffel,255,"%s.%s = %f",argv[0],argv[1],par->fVal); SCWrite(pCon,pBueffel,eValue); return 1; } else { snprintf(pBueffel,255,"ERROR: parameter %s not found",argv[1]); SCWrite(pCon,pBueffel,eError); return 0; } } return 1; } /*--------------------------------------------------------------------*/ static int StartDiffScan(pDiffScan self, pScanData pScan, SConnection *pCon, float fEnd){ pVarEntry pVar = NULL; void *pPtr = NULL; pCounter pCount = NULL; char pBueffel[255]; int status; /* error checks */ if(pScan->iScanVar < 1) { SCWrite(pCon,"ERROR: no scan variable to diffscan",eError); return 0; } if(pScan->iScanVar > 1) { snprintf(pBueffel,255, "WARNING: diffscan handles only first scan variable, %d %s", pScan->iScanVar - 1, "scan variables ignored"); SCWrite(pCon,pBueffel, eWarning); } /* initialize data structure */ self->scanObject = pScan; self->scanObject->pCon = pCon; self->skip = (int)ObVal(self->parArray,SKIP); self->scaleMonitor = (int)ObVal(self->parArray,DIFFMONITOR); self->normalizationScale = -1; pScan->iCounts = 0; /* get variable */ DynarGet(pScan->pScanVar,0,&pPtr); pVar = (pVarEntry)pPtr; if(pVar == NULL){ SCWrite(pCon,"ERROR: cannot access scan variable",eError); return 0; } /* drive to start position */ status = Drive(pCon,pServ->pSics,ScanVarName(pVar),ScanVarStart(pVar)); if(status != 1){ return 0; } /* Configure counter. We operate in timer mode with a very long preset mode. Stopping is done explicitly in the diffscan task */ SetCounterMode(pScan->pCounterData,eTimer); SetCounterPreset(pScan->pCounterData,3600.); /* start motor and counter */ status = pVar->pInter->SetValue(pVar->pObject,pCon,fEnd); if(status != OKOK){ /* errors will already have been reported in SetValue */ return 0; } pCount = (pCounter)pScan->pCounterData; assert(pCount); status = pCount->pCountInt->StartCount(pCount,pCon); if(status != OKOK){ return 0; } return 1; } /*--------------------------------------------------------------------*/ static float normalizeEntry(pCountEntry pCount, pCountEntry last, long monValue, int scaleMon){ int i; float fScale; float value; long diff; /* calculate scale */ diff = pCount->Monitors[scaleMon-1] - last->Monitors[scaleMon-1]; if(diff > 0) { fScale = (float)monValue/(float)diff; } else { fScale = 0.; } value = ((float)(pCount->lCount - last->lCount))*fScale; pCount->lCount = (long)value; for(i = 0; i < 10; i++){ pCount->Monitors[i] = (pCount->Monitors[i] - last->Monitors[i])*fScale; } return value; } /*--------------------------------------------------------------------*/ static void copyCountData(pCountEntry last, pCountEntry pCount){ memcpy(last,pCount,sizeof(CountEntry)); } /*---------------------------------------------------------------------*/ static int DiffScanTask(void *pData){ pCounter pCount = NULL; pCountEntry data; pVarEntry pVar = NULL; void *pPtr = NULL; float fPos, countValue; int status, finish = 1, count; char pBueffel[255]; long rawCount, rawMon; CountEntry rawCopy; pDiffScan self = (pDiffScan)pData; /* manage skip */ if(self->skip > 0){ if(self->skipCount > self->skip){ self->skipCount = 0; } else { self->skipCount++; return 1; } } /* read motor status */ DynarGet(self->scanObject->pScanVar,0,&pPtr); pVar = (pVarEntry)pPtr; status = pVar->pInter->CheckStatus(pVar->pObject,self->scanObject->pCon); if(status != HWBusy) { finish = 0; } /* read values */ status = GetDrivablePosition(pVar->pObject,self->scanObject->pCon, &fPos); if(status == 0){ return finish; } AppendScanVar(pVar,fPos); pCount = (pCounter)self->scanObject->pCounterData; pCount->pCountInt->TransferData(pCount,self->scanObject->pCon); CollectCounterData(self->scanObject); /* normalize (or not) */ DynarGet(self->scanObject->pCounts,self->scanObject->iCounts-1,&pPtr); data = (pCountEntry)pPtr; copyCountData(&rawCopy,data); if(self->normalizationScale < 0){ countValue = (float)data->lCount; rawCount = data->lCount; rawMon = data->Monitors[self->scaleMonitor-1]; self->normalizationScale = data->Monitors[self->scaleMonitor-1]; } else { if(data->Monitors[self->scaleMonitor -1] - self->last.Monitors[self->scaleMonitor-1] < 5) { SCWrite(self->scanObject->pCon, "WARNING: low count rate",eWarning); } rawCount = data->lCount; rawMon = data->Monitors[self->scaleMonitor-1]; countValue = normalizeEntry(data,&self->last, self->normalizationScale, self->scaleMonitor); } copyCountData(&self->last,&rawCopy); /* print progress */ snprintf(pBueffel,255,"%5d %12.4f %12.4f RAW: %10ld %10ld", self->scanObject->iCounts -1, fPos, countValue, rawCount, rawMon); SCWrite(self->scanObject->pCon,pBueffel,eWarning); InvokeCallBack(self->scanObject->pCall,SCANPOINT,self->scanObject); /* check for interrupt */ if(SCGetInterrupt(self->scanObject->pCon) >= eAbortScan){ pCount->pCountInt->Halt(pCount); pVar->pInter->Halt(pVar->pObject); SicsWait(1); finish = 0; } return finish; } /*----------------------------------------------------------------------*/ int RunDiffScan(pDiffScan self, pScanData pScan, SConnection *pCon, float fEnd){ long lID; pCounter pCount = NULL; if(StartDiffScan(self,pScan,pCon,fEnd) != 1) { return 0; } InvokeCallBack(self->scanObject->pCall,SCANSTART,self->scanObject); lID = TaskRegister(pServ->pTasker,DiffScanTask,NULL,NULL,self,10); TaskWait(pServ->pTasker,lID); pCount = (pCounter)self->scanObject->pCounterData; pCount->pCountInt->Halt(pCount); InvokeCallBack(self->scanObject->pCall,SCANEND,self->scanObject); return 1; }