- Added Pause and Continue commands - Fixed simulation counter to deal properly with pause - Fixed nxdict HDF5 problem SKIPPED: psi/makefile_alpha psi/nextrics.c psi/nxsans.c
855 lines
23 KiB
C
855 lines
23 KiB
C
/*--------------------------------------------------------------------------
|
|
|
|
S E L E C T O R
|
|
|
|
This is the implementation file for the the code necessary to deal
|
|
with an energy selector, monochromator. This is the Crystal
|
|
variety.
|
|
|
|
|
|
Mark Koennecke, January 1997
|
|
|
|
Copyright:
|
|
|
|
Labor fuer Neutronenstreuung
|
|
Paul Scherrer Institut
|
|
CH-5423 Villigen-PSI
|
|
|
|
|
|
The authors hereby grant permission to use, copy, modify, distribute,
|
|
and license this software and its documentation for any purpose, provided
|
|
that existing copyright notices are retained in all copies and that this
|
|
notice is included verbatim in any distributions. No written agreement,
|
|
license, or royalty fee is required for any of the authorized uses.
|
|
Modifications to this software may be copyrighted by their authors
|
|
and need not follow the licensing terms described here, provided that
|
|
the new terms are clearly indicated on the first page of each file where
|
|
they apply.
|
|
|
|
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
|
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
|
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
|
|
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
|
|
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
|
|
MODIFICATIONS.
|
|
----------------------------------------------------------------------------*/
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include "fortify.h"
|
|
#include "sics.h"
|
|
#include "motor.h"
|
|
#include "splitter.h"
|
|
#include "devexec.h"
|
|
#include "selector.h"
|
|
|
|
#define SS 0
|
|
#define B1C1 1
|
|
#define B1C2 2
|
|
#define B1MIN 3
|
|
#define B1MAX 4
|
|
#define B2C1 5
|
|
#define B2C2 6
|
|
#define B2MIN 7
|
|
#define B2MAX 8
|
|
#define LATD 9
|
|
#define RIGHTS 10
|
|
/*------------------------------------------------------------------------*/
|
|
typedef struct __SicsSelector {
|
|
ObjectDescriptor *pDes;
|
|
ObPar *pParams;
|
|
char *name;
|
|
pMotor pTheta;
|
|
pMotor pTwoTheta;
|
|
pMotor pBend1;
|
|
pMotor pBend2;
|
|
char *pType;
|
|
} SicsSelector;
|
|
/*-------------------------------------------------------------------------*/
|
|
char *MonoGetType(pSicsSelector self)
|
|
{
|
|
assert(self);
|
|
return self->pType;
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
pSicsSelector CreateSelector(char *name, pMotor pTheta, pMotor pTwoTheta,
|
|
pMotor pBend1, pMotor pBend2)
|
|
{
|
|
pSicsSelector pRes = NULL;
|
|
int iRet;
|
|
float fVal;
|
|
|
|
assert(pTheta);
|
|
assert(pTwoTheta);
|
|
|
|
/* allocate memory */
|
|
pRes = (pSicsSelector)malloc(sizeof(SicsSelector));
|
|
if(!pRes)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/* create ObjectDescriptor */
|
|
pRes->pDes = CreateDescriptor("CrystalSelector");
|
|
if(!pRes->pDes)
|
|
{
|
|
free(pRes);
|
|
return NULL;
|
|
}
|
|
|
|
/* create Parameter Array */
|
|
pRes->pParams = ObParCreate(11);
|
|
if(!pRes->pParams)
|
|
{
|
|
free(pRes->pDes);
|
|
free(pRes);
|
|
return NULL;
|
|
}
|
|
|
|
/* create all the parameters */
|
|
ObParInit(pRes->pParams,SS, "ss",1.,usUser);
|
|
ObParInit(pRes->pParams,B1C1, "vk1",1.,usInternal);
|
|
ObParInit(pRes->pParams,B1C2, "vk2",1.,usInternal);
|
|
ObParInit(pRes->pParams,B2C1, "hk1",1.,usInternal);
|
|
ObParInit(pRes->pParams,B2C2, "hk2",1.,usInternal);
|
|
ObParInit(pRes->pParams,LATD, "dd",2.087,usMugger);
|
|
ObParInit(pRes->pParams,RIGHTS, "access",usUser,usMugger);
|
|
|
|
/* assign motors */
|
|
pRes->pTheta = pTheta;
|
|
pRes->pTwoTheta = pTwoTheta;
|
|
|
|
/* provide default values for Bender Parameters in order to make
|
|
things look nice
|
|
*/
|
|
fVal = 0.;
|
|
ObParInit(pRes->pParams,B1MIN, "vmin",fVal,usInternal);
|
|
ObParInit(pRes->pParams,B1MAX, "vmax",fVal,usInternal);
|
|
ObParInit(pRes->pParams,B2MIN, "hmin",fVal,usInternal);
|
|
ObParInit(pRes->pParams,B2MAX, "hmax",fVal,usInternal);
|
|
|
|
|
|
/* handle benders, if present */
|
|
pRes->pBend1 = pBend1;
|
|
if(pBend1)
|
|
{
|
|
iRet = MotorGetPar(pBend1,"hardlowerlim",&fVal);
|
|
assert(iRet);
|
|
ObParInit(pRes->pParams,B1MIN, "vmin",fVal,usInternal);
|
|
iRet = MotorGetPar(pBend1,"hardupperlim",&fVal);
|
|
assert(iRet);
|
|
ObParInit(pRes->pParams,B1MAX, "vmax",fVal,usInternal);
|
|
}
|
|
pRes->pBend2 = pBend2;
|
|
if(pBend2)
|
|
{
|
|
iRet = MotorGetPar(pBend2,"hardlowerlim",&fVal);
|
|
assert(iRet);
|
|
ObParInit(pRes->pParams,B2MIN, "hmin",fVal,usInternal);
|
|
iRet = MotorGetPar(pBend2,"hardupperlim",&fVal);
|
|
assert(iRet);
|
|
ObParInit(pRes->pParams,B2MAX, "hmax",fVal,usInternal);
|
|
}
|
|
pRes->name = strdup(name);
|
|
pRes->pType = strdup("Unknown");
|
|
return pRes;
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
void DeleteSelector(void *self)
|
|
{
|
|
pSicsSelector pSelf;
|
|
|
|
assert(self);
|
|
|
|
pSelf = (pSicsSelector)self;
|
|
|
|
if(pSelf->pDes)
|
|
{
|
|
DeleteDescriptor(pSelf->pDes);
|
|
}
|
|
if(pSelf->pParams)
|
|
{
|
|
ObParDelete(pSelf->pParams);
|
|
}
|
|
if(pSelf->name)
|
|
{
|
|
free(pSelf->name);
|
|
}
|
|
if(pSelf->pType)
|
|
{
|
|
free(pSelf->pType);
|
|
}
|
|
free(pSelf);
|
|
}
|
|
/*--------------------------------------------------------------------------
|
|
Syntax:
|
|
MonoInit name Type ThetaMotor TwoThetaMotor Bend1Motor Bend2Motor
|
|
with Bend1Motor, Bend2Motor beeing optional.
|
|
*/
|
|
|
|
int MonoInit(SConnection *pCon, SicsInterp *pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
pSicsSelector pRes = NULL;
|
|
pMotor pTheta = NULL;
|
|
pMotor pTwoTheta = NULL;
|
|
pMotor pBend1 = NULL;
|
|
pMotor pBend2 = NULL;
|
|
TokenList *pList = NULL;
|
|
int iRet = 0;
|
|
TokenList *pCurrent;
|
|
char pBueffel[132];
|
|
char pName[132];
|
|
char *pType = NULL;
|
|
|
|
assert(pCon);
|
|
assert(pSics);
|
|
|
|
/* split arguments */
|
|
argtolower(argc,argv);
|
|
pList = SplitArguments(argc,argv);
|
|
if(!pList)
|
|
{
|
|
sprintf(pBueffel,"ERROR: parsing arguments in %s",argv[0]);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
return 0;
|
|
}
|
|
|
|
/* advance and search name */
|
|
pCurrent = pList->pNext;
|
|
if(!pCurrent)
|
|
{
|
|
sprintf(pBueffel,"ERRROR: Insufficient number of arguments to %s",
|
|
argv[0]);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
goto end;
|
|
}
|
|
strcpy(pName,pCurrent->text);
|
|
|
|
/* advance and find Type string */
|
|
pCurrent = pCurrent->pNext;
|
|
if(!pCurrent)
|
|
{
|
|
sprintf(pBueffel,"ERRROR: Insufficient number of arguments to %s",
|
|
argv[0]);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
goto end;
|
|
}
|
|
pType = pCurrent->text;
|
|
|
|
/* advance and find Theta motor */
|
|
pCurrent = pCurrent->pNext;
|
|
if(!pCurrent)
|
|
{
|
|
sprintf(pBueffel,"ERRROR: Insufficient number of arguments to %s",
|
|
argv[0]);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
goto end;
|
|
}
|
|
pTheta = FindMotor(pSics,pCurrent->text);
|
|
if(!pTheta)
|
|
{
|
|
sprintf(pBueffel,"ERROR: Cannot find motor %s for driving Theta",
|
|
pCurrent->text);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
goto end;
|
|
}
|
|
|
|
/* advance and find Two Theta motor */
|
|
pCurrent = pCurrent->pNext;
|
|
if(!pCurrent)
|
|
{
|
|
sprintf(pBueffel,"ERRROR: Insufficient number of arguments to %s",
|
|
argv[0]);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
goto end;
|
|
}
|
|
pTwoTheta = FindMotor(pSics,pCurrent->text);
|
|
if(!pTwoTheta)
|
|
{
|
|
sprintf(pBueffel,"ERROR: Cannot find motor %s for driving Two Theta",
|
|
pCurrent->text);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
goto end;
|
|
}
|
|
iRet = 1; /* we are now able to install a monochromator */
|
|
|
|
/* try find first bending motor */
|
|
pCurrent = pCurrent->pNext;
|
|
if(pCurrent)
|
|
{
|
|
pBend1 = FindMotor(pSics,pCurrent->text);
|
|
if(!pBend1)
|
|
{
|
|
sprintf(pBueffel,"ERROR: Cannot find motor %s for driving vertical bender",
|
|
pCurrent->text);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
goto end;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
goto end;
|
|
}
|
|
|
|
/* find second bender */
|
|
pCurrent = pCurrent->pNext;
|
|
if(pCurrent)
|
|
{
|
|
pBend2 = FindMotor(pSics,pCurrent->text);
|
|
if(!pBend2)
|
|
{
|
|
sprintf(pBueffel,"ERROR: Cannot find motor %s for driving horizontal bender",
|
|
pCurrent->text);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
end:
|
|
if(iRet)
|
|
{
|
|
pRes = CreateSelector(pName, pTheta, pTwoTheta,pBend1,pBend2);
|
|
if(!pRes)
|
|
{
|
|
iRet = 0;
|
|
}
|
|
else
|
|
{
|
|
if(pRes->pType)
|
|
{
|
|
free(pRes->pType);
|
|
}
|
|
pRes->pType = strdup(pType);
|
|
iRet = AddCommand(pSics, pName,MonoAction,DeleteSelector,(void *)pRes);
|
|
if(!iRet)
|
|
{
|
|
sprintf(pBueffel,"ERROR: duplicate command %s not created",argv[2]);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
DeleteTokenList(pList);
|
|
DeleteSelector((void *)pRes);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
DeleteTokenList(pList);
|
|
return iRet;
|
|
|
|
}
|
|
/*---------------------------------------------------------------------------
|
|
a private function used in MonoAction to print all relevant features of
|
|
the monochromator
|
|
*/
|
|
static void MonoList(pSicsSelector self, SConnection *pCon)
|
|
{
|
|
char pBueffel[512];
|
|
int i, iLen;
|
|
|
|
/* print known parameters */
|
|
iLen = ObParLength(self->pParams);
|
|
sprintf(pBueffel,"Parameter Listing for %s\n",self->name);
|
|
SCWrite(pCon,pBueffel,eStatus);
|
|
for(i = 0; i < iLen; i++)
|
|
{
|
|
sprintf(pBueffel,"%s.%s = %f\n",self->name,
|
|
self->pParams[i].name,self->pParams[i].fVal);
|
|
SCWrite(pCon,pBueffel,eStatus);
|
|
}
|
|
|
|
/* print motornames as well */
|
|
sprintf(pBueffel,"%s.ThetaMotor = %s\n",self->name,self->pTheta->name);
|
|
SCWrite(pCon,pBueffel,eStatus);
|
|
sprintf(pBueffel,"%s.TwoThetaMotor = %s\n",self->name,self->pTwoTheta->name);
|
|
SCWrite(pCon,pBueffel,eStatus);
|
|
if(self->pBend1)
|
|
{
|
|
sprintf(pBueffel,"%s.VerticalBenderMotor = %s\n",self->name,self->pBend1->name);
|
|
SCWrite(pCon,pBueffel,eStatus);
|
|
}
|
|
if(self->pBend2)
|
|
{
|
|
sprintf(pBueffel,"%s.HorizontalBenderMotor = %s\n",self->name,self->pBend2->name);
|
|
SCWrite(pCon,pBueffel,eStatus);
|
|
}
|
|
}
|
|
/*-----------------------------------------------------------------------------
|
|
The Action function. Syntax:
|
|
mononame list -- list all pars
|
|
mononame parname -- prints parameter
|
|
mononame parname value -- tries changing the parameter
|
|
*/
|
|
|
|
int MonoAction(SConnection *pCon, SicsInterp *pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
pSicsSelector pSelf = NULL;
|
|
TokenList *pList = NULL;
|
|
TokenList *pCurrent;
|
|
int iRet;
|
|
char pBueffel[132];
|
|
char pName[132];
|
|
float fVal;
|
|
ObPar *pPar = NULL;
|
|
|
|
assert(pCon);
|
|
assert(pSics);
|
|
assert(pData);
|
|
|
|
pSelf = (pSicsSelector)pData;
|
|
|
|
/* split arguments */
|
|
argtolower(argc,argv);
|
|
pList = SplitArguments(argc,argv);
|
|
if(!pList)
|
|
{
|
|
sprintf(pBueffel,"ERROR: parsing arguments in %s",argv[0]);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
return 0;
|
|
}
|
|
|
|
pCurrent = pList->pNext;
|
|
/* now we can have "list" or a parametername */
|
|
/* check for list first */
|
|
if(!pCurrent)
|
|
{
|
|
sprintf(pBueffel,"ERROR: Insufficient number of arguments to %s",
|
|
argv[0]);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
goto end;
|
|
}
|
|
if(strcmp(pCurrent->text,"list") == 0)
|
|
{
|
|
MonoList(pSelf,pCon);
|
|
iRet = 1;
|
|
goto end;
|
|
}
|
|
|
|
/* must be parametername now */
|
|
strcpy(pName,pCurrent->text);
|
|
|
|
/* find out if it is a set or a get. On set there is another paremeter,
|
|
else none
|
|
*/
|
|
pCurrent = pCurrent->pNext;
|
|
if(pCurrent) /* set */
|
|
{
|
|
/* check if input is proper */
|
|
if(pCurrent->Type == eFloat)
|
|
{
|
|
fVal = pCurrent->fVal;
|
|
}
|
|
else if(pCurrent->Type == eInt)
|
|
{
|
|
fVal = (float)pCurrent->iVal;
|
|
}
|
|
else
|
|
{
|
|
sprintf(pBueffel,"ERROR: Illegal parameter %s given to %s",
|
|
pCurrent->text, argv[0]);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
goto end;
|
|
}
|
|
iRet = ObParSet(pSelf->pParams,argv[0],pName,fVal,pCon);
|
|
goto end;
|
|
}
|
|
else /* get */
|
|
{
|
|
pPar = ObParFind(pSelf->pParams,pName);
|
|
if(!pPar)
|
|
{
|
|
sprintf(pBueffel,"ERROR: Parameter %s not found in %s",pName, argv[0]);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
goto end;
|
|
}
|
|
else
|
|
{
|
|
sprintf(pBueffel,"%s.%s = %f",argv[0],pName,pPar->fVal);
|
|
SCWrite(pCon,pBueffel,eValue);
|
|
iRet = 1;
|
|
DeleteTokenList(pList);
|
|
return 1;
|
|
}
|
|
}
|
|
end:
|
|
DeleteTokenList(pList);
|
|
if(iRet)
|
|
SCSendOK(pCon);
|
|
return iRet;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
struct SelPos {
|
|
float fTheta, fTwoTheta, fVert, fHor;
|
|
};
|
|
#define PI 3.14159265358979323846264338327950
|
|
#define RD 57.29577951308232087679815481410517
|
|
/* ------------------- C has no proper abs -------------------------------*/
|
|
static double absd(double f)
|
|
{
|
|
if(f < .0)
|
|
{
|
|
f = -f;
|
|
}
|
|
return f;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
static struct SelPos CalculatePosition(pSicsSelector self, float fWaveLength)
|
|
{
|
|
struct SelPos pRes;
|
|
double fD;
|
|
|
|
/* Theta, TwoTheta first */
|
|
fD = fWaveLength/(2.0* ObVal(self->pParams,LATD));
|
|
if(fD > 1.0)
|
|
{
|
|
pRes.fTheta = 1000.; /* error indication: energy to big */
|
|
return pRes;
|
|
}
|
|
fD = asin(fD);
|
|
pRes.fTheta = fD*ObVal(self->pParams,SS)*RD;
|
|
pRes.fTwoTheta = 2 * pRes.fTheta;
|
|
|
|
/* now first bender */
|
|
if(self->pBend1)
|
|
{
|
|
pRes.fVert = ObVal(self->pParams,B1C1)+(ObVal(self->pParams,B1C2)/
|
|
sin(fD));
|
|
}
|
|
|
|
|
|
/* now second bender */
|
|
if(self->pBend2)
|
|
{
|
|
pRes.fHor = ObVal(self->pParams,B2C1)+ (ObVal(self->pParams,B2C2)/
|
|
sin(fD));
|
|
}
|
|
return pRes;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
int MonoLimits(pSicsSelector self, float fWaveLength,
|
|
char *error, int iErrLen)
|
|
{
|
|
struct SelPos sNeu;
|
|
char pBueffel[132];
|
|
pIDrivable pDrivInt = NULL;
|
|
|
|
/* get Position */
|
|
sNeu = CalculatePosition(self,fWaveLength);
|
|
if(sNeu.fTheta > 900.) /* invalid wavelength or energy */
|
|
{
|
|
sprintf(pBueffel,"ERROR: Invalid wavelength or energy to high: %f",
|
|
fWaveLength);
|
|
strncpy(error,pBueffel,iErrLen-1);
|
|
return 0;
|
|
}
|
|
|
|
/* check each motor in turn */
|
|
pDrivInt = self->pTheta->pDescriptor->GetInterface(self->pTheta,DRIVEID);
|
|
if(!pDrivInt->CheckLimits(self->pTheta,sNeu.fTheta,error,iErrLen))
|
|
{
|
|
return 0;
|
|
}
|
|
pDrivInt = self->pTwoTheta->pDescriptor->GetInterface(self->pTwoTheta,
|
|
DRIVEID);
|
|
if(!pDrivInt->CheckLimits(self->pTwoTheta,sNeu.fTwoTheta,
|
|
error,iErrLen))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if(self->pBend1)
|
|
{
|
|
pDrivInt = self->pBend1->pDescriptor->GetInterface(self->pBend1,DRIVEID);
|
|
if(!pDrivInt->CheckLimits(self->pBend1,sNeu.fVert,
|
|
error,iErrLen))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
if(self->pBend2)
|
|
{
|
|
pDrivInt = self->pBend2->pDescriptor->GetInterface(self->pBend2,DRIVEID);
|
|
if(!pDrivInt->CheckLimits(self->pBend2,sNeu.fHor,
|
|
error,iErrLen))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
int MonoHalt(pSicsSelector self)
|
|
{
|
|
pIDrivable pDrivInt = NULL;
|
|
|
|
/* halt each motor in turn */
|
|
pDrivInt = self->pTheta->pDescriptor->GetInterface(self->pTheta,DRIVEID);
|
|
if(pDrivInt)
|
|
{
|
|
pDrivInt->Halt(self->pTheta);
|
|
}
|
|
|
|
pDrivInt = self->pTwoTheta->pDescriptor->GetInterface(self->pTwoTheta,
|
|
DRIVEID);
|
|
if(pDrivInt)
|
|
{
|
|
pDrivInt->Halt(self->pTwoTheta);
|
|
}
|
|
|
|
if(self->pBend1)
|
|
{
|
|
pDrivInt = self->pBend1->pDescriptor->GetInterface(self->pBend1,
|
|
DRIVEID);
|
|
if(pDrivInt)
|
|
{
|
|
pDrivInt->Halt(self->pBend1);
|
|
}
|
|
}
|
|
if(self->pBend2)
|
|
{
|
|
pDrivInt = self->pBend2->pDescriptor->GetInterface(self->pBend2,
|
|
DRIVEID);
|
|
if(pDrivInt)
|
|
{
|
|
pDrivInt->Halt(self->pBend2);
|
|
}
|
|
}
|
|
|
|
|
|
return 1;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
int MonoRun(pSicsSelector self, SConnection *pCon, float fWaveLength)
|
|
{
|
|
struct SelPos sNeu;
|
|
char pBueffel[132];
|
|
int iRet;
|
|
|
|
/* Check authorisation */
|
|
if(!SCMatchRights(pCon,(int)ObVal(self->pParams,RIGHTS)))
|
|
{
|
|
sprintf(pBueffel,
|
|
"ERROR: You are not authorised to move the monochromator %s",self->name);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
return 0;
|
|
}
|
|
|
|
/* get Position */
|
|
sNeu = CalculatePosition(self,fWaveLength);
|
|
if(sNeu.fTheta > 900.) /* invalid wavelength or energy */
|
|
{
|
|
sprintf(pBueffel,"ERROR: Invalid wavelength or energy to high: %f",
|
|
fWaveLength);
|
|
return 0;
|
|
}
|
|
|
|
/* start each motor in turn */
|
|
iRet = StartDevice(GetExecutor(),self->pTheta->name,
|
|
self->pTheta->pDescriptor,
|
|
self->pTheta,
|
|
pCon,sNeu.fTheta);
|
|
if(!iRet)
|
|
{
|
|
return 0;
|
|
}
|
|
iRet = StartDevice(GetExecutor(),self->pTwoTheta->name,
|
|
self->pTwoTheta->pDescriptor,
|
|
self->pTwoTheta,
|
|
pCon,sNeu.fTwoTheta);
|
|
if(!iRet)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* bending motors */
|
|
if(self->pBend1)
|
|
{
|
|
iRet = StartDevice(GetExecutor(),self->pBend1->name,
|
|
self->pBend1->pDescriptor,
|
|
self->pBend1,
|
|
pCon,sNeu.fVert);
|
|
if(!iRet)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
}
|
|
if(self->pBend2)
|
|
{
|
|
iRet = StartDevice(GetExecutor(),self->pBend2->name,
|
|
self->pBend2->pDescriptor,
|
|
self->pBend2,
|
|
pCon,sNeu.fHor);
|
|
if(!iRet)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
return OKOK;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
int MonoCheck(pSicsSelector self, SConnection *pCon)
|
|
{
|
|
int iRet;
|
|
pIDrivable pDrivInt = NULL;
|
|
|
|
/* cheack each motor in turn */
|
|
pDrivInt = self->pTheta->pDescriptor->GetInterface(self->pTheta,DRIVEID);
|
|
if(pDrivInt)
|
|
{
|
|
iRet = pDrivInt->CheckStatus(self->pTheta,pCon);
|
|
if( (iRet != OKOK) && (iRet != HWIdle))
|
|
{
|
|
return iRet;
|
|
}
|
|
}
|
|
|
|
pDrivInt = self->pTwoTheta->pDescriptor->GetInterface(self->pTwoTheta,
|
|
DRIVEID);
|
|
if(pDrivInt)
|
|
{
|
|
iRet = pDrivInt->CheckStatus(self->pTwoTheta,pCon);
|
|
if( (iRet != OKOK) && (iRet != HWIdle))
|
|
{
|
|
return iRet;
|
|
}
|
|
}
|
|
|
|
if(self->pBend1)
|
|
{
|
|
pDrivInt = self->pBend1->pDescriptor->GetInterface(self->pBend1,
|
|
DRIVEID);
|
|
if(pDrivInt)
|
|
{
|
|
iRet = pDrivInt->CheckStatus(self->pBend1,pCon);
|
|
if( (iRet != OKOK) && (iRet != HWIdle))
|
|
{
|
|
return iRet;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(self->pBend2)
|
|
{
|
|
pDrivInt = self->pBend2->pDescriptor->GetInterface(self->pBend2,
|
|
DRIVEID);
|
|
if(pDrivInt)
|
|
{
|
|
iRet = pDrivInt->CheckStatus(self->pBend2,pCon);
|
|
if( (iRet != OKOK) && (iRet != HWIdle))
|
|
{
|
|
return iRet;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return HWIdle;
|
|
}
|
|
/*--------------------------------------------------------------------------
|
|
returns the current Wavelength the monochromator is adjusted to
|
|
*/
|
|
float GetMonoPosition(pSicsSelector self, SConnection *pCon)
|
|
{
|
|
double fVal, dTheta;
|
|
float fTheta, fTwoTheta;
|
|
char pBueffel[132];
|
|
int iRet;
|
|
|
|
/* get the two positions */
|
|
iRet = MotorGetSoftPosition(self->pTheta,pCon,&fTheta);
|
|
if(!iRet)
|
|
{
|
|
sprintf(pBueffel,"ERROR: cannot read Theta motor for monochromator %s\n",
|
|
self->name);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
return 0.;
|
|
}
|
|
iRet = MotorGetSoftPosition(self->pTwoTheta,pCon,&fTwoTheta);
|
|
if(!iRet)
|
|
{
|
|
sprintf(pBueffel,
|
|
"ERROR: cannot read TwoTheta motor for monochromator %s\n",
|
|
self->name);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
return 0.;
|
|
}
|
|
|
|
/* check for sync */
|
|
fVal = fTwoTheta - 2* fTheta;
|
|
if(fVal < 0.)fVal = -fVal;
|
|
if(fVal > 0.01)
|
|
{
|
|
sprintf(pBueffel,"WARNING: monochromator %s out of sync by %f\n",
|
|
self->name,fVal);
|
|
SCWrite(pCon,pBueffel,eStatus);
|
|
}
|
|
|
|
/* calculate wavelength from angles */
|
|
dTheta =(double)fTheta;
|
|
dTheta = dTheta *(1.0/RD);
|
|
fVal = 2.0 * (double)ObVal(self->pParams,LATD);
|
|
fVal = fVal * sin(dTheta) * ObVal(self->pParams,SS);
|
|
return fVal;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
int GetMonoPositions(pSicsSelector self, SConnection *pCon,
|
|
float *fTh, float *f2TH, float *fB1, float *fB2)
|
|
{
|
|
int iRet;
|
|
char pBueffel[512];
|
|
|
|
iRet = MotorGetSoftPosition(self->pTheta,pCon,fTh);
|
|
if(!iRet)
|
|
{
|
|
sprintf(pBueffel,"ERROR: cannot read Theta motor for monochromator %s\n",
|
|
self->name);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
return 0.;
|
|
}
|
|
iRet = MotorGetSoftPosition(self->pTwoTheta,pCon,f2TH);
|
|
if(!iRet)
|
|
{
|
|
sprintf(pBueffel,
|
|
"ERROR: cannot read TwoTheta motor for monochromator %s\n",
|
|
self->name);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
return 0.;
|
|
}
|
|
|
|
if(self->pBend1)
|
|
{
|
|
iRet = MotorGetSoftPosition(self->pBend1,pCon,fB1);
|
|
if(!iRet)
|
|
{
|
|
sprintf(pBueffel,
|
|
"ERROR: cannot read vertical bender motor for monochromator %s\n",
|
|
self->name);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
return 0.;
|
|
}
|
|
}
|
|
if(self->pBend2)
|
|
{
|
|
iRet = MotorGetSoftPosition(self->pBend2,pCon,fB2);
|
|
if(!iRet)
|
|
{
|
|
sprintf(pBueffel,
|
|
"ERROR: cannot read horizontal bender motor for monochromator %s\n",
|
|
self->name);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
return 0.;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|