490 lines
13 KiB
C
490 lines
13 KiB
C
/*-------------------------------------------------------------------
|
|
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 <stdio.h>
|
|
#include <assert.h>
|
|
#include <tcl.h>
|
|
#include "fortify.h"
|
|
#include "sics.h"
|
|
#include "diffscan.h"
|
|
#include "drive.h"
|
|
#include "counter.h"
|
|
|
|
extern double DoubleTime(void);
|
|
|
|
#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 (strcasecmp(argv[1], "sicsvar") == 0) {
|
|
if (argc > 2) {
|
|
if (strcasecmp(argv[2], "none") == 0) {
|
|
self->sicsvar = NULL;
|
|
return 1;
|
|
} else {
|
|
self->sicsvar = FindVariable(pServ->pSics, argv[2]);
|
|
if (self->sicsvar == NULL) {
|
|
SCPrintf(pCon, eError, "Cannot find SICS Variable: %s\n", argv[2]);
|
|
return 0;
|
|
}
|
|
else if (self->sicsvar->eType != veText) {
|
|
SCPrintf(pCon, eError, "SICS Variable must be TEXT not %s\n",
|
|
self->sicsvar->eType == veInt ? "INT" :
|
|
self->sicsvar->eType == veFloat ? "FLOAT" : "unknown");
|
|
self->sicsvar = NULL;
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
} else {
|
|
SCPrintf(pCon, eValue, "sicsvar = %s\n", self->sicsvar ? self->sicsvar->name : "none");
|
|
return 1;
|
|
}
|
|
}
|
|
if (strcasecmp(argv[1], "hdbnode") == 0) {
|
|
if (argc > 2) {
|
|
if (strcasecmp(argv[2], "none") == 0) {
|
|
self->hdbnode = NULL;
|
|
return 1;
|
|
} else {
|
|
self->hdbnode = FindHdbNode(NULL, argv[2], pCon);
|
|
if (self->hdbnode == NULL) {
|
|
SCPrintf(pCon, eError, "Cannot find HDB Node: %s\n", argv[2]);
|
|
return 0;
|
|
}
|
|
else if (self->hdbnode->value.dataType != HIPTEXT) {
|
|
SCPrintf(pCon, eError, "HDB Node %s must be TEXT\n", argv[2]);
|
|
self->hdbnode = NULL;
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
} else {
|
|
char *path = NULL;
|
|
if (self->hdbnode != NULL)
|
|
path = GetHipadabaPath(self->hdbnode);
|
|
SCPrintf(pCon, eValue, "hdbnode = %s\n", path ? path : "none");
|
|
return 1;
|
|
}
|
|
}
|
|
/*
|
|
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;
|
|
pScan->iNP = 0;
|
|
|
|
/*
|
|
get variable
|
|
*/
|
|
DynarGet(pScan->pScanVar, 0, &pPtr);
|
|
pVar = (pVarEntry) pPtr;
|
|
if (pVar == NULL) {
|
|
SCWrite(pCon, "ERROR: cannot access scan variable", eError);
|
|
return 0;
|
|
}
|
|
InitScanVar(pVar);
|
|
|
|
/*
|
|
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;
|
|
}
|
|
pCount->pCountInt->lastStatus = HWBusy;
|
|
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;
|
|
}
|
|
fScale = pCount->fTime - last->fTime;
|
|
if (fScale > 0)
|
|
value /= 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;
|
|
double now;
|
|
|
|
pDiffScan self = (pDiffScan) pData;
|
|
|
|
/*
|
|
manage skip
|
|
*/
|
|
#if 1
|
|
now = DoubleTime();
|
|
if (self->skip > 0) {
|
|
if (now - self->last_report_time < 0.001 * self->skip) {
|
|
return 1;
|
|
}
|
|
} else {
|
|
if (now - self->last_report_time < 0.1) {
|
|
return 1;
|
|
}
|
|
}
|
|
self->last_report_time = now;
|
|
#else
|
|
if (self->skip > 0) {
|
|
if (self->skipCount > self->skip) {
|
|
self->skipCount = 0;
|
|
} else {
|
|
self->skipCount++;
|
|
return 1;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
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) {
|
|
ReleaseCountLock(pCount->pCountInt);
|
|
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];
|
|
if(rawMon > 100){
|
|
self->normalizationScale = rawMon;
|
|
traceSys("diffscan","START:normalizing on %d, scale monitor is %d",
|
|
self->normalizationScale, self->scaleMonitor);
|
|
} else {
|
|
traceSys("diffscan","START:normalization count %ld, on scale monitor is %d and is to low",
|
|
rawMon, self->scaleMonitor);
|
|
SCWrite(self->scanObject->pCon,"WARNING: Skipping first point because of low count rate", eWarning);
|
|
return finish;
|
|
}
|
|
} else {
|
|
if (data->Monitors[self->scaleMonitor - 1] -
|
|
self->last.Monitors[self->scaleMonitor - 1] < 5) {
|
|
SCWrite(self->scanObject->pCon, "WARNING: low count rate", eLog);
|
|
traceSys("diffscan","RUN:low monitor difference from %ld to %ld",data->Monitors[self->scaleMonitor-1],
|
|
self->last.Monitors[self->scaleMonitor -1]);
|
|
}
|
|
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 %10.3f",
|
|
self->scanObject->iCounts - 1,
|
|
fPos, countValue, rawCount, rawMon, data->fTime);
|
|
SCWrite(self->scanObject->pCon, pBueffel, eLog);
|
|
if (self->sicsvar != NULL && self->sicsvar->eType == veText)
|
|
VarSetText(self->sicsvar, pBueffel, usInternal);
|
|
if (self->hdbnode != NULL && self->hdbnode->value.dataType == HIPTEXT) {
|
|
hdbValue v;
|
|
char error[512];
|
|
cloneHdbValue(&self->hdbnode->value, &v);
|
|
if (!readHdbValue(&v, pBueffel, error, 512)) {
|
|
SCWrite(self->scanObject->pCon, error, eError);
|
|
} else {
|
|
UpdateHipadabaPar(self->hdbnode, v, self->scanObject->pCon);
|
|
}
|
|
ReleaseHdbValue(&v);
|
|
}
|
|
InvokeCallBack(self->scanObject->pCall, SCANPOINT, self->scanObject);
|
|
traceSys("diffscan","RUN: pos, count, rawcount, rawmon: %f, %f, %ld, %ld",
|
|
fPos, countValue, rawCount, rawMon);
|
|
|
|
/*
|
|
check for interrupt
|
|
*/
|
|
if (SCGetInterrupt(self->scanObject->pCon) >= eAbortScan) {
|
|
pCount->pCountInt->Halt(pCount);
|
|
pVar->pInter->Halt(pVar->pObject);
|
|
SicsWait(1);
|
|
finish = 0;
|
|
}
|
|
|
|
if(finish == 0) {
|
|
ReleaseCountLock(pCount->pCountInt);
|
|
}
|
|
|
|
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;
|
|
}
|
|
self->last_report_time = DoubleTime();
|
|
InvokeCallBack(self->scanObject->pCall, SCANSTART, self->scanObject);
|
|
|
|
|
|
lID = TaskRegisterN(pServ->pTasker,"diffscan", DiffScanTask, NULL, NULL, self, TASK_PRIO_HIGH);
|
|
TaskWait(pServ->pTasker, lID);
|
|
|
|
|
|
pCount = (pCounter) self->scanObject->pCounterData;
|
|
pCount->pCountInt->Halt(pCount);
|
|
InvokeCallBack(self->scanObject->pCall, SCANEND, self->scanObject);
|
|
pCount->pCountInt->lastStatus = HWIdle;
|
|
|
|
return 1;
|
|
}
|