- Added a log facility to scan which includes a variable which is logged but not driven during a scan. - Fixed normal beam operation
249 lines
7.3 KiB
C
249 lines
7.3 KiB
C
/*------------------------------------------------------------------------------------------------------
|
|
Virtual motor interface to reciprocal space coordinates H, K and L for a four circle diffractometer.
|
|
Requires a HKL object for calculations.
|
|
|
|
copyright: see file COPYRIGHT
|
|
|
|
Mark Koennecke, February 2005
|
|
--------------------------------------------------------------------------------------------------------*/
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include "sics.h"
|
|
#include "fortify.h"
|
|
#include "motor.h"
|
|
#include "matrix/matrix.h"
|
|
#include "hkl.h"
|
|
#include "hkl.i"
|
|
#include "hklmot.h"
|
|
/*=================== Object Descriptor Interface ===================================================*/
|
|
static void *HKLGetInterface(void *pData, int iID){
|
|
pHKLMot self = NULL;
|
|
|
|
self = (pHKLMot)pData;
|
|
if(self == NULL){
|
|
return NULL;
|
|
}
|
|
if(iID == DRIVEID){
|
|
return self->pDriv;
|
|
}
|
|
return NULL;
|
|
}
|
|
/*=================== Drivable Interface ============================================================*/
|
|
static int HKLHalt(void *pData){
|
|
pHKLMot self = NULL;
|
|
|
|
self = (pHKLMot)pData;
|
|
assert(self != NULL);
|
|
|
|
self->pHkl->pTheta->pDrivInt->Halt(self->pHkl->pTheta);
|
|
self->pHkl->pOmega->pDrivInt->Halt(self->pHkl->pOmega);
|
|
if(self->pHkl->iNOR == 1){
|
|
self->pHkl->pNu->pDrivInt->Halt(self->pHkl->pNu);
|
|
} else {
|
|
self->pHkl->pChi->pDrivInt->Halt(self->pHkl->pChi);
|
|
self->pHkl->pPhi->pDrivInt->Halt(self->pHkl->pPhi);
|
|
}
|
|
return 1;
|
|
}
|
|
/*-----------------------------------------------------------------------------------------------------*/
|
|
static int HKLCheckLimits(void *self, float fVal, char *error, int errLen){
|
|
/*
|
|
There is no meaningful implementation here. This gets called when starting the motor.
|
|
At that stage not all other values may be known. If the calculation fails, this will die
|
|
at status check time.
|
|
*/
|
|
return 1;
|
|
}
|
|
/*----------------------------------------------------------------------------------------------------*/
|
|
static long HKLSetValue(void *pData, SConnection *pCon, float fVal){
|
|
pHKLMot self = NULL;
|
|
|
|
if(!SCMatchRights(pCon,usUser)){
|
|
return 0;
|
|
}
|
|
|
|
self = (pHKLMot)pData;
|
|
assert(self != NULL);
|
|
|
|
self->pHkl->targetHKL[self->index] = fVal;
|
|
self->pHkl->targetDirty = 1;
|
|
return OKOK;
|
|
}
|
|
/*---------------------------------------------------------------------------------------------------*/
|
|
static int checkMotors(pHKLMot self, SConnection *pCon){
|
|
int status;
|
|
|
|
status = self->pHkl->pTheta->pDrivInt->CheckStatus(self->pHkl->pTheta, pCon);
|
|
if(status != HWIdle && status != OKOK){
|
|
return status;
|
|
}
|
|
status = self->pHkl->pOmega->pDrivInt->CheckStatus(self->pHkl->pOmega, pCon);
|
|
if(status != HWIdle && status != OKOK){
|
|
return status;
|
|
}
|
|
if(self->pHkl->iNOR == 1){
|
|
status = self->pHkl->pNu->pDrivInt->CheckStatus(self->pHkl->pNu, pCon);
|
|
if(status != HWIdle && status != OKOK){
|
|
return status;
|
|
}
|
|
} else {
|
|
status = self->pHkl->pChi->pDrivInt->CheckStatus(self->pHkl->pChi, pCon);
|
|
if(status != HWIdle && status != OKOK){
|
|
return status;
|
|
}
|
|
status = self->pHkl->pPhi->pDrivInt->CheckStatus(self->pHkl->pPhi, pCon);
|
|
if(status != HWIdle && status != OKOK){
|
|
return status;
|
|
}
|
|
}
|
|
return HWIdle;
|
|
}
|
|
/*-----------------------------------------------------------------------------------------------------*/
|
|
static int HKLCheckStatus(void *pData, SConnection *pCon){
|
|
pHKLMot self = NULL;
|
|
int status;
|
|
|
|
self = (pHKLMot)pData;
|
|
assert(self != NULL);
|
|
if(self->pHkl->targetDirty == 1){
|
|
status = RunHKL(self->pHkl,self->pHkl->targetHKL,.0,0,pCon);
|
|
self->pHkl->targetDirty = 0;
|
|
if(status != 1){
|
|
SCSetInterrupt(pCon,eAbortOperation);
|
|
return HWFault;
|
|
}
|
|
return HWBusy;
|
|
} else {
|
|
return checkMotors(self,pCon);
|
|
}
|
|
}
|
|
/*-----------------------------------------------------------------------------------------------------*/
|
|
static float HKLGetValue(void *pData, SConnection *pCon){
|
|
pHKLMot self = NULL;
|
|
float fVal[3];
|
|
int status;
|
|
|
|
self = (pHKLMot)pData;
|
|
assert(self != NULL);
|
|
|
|
|
|
status = GetHKLFromAngles(self->pHkl,pCon,fVal);
|
|
if(status != 1){
|
|
SCWrite(pCon,"ERROR: failed to read positions or convert to HKL",eError);
|
|
return -9999.99;
|
|
}
|
|
return fVal[self->index];
|
|
}
|
|
/*=============================== Live and Death ====================================*/
|
|
static pHKLMot MakeHKLMot(pHKL pHkl, int index){
|
|
pHKLMot self = NULL;
|
|
|
|
assert(pHkl != NULL);
|
|
assert(index >= 0 && index < 3);
|
|
|
|
self = (pHKLMot)malloc(sizeof(HKLMot));
|
|
if(self == NULL){
|
|
return NULL;
|
|
}
|
|
memset(self,0,sizeof(HKLMot));
|
|
self->pDes = CreateDescriptor("HKLMot");
|
|
self->pDriv = CreateDrivableInterface();
|
|
if(self->pDes == NULL || self->pDriv == NULL){
|
|
free(self);
|
|
return NULL;
|
|
}
|
|
self->pDes->GetInterface = HKLGetInterface;
|
|
self->pDriv->Halt = HKLHalt;
|
|
self->pDriv->CheckLimits = HKLCheckLimits;
|
|
self->pDriv->SetValue = HKLSetValue;
|
|
self->pDriv->CheckStatus = HKLCheckStatus;
|
|
self->pDriv->GetValue = HKLGetValue;
|
|
self->pHkl = pHkl;
|
|
self->index = index;
|
|
return self;
|
|
}
|
|
/*----------------------------------------------------------------------------------*/
|
|
static void KillHklMot(void *pData){
|
|
pHKLMot self = NULL;
|
|
|
|
self = (pHKLMot)pData;
|
|
if(self == NULL){
|
|
return;
|
|
}
|
|
if(self->pDes != NULL){
|
|
DeleteDescriptor(self->pDes);
|
|
}
|
|
if(self->pDriv){
|
|
free(self->pDriv);
|
|
}
|
|
free(self);
|
|
}
|
|
/*=============================== Interpreter Interface ============================*/
|
|
int HKLMotAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){
|
|
pHKLMot self = NULL;
|
|
float value;
|
|
char pBuffer[132];
|
|
|
|
self = (pHKLMot)pData;
|
|
assert(self != NULL);
|
|
|
|
value = self->pDriv->GetValue(self,pCon);
|
|
if(value < -9000.){
|
|
snprintf(pBuffer,131,"ERROR: failed to read %s",argv[0]);
|
|
SCWrite(pCon,pBuffer,eError);
|
|
return 0;
|
|
}
|
|
snprintf(pBuffer,131,"%s = %f", argv[0], value);
|
|
SCWrite(pCon,pBuffer,eValue);
|
|
return 1;
|
|
}
|
|
/*------------------------------------------------------------------------------------------*/
|
|
int HKLMotInstall(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){
|
|
pHKL pHkl;
|
|
pHKLMot pMot = NULL;
|
|
char pBuffer[131];
|
|
|
|
if(argc < 2){
|
|
SCWrite(pCon,"ERROR: Insifficient number of arguments to HKLMotInstall",eError);
|
|
return 0;
|
|
}
|
|
strtolower(argv[1]);
|
|
pHkl = (pHKL)FindCommandData(pSics,argv[1],"4-Circle-Calculus");
|
|
if(pHkl == NULL){
|
|
snprintf(pBuffer,131,"ERROR: %s is not present or no HKL object",argv[1]);
|
|
SCWrite(pCon,pBuffer,eError);
|
|
return 0;
|
|
}
|
|
|
|
pMot = MakeHKLMot(pHkl, 0);
|
|
if(pMot == NULL){
|
|
SCWrite(pCon,"ERROR: out of memory creating H Motor",eError);
|
|
return 0;
|
|
}
|
|
if(!AddCommand(pSics,"H",HKLMotAction,KillHklMot,pMot)){
|
|
SCWrite(pCon,"ERROR: duplicate command H not created",eError);
|
|
return 0;
|
|
}
|
|
|
|
pMot = MakeHKLMot(pHkl, 1);
|
|
if(pMot == NULL){
|
|
SCWrite(pCon,"ERROR: out of memory creating K Motor",eError);
|
|
return 0;
|
|
}
|
|
if(!AddCommand(pSics,"K",HKLMotAction,KillHklMot,pMot)){
|
|
SCWrite(pCon,"ERROR: duplicate command K not created",eError);
|
|
return 0;
|
|
}
|
|
|
|
pMot = MakeHKLMot(pHkl, 2);
|
|
if(pMot == NULL){
|
|
SCWrite(pCon,"ERROR: out of memory creating L Motor",eError);
|
|
return 0;
|
|
}
|
|
if(!AddCommand(pSics,"L",HKLMotAction,KillHklMot,pMot)){
|
|
SCWrite(pCon,"ERROR: duplicate command L not created",eError);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|