1498 lines
42 KiB
C
1498 lines
42 KiB
C
/*--------------------------------------------------------------------------
|
|
This is one implementation file for the TASMAD simulation module for
|
|
SICS. The requirement is to make SICS look as much as TASMAD as
|
|
possible. This includes:
|
|
- TASMAD is variable driven
|
|
- Sometimes variables are accessed in storage order.
|
|
- A complicated calculation has to be done for getting the instruments
|
|
settings right. The appropriate F77 routine from TASMAD will be
|
|
reused.
|
|
- The scan logic is different.
|
|
- Output of ILL-formatted data files is required.
|
|
|
|
This file implements the MAD sc command for scanning. The general idea is
|
|
that specialized action functions are defined for the scan object and the
|
|
main SICS scan loop is used as a driver.
|
|
|
|
Mark Koennecke, November-December 2000
|
|
---------------------------------------------------------------------------*/
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <time.h>
|
|
#include <ctype.h>
|
|
#include <tcl.h>
|
|
#include <fortify.h>
|
|
#include <sics.h>
|
|
#include <sicsvar.h>
|
|
#include <counter.h>
|
|
#include <motor.h>
|
|
#include <scan.h>
|
|
#include <scan.i>
|
|
#include <lld.h>
|
|
#include "tas.h"
|
|
#include "tasu.h"
|
|
#include <scanvar.h>
|
|
#include <evcontroller.h>
|
|
#include <splitter.h>
|
|
#include <status.h>
|
|
|
|
/*------------------------------------------------------------------------
|
|
a little local utility for making a line of characters
|
|
-------------------------------------------------------------------------*/
|
|
static void charLine(char *pBueffel, char c)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < 80; i++) {
|
|
pBueffel[i] = c;
|
|
}
|
|
pBueffel[80] = '\n';
|
|
pBueffel[81] = '\0';
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
static void strtoupper(char *pText)
|
|
{
|
|
assert(pText);
|
|
|
|
while (*pText != '\0') {
|
|
*pText = toupper(*pText);
|
|
pText++;
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
static void strcenter(char *str, char *target, int iLength)
|
|
{
|
|
int iPtr, i;
|
|
|
|
/*
|
|
catch the error if target is to long
|
|
*/
|
|
if (strlen(str) >= iLength) {
|
|
strlcpy(target, str, iLength);
|
|
}
|
|
|
|
iPtr = (iLength - strlen(str)) / 2;
|
|
for (i = 0; i < iPtr; i++) {
|
|
target[i] = ' ';
|
|
}
|
|
target[iPtr] = '\0';
|
|
strcat(target, str);
|
|
for (i = iPtr + strlen(str); i < iLength - 1; i++) {
|
|
target[i] = ' ';
|
|
}
|
|
target[iLength - 1] = '\0';
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------
|
|
helper function for TASHeader
|
|
------------------------------------------------------------------------*/
|
|
static void writePolFile(FILE * fd, pTASdata pTAS)
|
|
{
|
|
char pLine[132];
|
|
FILE *fpol = NULL;
|
|
|
|
assert(fd);
|
|
assert(pTAS);
|
|
|
|
fpol = fopen(pTAS->tasPar[POLFIL]->text, "r");
|
|
if (!fpol) {
|
|
/*
|
|
error gets reported anyway later on
|
|
*/
|
|
return;
|
|
}
|
|
|
|
while (fgets(pLine, 131, fpol) != NULL) {
|
|
if (strstr(pLine, "\n") == NULL) {
|
|
fprintf(fd, "POLAN: %s\n", pLine);
|
|
} else {
|
|
fprintf(fd, "POLAN: %s", pLine);
|
|
}
|
|
}
|
|
fclose(fpol);
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
static char *findLastPoint(char *text)
|
|
{
|
|
char *pPtr;
|
|
int i;
|
|
|
|
pPtr = text + strlen(text) - 1;
|
|
for (i = strlen(text); i > 0; i--, pPtr--) {
|
|
if (*pPtr == '.') {
|
|
return pPtr;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
TASHeader writes the header of a TAS data file. The format is an
|
|
obscure format from ILL ( not ill but Institute Laue Langevin). No
|
|
documentation about this exists except the files themselves. This is long
|
|
and tiresome code.
|
|
---------------------------------------------------------------------------*/
|
|
static int TASHeader(pScanData self)
|
|
{
|
|
pTASdata pTAS = (pTASdata) self->pSpecial;
|
|
int i, iCount, status, iFileNO=0;
|
|
char pBueffel[1024], pHeader[1024], pWork[132], pWork2[60], pTen[12],
|
|
*pcPtr;
|
|
time_t iDate;
|
|
struct tm *psTime;
|
|
pVarEntry pVar = NULL;
|
|
void *pPtr = NULL;
|
|
pMotor pMot;
|
|
float fVal, fVal2;
|
|
CommandList *pCom = NULL;
|
|
pDummy pDum = NULL;
|
|
pIDrivable pDrive = NULL;
|
|
pEVControl pTem = NULL;
|
|
pSicsVariable sVar = NULL;
|
|
float f1=.0, f2=.0, f3=.0, f4=.0;
|
|
|
|
assert(self);
|
|
assert(pTAS);
|
|
assert(self->pCon);
|
|
assert(self->pSics);
|
|
|
|
/* open data file */
|
|
self->fd = fopen(self->pFile, "w");
|
|
if (!self->fd) {
|
|
SCWrite(self->pCon, "ERROR: cannot write data file", eLogError);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
extract the file number from the name for entry into the
|
|
datafile
|
|
*/
|
|
pcPtr = findLastPoint(self->pFile);
|
|
if (pcPtr != NULL) {
|
|
pcPtr -= 6; /* 6 digits for number */
|
|
for (i = 0; i < 6; i++, pcPtr++) {
|
|
pWork[i] = *pcPtr;
|
|
}
|
|
pWork[6] = '\0';
|
|
iFileNO = atoi(pWork);
|
|
} else {
|
|
SCWrite(self->pCon, "WARNING: failed to decode file number", eLog);
|
|
}
|
|
|
|
/* the bizarre R, A, V header */
|
|
charLine(pBueffel, 'R');
|
|
fputs(pBueffel, self->fd);
|
|
fprintf(self->fd, "%8d%8d%8d\n", iFileNO, 1, 0);
|
|
fputs
|
|
("ILL TAS data in the new ASCII format follow after the line VV...V\n",
|
|
self->fd);
|
|
charLine(pBueffel, 'A');
|
|
fputs(pBueffel, self->fd);
|
|
fprintf(self->fd, "%8d%8d\n", 42, 0);
|
|
|
|
/*
|
|
format time to TAS format
|
|
*/
|
|
iDate = time(NULL);
|
|
psTime = localtime(&iDate);
|
|
memset(pWork, 0, 59);
|
|
strftime(pWork, 59, "%d-%b-%Y %H:%M:%S", psTime);
|
|
fprintf(self->fd, "%-10s%-12s%-s\n", pTAS->tasPar[INST]->text,
|
|
pTAS->tasPar[USR]->text, pWork);
|
|
|
|
charLine(pBueffel, 'V');
|
|
fputs(pBueffel, self->fd);
|
|
|
|
/*
|
|
output a plethora of parameters
|
|
*/
|
|
fprintf(self->fd, "INSTR: %s\n", pTAS->tasPar[INST]->text);
|
|
fprintf(self->fd, "EXPNO: \n");
|
|
fprintf(self->fd, "USER_: %s\n", pTAS->tasPar[USR]->text);
|
|
fprintf(self->fd, "LOCAL: %s\n", pTAS->tasPar[LOC]->text);
|
|
fprintf(self->fd, "FILE_: %d\n", iFileNO);
|
|
fprintf(self->fd, "DATE_: %s\n", pWork);
|
|
fprintf(self->fd, "TITLE: %s\n", pTAS->tasPar[TIT]->text);
|
|
fprintf(self->fd, "COMND: %s\n", pTAS->tasPar[COM]->text);
|
|
fprintf(self->fd,
|
|
"POSQE: QH=%8.4f, QK=%8.4f, QL=%8.4f, EN=%8.4f, UN=MEV\n",
|
|
pTAS->tasPar[QH]->fVal,
|
|
pTAS->tasPar[QK]->fVal,
|
|
pTAS->tasPar[QL]->fVal, pTAS->tasPar[EN]->fVal);
|
|
/*
|
|
build the steps line
|
|
*/
|
|
sprintf(pBueffel, "STEPS: ");
|
|
for (i = 0; i < self->iScanVar; i++) {
|
|
DynarGet(self->pScanVar, i, &pPtr);
|
|
pVar = (pVarEntry) pPtr;
|
|
if (pVar) {
|
|
strlcpy(pWork2, ScanVarName(pVar), 59);
|
|
strtoupper(pWork2);
|
|
sprintf(pWork, "D%s=%8.4f, ", pWork2, ScanVarStep(pVar));
|
|
strcat(pBueffel, pWork);
|
|
}
|
|
}
|
|
strcat(pBueffel, "\n");
|
|
fputs(pBueffel, self->fd);
|
|
|
|
/*
|
|
a lot of parameters
|
|
*/
|
|
fprintf(self->fd, "PARAM: DM=%8.4f, DA=%8.4f, SM=%2d, SS=%2d, SA=%2d\n",
|
|
pTAS->tasPar[DM]->fVal,
|
|
pTAS->tasPar[DA]->fVal,
|
|
pTAS->tasPar[SM]->iVal,
|
|
pTAS->tasPar[SS]->iVal, pTAS->tasPar[SA]->iVal);
|
|
fprintf(self->fd, "PARAM: FX=%3d, KFIX=%8.4f\n",
|
|
pTAS->tasPar[FX]->iVal, pTAS->tasPar[KF]->fVal);
|
|
fprintf(self->fd,
|
|
"PARAM: ALF1=%8.4f, ALF2=%8.4f, ALF3=%8.4f, ALF4=%8.4f\n",
|
|
pTAS->tasPar[ALF1]->fVal, pTAS->tasPar[ALF2]->fVal,
|
|
pTAS->tasPar[ALF3]->fVal, pTAS->tasPar[ALF4]->fVal);
|
|
fprintf(self->fd,
|
|
"PARAM: BET1=%8.4f, BET2=%8.4f, BET3=%8.4f, BET4=%8.4f\n",
|
|
pTAS->tasPar[BET1]->fVal, pTAS->tasPar[BET2]->fVal,
|
|
pTAS->tasPar[BET3]->fVal, pTAS->tasPar[BET4]->fVal);
|
|
fprintf(self->fd, "PARAM: ETAM=%8.4f, ETAA=%8.4f\n",
|
|
pTAS->tasPar[ETAM]->fVal, pTAS->tasPar[ETAA]->fVal);
|
|
fprintf(self->fd, "PARAM: AS=%8.4f, BS=%8.4f, CS=%8.4f\n",
|
|
pTAS->tasPar[AS]->fVal, pTAS->tasPar[BS]->fVal,
|
|
pTAS->tasPar[CS]->fVal);
|
|
fprintf(self->fd, "PARAM: AA=%8.4f, BB=%8.4f, CC=%8.4f\n",
|
|
pTAS->tasPar[AA]->fVal, pTAS->tasPar[BB]->fVal,
|
|
pTAS->tasPar[CC]->fVal);
|
|
fprintf(self->fd, "PARAM: AX=%8.4f, AY=%8.4f, AZ=%8.4f\n",
|
|
pTAS->tasPar[AX]->fVal, pTAS->tasPar[AY]->fVal,
|
|
pTAS->tasPar[AZ]->fVal);
|
|
fprintf(self->fd, "PARAM: BX=%8.4f, BY=%8.4f, BZ=%8.4f\n",
|
|
pTAS->tasPar[BX]->fVal, pTAS->tasPar[BY]->fVal,
|
|
pTAS->tasPar[BZ]->fVal);
|
|
|
|
sVar = FindCommandData(pServ->pSics, "ProposalID", "SicsVariable");
|
|
if (sVar != NULL) {
|
|
fprintf(self->fd,"PARAM: ProposalID=%s\n",sVar->text);
|
|
}
|
|
|
|
/*
|
|
* write mupad stuff if available
|
|
*/
|
|
sVar = FindCommandData(pServ->pSics, "w1", "SicsVariable");
|
|
if (sVar != NULL) {
|
|
f1 = sVar->fVal;
|
|
sVar = FindCommandData(pServ->pSics, "w2", "SicsVariable");
|
|
if (sVar != NULL) {
|
|
f2 = sVar->fVal;
|
|
}
|
|
sVar = FindCommandData(pServ->pSics, "w3", "SicsVariable");
|
|
if (sVar != NULL) {
|
|
f3 = sVar->fVal;
|
|
}
|
|
sVar = FindCommandData(pServ->pSics, "w4", "SicsVariable");
|
|
if (sVar != NULL) {
|
|
f4 = sVar->fVal;
|
|
}
|
|
fprintf(self->fd, "PARAM: W1=%8.4f, W2=%8.4f, W3=%8.4f, W4=%8.4f\n",
|
|
f1, f2, f3, f4);
|
|
|
|
sVar = FindCommandData(pServ->pSics, "p1", "SicsVariable");
|
|
if (sVar != NULL) {
|
|
f1 = sVar->fVal;
|
|
}
|
|
sVar = FindCommandData(pServ->pSics, "p2", "SicsVariable");
|
|
if (sVar != NULL) {
|
|
f2 = sVar->fVal;
|
|
}
|
|
sVar = FindCommandData(pServ->pSics, "p3", "SicsVariable");
|
|
if (sVar != NULL) {
|
|
f3 = sVar->fVal;
|
|
}
|
|
sVar = FindCommandData(pServ->pSics, "p4", "SicsVariable");
|
|
if (sVar != NULL) {
|
|
f4 = sVar->fVal;
|
|
}
|
|
fprintf(self->fd, "PARAM: P1=%8.4f, P2=%8.4f, P3=%8.4f, P4=%8.4f\n",
|
|
f1, f2, f3, f4);
|
|
|
|
|
|
}
|
|
|
|
/*
|
|
write motors and currents
|
|
*/
|
|
fprintf(self->fd, "VARIA: ");
|
|
iCount = 0;
|
|
for (i = 0; i < MAXMOT; i++) {
|
|
if (pTAS->iPOL >= 0
|
|
|| (tasMotorOrder[i][0] != 'i' && tasMotorOrder[i][0] != 'h')) {
|
|
/* do not write currents (names starting with i or h) when not in pol. mode */
|
|
fVal = readDrivable(tasMotorOrder[i], self->pCon);
|
|
if (iCount == 3) {
|
|
iCount = 0;
|
|
fprintf(self->fd, "\nVARIA: ");
|
|
}
|
|
strcpy(pWork2, tasMotorOrder[i]);
|
|
strtoupper(pWork2);
|
|
fprintf(self->fd, "%-8s=%8.4f, ", pWork2, fVal);
|
|
iCount++;
|
|
}
|
|
}
|
|
fprintf(self->fd, "\n");
|
|
|
|
/*
|
|
write zeros
|
|
*/
|
|
fprintf(self->fd, "ZEROS: ");
|
|
iCount = 0;
|
|
for (i = 0; i < CURMOT - 1; i++) {
|
|
pMot = FindMotor(self->pSics, tasMotorOrder[i]);
|
|
if (pMot) {
|
|
status = MotorGetPar(pMot, "softzero", &fVal);
|
|
if (!status) {
|
|
fVal = -9999.77;
|
|
}
|
|
fVal *= -1;
|
|
if (iCount == 3) {
|
|
iCount = 0;
|
|
fprintf(self->fd, "\nZEROS: ");
|
|
}
|
|
strcpy(pWork2, tasMotorOrder[i]);
|
|
strtoupper(pWork2);
|
|
fprintf(self->fd, "%-8s=%8.4f, ", pWork2, fVal);
|
|
iCount++;
|
|
} else {
|
|
sprintf(pBueffel, "WARNING: motor %s NOT found, %s",
|
|
tasMotorOrder[i], " possible data file corruption");
|
|
SCWrite(self->pCon, pBueffel, eWarning);
|
|
}
|
|
}
|
|
fprintf(self->fd, "\n");
|
|
|
|
if (pTAS->iPOL >= 0) {
|
|
writePolFile(self->fd, pTAS);
|
|
}
|
|
|
|
/*
|
|
write counter parameters
|
|
*/
|
|
fVal = GetCounterPreset(self->pCounterData);
|
|
if (GetCounterMode(self->pCounterData) == eTimer) {
|
|
fprintf(self->fd, "PARAM: TI=%8.4f\n", fVal);
|
|
} else {
|
|
fprintf(self->fd, "PARAM: MN=%8f\n", fVal);
|
|
}
|
|
|
|
/*
|
|
write temperature data
|
|
*/
|
|
pCom = FindCommand(self->pSics, "temperature");
|
|
if (pCom) {
|
|
pDum = (pDummy) pCom->pData;
|
|
pDrive = pDum->pDescriptor->GetInterface(pDum, DRIVEID);
|
|
if (pDrive) { /* a proper environment device */
|
|
fVal = pDrive->GetValue(pDum, self->pCon);
|
|
pTem = (pEVControl) pCom->pData;
|
|
EVCGetPar(pTem, "target", &fVal2);
|
|
fprintf(self->fd, "PARAM: TEM=%8.4f, RT=%8.4f\n", fVal, fVal2);
|
|
}
|
|
}
|
|
|
|
/*
|
|
build both the format and the data header line,
|
|
start with the scan variables
|
|
*/
|
|
if (pTAS->iPOL >= 0) {
|
|
strcpy(pBueffel, "FORMT: (I4,I4,1X,");
|
|
strcpy(pHeader, " PNT PAL");
|
|
} else {
|
|
strcpy(pBueffel, "FORMT: (I4,1X,");
|
|
strcpy(pHeader, " PNT ");
|
|
}
|
|
for (i = 0; i < self->iScanVar; i++) {
|
|
DynarGet(self->pScanVar, i, &pPtr);
|
|
pVar = (pVarEntry) pPtr;
|
|
if (pVar) {
|
|
strcat(pBueffel, "F9.4,1X,");
|
|
strlcpy(pWork2, pVar->Name, 59);
|
|
strtoupper(pWork2);
|
|
strcenter(pWork2, pTen, 11);
|
|
strcat(pHeader, pTen);
|
|
}
|
|
}
|
|
/*
|
|
put the standard counter things
|
|
*/
|
|
strcat(pBueffel, "F8.0,1X,F8.0,1X,F9.2,1X,F8.0,1X,F8.0,1X,F9.0,1X,");
|
|
strcat(pHeader, " M1 M2 TIME CNTS M3 M4 ");
|
|
/*
|
|
now the additional variables
|
|
*/
|
|
for (i = 0; i < pTAS->addCount; i++) {
|
|
if (i == pTAS->addCount - 1) {
|
|
strcat(pBueffel, "F9.4");
|
|
} else {
|
|
strcat(pBueffel, "F9.4,1X,");
|
|
}
|
|
if (pTAS->addType[i] == 1) { /* motor */
|
|
strcpy(pWork2, tasMotorOrder[pTAS->addOutput[i]]);
|
|
} else {
|
|
strcpy(pWork2, tasVariableOrder[pTAS->addOutput[i]]);
|
|
}
|
|
strtoupper(pWork2);
|
|
strcenter(pWork2, pTen, 11);
|
|
strcat(pHeader, pTen);
|
|
}
|
|
strcat(pBueffel, ")");
|
|
|
|
/*
|
|
write the final bit
|
|
*/
|
|
fprintf(self->fd, "%s\nDATA_:\n%s\n", pBueffel, pHeader);
|
|
|
|
/*
|
|
write header to screen as well
|
|
*/
|
|
SCWrite(self->pCon, pHeader, eLog);
|
|
|
|
/*
|
|
close the file, we will reopen later with append for the data
|
|
*/
|
|
fclose(self->fd);
|
|
self->fd = NULL;
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
TASScanPoint writes the data at each ScanPoint
|
|
---------------------------------------------------------------------------*/
|
|
static int TASScanPoint(pScanData self, int iPoint)
|
|
{
|
|
pTASdata pTAS = (pTASdata) self->pSpecial;
|
|
pVarEntry pVar = NULL;
|
|
void *pPtr = NULL;
|
|
int i, status, iPtr;
|
|
float fVal;
|
|
pMotor pMot = NULL;
|
|
long m1, m2, m3, m4, cnts;
|
|
char pBueffel[1024], pWork[80], pError[132];
|
|
|
|
/*
|
|
after polarisation analysis, this has to be ignored as it is called
|
|
another time from the ScanLoop
|
|
*/
|
|
if (pTAS->iIgnore) {
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
reopen file for appending
|
|
*/
|
|
self->fd = fopen(self->pFile, "a");
|
|
if (!self->fd) {
|
|
SCWrite(self->pCon, "ERROR: cannot append to data file", eLogError);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
write point number
|
|
*/
|
|
if (pTAS->iPOL > 0) {
|
|
sprintf(pBueffel, "%3d %3d ", iPoint + 1, pTAS->iPOL);
|
|
} else {
|
|
sprintf(pBueffel, "%4d ", iPoint + 1);
|
|
}
|
|
|
|
/*
|
|
write the scan variables
|
|
*/
|
|
for (i = 0; i < self->iScanVar; i++) {
|
|
DynarGet(self->pScanVar, i, &pPtr);
|
|
pVar = (pVarEntry) pPtr;
|
|
if (pVar) {
|
|
if (isTASMotor(ScanVarName(pVar)) >= 0) {
|
|
if (pVar->pInter != NULL) {
|
|
fVal = pVar->pInter->GetValue(pVar->pObject, self->pCon);
|
|
} else {
|
|
fVal = -9999.99;
|
|
}
|
|
} else if ((iPtr = isTASVar(pVar->Name)) >= 0) {
|
|
fVal = pTAS->tasPar[iPtr]->fVal;
|
|
}
|
|
}
|
|
sprintf(pWork, "%9.4f ", fVal);
|
|
strcat(pBueffel, pWork);
|
|
}
|
|
|
|
/*
|
|
write monitors and counters
|
|
*/
|
|
m1 = GetMonitor(self->pCounterData, 1, self->pCon);
|
|
m2 = GetMonitor(self->pCounterData, 2, self->pCon);
|
|
m3 = GetMonitor(self->pCounterData, 3, self->pCon);
|
|
m4 = GetMonitor(self->pCounterData, 4, self->pCon); // integrated proton charge on target
|
|
cnts = GetCounts(self->pCounterData, self->pCon);
|
|
fVal = GetCountTime(self->pCounterData, self->pCon);
|
|
sprintf(pWork, "%8ld %8ld %9.2f %8ld %8ld %9ld", m1, m2, fVal, cnts, m3, m4);
|
|
strcat(pBueffel, pWork);
|
|
|
|
/*
|
|
write additional parameters
|
|
*/
|
|
for (i = 0; i < pTAS->addCount; i++) {
|
|
fVal = -999.99;
|
|
if (pTAS->addType[i] == 1) { /* motor */
|
|
fVal = readDrivable(tasMotorOrder[pTAS->addOutput[i]], self->pCon);
|
|
if (fVal < -990.) {
|
|
sprintf(pError, "WARNING: problem reading %s",
|
|
tasMotorOrder[pTAS->addOutput[i]]);
|
|
SCWrite(self->pCon, pError, eLog);
|
|
}
|
|
} else {
|
|
fVal = pTAS->tasPar[pTAS->addOutput[i]]->fVal;
|
|
}
|
|
sprintf(pWork, "%9.4f ", fVal);
|
|
strcat(pBueffel, pWork);
|
|
}
|
|
|
|
/*
|
|
write both to file and onto screen
|
|
*/
|
|
fprintf(self->fd, "%s\n", pBueffel);
|
|
SCWrite(self->pCon, pBueffel, eLog);
|
|
|
|
/*
|
|
close the file
|
|
*/
|
|
fclose(self->fd);
|
|
self->fd = NULL;
|
|
return 1;
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------
|
|
disables a3 driving in powder mode. In powder mode a3 is fixed. This
|
|
supresses the error message issued otherwise.
|
|
------------------------------------------------------------------------*/
|
|
static void fixPowder(unsigned char tasTargetMask[20])
|
|
{
|
|
char *pPtr = NULL;
|
|
|
|
pPtr =
|
|
(char *) Tcl_GetVar(pServ->pSics->pTcl, "powder", TCL_GLOBAL_ONLY);
|
|
if (pPtr) {
|
|
if (strstr(pPtr, "1") != NULL) {
|
|
tasTargetMask[2] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------------
|
|
TASScanDrive starts all the motors necessary to drive to a new scan
|
|
position. It thereby takes care of the TAS calculation if necessary.
|
|
-------------------------------------------------------------------------*/
|
|
static int TASScanDrive(pScanData self, int iPoint)
|
|
{
|
|
pTASdata pTAS = (pTASdata) self->pSpecial;
|
|
pVarEntry pVar = NULL;
|
|
void *pPtr = NULL;
|
|
int i, status, iPtr;
|
|
int iTAS = 0;
|
|
pMotor pMot;
|
|
unsigned char tasTargetMask[20], tasMask[MAXEVAR];
|
|
float tasTargets[20];
|
|
|
|
/*
|
|
initialize masks to 0
|
|
*/
|
|
for (i = 0; i < 10; i++) {
|
|
tasMask[i] = 0;
|
|
tasTargetMask[i] = 0;
|
|
tasTargetMask[i + 10] = 0;
|
|
tasTargets[i] = .0;
|
|
tasTargets[i + 10] = .0;
|
|
}
|
|
tasMask[10] = 0;
|
|
tasMask[11] = 0;
|
|
|
|
/*
|
|
store SRO motor value
|
|
*/
|
|
getSRO(self->pCon, &pTAS->oldSRO);
|
|
|
|
/*
|
|
loop through all the scan variables
|
|
*/
|
|
for (i = 0; i < self->iScanVar; i++) {
|
|
DynarGet(self->pScanVar, i, &pPtr);
|
|
pVar = (pVarEntry) pPtr;
|
|
if (pVar) {
|
|
/* set variable if QE-variable */
|
|
if ((iPtr = isTASEnergy(ScanVarName(pVar))) >= 0) {
|
|
iTAS = 1;
|
|
pTAS->tasPar[EI + iPtr]->fVal =
|
|
ScanVarStart(pVar) + iPoint * ScanVarStep(pVar);
|
|
pTAS->tasPar[ETARGET + iPtr]->fVal =
|
|
ScanVarStart(pVar) + iPoint * ScanVarStep(pVar);
|
|
tasMask[iPtr] = 1;
|
|
} else {
|
|
/*
|
|
This is a motor, start it.
|
|
*/
|
|
StartMotor(pServ->pExecutor, self->pSics, self->pCon, pVar->Name,
|
|
RUNDRIVE, pVar->fStart + iPoint * pVar->fStep);
|
|
/*
|
|
Ignore errors. TAS scans continues when a motor runs into
|
|
a limit.
|
|
*/
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
now check if we need a TAS calculation: if so do it and start
|
|
the motors
|
|
*/
|
|
if (iTAS) {
|
|
status = TASCalc(pTAS, self->pCon, tasMask, tasTargets, tasTargetMask);
|
|
if (status) {
|
|
/*
|
|
Errors both in calculation or in starting motors are
|
|
ignored here on purpose. There is a slight chance that
|
|
other points in the scan fit the bill.
|
|
*/
|
|
fixPowder(tasTargetMask);
|
|
TASStart(pTAS, self->pCon, self->pSics, tasTargets, tasTargetMask);
|
|
} else {
|
|
SCSetInterrupt(self->pCon, eAbortOperation);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/*
|
|
now wait for our motors to arrive, thereby ignoring any error
|
|
returns. DO NOT WAIT if fast scan!
|
|
*/
|
|
if (pTAS->iFast) {
|
|
return 1;
|
|
} else {
|
|
status = Wait4Success(GetExecutor());
|
|
}
|
|
|
|
TASUpdate(pTAS, self->pCon);
|
|
return 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------
|
|
RunPolScan does a polarized scan
|
|
------------------------------------------------------------------------*/
|
|
static int RunPolScan(pScanData self, int iPoint)
|
|
{
|
|
FILE *fd = NULL;
|
|
char buffer[132];
|
|
pTASdata pTAS = (pTASdata) self->pSpecial;
|
|
|
|
fd = fopen(pTAS->tasPar[POLFIL]->text, "r");
|
|
if (!fd) {
|
|
SCWrite(self->pCon, "ERROR: failed to open polarisation analysis file",
|
|
eLogError);
|
|
return 0;
|
|
}
|
|
pTAS->iPOL = 0;
|
|
while (fgets(buffer, 131, fd) != NULL) {
|
|
/*
|
|
ignore all errors here
|
|
*/
|
|
if (buffer[0] != '#') {
|
|
InterpExecute(self->pSics,self->pCon,buffer);
|
|
strtolower(buffer);
|
|
if(strstr(buffer,"co") != NULL){
|
|
pTAS->iPOL++;
|
|
self->WriteScanPoints(self,iPoint);
|
|
}
|
|
}
|
|
/*
|
|
but allow for interrupts
|
|
*/
|
|
if (SCGetInterrupt(self->pCon) != eContinue) {
|
|
break;
|
|
}
|
|
}
|
|
pTAS->iIgnore = 1;
|
|
fclose(fd);
|
|
pTAS->iPOL = 1;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
TASScanCount starts the counter for a TAS scan or runs the polarization
|
|
analysis.
|
|
---------------------------------------------------------------------------*/
|
|
static int TASScanCount(pScanData self, int iPoint)
|
|
{
|
|
pTASdata pTAS = (pTASdata) self->pSpecial;
|
|
float fVal;
|
|
int status, iRet;
|
|
Status eOld;
|
|
|
|
pTAS->iIgnore = 0;
|
|
/*
|
|
call the polarisation scan function if necessary
|
|
*/
|
|
if (pTAS->iPOL >= 0) {
|
|
return RunPolScan(self, iPoint);
|
|
}
|
|
|
|
/*
|
|
this is easy, just an ordinary scan, start a counter
|
|
*/
|
|
fVal = GetCounterPreset(self->pCounterData);
|
|
status = DoCount(self->pCounterData, fVal, self->pCon, 2);
|
|
iRet = Wait4Success(GetExecutor());
|
|
if (iRet == DEVINT) {
|
|
SCWrite(self->pCon, "Counting aborted due to Interrupt", eLog);
|
|
status = 0;
|
|
} else if (iRet == DEVERROR) {
|
|
SCWrite(self->pCon, "Counting finished with Problems", eLog);
|
|
status = 0;
|
|
} else {
|
|
status = 1;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
TAS stores the scan data. This is necessary in order to support things
|
|
like peak or center which require the scan data for operation
|
|
--------------------------------------------------------------------------*/
|
|
static int TASCollect(pScanData self, int iPoint)
|
|
{
|
|
pVarEntry pVar = NULL;
|
|
void *pDings;
|
|
int i, iRet, status, iPtr;
|
|
float fVal;
|
|
CountEntry sCount;
|
|
char *pAns = NULL, *pPtr = NULL;
|
|
pTASdata pTAS = (pTASdata) self->pSpecial;
|
|
pMotor pMot;
|
|
|
|
assert(self);
|
|
assert(self->pCon);
|
|
|
|
/* loop over all scan variables */
|
|
status = 1;
|
|
for (i = 0; i < self->iScanVar; i++) {
|
|
DynarGet(self->pScanVar, i, &pDings);
|
|
pVar = (pVarEntry) pDings;
|
|
if (pVar) {
|
|
if ((iPtr = isTASEnergy(pVar->Name)) >= 0) {
|
|
fVal = pTAS->tasPar[EI + iPtr]->fVal;
|
|
} else {
|
|
fVal = readDrivable(pVar->Name, self->pCon);
|
|
}
|
|
AppendScanVar(pVar, fVal);
|
|
}
|
|
}
|
|
|
|
/* store counter data */
|
|
/* monitors */
|
|
for (i = 1; i < 10; i++) {
|
|
sCount.Monitors[i - 1] = GetMonitor((pCounter) self->pCounterData, i,
|
|
self->pCon);
|
|
}
|
|
if (self->iChannel != 0 && self->iChannel != -10) {
|
|
sCount.Monitors[self->iChannel - 1] =
|
|
GetCounts((pCounter) self->pCounterData, self->pCon);
|
|
}
|
|
|
|
/* counts, depending on iChannel */
|
|
if (self->iChannel == 0) {
|
|
sCount.lCount = GetCounts((pCounter) self->pCounterData, self->pCon);
|
|
} else {
|
|
sCount.lCount = GetMonitor((pCounter) self->pCounterData,
|
|
self->iChannel, self->pCon);
|
|
}
|
|
|
|
/* get time */
|
|
sCount.fTime = GetCountTime((pCounter) self->pCounterData, self->pCon);
|
|
/* stow away */
|
|
DynarReplace(self->pCounts, self->iCounts, &sCount, sizeof(CountEntry));
|
|
self->iCounts++;
|
|
return 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
SetTASScan sets the special TAS scan functions in the scan data
|
|
structure
|
|
------------------------------------------------------------------------*/
|
|
static void SetTASScan(pScanData self, pTASdata pTAS)
|
|
{
|
|
self->PrepareScan = NonCheckPrepare;
|
|
self->WriteHeader = TASHeader;
|
|
self->WriteScanPoints = TASScanPoint;
|
|
self->ScanDrive = TASScanDrive;
|
|
self->ScanCount = TASScanCount;
|
|
self->CollectScanData = TASCollect;
|
|
self->pSpecial = pTAS;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
AddTASScanVar is the same as the standard AddScanVar but without the
|
|
error checking for a drivable parameter
|
|
--------------------------------------------------------------------------*/
|
|
static int AddTASScanVar(pScanData self, SicsInterp * pSics,
|
|
SConnection * pCon, char *name, float fStart,
|
|
float fStep)
|
|
{
|
|
CommandList *pCom = NULL;
|
|
pIDrivable pDriv = NULL;
|
|
pDummy pData = NULL;
|
|
VarEntry pVar;
|
|
char pBueffel[512];
|
|
|
|
if (self->iActive) {
|
|
SCWrite(pCon,
|
|
"ERROR: cannot change parameters while scan is running",
|
|
eError);
|
|
return 0;
|
|
}
|
|
|
|
/* find the thing */
|
|
pCom = FindCommand(pSics, name);
|
|
if (!pCom) {
|
|
sprintf(pBueffel, "ERROR: Cannot find variable %s to scan", name);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
pData = (pDummy) pCom->pData;
|
|
if (!pData) {
|
|
sprintf(pBueffel, "ERROR: Cannot find data for variable %s", name);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
|
|
/* got everything, fill in the VarEntry structure */
|
|
strcpy(pVar.Name, name);
|
|
pVar.pInter = GetDrivableInterface(pData);
|
|
pVar.pObject = pData;
|
|
pVar.fStart = fStart;
|
|
pVar.fStep = fStep;
|
|
pVar.fData = NULL;
|
|
pVar.dataList = LLDcreate(sizeof(float));
|
|
|
|
/* put it away */
|
|
DynarPutCopy(self->pScanVar, self->iScanVar, &pVar, sizeof(VarEntry));
|
|
self->iScanVar++;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------
|
|
The TAS scan command line contains two types of items: Scan variables
|
|
and their center values and normal SICS variables such as the monitor
|
|
to use and the steps in each scan variable. As this is decidely easier
|
|
this command line is parsed in two pathes: In the first pass all the
|
|
variables are set and removed. In the second pass the scan variables
|
|
are parsed and entered into the scan data structure.
|
|
|
|
ParseVar implements the first pass.
|
|
-------------------------------------------------------------------------*/
|
|
#define NONE 0
|
|
#define NUM 1
|
|
#define TXT 2
|
|
extern char *stptok(const char *s, char *tok, size_t toklen, char *brk);
|
|
|
|
|
|
static int ParseVar(pTASdata pTAS, char *pBueffel, SConnection * pCon)
|
|
{
|
|
char *myBuffer = NULL, pToken[20], *pPtr, pError[132];
|
|
int iPtr, lastToken, lastVar;
|
|
VarType vt;
|
|
int qhPars;
|
|
|
|
/*
|
|
set up our own buffer
|
|
*/
|
|
myBuffer = (char *) malloc((strlen(pBueffel) + 10) * sizeof(char));
|
|
if (!myBuffer) {
|
|
SCWrite(pCon, "ERROR: out of memory in TASSCan", eError);
|
|
return 0;
|
|
}
|
|
memset(myBuffer, 0, 10 + strlen(pBueffel));
|
|
|
|
/*
|
|
parse loop
|
|
*/
|
|
lastToken = NONE;
|
|
lastVar = -1;
|
|
qhPars = 0;
|
|
pPtr = stptok(pBueffel, pToken, 20, " ,="); /* step over sc */
|
|
while (pPtr != NULL) {
|
|
pPtr = stptok(pPtr, pToken, 20, " ,=");
|
|
if (strlen(pToken) < 1 || pPtr == NULL)
|
|
continue;
|
|
switch (lastToken) {
|
|
case NONE:
|
|
if (tasNumeric(pToken)) {
|
|
sprintf(pError,
|
|
"ERROR: parse error at %s, expected variable", pToken);
|
|
SCWrite(pCon, pError, eError);
|
|
goto error;
|
|
}
|
|
lastToken = TXT;
|
|
if ((iPtr = isTASVar(pToken)) >= 0) {
|
|
if (isTASEnergy(pToken) >= 0) {
|
|
/* energy variables are scan variables */
|
|
strcpy(myBuffer, pToken);
|
|
strcat(myBuffer, " ");
|
|
} else {
|
|
lastVar = iPtr;
|
|
}
|
|
} else {
|
|
/* this is the motor case */
|
|
strcpy(myBuffer, pToken);
|
|
strcat(myBuffer, " ");
|
|
}
|
|
break;
|
|
case TXT:
|
|
if (tasNumeric(pToken)) {
|
|
lastToken = NUM;
|
|
if (qhPars == 3) {
|
|
SCWrite(pCon, "DQH cannot have 2 values", eError);
|
|
goto error;
|
|
}
|
|
qhPars = 0;
|
|
if (lastVar >= 0) {
|
|
vt = GetVarType(pTAS->tasPar[lastVar]);
|
|
if (vt == veFloat) {
|
|
VarSetFloat(pTAS->tasPar[lastVar], atof(pToken), usInternal);
|
|
SCparChange(pCon);
|
|
} else if (vt == veInt) {
|
|
VarSetInt(pTAS->tasPar[lastVar],
|
|
(int) atof(pToken), usInternal);
|
|
SCparChange(pCon);
|
|
} else {
|
|
pTAS->tasPar[lastVar]->text = strdup(pToken);
|
|
}
|
|
lastVar++;
|
|
} else {
|
|
strcat(myBuffer, pToken);
|
|
strcat(myBuffer, " ");
|
|
}
|
|
} else {
|
|
sprintf(pError, "ERROR: parse error at %s, expected number",
|
|
pToken);
|
|
SCWrite(pCon, pError, eError);
|
|
goto error;
|
|
}
|
|
break;
|
|
case NUM:
|
|
if (tasNumeric(pToken)) {
|
|
lastToken = NUM;
|
|
if (lastVar >= 0) {
|
|
if (qhPars == 0) {
|
|
if (lastVar != DQK) {
|
|
SCPrintf(pCon, eError, "ERROR: %s can have only one value",
|
|
tasVariableOrder[lastVar - 1]);
|
|
goto error;
|
|
}
|
|
qhPars = 3;
|
|
} else if (qhPars == 1) {
|
|
SCWrite(pCon, "ERROR: DQH can have only 4 values", eError);
|
|
goto error;
|
|
} else {
|
|
qhPars--;
|
|
}
|
|
|
|
vt = GetVarType(pTAS->tasPar[lastVar]);
|
|
if (vt != veFloat) {
|
|
SCPrintf(pCon, eError,
|
|
"ERROR: %s must be float (internal error)",
|
|
tasVariableOrder[lastVar]);
|
|
goto error;
|
|
}
|
|
VarSetFloat(pTAS->tasPar[lastVar], atof(pToken), usInternal);
|
|
SCparChange(pCon);
|
|
lastVar++;
|
|
} else {
|
|
strcat(myBuffer, pToken);
|
|
strcat(myBuffer, " ");
|
|
}
|
|
} else {
|
|
lastToken = TXT;
|
|
lastVar = -1;
|
|
if ((iPtr = isTASVar(pToken)) >= 0) {
|
|
if (isTASEnergy(pToken) >= 0) {
|
|
/* energy variables are scan variables */
|
|
strcat(myBuffer, pToken);
|
|
strcat(myBuffer, " ");
|
|
} else {
|
|
lastVar = iPtr;
|
|
}
|
|
} else {
|
|
/* this is the motor case */
|
|
strcat(myBuffer, pToken);
|
|
strcat(myBuffer, " ");
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (qhPars == 3) {
|
|
SCWrite(pCon, "DQH cannot have 2 values", eError);
|
|
goto error;
|
|
}
|
|
strcpy(pBueffel, myBuffer);
|
|
free(myBuffer);
|
|
return 1;
|
|
error:
|
|
free(myBuffer);
|
|
return 0;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------
|
|
EnterScanVar adds the scan variable given to the scan. Thereby it
|
|
caluclate sthe start of the scan from the center given and NP. To this
|
|
and other purposes it locates the scan variable increment.
|
|
-----------------------------------------------------------------------*/
|
|
|
|
static int EnterScanVar(pTASdata pTAS, char *name, float fCenter,
|
|
SConnection * pCon)
|
|
{
|
|
int iPtr;
|
|
char pIncrement[30], pError[132];
|
|
float fIncrement, fStart, fTemp;
|
|
|
|
/*
|
|
get increment
|
|
*/
|
|
strcpy(pIncrement, "d");
|
|
strcat(pIncrement, name);
|
|
iPtr = isTASVar(pIncrement);
|
|
if (iPtr < 0) {
|
|
sprintf(pError, "ERROR: internal error, increment %s not found",
|
|
pIncrement);
|
|
SCWrite(pCon, pError, eError);
|
|
return 0;
|
|
}
|
|
fIncrement = pTAS->tasPar[iPtr]->fVal;
|
|
|
|
/*
|
|
calculate start
|
|
*/
|
|
fStart = fCenter - (pTAS->pScan->iNP / 2) * fIncrement;
|
|
|
|
/*
|
|
If step > 0 save it for scaninfo
|
|
*/
|
|
if (fIncrement < 0)
|
|
fTemp = -fIncrement;
|
|
else
|
|
fTemp = fIncrement;
|
|
if (fTemp > .001 && strlen(pTAS->scanVar) < 2) {
|
|
sprintf(pTAS->scanVar, "%s,%f,%f", name, fStart, fIncrement);
|
|
}
|
|
|
|
/*
|
|
put it in
|
|
*/
|
|
return AddTASScanVar(pTAS->pScan, pTAS->pScan->pSics, pCon,
|
|
name, fStart, fIncrement);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
ParseScanVars parses the scan variables and enters them into the
|
|
scan. Thereby it takes care of the odd MAD syntax and off the fact that
|
|
the values given to sc are the center of the scan whereas we need the
|
|
start of the scan. Also ParseScanVars locates the increments for the
|
|
various variables which are represented as SICS variables. They are
|
|
just the variable name prepended with a "d".
|
|
------------------------------------------------------------------------*/
|
|
static int ParseScanVar(pTASdata pTAS, char *pBueffel, SConnection * pCon,
|
|
int *iTas)
|
|
{
|
|
char pToken[20], *pPtr, pError[132];
|
|
int iPtr, lastToken, lastVar, lastMotor, status;
|
|
VarType vt;
|
|
int qhPars;
|
|
|
|
/*
|
|
parse loop
|
|
*/
|
|
lastToken = NONE;
|
|
lastVar = lastMotor = -1;
|
|
pPtr = pBueffel;
|
|
qhPars = 0;
|
|
while (pPtr != NULL) {
|
|
pPtr = stptok(pPtr, pToken, 20, " ,=");
|
|
if (strlen(pToken) < 1 || pPtr == NULL)
|
|
continue;
|
|
switch (lastToken) {
|
|
case NONE:
|
|
if (tasNumeric(pToken)) {
|
|
sprintf(pError,
|
|
"ERROR: parse error at %s, expected variable", pToken);
|
|
SCWrite(pCon, pError, eError);
|
|
return 0;
|
|
}
|
|
lastToken = TXT;
|
|
if ((iPtr = isTASEnergy(pToken)) >= 0) {
|
|
/* QE - variables are scan variables */
|
|
lastVar = iPtr;
|
|
(*iTas)++;
|
|
} else if ((iPtr = isTASMotor(pToken)) >= 0) {
|
|
/* as are motors */
|
|
lastMotor = iPtr;
|
|
} else {
|
|
sprintf(pError, "ERROR: cannot scan %s", pToken);
|
|
SCWrite(pCon, pError, eError);
|
|
return 0;
|
|
}
|
|
break;
|
|
case TXT:
|
|
if (tasNumeric(pToken)) {
|
|
lastToken = NUM;
|
|
if (qhPars == 3) {
|
|
SCWrite(pCon, "QH cannot have 2 values", eError);
|
|
return 0;
|
|
}
|
|
qhPars = 0;
|
|
if (lastVar >= 0) {
|
|
/*
|
|
add energy variable
|
|
*/
|
|
status = EnterScanVar(pTAS, tasVariableOrder[EI + lastVar],
|
|
atof(pToken), pCon);
|
|
pTAS->tasPar[EI + lastVar]->fVal = atof(pToken);
|
|
if (!status)
|
|
return status;
|
|
lastVar++;
|
|
} else if (lastMotor >= 0) {
|
|
/*
|
|
add motor
|
|
*/
|
|
status = EnterScanVar(pTAS, tasMotorOrder[lastMotor],
|
|
atof(pToken), pCon);
|
|
if (!status)
|
|
return status;
|
|
lastMotor++;
|
|
} else {
|
|
/* internal error */
|
|
assert(0);
|
|
}
|
|
} else {
|
|
sprintf(pError, "ERROR: parse error at %s, expected number",
|
|
pToken);
|
|
SCWrite(pCon, pError, eError);
|
|
return 0;
|
|
}
|
|
break;
|
|
case NUM:
|
|
if (tasNumeric(pToken)) {
|
|
lastToken = NUM;
|
|
if (lastVar >= 0) {
|
|
if (qhPars == 0) {
|
|
if (EMIN + lastVar != QK) {
|
|
SCPrintf(pCon, eError, "ERROR: %s can have only one value",
|
|
tasVariableOrder[EMIN + lastVar - 1]);
|
|
return 0;
|
|
}
|
|
qhPars = 3;
|
|
} else if (qhPars == 1) {
|
|
SCWrite(pCon, "ERROR: QH can have only 4 values", eError);
|
|
return 0;
|
|
} else {
|
|
qhPars--;
|
|
}
|
|
|
|
/*
|
|
add energy variable
|
|
*/
|
|
status = EnterScanVar(pTAS, tasVariableOrder[EI + lastVar],
|
|
atof(pToken), pCon);
|
|
pTAS->tasPar[EI + lastVar]->fVal = atof(pToken);
|
|
if (!status)
|
|
return status;
|
|
lastVar++;
|
|
} else {
|
|
assert(lastMotor >= 0);
|
|
SCPrintf(pCon, eError, "ERROR: %s can have only one value",
|
|
tasMotorOrder[lastMotor - 1]);
|
|
return 0;
|
|
}
|
|
} else {
|
|
lastToken = TXT;
|
|
lastVar = lastMotor = -1;
|
|
if ((iPtr = isTASEnergy(pToken)) >= 0) {
|
|
/* QE - variables are scan variables */
|
|
lastVar = iPtr;
|
|
(*iTas)++;
|
|
} else if ((iPtr = isTASMotor(pToken)) >= 0) {
|
|
/* as are motors */
|
|
lastMotor = iPtr;
|
|
} else {
|
|
sprintf(pError, "ERROR: cannot scan %s", pToken);
|
|
SCWrite(pCon, pError, eError);
|
|
return 0;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (qhPars == 3) {
|
|
SCWrite(pCon, "QH cannot have 2 values", eError);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------
|
|
During a TAS scan additional output variables can be printed. These are
|
|
defined in a text variable called ouput. ParseOutput now parses this
|
|
variable and enters the variables found in there into the TAS data
|
|
structure so that they can be printed during the scan.
|
|
------------------------------------------------------------------------*/
|
|
static void ParseOutput(pTASdata pTAS, SConnection * pCon)
|
|
{
|
|
char *pText = NULL, *pPtr, pToken[20], pWarn[256];
|
|
int iPtr;
|
|
|
|
/*
|
|
get a copy of output
|
|
*/
|
|
pText =
|
|
(char *) malloc((strlen(pTAS->tasPar[OUT]->text) + 10) *
|
|
sizeof(char));
|
|
if (!pText) {
|
|
SCWrite(pCon, "WARNING: out of memory while parsing output variable",
|
|
eWarning);
|
|
return;
|
|
}
|
|
strcpy(pText, pTAS->tasPar[OUT]->text);
|
|
|
|
/*
|
|
wash it
|
|
*/
|
|
prepare2Parse(pText);
|
|
|
|
/*
|
|
parse
|
|
*/
|
|
pTAS->addCount = 0;
|
|
pPtr = pText;
|
|
while (pPtr != NULL) {
|
|
pPtr = stptok(pPtr, pToken, 20, " ,=");
|
|
if (strlen(pToken) < 1 || pPtr == NULL)
|
|
continue;
|
|
|
|
if ((iPtr = isTASMotor(pToken)) >= 0) {
|
|
pTAS->addOutput[pTAS->addCount] = iPtr;
|
|
pTAS->addType[pTAS->addCount] = 1;
|
|
pTAS->addCount++;
|
|
} else if ((iPtr = isTASVar(pToken)) >= 0) {
|
|
pTAS->addOutput[pTAS->addCount] = iPtr;
|
|
pTAS->addType[pTAS->addCount] = 0;
|
|
pTAS->addCount++;
|
|
} else {
|
|
sprintf(pWarn, "WARNING: ignored invalid token > %s < in output",
|
|
pToken);
|
|
SCWrite(pCon, pWarn, eWarning);
|
|
}
|
|
}
|
|
free(pText);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
Now, after so many lines of code we are really ready to boogey: Parse
|
|
the scan command line, set variables, set the scan up and then actually
|
|
perform the scan.
|
|
--------------------------------------------------------------------------*/
|
|
int TASScan(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
pTASdata pTAS = (pTASdata) pData;
|
|
char pLine[1024], pToken[20], *pPtr, pWork[70];
|
|
int i, status, iPtr, iTas;
|
|
time_t iDate;
|
|
struct tm *psTime;
|
|
float ach;
|
|
|
|
/*
|
|
check authorization
|
|
*/
|
|
if (!SCMatchRights(pCon, usUser))
|
|
return 0;
|
|
|
|
if (pTAS->pScan->iActive) {
|
|
SCWrite(pCon, "ERROR: a scan is still running", eError);
|
|
return 0;
|
|
}
|
|
/*
|
|
check if we are a fast scan or a normal scan
|
|
*/
|
|
strtolower(argv[0]);
|
|
if (strcmp(argv[0], "sf") == 0) {
|
|
pTAS->iFast = 1;
|
|
} else {
|
|
pTAS->iFast = 0;
|
|
}
|
|
|
|
/* Initialize parsing */
|
|
Arg2Text(argc, argv, pLine, 1023);
|
|
strtolower(pLine);
|
|
|
|
/*
|
|
set command text for data file
|
|
*/
|
|
VarSetText(pTAS->tasPar[COM], pLine, usInternal);
|
|
|
|
|
|
/*
|
|
first pass: parse simple variables
|
|
*/
|
|
status = ParseVar(pTAS, pLine, pCon);
|
|
if (!status)
|
|
return status;
|
|
|
|
/*
|
|
clear out old scan
|
|
*/
|
|
ClearScanVar(pTAS->pScan);
|
|
pTAS->scanVar[0] = '\0';
|
|
|
|
|
|
/*
|
|
at this stage all simple variables have been set. Now we get the values
|
|
of some important inital values which we need for entering the scan
|
|
variables.
|
|
*/
|
|
pTAS->pScan->iNP = pTAS->tasPar[NP]->iVal;
|
|
pTAS->pScan->iMode = GetCounterMode(pTAS->pScan->pCounterData);
|
|
pTAS->pScan->fPreset = GetCounterPreset(pTAS->pScan->pCounterData);
|
|
pTAS->pScan->pCon = pCon;
|
|
pTAS->pScan->pSics = pSics;
|
|
|
|
/*
|
|
check for polarisation
|
|
*/
|
|
if (pTAS->tasPar[LPA]->iVal == 1) {
|
|
pTAS->iPOL = 1;
|
|
} else {
|
|
pTAS->iPOL = -1;
|
|
}
|
|
|
|
/*
|
|
now parse the scan variables
|
|
*/
|
|
iTas = 0;
|
|
status = ParseScanVar(pTAS, pLine, pCon, &iTas);
|
|
if (!status)
|
|
return status;
|
|
|
|
/*
|
|
check if there is something to scan
|
|
*/
|
|
if (pTAS->pScan->iScanVar < 1) {
|
|
SCWrite(pCon, "ERROR: nothing to scan", eError);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
now there is enough information to set the scaninfo variable which
|
|
is needed to help the status display.
|
|
*/
|
|
sprintf(pWork, "%d,%s", pTAS->pScan->iNP, pTAS->scanVar);
|
|
VarSetText(pTAS->tasPar[SINFO], pWork, 0);
|
|
|
|
/*
|
|
parse the output variable in order to get additional stuff to write
|
|
*/
|
|
ParseOutput(pTAS, pCon);
|
|
|
|
/*
|
|
print some status information for the looser
|
|
*/
|
|
iDate = time(NULL);
|
|
psTime = localtime(&iDate);
|
|
memset(pWork, 0, 69);
|
|
strftime(pWork, 69, "%d-%b-%Y %H:%M:%S", psTime);
|
|
snprintf(pLine, 1023, "%8s %3d Points Scan %3d Scanned Variable(s) %s",
|
|
pTAS->tasPar[INST]->text,
|
|
pTAS->pScan->iNP, pTAS->pScan->iScanVar, pWork);
|
|
SCWrite(pCon, pLine, eLog);
|
|
if (GetCounterMode(pTAS->pScan->pCounterData) == eTimer) {
|
|
sprintf(pLine, " %8f Seconds per point",
|
|
GetCounterPreset(pTAS->pScan->pCounterData));
|
|
} else {
|
|
sprintf(pLine, " %8f Monitor Counts per point",
|
|
GetCounterPreset(pTAS->pScan->pCounterData));
|
|
|
|
}
|
|
SCWrite(pCon, pLine, eLog);
|
|
SCWrite(pCon, " ", eWarning);
|
|
SCWrite(pCon, " ", eWarning);
|
|
sprintf(pLine,
|
|
" %12s %6s HKLE: %5.2f %5.2f %5.2f %8.4f %6.3f %6.3f %6.3f %6.3f",
|
|
pTAS->tasPar[TIT]->text,
|
|
pTAS->tasPar[USR]->text,
|
|
pTAS->tasPar[QH]->fVal -
|
|
(pTAS->pScan->iNP / 2) * pTAS->tasPar[DQH]->fVal,
|
|
pTAS->tasPar[QK]->fVal -
|
|
(pTAS->pScan->iNP / 2) * pTAS->tasPar[DQL]->fVal,
|
|
pTAS->tasPar[QL]->fVal -
|
|
(pTAS->pScan->iNP / 2) * pTAS->tasPar[DQK]->fVal,
|
|
pTAS->tasPar[EN]->fVal -
|
|
(pTAS->pScan->iNP / 2) * pTAS->tasPar[DEN]->fVal,
|
|
pTAS->tasPar[DQH]->fVal, pTAS->tasPar[DQK]->fVal,
|
|
pTAS->tasPar[DQL]->fVal, pTAS->tasPar[DEN]->fVal);
|
|
SCWrite(pCon, pLine, eLog);
|
|
if (iTas > 0) {
|
|
if (pTAS->tasPar[FX]->iVal == 1) {
|
|
sprintf(pLine, " Constant KI Scan: KI= %7.4f Angs-1; EI= %9.4f",
|
|
pTAS->tasPar[KI]->fVal, pTAS->tasPar[EI]->fVal);
|
|
} else {
|
|
sprintf(pLine, " Constant KF Scan: KF= %7.4f Angs-1; EF= %9.4f",
|
|
pTAS->tasPar[KF]->fVal, pTAS->tasPar[EF]->fVal);
|
|
}
|
|
SCWrite(pCon, pLine, eLog);
|
|
}
|
|
|
|
/*
|
|
check ACH
|
|
*/
|
|
ach = readDrivable("ach",pCon);
|
|
if(ach < .05) {
|
|
SCWrite(pCon,"WARNING: Analyser is flat",eWarning);
|
|
}
|
|
|
|
/*
|
|
set our scan functions
|
|
*/
|
|
SetTASScan(pTAS->pScan, pTAS);
|
|
|
|
|
|
/*
|
|
finally scan
|
|
*/
|
|
status = DoScan(pTAS->pScan,
|
|
pTAS->pScan->iNP,
|
|
pTAS->pScan->iMode, pTAS->pScan->fPreset, pSics, pCon);
|
|
|
|
/*
|
|
cleanup a little
|
|
*/
|
|
ResetScanFunctions(pTAS->pScan);
|
|
|
|
/*
|
|
print a message for Severian Gvassilja
|
|
*/
|
|
sprintf(pLine, "Scan finished, data saved to %s", pTAS->pScan->pFile);
|
|
SCWrite(pCon, pLine, eLog);
|
|
|
|
return status;
|
|
}
|