963 lines
29 KiB
C
963 lines
29 KiB
C
/*---------------------------------------------------------------------------
|
|
A M O R 2 T
|
|
|
|
A class for controlling the two theta movement of the reflectometer
|
|
AMOR at SINQ. It is not clear if this class may be useful for other
|
|
reflectometers, too. At AMOR the two theta movement of the detector is
|
|
realized by translating the detector along x and z. Also it can be
|
|
tilted in omega. Furthermore the height of two diaphragms has to be
|
|
adjusted when moving two theta as well. In polarizing mode the analyzer
|
|
mirror has to be moved as well.
|
|
|
|
copyright: see copyright.h
|
|
|
|
Mark Koennecke, September 1999
|
|
|
|
Bugs fixed, analyzer included for A2T. Then there is a second thing:
|
|
aoz2t which allows to scan the analyzer in two-theta during alignment
|
|
of the instrument. As all the parameters are already held in the a2t
|
|
structures this extra was added into this module.
|
|
|
|
Mark Koennecke, May-June 2000
|
|
|
|
Introduced DIAFLAG to switch off diaphragm calculation.
|
|
|
|
Mark Koennecke, July 2005
|
|
---------------------------------------------------------------------------*/
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <math.h>
|
|
#include "fortify.h"
|
|
#include <tcl.h>
|
|
#include "sics.h"
|
|
#include "motor.h"
|
|
#include "obpar.h"
|
|
|
|
#define DEBUG 1
|
|
|
|
#define MAXMOT 13
|
|
#define MAXPAR 14
|
|
|
|
#include "amor2t.i"
|
|
#include "amor2t.h"
|
|
|
|
/*
|
|
Defines for accessing various motors and variables. Definition of motor: see
|
|
annotated AMOR drawing.
|
|
*/
|
|
|
|
/* monochromator omega */
|
|
#define MOTMOM 0
|
|
/* sample omega */
|
|
#define MOTSOM 1
|
|
/* detector height movement */
|
|
#define MOTCOZ 2
|
|
/* detector movement along main axis */
|
|
#define MOTCOX 3
|
|
/* sample holder height movement */
|
|
#define MOTSTZ 4
|
|
/* whole sample table height movement */
|
|
#define MOTSOZ 5
|
|
/* lift for diaphragm 4*/
|
|
#define MOTD4B 6
|
|
/* lift for diaphragm 5 */
|
|
#define MOTD5B 7
|
|
/* detector omega movement */
|
|
#define MOTCOM 8
|
|
/* lift for analyzer */
|
|
#define MOTAOZ 9
|
|
/* analyzer omega */
|
|
#define MOTAOM 10
|
|
/* detector 2 movement */
|
|
#define MOTC3Z 11
|
|
|
|
|
|
/*======================================================================
|
|
The core of it all: The calculation of the settings for the various
|
|
motors.
|
|
========================================================================*/
|
|
static void clearRunFlags(pAmor2T self)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAXMOT; i++) {
|
|
self->toStart[i].pMot = NULL;
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------*/
|
|
static int CalculateAMORE(pAmor2T self, SConnection * pCon, float fNew)
|
|
{
|
|
float fMOM, fSOM, fSTZ, fSOZ, fAOM, fAOZ, fC3Z, fconstAOM;
|
|
double fAngle, fX, fZ, fZ2, fBase, fPIR;
|
|
float fCOZ, fCOX, fCOM;
|
|
int iRet;
|
|
#ifdef DEBUG
|
|
char pBueffel[132];
|
|
#endif
|
|
|
|
/* get the necessary angles first */
|
|
iRet = MotorGetSoftPosition(self->aEngine[MOTMOM], pCon, &fMOM);
|
|
if (iRet != 1) {
|
|
return iRet;
|
|
}
|
|
iRet = MotorGetSoftPosition(self->aEngine[MOTSOM], pCon, &fSOM);
|
|
if (iRet != 1) {
|
|
return iRet;
|
|
}
|
|
iRet = MotorGetSoftPosition(self->aEngine[MOTSTZ], pCon, &fSTZ);
|
|
if (iRet != 1) {
|
|
return iRet;
|
|
}
|
|
iRet = MotorGetSoftPosition(self->aEngine[MOTSOZ], pCon, &fSOZ);
|
|
if (iRet != 1) {
|
|
return iRet;
|
|
}
|
|
|
|
/* calculate base height of sample table */
|
|
fBase = fSOZ + ObVal(self->aParameter, PARDH);
|
|
fPIR = 180. / 3.1415926;
|
|
|
|
clearRunFlags(self);
|
|
|
|
/* calculation for detector */
|
|
fAngle = fNew - 2 * fMOM;
|
|
if (fAngle < 0) {
|
|
fAngle = fAngle + 360.;
|
|
}
|
|
fAngle /= fPIR;
|
|
fX = ObVal(self->aParameter, PARDS) * cos(fAngle);
|
|
fZ = ObVal(self->aParameter, PARDS) * sin(fAngle);
|
|
self->toStart[0].pMot = self->aEngine[MOTCOX];
|
|
strcpy(self->toStart[0].pName, self->aEngine[MOTCOX]->name);
|
|
self->toStart[0].fTarget = fX - ObVal(self->aParameter, PARDS);
|
|
self->toStart[1].pMot = self->aEngine[MOTCOZ];
|
|
strcpy(self->toStart[1].pName, self->aEngine[MOTCOZ]->name);
|
|
self->toStart[1].fTarget = fZ + fBase - ObVal(self->aParameter, PARDDH);
|
|
self->toStart[2].pMot = self->aEngine[MOTCOM];
|
|
strcpy(self->toStart[2].pName, self->aEngine[MOTCOM]->name);
|
|
self->toStart[2].fTarget = fNew - 2 * fMOM;
|
|
|
|
if (ObVal(self->aParameter, DIAFLAG) > .0) {
|
|
/* calculation for diaphragm 4 */
|
|
fZ = ObVal(self->aParameter, PARDD4) * sin(fAngle);
|
|
self->toStart[3].pMot = self->aEngine[MOTD4B];
|
|
strcpy(self->toStart[3].pName, self->aEngine[MOTD4B]->name);
|
|
self->toStart[3].fTarget = fBase + fZ -
|
|
ObVal(self->aParameter, PARD4H);
|
|
|
|
/* calculation for diaphragm 5 */
|
|
fZ = ObVal(self->aParameter, PARDD5) * sin(fAngle);
|
|
self->toStart[4].pMot = self->aEngine[MOTD5B];
|
|
strcpy(self->toStart[4].pName, self->aEngine[MOTD5B]->name);
|
|
self->toStart[4].fTarget = fBase + fZ -
|
|
ObVal(self->aParameter, PARD5H);
|
|
#ifdef DEBUG
|
|
sprintf(pBueffel, "2T COZ COX COM D4B D5B ");
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
sprintf(pBueffel, "%6.2f %6.2f %6.2f %6.2f %6.2f %6.2f",
|
|
fNew, self->toStart[1].fTarget, self->toStart[0].fTarget,
|
|
self->toStart[2].fTarget, self->toStart[3].fTarget,
|
|
self->toStart[4].fTarget);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
#endif
|
|
}
|
|
|
|
if (ObVal(self->aParameter, ANAFLAG) > 0) {
|
|
/* the analyzer height */
|
|
fZ = ObVal(self->aParameter, PARADIS) * sin(fAngle);
|
|
fAOZ = fBase + fZ - ObVal(self->aParameter, PARANA);
|
|
self->toStart[5].pMot = self->aEngine[MOTAOZ];
|
|
strcpy(self->toStart[5].pName, self->aEngine[MOTAOZ]->name);
|
|
self->toStart[5].fTarget = fAOZ;
|
|
|
|
/* analyzer omega */
|
|
self->toStart[6].pMot = self->aEngine[MOTAOM];
|
|
strcpy(self->toStart[6].pName, self->aEngine[MOTAOM]->name);
|
|
self->toStart[6].fTarget = fNew / 2. + ObVal(self->aParameter, PARAOM);
|
|
|
|
/* C3Z */
|
|
fZ2 = (ObVal(self->aParameter, PARDS) - ObVal(self->aParameter,
|
|
PARADIS)) * sin(fAngle +
|
|
(fNew /
|
|
fPIR));
|
|
|
|
self->toStart[7].pMot = self->aEngine[MOTC3Z];
|
|
strcpy(self->toStart[7].pName, self->aEngine[MOTC3Z]->name);
|
|
self->toStart[7].fTarget = fBase + fZ + fZ2 -
|
|
ObVal(self->aParameter, PARDDD) - self->toStart[1].fTarget;
|
|
#ifdef DEBUG
|
|
sprintf(pBueffel, "2T AOZ AOM C3Z");
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
sprintf(pBueffel, "%6.2f %6.2f %6.2f %6.2f",
|
|
fNew, self->toStart[5].fTarget, self->toStart[6].fTarget,
|
|
self->toStart[7].fTarget);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
#endif
|
|
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*=======================================================================
|
|
Calculations for Analyzer two theta
|
|
=========================================================================*/
|
|
static int CalculateANA2T(pAmor2T self, SConnection * pCon, float fNew)
|
|
{
|
|
double fBase, fPIR;
|
|
float fAOZ, fIncident, fSOM, fMOM, fDiffracted, fDistance, fX, fZ;
|
|
int iRet;
|
|
#ifdef DEBUG
|
|
char pBueffel[132];
|
|
#endif
|
|
|
|
/* calculate base height of analyzer table */
|
|
iRet = MotorGetSoftPosition(self->aEngine[MOTSOZ], pCon, &fAOZ);
|
|
if (iRet != 1) {
|
|
return iRet;
|
|
}
|
|
fBase = fAOZ + ObVal(self->aParameter, PARANA);
|
|
fPIR = 180. / 3.1415926;
|
|
|
|
/* Calculate the incident angle at the analyzer */
|
|
iRet = MotorGetSoftPosition(self->aEngine[MOTSOM], pCon, &fSOM);
|
|
if (iRet != 1) {
|
|
return iRet;
|
|
}
|
|
iRet = MotorGetSoftPosition(self->aEngine[MOTMOM], pCon, &fMOM);
|
|
if (iRet != 1) {
|
|
return iRet;
|
|
}
|
|
fIncident = fMOM + 2. * fSOM;
|
|
|
|
/* calculate the angle of the diffracted beam against the
|
|
horizon at the analyzer.
|
|
|
|
fDiffracted = fIncident - 2. * AOM.
|
|
|
|
There is a problem here. We should read AOM in order to get the
|
|
value. However in the context of an omega - two-theta scan on AOM
|
|
and ana2t, it is fNew.
|
|
*/
|
|
fDiffracted = fIncident - fNew;
|
|
|
|
clearRunFlags(self);
|
|
|
|
/* calculation for detector */
|
|
fDiffracted /= fPIR;
|
|
fDistance = ObVal(self->aParameter, PARDS) -
|
|
ObVal(self->aParameter, PARANA);
|
|
fX = fDistance * cos(fDiffracted);
|
|
fZ = fDistance * sin(fDiffracted);
|
|
self->toStart[0].pMot = self->aEngine[MOTCOX];
|
|
strcpy(self->toStart[0].pName, self->aEngine[MOTCOX]->name);
|
|
self->toStart[0].fTarget = fX - fDistance;
|
|
|
|
self->toStart[1].pMot = self->aEngine[MOTCOZ];
|
|
strcpy(self->toStart[1].pName, self->aEngine[MOTCOZ]->name);
|
|
self->toStart[1].fTarget = fZ + fBase - ObVal(self->aParameter, PARDDH);
|
|
|
|
self->toStart[2].pMot = self->aEngine[MOTCOM];
|
|
strcpy(self->toStart[2].pName, self->aEngine[MOTCOM]->name);
|
|
self->toStart[2].fTarget = -fDiffracted * fPIR;
|
|
|
|
/* calculation for diaphragm 5 */
|
|
if (ObVal(self->aParameter, DIAFLAG) > .0) {
|
|
fZ = ObVal(self->aParameter, PARDD5) * sin(fDiffracted);
|
|
self->toStart[3].pMot = self->aEngine[MOTD5B];
|
|
strcpy(self->toStart[3].pName, self->aEngine[MOTD5B]->name);
|
|
self->toStart[3].fTarget = fBase + fZ -
|
|
ObVal(self->aParameter, PARD5H);
|
|
}
|
|
#ifdef DEBUG
|
|
sprintf(pBueffel, "2T COX COZ COM D5B ");
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
sprintf(pBueffel, "%6.2f %6.2f %6.2f %6.2f %6.2f ",
|
|
fNew, self->toStart[0].fTarget, self->toStart[1].fTarget,
|
|
self->toStart[2].fTarget, self->toStart[3].fTarget);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
#endif
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*========================================================================
|
|
Definition of interface functions.
|
|
=========================================================================*/
|
|
static long A2TSetValue(void *pData, SConnection * pCon, float fNew)
|
|
{
|
|
int i, iRet;
|
|
pIDrivable pDriv = NULL;
|
|
pAmor2T self = (pAmor2T) pData;
|
|
|
|
assert(self);
|
|
|
|
/* calculation */
|
|
iRet = CalculateAMORE(self, pCon, fNew);
|
|
if (iRet != 1) {
|
|
return iRet;
|
|
}
|
|
|
|
/* start them all */
|
|
for (i = 0; i < MAXMOT; i++) {
|
|
if (self->toStart[i].pMot == NULL) {
|
|
continue;
|
|
}
|
|
pDriv =
|
|
self->toStart[i].pMot->pDescriptor->GetInterface(self->toStart[i].
|
|
pMot, DRIVEID);
|
|
if (pDriv != NULL) {
|
|
iRet = pDriv->SetValue(self->toStart[i].pMot, pCon,
|
|
self->toStart[i].fTarget);
|
|
if (iRet != OKOK) {
|
|
return iRet;
|
|
}
|
|
}
|
|
}
|
|
return OKOK;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
static long ANA2TSetValue(void *pData, SConnection * pCon, float fNew)
|
|
{
|
|
int i, iRet;
|
|
pIDrivable pDriv = NULL;
|
|
pAmor2T self = (pAmor2T) pData;
|
|
|
|
assert(self);
|
|
|
|
/* calculation */
|
|
iRet = CalculateANA2T(self, pCon, fNew);
|
|
if (iRet != 1) {
|
|
return iRet;
|
|
}
|
|
|
|
/* start them all */
|
|
for (i = 0; i < MAXMOT; i++) {
|
|
if (self->toStart[i].pMot == NULL) {
|
|
continue;
|
|
}
|
|
pDriv =
|
|
self->toStart[i].pMot->pDescriptor->GetInterface(self->toStart[i].
|
|
pMot, DRIVEID);
|
|
if (pDriv != NULL) {
|
|
iRet = pDriv->SetValue(self->toStart[i].pMot, pCon,
|
|
self->toStart[i].fTarget);
|
|
if (iRet != OKOK) {
|
|
return iRet;
|
|
}
|
|
}
|
|
}
|
|
return OKOK;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int A2THalt(void *pData)
|
|
{
|
|
int i, iRet;
|
|
pIDrivable pDriv = NULL;
|
|
pAmor2T self = (pAmor2T) pData;
|
|
|
|
assert(self);
|
|
|
|
/* stop them all */
|
|
for (i = 0; i < MAXMOT; i++) {
|
|
if (self->toStart[i].pMot == NULL) {
|
|
continue;
|
|
}
|
|
pDriv =
|
|
self->toStart[i].pMot->pDescriptor->GetInterface(self->toStart[i].
|
|
pMot, DRIVEID);
|
|
if (pDriv != NULL) {
|
|
iRet = pDriv->Halt(self->toStart[i].pMot);
|
|
}
|
|
}
|
|
return OKOK;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
static int A2TCheck(void *pData, float fNew, char *error, int iErrLen)
|
|
{
|
|
int i, iRet;
|
|
pIDrivable pDriv = NULL;
|
|
pAmor2T self = (pAmor2T) pData;
|
|
SConnection *pDumCon = NULL;
|
|
|
|
|
|
assert(self);
|
|
pDumCon = SCCreateDummyConnection(pServ->pSics);
|
|
assert(pDumCon);
|
|
|
|
/* calculation */
|
|
iRet = CalculateAMORE(self, pDumCon, fNew);
|
|
SCDeleteConnection(pDumCon);
|
|
if (iRet != 1) {
|
|
return iRet;
|
|
}
|
|
|
|
/* check them all */
|
|
for (i = 0; i < MAXMOT; i++) {
|
|
if (self->toStart[i].pMot == NULL) {
|
|
continue;
|
|
}
|
|
pDriv =
|
|
self->toStart[i].pMot->pDescriptor->GetInterface(self->toStart[i].
|
|
pMot, DRIVEID);
|
|
if (pDriv != NULL) {
|
|
iRet = pDriv->CheckLimits(self->toStart[i].pMot,
|
|
self->toStart[i].fTarget, error, iErrLen);
|
|
if (iRet != 1) {
|
|
return iRet;
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
static int ANA2TCheck(void *pData, float fNew, char *error, int iErrLen)
|
|
{
|
|
int i, iRet;
|
|
pIDrivable pDriv = NULL;
|
|
pAmor2T self = (pAmor2T) pData;
|
|
SConnection *pDumCon = NULL;
|
|
|
|
|
|
assert(self);
|
|
pDumCon = SCCreateDummyConnection(pServ->pSics);
|
|
assert(pDumCon);
|
|
|
|
/* calculation */
|
|
iRet = CalculateANA2T(self, pDumCon, fNew);
|
|
SCDeleteConnection(pDumCon);
|
|
if (iRet != 1) {
|
|
return iRet;
|
|
}
|
|
|
|
/* check them all */
|
|
for (i = 0; i < MAXMOT; i++) {
|
|
if (self->toStart[i].pMot == NULL) {
|
|
continue;
|
|
}
|
|
pDriv =
|
|
self->toStart[i].pMot->pDescriptor->GetInterface(self->toStart[i].
|
|
pMot, DRIVEID);
|
|
if (pDriv != NULL) {
|
|
iRet = pDriv->CheckLimits(self->toStart[i].pMot,
|
|
self->toStart[i].fTarget, error, iErrLen);
|
|
if (iRet != 1) {
|
|
return iRet;
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
static int A2TStatus(void *pData, SConnection * pCon)
|
|
{
|
|
int i, iRet;
|
|
pIDrivable pDriv = NULL;
|
|
pAmor2T self = (pAmor2T) pData;
|
|
|
|
assert(self);
|
|
|
|
/* check them all */
|
|
for (i = 0; i < MAXMOT; i++) {
|
|
if (self->toStart[i].pMot == NULL) {
|
|
continue;
|
|
}
|
|
pDriv =
|
|
self->toStart[i].pMot->pDescriptor->GetInterface(self->toStart[i].
|
|
pMot, DRIVEID);
|
|
if (pDriv != NULL) {
|
|
iRet = pDriv->CheckStatus(self->toStart[i].pMot, pCon);
|
|
if ((iRet != OKOK) && (iRet != HWIdle)) {
|
|
return iRet;
|
|
}
|
|
}
|
|
}
|
|
return iRet;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
static float A2TGetValue(void *pData, SConnection * pCon)
|
|
{
|
|
float fVal, fMOM, fResult;
|
|
int iRet;
|
|
pAmor2T self = (pAmor2T) pData;
|
|
|
|
assert(self);
|
|
|
|
/* get COM */
|
|
iRet = MotorGetSoftPosition(self->aEngine[MOTCOM], pCon, &fVal);
|
|
if (!iRet) {
|
|
return -9999.99;
|
|
}
|
|
/* get MOM */
|
|
iRet = MotorGetSoftPosition(self->aEngine[MOTMOM], pCon, &fMOM);
|
|
if (!iRet) {
|
|
return -9999.99;
|
|
}
|
|
|
|
/* retrocalculate 2 theta */
|
|
fResult = fVal + 2 * fMOM;
|
|
return fResult;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
static float ANA2TGetValue(void *pData, SConnection * pCon)
|
|
{
|
|
float fVal, fMOM, fResult;
|
|
int iRet;
|
|
pAmor2T self = (pAmor2T) pData;
|
|
|
|
assert(self);
|
|
|
|
/* get AOM */
|
|
iRet = MotorGetSoftPosition(self->aEngine[MOTAOM], pCon, &fVal);
|
|
if (!iRet) {
|
|
return -9999.99;
|
|
}
|
|
|
|
return 2. * fVal;
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
static void *A2TGetInterface(void *pData, int iID)
|
|
{
|
|
pAmor2T self = (pAmor2T) pData;
|
|
|
|
assert(self);
|
|
if (iID == DRIVEID) {
|
|
return self->pDriv;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
static int A2TSave(void *pData, char *name, FILE * fd)
|
|
{
|
|
int i;
|
|
pAmor2T self = (pAmor2T) pData;
|
|
|
|
assert(self);
|
|
|
|
fprintf(fd, "%s detectord %f \n", name, ObVal(self->aParameter, PARDS));
|
|
fprintf(fd, "%s sampleh %f \n", name, ObVal(self->aParameter, PARDH));
|
|
fprintf(fd, "%s d4d %f \n", name, ObVal(self->aParameter, PARDD4));
|
|
fprintf(fd, "%s d5d %f \n", name, ObVal(self->aParameter, PARDD5));
|
|
fprintf(fd, "%s interrupt %f \n", name, ObVal(self->aParameter, PARINT));
|
|
fprintf(fd, "%s detectorh %f \n", name, ObVal(self->aParameter, PARDDH));
|
|
fprintf(fd, "%s d4h %f \n", name, ObVal(self->aParameter, PARD4H));
|
|
fprintf(fd, "%s d5h %f \n", name, ObVal(self->aParameter, PARD5H));
|
|
fprintf(fd, "%s anah %f \n", name, ObVal(self->aParameter, PARANA));
|
|
fprintf(fd, "%s anad %f \n", name, ObVal(self->aParameter, PARADIS));
|
|
fprintf(fd, "%s anaflag %f \n", name, ObVal(self->aParameter, ANAFLAG));
|
|
fprintf(fd, "%s c2h %f \n", name, ObVal(self->aParameter, PARDDD));
|
|
fprintf(fd, "%s aomconst %f \n", name, ObVal(self->aParameter, PARAOM));
|
|
fprintf(fd, "%s diaflag %f \n", name, ObVal(self->aParameter, DIAFLAG));
|
|
return 1;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
static void A2TList(pAmor2T self, SConnection * pCon, char *name)
|
|
{
|
|
char pBueffel[132];
|
|
Tcl_DString tString;
|
|
|
|
assert(pCon);
|
|
assert(self);
|
|
|
|
Tcl_DStringInit(&tString);
|
|
sprintf(pBueffel,
|
|
"%s.detectord %f \n", name, ObVal(self->aParameter, PARDS));
|
|
Tcl_DStringAppend(&tString, pBueffel, -1);
|
|
sprintf(pBueffel,
|
|
"%s.sampleh %f \n", name, ObVal(self->aParameter, PARDH));
|
|
Tcl_DStringAppend(&tString, pBueffel, -1);
|
|
sprintf(pBueffel, "%s.d4d %f \n", name, ObVal(self->aParameter, PARDD4));
|
|
Tcl_DStringAppend(&tString, pBueffel, -1);
|
|
sprintf(pBueffel, "%s.d5d %f \n", name, ObVal(self->aParameter, PARDD5));
|
|
Tcl_DStringAppend(&tString, pBueffel, -1);
|
|
sprintf(pBueffel,
|
|
"%s.interrupt %f \n", name, ObVal(self->aParameter, PARINT));
|
|
Tcl_DStringAppend(&tString, pBueffel, -1);
|
|
sprintf(pBueffel,
|
|
"%s.detectorh %f \n", name, ObVal(self->aParameter, PARDDH));
|
|
Tcl_DStringAppend(&tString, pBueffel, -1);
|
|
sprintf(pBueffel, "%s.d4h %f \n", name, ObVal(self->aParameter, PARD4H));
|
|
Tcl_DStringAppend(&tString, pBueffel, -1);
|
|
sprintf(pBueffel, "%s.d5h %f \n", name, ObVal(self->aParameter, PARD5H));
|
|
Tcl_DStringAppend(&tString, pBueffel, -1);
|
|
sprintf(pBueffel,
|
|
"%s.anah %f \n", name, ObVal(self->aParameter, PARANA));
|
|
Tcl_DStringAppend(&tString, pBueffel, -1);
|
|
sprintf(pBueffel,
|
|
"%s.anad %f \n", name, ObVal(self->aParameter, PARADIS));
|
|
Tcl_DStringAppend(&tString, pBueffel, -1);
|
|
sprintf(pBueffel,
|
|
"%s.anaflag %f \n", name, ObVal(self->aParameter, ANAFLAG));
|
|
Tcl_DStringAppend(&tString, pBueffel, -1);
|
|
sprintf(pBueffel, "%s.c2h %f \n", name, ObVal(self->aParameter, PARDDD));
|
|
Tcl_DStringAppend(&tString, pBueffel, -1);
|
|
sprintf(pBueffel,
|
|
"%s.aomconst %f \n", name, ObVal(self->aParameter, PARAOM));
|
|
Tcl_DStringAppend(&tString, pBueffel, -1);
|
|
sprintf(pBueffel,
|
|
"%s.diaflag %f \n", name, ObVal(self->aParameter, DIAFLAG));
|
|
Tcl_DStringAppend(&tString, pBueffel, -1);
|
|
SCWrite(pCon, Tcl_DStringValue(&tString), eValue);
|
|
Tcl_DStringFree(&tString);
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
static void A2TKill(void *pData)
|
|
{
|
|
pAmor2T self = (pAmor2T) pData;
|
|
|
|
if (self == NULL)
|
|
return;
|
|
|
|
if (self->pDes)
|
|
DeleteDescriptor(self->pDes);
|
|
|
|
if (self->pDriv)
|
|
free(self->pDriv);
|
|
|
|
if (self->aParameter)
|
|
ObParDelete(self->aParameter);
|
|
|
|
free(self);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
Initialization: All is done from the Factory function. This takes an Tcl
|
|
array as parameter which is supposed to hold the names of all motors.
|
|
This must fail if one of the motors cannot be accessed.
|
|
--------------------------------------------------------------------------*/
|
|
int Amor2TFactory(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
pAmor2T pNew, pAOM = NULL;
|
|
int i, iRet;
|
|
char pBueffel[512];
|
|
const char *pMot = NULL;
|
|
|
|
if (argc < 4) {
|
|
SCWrite(pCon,
|
|
"ERROR: Insufficient number of arguments to Amor2tFactory",
|
|
eError);
|
|
return 0;
|
|
}
|
|
|
|
/* allocate space .............. */
|
|
pNew = (pAmor2T) malloc(sizeof(Amor2T));
|
|
if (!pNew) {
|
|
SCWrite(pCon, "ERROR: out of memory in Amor2TFactory", eError);
|
|
return 0;
|
|
}
|
|
memset(pNew, 0, sizeof(Amor2T));
|
|
pNew->pDes = CreateDescriptor("Amor2T");
|
|
pNew->aParameter = ObParCreate(MAXPAR);
|
|
pNew->pDriv = CreateDrivableInterface();
|
|
if ((!pNew->pDes) || (!pNew->aParameter) || (!pNew->pDriv)) {
|
|
SCWrite(pCon, "ERROR: out of memory in Amor2TFactory", eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
|
|
/* find the motors */
|
|
pMot = Tcl_GetVar2(pSics->pTcl, argv[2], "mom", TCL_GLOBAL_ONLY);
|
|
if (!pMot) {
|
|
SCWrite(pCon, "ERROR: no value for mom motr found", eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
pNew->aEngine[MOTMOM] = FindMotor(pSics, (char *) pMot);
|
|
if (!pNew->aEngine[MOTMOM]) {
|
|
sprintf(pBueffel, "ERROR: motor %s NOT found!", pMot);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
|
|
pMot = Tcl_GetVar2(pSics->pTcl, argv[2], "som", TCL_GLOBAL_ONLY);
|
|
if (!pMot) {
|
|
SCWrite(pCon, "ERROR: no value for som motor found", eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
pNew->aEngine[MOTSOM] = FindMotor(pSics, (char *) pMot);
|
|
if (!pNew->aEngine[MOTSOM]) {
|
|
sprintf(pBueffel, "ERROR: motor %s NOT found!", pMot);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
|
|
pMot = Tcl_GetVar2(pSics->pTcl, argv[2], "coz", TCL_GLOBAL_ONLY);
|
|
if (!pMot) {
|
|
SCWrite(pCon, "ERROR: no value for coz motor found", eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
pNew->aEngine[MOTCOZ] = FindMotor(pSics, (char *) pMot);
|
|
if (!pNew->aEngine[MOTCOZ]) {
|
|
sprintf(pBueffel, "ERROR: motor %s NOT found!", pMot);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
|
|
pMot = Tcl_GetVar2(pSics->pTcl, argv[2], "cox", TCL_GLOBAL_ONLY);
|
|
if (!pMot) {
|
|
SCWrite(pCon, "ERROR: no value for cox motor found", eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
pNew->aEngine[MOTCOX] = FindMotor(pSics, (char *) pMot);
|
|
if (!pNew->aEngine[MOTCOX]) {
|
|
sprintf(pBueffel, "ERROR: motor %s NOT found!", pMot);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
|
|
pMot = Tcl_GetVar2(pSics->pTcl, argv[2], "stz", TCL_GLOBAL_ONLY);
|
|
if (!pMot) {
|
|
SCWrite(pCon, "ERROR: no value for stz motor found", eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
pNew->aEngine[MOTSTZ] = FindMotor(pSics, (char *) pMot);
|
|
if (!pNew->aEngine[MOTSTZ]) {
|
|
sprintf(pBueffel, "ERROR: motor %s NOT found!", pMot);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
|
|
pMot = Tcl_GetVar2(pSics->pTcl, argv[2], "soz", TCL_GLOBAL_ONLY);
|
|
if (!pMot) {
|
|
SCWrite(pCon, "ERROR: no value for soz motor found", eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
pNew->aEngine[MOTSOZ] = FindMotor(pSics, (char *) pMot);
|
|
if (!pNew->aEngine[MOTSOZ]) {
|
|
sprintf(pBueffel, "ERROR: motor %s NOT found!", pMot);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
|
|
pMot = Tcl_GetVar2(pSics->pTcl, argv[2], "d4b", TCL_GLOBAL_ONLY);
|
|
if (!pMot) {
|
|
SCWrite(pCon, "ERROR: no value for d4b motor found", eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
pNew->aEngine[MOTD4B] = FindMotor(pSics, (char *) pMot);
|
|
if (!pNew->aEngine[MOTD4B]) {
|
|
sprintf(pBueffel, "ERROR: motor %s NOT found!", pMot);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
|
|
pMot = Tcl_GetVar2(pSics->pTcl, argv[2], "d5b", TCL_GLOBAL_ONLY);
|
|
if (!pMot) {
|
|
SCWrite(pCon, "ERROR: no value for d5b motor found", eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
pNew->aEngine[MOTD5B] = FindMotor(pSics, (char *) pMot);
|
|
if (!pNew->aEngine[MOTD5B]) {
|
|
sprintf(pBueffel, "ERROR: motor %s NOT found!", pMot);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
|
|
pMot = Tcl_GetVar2(pSics->pTcl, argv[2], "com", TCL_GLOBAL_ONLY);
|
|
if (!pMot) {
|
|
SCWrite(pCon, "ERROR: no value for com motor found", eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
pNew->aEngine[MOTCOM] = FindMotor(pSics, (char *) pMot);
|
|
if (!pNew->aEngine[MOTCOM]) {
|
|
sprintf(pBueffel, "ERROR: motor %s NOT found!", pMot);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
|
|
pMot = Tcl_GetVar2(pSics->pTcl, argv[2], "aoz", TCL_GLOBAL_ONLY);
|
|
if (!pMot) {
|
|
SCWrite(pCon, "ERROR: no value for aoz motor found", eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
pNew->aEngine[MOTAOZ] = FindMotor(pSics, (char *) pMot);
|
|
if (!pNew->aEngine[MOTAOZ]) {
|
|
sprintf(pBueffel, "ERROR: motor %s NOT found!", pMot);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
|
|
pMot = Tcl_GetVar2(pSics->pTcl, argv[2], "aom", TCL_GLOBAL_ONLY);
|
|
if (!pMot) {
|
|
SCWrite(pCon, "ERROR: no value for aom motor found", eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
pNew->aEngine[MOTAOM] = FindMotor(pSics, (char *) pMot);
|
|
if (!pNew->aEngine[MOTAOM]) {
|
|
sprintf(pBueffel, "ERROR: motor %s NOT found!", pMot);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
|
|
pMot = Tcl_GetVar2(pSics->pTcl, argv[2], "c3z", TCL_GLOBAL_ONLY);
|
|
if (!pMot) {
|
|
SCWrite(pCon, "ERROR: no value for c3z motor found", eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
pNew->aEngine[MOTC3Z] = FindMotor(pSics, (char *) pMot);
|
|
if (!pNew->aEngine[MOTC3Z]) {
|
|
sprintf(pBueffel, "ERROR: motor %s NOT found!", pMot);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* initialize parameters */
|
|
ObParInit(pNew->aParameter, PARDS, "detectord", 1400., usMugger);
|
|
ObParInit(pNew->aParameter, PARDH, "sampleh", 50., usMugger);
|
|
ObParInit(pNew->aParameter, PARDD4, "d4d", 100., usMugger);
|
|
ObParInit(pNew->aParameter, PARDD5, "d5d", 200., usMugger);
|
|
ObParInit(pNew->aParameter, PARINT, "interrupt", 0., usMugger);
|
|
ObParInit(pNew->aParameter, PARDDH, "detectorh", 40., usMugger);
|
|
ObParInit(pNew->aParameter, PARD4H, "d4h", 40., usMugger);
|
|
ObParInit(pNew->aParameter, PARD5H, "d5h", 400., usMugger);
|
|
ObParInit(pNew->aParameter, PARANA, "anah", 400., usMugger);
|
|
ObParInit(pNew->aParameter, PARADIS, "anad", 600., usMugger);
|
|
ObParInit(pNew->aParameter, ANAFLAG, "anaflag", -1., usMugger);
|
|
ObParInit(pNew->aParameter, PARDDD, "c2h", 100., usMugger);
|
|
ObParInit(pNew->aParameter, PARAOM, "aomconst", 3., usMugger);
|
|
ObParInit(pNew->aParameter, DIAFLAG, "diaflag", 1., usMugger);
|
|
|
|
|
|
/* initialize interfaces */
|
|
pNew->pDes->GetInterface = A2TGetInterface;
|
|
pNew->pDes->SaveStatus = A2TSave;
|
|
pNew->pDriv->Halt = A2THalt;
|
|
pNew->pDriv->CheckLimits = A2TCheck;
|
|
pNew->pDriv->SetValue = A2TSetValue;
|
|
pNew->pDriv->CheckStatus = A2TStatus;
|
|
pNew->pDriv->GetValue = A2TGetValue;
|
|
|
|
/* copy data structure for second command for aom2t */
|
|
pAOM = (pAmor2T) malloc(sizeof(Amor2T));
|
|
if (!pAOM) {
|
|
A2TKill(pNew);
|
|
SCWrite(pCon, "ERROR: out of memory in Amor2TFactory", eError);
|
|
return 0;
|
|
}
|
|
memcpy(pAOM, pNew, sizeof(Amor2T));
|
|
pAOM->pDriv = CreateDrivableInterface();
|
|
pAOM->pDes = CreateDescriptor("Amor2T");
|
|
if (!pAOM->pDriv || !pAOM->pDes) {
|
|
A2TKill(pNew);
|
|
SCWrite(pCon, "ERROR: out of memory in Amor2TFactory", eError);
|
|
return 0;
|
|
}
|
|
|
|
/* set modified interface functions */
|
|
pAOM->pDes->GetInterface = A2TGetInterface;
|
|
pAOM->pDriv->Halt = A2THalt;
|
|
pAOM->pDriv->CheckLimits = ANA2TCheck;
|
|
pAOM->pDriv->SetValue = ANA2TSetValue;
|
|
pAOM->pDriv->GetValue = ANA2TGetValue;
|
|
pAOM->pDriv->CheckStatus = A2TStatus;
|
|
|
|
|
|
/* install commands */
|
|
iRet = AddCommand(pSics, argv[1], Amor2TAction, A2TKill, pNew);
|
|
if (!iRet) {
|
|
sprintf(pBueffel, "ERROR: duplicate command %s NOT created", argv[1]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
iRet = AddCommand(pSics, argv[3], Amor2TAction, free, pAOM);
|
|
if (!iRet) {
|
|
sprintf(pBueffel, "ERROR: duplicate command %s NOT created", argv[1]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
A2TKill(pNew);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
int Amor2TAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
pAmor2T self = (pAmor2T) pData;
|
|
char pBueffel[256];
|
|
float fVal;
|
|
double dVal;
|
|
ObPar *pPar = NULL;
|
|
int iRet;
|
|
|
|
assert(self);
|
|
|
|
if (argc > 1) {
|
|
strtolower(argv[1]);
|
|
/* deal with list */
|
|
if (strcmp(argv[1], "list") == 0) {
|
|
A2TList(self, pCon, argv[0]);
|
|
return 1;
|
|
}
|
|
/* otherwise it should be a parameter command */
|
|
if (argc >= 3) {
|
|
iRet = Tcl_GetDouble(pSics->pTcl, argv[2], &dVal);
|
|
if (iRet != TCL_OK) {
|
|
sprintf(pBueffel, "ERROR: failed to convert %s to number",
|
|
argv[2]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
iRet =
|
|
ObParSet(self->aParameter, argv[0], argv[1], (float) dVal, pCon);
|
|
if (iRet) {
|
|
SCSendOK(pCon);
|
|
}
|
|
return iRet;
|
|
} else {
|
|
pPar = ObParFind(self->aParameter, argv[1]);
|
|
if (!pPar) {
|
|
sprintf(pBueffel, "ERROR: parameter %s NOT found", argv[1]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
sprintf(pBueffel, "%s.%s = %f", argv[0], pPar->name, pPar->fVal);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
}
|
|
} else {
|
|
fVal = self->pDriv->GetValue(self, pCon);
|
|
sprintf(pBueffel, " %s = %f", argv[0], fVal);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
}
|
|
}
|