540 lines
14 KiB
C
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;
|
|
}
|
|
|