Files
sics/difrac.c
2000-02-07 10:38:55 +00:00

540 lines
14 KiB
C

/*-------------------------------------------------------------------------
D I F R A C
A four-circle diffractometer requires sophicticated procedures for
searching peaks, orienting crystals and for performing data collection.
Rather then invent all of this again the DIFRAC-F77 program written by
Peter White and Eric Gabe has been incoporated into SICS. This module
provides the C-language side of the interface between DIFRAC and SICS.
DIFRAC can only be included once into SICS, it is not possible to have
more then one copy of this. This is why there is file static global data
here.
copyright: see copyright.h
Mark Koennecke, November 1999
--------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <ctype.h>
#include "fortify.h"
#include "sics.h"
#include "motor.h"
#include "counter.h"
#include "status.h"
#include "splitter.h"
#include "difrac.h"
/*--------------------------------------------------------------------------
In order to deal with multiple request to the DIFRAC subsystem we need to
keep the connection objects on a stack. This stack is defined here.
---------------------------------------------------------------------------*/
#define MAXSTACK 50
static SConnection *ConStack[MAXSTACK];
static int iConStackPtr = -1;
/*--------------------------------------------------------------------------
In order to do the four circle work we need to know the motors of the
eulerian cradle and access to the counter. Furthermore we need to know
about the omega2theta motor and the scanning routine.
These data structures are initialized by the installation routine.
---------------------------------------------------------------------------*/
static pMotor pTTH, pOM, pCHI, pPHI;
static pCounter counter;
/*---------------------------------------------------------------------------
The following routines will be called from F77. Their names take care of the
system dependent name mangling scheme for calling C from F77. This may
need adjustment when porting to another system
---------------------------------------------------------------------------*/
/*========= read angles */
void sicsanget_(float *fTH, float *fOM, float *fCHI, float *fPHI)
{
int iRet;
/* this is just security, may never happen */
if(iConStackPtr < 0)
{
return;
}
if(ConStack[iConStackPtr] == NULL)
{
return;
}
iRet = MotorGetSoftPosition(pTTH,ConStack[iConStackPtr],fTH);
if(iRet != 1)
{
SCWrite(ConStack[iConStackPtr],
"ERROR: failed to read two theta, DIFRAC may be confused now",
eError);
}
iRet = MotorGetSoftPosition(pOM,ConStack[iConStackPtr],fOM);
if(iRet != 1)
{
SCWrite(ConStack[iConStackPtr],
"ERROR: failed to read omega, DIFRAC may be confused now",
eError);
}
iRet = MotorGetSoftPosition(pCHI,ConStack[iConStackPtr],fCHI);
if(iRet != 1)
{
SCWrite(ConStack[iConStackPtr],
"ERROR: failed to read chi, DIFRAC may be confused now",
eError);
}
iRet = MotorGetSoftPosition(pPHI,ConStack[iConStackPtr],fPHI);
if(iRet != 1)
{
SCWrite(ConStack[iConStackPtr],
"ERROR: failed to read two theta, DIFRAC may be confused now",
eError);
}
}
#define ABS(x) (x < 0 ? -(x) : (x))
/*=========== check angles */
void sicsangcheck_(float *fTH, float *fOM, float *fCHI, float *fPHI,
int *iInvalid)
{
int iRet;
SConnection *pCon = NULL;
float fHard;
char pBueffel[256], pError[131];
/* this is just security, may never happen */
if(iConStackPtr < 0)
{
return;
}
if(ConStack[iConStackPtr] == NULL)
{
return;
}
pCon = ConStack[iConStackPtr];
*iInvalid = 0;
iRet = MotorCheckBoundary(pTTH,*fTH,&fHard,pError,131);
if(iRet != 1)
{
sprintf(pBueffel,
"ERROR: %6.2f %6.2f %6.2f %6.2f violates twotheta limits",
*fTH, *fOM, *fCHI, *fPHI);
SCWrite(pCon,pBueffel,eError);
*iInvalid = 4;
return;
}
iRet = MotorCheckBoundary(pOM,*fOM,&fHard,pError,131);
if(iRet != 1)
{
sprintf(pBueffel,
"ERROR: %6.2f %6.2f %6.2f %6.2f violates omega limits",
*fTH, *fOM, *fCHI, *fPHI);
SCWrite(pCon,pBueffel,eError);
*iInvalid = 4;
return;
}
iRet = MotorCheckBoundary(pCHI,*fCHI,&fHard,pError,131);
if(iRet != 1)
{
sprintf(pBueffel,
"ERROR: %6.2f %6.2f %6.2f %6.2f violates chi limits",
*fTH, *fOM, *fCHI, *fPHI);
SCWrite(pCon,pBueffel,eError);
*iInvalid = 4;
return;
}
iRet = MotorCheckBoundary(pPHI,*fPHI,&fHard,pError,131);
if(iRet != 1)
{
sprintf(pBueffel,
"ERROR: %6.2f %6.2f %6.2f %6.2f violates phi limits",
*fTH, *fOM, *fCHI, *fPHI);
SCWrite(pCon,pBueffel,eError);
*iInvalid = 4;
return;
}
}
/*======== set angles */
void sicsangset_(float *fTTH, float *fOM, float *fCHI, float *fPHI,
int *icol)
{
pDummy pDum;
int iRet;
SConnection *pCon = NULL;
float fT1, fT2, fT3, fT4;
*icol = 0;
/* this is just security, may never happen */
if(iConStackPtr < 0)
{
return;
}
if(ConStack[iConStackPtr] == NULL)
{
return;
}
pCon = ConStack[iConStackPtr];
/* check if this is possible, if not complain */
sicsangcheck_(fTTH, fOM,fCHI,fPHI, &iRet);
if(iRet >= 4)
{
*icol = 1;
return;
}
/* start */
pDum = (pDummy)pTTH;
iRet = StartDevice(pServ->pExecutor, "TTH",
pDum->pDescriptor, pDum,pCon, *fTTH);
if(!iRet)
{
SCWrite(pCon,"ERROR: cannot start two theta motor",eError);
StopExe(pServ->pExecutor,"all");
*icol = 10;
}
pDum = (pDummy)pOM;
iRet = StartDevice(pServ->pExecutor, "OM",
pDum->pDescriptor, pDum,pCon, *fOM);
if(!iRet)
{
SCWrite(pCon,"ERROR: cannot start omega motor",eError);
StopExe(pServ->pExecutor,"all");
*icol = 10;
}
pDum = (pDummy)pCHI;
iRet = StartDevice(pServ->pExecutor, "CHI",
pDum->pDescriptor, pDum,pCon, *fCHI);
if(!iRet)
{
SCWrite(pCon,"ERROR: cannot start chi motor",eError);
StopExe(pServ->pExecutor,"all");
*icol = 10;
}
pDum = (pDummy)pPHI;
iRet = StartDevice(pServ->pExecutor, "PHI",
pDum->pDescriptor, pDum,pCon, *fPHI);
if(!iRet)
{
SCWrite(pCon,"ERROR: cannot start two theta motor",eError);
StopExe(pServ->pExecutor,"all");
*icol = 10;
}
/* wait for end of it */
iRet = Wait4Success(pServ->pExecutor);
switch(iRet)
{
case DEVINT:
if(SCGetInterrupt(pCon) == eAbortOperation)
{
SCSetInterrupt(pCon,eContinue);
SCSetError(pCon,OKOK);
}
break;
case DEVDONE:
break;
default:
break;
}
/*
As TRICS has such a shitty cradle check angles and report error
if bad
*/
sicsanget_(&fT1, &fT2, &fT3, &fT4);
if(ABS(fT1 - *fTTH) > .2)
{
*icol = 10;
}
if(ABS(fT2 - *fOM) > .2)
{
*icol = 10;
}
if(ABS(fT3 - *fCHI) > .2)
{
*icol = 10;
}
if(ABS(fT4 - *fPHI) > .2)
{
*icol = 10;
}
}
/*=========== count */
void sicscount_(float *fPreset, float *fCounts)
{
pDummy pDum;
int iRet;
SConnection *pCon = NULL;
long lTask;
/* this is just security, may never happen */
if(iConStackPtr < 0)
{
return;
}
if(ConStack[iConStackPtr] == NULL)
{
return;
}
pCon = ConStack[iConStackPtr];
pDum = (pDummy)counter;
SetCounterPreset(counter,*fPreset);
iRet = StartDevice(pServ->pExecutor,
"DifracCount",
pDum->pDescriptor,
counter,
pCon,
*fPreset);
if(!iRet)
{
SCWrite(pCon,"ERROR: Failed to start counting ",eError);
return;
}
SetStatus(eCounting);
/* wait for finish */
lTask = GetDevexecID(pServ->pExecutor);
if(lTask > 0);
{
TaskWait(pServ->pTasker,lTask);
}
*fCounts = (float)GetCounts(counter,pCon);
}
/*========= sicswrite */
void sicswrite_(int *iText, int *iLen)
{
SConnection *pCon = NULL;
char pBueffel[256];
int i;
if(*iLen > 255)
return;
for(i = 0; i < *iLen; i++)
{
pBueffel[i] = (char)iText[i];
}
pBueffel[i] = '\0';
/* this is just security, may never happen */
if(iConStackPtr < 0)
{
puts(pBueffel);
return;
}
if(ConStack[iConStackPtr] == NULL)
{
puts(pBueffel);
return;
}
pCon = ConStack[iConStackPtr];
SCWrite(pCon,pBueffel,eValue);
}
/*========== sicsgetline */
void sicsgetline_(int *iText, int *iLen)
{
SConnection *pCon = NULL;
char pBueffel[256];
int i, iRet;
/* this is just security, may never happen */
if(iConStackPtr < 0)
{
return;
}
if(ConStack[iConStackPtr] == NULL)
{
return;
}
pCon = ConStack[iConStackPtr];
iRet = SCPrompt(pCon,"Enter data please >>" , pBueffel, 255);
/* difrac cannot handle an interrupted input operation */
if(iRet == 0)
{
SCSetInterrupt(pCon,eContinue);
}
for(i = 0; i < strlen(pBueffel); i++)
{
iText[i] = (int)pBueffel[i];
}
*iLen = strlen(pBueffel);
}
/*============= checkint */
void checkint_(int *iK)
{
SConnection *pCon = NULL;
char pBueffel[256];
int i;
/* this is just security, may never happen */
if(iConStackPtr < 0)
{
*iK = 0;
return;
}
if(ConStack[iConStackPtr] == NULL)
{
return;
}
pCon = ConStack[iConStackPtr];
if(SCGetInterrupt(pCon) >= eAbortScan)
{
*iK = 0;
}
else
{
*iK = 1;
}
}
/*--------------------------------------------------------------------------
DifracAction is the interface routine between the SICS interpreter and
the DIFRAC subsystem. What it basically does is: pop the connection onto
the stack. Concatenate all pending command line data to a string. Then
call DIFRAC with this string as an parameter. On return, remove the
connection from the stack again and return.
-------------------------------------------------------------------------*/
/* some protoypes for things defined in F77 */
extern void difini_(void);
extern void difint_(int *iText, int *iLen);
int DifracAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
char pInput[256];
int iInput[256];
int iLen, i;
if(argc < 2)
{
SCWrite(pCon,"ERROR: dif expects at least one argument",eError);
return 0;
}
/* user privilege required */
if(!SCMatchRights(pCon,usUser))
{
return 0;
}
/* steal: redirect the I/O to me */
strcpy(pInput,argv[1]);
strtolower(pInput);
if(strcmp(pInput,"steal") == 0)
{
if(iConStackPtr >= 0)
{
ConStack[iConStackPtr] = pCon;
}
SCSendOK(pCon);
return 1;
}
iConStackPtr++;
ConStack[iConStackPtr] = pCon;
Arg2Text(argc-1, &argv[1],pInput,255);
iLen = strlen(pInput);
for(i = 0; i < iLen; i++)
{
iInput[i] = toupper((int)pInput[i]);
}
/* do difrac */
difint_(iInput, &iLen);
SCWrite(pCon,"Difrac subsystem finished",eWarning);
iConStackPtr--;
if(SCGetInterrupt(pCon) != eContinue)
{
return 0;
}
else
{
return 1;
}
}
/*-------------------- The initialization routine ----------------------*/
int MakeDifrac(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
CommandList *pCom = NULL;
pICountable pCts = NULL;
int iRet;
if(argc < 6)
{
SCWrite(pCon,
"ERROR: Insufficient number of arguments to MakeDifrac",eError);
return 0;
}
/* find motors */
pTTH = FindMotor(pSics,argv[1]);
if(!pTTH)
{
SCWrite(pCon,"ERROR: cannot find two theta motor",eError);
return 0;
}
pOM = FindMotor(pSics,argv[2]);
if(!pOM)
{
SCWrite(pCon,"ERROR: cannot find omega motor",eError);
return 0;
}
pCHI = FindMotor(pSics,argv[3]);
if(!pTTH)
{
SCWrite(pCon,"ERROR: cannot find chi motor",eError);
return 0;
}
pPHI = FindMotor(pSics,argv[4]);
if(!pTTH)
{
SCWrite(pCon,"ERROR: cannot find phi motor",eError);
return 0;
}
/* locate counter */
pCom = FindCommand(pSics,argv[5]);
if(pCom == NULL)
{
SCWrite(pCon,"ERROR: counter not found in MakeDifrac",
eError);
return 0;
}
pCts = GetCountableInterface(pCom->pData);
if(!pCts)
{
SCWrite(pCon,"ERROR: argument to MakeDifrac is no counter",
eError);
return 0;
}
counter = (pCounter)pCom->pData;
/* initialize difrac */
difini_();
/* install command */
iRet = AddCommand(pSics,
"dif",
DifracAction,
NULL,
NULL);
if(!iRet)
{
SCWrite(pCon,"ERROR: duplicate command dif NOT created",
eError);
}
return iRet;
}