1643 lines
43 KiB
C
1643 lines
43 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)
|
|
{
|
|
strncpy(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;
|
|
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, f2, f3, f4;
|
|
|
|
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",eError);
|
|
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",eWarning);
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
strncpy(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);
|
|
|
|
/*
|
|
* 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,");
|
|
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,");
|
|
strncpy(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,");
|
|
strcat(pHeader," M1 M2 TIME CNTS M3 ");
|
|
/*
|
|
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,eWarning);
|
|
|
|
/*
|
|
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, 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",eError);
|
|
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);
|
|
cnts = GetCounts(self->pCounterData,self->pCon);
|
|
fVal = GetCountTime(self->pCounterData, self->pCon);
|
|
sprintf(pWork,"%8ld %8ld %9.2f %8ld %8ld ",m1,m2,fVal, cnts, m3);
|
|
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,eWarning);
|
|
}
|
|
}
|
|
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,eWarning);
|
|
|
|
/*
|
|
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,
|
|
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",
|
|
eError);
|
|
return 0;
|
|
}
|
|
pTAS->iPOL = 0;
|
|
while(fgets(buffer,131,fd) != NULL){
|
|
/*
|
|
ignore all errors here
|
|
*/
|
|
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);
|
|
eOld = GetStatus();
|
|
status = DoCount(self->pCounterData,fVal,self->pCon,0);
|
|
iRet = Wait4Success(GetExecutor());
|
|
if(iRet == DEVINT)
|
|
{
|
|
SCWrite(self->pCon,"Counting aborted due to Interrupt",eStatus);
|
|
status = 0;
|
|
}
|
|
else if(iRet == DEVERROR)
|
|
{
|
|
SCWrite(self->pCon,"Counting finished with Problems",eStatus);
|
|
status = 0;
|
|
}
|
|
else
|
|
{
|
|
status = 1;
|
|
}
|
|
SetStatus(eOld);
|
|
|
|
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;
|
|
|
|
/*
|
|
check authorization
|
|
*/
|
|
if(!SCMatchRights(pCon,usUser))
|
|
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,eWarning);
|
|
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,eWarning);
|
|
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,eWarning);
|
|
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,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,eWarning);
|
|
|
|
return status;
|
|
}
|