482 lines
12 KiB
C
482 lines
12 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;
|
|
}
|