483 lines
11 KiB
C
483 lines
11 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 initialization part of the whole thing.
|
|
|
|
Mark Koennecke, November 2000
|
|
---------------------------------------------------------------------------*/
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <fortify.h>
|
|
#include <sics.h>
|
|
#include <sicsvar.h>
|
|
#include <counter.h>
|
|
#include <motor.h>
|
|
#include <scan.h>
|
|
#include <scan.i>
|
|
#include "tas.h"
|
|
#include "tasu.h"
|
|
|
|
extern int getSRO(SConnection * pCon, float *fVal); /* tasutil.c */
|
|
|
|
/*
|
|
As variables may be accessed in storage order, it is necessary to
|
|
know the order of the motors
|
|
*/
|
|
char *tasMotorOrder[MAXMOT + 1] = { "a1",
|
|
"a2",
|
|
"a3",
|
|
"a4",
|
|
"a5",
|
|
"a6",
|
|
"mcv",
|
|
"sro",
|
|
"ach",
|
|
"mtl",
|
|
"mtu",
|
|
"stl",
|
|
"stu",
|
|
"stl",
|
|
"atu",
|
|
"mgl",
|
|
"sgl",
|
|
"sgu",
|
|
"agl",
|
|
"atl",
|
|
"tt",
|
|
"i1",
|
|
"i2",
|
|
"i3",
|
|
"i4",
|
|
"hxx",
|
|
"hyy",
|
|
"hzz",
|
|
"i5",
|
|
"i6",
|
|
"i7",
|
|
"i8",
|
|
"mf",
|
|
"tem",
|
|
NULL
|
|
};
|
|
|
|
/*
|
|
In order to initialise the variable array in the TAS data structure we
|
|
need to know the names of the variables in the right order. This order
|
|
has to match the order defined in tas.h through the defines. Otherwise
|
|
quite weird things may happen at runtime.
|
|
*/
|
|
char *tasVariableOrder[MAXPAR + 1] = {
|
|
"wav",
|
|
"dm",
|
|
"da",
|
|
"etam",
|
|
"etaa",
|
|
"ti",
|
|
"mn",
|
|
"if1v",
|
|
"if1h",
|
|
"if2v",
|
|
"if2h",
|
|
"helm",
|
|
"as",
|
|
"bs",
|
|
"cs",
|
|
"aa",
|
|
"bb",
|
|
"cc",
|
|
"etas",
|
|
"ax",
|
|
"ay",
|
|
"az",
|
|
"bx",
|
|
"by",
|
|
"bz",
|
|
"ei",
|
|
"ki",
|
|
"ef",
|
|
"kf",
|
|
"qh",
|
|
"qk",
|
|
"ql",
|
|
"en",
|
|
"qm",
|
|
"hx",
|
|
"hy",
|
|
"hz",
|
|
"da1",
|
|
"da2",
|
|
"da3",
|
|
"da4",
|
|
"da5",
|
|
"da6",
|
|
"dmcv",
|
|
"dsro",
|
|
"dach",
|
|
"dmtl",
|
|
"dmtu",
|
|
"dstl",
|
|
"dstu",
|
|
"datl",
|
|
"datu",
|
|
"dmgl",
|
|
"dsgl",
|
|
"dsgu",
|
|
"dagl",
|
|
"dei",
|
|
"dki",
|
|
"def",
|
|
"dkf",
|
|
"dqh",
|
|
"dqk",
|
|
"dql",
|
|
"den",
|
|
"dqm",
|
|
"dtt",
|
|
"sm",
|
|
"ss",
|
|
"sa",
|
|
"fx",
|
|
"np",
|
|
"f1",
|
|
"f2",
|
|
"lpa",
|
|
"mrx1",
|
|
"mrx2",
|
|
"arx1",
|
|
"arx2",
|
|
"instrument",
|
|
"title",
|
|
"user",
|
|
"lastcommand",
|
|
"alf1",
|
|
"alf2",
|
|
"alf3",
|
|
"alf4",
|
|
"bet1",
|
|
"bet2",
|
|
"bet3",
|
|
"bet4",
|
|
"output",
|
|
"local",
|
|
"swunit",
|
|
"scaninfo",
|
|
"tei",
|
|
"tki",
|
|
"tef",
|
|
"tkf",
|
|
"tqh",
|
|
"tqk",
|
|
"tql",
|
|
"ten",
|
|
"tqm",
|
|
"ti1",
|
|
"ti2",
|
|
"ti3",
|
|
"ti4",
|
|
"ti5",
|
|
"ti6",
|
|
"ti7",
|
|
"ti8",
|
|
"di1",
|
|
"di2",
|
|
"di3",
|
|
"di4",
|
|
"di5",
|
|
"di6",
|
|
"di7",
|
|
"di8",
|
|
"dhx",
|
|
"dhy",
|
|
"dhz",
|
|
"thx",
|
|
"thy",
|
|
"thz",
|
|
"hconv1",
|
|
"hconv2",
|
|
"hconv3",
|
|
"hconv4",
|
|
"polfile",
|
|
"pix",
|
|
"piy",
|
|
"piz",
|
|
"pfx",
|
|
"pfy",
|
|
"pfz",
|
|
"dmf",
|
|
"dtem",
|
|
NULL
|
|
};
|
|
|
|
/*-------------------------------------------------------------------
|
|
Normally SICS does not store motor hardware limits into status files as
|
|
they are read from the motor controller. However, in order to better
|
|
synchronize simulation and instrument this has to be done for TASP.
|
|
TasSave does just that: saving hard limits in order for the simulation to
|
|
be able to read them.
|
|
------------------------------------------------------------------------*/
|
|
static int TasSaveStatus(void *self, char *name, FILE * fd)
|
|
{
|
|
int i = 0, iscat;
|
|
pMotor pMot;
|
|
float value;
|
|
SConnection *pCon = NULL;
|
|
pSicsVariable pScat = NULL;
|
|
|
|
pCon = SCCreateDummyConnection(pServ->pSics);
|
|
if (!pCon) {
|
|
return 0;
|
|
}
|
|
if (strcmp(name, "dr") != 0) { /* save only once (for dr, but not for sc,fs,updateqe) */
|
|
return 1;
|
|
}
|
|
while (tasMotorOrder[i] != NULL) {
|
|
pMot = FindMotor(pServ->pSics, tasMotorOrder[i]);
|
|
if (pMot) {
|
|
MotorGetPar(pMot, "hardupperlim", &value);
|
|
fprintf(fd, "catch {%s hardupperlim %f}\n", tasMotorOrder[i], value);
|
|
MotorGetPar(pMot, "hardlowerlim", &value);
|
|
fprintf(fd, "catch {%s hardlowerlim %f}\n", tasMotorOrder[i], value);
|
|
/*
|
|
DISABLED: reading all the motors made to much of a delay during
|
|
normal operation of the instrument. This is mainly due to the
|
|
sloooooooooowwwwwwwww SINQ hardware
|
|
MotorGetSoftPosition(pMot,pCon,&value);
|
|
fprintf(fd,"run %s %f\n",tasMotorOrder[i], value);
|
|
*/
|
|
|
|
}
|
|
i++;
|
|
}
|
|
pScat = (pSicsVariable)FindCommandData(pServ->pSics,"SS","SicsVariable");
|
|
if(pScat != NULL){
|
|
VarGetInt(pScat,&iscat);
|
|
fprintf(fd,"catch {scatfix ss %d}\n", iscat);
|
|
}
|
|
pScat = (pSicsVariable)FindCommandData(pServ->pSics,"SA","SicsVariable");
|
|
if(pScat != NULL){
|
|
VarGetInt(pScat,&iscat);
|
|
fprintf(fd,"catch {scatfix sa %d}\n", iscat);
|
|
}
|
|
|
|
SCDeleteConnection(pCon);
|
|
/*
|
|
fprintf(fd,"success\n");
|
|
*/
|
|
|
|
fprintf(fd, "updateqe\n");
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------
|
|
There is a special feauture in MAD where the count mode is determined
|
|
which variable, MN for monitor od TI for time has been set as the last
|
|
one. In order to implement this in SICS callback functions will be
|
|
used on the variables which switch the counter box into the appropriate
|
|
mode.
|
|
-----------------------------------------------------------------------*/
|
|
static int MonitorCallback(int iEvent, void *pEvent, void *pUser)
|
|
{
|
|
pTASdata self = (pTASdata) pUser;
|
|
assert(self);
|
|
|
|
if (iEvent != VALUECHANGE)
|
|
return 0;
|
|
|
|
SetCounterMode(self->pScan->pCounterData, ePreset);
|
|
SetCounterPreset(self->pScan->pCounterData,
|
|
(float) self->tasPar[MN]->iVal);
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------*/
|
|
static int TimerCallback(int iEvent, void *pEvent, void *pUser)
|
|
{
|
|
pTASdata self = (pTASdata) pUser;
|
|
assert(self);
|
|
|
|
if (iEvent != VALUECHANGE)
|
|
return 0;
|
|
|
|
SetCounterMode(self->pScan->pCounterData, eTimer);
|
|
SetCounterPreset(self->pScan->pCounterData, self->tasPar[TI]->fVal);
|
|
return 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------
|
|
This is an interpreter wrapper function which allows to call for the
|
|
recalculation of the energy variables from scripts.
|
|
--------------------------------------------------------------------------*/
|
|
extern int TASUpdate(pTASdata self, SConnection * pCon); /* tasutil.c */
|
|
|
|
static int RecalcAction(SConnection * pCon, SicsInterp * pSics,
|
|
void *pData, int argc, char *argv[])
|
|
{
|
|
pTASdata self = NULL;
|
|
|
|
assert(pCon);
|
|
assert(pSics);
|
|
self = (pTASdata) pData;
|
|
assert(self);
|
|
|
|
return TASUpdate(self, pCon);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
when A6 has been drive Bertrand wants to wait for some seconds in order
|
|
to allow for the analyzer shielding to settle down. This is done
|
|
through this callback function
|
|
---------------------------------------------------------------------------*/
|
|
static int A6WaitCallback(int iEvent, void *pEventData, void *pUserData)
|
|
{
|
|
if (iEvent == MOTEND) {
|
|
SicsWait(5);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------
|
|
A function for killing the TAS data structure is needed
|
|
-------------------------------------------------------------------------*/
|
|
static void TASKill(void *pData)
|
|
{
|
|
pTASdata self = (pTASdata) pData;
|
|
if (!self)
|
|
return;
|
|
|
|
if (self->pDes)
|
|
DeleteDescriptor(self->pDes);
|
|
free(self);
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
int TASFactory(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
pTASdata pNew = NULL;
|
|
int iPtr, iError;
|
|
char pBueffel[132];
|
|
pSicsVariable pVar = NULL;
|
|
CommandList *pCom = NULL;
|
|
pMotor pMot = NULL;
|
|
commandContext comCon;
|
|
|
|
/* check arguments */
|
|
if (argc < 2) {
|
|
SCWrite(pCon, "ERROR: insufficient paarameters to MakeTAS", eError);
|
|
return 0;
|
|
}
|
|
|
|
/* create a new data structure */
|
|
pNew = (pTASdata) malloc(sizeof(TASdata));
|
|
if (!pNew) {
|
|
SCWrite(pCon,
|
|
"ERROR: insufficient memory to allocate TAS data structure",
|
|
eError);
|
|
return 0;
|
|
}
|
|
memset(pNew, 0, sizeof(TASdata));
|
|
pNew->pDes = CreateDescriptor("TAS");
|
|
if (!pNew->pDes) {
|
|
SCWrite(pCon,
|
|
"ERROR: insufficient memory to allocate TAS data structure",
|
|
eError);
|
|
free(pNew);
|
|
return 0;
|
|
}
|
|
pNew->iPOL = -1;
|
|
pNew->pDes->SaveStatus = TasSaveStatus;
|
|
|
|
/* connect to all the variables */
|
|
iPtr = 0;
|
|
iError = 0;
|
|
while (tasVariableOrder[iPtr] != NULL) {
|
|
pNew->tasPar[iPtr] = FindVariable(pSics, tasVariableOrder[iPtr]);
|
|
if (!pNew->tasPar[iPtr]) {
|
|
sprintf(pBueffel, "ERROR: TAS variable %s not found",
|
|
tasVariableOrder[iPtr]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
iError++;
|
|
}
|
|
iPtr++;
|
|
}
|
|
if (iError != 0) {
|
|
SCWrite(pCon, "ERROR: TAS bad initialisation, TAS not created",
|
|
eError);
|
|
TASKill(pNew);
|
|
return 0;
|
|
}
|
|
|
|
/* connect to the scan object */
|
|
pCom = FindCommand(pSics, argv[1]);
|
|
if (!pCom) {
|
|
SCWrite(pCon, "ERROR: no scan routine for TAS found", eError);
|
|
TASKill(pNew);
|
|
return 0;
|
|
}
|
|
pNew->pScan = (pScanData) pCom->pData;
|
|
|
|
/*
|
|
Install the callbacks for TI and MN. Sloppy error checking because
|
|
the variables should have been accessed earlier on.
|
|
*/
|
|
pVar = FindVariable(pSics, "MN");
|
|
if (pVar) {
|
|
RegisterCallback(pVar->pCall, VALUECHANGE, MonitorCallback, pNew,
|
|
NULL);
|
|
}
|
|
pVar = FindVariable(pSics, "TI");
|
|
if (pVar) {
|
|
RegisterCallback(pVar->pCall, VALUECHANGE, TimerCallback, pNew, NULL);
|
|
}
|
|
|
|
/*
|
|
Install the wait callback for A6
|
|
*/
|
|
pMot = FindMotor(pSics, "a6");
|
|
if (pMot != NULL) {
|
|
RegisterCallback(pMot->pCall, MOTEND, A6WaitCallback, NULL, NULL);
|
|
}
|
|
|
|
|
|
/*
|
|
initialize SRO value
|
|
*/
|
|
getSRO(pCon, &pNew->oldSRO);
|
|
|
|
/* install TAS commands */
|
|
iError = AddCommand(pSics, "dr", TASDrive, TASKill, pNew);
|
|
if (!iError) {
|
|
SCWrite(pCon, "ERROR: duplicate dr command not created", eError);
|
|
TASKill(pNew);
|
|
return 0;
|
|
}
|
|
iError = AddCommand(pSics, "sc", TASScan, NULL, pNew);
|
|
if (!iError) {
|
|
SCWrite(pCon, "ERROR: duplicate sc command not created", eError);
|
|
TASKill(pNew);
|
|
return 0;
|
|
}
|
|
iError = AddCommand(pSics, "fs", TASScan, NULL, pNew);
|
|
if (!iError) {
|
|
SCWrite(pCon, "ERROR: duplicate sf command not created", eError);
|
|
TASKill(pNew);
|
|
return 0;
|
|
}
|
|
iError = AddCommand(pSics, "updateqe", RecalcAction, NULL, pNew);
|
|
if (!iError) {
|
|
SCWrite(pCon, "ERROR: duplicate updateqe command not created", eError);
|
|
TASKill(pNew);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|