- Removed old code

- Extended tasker to support task groups
- Added task functions for motors and counters
- Modifed devexec to use the new task functions
- Modified TAS to treat the monochromator separatly
- Coded a EIGER monochromator module to reflect even more new
  requirements
- Added EPICS counters and motors
- Modified multicounter to be better performing


SKIPPED:
	psi/eigermono.c
	psi/make_gen
	psi/makefile_linux
	psi/psi.c
	psi/sinqhttp.c
This commit is contained in:
koennecke
2013-04-02 15:13:35 +00:00
parent 86e246416b
commit 1afe142812
54 changed files with 1654 additions and 2841 deletions

View File

@ -23,6 +23,7 @@
#include "nserver.h"
#include "servlog.h"
extern void KeepStartupCommands(); /* ofac.c */
/***************************** Necessary Globals ****************************/
IPair *pSICSOptions = NULL;
@ -47,6 +48,8 @@ int main(int argc, char *argv[])
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-nolog") == 0) {
SICSLogEnable(0);
}else if(strcmp(argv[i],"-keepstartup") == 0){
KeepStartupCommands();
} else if (file == NULL) {
file = argv[i];
}

View File

@ -14,14 +14,14 @@
- a checkscript to be run at the end of driving the motor
- a means to call the write script multiple times. This is useful if
you need to drive to the value in multiple steps. An example is the
BOA double crystal monochromator where you first have to pu the baldes to
BOA double crystal monochromator where you first have to put the blades to
0, then drive the translation and then drive the blades to the real theta.
All this to avoid collisions. In order to support this, a state field and
and a readable target field has been added. The mode of operation is such
that the on first run the, writescript set the state to something different
then idle. This causes after the first set of motors finished running the
writescript to be called again. This can figure out by lookin at the
state variable what to do. This can be doen in repetition until the
state variable what to do. This can be done in repetition until the
writescript sets state to idle again.
Mark Koennecke, April 2012

View File

@ -61,7 +61,7 @@ typedef struct {
char *pName;
} MonEvent, *pMonEvent;
/*--------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------*/
static int Halt(void *pData)
{
pCounter self = NULL;
@ -444,12 +444,13 @@ int MakeCounter(SConnection * pCon, SicsInterp * pSics, void *pData,
assert(pCon);
assert(pSics);
argtolower(argc, argv);
if (argc < 3) {
SCWrite(pCon, "ERROR: insuficient number of arguments to MakeCounter",
eError);
return 0;
}
strtolower(argv[1]);
strtolower(argv[2]);
site = getSite();
if (site != NULL) {
pDriv = site->CreateCounterDriver(pCon, argc, argv);

835
devexec.c

File diff suppressed because it is too large Load Diff

View File

@ -184,5 +184,7 @@
*/
void *GetExecutorCallback(pExeList self);
/*----------------------- Logging -----------------------------------------*/
void DevexecLog(char *op, char *device);
void DevexecLog(char *op, char *device);
void ExeInterest(pExeList pExe, char *name, char *action);
void InvokeNewTarget(pExeList pExe, char *name, float fTarget);
#endif

View File

@ -373,7 +373,9 @@ to the global SICS device executor.
\mbox{}\verb@ */ @\\
\mbox{}\verb@ void *GetExecutorCallback(pExeList self);@\\
\mbox{}\verb@/*----------------------- Logging -----------------------------------------*/@\\
\mbox{}\verb@ void DevexecLog(char *op, char *device); @\\
\mbox{}\verb@ void DevexecLog(char *op, char *device);@\\
\mbox{}\verb@ void ExeInterest(pExeList pExe, char *name, char *action); @\\
\mbox{}\verb@ void InvokeNewTarget(pExeList pExe, char *name, float fTarget);@\\
\mbox{}\verb@#endif @\\
\mbox{}\verb@@$\Diamond$
\end{list}

View File

@ -319,7 +319,9 @@ to the global SICS device executor.
*/
void *GetExecutorCallback(pExeList self);
/*----------------------- Logging -----------------------------------------*/
void DevexecLog(char *op, char *device);
void DevexecLog(char *op, char *device);
void ExeInterest(pExeList pExe, char *name, char *action);
void InvokeNewTarget(pExeList pExe, char *name, float fTarget);
#endif
@}

481
difrac.c
View File

@ -1,481 +0,0 @@
/*-------------------------------------------------------------------------
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;
}

View File

@ -1,14 +0,0 @@
/*--------------------------------------------------------------------------
D I F R A C
Header file for the interface between SICS and the F77 package
DIFRAC. Only the factory routine is defined.
Mark Koennecke, November 1999
--------------------------------------------------------------------------*/
#ifndef DIFRAC
#define DIFRAC
int MakeDifrac(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[]);
#endif

89
drive.c
View File

@ -160,7 +160,7 @@ int Start2Run(SConnection * pCon, SicsInterp * pInter, char *name,
/* check if user is allowed to drive */
if (!SCMatchRights(pCon, usUser)) {
snprintf(pBueffel,511, "Insuficient Privilege to drive %s", name);
snprintf(pBueffel,511, "ERROR: Insuficient Privilege to drive %s", name);
SCWrite(pCon, pBueffel, eError);
return 0;
}
@ -168,7 +168,7 @@ int Start2Run(SConnection * pCon, SicsInterp * pInter, char *name,
/* first try to find the thing to drive */
pObject = FindCommand(pInter, name);
if (!pObject) {
snprintf(pBueffel,511, "Cannot find %s to drive ", name);
snprintf(pBueffel,511, "ERROR: Cannot find %s to drive ", name);
SCWrite(pCon, pBueffel, eError);
return 0;
}
@ -179,7 +179,7 @@ int Start2Run(SConnection * pCon, SicsInterp * pInter, char *name,
pDum = (Dummy *) pObject->pData;
pDes = pDum->pDescriptor;
if (!pDes) {
snprintf(pBueffel,511, "%s is NOT drivable!", pDes->name);
snprintf(pBueffel,511, "ERROR: %s is NOT drivable!", pDes->name);
SCWrite(pCon, pBueffel, eError);
return 0;
}
@ -189,14 +189,14 @@ int Start2Run(SConnection * pCon, SicsInterp * pInter, char *name,
*/
pInt = pDes->GetInterface(pDum, DRIVEID);
if (!pInt) {
snprintf(pBueffel,511, "%s is NOT drivable!", pDes->name);
snprintf(pBueffel,511, "ERROR: %s is NOT drivable!", pDes->name);
SCWrite(pCon, pBueffel, eError);
return 0;
}
if (pInt) {
iRet = pInt->CheckLimits(pDum, fNew, pBueffel, 511);
if (!iRet) {
SCWrite(pCon, pBueffel, eError);
SCPrintf(pCon, eError, "ERROR: %s", pBueffel);
SCSetInterrupt(pCon, eAbortOperation);
return 0;
}
@ -207,7 +207,7 @@ int Start2Run(SConnection * pCon, SicsInterp * pInter, char *name,
return 1;
}
} else {
snprintf(pBueffel,511, "%s is NOT drivable", pDes->name);
snprintf(pBueffel,511, "ERROR: %s is NOT drivable", pDes->name);
SCWrite(pCon, pBueffel, eError);
return 0;
}
@ -426,7 +426,72 @@ int RunWrapper(SConnection * pCon, SicsInterp * pSics, void *pData,
}
return 1;
}
/*---------------------------------------------------------------------------*/
int MoveWrapper(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[])
{
Tcl_Interp *tcl_interp;
int iRet, i;
double dTarget;
float curPos;
char pBueffel[512];
Status eOld;
long groupID, taskID;
void *obj;
assert(pCon);
assert(pSics);
tcl_interp = InterpGetTcl(pSics);
/* check Status */
eOld = GetStatus();
/* check no of args */
if (argc < 3) {
snprintf(pBueffel,511, "Insufficient number of args. Usage %s name val",
argv[0]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
/* check authorisation */
if (!SCMatchRights(pCon, usUser)) {
SCWrite(pCon,
"ERROR: You are not authorized to use the mv command",
eError);
return 0;
}
groupID = GetTaskGroupID(pServ->pTasker);
for (i = 1; i < argc; i += 2) {
if (argv[i + 1] == NULL) {
snprintf(pBueffel,511, "ERROR: no value found for driving %s", argv[i]);
SCWrite(pCon, pBueffel, eError);
SetStatus(eOld);
return 0;
}
iRet = Tcl_GetDouble(tcl_interp, argv[i + 1], &dTarget);
if (iRet == TCL_ERROR) {
SCWrite(pCon, Tcl_GetStringResult(tcl_interp), eError);
StopExe(GetExecutor(), "ALL");
SetStatus(eOld);
return 0;
}
obj = FindCommandData(pSics,argv[i],NULL);
if(obj == NULL || GetDrivableInterface(obj) == NULL){
SCPrintf(pCon,eError, "ERROR: %s not found, not started",argv[i]);
break;
}
GetDrivablePosition(obj,pCon,&curPos);
dTarget = curPos + dTarget;
taskID = StartDriveTask(obj, pCon, argv[i], (float)dTarget);
AddTaskToGroup(pServ->pTasker,taskID,groupID);
}
while(isTaskGroupRunning(pServ->pTasker,groupID)){
TaskYield(pServ->pTasker);
}
SCSendOK(pCon);
return 0;
}
/*---------------------------------------------------------------------------*/
int MakeDrive(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[])
@ -457,5 +522,17 @@ int MakeDrive(SConnection * pCon, SicsInterp * pSics, void *pData,
SCWrite(pCon, pBueffel, eError);
return 0;
}
if (argc > 3) {
iRet = AddCommand(pSics, argv[2], MoveWrapper, NULL, NULL);
} else {
iRet = AddCommand(pSics, "mv", MoveWrapper, NULL, NULL);
}
if (!iRet) {
sprintf(pBueffel, "ERROR: duplicate command mv not created");
SCWrite(pCon, pBueffel, eError);
return 0;
}
return 1;
}

View File

@ -1,622 +0,0 @@
/*----------------------------------------------------------------------------
This is a single counter implemented on top of the Risoe ECB electronic
copyright: see file COPYRIGHT
Mark Koennecke, January-February 2003
---------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <tcl.h>
#include <math.h>
#include <unistd.h>
#include "fortify.h"
#include "sics.h"
#include "status.h"
#include "psi/ecb.h"
#include "countdriv.h"
/*------------------ our private data structure ------------------------*/
typedef struct {
pECB ecb; /* the ECB system we talk to */
unsigned char prescaler[8]; /* an array for the prescaler values */
int tfreq; /* timer frequency */
unsigned char control; /* marks the control monitor */
int state; /* current counting state */
} ECBCounter, *pECBCounter;
/*----------------- private defines ------------------------------------*/
#define STFRD 137
#define STREAD 138
#define STOPS 136
#define STCLEA 134
#define PRELOA 139
#define STLOAD 156
#define STCPRE 133
#define STARTS 135
#define SPCSTA 169
/*------------------ state codes --------------------------------------*/
#define IDLE 0
#define COUNT 2
#define NOBEAM 3
/*--------------------------------------------------------------------*/
#define MAX_COUNT 4294967295.0
/*------------------ error codes --------------------------------------*/
#define COMMERROR -300
#define TOMANYCOUNTS -301
#define NOSEND -302
#define INVALIDCOUNTER -304
#define INVALIDPRESCALER -305
#define BADFREQ -306
/*======================================================================*/
static int readScaler(pECBCounter pPriv, int scaler, int *count)
{
int status;
Z80_reg in, out;
Ecb_pack data;
in.c = (unsigned char) scaler;
status = ecbExecute(pPriv->ecb, STREAD, in, &out);
if (status != 1) {
return COMMERROR;
}
data.b.byt3 = out.c;
data.b.byt2 = out.b;
data.b.byt1 = out.d;
data.b.byt0 = out.e;
if (scaler == 0) {
*count = data.result / pPriv->tfreq;
} else {
*count = data.result;
}
return 1;
}
/*---------------------------------------------------------------------*/
static int check4Beam(struct __COUNTER *pCter, int *beam)
{
Z80_reg in, out;
pECBCounter self = NULL;
int status;
self = (pECBCounter) pCter->pData;
assert(self);
in.c = 1;
status = ecbExecute(self->ecb, SPCSTA, in, &out);
if (status != 1) {
pCter->iErrorCode = COMMERROR;
return HWFault;
}
*beam = (int) out.d;
return 1;
}
/*----------------------------------------------------------------------*/
static int stopScalers(pECBCounter self)
{
int status;
Z80_reg in, out;
status = ecbExecute(self->ecb, STOPS, in, &out);
if (status != 1) {
return COMMERROR;
}
return 1;
}
/*========================================================================
These two functions currently rely on the idea that the ECB stops
and starts without clearing counters in between. The sequence of
things necessary to start it, suggests this. If this is not the case then
this will not work.
===========================================================================*/
static int ECBPause(struct __COUNTER *self)
{
int status;
pECBCounter pPriv = NULL;
assert(self);
pPriv = (pECBCounter) self->pData;
assert(pPriv);
if ((status = stopScalers(pPriv)) <= 0) {
self->iErrorCode = status;
return HWFault;
}
return OKOK;
}
/*=======================================================================*/
static int ECBContinue(struct __COUNTER *self)
{
int status;
pECBCounter pPriv = NULL;
Z80_reg in, out;
assert(self);
pPriv = (pECBCounter) self->pData;
assert(pPriv);
status = ecbExecute(pPriv->ecb, STARTS, in, &out);
if (status != 1) {
self->iErrorCode = status;
return HWFault;
}
return OKOK;
}
/*-----------------------------------------------------------------------*/
static int ECBGetStatus(struct __COUNTER *self, float *fControl)
{
pECBCounter pPriv = (pECBCounter) self->pData;
int status, result, scaler;
Z80_reg in, out;
int count, beam;
assert(pPriv);
/*
This can happen after a stop
*/
if (pPriv->state == IDLE) {
ECBTransfer(self);
return HWIdle;
}
/*
read status bit
*/
status = ecbExecute(pPriv->ecb, STFRD, in, &out);
if (status != 1) {
self->iErrorCode = COMMERROR;
pPriv->state = IDLE;
return HWFault;
}
/*
read beam status
*/
status = check4Beam(self, &beam);
if (status != 1) {
self->iErrorCode = COMMERROR;
return HWFault;
}
beam &= 1;
/*
sophisticated logic in order to keep track of the various states
the thing can be in. Complicated by the fact that the status becomes
idle (out.d = 0) when the measurement is paused due to the lack of
beam.
*/
if (pPriv->state == COUNT && beam == 1) {
ECBPause(self);
pPriv->state = NOBEAM;
SetStatus(eOutOfBeam);
result = HWNoBeam;
}
if (pPriv->state == NOBEAM && beam == 0) {
ECBContinue(self);
pPriv->state = COUNT;
SetStatus(eCounting);
return HWBusy;
}
if (pPriv->state == NOBEAM && beam == 1) {
return HWNoBeam;
}
if (out.d == 0 && pPriv->state == COUNT) {
result = HWIdle;
ECBTransfer(self);
pPriv->state = IDLE;
} else {
result = HWBusy;
}
/*
select which scaler to read
*/
if (self->eMode == eTimer) {
scaler = 0;
} else {
scaler = pPriv->control;
}
readScaler(pPriv, scaler, &count);
/*
ignore errors on this one
*/
*fControl = (float) count;
return result;
}exit
/*=====================================================================*/
static int clearScalers(pECBCounter self)
{
int status;
Z80_reg in, out;
status = ecbExecute(self->ecb, STCLEA, in, &out);
if (status != 1) {
return COMMERROR;
}
return 1;
}
/*----------------------------------------------------------------------*/
static int loadPrescalers(pECBCounter self)
{
Z80_reg in, out;
int status, i;
for (i = 0; i < 8; i++) {
in.c = (unsigned char) i;
in.d = self->prescaler[i];
status = ecbExecute(self->ecb, PRELOA, in, &out);
if (status != 1) {
return COMMERROR;
}
}
return 1;
}
/*----------------------------------------------------------------------*/
static int loadPreset(pECBCounter self, int preset, unsigned char control)
{
Z80_reg in, out;
Ecb_pack data;
int status, i;
data.result = preset;
in.c = data.b.byt3;
in.b = data.b.byt2;
in.e = data.b.byt1;
in.d = data.b.byt0;
status = ecbExecute(self->ecb, STLOAD, in, &out);
if (status != 1) {
return COMMERROR;
}
in.b = data.b.byt2;
in.e = data.b.byt1;
in.d = data.b.byt0;
in.c = 4 * control;
status = ecbExecute(self->ecb, STCPRE, in, &out);
if (status != 1) {
return COMMERROR;
}
return 1;
}
/*-----------------------------------------------------------------------*/
static int ECBStart(struct __COUNTER *self)
{
pECBCounter pPriv = NULL;
int preset, status, controlUnit;
Z80_reg in, out;
assert(self);
pPriv = (pECBCounter) self->pData;
assert(pPriv);
/*
check if the preset is permissible
*/
preset = (int) rint(self->fPreset);
if (preset > MAX_COUNT) {
self->iErrorCode = TOMANYCOUNTS;
return HWFault;
}
if (self->eMode == eTimer) {
controlUnit = 0;
preset *= pPriv->tfreq;
if (preset > MAX_COUNT) {
self->iErrorCode = TOMANYCOUNTS;
return HWFault;
}
} else {
controlUnit = pPriv->control;
}
if ((status = stopScalers(pPriv)) <= 0) {
self->iErrorCode = status;
return HWFault;
}
if ((status = clearScalers(pPriv)) <= 0) {
self->iErrorCode = status;
return HWFault;
}
if ((status = loadPrescalers(pPriv)) <= 0) {
self->iErrorCode = status;
return HWFault;
}
if ((status =
loadPreset(pPriv, preset, (unsigned char) controlUnit)) <= 0) {
self->iErrorCode = status;
return HWFault;
}
status = ecbExecute(pPriv->ecb, STARTS, in, &out);
if (status != 1) {
self->iErrorCode = status;
return HWFault;
}
pPriv->state = COUNT;
return OKOK;
}
/*=======================================================================*/
static int ECBHalt(struct __COUNTER *self)
{
int status;
pECBCounter pPriv = NULL;
assert(self);
pPriv = (pECBCounter) self->pData;
assert(pPriv);
pPriv->state = IDLE;
if ((status = stopScalers(pPriv)) <= 0) {
self->iErrorCode = status;
return HWFault;
}
return OKOK;
}
/*=======================================================================*/
static int ECBTransfer(struct __COUNTER *self)
{
int status, count, i;
pECBCounter pPriv = NULL;
assert(self);
pPriv = (pECBCounter) self->pData;
assert(pPriv);
/*
read time
*/
status = readScaler(pPriv, 0, &count);
if (status <= 0) {
self->iErrorCode = COMMERROR;
return HWFault;
}
self->fTime = (float) count;
/*
read other scalers
*/
for (i = 1; i < 8; i++) {
status = readScaler(pPriv, i, &count);
if (status <= 0) {
self->iErrorCode = COMMERROR;
return HWFault;
}
self->lCounts[i - 1] = count;
}
return OKOK;
}
/*======================================================================*/
static int ECBGetError(struct __COUNTER *self, int *iCode,
char *errorText, int errlen)
{
char pBueffel[132];
*iCode = self->iErrorCode;
switch (self->iErrorCode) {
case COMMERROR:
strlcpy(errorText, "Communication error with ECB", errlen);
break;
case TOMANYCOUNTS:
strlcpy(errorText, "Preset is to high!", errlen);
break;
case NOSEND:
strlcpy(errorText, "Cannot send naked data to ECB", errlen);
break;
case UNKNOWNPAR:
strlcpy(errorText, "parameter unknown", errlen);
break;
case INVALIDCOUNTER:
strlcpy(errorText, "Invalid counter number requested, 0-7 allowed",
errlen);
break;
case INVALIDPRESCALER:
strlcpy(errorText, "Invalid prescaler value, allowed 1 or 10", errlen);
break;
case BADFREQ:
strlcpy(errorText, "Bad timer frequency: 10 or 1000 allowed", errlen);
break;
default:
sprintf(pBueffel, "Unknown error code %d", self->iErrorCode);
strlcpy(errorText, pBueffel, errlen);
break;
}
return 1;
}
/*=======================================================================*/
static int ECBFixIt(struct __COUNTER *self, int iCode)
{
return COTERM;
}
/*======================================================================*/
/*******************************************************************************
* Load the parameters 'dot' and 'divide' for a motor or an encoder.
* 'dot' specifies the placement of a punctuation mark on the display
* of f.ex a motor position. 'divide' specifies how many times the po-
* sition is to be divided by two before it is displayed.
******************************************************************************/
static void Dot_divide(int device, int data, pECB ecb)
{
int function, dot, divide;
Z80_reg x_inreg, out;
if (data == 0) /* If zero, dont send dot/divide) */
return;
dot = 0;
while ((data % 10) == 0) {
dot++;
data /= 10;
}
divide = 0;
while ((data % 2) == 0) {
divide++;
data /= 2;
}
if (data != 1) /* If != 1, not a binary No. */
return;
if (dot > 0)
dot = 8 - dot;
x_inreg.c = 0; /* Specify input */
x_inreg.b = (unsigned char) device;
x_inreg.d = (unsigned char) dot; /* Dot position */
x_inreg.e = (unsigned char) divide; /* No. of times to divide by 2 */
ecbExecute(ecb, 170, x_inreg, &out);
return;
}
/*-----------------------------------------------------------------------*/
static int ECBSet(struct __COUNTER *self, char *name,
int iCter, float fVal)
{
pECBCounter pPriv = NULL;
int iVal;
assert(self);
pPriv = (pECBCounter) self->pData;
assert(pPriv);
iVal = (int) rint(fVal);
if (strcmp(name, "prescaler") == 0) {
if (iCter < 0 || iCter > 7) {
self->iErrorCode = INVALIDCOUNTER;
return HWFault;
}
if (iVal != 1 && iVal != 10) {
self->iErrorCode = INVALIDPRESCALER;
return HWFault;
}
pPriv->prescaler[iCter] = (unsigned char) iVal;
return OKOK;
} else if (strcmp(name, "tfreq") == 0) {
if (fVal == 1000) {
pPriv->prescaler[0] = 1;
pPriv->tfreq = 1000;
Dot_divide(64, 1000, pPriv->ecb);
return OKOK;
} else if (fVal == 10) {
pPriv->tfreq = 10;
pPriv->prescaler[0] = 10;
Dot_divide(64, 10, pPriv->ecb);
return OKOK;
} else {
self->iErrorCode = BADFREQ;
return HWFault;
}
} else {
self->iErrorCode = UNKNOWNPAR;
return HWFault;
}
}
/*===================================================================*/
static int ECBGet(struct __COUNTER *self, char *name,
int iCter, float *fVal)
{
pECBCounter pPriv = NULL;
assert(self);
pPriv = (pECBCounter) self->pData;
assert(pPriv);
if (strcmp(name, "prescaler") == 0) {
*fVal = (float) pPriv->prescaler[iCter];
return OKOK;
} else if (strcmp(name, "tfreq") == 0) {
*fVal = (float) pPriv->tfreq;
return OKOK;
} else {
self->iErrorCode = UNKNOWNPAR;
return HWFault;
}
}
/*=====================================================================*/
static int ECBSend(struct __COUNTER *self, char *text,
char *reply, int replylen)
{
strlcpy(reply, "ECB does not feast on ASCII strings, refused!",
replylen);
return OKOK;
}
/*====================================================================*/
pCounterDriver MakeECBCounter(char *ecb)
{
pECBCounter pPriv = NULL;
pCounterDriver self = NULL;
int i;
/*
memory for everybody
*/
self = CreateCounterDriver("ecb", "ecb");
pPriv = (pECBCounter) malloc(sizeof(ECBCounter));
if (self == NULL || pPriv == NULL) {
return NULL;
}
memset(pPriv, 0, sizeof(ECBCounter));
/*
initialize private data structure
*/
pPriv->ecb = (pECB) FindCommandData(pServ->pSics, ecb, "ECB");
if (pPriv->ecb == NULL) {
DeleteCounterDriver(self);
free(pPriv);
return NULL;
}
for (i = 0; i < 8; i++) {
pPriv->prescaler[i] = 1;
}
pPriv->tfreq = 1000;
pPriv->control = 1;
/*
assign function pointers
*/
self->GetStatus = ECBGetStatus;
self->Start = ECBStart;
self->Pause = ECBPause;
self->Continue = ECBContinue;
self->Halt = ECBHalt;
self->ReadValues = ECBTransfer;
self->GetError = ECBGetError;
self->TryAndFixIt = ECBFixIt;
self->Set = ECBSet;
self->Get = ECBGet;
self->Send = ECBSend;
self->KillPrivate = NULL;
self->pData = pPriv;
return self;
}

View File

@ -1,17 +0,0 @@
/*-------------------------------------------------------------------------
Header file for the counter driver for the Risoe ECB system.
copyright: see file COPYRIGHT
Mark Koennecke, January 2003
-------------------------------------------------------------------------*/
#ifndef ECBCOUNTER
#define ECBCOUNTER
#include "countdriv.h"
pCounterDriver MakeECBCounter(char *ecb);
void KillECBCounter(CounterDriver * pDriv);
#endif

313
epicsmotor.c Normal file
View File

@ -0,0 +1,313 @@
/**
* This is a very basic first generation SICS EPICS motor driver for testing.
* It should be replaced by a second generation version when SINQ gets serious
* about EPICS and SICS.
*
* Mark Koennecke, February 2012
*/
#include <stdlib.h>
#include <sics.h>
#include <modriv.h>
/* EPICS stuff */
#include <tsDefs.h>
#include <cadef.h>
#include <ezca.h>
#include <alarmString.h>
#include <menuAlarmStat.h>
#include <db_access.h>
#include <epicsThread.h>
typedef struct __epicsMoDriv{
/* general motor driver interface
fields. REQUIRED!
*/
float fUpper; /* upper limit */
float fLower; /* lower limit */
char *name;
int (*GetPosition)(void *self, float *fPos);
int (*RunTo)(void *self,float fNewVal);
int (*GetStatus)(void *self);
void (*GetError)(void *self, int *iCode, char *buffer, int iBufLen);
int (*TryAndFixIt)(void *self, int iError,float fNew);
int (*Halt)(void *self);
int (*GetDriverPar)(void *self, char *name,
float *value);
int (*SetDriverPar)(void *self,SConnection *pCon,
char *name, float newValue);
void (*ListDriverPar)(void *self, char *motorName,
SConnection *pCon);
void (*KillPrivate)(void *self);
/* your drivers private fields follow below */
char *motBaseName;
char *ezcaError;
int ezcaCode;
int connectCount;
} epicsMotorDriver;
/*================================================================
GetPos returns OKOK on success, HWFault on failure
------------------------------------------------------------------*/
static int epicsGetPos(void *data, float *fPos){
epicsMotorDriver *self = NULL;
char fullName[132];
int status;
double position;
self = (epicsMotorDriver *)data;
snprintf(fullName,sizeof(fullName),"%s.DRBV",self->motBaseName);
status = ezcaGet(fullName,ezcaDouble,1, &position);
if(status == EZCA_OK){
*fPos =(float) position;
self->connectCount = 0;
return OKOK;
} else {
ezcaGetErrorString("ERROR: EPICS: ", &self->ezcaError);
self->ezcaCode = status;
return HWFault;
}
}
/*-------------- dummy callback for runto -------------------------*/
static void RunToDummy(struct event_handler_args d)
{
}
/*----------------------------------------------------------------
RunTo starts the motor running. Returns OKOK on success, HWfault
on Errors
------------------------------------------------------------------*/
static int epicsRunTo(void *data, float newValue){
epicsMotorDriver *self = NULL;
char fullName[132];
double position = newValue;
int status;
chid *cid;
self = (epicsMotorDriver *)data;
snprintf(fullName,sizeof(fullName),"%s.DVAL",self->motBaseName);
ezcaPvToChid(fullName,&cid);
status = ca_put_callback(DBR_DOUBLE,*cid,&position, RunToDummy,NULL);
if(status != ECA_NORMAL){
snprintf(fullName, sizeof(fullName),"Bad CA status %d", status);
self->ezcaError = strdup(fullName);
self->ezcaCode = status;
return HWFault;
} else {
ca_pend_event(.05);
self->connectCount = 0;
return OKOK;
}
}
/*------------------------------------------------------------------
CheckStatus queries the sattus of a running motor. Possible return
values can be:
HWBusy : motor still running
HWFault : motor error detected
HWPosFault : motor finished, but position not reached
HWIdle : motor finished OK
HWWarn : motor issued warning
--------------------------------------------------------------------*/
static int epicsCheckStatus(void *data){
epicsMotorDriver *self = NULL;
char fullName[132];
short smov, stat;
int status;
self = (epicsMotorDriver *)data;
snprintf(fullName,sizeof(fullName),"%s.DMOV",self->motBaseName);
status = ezcaGet(fullName,ezcaShort,1, &smov);
if(status == EZCA_OK){
self->connectCount = 0;
if(smov == 0){
return HWBusy;
} else {
snprintf(fullName,sizeof(fullName),"%s.STAT",self->motBaseName);
status = ezcaGet(fullName,ezcaShort,1, &stat);
if(stat != menuAlarmStatNO_ALARM){
snprintf(fullName,sizeof(fullName),"EPICS ALARM: %s", epicsAlarmConditionStrings[stat]);
self->ezcaError = strdup(fullName);
return HWFault;
} else {
return HWIdle;
}
}
} else {
ezcaGetErrorString("ERROR: EPICS: ", &self->ezcaError);
self->ezcaCode = status;
return HWFault;
}
}
/*------------------------------------------------------------------
GetError gets more information about error which occurred
*iCode is an integer error code to be used in TryFixIt as indicator
buffer is a buffer for a text description of the problem
iBufLen is the length of buffer
--------------------------------------------------------------------*/
static void epicsGetError(void *data, int *iCode, char *buffer,
int iBufLen){
epicsMotorDriver *self = NULL;
self = (epicsMotorDriver *)data;
if(self->ezcaError != NULL){
strncpy(buffer,self->ezcaError,iBufLen);
ezcaFree(self->ezcaError);
self->ezcaError = NULL;
}
}
/*------------------------------------------------------------------
TryAndFixIt tries everything which is possible in software to fix
a problem. iError is the error code from GetError, newValue is
the target value for the motor
Possible retrun values are:
MOTOK : everything fixed
MOTREDO : try again
MOTFAIL : cannot fix this
--------------------------------------------------------------------*/
static int epicsFixIt(void *data, int iError, float newValue){
epicsMotorDriver *self = NULL;
self = (epicsMotorDriver *)data;
if(self->ezcaCode == EZCA_NOTCONNECTED && self->connectCount < 2) {
self->connectCount++;
return MOTREDO;
}
return MOTFAIL;
}
/*-------------------------------------------------------------------
Halt tries to stop the motor. Halt errors are ignored.
For some as yet unknown reasons, I cannot send the stop on the
same CA line then the rest. But with a new thread which just sends
the stop, it works. This is a straightforward use of a thread:
do your thing and terminate. Do not interact with other parts
of the program.
---------------------------------------------------------------------*/
static void HaltThreadFunc(void *param)
{
char *pvName = (char *)param;
short stop = 1;
chid cid;
ca_context_create(ca_disable_preemptive_callback);
ca_create_channel(pvName,NULL,NULL,10,&cid);
ca_pend_io(5.);
ca_put(DBR_SHORT,cid,&stop);
ca_pend_io(5.0);
free(pvName);
printf("HaltThread ends\n");
}
/*-------------------------------------------------------------------*/
static int epicsHalt(void *data){
epicsMotorDriver *self = NULL;
char fullName[132];
short stop =1;
chid *cid;
int status;
self = (epicsMotorDriver *)data;
snprintf(fullName,sizeof(fullName),"%s.STOP",self->motBaseName);
/* ezcaStartGroup(); */
/* ezcaPut(fullName,ezcaShort,1,&stop); */
/* ezcaEndGroup(); */
/* ezcaPvToChid(fullName,&cid); */
/* status = ca_put_callback(DBR_SHORT,*cid,&stop, RunToDummy,NULL); */
/* printf("Halt status %d\n", status); */
/* ca_flush_io(); */
/* printf("Halt after poll\n"); */
epicsThreadCreate("Hugo",
epicsThreadPriorityHigh,
epicsThreadStackMedium,
HaltThreadFunc,
(void *)strdup(fullName));
return 1;
}
/*--------------------------------------------------------------------
GetDriverPar retrieves the value of a driver parameter.
Name is the name of the parameter, fValue the value when found.
Returns 0 on success, 0 else
-----------------------------------------------------------------------*/
static int epicsGetDriverPar(void *data, char *name, float *value){
epicsMotorDriver *self = NULL;
self = (epicsMotorDriver *)data;
return 0;
}
/*----------------------------------------------------------------------
SetDriverPar sets a driver parameter. Returns 0 on failure, 1 on
success. Name is the parameter name, pCon the connection to report
errors too, value the new value
------------------------------------------------------------------------*/
static int epicsSetDriverPar(void *data, SConnection *pCon,
char *name, float value){
epicsMotorDriver *self = NULL;
self = (epicsMotorDriver *)data;
return 0;
}
/*-----------------------------------------------------------------------
ListDriverPar lists the names and values of driver parameters to
pCon. Motorname is the name of the motor ro prefix to the listing.
-------------------------------------------------------------------------*/
static void epicsListDriverPar(void *data, char *motorname,
SConnection *pCon){
epicsMotorDriver *self = NULL;
self = (epicsMotorDriver *)data;
}
/*-----------------------------------------------------------------------
KillPrivate has the task to delete possibly dynamically allocated
memory in the private part of the driver structure
------------------------------------------------------------------------*/
static void epicsKillPrivate(void *data){
epicsMotorDriver *self = NULL;
self = (epicsMotorDriver *)data;
if(self->ezcaError != NULL){
ezcaFree(self->ezcaError);
}
if(self->motBaseName != NULL){
free(self->motBaseName);
}
}
/*=======================================================================*/
MotorDriver *epicsMakeMotorDriver(char *baseName) {
epicsMotorDriver *pNew = NULL;
char fullName[132];
double limit;
pNew = malloc(sizeof(epicsMotorDriver));
if(pNew == NULL){
return NULL;
}
memset(pNew,0,sizeof(epicsMotorDriver));
pNew->motBaseName = strdup(baseName);
snprintf(fullName,sizeof(fullName),"%s.DRBV",pNew->motBaseName);
ezcaSetMonitor(fullName,ezcaDouble,1);
snprintf(fullName,sizeof(fullName),"%s.DMOV",pNew->motBaseName);
ezcaSetMonitor(fullName,ezcaShort,1);
snprintf(fullName,sizeof(fullName),"%s.STAT",pNew->motBaseName);
ezcaSetMonitor(fullName,ezcaShort,1);
snprintf(fullName,sizeof(fullName),"%s.HLM",pNew->motBaseName);
ezcaGet(fullName,ezcaDouble,1, &limit);
pNew->fUpper = limit;
snprintf(fullName,sizeof(fullName),"%s.LLM",pNew->motBaseName);
ezcaGet(fullName,ezcaDouble,1, &limit);
pNew->fLower = limit;
pNew->GetPosition = epicsGetPos;
pNew->RunTo = epicsRunTo;
pNew->Halt = epicsHalt;
pNew->GetStatus = epicsCheckStatus;
pNew->GetError = epicsGetError;
pNew->TryAndFixIt = epicsFixIt;
pNew->GetDriverPar = epicsGetDriverPar;
pNew->SetDriverPar = epicsSetDriverPar;
pNew->ListDriverPar = epicsListDriverPar;
pNew->KillPrivate = epicsKillPrivate;
/* ezcaTraceOn(); */
return (MotorDriver *)pNew;
}

View File

@ -71,6 +71,8 @@ static char *pEvent[] = {
"STATEEND",
"NEWTARGET",
"DIMCHANGE",
"PAUSE",
"CONTINUE",
NULL
};

12
event.h
View File

@ -1,5 +1,5 @@
#line 103 "event.w"
#line 108 "event.w"
/*----------------------------------------------------------------------------
E V E N T
@ -18,7 +18,7 @@
int Text2Event(char *pText);
#line 116 "event.w"
#line 121 "event.w"
@ -49,8 +49,10 @@
#define STEND 22
#define NEWTARGET 23
#define DIMCHANGE 24
#define IPAUSE 25
#define CONTINUE 26
#line 118 "event.w"
#line 123 "event.w"
/*----------------- event data structure for the NEWTARGET event ---------*/
@ -60,7 +62,7 @@ typedef struct {
} NewTarget, *pNewTarget;
/*--------------- Signals for the Signalfunction of each task ------------*/
#line 85 "event.w"
#line 90 "event.w"
#define SICSINT 300
#define SICSBROADCAST 301
@ -69,6 +71,6 @@ typedef struct {
#define COMLOG 304
#define CRONLIST 305
#line 126 "event.w"
#line 131 "event.w"
#endif

View File

@ -60,6 +60,8 @@ $\langle$VE {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@#define STEND 22@\\
\mbox{}\verb@#define NEWTARGET 23@\\
\mbox{}\verb@#define DIMCHANGE 24@\\
\mbox{}\verb@#define IPAUSE 25@\\
\mbox{}\verb@#define CONTINUE 26@\\
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-1ex}
@ -99,8 +101,11 @@ operation.
\item[HDBVAL] The Hdb is notified of a value change. The eventData will be
the object on which the data changed.
\item[NEWTARGET] is invoked when a new target has been set on a drivable.
\item[PAUSE] Pause counting
\item[CONTINUE] Continue counting
\end{description}
Furthermore event contains system wide signal codes which are interpreted in
the signal functions provided by each SICS task. These code are
evaluated by the TaskSignalFunction which may be configured for each

View File

@ -43,6 +43,8 @@ if the event code is not known, else the apropriate event code.
#define STEND 22
#define NEWTARGET 23
#define DIMCHANGE 24
#define IPAUSE 25
#define CONTINUE 26
@}
\begin{description}
\item[VALUECHANGE] This is a variable changing its value. As event data a pointer to the
@ -74,8 +76,11 @@ operation.
\item[HDBVAL] The Hdb is notified of a value change. The eventData will be
the object on which the data changed.
\item[NEWTARGET] is invoked when a new target has been set on a drivable.
\item[PAUSE] Pause counting
\item[CONTINUE] Continue counting
\end{description}
Furthermore event contains system wide signal codes which are interpreted in
the signal functions provided by each SICS task. These code are
evaluated by the TaskSignalFunction which may be configured for each

View File

@ -17,6 +17,10 @@
* copyright: see file COPYRIGHT
*
* Mark Koennecke, March 2009
*
* Added CountTblCmd
*
* Mark Koennecke, march 2013
*/
#include <stdlib.h>
#include "sicshipadaba.h"
@ -75,6 +79,20 @@ static int ClearTblCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
return 1;
}
/*----------------------------------------------------------------------*/
int CountTblCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
pHdb par[], int nPar)
{
pHdb node;
int nRows = 0;
node = GetHipadabaNode(self->objectNode,"data");
if(node != NULL){
nRows = CountHdbChildren(node);
}
SCPrintf(pCon,eValue,"rows = %d", nRows);
return 1;
}
/*----------------------------------------------------------------------*/
static int AddTblRowCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
pHdb par[], int nPar)
{
@ -470,6 +488,9 @@ pSICSOBJ MakeHdbTable(char *name, char *hdbclass)
SetHdbProperty(node,"priv","user");
AddHipadabaChild(cmd,node, NULL);
cmd = AddSICSHdbPar(result->objectNode, "count", usSpy,
MakeSICSFunc(CountTblCmd));
return result;
}
/*---------------------------------------------------------------------------*/

View File

@ -208,8 +208,8 @@ static int HistStartCount(void *pData, SConnection * pCon)
iRet = self->pDriv->Start(self->pDriv, pCon);
if (iRet == OKOK) {
/* send a COUNTSTART event */
clearHMData(self->pDriv->data);
InvokeCallBack(self->pCall, COUNTSTART, pCon);
updateHMData(self->pDriv->data);
return iRet;
} else {
iRet = self->pDriv->GetError(self->pDriv, &iErr, pError, 79);
@ -350,9 +350,9 @@ static int HistCountStatus(void *pData, SConnection * pCon)
return HWBusy;
}
}
if (eCt == HWBusy){
updateHMData(self->pDriv->data);
}
/* if (eCt == HWBusy){ */
/* updateHMData(self->pDriv->data); */
/* } */
if (eCt == HWIdle) {
/* force an update of local histogram data with next
@ -879,7 +879,7 @@ int GetHistogram(pHistMem self, SConnection * pCon,
eWarning);
iEnd = (iDataLen / sizeof(HistInt)) - 1;
}
return getHMDataHistogram(self, pCon, i, iStart, iEnd, lData);
return getHMDataHistogram(self, pCon, i, iStart, iEnd-iStart, lData);
}
/*-------------------------------------------------------------------------*/
@ -1335,6 +1335,22 @@ int HistAction(SConnection * pCon, SicsInterp * pSics, void *pData,
} else {
return 0;
}
} else if (strcmp(argv[1], "clearhm") == 0) {
/*
clear the local copy of the HM. Assumes that the HM
clears itself on start. Which it does.
*/
if (SCMatchRights(pCon, usUser)) {
if(self->pDriv->data != NULL){
clearHMData(self->pDriv->data);
SCSendOK(pCon);
return 1;
} else {
return 0;
}
} else {
return 0;
}
} else if (strcmp(argv[1], "list") == 0) {
HMListOption(self, pCon);
return 1;
@ -1798,4 +1814,5 @@ int HistAction(SConnection * pCon, SicsInterp * pSics, void *pData,
SCWrite(pCon, pBueffel, eError);
return 0;
}
return 0;
}

49
hkl.c
View File

@ -26,6 +26,10 @@
Heavily reworked to fit into the new four circle setup
Mark Koennecke, July 2008
Added calculation of angles between reflection
Mark Koennecke, March 2013
-----------------------------------------------------------------------------*/
#include <math.h>
#include <ctype.h>
@ -687,6 +691,47 @@ static int HKLCalculateTheta(pHKL self, float fHKL[3], double *stt)
*stt = 2. * theta;
return status;
}
/*-------------------------------------------------------------------------*/
static int HKLAngle(SConnection *pCon, int argc, char *argv[])
{
reflection r1, r2;
lattice direct;
const double *cell;
MATRIX B;
double ang;
if(argc < 8){
SCWrite(pCon,"ERROR: insufficient no of arguments to hkl angle",eError);
return 0;
}
r1.h = atof(argv[2]);
r1.k = atof(argv[3]);
r1.l = atof(argv[4]);
r2.h = atof(argv[5]);
r2.k = atof(argv[6]);
r2.l = atof(argv[7]);
cell = SXGetCell();
direct.a = cell[0];
direct.b = cell[1];
direct.c = cell[2];
direct.alpha = cell[3];
direct.beta = cell[4];
direct.gamma = cell[5];
B = mat_creat(3,3,ZERO_MATRIX);
if(B == NULL){
SCWrite(pCon,"ERROR: out of memory in HKL angle",eError);
return 0;
}
calculateBMatrix(direct,B);
ang = angleBetweenReflections(B,r1,r2);
SCPrintf(pCon,eValue,"angle = %f", ang);
mat_free(B);
return 1;
}
/*--------------------------------------------------------------------------*/
static int HandleBiToNB(SConnection *pCon, int argc, char *argv[])
{
@ -993,6 +1038,10 @@ int HKLAction(SConnection * pCon, SicsInterp * pSics, void *pData,
SCPrintf(pCon, eValue, "two-theta = %lf", stt);
return 1;
}
/*--------------- calculate angle */
else if (strcmp(argv[1], "angle") == 0) {
return HKLAngle(pCon,argc,argv);
}
/*------------------ run */
else if (strcmp(argv[1], "run") == 0) {
if (!SCMatchRights(pCon, usUser)) {

View File

@ -59,6 +59,7 @@ void clearHMData(pHMdata self)
size *= getNoOfTimebins(self);
}
memset(self->localBuffer, 0, size * sizeof(HistInt));
self->nextUpdate = time(NULL) + self->updateIntervall;
}
/*----------------------------------------------------------------------*/
@ -313,7 +314,7 @@ static int updateHMbuffer(pHistMem hist, int bank, SConnection * pCon)
}
if (status == OKOK) {
return 1;
} else {
} else {
return HWFault;
}
}

View File

@ -1,79 +0,0 @@
/*---------------------------------------------------------------------------
Client side implementation of the Interrupt interface.
Mark Koennecke, December 1996
Copyright:
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5423 Villigen-PSI
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
------------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include "fortify.h"
#include "network.h"
#include "interrupt.h"
static mkChannel *pChannel = NULL;
/*---------------------------------------------------------------------------*/
int ClientSetupInterrupt(char *host, int iPort)
{
pChannel = UDPConnect(host, iPort);
if (pChannel == NULL) {
return 0;
} else {
return 1;
}
}
/*---------------------------------------------------------------------------*/
void ClientStopInterrupt(void)
{
if (pChannel) {
NETClosePort(pChannel);
free(pChannel);
}
}
/*---------------------------------------------------------------------------*/
void SendInterrupt(int iCode)
{
char pBueffel[132];
if ((iCode < 0)) {
return;
}
snprintf(pBueffel,sizeof(pBueffel)-1, "SICSINT %d", iCode);
UDPWrite(pChannel, pBueffel, strlen(pBueffel));
}

View File

@ -1,4 +1,4 @@
/*--------------------------------------------------------------------------
/*--------------------------------------------------------------------------
I N T E R F A C E
@ -12,6 +12,11 @@
Paul Scherrer Institut
CH-5423 Villigen-PSI
Extended over time with utility functions
Added Drivable and Countable task functions
Mark Koennecke, February 2013
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
@ -42,6 +47,7 @@
#include "fortify.h"
#include "sics.h"
#include "motor.h"
#include <status.h>
/*=========================================================================
Empty driveable interface functions
==========================================================================*/
@ -168,7 +174,107 @@ int GetDrivablePosition(void *pObject, SConnection * pCon, float *fPos)
*fPos = value;
return 1;
}
/*--------------------------------------------------------------------------*/
typedef struct {
void *obj;
pIDrivable pDriv;
SConnection *pCon;
char *name;
}DriveTaskData;
/*-------------------------------------------------------------------------*/
static void KillDriveTaskData(void *data)
{
DriveTaskData *taskData = (DriveTaskData *)data;
if(taskData == NULL){
return;
}
if(taskData->name != NULL){
free(taskData->name);
}
if(taskData->pCon != NULL){
SCDeleteConnection(taskData->pCon);
}
}
/*-------------------------------------------------------------------------*/
static void DriveTaskSignal(void *data, int iSignal, void *pSigData)
{
DriveTaskData *taskData = (DriveTaskData *)data;
int *interrupt;
assert(taskData != NULL);
if(iSignal == SICSINT){
interrupt = (int *)pSigData;
if(*interrupt != eContinue){
SCPrintf(taskData->pCon,eLogError,"ERROR: Interrupting %s", taskData->name);
taskData->pDriv->Halt(taskData->obj);
SCSetInterrupt(taskData->pCon,*interrupt);
}
}
}
/*--------------------------------------------------------------------------*/
static int DriveTaskFunc(void *data)
{
DriveTaskData *taskData = (DriveTaskData *)data;
int status;
assert(taskData != NULL);
status = taskData->pDriv->CheckStatus(taskData->obj,taskData->pCon);
if(status == HWBusy){
return 1;
}
DevexecLog("STOP",taskData->name);
if(status == HWIdle || status == OKOK){
ExeInterest(pServ->pExecutor,taskData->name, "finished");
} else {
ExeInterest(pServ->pExecutor,taskData->name, "finished with problem");
}
return 0;
}
/*--------------------------------------------------------------------------*/
long StartDriveTask(void *obj, SConnection *pCon, char *name, float fTarget)
{
pIDrivable pDriv = NULL;
char error[132], buffer[132];
DriveTaskData *taskData = NULL;
pDriv = GetDrivableInterface(obj);
if(pDriv == NULL){
SCPrintf(pCon,eError,"ERROR: %s is not drivable", name);
return 1;
}
if(pDriv->CheckLimits(obj,fTarget,error,sizeof(error)) != OKOK){
SCPrintf(pCon,eError,"ERROR: %s cannot reach %f, reason %s", name,
fTarget, error);
return -1;
}
taskData = calloc(1,sizeof(DriveTaskData));
if(taskData == NULL){
SCPrintf(pCon,eError,"ERROR: out of memory starting %s", name);
return -1;
}
if(pDriv->SetValue(obj,pCon,fTarget) != OKOK){
return -1;
}
ExeInterest(pServ->pExecutor,name,"started");
DevexecLog("START",name);
InvokeNewTarget(pServ->pExecutor,name,fTarget);
taskData->obj = obj;
taskData->pDriv = pDriv;
taskData->pCon = SCCopyConnection(pCon);
taskData->name = strdup(name);
return TaskRegisterN(pServ->pTasker,
name,
DriveTaskFunc,
DriveTaskSignal,
KillDriveTaskData,
taskData,0);
}
/*--------------------------------------------------------------------------*/
pICountable GetCountableInterface(void *pObject)
{
@ -201,6 +307,112 @@ int isRunning(pICountable self)
{
return self->running;
}
/*--------------------------------------------------------------------------*/
typedef struct {
void *obj;
pICountable pCount;
SConnection *pCon;
char *name;
}CountTaskData;
/*-------------------------------------------------------------------------*/
static void KillCountTaskData(void *data)
{
CountTaskData *taskData = (CountTaskData *)data;
if(taskData == NULL){
return;
}
if(taskData->name != NULL){
free(taskData->name);
}
if(taskData->pCon != NULL){
SCDeleteConnection(taskData->pCon);
}
}
/*-------------------------------------------------------------------------*/
static void CountTaskSignal(void *data, int iSignal, void *pSigData)
{
CountTaskData *taskData = (CountTaskData *)data;
int *interrupt;
assert(taskData != NULL);
if(iSignal == SICSINT){
interrupt = (int *)pSigData;
if(*interrupt != eContinue){
SCPrintf(taskData->pCon,eLogError,"ERROR: Interrupting %s", taskData->name);
taskData->pCount->Halt(taskData->obj);
SCSetInterrupt(taskData->pCon,*interrupt);
}
} else if(iSignal == IPAUSE){
taskData->pCount->Pause(taskData->obj,taskData->pCon);
} else if(iSignal == CONTINUE){
taskData->pCount->Continue(taskData->obj,taskData->pCon);
}
}
/*--------------------------------------------------------------------------*/
static int CountTaskFunc(void *data)
{
CountTaskData *taskData = (CountTaskData *)data;
int status;
assert(taskData != NULL);
status = taskData->pCount->CheckCountStatus(taskData->obj,taskData->pCon);
if(status == HWBusy) {
SetStatus(eCounting);
return 1;
} else if(status == HWNoBeam){
SetStatus(eOutOfBeam);
return 1;
} else if(status == HWPause){
SetStatus(ePaused);
return 1;
}
DevexecLog("STOP",taskData->name);
if(status == HWIdle || status == OKOK){
ExeInterest(pServ->pExecutor,taskData->name, "finished");
} else {
ExeInterest(pServ->pExecutor,taskData->name, "finished with problem");
}
return 0;
}
/*--------------------------------------------------------------------------*/
long StartCountTask(void *obj, SConnection *pCon, char *name)
{
pICountable pCount = NULL;
char error[132], buffer[132];
CountTaskData *taskData = NULL;
pCount = FindInterface(obj,COUNTID);
if(pCount == NULL){
SCPrintf(pCon,eError,"ERROR: %s is not countable", name);
return 1;
}
taskData = calloc(1,sizeof(CountTaskData));
if(taskData == NULL){
SCPrintf(pCon,eError,"ERROR: out of memory starting %s", name);
return -1;
}
if(pCount->StartCount(obj,pCon) != OKOK){
return -1;
}
ExeInterest(pServ->pExecutor,name,"started");
DevexecLog("START",name);
taskData->obj = obj;
taskData->pCount = pCount;
taskData->pCon = SCCopyConnection(pCon);
taskData->name = strdup(name);
return TaskRegisterN(pServ->pTasker,
name,
CountTaskFunc,
CountTaskSignal,
KillCountTaskData,
taskData,0);
}
/*--------------------------------------------------------------------------*/
pICallBack GetCallbackInterface(void *pObject)

View File

@ -1,5 +1,5 @@
#line 399 "interface.w"
#line 412 "interface.w"
/*---------------------------------------------------------------------------
I N T E R F A C E S
@ -30,107 +30,113 @@
#line 121 "interface.w"
typedef struct {
int ID;
int (*Halt) (void *self);
int (*CheckLimits) (void *self, float fVal, char *error, int iErrLen);
long (*SetValue) (void *self, SConnection * pCon, float fVal);
int (*CheckStatus) (void *self, SConnection * pCon);
float (*GetValue) (void *self, SConnection * pCon);
int iErrorCount;
int drivableStatus;
} IDrivable, *pIDrivable;
typedef struct {
int ID;
int (*Halt)(void *self);
int (*CheckLimits)(void *self, float fVal,
char *error, int iErrLen);
long (*SetValue)(void *self, SConnection *pCon,
float fVal);
int (*CheckStatus)(void *self, SConnection *pCon);
float (*GetValue)(void *self, SConnection *pCon);
int iErrorCount;
int drivableStatus;
} IDrivable, *pIDrivable;
pIDrivable GetDrivableInterface(void *pObject);
int GetDrivablePosition(void *pObject, SConnection * pCon, float *fPos);
pIDrivable GetDrivableInterface(void *pObject);
int GetDrivablePosition(void *pObject, SConnection *pCon,
float *fPos);
long StartDriveTask(void *self, SConnection *pCon, char *name, float fTarget);
#line 425 "interface.w"
pIDrivable CreateDrivableInterface(void);
/* ------------------------ The countable interface ---------------------*/
#line 188 "interface.w"
typedef struct {
int ID;
int running;
int (*Halt) (void *self);
void (*SetCountParameters) (void *self, float fPreset,
CounterMode eMode);
int (*StartCount) (void *self, SConnection * pCon);
int (*CheckCountStatus) (void *self, SConnection * pCon);
int (*Pause) (void *self, SConnection * pCon);
int (*Continue) (void *self, SConnection * pCon);
int (*TransferData) (void *self, SConnection * pCon);
} ICountable, *pICountable;
pICountable GetCountableInterface(void *pObject);
int GetCountLock(pICountable self, SConnection * pCon);
void ReleaseCountLock(pICountable self);
int isRunning(pICountable self);
#line 430 "interface.w"
pICountable CreateCountableInterface(void);
/* ------------------------- The CallBack Interface --------------------*/
#line 253 "interface.w"
typedef void (*KillFuncIT) (void *pData);
typedef int (*SICSCallBack) (int iEvent, void *pEventData,
void *pUserData);
#line 435 "interface.w"
#line 275 "interface.w"
typedef struct __ICallBack *pICallBack;
/* event source side */
pICallBack CreateCallBackInterface(void);
void DeleteCallBackInterface(pICallBack self);
int InvokeCallBack(pICallBack pInterface, int iEvent, void *pEventData);
/* callback client side */
long RegisterCallback(pICallBack pInterface,
int iEvent, SICSCallBack pFunc,
void *pUserData, KillFuncIT pKill);
int RemoveCallback(pICallBack pInterface, long iID);
int RemoveCallback2(pICallBack pInterface, void *pUserData);
int RemoveCallbackCon(pICallBack pInterface, SConnection * pCon);
int CallbackScript(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[]);
pICallBack GetCallbackInterface(void *pData);
#line 436 "interface.w"
/*---------------------- The Environment Interface --------------------*/
#line 353 "interface.w"
typedef enum { EVIdle, EVDrive, EVMonitor, EVError } EVMode;
typedef struct {
int iID;
EVMode(*GetMode) (void *self);
int (*IsInTolerance) (void *self);
int (*HandleError) (void *self);
} EVInterface, *pEVInterface;
#line 438 "interface.w"
#line 379 "interface.w"
pIDrivable CreateDrivableInterface(void);
pEVInterface CreateEVInterface(void);
/* ------------------------ The countable interface ---------------------*/
#line 439 "interface.w"
#line 195 "interface.w"
typedef struct {
int ID;
int running;
int (*Halt)(void *self);
void (*SetCountParameters)(void *self, float fPreset,
CounterMode eMode);\
int (*StartCount)(void *self, SConnection *pCon);
int (*CheckCountStatus)(void *self, SConnection *pCon);
int (*Pause)(void *self, SConnection *pCon);
int (*Continue)(void *self, SConnection *pCon);
int (*TransferData)(void *self, SConnection *pCon);
} ICountable, *pICountable;
pICountable GetCountableInterface(void *pObject);
int GetCountLock(pICountable self, SConnection *pCon);
void ReleaseCountLock(pICountable self);
int isRunning(pICountable self);
long StartCountTask(void *self, SConnection *pCon, char *name);
#line 443 "interface.w"
pICountable CreateCountableInterface(void);
/* ------------------------- The CallBack Interface --------------------*/
#line 266 "interface.w"
typedef void (*KillFuncIT)(void *pData);
typedef int (*SICSCallBack)(int iEvent, void *pEventData,
void *pUserData);
#line 448 "interface.w"
#line 288 "interface.w"
typedef struct __ICallBack *pICallBack;
/* event source side */
pICallBack CreateCallBackInterface(void);
void DeleteCallBackInterface(pICallBack self);
int InvokeCallBack(pICallBack pInterface, int iEvent, void *pEventData);
/* callback client side */
long RegisterCallback(pICallBack pInterface,
int iEvent, SICSCallBack pFunc,
void *pUserData, KillFuncIT pKill);
int RemoveCallback(pICallBack pInterface, long iID);
int RemoveCallback2(pICallBack pInterface, void *pUserData);
int RemoveCallbackCon(pICallBack pInterface, SConnection *pCon);
int CallbackScript(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
pICallBack GetCallbackInterface(void *pData);
#line 449 "interface.w"
/*---------------------- The Environment Interface --------------------*/
#line 366 "interface.w"
typedef enum { EVIdle, EVDrive, EVMonitor, EVError } EVMode;
typedef struct {
int iID;
EVMode (*GetMode)(void *self);
int (*IsInTolerance)(void *self);
int (*HandleError)(void *self);
} EVInterface, *pEVInterface;
#line 451 "interface.w"
#line 392 "interface.w"
pEVInterface CreateEVInterface(void);
#line 452 "interface.w"
#endif

View File

@ -154,6 +154,8 @@ $\langle$driv {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ int GetDrivablePosition(void *pObject, SConnection *pCon,@\\
\mbox{}\verb@ float *fPos);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ long StartDriveTask(void *self, SConnection *pCon, char *name, float fTarget);@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-1ex}
@ -206,6 +208,11 @@ will be returned.
object. If the device is a motor corrections for zero points and signs
will be applied. Returns 1 on success and 0 on failure}
{\bf StartDriveTask starts a drivable in a new task. If the task can be started, its
task ID is returned. -1 is returned on failure.
}
\subsubsection{The Countable Interface}
This is an interface for interacting with anything which counts.
@ -233,6 +240,7 @@ $\langle$count {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ int GetCountLock(pICountable self, SConnection *pCon);@\\
\mbox{}\verb@ void ReleaseCountLock(pICountable self);@\\
\mbox{}\verb@ int isRunning(pICountable self);@\\
\mbox{}\verb@ long StartCountTask(void *self, SConnection *pCon, char *name);@\\
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-1ex}
@ -273,6 +281,11 @@ will be returned.
{\bf ReleaseCountLock} release the count lock.
{\bf isRunning} returns the running flag.
{\bf StartCountTask starts a countable in a new task. If the task can be started, its
task ID is returned. -1 is returned on failure.
}
\subsubsection{The Callback Interface}
The Callback Interface is SICS suport for component behaviour for objects.

View File

@ -137,6 +137,8 @@ environment controllers fit this bill as well.
int GetDrivablePosition(void *pObject, SConnection *pCon,
float *fPos);
long StartDriveTask(void *self, SConnection *pCon, char *name, float fTarget);
@}
The first member of this structure is an ID which can be used in order to
check if the right datastructure has been obtained.
@ -181,6 +183,11 @@ will be returned.
object. If the device is a motor corrections for zero points and signs
will be applied. Returns 1 on success and 0 on failure}
{\bf StartDriveTask starts a drivable in a new task. If the task can be started, its
task ID is returned. -1 is returned on failure.
}
\subsubsection{The Countable Interface}
This is an interface for interacting with anything which counts.
@ -203,6 +210,7 @@ This is an interface for interacting with anything which counts.
int GetCountLock(pICountable self, SConnection *pCon);
void ReleaseCountLock(pICountable self);
int isRunning(pICountable self);
long StartCountTask(void *self, SConnection *pCon, char *name);
@}
{\bf running } Is a flag which says if the counter is operating or not.
@ -236,6 +244,11 @@ will be returned.
{\bf ReleaseCountLock} release the count lock.
{\bf isRunning} returns the running flag.
{\bf StartCountTask starts a countable in a new task. If the task can be started, its
task ID is returned. -1 is returned on failure.
}
\subsubsection{The Callback Interface}
The Callback Interface is SICS suport for component behaviour for objects.

View File

@ -8,6 +8,10 @@
Mark Koennecke, November 1996
Revised: Mark Koennecke, September 1997
Removed unused UDP interrupt port stuff
Mark Koennecke, February 2013
Copyright: see copyright.h
@ -22,10 +26,7 @@
#include <strlutil.h>
#include "fortify.h"
#include "conman.h"
#include "SCinter.h"
#include "nserver.h"
#include "obdes.h"
#include "sics.h"
#include "network.h"
#include "interrupt.h"
#include "status.h"
@ -40,8 +41,6 @@
#define MAXINTERRUPT 7
#define INTERUPTWAIT 5
static mkChannel *IntPort = NULL;
static pTaskMan pTask = NULL;
/*----------------------------------------------------------------------------*/
static char *pIntText[] = {
"continue",
@ -53,35 +52,6 @@ static char *pIntText[] = {
"end",
NULL
};
/*---------------------------------------------------------------------------*/
int ServerSetupInterrupt(int iPort, pNetRead pNet, pTaskMan pTasker)
{
int i;
pTask = pTasker;
/* setup interrupt port */
IntPort = UDPOpen(iPort);
if (IntPort == NULL) {
return 0;
} else {
NetReadRegister(pNet, IntPort, udp, NULL);
return 1;
}
}
/*--------------------------------------------------------------------------*/
void ServerStopInterrupt(void)
{
/* close the port */
if (IntPort) {
NETClosePort(IntPort);
free(IntPort);
}
}
/*-------------------------------------------------------------------------*/
void SetInterrupt(int iCode)
{
@ -89,7 +59,7 @@ void SetInterrupt(int iCode)
iInt = iCode;
TaskSignal(pTask, SICSINT, &iInt);
TaskSignal(pServ->pTasker, SICSINT, &iInt);
}
/*--------------------------------------------------------------------------*/

View File

@ -5,11 +5,13 @@
# Markus Zolliker March 2003
#---------------------------------------------------------------------------
EPICSOBJ=epicsmotor.o
COBJ = Sclient.o network.o ifile.o intcli.o $(FORTIFYOBJ)
SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \
servlog.o sicvar.o nserver.o SICSmain.o motorlist.o\
sicsexit.o costa.o task.o $(FORTIFYOBJ) testprot.o\
macro.o ofac.o obpar.o obdes.o drive.o status.o intserv.o \
macro.o ofac.o obpar.o obdes.o drive.o status.o intserv.o \
devexec.o mumo.o mumoconf.o selector.o selvar.o fupa.o lld.o \
lld_blob.o strrepl.o lin2ang.o fomerge.o napi5.o napi4.o\
script.o o2t.o alias.o napi.o stringdict.o sdynar.o \
@ -42,13 +44,13 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \
singlenb.o simindex.o simidx.o uselect.o singletas.o motorsec.o \
rwpuffer.o asynnet.o background.o countersec.o hdbtable.o velosec.o \
histmemsec.o sansbc.o sicsutil.o strlutil.o genbinprot.o trace.o\
singlebinb.o taskobj.o sctcomtask.o
singlebinb.o taskobj.o sctcomtask.o tasmono.o
MOTOROBJ = motor.o simdriv.o
COUNTEROBJ = countdriv.o simcter.o counter.o
VELOOBJ = velo.o velosim.o
OBJ = $(SOBJ) $(MOTOROBJ) $(COUNTEROBJ) $(VELOOBJ) $(DIFIL) $(EXTRA)
OBJ = $(SOBJ) $(MOTOROBJ) $(COUNTEROBJ) $(VELOOBJ) $(DIFIL) $(EXTRA) $(EPICSOBJ)
.SUFFIXES:
.SUFFIXES: .tcl .htm .c .o .tc
@ -65,7 +67,7 @@ all: libmat libhlib libtecsl libpsi SICServer
full: purge all
SICServer: $(OBJ) $(SUBLIBS)
$(CC) -g -o SICServer $(OBJ) $(LIBS)
$(CC) $(DBG) -o SICServer $(OBJ) $(LIBS)
matrix/libmatrix.a: libmat

View File

@ -11,19 +11,21 @@ NI= -DHAVENI
NIOBJ= nigpib.o
NILIB=$(SINQDIR)/sl6/lib/cib.o
EPICSLIBS=-L$(SINQDIR)/sl6/lib/linux-x86 -lezca -lca -lCom
include sllinux_def
CC = gcc
CFLAGS = -I$(HDFROOT)/include -DNXXML -DHDF5 $(NI) \
-Ipsi/hardsup -I. -MMD \
-Werror -DCYGNUS -DNONINTF -g $(DFORTIFY) \
-Werror -DCYGNUS -DNONINTF $(DBG) $(DFORTIFY) \
-Wall -Wno-unused -Wunused-value -Wno-comment -Wno-switch
BINTARGET = bin
EXTRA=nintf.o
SUBLIBS = psi/libpsi.a psi/hardsup/libhlib.a matrix/libmatrix.a \
psi/tecs/libtecsl.a
LIBS = -L$(HDFROOT)/lib $(SUBLIBS) $(NILIB)\
LIBS = -L$(HDFROOT)/lib $(SUBLIBS) $(NILIB) $(EPICSLIBS) \
-ltcl $(HDFROOT)/lib/libhdf5.a \
$(HDFROOT)/lib/libsz.a \
$(HDFROOT)/lib/libjson.a \

18
motor.c
View File

@ -992,6 +992,7 @@ int MotorCheckPosition(void *sulf, SConnection * pCon)
*/
extern MotorDriver *MakePiPiezo(Tcl_Interp * pTcl, char *pArray);
extern MotorDriver *epicsMakeMotorDriver(char *baseName);
int MotorCreate(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[])
@ -1052,6 +1053,23 @@ int MotorCreate(SConnection * pCon, SicsInterp * pSics, void *pData,
SCWrite(pCon, pBueffel, eLogError);
return 0;
}
} else if (strcmp(argv[2], "epics") == 0) {
if(argc > 3){
pDriver = epicsMakeMotorDriver(argv[3]);
if (!pDriver) {
return 0;
}
} else {
SCWrite(pCon,"ERROR: missing basename argument to create EPICS motor",eError);
return 0;
}
/* create the motor */
pNew = MotorInit("regress", argv[1], pDriver);
if (!pNew) {
snprintf(pBueffel,sizeof(pBueffel)-1, "Failure to create motor %s", argv[1]);
SCWrite(pCon, pBueffel, eLogError);
return 0;
}
} else {
site = getSite();
if (site != NULL) {

View File

@ -37,6 +37,7 @@ typedef struct {
pICountable slaves[MAXSLAVE];
char *transferScript;
int nSlaves;
int checkSlaves;
} MultiCounter, *pMultiCounter;
/*--------------------------------------------------------------------------*/
static void KillMultiDriver(struct __COUNTER *data)
@ -106,10 +107,12 @@ static int MMCCStart(void *pData, SConnection * pCon)
pCount->isUpToDate = 0;
pCount->tStart = time(NULL);
InvokeCallBack(pCount->pCall, COUNTSTART, pCon);
self->checkSlaves = 0;
return OKOK;
}
/*-------------------------------------------------------------------------*/
static int MMCCStatus(void *pData, SConnection * pCon)
{
int status, i;
@ -129,25 +132,46 @@ static int MMCCStatus(void *pData, SConnection * pCon)
return HWFault;
}
status = self->slaves[0]->CheckCountStatus(self->slaveData[0], pCon);
pMaster = (pCounter)self->slaveData[0];
pCount->pDriv->fLastCurrent = GetControlValue(pMaster);
if (status == HWIdle || status == HWFault) {
/*
stop counting on slaves when finished or when an error
occurred.
*/
InvokeCallBack(pCount->pCall, COUNTEND, pCon);
MMCCHalt(pCount);
}
for (i = 1; i < MAXSLAVE; i++) {
if (self->slaves[i] != NULL) {
pDum = (pDummy) self->slaveData[i];
if (strcmp(pDum->pDescriptor->name, "HistMem") == 0) {
HistDirty((pHistMem) self->slaveData[i]);
}
ReleaseCountLock(self->slaves[i]);
if(self->checkSlaves == 0) {
status = self->slaves[0]->CheckCountStatus(self->slaveData[0], pCon);
if (status == HWIdle || status == HWFault) {
/*
stop counting on slaves when finished or when an error
occurred.
*/
MMCCHalt(pData);
ReleaseCountLock(pCount->pCountInt);
self->checkSlaves = 1;
status = HWBusy;
}
} else {
/*
* wait for the detectors to report finish too. Otherwise, with the second
* generation HM data may not be fully transferred.
*/
for(i = 1; i < self->nSlaves; i++){
status = self->slaves[i]->CheckCountStatus(self->slaveData[i], pCon);
if(!(status == HWIdle || status == HWFault)){
return status;
}
}
/*
Warning: this assumes that slaves 1 - MAXSLAVE are histogram memories.
If this assumption does not hold, change this code to check if this
is really a histogram memory.
*/
for (i = 1; i < self->nSlaves; i++) {
if (self->slaves[i] != NULL) {
pDum = (pDummy)self->slaveData[i];
if (strcmp(pDum->pDescriptor->name, "HistMem") == 0) {
HistDirty((pHistMem) self->slaveData[i]);
}
ReleaseCountLock(self->slaves[i]);
}
}
status = HWIdle;
InvokeCallBack(pCount->pCall, COUNTEND, pCon);
self->checkSlaves = 0;
}
return status;
}

View File

@ -39,10 +39,6 @@
#include "sicshipadaba.h"
#include "commandlog.h"
int ServerSetupInterrupt(int iPort, pNetRead pNet, pTaskMan pTasker);
/*
configures a port for listening for interrupts
*/
extern void StopExit(void); /* in SICSmain.c */
@ -236,10 +232,6 @@ int InitServer(char *file, pServer * pServ)
IFDeleteOptions(pSICSOptions);
return 0;
}
iRet = ServerSetupInterrupt(iPort, pReader, self->pTasker);
if (!iRet) {
SCWrite(pCon, "WARNING: UDP interrupt port not initialized", eWarning);
}
/* install a secret fully priviledged entry point for ME */
AddUser("Achterbahn", "Kiel", usInternal);
@ -346,10 +338,6 @@ void StopServer(pServer self)
/* remove the in memory password database */
KillPasswd();
/* close Interrupt system */
ServerStopInterrupt();
/* Remove Status Callback */
KillStatus(NULL);
@ -481,6 +469,13 @@ int UserWait(SConnection * pCon, SicsInterp * pSics, void *pData,
}
}
/*--------------------------------------------------------------------------*/
int UserYield(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[])
{
TaskYield(pServ->pTasker);
return 1;
}
/*--------------------------------------------------------------------------*/
int SicsWait(long lTime)
{
pTaskMan pTasker = NULL;

54
obdes.h
View File

@ -1,5 +1,5 @@
#line 385 "interface.w"
#line 398 "interface.w"
#line 29 "interface.w"
@ -25,19 +25,19 @@
#include <ifile.h>
#include <hipadaba.h>
typedef struct {
char *name;
int (*SaveStatus) (void *self, char *name, FILE * fd);
void *(*GetInterface) (void *self, int iInterfaceID);
IPair *pKeys;
pHdb parNode;
} ObjectDescriptor, *pObjectDescriptor;
typedef struct {
char *name;
int (*SaveStatus)(void *self, char *name,FILE *fd);
void *(*GetInterface)(void *self, int iInterfaceID);
IPair *pKeys;
pHdb parNode;
} ObjectDescriptor, *pObjectDescriptor;
/*---------------------------------------------------------------------------*/
pObjectDescriptor CreateDescriptor(char *name);
void DeleteDescriptor(pObjectDescriptor self);
pObjectDescriptor FindDescriptor(void *pData);
pObjectDescriptor CreateDescriptor(char *name);
void DeleteDescriptor(pObjectDescriptor self);
pObjectDescriptor FindDescriptor(void *pData);
/*============================================================================
Objects which do not carry data need a dummy descriptor. Otherwise
drive or scan will protection fault when trying to drive something
@ -45,26 +45,26 @@ pObjectDescriptor FindDescriptor(void *pData);
*/
typedef struct {
pObjectDescriptor pDescriptor;
} Dummy, *pDummy;
pObjectDescriptor pDescriptor;
}Dummy, *pDummy;
pDummy CreateDummy(char *name);
void KillDummy(void *pData);
pDummy CreateDummy(char *name);
void KillDummy(void *pData);
int iHasType(void *pData, char *Type);
#endif
int iHasType(void *pData, char *Type);
#endif
#line 386 "interface.w"
#line 399 "interface.w"
/*--------------------------------------------------------------------------*/
/* Additional properties used by the ANSTO site to provide more information
* about each object instance, especially devices.
*/
void SetDescriptorKey(pObjectDescriptor self, char *keyName, char *value);
void SetDescriptorGroup(pObjectDescriptor self, char *group);
void SetDescriptorDescription(pObjectDescriptor self, char *description);
char *GetDescriptorKey(pObjectDescriptor self, char *keyName);
char *GetDescriptorGroup(pObjectDescriptor self);
char *GetDescriptorDescription(pObjectDescriptor self);
void SetDescriptorKey(pObjectDescriptor self, char *keyName, char *value);
void SetDescriptorGroup(pObjectDescriptor self, char *group);
void SetDescriptorDescription(pObjectDescriptor self, char *description);
char * GetDescriptorKey(pObjectDescriptor self, char *keyName);
char * GetDescriptorGroup(pObjectDescriptor self);
char * GetDescriptorDescription(pObjectDescriptor self);

15
ofac.c
View File

@ -17,6 +17,8 @@
#include "site.h"
#include "sicshipadaba.h"
static unsigned int killStartupCommands = 1;
extern void DevExecInit(void); /* devexec.c */
/*--------------------------------------------------------------------------*/
static void InitGeneral(void)
@ -44,6 +46,7 @@ static void InitGeneral(void)
INIT(AddGenBinProtocoll);
INIT(AddSyncedProt);
INIT(MakeTrace);
INIT(InitTaskOBJ);
INIT(SiteInit); /* site specific initializations */
}
@ -111,6 +114,7 @@ static void InitIniCommands(SicsInterp * pInter)
PCMD("TclReplaceDrivable", TclReplaceDrivable);
PCMD("transact", TransactAction);
PCMD("wait", UserWait);
PCMD("yield", UserYield);
PCMD("checksum", CheckSum);
/* startup commands in alphabetic order */
@ -169,7 +173,6 @@ static void InitIniCommands(SicsInterp * pInter)
SCMD("SicsAlias", SicsAlias);
SCMD("SicsUser", PWSicsUser);
SCMD("TokenInit", TokenInit);
SCMD("MakeTask", TaskOBJFactory);
SCMD("UpdateFactory", UpdateFactory);
SCMD("VarMake", VarFactory);
SCMD("VelocitySelector", VelSelFactory);
@ -229,7 +232,13 @@ int InitObjectCommands(pServer pServ, char *file)
if (site != NULL && site->RemoveSiteCommands != NULL) {
site->RemoveSiteCommands(pSics);
}
RemoveStartupCommands();
if(killStartupCommands){
RemoveStartupCommands();
}
return 1;
}
/*---------------------------------------------------------------------------------*/
void KeepStartupCommands()
{
killStartupCommands = 0;
}

1
ofac.h
View File

@ -21,5 +21,4 @@
#include "sics.h"
int InitObjectCommands(pServer pServ, char *file);
#endif

View File

@ -24,6 +24,10 @@
static char undef[] = "Undefined";
#define IDXFMT " %8.4f"
#define ANGFMT " %8.2f"
int CountTblCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
pHdb par[], int nPar); /* from hdbtable.c */
/*----------------------------------------------------------------------*/
typedef struct {
int idxCount;
@ -549,6 +553,10 @@ pSICSOBJ CreateReflectionList(SConnection * pCon, SicsInterp * pSics,
SetHdbProperty(cmd,"priv","user");
AddSICSHdbPar(cmd, "id", usUser, MakeHdbText(""));
cmd = AddSICSHdbPar(pNew->objectNode, "count", usUser,
MakeSICSFunc(CountTblCmd));
AddCommand(pSics, name, InterInvokeSICSOBJ, KillSICSOBJ, pNew);
return pNew;
}

2
scan.c
View File

@ -644,6 +644,7 @@ int DoScan(pScanData self, int iNP, int iMode, float fPreset,
return 0;
}
self->iActive = 1;
self->iNP = iNP;
self->iMode = iMode;
self->fPreset = fPreset;
@ -661,7 +662,6 @@ int DoScan(pScanData self, int iNP, int iMode, float fPreset,
}
self->iActive = 1;
iRet = ScanLoop(self);
ScriptScanFinish(self);
InvokeCallBack(self->pCall, SCANEND, self);

View File

@ -148,7 +148,7 @@ static long SCTDRIVSetValue(void *data, SConnection * pCon, float val)
}
pPriv->pCon = SCCopyConnection(pCon);
StopByData(pServ->pExecutor, data);
/* StopByData(pServ->pExecutor, data); */
v = MakeHdbFloat(val);
SetHdbProperty(self->objectNode, "writestatus", "start");

View File

@ -711,8 +711,13 @@ static int copyHM(pSICSData self, int argc, char *argv[],
SCWrite(pCon, "ERROR: out of memory in SICSData copyhm", eError);
return 0;
}
GetHistogramDirect(pHist, pCon, 0, start, end, iData,
if(end > GetHistLength(pHist)){
GetHistogramDirect(pHist, pCon, 0, start, end, iData,
(end - start) * sizeof(int));
} else {
GetHistogram(pHist, pCon, 0, start, end, iData,
(end - start) * sizeof(int));
}
assignType(self, pos, pos + (end - start), INTTYPE);
SCSendOK(pCon);
return 1;

View File

@ -284,7 +284,7 @@ static hdbCallbackReturn SetModeCB(pHdb node, void *userData,
priv->mode = Bisecting;
initializeSingleBisectingOrion(priv->diffractometer);
free(set->v->v.text);
set->v->v.text = strdup("bi");
set->v->v.text = strdup("bio");
return hdbContinue;
break;
case NB:

View File

@ -10,4 +10,6 @@
MFLAGS=-f makefile_linux$(DUMMY)
HDFROOT=/afs/psi.ch/project/sinq/sl6
TCLINC=.
TCLINC=.
DBG= -g

627
tacov.c
View File

@ -1,627 +0,0 @@
/* tacov.f -- translated by f2c (version 20000817).
You must link the resulting object file with the libraries:
-lf2c -lm (in that order)
*/
#include "f2c.h"
/* Common Block Declarations */
struct {
integer inx;
real c1rx, c2rx, rmin, rmax, cl1r;
} curve_;
#define curve_1 curve_
/* Table of constant values */
static doublereal c_b7 = 1.;
static doublereal c_b9 = 360.;
/* ----------------------------------------------------------------------- */
/* FILE T_CONV */
/* SUBROUTINE T_CONV(EI,AKI,EF,AKF,QHKL,EN,HX,HY,HZ,IF1,IF2,LDK,LDH,LDF */
/* 1 LPA,DM,DA,HELM,F1H,F1V,F2H,F2V,F,IFX,ISS,ISM,ISA, */
/* 2 T_A,T_RM,T_ALM,LDRA,LDR_RM,LDR_ALM,P_IH,C_IH,IER) */
/* SUBROUTINE EX_CASE(DX,ISX,AKX,AX1,AX2,RX,ALX,IER) */
/* SUBROUTINE SAM_CASE(QT,QM,QS,AKI,AKF,AX3,AX4,ISS,IER) */
/* SUBROUTINE HELM_CASE(HX,HY,HZ,P_IH,AKI,AKF,A4,QM,HELM,IER) */
/* SUBROUTINE FLIP_CASE(IF1,IF2,P_IH,F1V,F1H,F2V,F2H,AKI,AKF,IER) */
/* ----------------------------------------------------------------------- */
/* Subroutine */ int t_conv__(real * ei, real * aki, real * ef, real * akf,
real *
qhkl, real * en, real * hx, real * hy,
real * hz, integer * if1, integer * if2,
logical * ldk, logical * ldh, logical * ldf,
logical * lpa, real * dm, real * da,
real * helm, real * f1h, real * f1v,
real * f2h, real * f2v, real * f,
integer * ifx, integer * iss, integer * ism,
integer * isa, real * t_a__, real * t_rm__,
real * t_alm__, real * qm, logical * ldra,
logical * ldr_rm__, logical * ldr_alm__,
real * p_ih__, real * c_ih__, integer * ier)
{
/* System generated locals */
doublereal d__1;
/* Builtin functions */
double sqrt(doublereal);
/* Local variables */
static doublereal edef[2], dakf, daki;
static integer imod;
extern /* Subroutine */ int sam_case__(doublereal *, doublereal *,
doublereal *, doublereal *,
doublereal *, doublereal *,
doublereal *, integer *,
integer *);
static integer i__;
static doublereal akdef[2];
extern /* Subroutine */ int helm_case__(real *, real *, real *, real *,
real *, real *, real *,
doublereal *, real *, real *,
integer *);
static doublereal dqhkl[3];
extern /* Subroutine */ int flip_case__(integer *, integer *, real *,
real *, real *, real *, real *,
real *, real *, integer *);
static logical lmoan[2];
static doublereal a1, a2, a3, a4, a5, a6;
static integer id;
static doublereal ra;
extern /* Subroutine */ int rl2spv_(doublereal *, doublereal *,
doublereal *, doublereal *,
integer *);
static integer iq;
static doublereal rm;
static logical lqhkle;
extern /* Subroutine */ int erreso_(integer *, integer *);
static doublereal dda, ala, def, dei, ddm, alm, dqm;
extern /* Subroutine */ int ex_case__(doublereal *, integer *, doublereal
*, doublereal *, doublereal *,
doublereal *, doublereal *,
integer *);
static doublereal dqt[3], dqs;
/* ----------------------------------------------------------------------- */
/* INPUT */
/* EI,AKI,EF,AKF,QHKL,EN,HX,HY,HZ : POTENTIAL TARGETS */
/* IF1,IF2 Status of flippers On (1) Off (0) */
/* LDK(8) LOGICAL INDICATING IF (ENERGY,K OR Q) ARE DRIVEN */
/* LDH,LDF LOGICAL INDICATING IF (HX,HY,HZ) OR (F1,F2) ARE DRIVEN */
/* configuration of the machine */
/* LPA LOGICAL TRUE IF MACHINE IN POLARIZATION MODE */
/* DM,DA,HELM,F1H,F1V,F2H,F2V,F,IFX,ISS,ISM,ISA,QM (F ENERGY UNIT) */
/* OUTPUT */
/* T_A TARGETS OF ANGLES A1-A6 */
/* T_RM,T_ALM TARGETS OF RM ,LM */
/* QM TARGETS OF QM */
/* LDRA LOGICAL INDICATING WHICH ANGLES ARE TO BE DRIVEN */
/* LDR_RM,LDR_ALM LOGICAL INDICATING IF RM OR ALM ARE TO BE DRIVEN */
/* P_IH TARGETS OF CURRENTS FOR FLIPPERS AND HELMOTZ (8 CURRENTS) */
/* C_IH CONVERSION FACTORS FOR HELMOTZ (4 CURRENTS) */
/* SPECIAL OUTPUTS */
/* TARGET OF EI(EF) IS UPDATED IS KI(KF) IS DRIVEN */
/* TARGET OF VARIABLE ENERGY IS UPDATED IF EN IS DRIVEN */
/* ----------------------------------------------------------------------- */
/* ----------------------------------------------------------------------- */
/* PASSED PARAMETERS */
/* ----------------------------------------------------------------------- */
/* LOCAL VARIABLES */
/* ----------------------------------------------------------------------- */
/* SET UP */
/* IMOD INDEX FOR ERROR TREATMENAT BY ERRESO */
/* LDQHKLE : LOGICAL INDICATING THAT WE ARE DEALING WITH A MOVE */
/* IN RECIPROCICAL SPACE */
/* WE REMAP THE ENERGY PB AS FIXED ENERGY IN EDEF(1) */
/* AND VARIABLE ENERGY IN EDEF(2) */
/* IF ISA IS NUL SET IFX TO 1 AND PUT EF,KF, EQUAL TO EI,KI */
/* Parameter adjustments */
--c_ih__;
--p_ih__;
--ldra;
--t_a__;
--ldk;
--qhkl;
/* Function Body */
imod = 3;
ddm = *dm;
dda = *da;
for (i__ = 1; i__ <= 2; ++i__) {
lmoan[i__ - 1] = FALSE_;
}
lqhkle = FALSE_;
for (iq = 5; iq <= 8; ++iq) {
lqhkle = lqhkle || ldk[iq];
}
daki = *aki;
dakf = *akf;
if (*isa == 0) {
*ifx = 1;
}
edef[*ifx - 1] = *ei;
akdef[*ifx - 1] = *aki;
edef[3 - *ifx - 1] = *ef;
akdef[3 - *ifx - 1] = *akf;
if (*isa == 0) {
edef[1] = edef[0];
akdef[1] = akdef[0];
ldk[3] = TRUE_;
ldk[4] = TRUE_;
t_a__[5] = 0.f;
t_a__[6] = 0.f;
ldra[5] = TRUE_;
ldra[6] = TRUE_;
}
/* ----------------------------------------------------------------------- */
/* FIRST TAKE IN ACCOUNT THE FIXED ENERGY PB */
if (ldk[(*ifx << 1) - 1] || ldk[*ifx * 2]) {
lmoan[*ifx - 1] = TRUE_;
if (ldk[(*ifx << 1) - 1]) {
*ier = 1;
if (edef[0] < .1) {
goto L999;
}
*ier = 0;
akdef[0] = sqrt(edef[0] / *f);
} else {
*ier = 1;
if (akdef[0] < .1) {
goto L999;
}
*ier = 0;
/* Computing 2nd power */
d__1 = akdef[0];
edef[0] = *f * (d__1 * d__1);
}
}
/* ----------------------------------------------------------------------- */
/* NOW TAKE IN ACCOUNT THE VARIABLE ENERGY PB */
/* VARIABLE ENERGUY IS DRIVEN EITHER EXPLICITLY */
/* E.G. BY DRIVING EI OR KI WITH IFX=2 */
/* ( AND WE MUST CALCULATE EN FROM EVAR) */
/* THE RULE IS : EI=EF+EN : EN IS THE ENERGY LOSS OF NEUTRONS */
/* OR ENERGY GAIN OF SAMPLE */
/* OR IMPLICITLY BY DRIVING THE TRANSFERED ENERGY EN */
/* ( AND WE MUST CALCULATE EVAR FROM EN) */
/* IF KI IS CONSTANT USE THE CURRENT VALUE CONTAINED IN POSN ARRAY */
/* TO CALCULATE THE NON-"CONSTANT" K. */
/* IF KF IS CONSTANT USE ALWAYS THE VALUE IN TARGET AND */
/* DO A DRIVE OF KF TO KEEP A5/A6 IN RIGHT POSITION */
if (ldk[5 - (*ifx << 1)] || ldk[6 - (*ifx << 1)]) {
lmoan[3 - *ifx - 1] = TRUE_;
if (ldk[5 - (*ifx << 1)]) {
*ier = 1;
if (edef[1] < 1e-4) {
goto L999;
}
*ier = 0;
akdef[1] = sqrt(edef[1] / *f);
} else {
*ier = 1;
if (akdef[1] < 1e-4) {
goto L999;
}
*ier = 0;
/* Computing 2nd power */
d__1 = akdef[1];
edef[1] = *f * (d__1 * d__1);
}
*en = (3 - (*ifx << 1)) * (edef[0] - edef[1]);
} else if (lqhkle) {
lmoan[3 - *ifx - 1] = TRUE_;
edef[1] = edef[0] + ((*ifx << 1) - 3) * *en;
*ier = 1;
if (edef[1] < 1e-4) {
goto L999;
}
*ier = 0;
akdef[1] = sqrt(edef[1] / *f);
}
/* ----------------------------------------------------------------------- */
/* CALCULATE MONOCHROMATOR AND ANALYSER ANGLES */
if (lmoan[0]) {
dei = edef[*ifx - 1];
daki = akdef[*ifx - 1];
ex_case__(&ddm, ism, &daki, &a1, &a2, &rm, &alm, ier);
if (*ier == 0) {
*aki = daki;
*ei = dei;
t_a__[1] = a1;
t_a__[2] = a2;
*t_rm__ = rm;
*t_alm__ = alm;
ldra[1] = TRUE_;
ldra[2] = TRUE_;
*ldr_rm__ = TRUE_;
*ldr_alm__ = TRUE_;
} else {
goto L999;
}
}
if (lmoan[1]) {
def = edef[3 - *ifx - 1];
dakf = akdef[3 - *ifx - 1];
ex_case__(&dda, isa, &dakf, &a5, &a6, &ra, &ala, ier);
if (*ier == 0) {
*akf = dakf;
*ef = def;
t_a__[5] = a5;
t_a__[6] = a6;
ldra[5] = TRUE_;
ldra[6] = TRUE_;
} else {
goto L999;
}
}
/* ----------------------------------------------------------------------- */
/* USE (QH,QK,QL) TO CALCULATE A3 AND A4 */
/* CALCULATE Q1 AND Q2 IN SCATTERING PLANE */
imod = 2;
if (lqhkle) {
for (id = 1; id <= 3; ++id) {
dqhkl[id - 1] = qhkl[id];
}
rl2spv_(dqhkl, dqt, &dqm, &dqs, ier);
if (*ier != 0) {
goto L999;
}
sam_case__(dqt, &dqm, &dqs, &daki, &dakf, &a3, &a4, iss, ier);
if (*ier == 0) {
t_a__[3] = a3;
t_a__[4] = a4;
ldra[3] = TRUE_;
ldra[4] = TRUE_;
*qm = dqm;
} else {
goto L999;
}
}
/* ----------------------------------------------------------------------- */
/* DEAL WITH FLIPPERS AND HELMOTZ COILS IF LPA */
if (*lpa && (lmoan[0] || lmoan[1])) {
if (*ldf) {
flip_case__(if1, if2, &p_ih__[1], f1v, f1h, f2v, f2h, aki, akf, ier);
}
if (*ldh) {
helm_case__(hx, hy, hz, &p_ih__[1], &c_ih__[1], aki, akf, &a4, qm,
helm, ier);
}
}
/* ----------------------------------------------------------------------- */
L999:
if (*ier != 0) {
erreso_(&imod, ier);
}
return 0;
} /* t_conv__ */
/* Subroutine */ int ex_case__(doublereal * dx, integer * isx,
doublereal * akx,
doublereal * ax1, doublereal * ax2,
doublereal * rx, doublereal * alx,
integer * ier)
{
/* System generated locals */
doublereal d__1, d__2;
/* Builtin functions */
double asin(doublereal), sin(doublereal), cos(doublereal),
sqrt(doublereal);
/* Local variables */
static doublereal dcl1r, dc1rx, dc2rx, drmin, drmax, arg;
/* ----------------------------------------------------------------------- */
/* CALCULATE ANGLES ON MONO/ANALYSER */
/* CALCULATE AX1 AX2 */
/* CALCULATE RX LX MONO CURVATURE AND LM FOR IN8 */
/* INPUT */
/* DX D-SPACINGS */
/* ISX SENS OF SCATTERING ON CRYSTAL */
/* AKX TARGET OF MOMENTUM */
/* OUTPUT */
/* AX1 AX2 THETA 2*THETA ANGLES */
/* RX MONO OR ANALYSER CURVATURE */
/* ALX SPECIAL TRANSLATION FOR IN8 */
/* IER */
/* 1 ' KI OR KF CANNOT BE OBTAINED CHECK D-SPACINGS', */
/* 2 ' KI OR KF TOO SMALL', */
/* 3 ' KI OR KF TOO BIG', */
/* ----------------------------------------------------------------------- */
/* Values of parameters */
/* INX=1 IN8 , INX=0 others instruments */
/* C1RX C2RX constants values to calculate RM on all instruments */
/* RMIN, RMAX min max on RNM */
/* CL1R constant value to calculate LM for IN8 */
/* ----------------------------------------------------------------------- */
/* ----------------------------------------------------------------------- */
/* PASSED PARAMETERS */
/* ----------------------------------------------------------------------- */
/* LOCAL VAR */
/* ----------------------------------------------------------------------- */
/* INIT AND TEST */
*ier = 0;
dc1rx = curve_1.c1rx;
dc2rx = curve_1.c2rx;
drmin = curve_1.rmin;
drmax = curve_1.rmax;
dcl1r = curve_1.cl1r;
if (*dx < .1f) {
*ier = 1;
}
if (*akx < .1f) {
*ier = 2;
}
arg = 3.1415926535897932384626433832795f / (*dx * *akx);
if (abs(arg) > 1.f) {
*ier = 3;
}
if (*ier != 0) {
goto L999;
}
/* ----------------------------------------------------------------------- */
/* CALCULATION OF THE TWO ANGLES */
*ax1 = asin(arg) * *isx * 57.29577951308232087679815481410517f;
*ax2 = *ax1 * 2.;
/* ----------------------------------------------------------------------- */
/* CALCULATION OF MONO CURVATURE RM OR ANALYSER CURVATURE RA */
/* STANDARD LAW IS C1RX+C2RX/SIN(A1/RD) */
/* C1RX AND C2RX ARE CONSTANTS DEPENDING ON MONO AND MACHINES */
/* C1RX=.47 */
/* C2RX=.244 */
/* RMIN=0. */
/* RMAX=20. */
/* IN1/IN3/IN12/IN14/IN20 CASE */
if (curve_1.inx == 0) {
/* Computing MIN */
/* Computing MAX */
d__2 = dc1rx + dc2rx / sin(abs(*ax1) /
57.29577951308232087679815481410517f);
d__1 = max(d__2, drmin);
*rx = min(d__1, drmax);
} else {
/* IN8 CASE */
*alx =
dcl1r / sin(*ax2 / 57.29577951308232087679815481410517f) *
cos(*ax2 / 57.29577951308232087679815481410517f);
*rx = dc2rx * sqrt(sin(*ax2 / 57.29577951308232087679815481410517f))
- dc1rx;
}
/* ----------------------------------------------------------------------- */
L999:
return 0;
} /* ex_case__ */
/* ========================================================================= */
/* Subroutine */ int sam_case__(doublereal * qt, doublereal * qm,
doublereal *
qs, doublereal * aki, doublereal * akf,
doublereal * ax3, doublereal * ax4,
integer * iss, integer * ier)
{
/* System generated locals */
doublereal d__1, d__2;
/* Builtin functions */
double acos(doublereal), atan2(doublereal, doublereal), d_sign(doublereal
*,
doublereal
*),
d_mod(doublereal *, doublereal *);
/* Local variables */
static doublereal arg, sax3;
/* ----------------------------------------------------------------------- */
/* DEAL WITH SAMPLE ANGLES CALCULATION FROM Q VERTOR IN C-N PLANE */
/* CALCULATE A3 AND A4 */
/* INPUT */
/* QT Q-VECTOR IN SCATTERING PLANE */
/* QM,QS Q MODULUS AND QMODULUS SQUARED */
/* AKI,AKF MOMEMTA ON MONO AND ANYLSER */
/* ISS SENS OF SCATTERING ON SAMPLE */
/* OUTPUT */
/* AX3 AX4 ANGLES ON SAMPLES */
/* IER SAME ERROR AS RL2SPV */
/* IER */
/* 1 ' MATRIX S NOT OK', */
/* 2 ' Q NOT IN SCATTERING PLANE', */
/* 3 ' Q MODULUS TOO SMALL', */
/* 4 ' Q MODULUS TOO BIG', */
/* ----------------------------------------------------------------------- */
/* ----------------------------------------------------------------------- */
/* PASSED PARAMETERS */
/* ----------------------------------------------------------------------- */
/* INIT AND TEST */
/* Parameter adjustments */
--qt;
/* Function Body */
*ier = 0;
if (abs(*qs) < 1e-6 || abs(*qm) < .001) {
*ier = 3;
goto L999;
}
/* ----------------------------------------------------------------------- */
/* CALCULATE A3 AND MOVE IT INTHE -180 ,+180 INTERVAL */
/* Computing 2nd power */
d__1 = *aki;
/* Computing 2nd power */
d__2 = *akf;
arg = (d__1 * d__1 + d__2 * d__2 - *qs) / (*aki * 2. * *akf);
if (abs(arg) > 1.) {
*ier = 4;
goto L999;
} else {
*ax4 = acos(arg) * *iss * 57.29577951308232087679815481410517;
}
/* Computing 2nd power */
d__1 = *akf;
/* Computing 2nd power */
d__2 = *aki;
*ax3 =
(-atan2(qt[2], qt[1]) -
acos((d__1 * d__1 - *qs -
d__2 * d__2) / (*qm * -2. * *aki)) * d_sign(&c_b7,
ax4)) *
57.29577951308232087679815481410517;
sax3 = d_sign(&c_b7, ax3);
d__1 = *ax3 + sax3 * 180.;
*ax3 = d_mod(&d__1, &c_b9) - sax3 * 180.;
/* IF(LPLATE) AX3=-ATAN(SIN(AX4/RD)/(LSA*TAN(AX5/RD)/(ALMS*C */
/* 1 TAN(AX1/RD))*(AKI/KF)**2-COS(AX4/RD)))*RD !PLATE FOCALIZATION OPTION */
/* IF(AXX3.GT.180.D0) AX3=AX3-360.D0 */
/* IF( A3.LT.-180.D0) AX3=AX3+360.D0 */
/* IF(LPLATE.AND.A3.GT.0.0) AX3=AX3-180 */
/* C----------------------------------------------------------------------- */
L999:
return 0;
} /* sam_case__ */
/* ============================================================================ */
/* Subroutine */ int helm_case__(real * hx, real * hy, real * hz,
real * t_ih__,
real * c_ih__, real * aki, real * akf,
doublereal * a4, real * qm, real * helm,
integer * ier)
{
/* System generated locals */
real r__1, r__2;
/* Builtin functions */
double cos(doublereal), sin(doublereal), atan2(doublereal, doublereal),
sqrt(doublereal);
/* Local variables */
static real hrad, hdir, qpar, hdir2, qperp;
static integer ic;
static real phi;
/* ----------------------------------------------------------------------- */
/* DEAL WITH HELMOTZ COIL FIELD CALCULATIONS */
/* CALCULATE HX HY HZ */
/* ----------------------------------------------------------------------- */
/* ----------------------------------------------------------------------- */
/* PASSED PARAMETERS */
/* ----------------------------------------------------------------------- */
/* INIT AND TEST */
/* Parameter adjustments */
--c_ih__;
--t_ih__;
/* Function Body */
*ier = 1;
if (dabs(*qm) < 1e-4f) {
goto L999;
}
*ier = 0;
for (ic = 1; ic <= 4; ++ic) {
if (c_ih__[ic] < 1e-4f) {
*ier = 2;
}
}
if (*ier != 0) {
goto L999;
}
/* ----------------------------------------------------------------------- */
/* CALCULATE MODULE AND ANGLES OF IN PLANE FIELD H */
/* PHI !ANGLE BETWEEN Q AND KI */
/* HRAD !RADIAL COMP. OF H */
/* HDIR !DIRECTION OF H (IN RADIANS) */
/* HDIR2 !ANGLE BETWEEN FIELD AND AXE OF COIL 1 */
qpar = *aki - *akf * cos(*a4 / 57.29577951308232087679815481410517f);
qperp = *akf * sin(*a4 / 57.29577951308232087679815481410517f);
phi = atan2(qpar, qperp);
/* Computing 2nd power */
r__1 = *hx;
/* Computing 2nd power */
r__2 = *hy;
hrad = sqrt(r__1 * r__1 + r__2 * r__2);
if (hrad > 1e-4f) {
hdir = atan2(*hy, *hx);
}
hdir2 = phi + hdir + *helm / 57.29577951308232087679815481410517f +
1.5707963267948966f;
/* ----------------------------------------------------------------------- */
/* !CALC CURRENTS */
/* !POSITION OF PSP FOR COIL I */
for (ic = 1; ic <= 3; ++ic) {
t_ih__[ic + 4] = cos(hdir2 + (ic - 1) * 2.f *
3.1415926535897932384626433832795f / 3.f) * hrad /
c_ih__[ic]
/ 1.5f;
}
t_ih__[8] = *hz / c_ih__[4];
/* ----------------------------------------------------------------------- */
L999:
return 0;
} /* helm_case__ */
/* Subroutine */ int flip_case__(integer * if1, integer * if2,
real * t_ih__,
real * f1v, real * f1h, real * f2v,
real * f2h, real * aki, real * akf,
integer * ier)
{
/* ----------------------------------------------------------------------- */
/* DEAL WITH FLIPPER COIL CALCULATIONS */
/* CALCULATE P_IF CURRENTS FOR THE TWO FLIPPERS */
/* ----------------------------------------------------------------------- */
/* PASSED PARAMETERS */
/* ----------------------------------------------------------------------- */
/* INIT AND TEST */
/* Parameter adjustments */
--t_ih__;
/* Function Body */
*ier = 0;
/* ----------------------------------------------------------------------- */
if (*if1 == 1) {
t_ih__[1] = *f1v;
t_ih__[2] = *aki * *f1h;
} else {
t_ih__[1] = 0.f;
t_ih__[2] = 0.f;
}
if (*if2 == 1) {
t_ih__[3] = *f2v;
t_ih__[4] = *akf * *f2h;
} else {
t_ih__[3] = 0.f;
t_ih__[4] = 0.f;
}
/* ----------------------------------------------------------------------- */
/* L999: */
return 0;
} /* flip_case__ */

View File

@ -227,7 +227,16 @@ static int TASHalt(void *pData)
if (self->math->tasMode == ELASTIC) {
length = 8;
}
for (i = 0; i < length; i++) {
/*
stop monochromator
*/
self->math->mono->Halt(self->math->monoData);
/*
stop rest
*/
for (i = 4; i < length; i++) {
if (self->math->motors[i] != NULL) {
pDriv = GetDrivableInterface(self->math->motors[i]);
pDriv->Halt(self->math->motors[i]);
@ -295,8 +304,8 @@ static int startTASMotor(pMotor mot, SConnection * pCon, char *name,
to force updates on targets
*/
InvokeNewTarget(pServ->pExecutor, name, target);
writeMotPos(pCon, silent, name, val, target);
}
writeMotPos(pCon, silent, name, val, target);
return status;
}
@ -313,39 +322,43 @@ static int startMotors(ptasMot self, tasAngles angles,
/*
monochromator
*/
status = startTASMotor(self->math->motors[A1], pCon, "a1",
angles.monochromator_two_theta / 2., silent, stopFixed);
if (status != OKOK) {
/* status = startTASMotor(self->math->motors[A1], pCon, "a1", */
/* angles.monochromator_two_theta / 2., silent, stopFixed); */
/* if (status != OKOK) { */
/* return status; */
/* } */
/* status = startTASMotor(self->math->motors[A2], pCon, "a2", */
/* angles.monochromator_two_theta, silent,stopFixed); */
/* if (status != OKOK) { */
/* return status; */
/* } */
/* if (self->math->motors[MCV] != NULL) { */
/* curve = maCalcVerticalCurvature(self->math->machine.monochromator, */
/* angles.monochromator_two_theta); */
/* status = startTASMotor(self->math->motors[MCV], pCon, "mcv", */
/* curve, silent,stopFixed); */
/* if (status != OKOK) { */
/* SCWrite(pCon,"WARNING: monochromator vertical curvature motor failed to start", eLog); */
/* SCSetInterrupt(pCon,eContinue); */
/* } */
/* } */
/* if (self->math->motors[MCH] != NULL) { */
/* curve = maCalcHorizontalCurvature(self->math->machine.monochromator, */
/* angles.monochromator_two_theta); */
/* status = startTASMotor(self->math->motors[MCH], pCon, "mch", */
/* curve, silent,stopFixed); */
/* if (status != OKOK) { */
/* SCWrite(pCon,"WARNING: monochromator horizontal curvature motor failed to start", eLog); */
/* SCSetInterrupt(pCon,eContinue); */
/* } */
/* } */
status = self->math->mono->SetValue(self->math->monoData,
pCon,angles.monochromator_two_theta);
if(status != OKOK){
return status;
}
status = startTASMotor(self->math->motors[A2], pCon, "a2",
angles.monochromator_two_theta, silent,stopFixed);
if (status != OKOK) {
return status;
}
if (self->math->motors[MCV] != NULL) {
curve = maCalcVerticalCurvature(self->math->machine.monochromator,
angles.monochromator_two_theta);
status = startTASMotor(self->math->motors[MCV], pCon, "mcv",
curve, silent,stopFixed);
if (status != OKOK) {
SCWrite(pCon,"WARNING: monochromator vertical curvature motor failed to start", eLog);
SCSetInterrupt(pCon,eContinue);
}
}
if (self->math->motors[MCH] != NULL) {
curve = maCalcHorizontalCurvature(self->math->machine.monochromator,
angles.monochromator_two_theta);
status = startTASMotor(self->math->motors[MCH], pCon, "mch",
curve, silent,stopFixed);
if (status != OKOK) {
SCWrite(pCon,"WARNING: monochromator horizontal curvature motor failed to start", eLog);
SCSetInterrupt(pCon,eContinue);
}
}
/*
analyzer
@ -491,24 +504,24 @@ static int calculateAndDrive(ptasMot self, SConnection * pCon)
switch (status) {
case ENERGYTOBIG:
SCWrite(pCon, "ERROR: desired energy to big", eError);
SCWrite(pCon, "ERROR: desired energy to big", eLogError);
return HWFault;
break;
case UBNOMEMORY:
SCWrite(pCon, "ERROR: out of memory calculating angles", eError);
SCWrite(pCon, "ERROR: out of memory calculating angles", eLogError);
driveQ = 0;
break;
case BADRMATRIX:
SCWrite(pCon, "ERROR: bad crystallographic parameters or bad UB",
eError);
eLogError);
driveQ = 0;
break;
case BADUBORQ:
SCWrite(pCon, "ERROR: bad UB matrix or bad Q-vector", eError);
SCWrite(pCon, "ERROR: bad UB matrix or bad Q-vector", eLogError);
driveQ = 0;
break;
case TRIANGLENOTCLOSED:
SCWrite(pCon, "ERROR: cannot close scattering triangle", eError);
SCWrite(pCon, "ERROR: cannot close scattering triangle", eLogError);
driveQ = 0;
break;
}
@ -546,7 +559,7 @@ static int calculateAndDrive(ptasMot self, SConnection * pCon)
if (driveQ == 0 && self->math->mustDriveQ == 1) {
SCWrite(pCon, "WARNING: NOT driving Q-vector because of errors",
eError);
eLogError);
}
/*
* reset the Q flag
@ -577,7 +590,20 @@ static int checkMotors(ptasMot self, SConnection * pCon)
mask[SGL] = 0;
}
for (i = 0; i < 12; i++) {
/*
check monochromator
*/
status = self->math->mono->CheckStatus(self->math->monoData,pCon);
if(status == HWIdle){
for(i = 0; i < 4; i++){
busy[i] = 0;
}
}
/*
check the rest
*/
for (i = 4; i < 12; i++) {
if(self->math->motors[i] == NULL){
busy[i] = 0;
} else {
@ -635,35 +661,39 @@ static int startQMMotors(ptasMot self, tasAngles angles,
/*
monochromator
*/
status = startTASMotor(self->math->motors[A1], pCon, "a1",
angles.monochromator_two_theta / 2., silent,stopFixed);
if (status != OKOK) {
return status;
}
status = startTASMotor(self->math->motors[A2], pCon, "a2",
angles.monochromator_two_theta, silent,stopFixed);
if (status != OKOK) {
return status;
}
/* status = startTASMotor(self->math->motors[A1], pCon, "a1", */
/* angles.monochromator_two_theta / 2., silent,stopFixed); */
/* if (status != OKOK) { */
/* return status; */
/* } */
/* status = startTASMotor(self->math->motors[A2], pCon, "a2", */
/* angles.monochromator_two_theta, silent,stopFixed); */
/* if (status != OKOK) { */
/* return status; */
/* } */
if (self->math->motors[MCV] != NULL) {
curve = maCalcVerticalCurvature(self->math->machine.monochromator,
angles.monochromator_two_theta);
status = startTASMotor(self->math->motors[MCV], pCon, "mcv",
curve, silent,stopFixed);
if (status != OKOK) {
return status;
}
}
/* if (self->math->motors[MCV] != NULL) { */
/* curve = maCalcVerticalCurvature(self->math->machine.monochromator, */
/* angles.monochromator_two_theta); */
/* status = startTASMotor(self->math->motors[MCV], pCon, "mcv", */
/* curve, silent,stopFixed); */
/* if (status != OKOK) { */
/* return status; */
/* } */
/* } */
if (self->math->motors[MCH] != NULL) {
curve = maCalcHorizontalCurvature(self->math->machine.monochromator,
angles.monochromator_two_theta);
status = startTASMotor(self->math->motors[MCH], pCon, "mch",
curve, silent,stopFixed);
if (status != OKOK) {
return status;
}
/* if (self->math->motors[MCH] != NULL) { */
/* curve = maCalcHorizontalCurvature(self->math->machine.monochromator, */
/* angles.monochromator_two_theta); */
/* status = startTASMotor(self->math->motors[MCH], pCon, "mch", */
/* curve, silent,stopFixed); */
/* if (status != OKOK) { */
/* return status; */
/* } */
/* } */
status = self->math->mono->SetValue(self->math->monoData,pCon,angles.analyzer_two_theta);
if(status != OKOK){
return status;
}

37
task.c
View File

@ -68,7 +68,8 @@ static pTaskHead MakeTaskHead(char *name, TaskFunc pTask, SignalFunc pSignal,
pNew->pSignal = pSignal;
pNew->pData = pData;
pNew->pKill = pKill;
pNew->lID = lIDMama++;
lIDMama++;
pNew->lID = lIDMama;
pNew->iStatus = READY;
if(lIDMama < 0){
@ -455,6 +456,25 @@ int isTaskRunning(pTaskMan self, char *name)
return 0;
}
/*-----------------------------------------------------------------------------*/
int isTaskIDRunning(pTaskMan self, long lID)
{
int iRet;
pTaskHead pCurrent, pNext;
if (self == NULL) return 0;
assert(self->iID == TASKERID);
pNext = self->pHead->pNext; /* skip dummy task */
while (pNext != NULL) {
pCurrent = pNext;
pNext = pCurrent->pNext;
if (pCurrent->lID == lID) {
return 1;
}
}
return 0;
}
/*-----------------------------------------------------------------------------*/
pTaskHead TaskIteratorStart(pTaskMan self)
{
if (self == NULL) return NULL;
@ -502,6 +522,21 @@ char *TaskDescription(pTaskHead it)
}
/*------------------------------------------------------------------------------*/
long GetTaskID(pTaskHead it)
{
return it->lID;
}
/*------------------------------------------------------------------------------*/
long GetGroupID(pTaskHead it)
{
return it-> groupID;
}
/*------------------------------------------------------------------------------*/
const char * GetTaskName(pTaskHead it)
{
return (const char*)it->name;
}
/*------------------------------------------------------------------------------*/
long GetTaskGroupID(pTaskMan self)
{
lIDMama++;

23
task.h
View File

@ -6,7 +6,10 @@
a yield and a primitive form of inter task communication is implemented.
Mark Koennecke, September 1997
extended to suuport task groups
Mark Koennecke, December 2012
copyright: see implementation file
-----------------------------------------------------------------------------*/
#ifndef TASKOMAT
@ -144,6 +147,11 @@ int TaskSignal(pTaskMan self, int iSignal, void *pSigData);
/*
returns 1 when task name is running, 0 else
*/
/*--------------------------------------------------------------------------*/
int isTaskIDRunning(pTaskMan self, long lID);
/*
returns 1 when task name is running, 0 else
*/
/*===========================================================================
Iterating the task list. This works like:
@ -177,6 +185,19 @@ char *TaskDescription(pTaskHead it);
get a description of the task at the current iterator
You are responsible for deleting the returned character array.
*/
long GetTaskID(pTaskHead it);
/*
get the ID of the current task
*/
long GetGroupID(pTaskHead it);
/*
get the group ID of the current task
*/
const char *GetTaskName(pTaskHead it);
/*
get the name of the current task. Do not delete the returned pointer.
*/
/*=============================================================================
Task Groups. The implementation has the limit that any given task can
only be member of one task group

View File

@ -61,6 +61,10 @@ static int KillCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
return 0;
}
if(!SCMatchRights(pCon,usMugger)){
return 0;
}
status = StopTask(pServ->pTasker,par[0]->value.v.text);
if(status == 0) {
SCWrite(pCon,"ERROR: cannot commit suicide!", eError);
@ -183,3 +187,37 @@ int TaskOBJFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
return 1;
}
/*-------------------------------------------------------------------*/
void InitTaskOBJ()
{
pSICSOBJ pNew = NULL;
pHdb cmd = NULL, node;
pNew = MakeSICSOBJv("task", "TaskOBJ", HIPNONE, usInternal);
if (pNew == NULL) {
SCWrite(pServ->dummyCon, "ERROR: out of memory creating new SICS object", eError);
return;
}
cmd = AddSICSHdbPar(pNew->objectNode, "ps", usSpy,
MakeSICSFunc(ListCmd));
cmd = AddSICSHdbPar(pNew->objectNode, "kill", usSpy,
MakeSICSFunc(KillCmd));
SetHdbProperty(cmd,"type","command");
SetHdbProperty(cmd,"priv","spy");
node = MakeSICSHdbPar("task",usSpy,MakeHdbText("banana"));
AddHipadabaChild(cmd,node,NULL);
cmd = AddSICSHdbPar(pNew->objectNode, "run", usSpy,
MakeSICSFunc(RunCmd));
SetHdbProperty(cmd,"type","command");
SetHdbProperty(cmd,"priv","spy");
node = MakeSICSHdbPar("script",usSpy,MakeHdbText("banana"));
AddHipadabaChild(cmd,node,NULL);
AddCommand(pServ->pSics,
"task", InterInvokeSICSOBJ, KillSICSOBJ, pNew);
}

234
tasmono.c Normal file
View File

@ -0,0 +1,234 @@
/**
* Triple axis monochromator module
* EIGER made it necessary to abstract out the monochromator. This is
* the default implementation for a sane, normal TAS. This implements a
* drivable interface. It gets an A2 value from the tasub module and is
* supposed to drive and monitor all the dependent monochromator motors.
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke, February 2013
*/
#include <sics.h>
#include "tasmono.h"
#include "tasub.h"
#define MOTPREC .01
#define A1 0
#define A2 1
#define MCV 2
#define MCH 3
#define NOTSTARTED -100
#define ABS(x) (x < 0 ? -(x) : (x))
/*----------------------------------------------------------------
This routine can return either OKOK or HWFault when thing
go wrong. However, the return value of Halt is usually ignored!
------------------------------------------------------------------*/
static int TAMOHalt(void *data) {
ptasUB self = NULL;
pIDrivable pDriv;
int i;
self = (ptasUB)data;
for(i = 0; i < 4; i++){
if (self->motors[i] != NULL) {
pDriv = GetDrivableInterface(self->motors[i]);
pDriv->Halt(self->motors[i]);
}
}
return OKOK;
}
/*----------------------------------------------------------------
This routine can return either 1 or 0. 1 means the position can
be reached, 0 NOT
If 0, error shall contain up to errlen characters of information
about which limit was violated
------------------------------------------------------------------*/
static int TAMOCheckLimits(void *data, float val,
char *error, int errlen){
ptasUB self = NULL;
self = (ptasUB)data;
/*
Not meaningful in this context
*/
return 1;
}
/*----------------------------------------------------------------
This routine can return 0 when a limit problem occurred
OKOK when the motor was successfully started
HWFault when a problem occured starting the device
Possible errors shall be printed to pCon
For real motors, this is supposed to try at least three times
to start the motor in question
val is the value to drive the motor too
------------------------------------------------------------------*/
static void writeMotPos(SConnection * pCon, int silent, char *name,
float val, float target)
{
char pBueffel[132];
if (silent != 1) {
snprintf(pBueffel, 131, "Driving %5s from %8.3f to %8.3f",
name, val, target);
SCWrite(pCon, pBueffel, eLog);
}
}
/*--------------------------------------------------------------------------*/
static long startTASMotor(pMotor mot, SConnection * pCon, char *name,
double target, int silent, int stopFixed)
{
float val, fixed, precision = MOTPREC;
long status = NOTSTARTED;
char buffer[132];
pIDrivable pDriv = NULL;
pDummy dum = NULL;
pDynString mes = NULL;
dum = (pDummy)mot;
GetDrivablePosition(mot, pCon,&val);
if(strcmp(dum->pDescriptor->name,"Motor") == 0){
MotorGetPar(mot,"precision",&precision);
MotorGetPar(mot, "fixed", &fixed);
if (ABS(fixed - 1.0) < .1) {
if(stopFixed == 0){
snprintf(buffer, 131, "WARNING: %s is FIXED", name);
SCWrite(pCon, buffer, eLog);
}
return NOTSTARTED;
}
}
mot->stopped = 0;
if (ABS(val - target) > precision) {
status = StartDriveTask(mot, pCon, name, (float)target);
if(status < 0){
SCPrintf(pCon,eLog,"ERROR: failed to drive %s to %f", name, target);
}
/*
to force updates on targets
*/
InvokeNewTarget(pServ->pExecutor, name, target);
writeMotPos(pCon, silent, name, val, target);
return status;
} else {
return NOTSTARTED;
}
}
/*-------------------------------------------------------------------------*/
static long TAMOSetValue(void *data, SConnection *pCon, float val){
ptasUB self = NULL;
self = (ptasUB)data;
int stopFixed = 0;
double curve;
int status;
self->monoTaskID = GetTaskGroupID(pServ->pTasker);
status = startTASMotor(self->motors[A1], pCon, "a1",
val / 2., self->silent, stopFixed);
if (status < 0 && status != NOTSTARTED) {
return HWFault;
}
if(status != NOTSTARTED){
AddTaskToGroup(pServ->pTasker,status, self->monoTaskID);
}
status = startTASMotor(self->motors[A2], pCon, "a2",
val, self->silent,stopFixed);
if (status < 0 && status != NOTSTARTED) {
return HWFault;
}
if(status != NOTSTARTED){
AddTaskToGroup(pServ->pTasker,status, self->monoTaskID);
}
if (self->motors[MCV] != NULL) {
curve = maCalcVerticalCurvature(self->machine.monochromator,
val);
status = startTASMotor(self->motors[MCV], pCon, "mcv",
curve, self->silent,stopFixed);
if (status < 0 && status != NOTSTARTED) {
SCWrite(pCon,"WARNING: monochromator vertical curvature motor failed to start", eLog);
SCSetInterrupt(pCon,eContinue);
} else {
AddTaskToGroup(pServ->pTasker,status, self->monoTaskID);
}
}
if (self->motors[MCH] != NULL) {
curve = maCalcHorizontalCurvature(self->machine.monochromator,
val);
status = startTASMotor(self->motors[MCH], pCon, "mch",
curve, self->silent,stopFixed);
if (status < 0 && status != NOTSTARTED) {
SCWrite(pCon,"WARNING: monochromator horizontal curvature motor failed to start", eLog);
SCSetInterrupt(pCon,eContinue);
}else {
AddTaskToGroup(pServ->pTasker,status,self->monoTaskID);
}
}
return OKOK;
}
/*----------------------------------------------------------------
Checks the status of a running motor. Possible return values
HWBusy The motor is still running
OKOK or HWIdle when the motor finished driving
HWFault when a hardware problem ocurred
HWPosFault when the hardware cannot reach a position
Errors are duly to be printed to pCon
For real motors CheckStatus again shall try hard to fix any
issues with the motor
------------------------------------------------------------------*/
static int TAMOCheckStatus(void *data, SConnection *pCon){
ptasUB self = NULL;
self = (ptasUB)data;
if(isTaskGroupRunning(pServ->pTasker,self->monoTaskID)) {
return HWBusy;
} else {
return HWIdle;
}
return 1;
}
/*----------------------------------------------------------------
GetValue is supposed to read a motor position
On errors, -99999999.99 is returned and messages printed to pCon
------------------------------------------------------------------*/
static float TAMOGetValue(void *data, SConnection *pCon){
ptasUB self = NULL;
float val = -99999999.99;
int status;
self = (ptasUB)data;
status = GetDrivablePosition(self->motors[A2], pCon, &val);
if (status == 0) {
return -99999999.99;
}
return val;
}
/*----------------------------------------------------------------
returns NULL on failure, a new datastructure else
------------------------------------------------------------------*/
pIDrivable MakeTasMono(){
pIDrivable pDriv;
pDriv = calloc(1,sizeof(IDrivable));
if(pDriv == NULL){
return NULL;
}
pDriv->Halt = TAMOHalt;
pDriv->CheckLimits = TAMOCheckLimits;
pDriv->SetValue = TAMOSetValue;
pDriv->CheckStatus = TAMOCheckStatus;
pDriv->GetValue = TAMOGetValue;
return pDriv;
}

19
tasmono.h Normal file
View File

@ -0,0 +1,19 @@
/**
* Triple axis monochromator module
* EIGER made it necessary to abstract out the monochromator. This is
* the default implementation for a sane, normal TAS. This implements a
* drivable interface. It gets an A2 value from the tasub module and is
* supposed to drive and monitor all the dependent monochromator motors.
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke, February 2013
*/
#ifndef __TASMONO
#define __TASMONO
pIDrivable MakeTasMono();
#endif

View File

@ -22,6 +22,7 @@
#include "tasub.h"
#include "tasdrive.h"
#include "vector.h"
#include "tasmono.h"
/*------------------- motor indexes in motor data structure ---------*/
#define A1 0
#define A2 1
@ -173,6 +174,8 @@ static ptasUB MakeTasUB()
pNew->actualEn = .0;
pNew->outOfPlaneAllowed = 1;
pNew->mustRecalculate = 1;
pNew->mono = MakeTasMono();
pNew->monoData = pNew;
return pNew;
}
@ -198,6 +201,9 @@ static void KillTasUB(void *pData)
if(self->updater != NULL){
free(self->updater);
}
if(self->mono != NULL){
free(self->mono);
}
free(self);
}

View File

@ -30,6 +30,9 @@
int mustDriveQ;
pMotor motors[12];
tasReflection r1, r2;
pIDrivable mono;
long monoTaskID;
void *monoData;
int ubValid;
int silent;
int stopFixed; /* flag to stop multiple fixed messages in scans*/

20
trace.c
View File

@ -199,12 +199,20 @@ static int strrepc(char *pszStr, char cFrom, char cTo)
/*-----------------------------------------------------------------*/
void traceprint(char *sub, char *id, char *data)
{
if(log != NULL && filter(sub,id)){
strrepc(data,'\n',':');
strrepc(sub,':','@');
strrepc(id,':','@');
fprintf(log,"%s:%s:%lf:%s\n",sub,id,DoubleTime(),data);
}
char *mysub, *myid, *mydata;
if(log != NULL && filter(sub,id)){
mysub = strdup(sub);
myid = strdup(id);
mydata = strdup(data);
strrepc(mydata,'\n',':');
strrepc(mysub,':','@');
strrepc(myid,':','@');
fprintf(log,"%s:%s:%lf:%s\n",mysub,myid,DoubleTime(),mydata);
free(mysub);
free(myid);
free(mydata);
}
}
/*-----------------------------------------------------------------*/
void traceIO(char *id, char *format, ...)

View File

@ -10,6 +10,10 @@
Heavily reworked to fit into the new four circle system
Mark Koennecke, July 2008
Added UBfromCell
Mark Koennecke, March 2013
-----------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
@ -252,7 +256,39 @@ static int calcUB(pUBCALC self, SConnection * pCon, char *ref1, char *ref2)
return 1;
}
}
/*---------------------------------------------------------------------*/
static int UBFromCell(pUBCALC self, SConnection *pCon)
{
const double *cell;
lattice mycell;
MATRIX B;
double ub[9];
int i;
cell = SXGetCell();
mycell.a = cell[0];
mycell.b = cell[1];
mycell.c = cell[2];
mycell.alpha = cell[3];
mycell.beta = cell[4];
mycell.gamma = cell[5];
B = mat_creat(3,3,ZERO_MATRIX);
if(B == NULL){
SCWrite(pCon,"ERROR: out of memory in UBfromCell",eError);
return 0;
}
calculateBMatrix(mycell,B);
if(self->UB != NULL){
mat_free(self->UB);
}
self->UB = B;
SCSendOK(pCon);
return 1;
}
/*---------------------------------------------------------------------*/
static int sendUBToHKL(SConnection * pCon, SicsInterp * pSics,
pHKL hkl, MATRIX UB)
@ -551,6 +587,8 @@ int UBCalcWrapper(SConnection * pCon, SicsInterp * pSics, void *pData,
return sendUBToHKL(pCon, pSics, self->hkl, self->UB);
} else if (strcmp(argv[1], "index") == 0) {
return findIndex(self, pCon, pSics, argc, argv);
} else if (strcmp(argv[1], "fromcell") == 0) {
return UBFromCell(self, pCon);
} else {
if (argc > 2) {
return setUBCalcParameters(self, pCon, argv[1], argv[2]);

View File

@ -117,7 +117,7 @@ double angleBetweenReflections(MATRIX B, reflection r1, reflection r2);
/**
* calculate the length of the scattering vector belonging to r
* @param B The B metric matrix to use
* @param r The reflction for which to calculate
* @param r The reflection for which to calculate
* @return The length of the scattering vector
*/
double scatteringVectorLength(MATRIX B, reflection r);

2
velo.c
View File

@ -802,7 +802,7 @@ int VelSelFactory(SConnection * pCon, SicsInterp * pSics, void *pData,
}
pT = InterpGetTcl(pSics);
site = getSite();
if (site != NULL) {
if (site != NULL && site->CreateVelocitySelector != NULL) {
pDriv = site->CreateVelocitySelector(argv[3], argv[4], pT);
}
if (!pDriv) {