PSI sics-cvs-psi-complete-tree-post-site-support
This commit is contained in:
234
SCinter.c
234
SCinter.c
@ -6,6 +6,9 @@
|
||||
|
||||
Mark Koennecke, November 1996
|
||||
|
||||
Made ListObjects moe intelligent: list objects according to interface etc.
|
||||
Mark Koennecke, December 2003
|
||||
|
||||
Copyright:
|
||||
|
||||
Labor fuer Neutronenstreuung
|
||||
@ -422,11 +425,9 @@ extern char *SkipSpace(char *pPtr);
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int ListObjects(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
/*------------------------------------------------------------------------*/
|
||||
static void printAll(SicsInterp *pSics, SConnection *pCon)
|
||||
{
|
||||
CommandList *pCurrent;
|
||||
char pBueffel[256];
|
||||
int iNum = 0;
|
||||
@ -465,6 +466,228 @@ extern char *SkipSpace(char *pPtr);
|
||||
strcat(pBueffel,"\r\n");
|
||||
SCWrite(pCon,pBueffel,eStatus);
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------------------
|
||||
printInterface prints only those objects which implement an interface
|
||||
as specified bi the id given
|
||||
-------------------------------------------------------------------------*/
|
||||
static void printInterface(SicsInterp *pSics, SConnection *pCon, int id)
|
||||
{
|
||||
CommandList *pCurrent;
|
||||
char pBueffel[256];
|
||||
int iNum = 0;
|
||||
pObjectDescriptor pObj = NULL;
|
||||
|
||||
assert(pSics);
|
||||
assert(pCon);
|
||||
|
||||
pBueffel[0] = '\0';
|
||||
pCurrent = pSics->pCList;
|
||||
while(pCurrent)
|
||||
{
|
||||
pObj = FindDescriptor(pCurrent->pData);
|
||||
if(pObj != NULL)
|
||||
{
|
||||
if(pObj->GetInterface(pObj,id) != NULL)
|
||||
{
|
||||
if(iNum == 0)
|
||||
{
|
||||
strcpy(pBueffel,pCurrent->pName);
|
||||
iNum++;
|
||||
}
|
||||
else if(iNum < 4)
|
||||
{
|
||||
strcat(pBueffel," ");
|
||||
strcat(pBueffel,pCurrent->pName);
|
||||
iNum++;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcat(pBueffel," ");
|
||||
strcat(pBueffel,pCurrent->pName);
|
||||
strcat(pBueffel,"\r\n");
|
||||
SCWrite(pCon,pBueffel,eStatus);
|
||||
iNum = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
pCurrent = pCurrent->pNext;
|
||||
}
|
||||
|
||||
/* write final entries */
|
||||
strcat(pBueffel,"\r\n");
|
||||
SCWrite(pCon,pBueffel,eStatus);
|
||||
}
|
||||
/*-----------------------------------------------------------------------
|
||||
printMatch prints only those objects which match the wildcard string given
|
||||
-------------------------------------------------------------------------*/
|
||||
extern int match(const char *mask, const char *name); /* from wwildcard.c */
|
||||
|
||||
static void printMatch(SicsInterp *pSics, SConnection *pCon, char *mask)
|
||||
{
|
||||
CommandList *pCurrent;
|
||||
char pBueffel[256];
|
||||
int iNum = 0;
|
||||
pObjectDescriptor pObj = NULL;
|
||||
|
||||
assert(pSics);
|
||||
assert(pCon);
|
||||
|
||||
pBueffel[0] = '\0';
|
||||
pCurrent = pSics->pCList;
|
||||
while(pCurrent)
|
||||
{
|
||||
pObj = FindDescriptor(pCurrent->pData);
|
||||
if(pObj != NULL)
|
||||
{
|
||||
if(!match(mask,pObj->name))
|
||||
{
|
||||
if(iNum == 0)
|
||||
{
|
||||
strcpy(pBueffel,pCurrent->pName);
|
||||
iNum++;
|
||||
}
|
||||
else if(iNum < 4)
|
||||
{
|
||||
strcat(pBueffel," ");
|
||||
strcat(pBueffel,pCurrent->pName);
|
||||
iNum++;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcat(pBueffel," ");
|
||||
strcat(pBueffel,pCurrent->pName);
|
||||
strcat(pBueffel,"\r\n");
|
||||
SCWrite(pCon,pBueffel,eStatus);
|
||||
iNum = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
pCurrent = pCurrent->pNext;
|
||||
}
|
||||
|
||||
/* write final entries */
|
||||
strcat(pBueffel,"\r\n");
|
||||
SCWrite(pCon,pBueffel,eStatus);
|
||||
}
|
||||
/*-----------------------------------------------------------------------
|
||||
printType prints only those objects which match the type given
|
||||
-------------------------------------------------------------------------*/
|
||||
static void printType(SicsInterp *pSics, SConnection *pCon, char *type)
|
||||
{
|
||||
CommandList *pCurrent;
|
||||
char pBueffel[256];
|
||||
int iNum = 0;
|
||||
|
||||
assert(pSics);
|
||||
assert(pCon);
|
||||
|
||||
pBueffel[0] = '\0';
|
||||
pCurrent = pSics->pCList;
|
||||
while(pCurrent)
|
||||
{
|
||||
if(pCurrent->pData != NULL)
|
||||
{
|
||||
if(iHasType(pCurrent->pData,type))
|
||||
{
|
||||
if(iNum == 0)
|
||||
{
|
||||
strcpy(pBueffel,pCurrent->pName);
|
||||
iNum++;
|
||||
}
|
||||
else if(iNum < 4)
|
||||
{
|
||||
strcat(pBueffel," ");
|
||||
strcat(pBueffel,pCurrent->pName);
|
||||
iNum++;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcat(pBueffel," ");
|
||||
strcat(pBueffel,pCurrent->pName);
|
||||
strcat(pBueffel,"\r\n");
|
||||
SCWrite(pCon,pBueffel,eStatus);
|
||||
iNum = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
pCurrent = pCurrent->pNext;
|
||||
}
|
||||
|
||||
/* write final entries */
|
||||
strcat(pBueffel,"\r\n");
|
||||
SCWrite(pCon,pBueffel,eStatus);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int ListObjects(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
|
||||
if(argc < 2)
|
||||
{
|
||||
printAll(pSics,pCon);
|
||||
return 1;
|
||||
}
|
||||
|
||||
strtolower(argv[1]);
|
||||
/*
|
||||
stand alone subcommands
|
||||
*/
|
||||
if(strstr(argv[1],"var") != NULL)
|
||||
{
|
||||
printType(pSics,pCon,"SicsVariable");
|
||||
return 1;
|
||||
}
|
||||
if(strstr(argv[1],"mot") != NULL)
|
||||
{
|
||||
printType(pSics,pCon,"Motor");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
subcommand with three args
|
||||
*/
|
||||
if(argc < 3)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: missing parameter to command or bad subcommand",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
interface
|
||||
*/
|
||||
if(strcmp(argv[1],"inter") == 0)
|
||||
{
|
||||
strtolower(argv[2]);
|
||||
if(strstr(argv[2],"driv") != NULL)
|
||||
{
|
||||
printInterface(pSics,pCon,DRIVEID);
|
||||
return 1;
|
||||
}
|
||||
if(strstr(argv[2],"coun") != NULL)
|
||||
{
|
||||
printInterface(pSics,pCon,COUNTID);
|
||||
return 1;
|
||||
}
|
||||
if(strstr(argv[2],"env") != NULL)
|
||||
{
|
||||
printInterface(pSics,pCon,ENVIRINTERFACE);
|
||||
return 1;
|
||||
}
|
||||
SCWrite(pCon,"ERROR: interface description nor recognized",eError);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
match
|
||||
*/
|
||||
if(strcmp(argv[1],"match") == 0)
|
||||
{
|
||||
printMatch(pSics,pCon,argv[2]);
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
@ -567,3 +790,4 @@ void *FindDrivable(SicsInterp *pSics, char *name){
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
15
alpha_def
Normal file
15
alpha_def
Normal file
@ -0,0 +1,15 @@
|
||||
#------------------------------------------------------------------------
|
||||
# Some defines used further up in the makefile hierarchy of the PSI SICS
|
||||
# universe.
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
#==========================================================================
|
||||
# the following lines only for fortified version
|
||||
#DFORTIFY=-DFORTIFY -I$(ROOT)/$(SRC)
|
||||
#FORTIFYOBJ=strdup.o fortify.o
|
||||
|
||||
#----------------select proper Makefile
|
||||
MFLAGS= -f $(SRC)makefile_alpha$(DUMMY) SRC=$(SRC)
|
||||
|
||||
#------------- path to HDF installation
|
||||
HDFROOT=/data/lnslib
|
@ -162,7 +162,10 @@ static int ColliderCheckStatus(void *pData, SConnection *pCon){
|
||||
Most of these are dummies........
|
||||
-----------------------------------------------------------------------*/
|
||||
static int ColliderHalt(void *pData){
|
||||
StopExe(pServ->pExecutor,"all");
|
||||
pAntiCollider self = (pAntiCollider) pData;
|
||||
|
||||
StopAllMotors(self->motorList);
|
||||
self->level = 999999999;
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------*/
|
||||
@ -178,7 +181,7 @@ static float ColliderGetValue(void *self, SConnection *pCon){
|
||||
int StartLevel(int level, int sequenceList, int motorList, SConnection *pCon){
|
||||
Sequence seq;
|
||||
pMotReg pMot = NULL;
|
||||
int iRet;
|
||||
int iRet, status;
|
||||
int count = 0;
|
||||
char pBueffel[132];
|
||||
|
||||
@ -188,8 +191,10 @@ int StartLevel(int level, int sequenceList, int motorList, SConnection *pCon){
|
||||
if(seq.level == level){
|
||||
pMot = FindMotEntry(motorList,seq.pMotor);
|
||||
if(pMot){
|
||||
StartRegMot(pMot,pCon,seq.target);
|
||||
count++;
|
||||
status = StartRegMot(pMot,pCon,seq.target);
|
||||
if(status){
|
||||
count++;
|
||||
}
|
||||
} else {
|
||||
sprintf(pBueffel,"ERROR: motor %s, requested from anticollider script",
|
||||
seq.pMotor);
|
||||
|
2
cd_obj
Normal file
2
cd_obj
Normal file
@ -0,0 +1,2 @@
|
||||
# define an alias to 'source cd_obj' for switching quick to object directory
|
||||
cd obj/$SICS_VERSION
|
85
choco.c
85
choco.c
@ -12,6 +12,7 @@
|
||||
#include <assert.h>
|
||||
#include "fortify.h"
|
||||
#include "sics.h"
|
||||
#include "site.h"
|
||||
#define CHOCOINTERNAL
|
||||
#include "choco.h"
|
||||
|
||||
@ -174,9 +175,6 @@
|
||||
*/
|
||||
|
||||
extern pCodri MakeSimChopper(void);
|
||||
extern pCodri MakeDoChoDriver(char *pHost, int iPort, int iChannel,
|
||||
int iSingle);
|
||||
extern pCodri MakeCookerDriver(char *pHost, int iPort, int iChannel);
|
||||
/*-----------------------------------------------------------------------*/
|
||||
int ChocoFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
@ -187,6 +185,7 @@ extern pCodri MakeCookerDriver(char *pHost, int iPort, int iChannel);
|
||||
char pBueffel[132];
|
||||
int iRet, iPort, iChannel;
|
||||
int iSingle = 0;
|
||||
pSite site = NULL;
|
||||
|
||||
if(argc < 3)
|
||||
{
|
||||
@ -206,78 +205,20 @@ extern pCodri MakeCookerDriver(char *pHost, int iPort, int iChannel);
|
||||
{
|
||||
pDriv = MakeSimChopper();
|
||||
}
|
||||
else if(strcmp(argv[2],"docho") == 0)
|
||||
{
|
||||
if(argc < 6)
|
||||
{
|
||||
SCWrite(pCon,
|
||||
"ERROR: Insufficient number of arguments to install Dornier Chopper driver",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
iRet = Tcl_GetInt(pSics->pTcl,argv[4],&iPort);
|
||||
if(iRet != TCL_OK)
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: expected integer as port number, got %s",
|
||||
argv[4]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
iRet = Tcl_GetInt(pSics->pTcl,argv[5],&iChannel);
|
||||
if(iRet != TCL_OK)
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: expected integer as channel number, got %s",
|
||||
argv[4]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
if(argc > 6)
|
||||
{
|
||||
iRet = Tcl_GetInt(pSics->pTcl,argv[6],&iSingle);
|
||||
if(iRet != TCL_OK)
|
||||
{
|
||||
sprintf(pBueffel,
|
||||
"ERROR: expected integer as single flag, got %s",
|
||||
argv[6]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
pDriv = MakeDoChoDriver(argv[3],iPort,iChannel,iSingle);
|
||||
}
|
||||
else if(strcmp(argv[2],"sanscook") == 0)
|
||||
{
|
||||
if(argc < 6)
|
||||
{
|
||||
SCWrite(pCon,
|
||||
"ERROR: Insufficient number of arguments to install SANS Cooker driver",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
iRet = Tcl_GetInt(pSics->pTcl,argv[4],&iPort);
|
||||
if(iRet != TCL_OK)
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: expected integer as port number, got %s",
|
||||
argv[4]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
iRet = Tcl_GetInt(pSics->pTcl,argv[5],&iChannel);
|
||||
if(iRet != TCL_OK)
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: expected integer as channel number, got %s",
|
||||
argv[4]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
pDriv = MakeCookerDriver(argv[3],iPort,iChannel);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: Driver %s NOT supported for MakeController",
|
||||
site = getSite();
|
||||
if(site != NULL){
|
||||
pDriv = site->CreateControllerDriver(pCon,argc-2,&argv[2]);
|
||||
} else {
|
||||
pDriv = NULL;
|
||||
}
|
||||
if(pDriv == NULL){
|
||||
sprintf(pBueffel,"ERROR: Driver %s NOT supported for MakeController",
|
||||
argv[2]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if( (pNew == NULL) || (pDes == NULL) || (pDriv == NULL) )
|
||||
{
|
||||
|
@ -105,7 +105,7 @@ the error can be ignored or was fully resolved.
|
||||
\item[pParList] is text string containing a comma separated list of
|
||||
all parameters understood by this driver.
|
||||
\item[pPrivate] Is a pointer to a driver specific specific data
|
||||
structure. This data structure will not be messed with by upper level code.
|
||||
structure. This data structure shall not be messed with by upper level code.
|
||||
\end{description}
|
||||
|
||||
\subsubsection{The Controller Object}
|
||||
|
@ -162,7 +162,7 @@
|
||||
for(i = 0; i < iNum; i++)
|
||||
{
|
||||
pPtr = (char *)getCircular(pTail);
|
||||
if(pCon->pSock)
|
||||
if(pCon->pSock && pPtr != NULL)
|
||||
{
|
||||
TelnetWrite(pCon->pSock, pPtr);
|
||||
}
|
||||
|
@ -15,5 +15,4 @@
|
||||
|
||||
void CommandLogClose(void *pData);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
18
conman.c
18
conman.c
@ -545,6 +545,13 @@ extern pServer pServ;
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
Do not die if no data
|
||||
*/
|
||||
if(pBuffer == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return self->write(self,pBuffer,iOut);
|
||||
}
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@ -647,7 +654,7 @@ void SCSetWriteFunc(SConnection *self, writeFunc x)
|
||||
iRet = NETWrite(self->pSock,buffer,strlen(buffer));
|
||||
if(!HasNL(buffer))
|
||||
{
|
||||
iRet = NETWrite(self->pSock,"\n",sizeof("\n"));
|
||||
iRet = NETWrite(self->pSock,"\n",strlen("\n"));
|
||||
}
|
||||
}
|
||||
if(!iRet)
|
||||
@ -951,6 +958,15 @@ void SCSetWriteFunc(SConnection *self, writeFunc x)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
do nothing if no data
|
||||
*/
|
||||
if(pName == NULL || pData == NULL)
|
||||
{
|
||||
SCWrite(self,"ERROR: no data to write in SCWriteZiped",eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* initialize the compression stuff */
|
||||
compStream.zalloc = (alloc_func)NULL;
|
||||
compStream.zfree = (free_func)NULL;
|
||||
|
16
conman.h
16
conman.h
@ -10,6 +10,8 @@
|
||||
|
||||
Mark Koennecke, September 1997
|
||||
|
||||
Mark Koennecke, Aprl 2003
|
||||
|
||||
copyright: see copyright.h
|
||||
----------------------------------------------------------------------------*/
|
||||
#ifndef SICSCONNECT
|
||||
@ -23,7 +25,7 @@
|
||||
#define MAXLOGFILES 10
|
||||
|
||||
typedef int (*writeFunc)(struct __SConnection *pCon,
|
||||
char *pMessage, int iCode);
|
||||
char *pMessage, int iCode);
|
||||
|
||||
typedef struct __SConnection {
|
||||
/* object basics */
|
||||
@ -47,24 +49,24 @@ typedef int (*writeFunc)(struct __SConnection *pCon,
|
||||
int eInterrupt;
|
||||
int iUserRights;
|
||||
int inUse;
|
||||
int iDummy;
|
||||
int iGrab;
|
||||
SicsInterp *pSics;
|
||||
|
||||
/* flag for parameter change */
|
||||
int iErrCode;
|
||||
int parameterChange;
|
||||
SicsInterp *pSics;
|
||||
|
||||
/* a FIFO */
|
||||
pCosta pStack;
|
||||
|
||||
/* callback registry */
|
||||
int iList;
|
||||
|
||||
|
||||
/* Tasking Stuff */
|
||||
int iEnd;
|
||||
/* for keeping track of the login
|
||||
process on a non telnet connection.
|
||||
Should only be used in SCTaskFunction
|
||||
*/
|
||||
*/
|
||||
int iLogin;
|
||||
time_t conStart;
|
||||
}SConnection;
|
||||
@ -99,7 +101,7 @@ typedef int (*writeFunc)(struct __SConnection *pCon,
|
||||
int SCRegister(SConnection *pCon, SicsInterp *pSics,
|
||||
void *pInter, long lID);
|
||||
int SCUnregister(SConnection *pCon, void *pInter);
|
||||
/******************************* Interrupt *********************************/
|
||||
/******************************* Error **************************************/
|
||||
void SCSetInterrupt(SConnection *self, int eCode);
|
||||
int SCGetInterrupt(SConnection *self);
|
||||
/****************************** Macro ***************************************/
|
||||
|
663
countdriv.c
663
countdriv.c
@ -43,9 +43,6 @@
|
||||
#include <string.h>
|
||||
#include "sics.h"
|
||||
#include "countdriv.h"
|
||||
#include "hardsup/sinq_prototypes.h"
|
||||
#include "hardsup/el737_def.h"
|
||||
#include "hardsup/el737fix.h"
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
pCounterDriver CreateCounterDriver(char *name, char *type)
|
||||
@ -92,661 +89,13 @@
|
||||
}
|
||||
if(self->pData)
|
||||
{
|
||||
free(self->pData);
|
||||
if(self->KillPrivate != NULL)
|
||||
{
|
||||
self->KillPrivate(self);
|
||||
} else {
|
||||
free(self->pData);
|
||||
}
|
||||
}
|
||||
free(self);
|
||||
}
|
||||
/*----------------------------- EL737 ------------------------------------*/
|
||||
typedef struct {
|
||||
char *host;
|
||||
int iPort;
|
||||
int iChannel;
|
||||
void *pData;
|
||||
int finishCount;
|
||||
} EL737st;
|
||||
/*------------------------------------------------------------------------*/
|
||||
static int EL737GetStatus(struct __COUNTER *self, float *fControl)
|
||||
{
|
||||
int iRet;
|
||||
int iC1, iC2, iC3,iC4,iRS;
|
||||
float fTime;
|
||||
EL737st *pEL737;
|
||||
|
||||
assert(self);
|
||||
pEL737 = (EL737st *)self->pData;
|
||||
assert(pEL737);
|
||||
iRet = EL737_GetStatus(&pEL737->pData,&iC1,&iC2,&iC3,&iC4,&fTime,&iRS);
|
||||
if(self->eMode == eTimer)
|
||||
{
|
||||
*fControl = fTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
*fControl = iC1;
|
||||
}
|
||||
/* store time */
|
||||
self->fTime = fTime;
|
||||
|
||||
if(iRet != 1)
|
||||
{
|
||||
return HWFault;
|
||||
}
|
||||
self->lCounts[0] = iC2;
|
||||
self->lCounts[1] = iC1;
|
||||
self->lCounts[2] = iC3;
|
||||
self->lCounts[3] = iC4;
|
||||
|
||||
/* get extra counters for 8-fold counter boxes */
|
||||
iRet = EL737_GetStatusExtra(&pEL737->pData,&iC1,&iC2,&iC3,&iC4);
|
||||
self->lCounts[4] = iC1;
|
||||
self->lCounts[5] = iC2;
|
||||
self->lCounts[6] = iC3;
|
||||
self->lCounts[7] = iC4;
|
||||
if(iRS == 0)
|
||||
{
|
||||
pEL737->finishCount++;
|
||||
if(pEL737->finishCount >= 2)
|
||||
{
|
||||
return HWIdle;
|
||||
}
|
||||
else
|
||||
{
|
||||
return HWBusy;
|
||||
}
|
||||
}
|
||||
else if((iRS == 1) || (iRS == 2))
|
||||
{
|
||||
pEL737->finishCount = 0;
|
||||
return HWBusy;
|
||||
}
|
||||
else if( (iRS == 5) || (iRS == 6))
|
||||
{
|
||||
pEL737->finishCount = 0;
|
||||
return HWNoBeam;
|
||||
}
|
||||
else
|
||||
{
|
||||
pEL737->finishCount = 0;
|
||||
return HWPause;
|
||||
}
|
||||
}
|
||||
#ifdef NONINTF
|
||||
extern float nintf(float f);
|
||||
#endif
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static int EL737Start(struct __COUNTER *self)
|
||||
{
|
||||
int iRet, iRS;
|
||||
EL737st *pEL737;
|
||||
|
||||
assert(self);
|
||||
pEL737 = (EL737st *)self->pData;
|
||||
assert(pEL737);
|
||||
|
||||
|
||||
self->fTime = 0.;
|
||||
|
||||
if(self->eMode == ePreset)
|
||||
{
|
||||
iRet = EL737_StartCnt(&pEL737->pData,(int)nintf(self->fPreset),&iRS);
|
||||
if(iRet == 1)
|
||||
{
|
||||
pEL737->finishCount = 0;
|
||||
return OKOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return HWFault;
|
||||
}
|
||||
}
|
||||
else if(self->eMode == eTimer)
|
||||
{
|
||||
iRet = EL737_StartTime(&pEL737->pData,self->fPreset,&iRS);
|
||||
if(iRet == 1)
|
||||
{
|
||||
pEL737->finishCount = 0;
|
||||
return OKOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return HWFault;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static int EL737Pause(struct __COUNTER *self)
|
||||
{
|
||||
int iRet, iRS;
|
||||
EL737st *pEL737;
|
||||
|
||||
assert(self);
|
||||
pEL737 = (EL737st *)self->pData;
|
||||
assert(pEL737);
|
||||
|
||||
|
||||
iRet = EL737_Pause(&pEL737->pData,&iRS);
|
||||
if(iRet == 1)
|
||||
{
|
||||
return OKOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return HWFault;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static int EL737Continue(struct __COUNTER *self)
|
||||
{
|
||||
int iRet, iRS;
|
||||
EL737st *pEL737;
|
||||
|
||||
assert(self);
|
||||
pEL737 = (EL737st *)self->pData;
|
||||
assert(pEL737);
|
||||
|
||||
|
||||
iRet = EL737_Continue(&pEL737->pData,&iRS);
|
||||
if(iRet == 1)
|
||||
{
|
||||
return OKOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return HWFault;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static int EL737Halt(struct __COUNTER *self)
|
||||
{
|
||||
int iRet, iC1, iC2, iC3, iC4,iRS;
|
||||
float fPreset;
|
||||
EL737st *pEL737;
|
||||
|
||||
assert(self);
|
||||
pEL737 = (EL737st *)self->pData;
|
||||
assert(pEL737);
|
||||
|
||||
|
||||
|
||||
iRet = EL737_Stop(&pEL737->pData,&iC1, &iC2,&iC3,&iC4,&fPreset,&iRS);
|
||||
if(iRet == 1)
|
||||
{
|
||||
self->lCounts[0] = iC2;
|
||||
self->lCounts[1] = iC1;
|
||||
self->lCounts[2] = iC3;
|
||||
self->lCounts[3] = iC4;
|
||||
return OKOK;
|
||||
}
|
||||
return HWFault;
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static int EL737ReadValues(struct __COUNTER *self)
|
||||
{
|
||||
int iRet;
|
||||
int iC1, iC2, iC3,iC4,iRS;
|
||||
float fTime;
|
||||
EL737st *pEL737;
|
||||
|
||||
assert(self);
|
||||
pEL737 = (EL737st *)self->pData;
|
||||
assert(pEL737);
|
||||
|
||||
|
||||
iRet = EL737_GetStatus(&pEL737->pData,&iC1,&iC2,&iC3,&iC4,&fTime,&iRS);
|
||||
if(iRet != 1)
|
||||
{
|
||||
return HWFault;
|
||||
}
|
||||
self->fTime = fTime;
|
||||
|
||||
self->lCounts[0] = iC2;
|
||||
self->lCounts[1] = iC1;
|
||||
self->lCounts[2] = iC3;
|
||||
self->lCounts[3] = iC4;
|
||||
/* get extra counters for 8-fold counter boxes */
|
||||
iRet = EL737_GetStatusExtra(&pEL737->pData,&iC1,&iC2,&iC3,&iC4);
|
||||
self->lCounts[4] = iC1;
|
||||
self->lCounts[5] = iC2;
|
||||
self->lCounts[6] = iC3;
|
||||
self->lCounts[7] = iC4;
|
||||
|
||||
return OKOK;
|
||||
}
|
||||
/*---------------------------------------------------------------------------
|
||||
|
||||
EL737Error2Text converts between an EL734 error code to text
|
||||
-----------------------------------------------------------------------------*/
|
||||
static void EL737Error2Text(char *pBuffer, int iErr)
|
||||
{
|
||||
switch(iErr)
|
||||
{
|
||||
case EL737__BAD_ADR:
|
||||
strcpy(pBuffer,"EL737__BAD_ADR");
|
||||
break;
|
||||
case EL737__BAD_OVFL:
|
||||
strcpy(pBuffer,"EL737__BAD_OVFL");
|
||||
break;
|
||||
case EL737__BAD_BSY:
|
||||
strcpy(pBuffer,"EL737__BAD_BSY");
|
||||
break;
|
||||
case EL737__BAD_SNTX:
|
||||
strcpy(pBuffer,"EL737__BAD_SNTX");
|
||||
break;
|
||||
case EL737__BAD_CONNECT:
|
||||
strcpy(pBuffer,"EL737__BAD_CONNECT");
|
||||
break;
|
||||
case EL737__BAD_FLUSH:
|
||||
strcpy(pBuffer,"EL737__BAD_FLUSH");
|
||||
break;
|
||||
case EL737__BAD_DEV:
|
||||
strcpy(pBuffer,"EL734__BAD_DEV");
|
||||
break;
|
||||
case EL737__BAD_ID:
|
||||
strcpy(pBuffer,"EL737__BAD_ID");
|
||||
break;
|
||||
case EL737__BAD_ILLG:
|
||||
strcpy(pBuffer,"EL737__BAD_ILLG");
|
||||
break;
|
||||
case EL737__BAD_LOC:
|
||||
strcpy(pBuffer,"EL737__BAD_LOC");
|
||||
break;
|
||||
case EL737__BAD_MALLOC:
|
||||
strcpy(pBuffer,"EL737__BAD_MALLOC");
|
||||
break;
|
||||
case EL737__BAD_NOT_BCD:
|
||||
strcpy(pBuffer,"EL737__BAD_NOT_BCD");
|
||||
break;
|
||||
case EL737__BAD_OFL:
|
||||
strcpy(pBuffer,"EL737__BAD_OFL");
|
||||
break;
|
||||
case EL737__BAD_PAR:
|
||||
strcpy(pBuffer,"EL737__BAD_PAR");
|
||||
break;
|
||||
|
||||
case EL737__BAD_RECV:
|
||||
strcpy(pBuffer,"EL737__BAD_RECV");
|
||||
break;
|
||||
case EL737__BAD_RECV_NET:
|
||||
strcpy(pBuffer,"EL737__BAD_RECV_NET");
|
||||
break;
|
||||
case EL737__BAD_RECV_PIPE:
|
||||
strcpy(pBuffer,"EL737__BAD_RECV_PIPE");
|
||||
break;
|
||||
case EL737__BAD_RECV_UNKN:
|
||||
strcpy(pBuffer,"EL737__BAD_RECV_UNKN");
|
||||
break;
|
||||
case EL737__BAD_RECVLEN:
|
||||
strcpy(pBuffer,"EL737__BAD_RECVLEN");
|
||||
break;
|
||||
case EL737__BAD_RECV1:
|
||||
strcpy(pBuffer,"EL737__BAD_RECV1");
|
||||
break;
|
||||
case EL737__BAD_RECV1_NET:
|
||||
strcpy(pBuffer,"EL737__BAD_RECV1_NET");
|
||||
break;
|
||||
case EL737__BAD_RECV1_PIPE:
|
||||
strcpy(pBuffer,"EL737__BAD_RECV1_PIPE");
|
||||
break;
|
||||
case EL737__BAD_RNG:
|
||||
strcpy(pBuffer,"EL737__BAD_RNG");
|
||||
break;
|
||||
case EL737__BAD_SEND:
|
||||
strcpy(pBuffer,"EL737__BAD_SEND");
|
||||
break;
|
||||
case EL737__BAD_SEND_PIPE:
|
||||
strcpy(pBuffer,"EL737__BAD_SEND_PIPE");
|
||||
break;
|
||||
case EL737__BAD_SEND_NET:
|
||||
strcpy(pBuffer,"EL737__BAD_SEND_NET");
|
||||
break;
|
||||
case EL737__BAD_SEND_UNKN:
|
||||
strcpy(pBuffer,"EL737__BAD_SEND_UNKN");
|
||||
break;
|
||||
case EL737__BAD_SENDLEN:
|
||||
strcpy(pBuffer,"EL737__BAD_SENDLEN");
|
||||
break;
|
||||
case EL737__BAD_SOCKET:
|
||||
strcpy(pBuffer,"EL737__BAD_SOCKET");
|
||||
break;
|
||||
case EL737__BAD_TMO:
|
||||
strcpy(pBuffer,"EL737__BAD_TMO");
|
||||
break;
|
||||
case EL737__FORCED_CLOSED:
|
||||
strcpy(pBuffer,"EL737__FORCED_CLOSED");
|
||||
break;
|
||||
case EL737__BAD_ASYNSRV:
|
||||
strcpy(pBuffer,"EL737__BAD_ASYNSRV");
|
||||
break;
|
||||
default:
|
||||
sprintf(pBuffer,"Unknown EL737 error %d", iErr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static int EL737GetError(struct __COUNTER *self, int *iCode,
|
||||
char *error, int iErrLen)
|
||||
{
|
||||
char *pErr = NULL;
|
||||
int iC1, iC2, iC3;
|
||||
char pBueffel[256];
|
||||
|
||||
if(self->iErrorCode == UNKNOWNPAR)
|
||||
{
|
||||
strncpy(error,"unknown internal parameter code",iErrLen);
|
||||
*iCode = self->iErrorCode;
|
||||
self->iErrorCode = 0;
|
||||
return 1;
|
||||
}
|
||||
else if(self->iErrorCode == BADCOUNTER)
|
||||
{
|
||||
strncpy(error,"monitor cannot be selected",iErrLen);
|
||||
*iCode = self->iErrorCode;
|
||||
self->iErrorCode = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
EL737_ErrInfo(&pErr,&iC1,&iC2, &iC3);
|
||||
EL737Error2Text(pBueffel,iC1);
|
||||
|
||||
strncpy(error,pBueffel,iErrLen);
|
||||
*iCode = iC1;
|
||||
return 1;
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static int EL737TryAndFixIt(struct __COUNTER *self, int iCode)
|
||||
{
|
||||
EL737st *pEL737;
|
||||
int iRet;
|
||||
char pCommand[50], pReply[50];
|
||||
|
||||
assert(self);
|
||||
pEL737 = (EL737st *)self->pData;
|
||||
assert(pEL737);
|
||||
|
||||
switch(iCode)
|
||||
{
|
||||
case EL737__BAD_ILLG:
|
||||
case EL737__BAD_ADR:
|
||||
case EL737__BAD_PAR:
|
||||
case EL737__BAD_TMO:
|
||||
case EL737__BAD_REPLY:
|
||||
case EL737__BAD_SNTX:
|
||||
case EL737__BAD_OVFL:
|
||||
return COREDO;
|
||||
break;
|
||||
case EL737__BAD_BSY:
|
||||
strcpy(pCommand,"S \r");
|
||||
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,49);
|
||||
if(iRet < 0)
|
||||
{
|
||||
return COTERM;
|
||||
}
|
||||
else
|
||||
{
|
||||
return COREDO;
|
||||
}
|
||||
break;
|
||||
case EL737__BAD_LOC:
|
||||
strcpy(pCommand,"rmt 1\r");
|
||||
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,49);
|
||||
if(iRet < 0)
|
||||
{
|
||||
return COTERM;
|
||||
}
|
||||
strcpy(pCommand,"echo 2\r");
|
||||
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,49);
|
||||
if(iRet < 0)
|
||||
{
|
||||
return COTERM;
|
||||
}
|
||||
strcpy(pCommand,"ra\r");
|
||||
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,49);
|
||||
if(iRet < 0)
|
||||
{
|
||||
return COTERM;
|
||||
}
|
||||
return COREDO;
|
||||
break;
|
||||
case EL737__BAD_DEV:
|
||||
case EL737__BAD_ID:
|
||||
case EL737__BAD_NOT_BCD:
|
||||
case UNKNOWNPAR:
|
||||
case BADCOUNTER:
|
||||
return COTERM;
|
||||
break;
|
||||
case EL737__FORCED_CLOSED:
|
||||
iRet = EL737_Open(&pEL737->pData,pEL737->host, pEL737->iPort,
|
||||
pEL737->iChannel);
|
||||
if(iRet == 1)
|
||||
{
|
||||
return COREDO;
|
||||
}
|
||||
else
|
||||
{
|
||||
return COTERM;
|
||||
}
|
||||
break;
|
||||
case EL737__BAD_OFL:
|
||||
EL737_Close(&pEL737->pData,0);
|
||||
iRet = EL737_Open(&pEL737->pData,pEL737->host, pEL737->iPort,
|
||||
pEL737->iChannel);
|
||||
if(iRet == 1)
|
||||
{
|
||||
return COREDO;
|
||||
}
|
||||
else
|
||||
{
|
||||
return COTERM;
|
||||
}
|
||||
break;
|
||||
/* case EL737__BAD_ASYNSRV:
|
||||
EL737_Close(&pEL737->pData,1);
|
||||
return COREDO;
|
||||
*/ default:
|
||||
/* try to reopen connection */
|
||||
|
||||
EL737_Close(&pEL737->pData,1);
|
||||
iRet = EL737_Open(&pEL737->pData,pEL737->host, pEL737->iPort,
|
||||
pEL737->iChannel);
|
||||
if(iRet == 1)
|
||||
{
|
||||
return COREDO;
|
||||
}
|
||||
else
|
||||
{
|
||||
return COTERM;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return COTERM;
|
||||
}
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static int EL737Set(struct __COUNTER *self, char *name, int iCter,
|
||||
float fVal)
|
||||
{
|
||||
int iRet;
|
||||
EL737st *pEL737;
|
||||
char pCommand[80],pReply[80];
|
||||
|
||||
assert(self);
|
||||
pEL737 = (EL737st *)self->pData;
|
||||
assert(pEL737);
|
||||
|
||||
if(strcmp(name,"threshold") == 0)
|
||||
{
|
||||
sprintf(pCommand,"DL %1.1d %f\r",iCter,fVal);
|
||||
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,79);
|
||||
if(iRet == 1)
|
||||
{
|
||||
if(pCommand[0] == '?')
|
||||
{
|
||||
self->iErrorCode = BADCOUNTER;
|
||||
return HWFault;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return HWFault;
|
||||
}
|
||||
sprintf(pCommand,"DR %1.1d \r",iCter);
|
||||
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,79);
|
||||
if(iRet == 1)
|
||||
{
|
||||
if(pCommand[0] == '?')
|
||||
{
|
||||
self->iErrorCode = BADCOUNTER;
|
||||
return HWFault;
|
||||
}
|
||||
return OKOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return HWFault;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self->iErrorCode = UNKNOWNPAR;
|
||||
return HWFault;
|
||||
}
|
||||
}
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static int EL737Get(struct __COUNTER *self, char *name, int iCter,
|
||||
float *fVal)
|
||||
{
|
||||
int iRet;
|
||||
EL737st *pEL737;
|
||||
char pCommand[80],pReply[80];
|
||||
|
||||
assert(self);
|
||||
pEL737 = (EL737st *)self->pData;
|
||||
assert(pEL737);
|
||||
|
||||
if(strcmp(name,"threshold") == 0)
|
||||
{
|
||||
sprintf(pCommand,"DL %1.1d\r",iCter);
|
||||
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,79);
|
||||
if(iRet == 1)
|
||||
{
|
||||
if(pReply[0] == '?')
|
||||
{
|
||||
self->iErrorCode = BADCOUNTER;
|
||||
return HWFault;
|
||||
}
|
||||
sscanf(pReply,"%f",fVal);
|
||||
return OKOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return HWFault;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self->iErrorCode = UNKNOWNPAR;
|
||||
return HWFault;
|
||||
}
|
||||
}
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static int EL737Send(struct __COUNTER *self, char *pText, char *pReply,
|
||||
int iReplyLen)
|
||||
{
|
||||
EL737st *pEL737;
|
||||
char pBuffer[256];
|
||||
|
||||
assert(self);
|
||||
pEL737 = (EL737st *)self->pData;
|
||||
assert(pEL737);
|
||||
|
||||
/* ensure a \r at the end of the text */
|
||||
if(strlen(pText) > 254)
|
||||
{
|
||||
strncpy(pReply,"Command to long",iReplyLen);
|
||||
return 1;
|
||||
}
|
||||
strcpy(pBuffer,pText);
|
||||
if(strchr(pBuffer,(int)'\r') == NULL)
|
||||
{
|
||||
strcat(pBuffer,"\r");
|
||||
}
|
||||
|
||||
return EL737_SendCmnd(&pEL737->pData,pBuffer,pReply,iReplyLen);
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
pCounterDriver NewEL737Counter(char *name, char *host, int iPort, int iChannel)
|
||||
{
|
||||
pCounterDriver pRes = NULL;
|
||||
EL737st *pData = NULL;
|
||||
int iRet;
|
||||
int iC1, iC2, iC3;
|
||||
char *pErr;
|
||||
char pBueffel[132];
|
||||
|
||||
pRes = CreateCounterDriver(name, "EL737");
|
||||
if(!pRes)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* open connection to counter */
|
||||
pData = (EL737st *)malloc(sizeof(EL737st));
|
||||
if(!pData)
|
||||
{
|
||||
DeleteCounterDriver(pRes);
|
||||
return NULL;
|
||||
}
|
||||
pData->host = strdup(host);
|
||||
pData->iPort = iPort;
|
||||
pData->iChannel = iChannel;
|
||||
pData->pData = NULL;
|
||||
iRet = EL737_Open(&(pData->pData), host,iPort,iChannel);
|
||||
if(iRet != 1)
|
||||
{
|
||||
EL737_ErrInfo(&pErr,&iC1,&iC2, &iC3);
|
||||
DeleteCounterDriver(pRes);
|
||||
if(pData->host)
|
||||
{
|
||||
free(pData->host);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
pRes->pData = (void *)pData;
|
||||
|
||||
/* assign functions */
|
||||
pRes->GetStatus = EL737GetStatus;
|
||||
pRes->Start = EL737Start;
|
||||
pRes->Halt = EL737Halt;
|
||||
pRes->ReadValues = EL737ReadValues;
|
||||
pRes->GetError = EL737GetError;
|
||||
pRes->TryAndFixIt = EL737TryAndFixIt;
|
||||
pRes->Pause = EL737Pause;
|
||||
pRes->Continue = EL737Continue;
|
||||
pRes->Set = EL737Set;
|
||||
pRes->Get = EL737Get;
|
||||
pRes->Send = EL737Send;
|
||||
pRes->iNoOfMonitors = 7;
|
||||
pRes->fTime = 0.;
|
||||
|
||||
return pRes;
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
void KillEL737Counter(pCounterDriver self)
|
||||
{
|
||||
EL737st *pEL737 = NULL;
|
||||
|
||||
assert(self);
|
||||
pEL737 = (EL737st *)self->pData;
|
||||
assert(pEL737);
|
||||
|
||||
EL737_Close(&pEL737->pData,0);
|
||||
if(pEL737->host)
|
||||
{
|
||||
free(pEL737->host);
|
||||
}
|
||||
DeleteCounterDriver(self);
|
||||
}
|
||||
|
||||
|
@ -61,6 +61,7 @@
|
||||
int iCter, float *fVal);
|
||||
int (*Send)(struct __COUNTER *self, char *pText,
|
||||
char *pReply, int iReplyLen);
|
||||
void (*KillPrivate)(struct __COUNTER *self);
|
||||
void *pData; /* counter specific data goes here, ONLY for
|
||||
internal driver use!
|
||||
*/
|
||||
|
94
counter.c
94
counter.c
@ -5,13 +5,13 @@
|
||||
The SICS Interface to a single detector and his associated
|
||||
monitors.
|
||||
|
||||
|
||||
|
||||
Mark Koennecke, January 1997
|
||||
|
||||
Copyright:
|
||||
|
||||
Labor fuer Neutronenstreuung
|
||||
Paul Scherrer Institut
|
||||
Paul Scherrer Institut
|
||||
CH-5423 Villigen-PSI
|
||||
|
||||
|
||||
@ -50,7 +50,7 @@
|
||||
#include "fupa.h"
|
||||
#include "status.h"
|
||||
#include "splitter.h"
|
||||
#include "ecbcounter.h"
|
||||
#include "site.h"
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/*
|
||||
The monitor callback data structure
|
||||
@ -104,6 +104,7 @@
|
||||
{
|
||||
self->isUpToDate = 0;
|
||||
self->tStart = time(&tX);
|
||||
InvokeCallBack(self->pCall,COUNTSTART,pCon);
|
||||
return iRet;
|
||||
}
|
||||
else
|
||||
@ -154,7 +155,8 @@
|
||||
iRet = self->pDriv->TryAndFixIt(self->pDriv,iErr);
|
||||
if(iRet == COTERM)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: Cannot fix counter problem, aborting",eError);
|
||||
SCWrite(pCon,"ERROR: Cannot fix counter problem, aborting",
|
||||
eError);
|
||||
SCSetInterrupt(pCon,eAbortBatch);
|
||||
return HWFault;
|
||||
}
|
||||
@ -230,6 +232,7 @@
|
||||
{
|
||||
SCWrite(pCon,"ERROR: Cannot fix counter problem, aborting",eError);
|
||||
SCSetInterrupt(pCon,eAbortBatch);
|
||||
InvokeCallBack(self->pCall,COUNTEND,NULL);
|
||||
return eCt;
|
||||
}
|
||||
else
|
||||
@ -237,6 +240,10 @@
|
||||
return HWBusy;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
handle count parameters and notify listeners on progress
|
||||
*/
|
||||
sMon.fCurrent = fControl;
|
||||
sMon.fPreset = self->pDriv->fPreset;
|
||||
sMon.pName = self->name;
|
||||
@ -250,6 +257,14 @@
|
||||
self->iCallbackCounter++;
|
||||
}
|
||||
self->pDriv->fLastCurrent = fControl;
|
||||
|
||||
/*
|
||||
notification on finish
|
||||
*/
|
||||
if(eCt == HWIdle)
|
||||
{
|
||||
InvokeCallBack(self->pCall,COUNTEND,NULL);
|
||||
}
|
||||
return eCt;
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
@ -411,22 +426,7 @@
|
||||
}
|
||||
if(self->pDriv)
|
||||
{
|
||||
if(strcmp(self->pDriv->type,"EL737") == 0)
|
||||
{
|
||||
KillEL737Counter(self->pDriv);
|
||||
}
|
||||
else if (strcmp(self->pDriv->type,"SIM") == 0)
|
||||
{
|
||||
KillSIMCounter(self->pDriv);
|
||||
}
|
||||
else if(strcmp(self->pDriv->type,"ecb") == 0)
|
||||
{
|
||||
KillECBCounter(self->pDriv);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
DeleteCounterDriver(self->pDriv);
|
||||
}
|
||||
free(self);
|
||||
}
|
||||
@ -488,6 +488,7 @@
|
||||
SetStatus(eOld);
|
||||
return iRet;
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
@ -496,46 +497,35 @@
|
||||
{
|
||||
pCounter pNew = NULL;
|
||||
pCounterDriver pDriv = NULL;
|
||||
float fFail = -1;
|
||||
int iRet;
|
||||
char pBueffel[256];
|
||||
char **argx;
|
||||
FuPaResult pParse;
|
||||
FuncTemplate MakeTemplate[] = {
|
||||
{"el737",3,{FUPATEXT,FUPAINT,FUPAINT}},
|
||||
{"sim",1,{FUPAFLOAT}},
|
||||
{"ecb",1,{FUPATEXT}}
|
||||
};
|
||||
pSite site = NULL;
|
||||
|
||||
assert(pCon);
|
||||
assert(pSics);
|
||||
|
||||
argtolower(argc,argv);
|
||||
/* parse function template */
|
||||
argx = &argv[2]; /* 0 = MakeCounter, 1 = counter name */
|
||||
iRet = EvaluateFuPa((pFuncTemplate)&MakeTemplate,3,argc-2,argx,&pParse);
|
||||
if(iRet < 0) /* I/O error */
|
||||
{
|
||||
sprintf(pBueffel,"%s",pParse.pError);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
argtolower(argc,argv);
|
||||
if(argc < 3){
|
||||
SCWrite(pCon,"ERROR: insuficient number of arguments to MakeCounter",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* create driver depending on parse result */
|
||||
switch(iRet)
|
||||
{
|
||||
case 0: /* EL737 driver */
|
||||
pDriv = NewEL737Counter(argv[1],pParse.Arg[0].text,
|
||||
pParse.Arg[1].iVal,pParse.Arg[2].iVal);
|
||||
break;
|
||||
case 1: /* SIM */
|
||||
pDriv = NewSIMCounter(argv[1],pParse.Arg[0].fVal);
|
||||
break;
|
||||
case 2: /* ecb */
|
||||
pDriv = MakeECBCounter(pParse.Arg[0].text);
|
||||
break;
|
||||
default:
|
||||
assert(0); /* internal error */
|
||||
site = getSite();
|
||||
if(site != NULL){
|
||||
pDriv = site->CreateCounterDriver(pCon,argc,argv);
|
||||
}
|
||||
|
||||
/*
|
||||
test for simulation driver, which is for everybody
|
||||
*/
|
||||
if(strcmp(argv[2],"sim") == 0){
|
||||
if(argc > 3){
|
||||
fFail = atof(argv[3]);
|
||||
pDriv = NewSIMCounter(argv[1],fFail);
|
||||
}
|
||||
}
|
||||
|
||||
if(!pDriv)
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: cannot create requested driver %s",
|
||||
@ -743,7 +733,7 @@
|
||||
{"setexponent",1,{FUPAINT,0}},
|
||||
{"getexponent",0,{0,0}},
|
||||
{"interest",0,{0,0}},
|
||||
{"uninterest",0,{0,0}},
|
||||
{"uninterest",0,{0,0}},
|
||||
{"status",0,{0,0}},
|
||||
{"gettime",0,{0,0}},
|
||||
{"countnb",1,{FUPAFLOAT} },
|
||||
|
242
danu.c
242
danu.c
@ -4,7 +4,12 @@
|
||||
Implementation file for the data number module.
|
||||
|
||||
Mark Koennecke, Juli 1997
|
||||
|
||||
|
||||
Added callbacks, stepping to next thousand
|
||||
|
||||
Mark Koennecke, December 2003
|
||||
|
||||
|
||||
Copyright:
|
||||
|
||||
Labor fuer Neutronenstreuung
|
||||
@ -38,18 +43,87 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include "fortify.h"
|
||||
#include "conman.h"
|
||||
#include "obdes.h"
|
||||
#include "sics.h"
|
||||
#include "danu.h"
|
||||
|
||||
/* ------------------ the data structure ----------------------------------*/
|
||||
typedef struct __DataNumber {
|
||||
pObjectDescriptor pDes;
|
||||
pICallBack pCall;
|
||||
char *pFileName;
|
||||
} DataNumber;
|
||||
/*----------------------------------------------------------------------*/
|
||||
static int readDataNumber(pDataNumber self)
|
||||
{
|
||||
FILE *fd = NULL;
|
||||
int iNum = 0;
|
||||
|
||||
/* open file */
|
||||
fd = fopen(self->pFileName,"r");
|
||||
if(!fd)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* get and increment number */
|
||||
fscanf(fd,"%d",&iNum);
|
||||
fclose(fd);
|
||||
return iNum;
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static int writeDataNumber(pDataNumber self, int iNum)
|
||||
{
|
||||
FILE *fd = NULL;
|
||||
|
||||
/* reopen for rewriting */
|
||||
fd = fopen(self->pFileName,"w");
|
||||
if(fd == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* write file and leave */
|
||||
fprintf(fd," %d \n",iNum);
|
||||
fprintf(fd,"NEVER, EVER modify or delete this file\n");
|
||||
fprintf(fd,
|
||||
"You'll risk eternal damnation and a reincarnation as a cockroach!|n");
|
||||
fclose(fd);
|
||||
return 1;
|
||||
}
|
||||
/*------------------- The CallBack function for interest ------------------*/
|
||||
static int InterestCallback(int iEvent, void *pEvent, void *pUser)
|
||||
{
|
||||
pDataNumber self = NULL;
|
||||
SConnection *pCon = NULL;
|
||||
char pBueffel[132];
|
||||
int iNum;
|
||||
|
||||
if(iEvent != VALUECHANGE)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
assert(pEvent);
|
||||
assert(pUser);
|
||||
|
||||
pCon = (SConnection *)pUser;
|
||||
self = (pDataNumber)pEvent;
|
||||
|
||||
/*
|
||||
read number
|
||||
*/
|
||||
iNum = readDataNumber(self);
|
||||
if(iNum > 0)
|
||||
{
|
||||
snprintf(pBueffel,131,"sicsdatanumber = %d", iNum);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*-------------------------------------------------------------------------*/
|
||||
pDataNumber CreateDataNumber(char *pFileName)
|
||||
{
|
||||
@ -64,7 +138,8 @@
|
||||
memset(pNew,0,sizeof(DataNumber));
|
||||
|
||||
pNew->pDes = CreateDescriptor("DataNumber");
|
||||
if(!pNew->pDes)
|
||||
pNew->pCall = CreateCallBackInterface();
|
||||
if(!pNew->pDes || !pNew->pCall)
|
||||
{
|
||||
free(pNew);
|
||||
return NULL;
|
||||
@ -95,6 +170,11 @@
|
||||
{
|
||||
DeleteDescriptor(self->pDes);
|
||||
}
|
||||
if(self->pCall)
|
||||
{
|
||||
DeleteCallBackInterface(self->pCall);
|
||||
self->pCall = NULL;
|
||||
}
|
||||
if(self->pFileName)
|
||||
{
|
||||
free(self->pFileName);
|
||||
@ -109,36 +189,26 @@
|
||||
time_t iTime;
|
||||
struct tm *psTime;
|
||||
|
||||
/* open file */
|
||||
fd = fopen(self->pFileName,"r");
|
||||
if(!fd)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* get and increment number */
|
||||
fscanf(fd,"%d",&iNum);
|
||||
iNum++;
|
||||
fclose(fd);
|
||||
|
||||
/* reopen for rewriting */
|
||||
fd = fopen(self->pFileName,"w");
|
||||
if(fd == NULL)
|
||||
iNum = readDataNumber(self);
|
||||
if(iNum < 0)
|
||||
{
|
||||
return -1;
|
||||
return iNum;
|
||||
}
|
||||
|
||||
/* write file and leave */
|
||||
fprintf(fd," %d \n",iNum);
|
||||
fprintf(fd,"NEVER, EVER modify or delete this file\n");
|
||||
fprintf(fd,"You'll risk eternal damnation and a reincarnation as a cockroach!|n");
|
||||
fclose(fd);
|
||||
|
||||
|
||||
iNum++;
|
||||
|
||||
/* get year */
|
||||
iTime = time(NULL);
|
||||
psTime = localtime(&iTime);
|
||||
*iYear = psTime->tm_year + 1900;
|
||||
|
||||
if(writeDataNumber(self,iNum) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
InvokeCallBack(self->pCall, VALUECHANGE, self);
|
||||
|
||||
return iNum;
|
||||
}
|
||||
@ -146,34 +216,55 @@
|
||||
int DecrementDataNumber(pDataNumber self)
|
||||
{
|
||||
FILE *fd = NULL;
|
||||
int iNum;
|
||||
|
||||
/* open file */
|
||||
fd = fopen(self->pFileName,"r");
|
||||
if(!fd)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* get and decrement number */
|
||||
fscanf(fd,"%d",&iNum);
|
||||
iNum--;
|
||||
if(iNum < 0)
|
||||
iNum = 0;
|
||||
fclose(fd);
|
||||
int iNum, currentThousand;
|
||||
|
||||
/* reopen for rewriting */
|
||||
fd = fopen(self->pFileName,"w");
|
||||
|
||||
/* write file and leave */
|
||||
fprintf(fd," %d \n",iNum);
|
||||
fprintf(fd,"NEVER, EVER modify or delete this file\n");
|
||||
fprintf(fd,"You'll risk eternal damnation and a reincarnation as a cockroach!|n");
|
||||
fclose(fd);
|
||||
iNum = readDataNumber(self);
|
||||
if(iNum < 0)
|
||||
{
|
||||
return iNum;
|
||||
}
|
||||
|
||||
/*
|
||||
decrement DataNumber with restrictions:
|
||||
- not at all lower 0
|
||||
- do not understep a thousand boundary
|
||||
*/
|
||||
currentThousand = (int)floor(iNum/1000.);
|
||||
iNum--;
|
||||
if((int)floor(iNum/1000.) < currentThousand)
|
||||
{
|
||||
iNum++;
|
||||
}
|
||||
|
||||
if(writeDataNumber(self,iNum) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return iNum;
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
int NewThousand(pDataNumber self)
|
||||
{
|
||||
int iNum, currentThousand;
|
||||
|
||||
iNum = readDataNumber(self);
|
||||
if(iNum < 0)
|
||||
{
|
||||
return iNum;
|
||||
}
|
||||
|
||||
/* set to next thousand number */
|
||||
currentThousand = (int)floor(iNum/1000.);
|
||||
iNum = (currentThousand + 1)*1000;
|
||||
|
||||
if(writeDataNumber(self,iNum) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return iNum;
|
||||
}
|
||||
/*-------------------------------------------------------------------------*/
|
||||
int DNWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
@ -182,6 +273,7 @@
|
||||
FILE *fd = NULL;
|
||||
int iNum, iYear;
|
||||
char pBueffel[512];
|
||||
long lID;
|
||||
|
||||
self = (pDataNumber)pData;
|
||||
assert(self);
|
||||
@ -190,18 +282,16 @@
|
||||
argtolower(argc,argv);
|
||||
if(argc < 2) /* value request */
|
||||
{
|
||||
fd = fopen(self->pFileName,"r");
|
||||
if(!fd)
|
||||
{
|
||||
iNum = readDataNumber(self);
|
||||
if(iNum < 0)
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: cannot open file %s",self->pFileName);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
fscanf(fd,"%d",&iNum);
|
||||
fclose(fd);
|
||||
sprintf(pBueffel,"%s = %d",argv[0],iNum);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
}
|
||||
sprintf(pBueffel,"%s = %d",argv[0],iNum);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(strcmp(argv[1],"incr") == 0)
|
||||
@ -219,6 +309,38 @@
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(strcmp(argv[1],"nextthousand") == 0)
|
||||
{
|
||||
if(!SCMatchRights(pCon,usMugger))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
iNum = NewThousand(self);
|
||||
if(iNum > 0)
|
||||
{
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: cannot increment %s",argv[0]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(strcmp(argv[1],"interest") == 0)
|
||||
{
|
||||
lID = RegisterCallback(self->pCall, VALUECHANGE, InterestCallback,
|
||||
pCon, NULL);
|
||||
SCRegister(pCon,pSics, self->pCall,lID);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
if(strcmp(argv[1],"uninterest") == 0)
|
||||
{
|
||||
RemoveCallback2(self->pCall,pCon);
|
||||
SCSendOK(pCon);
|
||||
}
|
||||
|
||||
sprintf(pBueffel,"ERROR: unknown command %s supplied to %s",
|
||||
argv[1], argv[0]);
|
||||
|
2
danu.dat
2
danu.dat
@ -1,3 +1,3 @@
|
||||
286
|
||||
290
|
||||
NEVER, EVER modify or delete this file
|
||||
You'll risk eternal damnation and a reincarnation as a cockroach!|n
|
73
devexec.c
73
devexec.c
@ -431,11 +431,15 @@
|
||||
}
|
||||
break;
|
||||
case HWBusy:
|
||||
if(pCountInt)
|
||||
if(pCountInt != NULL && pDrivInt != NULL)
|
||||
{
|
||||
SetStatus(eCountDrive);
|
||||
}
|
||||
else if(pCountInt != NULL && pDrivInt == NULL)
|
||||
{
|
||||
SetStatus(eCounting);
|
||||
}
|
||||
else if(pDrivInt)
|
||||
else if(pDrivInt != NULL && pCountInt == NULL)
|
||||
{
|
||||
SetStatus(eDriving);
|
||||
}
|
||||
@ -644,7 +648,7 @@
|
||||
assert(self);
|
||||
|
||||
/* step through the list */
|
||||
iRes = 0;
|
||||
iRes = 1;
|
||||
iRet = LLDnodePtr2First(self->iList);
|
||||
while(iRet != 0)
|
||||
{
|
||||
@ -702,7 +706,7 @@
|
||||
assert(self);
|
||||
|
||||
/* step through the list */
|
||||
iRes = 0;
|
||||
iRes = 1;
|
||||
iRet = LLDnodePtr2First(self->iList);
|
||||
while(iRet != 0)
|
||||
{
|
||||
@ -771,7 +775,7 @@
|
||||
assert(pData);
|
||||
|
||||
/* check Privilege: Muggers may do it */
|
||||
if(!SCMatchRights(pCon,usMugger))
|
||||
if(!SCMatchRights(pCon,usUser))
|
||||
{
|
||||
SCWrite(pCon,"ERROR: NO Privilege to Stop operation ",eError);
|
||||
return 0;
|
||||
@ -834,6 +838,50 @@
|
||||
SetStatus(eEager);
|
||||
return iRet;
|
||||
}
|
||||
/*-------------------------------------------------------------------------*/
|
||||
int PauseAction(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
int status;
|
||||
|
||||
status = PauseExecution((pExeList)pData);
|
||||
if(status)
|
||||
{
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
SCWrite(pCon,"ERROR: failed to pause",eError);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/*-------------------------------------------------------------------------*/
|
||||
int ContinueAction(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
int status;
|
||||
Status eStat;
|
||||
|
||||
eStat = GetStatus();
|
||||
if(eStat != ePaused)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: Not paused, ignored",eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
status = ContinueExecution((pExeList)pData);
|
||||
if(status)
|
||||
{
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
SCWrite(pCon,"ERROR: failed to pause",eError);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int isInRunMode(pExeList self)
|
||||
@ -859,7 +907,8 @@
|
||||
int DevExecTask(void *pData)
|
||||
{
|
||||
pExeList self = NULL;
|
||||
int iRet;
|
||||
char pBueffel[132], pInterrupt[80];
|
||||
int iRet, iInterrupt;
|
||||
|
||||
self = (pExeList)pData;
|
||||
|
||||
@ -875,11 +924,17 @@
|
||||
switch(iRet)
|
||||
{
|
||||
case -1: /* some problem */
|
||||
if(SCGetInterrupt(self->pOwner) != eContinue)
|
||||
iInterrupt = SCGetInterrupt(self->pOwner);
|
||||
if(iInterrupt != eContinue)
|
||||
{
|
||||
SCWrite(self->pOwner,"ERROR: aborting operation due to HW problem",
|
||||
eError);
|
||||
SCWrite(self->pOwner,pBueffel, eError);
|
||||
if(iInterrupt > 1)
|
||||
{
|
||||
Interrupt2Text(iInterrupt,pInterrupt,79);
|
||||
snprintf(pBueffel,131,"ERROR: interrupt %s triggered",
|
||||
pInterrupt);
|
||||
StopExe(self,"all");
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("DevExecTask found an error\n");
|
||||
#endif
|
||||
|
13
devexec.h
13
devexec.h
@ -137,6 +137,17 @@
|
||||
connection with non blocking operation such as motors started
|
||||
with run.
|
||||
*/
|
||||
int PauseAction(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
/*
|
||||
pauses execution
|
||||
*/
|
||||
int ContinueAction(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
/*
|
||||
continues execution
|
||||
*/
|
||||
|
||||
/*--------------------------- Locking ---------------------------------*/
|
||||
|
||||
#line 183 "devexec.w"
|
||||
@ -145,7 +156,7 @@
|
||||
void UnlockDeviceExecutor(pExeList self);
|
||||
|
||||
|
||||
#line 281 "devexec.w"
|
||||
#line 292 "devexec.w"
|
||||
|
||||
/* -------------------------- Executor management -------------------------*/
|
||||
|
||||
|
11
devexec.tex
11
devexec.tex
@ -331,6 +331,17 @@ to the global SICS device executor.
|
||||
\mbox{}\verb@ connection with non blocking operation such as motors started@\\
|
||||
\mbox{}\verb@ with run.@\\
|
||||
\mbox{}\verb@ */@\\
|
||||
\mbox{}\verb@ int PauseAction(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
|
||||
\mbox{}\verb@ int argc, char *argv[]);@\\
|
||||
\mbox{}\verb@ /*@\\
|
||||
\mbox{}\verb@ pauses execution@\\
|
||||
\mbox{}\verb@ */@\\
|
||||
\mbox{}\verb@ int ContinueAction(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
|
||||
\mbox{}\verb@ int argc, char *argv[]);@\\
|
||||
\mbox{}\verb@ /*@\\
|
||||
\mbox{}\verb@ continues execution@\\
|
||||
\mbox{}\verb@ */ @\\
|
||||
\mbox{}\verb@ @\\
|
||||
\mbox{}\verb@/*--------------------------- Locking ---------------------------------*/@\\
|
||||
\mbox{}\verb@ @$\langle$devlock {\footnotesize ?}$\rangle$\verb@ @\\
|
||||
\mbox{}\verb@/* -------------------------- Executor management -------------------------*/@\\
|
||||
|
11
devexec.w
11
devexec.w
@ -277,6 +277,17 @@ to the global SICS device executor.
|
||||
connection with non blocking operation such as motors started
|
||||
with run.
|
||||
*/
|
||||
int PauseAction(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
/*
|
||||
pauses execution
|
||||
*/
|
||||
int ContinueAction(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
/*
|
||||
continues execution
|
||||
*/
|
||||
|
||||
/*--------------------------- Locking ---------------------------------*/
|
||||
@<devlock@>
|
||||
/* -------------------------- Executor management -------------------------*/
|
||||
|
@ -20,22 +20,28 @@ access internal SICS interfaces like the drive command or
|
||||
others. Object aliases are installed into SICS with the SICSAlias
|
||||
command:
|
||||
<DL>
|
||||
<DT>SicsAlias newname oldname
|
||||
<DT>SicsAlias oldname newname
|
||||
<DD>This command installs newname as alias for the object oldname.
|
||||
</dl>
|
||||
SicsAlias can only be used within initialization scripts. SicsAlias is
|
||||
considrered deprecated and can be replaced with the superior runtime
|
||||
considered deprecated and can be replaced with the superior runtime
|
||||
aliases described below.
|
||||
</p>
|
||||
<h2>Runtime Aliases</h2>
|
||||
<p>
|
||||
Runtime aliases are full object aliases which can be configured into the
|
||||
system at run time by a SICS manager. The syntax looks like this:
|
||||
system at run time by a SICS manager.
|
||||
The syntax looks like this:
|
||||
<dl>
|
||||
<dt>definealias SICSobject aliasname
|
||||
<dt>DefineAlias aliasname SICSobject
|
||||
<dd>This defines aliasname to be the alias for the SICS object SICSobject.
|
||||
<dt>definealias aliasname
|
||||
<dd>This command deltes the alias aliasname.
|
||||
It is not needed that SICSobject already exists. If SICSobject is already
|
||||
an alias, it is translated before definition.
|
||||
Multiple translation is possible, depending on the order of definition.
|
||||
When an alias is used, and it does not point to an existing object,
|
||||
the behaviour is the same as if an unknown object would have been used.
|
||||
<dt>DefineAlias aliasname
|
||||
<dd>This command deletes the alias aliasname.
|
||||
</dl>
|
||||
</p>
|
||||
<h2>Command Aliases</h2>
|
||||
|
@ -72,7 +72,7 @@ in the system. M1 and M2 are the names of the Theta and two Theta motors
|
||||
respectively. M3 is an optional parameter defining a motor for driving the
|
||||
horizontal curvature. M4 is an optional parameter defining a motor for
|
||||
driving the vertical curvature of the monochromator.
|
||||
<DT>InitToken tokenpassword
|
||||
<DT>TokenInit tokenpassword
|
||||
<DD> This command initialises the token control management system with the
|
||||
token command. The single parameter tokenpassword specifies the password for
|
||||
the token force command.
|
||||
|
34
doc/manager/helpman.htm
Normal file
34
doc/manager/helpman.htm
Normal file
@ -0,0 +1,34 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>The SICS Online Help System</TITLE>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
<H1>The SICS Online Help System</H1>
|
||||
<P>
|
||||
SICS has a simple built in help system. Help text is stored in simple
|
||||
ASCII text files which are printed to the client on demand. The help
|
||||
system can search for help files in several directories. Typically one
|
||||
would want one directory with general SICS help files and another one
|
||||
with instrument specific help files. If help is invoked without any
|
||||
options, a default help file is printed. This file is supposed to
|
||||
contain a directory of available help topics together with a brief
|
||||
description. The normal usage is: help topicname . The help system
|
||||
will then search for a file named topicname.txt in its help
|
||||
directories.
|
||||
</P>
|
||||
<p>
|
||||
A SICS manager will need to configure this help system. A new
|
||||
directory can be added to the list of directories to search with the
|
||||
command:
|
||||
<pre>
|
||||
help configure adddir dirname
|
||||
</pre>
|
||||
The default help file can be specified with:
|
||||
<pre>
|
||||
help configure defaultfile filename
|
||||
</pre>
|
||||
Each of these command given without a parameter print the current
|
||||
settings.
|
||||
</P>
|
||||
</BODY>
|
||||
</HTML>
|
@ -19,6 +19,7 @@ Go to:
|
||||
<li> A discussion of SICS <a href = var.htm> variables</a>.
|
||||
<li> Advice about <a href=hwini.htm> hardware </a> configuration.
|
||||
<li> A description of <a href = command.htm> command </a> initialisation.
|
||||
<li> Managing the SICS <a href="helpman.htm"> help </a> system.
|
||||
</ul>
|
||||
</p>
|
||||
<!latex-on>
|
||||
|
@ -46,6 +46,7 @@ which is described elsewhere.
|
||||
%html var.htm 1
|
||||
%html hwini.htm 1
|
||||
%html command.htm 1
|
||||
%html helpman.htm 2
|
||||
%html special.htm 1
|
||||
%html serial.htm 2
|
||||
%html status.htm 2
|
||||
@ -54,6 +55,8 @@ which is described elsewhere.
|
||||
%html alias.htm 2
|
||||
%html cron.htm 2
|
||||
%html rs232.htm 2
|
||||
%html nxscript.htm 2
|
||||
%html nxupdate.htm 2
|
||||
%html ../user/trouble.htm 1
|
||||
%html move.htm 1
|
||||
\end{document}
|
||||
|
@ -99,9 +99,10 @@ experiment.
|
||||
</dl>
|
||||
<dt>nxscript puthm hmAlias hmName ?start? ?length?
|
||||
<dd>Writes data from the histogram memory hmName to a NeXus file using
|
||||
the alias hmAlias. The definition string for the alias should not
|
||||
contain neither -rank nor -dim information as this will be appended by
|
||||
nxscript. If the optional parameters start and end are given, a
|
||||
the alias hmAlias. Nxscript automatically updates the dim0, dim1, ..., timedim
|
||||
dictionary variables. Thus these can be used to define the dimensions in the
|
||||
dictionary file.
|
||||
If the optional parameters start and end are given, a
|
||||
subset of the data is written. It is the users responsability that the
|
||||
values requested make sense to the histogram memory. In the case of
|
||||
subset writing, the dimensions have to be specified in the definition
|
||||
|
71
doc/manager/nxupdate.htm
Normal file
71
doc/manager/nxupdate.htm
Normal file
@ -0,0 +1,71 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Automatic Updating of NeXus Files</TITLE>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
<H1>Automatic Updating of NeXus Files</H1>
|
||||
<P>
|
||||
Some instruments perform measurements for quite long counting
|
||||
times. In such cases it is advisable to save the data measured so far
|
||||
to file in order to protect against hardware or software failures. To
|
||||
this purpose an automatic file upgrade manager is provided. On
|
||||
installation the automatic update object is connected wth a counting
|
||||
device through the the callback interface. This makes sure that the
|
||||
update manager is automatically notified when counting starts or
|
||||
finishes.
|
||||
</P>
|
||||
<h2>Prerequisites for Using the Automatic Update Manager</h2>
|
||||
<p>
|
||||
In order to use automatic updating, three programs must be
|
||||
provided. Each of these programs can be a script which uses the
|
||||
nxscript facility. It can also be a SICS command.
|
||||
<dl>
|
||||
<dt>startScript
|
||||
<dd>This program is supposed to write the static part of the file. It
|
||||
is called once when the file is created.
|
||||
<dt>updateScript
|
||||
<dd>This program is supposed to create and update the variable data
|
||||
elements in the NeXus file. This is called frequently.
|
||||
<dt>linkScript
|
||||
<dd>This program is supposed to create the links within the NeXus
|
||||
file. This is called once after startcript and updateScript have been
|
||||
run.
|
||||
</dl>
|
||||
</p>
|
||||
<h2>Installing Automatic Update</h2>
|
||||
<p>
|
||||
An automatic update object is installed into SICS with:
|
||||
<pre>
|
||||
updatefactory name countername
|
||||
</pre>
|
||||
name is a placeholder for the name under which SICS knows the
|
||||
automatic update object. name is available as a SICS command later on.
|
||||
countername is a placeholder for a counter
|
||||
object (counter or HM) which triggers automatic updating of NeXus
|
||||
files. This object has to support both the countable and callback
|
||||
interfaces of SICS. Suitable SICS objects include counter and
|
||||
histogram memory objects.
|
||||
</p>
|
||||
<h2>Configuring Automatic Update</h2>
|
||||
<p>
|
||||
The SICS command created with updatefactory (see above) supports a few
|
||||
parameters which allow for the configuration of the whole
|
||||
process. Parameters follow the normal SICS syntax. Futhermore there is
|
||||
a subcommand list, which lists all configuration
|
||||
parameters. Supported parameters are:
|
||||
<dl>
|
||||
<dt>startScript
|
||||
<dd>The program supposed to write the static part of the file.
|
||||
<dt>updateScript
|
||||
<dd>The program supposed to create and update the variable data
|
||||
elements in the NeXus file.
|
||||
<dt>linkScript
|
||||
<dd>This program supposed to create the links within the NeXus
|
||||
file.
|
||||
<dt>updateintervall
|
||||
<dd>The time intervall in seconds between updates. The defualt is
|
||||
1200, eg. 20 minutes.
|
||||
</dl>
|
||||
</p>
|
||||
</BODY>
|
||||
</HTML>
|
76
doc/manager/rs232.htm
Normal file
76
doc/manager/rs232.htm
Normal file
@ -0,0 +1,76 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Direct Access to RS232 Controllers</TITLE>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
<H1>Direct Access to RS232 Controllers</H1>
|
||||
<P>
|
||||
Usually serial ports are accessed by SICS through David Maden's
|
||||
SerPortServer program which then communicates with a terminal server
|
||||
box through the TCP/IP network. This limits the amount of control over
|
||||
the controller. If more control is required, the RS232 controllers can
|
||||
be accessed directly from SICS through the terminal server, thereby
|
||||
bypassing the SerPortServer program. Please note, that these two modes
|
||||
of operation are mutually exclusive: a given port can either be
|
||||
accessed through the mechanism described here OR through
|
||||
SerPortServer.
|
||||
</P>
|
||||
Before being able to use this system, the RS232 controller has to be
|
||||
configured into SICS as described in the hardware initialization
|
||||
section through the following command in the initialization file:
|
||||
<pre>
|
||||
MakeRS232Controller name terminalserver port
|
||||
</pre>
|
||||
For example:
|
||||
<pre>
|
||||
MakeRS232Controller hugo psts213 3004
|
||||
</pre>
|
||||
name is the SICS name for the controller, terminalserver is the name
|
||||
of the terminal server the device is connected to and port is the port
|
||||
number at which the terminal server publishes the RS232 channel to
|
||||
which the device is connected. This is usally the port number plus 3000.
|
||||
</p>
|
||||
<p>
|
||||
Now various commands are available for interfacing with the RS232
|
||||
controller. In the following description the SICS name of the
|
||||
controller is replaced by the symbol rs232name.
|
||||
<dl>
|
||||
<dT>rs232name sendterminator
|
||||
<dD>prints the current terminator used when sending data to the device
|
||||
as hexadecimal numbers.
|
||||
<dT>rs232name sendterminator h1h2..hn
|
||||
<dD>sets the current terminator used when sending data to the device
|
||||
to the characters described by the hexadecimal numbers h1 to hn. The
|
||||
numbers are in the format 0xval, where val is the hex number.
|
||||
<dT>rs232name replyterminator
|
||||
<dD>prints the current terminator expected to terminate a response
|
||||
from the device as a hexadecimal number.
|
||||
<dT>rs232name replyterminator h1h2..hn
|
||||
<dD>sets the current terminator expected to terminate a response from
|
||||
the device to the characters described by the hexadecimal numbers h1
|
||||
to hn.
|
||||
The numbers are in the format 0xval, where val is the hex number.
|
||||
<dt>rs232name timeout
|
||||
<dd>prints the current timeout when waiting for a reponse from the
|
||||
device.
|
||||
<dt>rs232name timeout val
|
||||
<dd>sets the timeout for waiting for responses from the device. The
|
||||
value is in microseconds.
|
||||
<dt>rs232name send data data data
|
||||
<dd>sends the remainder of the line to the RS232 device and waits for
|
||||
a response terminated with the proper reply terminator specified. This
|
||||
commands waits at maximum timeout microseconds for a response. If a
|
||||
valid response is obtained it is printed, otherwise an error message
|
||||
occurs.
|
||||
<dt>rs232name write data data data
|
||||
<dd>writes the remainder of the line after write to the device without
|
||||
waiting for a response.
|
||||
<dt>rs232 available
|
||||
<dd>checks if data is pending to be read from the device.
|
||||
<dt>rs232 read
|
||||
<dd>reads data from the device.
|
||||
</dl>
|
||||
</p>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
@ -15,6 +15,8 @@ This section describes a few commands which need not be known to SICS users.
|
||||
<li> <a href="cron.htm">Reoccuring tasks</a>.
|
||||
<li> Direct access to <a href="rs232.htm">RS232 controllers</a> through
|
||||
the terminal server.
|
||||
<li>Scripting the content of<a href="nxscript.htm"> NeXus</a> files.
|
||||
<li>Automatic <a href="nxupdate.htm">update</a> of files during long counting operations.
|
||||
</uL>
|
||||
<!latex-on>
|
||||
</P>
|
||||
|
@ -191,13 +191,8 @@ This document also explains how to get hold the source code for most
|
||||
\subsubsection{Backup}
|
||||
The laboratory server is also the central backup server for SINQ. Backups are
|
||||
performed with the Legato networker software onto a tape jukebox holding
|
||||
5 tapes with 20GB capacity each. The following items are backed up through
|
||||
this system:
|
||||
\begin{itemize}
|
||||
\item The laboratory server.
|
||||
\item The instrument accounts on the instrument computers.
|
||||
\item The lnsdata and lnslib shares of the lns00 Windows--NT server.
|
||||
\end{itemize}
|
||||
5 tapes with 20GB capacity each. Currently only the /home (holding
|
||||
user home directories) and the /lnsarchive hierarchy are backed up.
|
||||
This backup system is a protection against a major harddisk failure. It is no
|
||||
archive system. Though backup tapes are held as long as possible it
|
||||
cannot be guaranteed that files older then half a year can be recovered.
|
||||
@ -205,6 +200,38 @@ This backup system is a protection against a major harddisk failure. It is no
|
||||
system. No further documentation exists, but the setup can be viewed
|
||||
through the nwadmin application.
|
||||
|
||||
The instrument accounts on the instrument computers must be backed up
|
||||
as well because they sometimes contain valuable scripts. Unfortunately
|
||||
there are not enough Networker licenses to go round and there is no
|
||||
reliable linux client software for our version of Legato Networker.
|
||||
Therefore the data in the instrument accounts is copied nightly to a
|
||||
special account on lnsa15 which is subjected to the normal
|
||||
backup. More details:
|
||||
\begin{itemize}
|
||||
\item There is a script which does the copying. It is {\bf backupinst}
|
||||
in either /data/lnslib/bin or
|
||||
/afs/.psi.ch/project/sinq/linux/bin. This script is called with {\bf
|
||||
backupinst INST} where INST must be replaced by the instrument name in
|
||||
capitals. This script essentially calls rsync with appropriate
|
||||
arguments to synchronize the instrument account minus the data
|
||||
directory (which is automatically copied anyway).
|
||||
\item backupinst is triggered by a cron job. For this to work each
|
||||
instrument computer must have an entry in crontab reading like:
|
||||
\begin{verbatim}
|
||||
0 3 * * * /data/lnslib/bin/backupinst TOPSI >/tmp/topsi.log 2>&1
|
||||
\end{verbatim}
|
||||
Please replace paths and instrument names to match the instrument.
|
||||
\item The backup account on lnsa15 is named SINQINST, password:
|
||||
333SINQINST555. It contains a directory for each supported
|
||||
instruments. For backupinst to work properly there must be a line in
|
||||
the .rhosts file of this account for each instrument computer which
|
||||
reads:
|
||||
\begin{verbatim}
|
||||
instcomputer.psi.ch root
|
||||
\end{verbatim} Please note that this has to be the pcXXXX name for
|
||||
linux instrument computers, not the DNS alias.
|
||||
\end{itemize}
|
||||
|
||||
|
||||
\subsubsection{Motor Parameter Backup}
|
||||
At SINQ the PSI EL--734 motor controllers are used. These motor controllers
|
||||
|
@ -105,7 +105,7 @@ the error can be ignored or was fully resolved.
|
||||
\item[pParList] is text string containing a comma separated list of
|
||||
all parameters understood by this driver.
|
||||
\item[pPrivate] Is a pointer to a driver specific specific data
|
||||
structure. This data structure will not be messed with by upper level code.
|
||||
structure. This data structure shall not be messed with by upper level code.
|
||||
\end{description}
|
||||
|
||||
\subsubsection{The Controller Object}
|
||||
|
637
doc/programmer/command.tex
Normal file
637
doc/programmer/command.tex
Normal file
@ -0,0 +1,637 @@
|
||||
\chapter{Writing new SICS Commands}
|
||||
If you wish to write a new command or add a completely new piece of hardware to
|
||||
SICS, this is the chapter to study. There are two ways to implement
|
||||
new commands into SICS: through the internal Tcl scripting language and
|
||||
in ANSI--C. This section describes command writing in ANSI--C. You
|
||||
should consider using Tcl when:
|
||||
\begin{itemize}
|
||||
\item The new command is very instrument specific. Rather extend a
|
||||
SICS command in order to support your script.
|
||||
\item The new command is a local syntax fudge.
|
||||
\item The hardware device is an auxiliary, such a He level meter
|
||||
etc.
|
||||
\end{itemize}
|
||||
On the other hand there are indications when to write in ANSI--C:
|
||||
\begin{itemize}
|
||||
\item Complex calculations need to be carried out.
|
||||
\item Large amounts of data need to be handled.
|
||||
\item The code requires extensive bit twiddling.
|
||||
\item A new general SICS facility is provided.
|
||||
\end{itemize}
|
||||
|
||||
|
||||
\section{Mapping Object Oriented Concepts into ANSI--C}
|
||||
SICS is in principle an object oriented system. However, it is implemented
|
||||
in ANSI--C. Therefore object oriented concepts must be mapped into C. The
|
||||
three object oriented concepts which need to be mapped are:
|
||||
\begin{itemize}
|
||||
\item Data Encapsulation.
|
||||
\item Polymorphism.
|
||||
\item Inheritance.
|
||||
\end{itemize}
|
||||
|
||||
Of these, data encapsulation is by far the most important concept. Objects
|
||||
in computer science can be understood as little boxes which contain some
|
||||
data describing their state and which understand messages sent by other
|
||||
objects. If such a message comes in, the object performs some action,
|
||||
perhaps changes its internal state or sends new messages to other objects.
|
||||
It is understood that changes to the internal data of the object can be
|
||||
achieved only through messages to the object and not by directly manipulating
|
||||
variables from the outside. In ANSI--C an object maps to a structure holding
|
||||
the objects data and the messages map to functions which act upon the data
|
||||
structure. In order to do this, the functions must take a pointer to the
|
||||
objects data structure as first parameter. In order to prevent messing with
|
||||
an objects data structure, only a pointer to a structure is declared in the
|
||||
header file. The actual definition of the data structure happens only in
|
||||
the implementation file. All functions belonging to an object are defined in that
|
||||
implementation file and have full access to the data structure.
|
||||
Users of the object see only the header file and thus only a pointer to the
|
||||
objects data structure which prevents
|
||||
them from messing with the objects data directly.
|
||||
In order to illustrate the concepts lets look at
|
||||
a primitive integer object defined in such a way.
|
||||
\begin{verbatim}
|
||||
/*-----------------------------------------------------------------------
|
||||
ExampleInt.h
|
||||
------------------------------------------------------------------------*/
|
||||
typedef struct __ExampleInt *pExampleInt;
|
||||
|
||||
int GetInt(pExampleInt self);
|
||||
void SetInt(pExampleInt self, int iNew);
|
||||
/*------------------- EOF ExampleInt.h---------------------------------*/
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
ExampleInt.c, Implementation file
|
||||
-----------------------------------------------------------------------*/
|
||||
typedef struct __ExampleInt {
|
||||
int iExample;
|
||||
} ExampleInt;
|
||||
/*--------------------------------------------------------------------*/
|
||||
int GetInt(pExampleInt self)
|
||||
{
|
||||
return self->iExample;
|
||||
}
|
||||
/*---------------------------------------------------------------------*/
|
||||
void SetInt(pExampleInt self, int iNew)
|
||||
{
|
||||
self->iExample = iNew;
|
||||
}
|
||||
\end{verbatim}
|
||||
Using this scheme all code changing the internal state of an object lives
|
||||
in one file. Changes to the objects data structure affect only the
|
||||
implementation file and no other files.
|
||||
This scheme is used for almost all SICS objects. A few system objects and
|
||||
older SICS objects define their data structures in header files. This is
|
||||
either a relic or had to be done for performance reasons.
|
||||
|
||||
The next concept is polymorphism. This describes the situation when a group
|
||||
of objects respond to the same message but doing different things. For
|
||||
instance a whole set of objects would implement a write functionality
|
||||
which writes the objects state to a file. Higher level would then not need
|
||||
to know of which type the actual object is, it just can send the write message
|
||||
and the rest is taken care of by the object. This concept is used for all
|
||||
hardware drivers in SICS. Mapping this to C requires to expose the objects
|
||||
data structure and let the data structure include a pointer to that polymorphic
|
||||
function. As an example, the ExampleInteger with a write function:
|
||||
\begin{verbatim}
|
||||
/*-----------------------------------------------------------------------
|
||||
ExampleInt.h
|
||||
------------------------------------------------------------------------*/
|
||||
typedef struct __ExampleInt{
|
||||
int iExample;
|
||||
void (*write)(struct __ExampleInt *self, FILE *fd);
|
||||
} *pExampleInt, ExampleInt;
|
||||
|
||||
pExampleInt MakeInt(int iNew);
|
||||
|
||||
int GetInt(pExampleInt self);
|
||||
void SetInt(pExampleInt self, int iNew);
|
||||
/*------------------- EOF ExampleInt.h---------------------------------*/
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
ExampleInt.c, Implementation file
|
||||
-----------------------------------------------------------------------*/
|
||||
static void ExampleWrite(struct _-ExampleInt *self, FILE *fd)
|
||||
{
|
||||
fprintf(fd,"INT = %d",self->iExample);
|
||||
}
|
||||
/*---------------------------------------------------------------------*/
|
||||
pExampleInt MakeInt(int iNew)
|
||||
{
|
||||
pExampleInt pNew = NULL;
|
||||
|
||||
pNew = (pExampleInt)malloc(sizeof(ExampleInt));
|
||||
pNew->iExample = iNew;
|
||||
pNew->write = ExampleWrite;
|
||||
return pNew;
|
||||
}
|
||||
.
|
||||
.
|
||||
.
|
||||
\end{verbatim}
|
||||
This can then be called:
|
||||
\begin{verbatim}
|
||||
void SomeFunc()
|
||||
{
|
||||
pExampleInt pTest;
|
||||
|
||||
pTest = MakeInt(25);
|
||||
.
|
||||
.
|
||||
.
|
||||
pTest->write(pTest,fd);
|
||||
}
|
||||
\end{verbatim}
|
||||
This example also illustrates the concept of a special function which creates
|
||||
a new object of the appropriate type and initializes its data structure
|
||||
properly.
|
||||
|
||||
The last concept to discuss is inheritance. Inheritance can be used when
|
||||
an object is a derivative of another object. For instance a truck is a
|
||||
derivative of a motor car. Much of the behavior of a motor car will be the
|
||||
same as for a truck. In order to prevent rewriting of code, the truck
|
||||
should use the same data structures and code as the motor car. And add
|
||||
or modify only what is special. Inheritance is not much used in SICS. It can
|
||||
be implemented by overlaying data structures. This means the derived
|
||||
classes data structure has the same fields in the same order as the parent
|
||||
class and adds its specials at the end. For example:
|
||||
\begin{verbatim}
|
||||
typedef struct __MotorCar {
|
||||
int iWheels;
|
||||
float fSpeed;
|
||||
} *pMotorCar, MotorCar;
|
||||
|
||||
|
||||
typedef struct __Truck {
|
||||
int iWheels;
|
||||
float fSpeed; /* same as MotorCar */
|
||||
double dPayLoad; /* special for Truck */
|
||||
} *pTruck, Truck;
|
||||
|
||||
\end{verbatim}
|
||||
Thus functions defined for motor car can operate on trucks as well.
|
||||
For more details study the relationship between the ITC4 controller and
|
||||
general environment controllers. This is the only place where SICS
|
||||
currently uses inheritance.
|
||||
|
||||
|
||||
\section{Command Writing Basics}
|
||||
\subsubsection{The Object Wrapper Function}
|
||||
The first thing needed in order to implement a new command in SICS is
|
||||
the object wrapper function. This function has the following
|
||||
signature:
|
||||
\begin{verbatim}
|
||||
int ObjectWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
\end{verbatim}
|
||||
The parameters are:
|
||||
\begin{description}
|
||||
\item[pCon] A pointer to the connection object representing the client
|
||||
invoking this command.
|
||||
\item[pSics] A pointer to the SICS interpreter.
|
||||
\item[pData] A pointer to a user data structure for this object. Can
|
||||
be NULL if no such thing exists.
|
||||
\item[argc] Number of arguments in argv to this function.
|
||||
\item[argv] Arguments to this function. The argc, argv scheme is
|
||||
the same as for a C--language main function. The first argument is
|
||||
always the name of the object.
|
||||
\end{description}
|
||||
This object wrapper function must evaluate its arguments, do what it
|
||||
is meant to do and write any results to the client connection. In the
|
||||
case of an error this function must return 0, in case of success 1.
|
||||
|
||||
|
||||
\subsubsection{The Object Data Structure}
|
||||
Only the most primitive objects or commands get away without an own
|
||||
data structure. Usually a data structure will be needed by SICS
|
||||
objects in order to keep configuration parameters etc. A pointer to
|
||||
such a datastructure is passed into the object wrapper function as the
|
||||
pointer pData. This object data structure has to fulfill some
|
||||
conditions in order to live happily within SICS. And actually, not
|
||||
only the datastructure is needed but also a function which is able to
|
||||
release any memory allocated by the datastructure. SICS needs this
|
||||
function in order to clean things up properly.
|
||||
|
||||
|
||||
A valid SICS object structure has to look like this:
|
||||
\begin{verbatim}
|
||||
typedef struct __MyObject {
|
||||
pObjectDescriptor pDes;
|
||||
int iMyExtremlyImportantInt;
|
||||
.
|
||||
.
|
||||
.
|
||||
} MyObject;
|
||||
\end{verbatim}
|
||||
Please note that the first item in the data structure MUST be a
|
||||
pointer to an SICS object descriptor. Add your own stuff below
|
||||
that. If you do not adhere to this requirement, SICS will dump core on
|
||||
you rather sooner then later.
|
||||
|
||||
|
||||
SICS needs this object descriptor for its own internal purposes. The
|
||||
object descriptor is again a data structure with this signature:
|
||||
\begin{verbatim}
|
||||
typedef struct {
|
||||
char *name;
|
||||
int (*SaveStatus)(void *self, char *name,FILE *fd);
|
||||
void *(*GetInterface)(void *self, int iInterfaceID);
|
||||
} ObjectDescriptor, *pObjectDescriptor;
|
||||
|
||||
\end{verbatim}
|
||||
\begin{description}
|
||||
\item[name] This is a type identifier for the object. SICS uses this
|
||||
identifier for run time type identification (RTTI). For example this
|
||||
field says Motor for motors, Counter for counters etc.
|
||||
\item[SaveStatus] is the function called by the SICS status backup
|
||||
mechanism. The default implementation of this function does
|
||||
nothing. But if your new object has to store configuration commands
|
||||
into the status file you should create an own function with the same
|
||||
signature and assign this function to the object descriptors
|
||||
SaveStatus. A suitable function will print the necessary commands to
|
||||
achieve the same configuration as the current state into the file
|
||||
represented by fd.
|
||||
\item[GetInterface] SICS objects can have various capabilities: a
|
||||
motor can be driven or scanned, you may count on a counter etc. Such
|
||||
capabilities are expressed as interfaces(see \ref{interface}) in SICS.
|
||||
There is an integer ID for each of those interfaces. GetInterface now
|
||||
returns a suitable
|
||||
interface in return for a given interface ID or NULL if the object
|
||||
does not implement the interface. The default version of this function
|
||||
retuns NULL always. If your object implements an interface, this
|
||||
function has to be overloaded to return this interface on demand.
|
||||
\end{description}
|
||||
|
||||
A default object descriptor can be created with:
|
||||
\begin{verbatim}
|
||||
pObjectDescriptor CreateDescriptor(type);
|
||||
\end{verbatim}
|
||||
with type being the object type identifier. A descriptor can be
|
||||
deleted with:
|
||||
\begin{verbatim}
|
||||
DeleteDescriptor(pDes);
|
||||
\end{verbatim}
|
||||
|
||||
|
||||
As already mentioned, a function to release any memory allocated for
|
||||
the object data structure is also needed. Its signature is simple:
|
||||
\begin{verbatim}
|
||||
void KillObject(void *pdata);
|
||||
\end{verbatim}
|
||||
with pdata being the object to delete.
|
||||
|
||||
|
||||
\subsection{Installing the new Command into the SICS Interpreter}
|
||||
A new command can be installed into SICS with the function:
|
||||
\begin{verbatim}
|
||||
int AddCommand(SicsInterp *pSics,
|
||||
char *name,
|
||||
ObjectFunc ofunc,
|
||||
KillFunc killo,
|
||||
void *objectData);
|
||||
\end{verbatim}
|
||||
with pSics being the interpreter into which to install the command,
|
||||
name the name of the command, ofunc its wrapper function, killo the
|
||||
object data structure deletion function and objectData being a pointer
|
||||
to the object data structure. If no data structure is defined for the
|
||||
command, killo and objectData must be NULL.
|
||||
|
||||
|
||||
Now the question arise where AddCommand has to be placed. Various
|
||||
cases have to be distinguished: The first case is that the new command
|
||||
is relevant to SICS users in all corners of the world. Then the new
|
||||
command should be added to the function InitIniCommand in file
|
||||
ofac.c.
|
||||
|
||||
The second case is that the command is specific to a certain
|
||||
instrument or a special hardware or implements a local fashion of
|
||||
dealing with things. Then the new command should be installed from the
|
||||
function AddSiteCommand in the site data structure (see \ref{site}).
|
||||
|
||||
Another scheme becomes valid when multiple instances of the object
|
||||
need to be created. \label{factory} For instance the object represents
|
||||
a motor of which you may have many. Then it is useful to create a factory
|
||||
command. This is a special SICS command which creates the desired
|
||||
objects and installs them in the interpreter. This factory command
|
||||
then has to be installed according to the logic given above. Usually
|
||||
such objects are installed in the SICS initialization file. After
|
||||
processing this initialization file the factory command is not useful
|
||||
any longer. Then such factory commands should be removed from the
|
||||
interpreter with:
|
||||
\begin{verbatim}
|
||||
RemoveCommand(SicsInterp *pSics, char *name);
|
||||
\end{verbatim}
|
||||
This has to be placed into the sites member function RemoveSiteCommand
|
||||
or into KillIniCommand in ofac.c, depending where you installed the
|
||||
command in the first place.
|
||||
|
||||
Be careful with commands for deleting objects though. SICS objects may
|
||||
be aliased, used by other objects or connected through the callback
|
||||
interface (see \ref{inter}). SICS does not implement proper
|
||||
bookkeeping on all these relationships and thus deleting a command from
|
||||
SICS without taking this into account may cause SICS to dump core on
|
||||
you.
|
||||
|
||||
|
||||
\section{Interacting with the Client Connection}\label{gow}
|
||||
A SICS command writer needs to interact with the client connection for
|
||||
a variety of reasons:
|
||||
\begin{itemize}
|
||||
\item To write error messages and other output
|
||||
\item To prompt for more data
|
||||
\item To check if the user has appropriate privileges for the command
|
||||
implemented.
|
||||
\item To tell upper level code that something went very wrong.
|
||||
\end{itemize}
|
||||
As these tasks are so common you will find that the connection object
|
||||
has to be passed frequently into lower level code as an argument.
|
||||
|
||||
\subsection{Writing and Reading to the Client}
|
||||
All I/O to the client has to be processed through the I/O functions
|
||||
for connections defined in conman.h and implemented in conman.c. The
|
||||
most common of these are SCWrite and SCPrompt.
|
||||
These function will now be inspected in more detail:
|
||||
\begin{verbatim}
|
||||
int SCWrite(SConnection *pCon, char *pText, int eCode);
|
||||
int SCPrompt(SConnection *pCon, char *pPrompt, char *pBuffer, int iBufLen);
|
||||
\end{verbatim}
|
||||
SCWrite writes the data pText to the connection specified by pCon. The
|
||||
parameter eCode denotes the output code of the data in pText. SICS clients
|
||||
can choose to suppress some I/O from the SICS server. For instance a
|
||||
GUI--client might chooses not to receive scan status reports. For this
|
||||
purpose it was necessary to stick an output code onto each message to the
|
||||
client. Possible output codes are: eError, eWarning, eValue, eStatus and
|
||||
some internal codes. The names are self explaining. eValue denotes a value
|
||||
which has been explicitly asked for by the client. The rule specified above
|
||||
becomes understandable and thus bearable when looking at all the things
|
||||
SCWrite does with the message:
|
||||
\begin{itemize}
|
||||
\item It is written to the client connection socket, subject to the output
|
||||
code specified.
|
||||
\item The message is written to all log files configured for the client
|
||||
connection.
|
||||
\item If the client privilege is user or manager, the data is written
|
||||
to the command log.
|
||||
\item The message is written to the server log together with the socket
|
||||
number of the connection.
|
||||
\item SCWrite stores the message into the Tcl macro interpreter in order to
|
||||
enable processing of data from SICS commands in Tcl scripts.
|
||||
\item SCWrite suppresses all messages to the client while executing a macro.
|
||||
This stops spurious output to appear at the client connection when running a
|
||||
command defined in the macro language. The exception are messages of type
|
||||
eError and eWarning. Such messages are always sent to the client.
|
||||
\end{itemize}
|
||||
|
||||
SCPrompt prompts the user at the client connection for data. The prompt
|
||||
string pPrompt is sent. Data entered by the user is returned in buffer
|
||||
pBuffer. Maximum iBufLen character are returned. While waiting for client to
|
||||
provide data, the SICS task switcher runs.
|
||||
|
||||
There is another convenience function SCSendOK(SConnection *pCon) which is
|
||||
just a wrapper around SCWrite. SCSendOk sends an 'OK' to the client. It is good
|
||||
practice to let the user know that the operation requested had been
|
||||
performed.
|
||||
|
||||
There are some more conventions which are useful to adhere to:
|
||||
\begin{itemize}
|
||||
\item All error messages start with the string ERROR:
|
||||
\item All warnings start with the string WARNING:
|
||||
\item All requested values are returned in the format name = value.
|
||||
\end{itemize}
|
||||
|
||||
There exist special functions to send mass data through a connection
|
||||
in either uuencoded or zipped form. The latter works only through
|
||||
plain socket connections, telnet will mess up binary data. Please
|
||||
note, that numeric data sent by the SICS server needs to be in network
|
||||
byte order in order to be understood by the Java clients. Further
|
||||
functions allow to tailor writing behavious further by overloading the
|
||||
operations performed by SCWrite. This is documented in conman.h
|
||||
|
||||
|
||||
\subsection{Checking Client Privileges}
|
||||
One task any SICS object has to perform is to check if a client,
|
||||
represented through a connection object, is privileged to perform a
|
||||
requested operation. The most useful function to do this is:
|
||||
\begin{verbatim}
|
||||
int SCMatchRights(SConnection *pCon, int rights);
|
||||
\end{verbatim}
|
||||
This function not only checks if the user has at least the user rights
|
||||
given as parameter rights but also checks if the SICS server is
|
||||
currently performing a scan or something. It is generally a bad idea
|
||||
to change parameters while the instrument is taking a measurement. If
|
||||
all is good 1 is returned, 0 in case of trouble. All troubles will
|
||||
already have been reported to the client by this function. SICS knows
|
||||
four levels of user rights:
|
||||
\begin{description}
|
||||
\item[usSpy] may look at things but change nothing.
|
||||
\item[usUser] may do those things a normal user is supposed to do.
|
||||
\item[usMugger] may perform configuration tasks.
|
||||
\item[usInternal] absolutely no restrictions, used only internally.
|
||||
\end{description}
|
||||
|
||||
|
||||
There are further functions for requesting client and setting client
|
||||
rights codes. These functions are all defined in conman.h.
|
||||
|
||||
\subsection{Interrupting}
|
||||
On occasion a SICS object may come to the conclusion that an error is
|
||||
so bad that the measurement needs to be stopped. Clearly a means is
|
||||
needed to communicate this to upper level code. This means is setting
|
||||
an interrupt on the connection.
|
||||
The current active interrupt is located at the connection object
|
||||
and can be retrieved with {\bf SCGetInterrupt} and set with {\bf
|
||||
SCSetInterrupt}. Interrupt codes are defined in interrupt.h and are ordered
|
||||
into a hierarchy:
|
||||
\begin{description}
|
||||
\item[eContinue] Everything is just fine.
|
||||
\item[eAbortOperation] Stop the current scan point or whatever is done,
|
||||
but do not stop altogether.
|
||||
\item[eAbortScan] Abort the current scan, but continue processing of further
|
||||
commands in R\"unbuffers or command files.
|
||||
\item[eAbortBatch] Aborts everything, operations, scans and batch processing
|
||||
and leaves the system ready to enter new commands.
|
||||
\item[eHaltSystem] As eAbortBatch, but lock the system.
|
||||
\item[eFreeSystem] Unlocks a system halted with eHaltSystem.
|
||||
\item[eEndServer] Makes the SICS server run down and exit.
|
||||
For internal usage only.
|
||||
\end{description}
|
||||
|
||||
Higher level SICS objects may come to the conclusion that the error
|
||||
reported by lower level code is actually not that critical and clear
|
||||
any pending interrupts by setting the interrupt code to eContinue and
|
||||
thus consume the interrupt.
|
||||
|
||||
\subsection{Communicating with all Clients}
|
||||
Two facilities exist which allow one SICS command to reach out to all
|
||||
connected clients.
|
||||
\begin{itemize}
|
||||
\item There is a function which writes a message to all clients. This
|
||||
is ServerWriteGlobal(char *text, int outCode);
|
||||
\item There exists a global status code which can be set with
|
||||
SetStatus and retrieved with GetStatus. See status.h for more
|
||||
details. Use this when your SICS command starts lengthy operations
|
||||
such as driving or counting.
|
||||
\end{itemize}
|
||||
|
||||
\section{Using other SICS Objects}
|
||||
In most cases a new command needs to make use of other SICS
|
||||
objects. Before another SICS object can be used, it must be found
|
||||
within the SICS interpreter. In order do this the name of the object
|
||||
is obviously needed. This must be a configuration parameter or passed
|
||||
in as a argument to the command. In general it is also necessary to
|
||||
check if this name points to the right type of object. All this can be
|
||||
achieved with the function:
|
||||
\begin{verbatim}
|
||||
void *FindCommandData(SicsInterp *pSics, char *name, char *type);
|
||||
\end{verbatim}
|
||||
This function tries to find a command name in the interpreter and also
|
||||
checks if the objects type descriptor (the name parameter in the
|
||||
object descriptor structure) matches type. If this is so, a pointer to
|
||||
the objects data structure is returned. If one of the test fails, NULL
|
||||
is returned. Suitable parameters for type can be found by searching
|
||||
for CreateDescriptor in the implementation file of the desired
|
||||
object. After a cast to the proper pointer type, all the functions
|
||||
defined for the object and documented in its header file can be used.
|
||||
|
||||
\subsection{Running Motors and Counters}
|
||||
There are special rules which apply if a new command is written which
|
||||
coordinates motors and counters. For instance a special scan or drive
|
||||
command. It is important that such higher level code starts motors,
|
||||
virtual motors and counters through the interfaces defined by the
|
||||
device executor. The device executor guarantees proper monitoring of
|
||||
the device. The relevant functions are:
|
||||
\begin{verbatim}
|
||||
int StartMotor(pExeList self, SicsInterp *pSics, SConnection *pCon,
|
||||
char *name, float fNew);
|
||||
int StartCounter(pExeList self, SicsInterp *pSics, SConnection
|
||||
*pCon, char *name);
|
||||
|
||||
\end{verbatim}
|
||||
StartMotor starts the motor name to run to the new value
|
||||
fNew. StartCounter starts the counter name. The counter must have been
|
||||
loaded with proper presets etc. with the appropriate function
|
||||
calls. The device executor hides behind the pExeList pointer. This is
|
||||
always accessible through the global pointer: \verb+pServ->pExecutor+.
|
||||
|
||||
Once a counter or motor has been started, quite often the command can
|
||||
only continue if the operation has finished. But during this time the
|
||||
SICS server should be responsive to other clients. In order to do this
|
||||
we have to wait for the device executor task to finish. A code
|
||||
fragment implementing all this for a count operation is shown below:
|
||||
\begin{verbatim}
|
||||
/*-------------- count */
|
||||
iRet = StartCounter(pServ->pExecutor, pSics,
|
||||
pCon,
|
||||
``ScanCounter'');
|
||||
if(!iRet)
|
||||
{
|
||||
SCWrite(self->pCon,"ERROR: Cannot Count, Scan aborted",eError);
|
||||
return 0;
|
||||
}
|
||||
/* get the ID of the device executor task */
|
||||
lTask = GetDevexecID(pServ->pExecutor); /* get ID of device
|
||||
executor task */
|
||||
if(lTask > 0);
|
||||
{
|
||||
/* wait for the device executor to finish */
|
||||
TaskWait(pServ->pTasker,lTask);
|
||||
}
|
||||
|
||||
/* finished, check for interrupts. Whatever happened, user
|
||||
interrupt or HW interrupt, it will be on our connection
|
||||
*/
|
||||
iInt = SCGetInterrupt(self->pCon);
|
||||
switch(iInt)
|
||||
{
|
||||
case eContinue:
|
||||
break;
|
||||
case eAbortOperation:
|
||||
continue;
|
||||
break;
|
||||
case eAbortScan:
|
||||
SCWrite(self->pCon,"ERROR: Scan aborted",eError);
|
||||
/* eat the interrupt, the requested op has been
|
||||
done
|
||||
*/
|
||||
SCSetInterrupt(self->pCon,eContinue);
|
||||
return 0;
|
||||
break;
|
||||
default: /* all others */
|
||||
SCWrite(self->pCon,"ERROR: Scan aborted",eError);
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
\end{verbatim}
|
||||
This code also shows the necessary error checking. It also shows how
|
||||
to check for possible interrupts after such an operation. It is very
|
||||
advisable to do this because the user may have interrupted the
|
||||
process. And she might not be all to happy if the new command just
|
||||
continues with the next step rather then aborting the process.
|
||||
|
||||
|
||||
\section{SICS Interfaces}\label{interface}\label{inter}
|
||||
The point about SICS interfaces can best be deduced from an example:
|
||||
Everybody expects that a motor can be operated through a drive command
|
||||
or scanned in a scan. But there are other things which should be
|
||||
operated through a drive or scan commands too: environment controllers
|
||||
(temperature), virtual motors, chopper speeds, chopper phases and
|
||||
possibly other things. In order to make upper level scan or drive
|
||||
commands independent of the implementation of the actual operation it
|
||||
is useful to have an abstract interface for everything which can be
|
||||
driven or scanned. This is the drivable interface. Any such object
|
||||
which should be driven or scanned has to implement this interface.
|
||||
|
||||
Several of these interfaces exist in SICS:
|
||||
\begin{description}
|
||||
\item[Drivable] The drivable interface for everything which can be
|
||||
moved and takes some time to complete its movement.
|
||||
\item[Countable] Everything which counts: counters, histogram memories
|
||||
etc.
|
||||
\item[Environment] An interface which allows for monitoring of a
|
||||
parameter through the environment monitor. Usually these are sample
|
||||
environment things but it could also be chopper phases etc.
|
||||
\item[Callback] This is an interface which allows object A to call a
|
||||
special function, the callback function, in the context of object B
|
||||
whenever a certain event in A occurs. This is a way to automatically
|
||||
link object together in a component programming manner. This is also
|
||||
used for automatic notification of status clients when instrument
|
||||
parameters change.
|
||||
\end{description}
|
||||
|
||||
There are several situations when the SICS interfaces have to be
|
||||
considered:
|
||||
\begin{itemize}
|
||||
\item When hacking SICS kernel code or replacing parts of it.
|
||||
\item The driveable interface should be implemented by virtual
|
||||
motors. Virtual motors are objects which realize complex movements
|
||||
possibly involving multiple motors. Examples include driving
|
||||
wavelength (theta,two theta and possibly curvature motors have to be
|
||||
moved) or omega two theta.
|
||||
\item Any time objects are introduced into SICS which repesent
|
||||
completely new hardware.
|
||||
\item When automatical notifications between objects are needed, use
|
||||
the callback interface.
|
||||
\end{itemize}
|
||||
|
||||
Adding any such interface to your new SICS object involves the
|
||||
following steps:
|
||||
\begin{itemize}
|
||||
\item Add a data structure representing the interface to your objects
|
||||
data structure.
|
||||
\item Write all the functions required by the interface.
|
||||
\item Populate the interface data structure with the pointers to your
|
||||
function implementations.
|
||||
\item Write a new GetInterface function for the object descriptor
|
||||
which returns your new interface when requested and assign it to your
|
||||
object descriptors GetInterface field. SICS needs this in order to be
|
||||
able to find the objects new interface.
|
||||
\end{itemize}
|
||||
|
||||
The interfaces available are documented in the files interface.w,
|
||||
interface.h and interface.tex in the main SICS directory and through
|
||||
numerous examples in the source code.
|
||||
|
||||
A not overly complex example for the implementation of an interface is
|
||||
the code in o2t.* which implements the coupled driving of two motors
|
||||
where the second is always the double of the value of the first. This
|
||||
is for omega two-theta scans.
|
@ -41,7 +41,11 @@ $\langle$evdata {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@ pEVDriver pDriv;@\\
|
||||
\mbox{}\verb@ EVMode eMode;@\\
|
||||
\mbox{}\verb@ float fTarget;@\\
|
||||
\mbox{}\verb@ time_t start;@\\
|
||||
\mbox{}\verb@ time_t lastt;@\\
|
||||
\mbox{}\verb@ char *pName;@\\
|
||||
\mbox{}\verb@ char *driverName;@\\
|
||||
\mbox{}\verb@ char *errorScript;@\\
|
||||
\mbox{}\verb@ ObPar *pParam;@\\
|
||||
\mbox{}\verb@ int iLog;@\\
|
||||
\mbox{}\verb@ pVarLog pLog;@\\
|
||||
@ -69,8 +73,13 @@ reached its target value. Then there is a pointer to a callback
|
||||
interface. The fifth field is a pointer to the driver for
|
||||
the actual hardware. Next is the mode the device is in. Of course there
|
||||
must be floating point value which defines the current target value for the
|
||||
device. pName is a pointer to a string representing the name of the
|
||||
controller. Then there is a
|
||||
device. start and lastt are used to control the settling time.
|
||||
|
||||
pName is a pointer to a string representing the name of the
|
||||
controller. driverName is the name of the driver used by this
|
||||
device. errorScript is the name of a script command to run when the
|
||||
controller goes out of tolerance.
|
||||
Then there is a
|
||||
parameter array. iLog is a boolean which says if data should be logged
|
||||
for this controller or not. pLog is the a pointer to a Varlog structure
|
||||
holding the logging information. Then there is a switch, iWarned, which is
|
||||
@ -94,6 +103,8 @@ $\langle$evdriv {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@ typedef struct __EVDriver {@\\
|
||||
\mbox{}\verb@ int (*SetValue)(pEVDriver self, float fNew);@\\
|
||||
\mbox{}\verb@ int (*GetValue)(pEVDriver self, float *fPos);@\\
|
||||
\mbox{}\verb@ int (*GetValues)(pEVDriver self, float *fTarget,@\\
|
||||
\mbox{}\verb@ float *fPos, float *fDelta);@\\
|
||||
\mbox{}\verb@ int (*Send)(pEVDriver self, char *pCommand,@\\
|
||||
\mbox{}\verb@ char *pReplyBuffer, int iReplBufLen); @\\
|
||||
\mbox{}\verb@ int (*GetError)(pEVDriver self, int *iCode,@\\
|
||||
@ -290,6 +301,8 @@ See the documentation for commands understood.
|
||||
\mbox{}\verb@#define UPLIMIT 4@\\
|
||||
\mbox{}\verb@#define LOWLIMIT 5@\\
|
||||
\mbox{}\verb@#define SAFEVALUE 6@\\
|
||||
\mbox{}\verb@#define MAXWAIT 7@\\
|
||||
\mbox{}\verb@#define SETTLE 8@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@@$\langle$evdata {\footnotesize ?}$\rangle$\verb@@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
|
@ -48,6 +48,7 @@ $\langle$VE {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@#define COUNTSTART 10@\\
|
||||
\mbox{}\verb@#define COUNTEND 11@\\
|
||||
\mbox{}\verb@#define FILELOADED 12@\\
|
||||
\mbox{}\verb@#define MOTEND 13@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
\vspace{-1ex}
|
||||
@ -76,6 +77,7 @@ fiffractometer has been measured.
|
||||
\item[COUNTSTART] is an event which signals the start of a counting
|
||||
operation.
|
||||
\item[COUNTEND] is an event signalling the end of a counting operation.
|
||||
\item[MOTEND] signals the end of a driving operation.
|
||||
\end{description}
|
||||
|
||||
Furthermore event contains system wide signal codes which are interpreted in
|
||||
|
@ -3,7 +3,7 @@ In this chapter the facilities of the SICS servers kernel will be examined
|
||||
more closely. All the kernel modules and their function will be listed,
|
||||
together with some explanatory information and an overview about the
|
||||
application programmers interfaces (API) provided. This section should
|
||||
answer the questions: WHat is available?, Where to find what?,
|
||||
answer the questions: What is available?, Where to find what?,
|
||||
Why did they do that? Details of
|
||||
the API's mentioned are given in the reference section.
|
||||
|
||||
@ -34,11 +34,12 @@ SICS sense is defined by a function, the task function. It is of the type:
|
||||
int TaskFunction(void *pData);
|
||||
\end{verbatim}
|
||||
When it is time for the task to execute this function is called, with a
|
||||
parameter to a the tasks own data structure. This data structure must have
|
||||
been defined by the user of this module. The task function returns 1, if it
|
||||
shall continue to live, or 0 if it should be deleted from the task list.
|
||||
These task functions are kept in a list. The elements of this list are
|
||||
visited cyclically, when the scheduler runs.
|
||||
pointer to the tasks own data structure as a parameter. This data
|
||||
structure must have been defined by the user of this module. The task
|
||||
function returns 1, if it shall continue to live, or 0 if it should be
|
||||
deleted from the task list. These task functions are kept in a
|
||||
list. The elements of this list are visited cyclically, when the
|
||||
scheduler runs.
|
||||
|
||||
The API to this object consists of functions for creating a task manager,
|
||||
adding tasks to the task list and to run the task list. Other functions
|
||||
@ -102,7 +103,7 @@ SICS should be changed. For instance to Token--Ring or AppleTalk or
|
||||
whatever.
|
||||
The network reader implements the polling for network message in the SICS
|
||||
server. It is organized as one of the SICS system tasks. Polling in a POSIX
|
||||
environment is all about the select system call. The select system call
|
||||
environment is all about the select() system call. The select() system call
|
||||
allows to enquire if an open TCP/IP socket has data pending to be read, can
|
||||
be written to etc. For more details see the unix man pages for the select
|
||||
system call. An earlier version of the SICS server had a list of connection
|
||||
@ -124,7 +125,7 @@ The network reader currently supports four types of sockets:
|
||||
\item User sockets.
|
||||
\end{itemize}
|
||||
|
||||
The accept type of socket is the main server port where clients try to
|
||||
The accept type of socket is the main server port to which clients try to
|
||||
connect to. The network reader accepts the connection and tries to read a
|
||||
username/password pair for a specified amount of time.
|
||||
If the username/password is valid, the connection will be accepted,
|
||||
@ -135,13 +136,15 @@ the system and the network reader registers a new client command port.
|
||||
|
||||
The normal client command ports are accepted connections from a client. The
|
||||
SICS server expects commands to be sent from the clients. Thus any data
|
||||
pending on such a socket will be read, split into single commands at the \\n
|
||||
and put into the connections command stack for execution. At this place
|
||||
there is also the check for the special interrupt string on command
|
||||
connections (see \ref{prot1}).
|
||||
pending on such a socket will be read and split into single commands at
|
||||
the newline character. Now the network reader checks if the command
|
||||
represents an interrupt(see \ref{prot1}) and if so process the interrupt
|
||||
immediately. If not then command is put into the connections command
|
||||
stack for execution.
|
||||
|
||||
The SICS server accepts only interrupts on its UDP port. This will be checked
|
||||
for when handling data pending on the servers UDP port.
|
||||
The SICS server accepts interrupts also on its UDP port. This will be checked
|
||||
for when handling data pending on the servers UDP port. This feauture
|
||||
is implemented but not well tested and not used in the moment.
|
||||
|
||||
User type sockets are a feature for dealing with extremely slow hardware
|
||||
connections. Some hardware devices require a long time to answer requests.
|
||||
@ -175,16 +178,18 @@ mechanism. For more details see John Ousterhout's book.
|
||||
In an earlier stage it was considered to use the Tcl interpreter as the SICS
|
||||
interpreter. This idea was discarded for some reasons: One was the
|
||||
difficulty of transporting the client execution context (i.e. the connection
|
||||
object) through the Tcl interpreter. There is no standard Tcl mechanism for
|
||||
doing that. The second was security: the Tcl
|
||||
interpreter is very powerful and can be abused. It was felt that the system
|
||||
had to be protected against such problems. The third reasons was that the
|
||||
set of user commands should not be cluttered with Tcl commands in order to
|
||||
prevent confusion. Programming macros is anyway something which is done by
|
||||
SICS managers or programmers. However, the SICS interpreter is still modeled
|
||||
very much like the Tcl-interpreter. A Tcl interpreter is still included in
|
||||
order to provide a full featured macro language. The SICS interpreter and the
|
||||
Tcl macro interpreter are still tightly coupled.
|
||||
object) through the Tcl interpreter. This reason has become invalid
|
||||
now, with the advent of Tcl 8.+ which supports namespaces. The second
|
||||
was security: the Tcl interpreter is very powerful and can be
|
||||
abused. It was felt that the system had to be protected against such
|
||||
problems. The third reasons was that the set of user commands should
|
||||
not be cluttered with Tcl commands in order to prevent
|
||||
confusion. Programming macros is anyway something which is done by
|
||||
SICS managers or programmers. However, the SICS interpreter is still
|
||||
modeled very much like the Tcl-interpreter. A Tcl interpreter is
|
||||
still included in order to provide a full featured macro
|
||||
language. The SICS interpreter and the Tcl macro interpreter are
|
||||
still tightly coupled.
|
||||
|
||||
The SICS interpreter must forward commands to the SICS objects. For this the
|
||||
interpreter needs some help from the objects themselves. Each SICS object
|
||||
@ -285,34 +290,15 @@ For the SICS concept for handling sample environment devices see
|
||||
\section{The Server}
|
||||
The server module defines a server data structure. A pointer to this
|
||||
data structure is the sole global variable in the SICS system. Its name is
|
||||
{\bf {\huge pServ}}. This data structure contains pointers to the most
|
||||
{\bf pServ}. This data structure contains pointers to the most
|
||||
important SICS components: the interpreter, the task switcher, the device
|
||||
executor, the environment monitor and the network reader. This module also
|
||||
contains the code for initializing, running and stopping the server.
|
||||
|
||||
\section{The ServerLog}
|
||||
As part of the SICS kernel there exists a global server log file. This file
|
||||
contains:
|
||||
\begin{itemize}
|
||||
\item All traffic on all client connections. Even messages suppressed by the
|
||||
clients.
|
||||
\item All internal error messages.
|
||||
\item Notifications about important internal status changes.
|
||||
\end{itemize}
|
||||
This server log is meant as an aid in debugging the server. As the SICS
|
||||
server may run for days, weeks and months uninterrupted this log file may
|
||||
become very large. However, only the last thousand or so messages are really
|
||||
of interest when tracking a problem. Therefore a scheme is implemented to
|
||||
limit the disk space used by the server log. The server log writes
|
||||
cyclically into a number of files. A count of the lines is kept which were
|
||||
written to each file. Above a predefined count, a new file is started.
|
||||
As an interface the server log provides a function which allows to write
|
||||
a message to it. This can be used by any object in the system for
|
||||
interesting messages. The number of files to cycle through and the length of
|
||||
each file can be configured by defines at the top of servlog.c.
|
||||
|
||||
\section{The Performance Monitor}
|
||||
This facility provides the data for the Performance (see user documentation)
|
||||
This facility provides the data for the ``Performance''
|
||||
(see user documentation)
|
||||
command. The Performance Monitor is a task which increments a counter each
|
||||
time it is executed. After a predefined integration time (20 seconds) a new
|
||||
value cycles/per second is calculated. This is the data retrievable by the
|
||||
@ -325,7 +311,7 @@ monitor may well be removed from the system without harm.
|
||||
\section{The Object Factory}
|
||||
During SICS initialization the SICS interpreters command list needs to be
|
||||
initialized. This is the task of the object factory. Its function
|
||||
IniIniCommand initializes all fixed, general SICS commands and all object
|
||||
InitIniCommands initializes all fixed, general SICS commands and all object
|
||||
creation commands. Then the server initialization file is processed from the
|
||||
server initialization code. After this is done, the server initialization
|
||||
code calls KillIniCommands which removes the now surplus object creation
|
||||
@ -351,5 +337,63 @@ users. If this becomes a serious concern, this module has to be rewritten.
|
||||
\section{The Server Main Function}
|
||||
This does not do much, just initialize the server, run it, and stop it.
|
||||
|
||||
|
||||
|
||||
\section{Logging}
|
||||
The SICS server offers multiple options for logging:
|
||||
\begin{itemize}
|
||||
\item There is a cyclical server log logging all traffic. This is
|
||||
described below.
|
||||
\item Per client connection log files can be configured. This is part
|
||||
of the connection object interface.
|
||||
\item A special module, the commandlog exists, which saves all traffic
|
||||
issued on client connections with user or manager privilege. This is
|
||||
the most useful log for finding problems. This facility can be
|
||||
configured to create a log file per day. Or the user can demand to
|
||||
have her very own log file.
|
||||
\end{itemize}
|
||||
|
||||
|
||||
\subsection{The ServerLog}
|
||||
As part of the SICS kernel there exists a global server log file. This file
|
||||
contains:
|
||||
\begin{itemize}
|
||||
\item All traffic on all client connections. Even messages suppressed by the
|
||||
clients.
|
||||
\item All internal error messages.
|
||||
\item Notifications about important internal status changes.
|
||||
\end{itemize}
|
||||
This server log is meant as an aid in debugging the server. As the SICS
|
||||
server may run for days, weeks and months uninterrupted this log file may
|
||||
become very large. However, only the last thousand or so messages are really
|
||||
of interest when tracking a problem. Therefore a scheme is implemented to
|
||||
limit the disk space used by the server log. The server log writes
|
||||
cyclically into a number of files. A count of the lines is kept which were
|
||||
written to each file. Above a predefined count, a new file is started.
|
||||
As an interface the server log provides a function which allows to write
|
||||
a message to it. This can be used by any object in the system for
|
||||
interesting messages. The number of files to cycle through and the length of
|
||||
each file can be configured by defines at the top of servlog.c.
|
||||
|
||||
|
||||
\section{Instrument Status Persistence}
|
||||
Real programs do dump core (the SICS server is good, but is no
|
||||
exception in this respect) and real computers fall over. In such cases
|
||||
it would be useful if instrument configuration parameters such as
|
||||
zero points , variable settings etc. are not lost. SICS achieves this
|
||||
by writing a status file each time a parameter changes. This
|
||||
status file is read back whenever the SICS server starts. The default
|
||||
status file is configured in the instrument startup file as the SicsOption
|
||||
statusfile. The user
|
||||
can also request a status file to be written or recovered manually.
|
||||
The status file is just a file with SICS commands which configure
|
||||
relevant parameters. The actual writing of these commands is delegated
|
||||
to each SICS object. Each SICS object which whishes to save data into
|
||||
the status file has to implement a function which will
|
||||
automatically be called when a status file is written. For details,
|
||||
consult the chapter on SICS object implementation.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -44,7 +44,7 @@ Clients can choose to suppress certain types of messages in order to
|
||||
reduce I/O.
|
||||
|
||||
The logic is mostly implemented in the
|
||||
file static function SCNormalWrite. The follwoing conditions are
|
||||
file static function SCNormalWrite. The following conditions are
|
||||
implemented:
|
||||
\begin{itemize}
|
||||
\item Any output is logged to the
|
||||
@ -60,17 +60,17 @@ type error or warning are printed to the socket even during macro
|
||||
evaluation.
|
||||
\item In the normal case the output is printed to the socket and all
|
||||
log files configured for the connection.
|
||||
\item As of recent the output function can be modified by setting a
|
||||
new function. One sich function exists which supresses all output to
|
||||
the socket. This is done in order to help when the connection gets
|
||||
lost. For instance with the cron command.
|
||||
\end{itemize}
|
||||
This aspect of the connection object could do with a cleanup. A
|
||||
possible cleanup path is the implementation of the different output
|
||||
strategies in different functions and devise a SCsetOutMode function which
|
||||
switches between the various possibilities. Also, it can be argued if
|
||||
the client specific log files are still needed. Then this part of the
|
||||
code can be cleaned out as well.
|
||||
The above described the default. It turned out that many special cases
|
||||
exist where it is feasible to suppress parts of the output. In order
|
||||
to take care of this, SCWrite calls a configurable write
|
||||
function. This write function can be retrieved and set with
|
||||
SCGetWriteFunc and SCSetWriteFunc. SCnoSock, SConlySock, SCnotWrite
|
||||
select some predefined write functions for special cases. Please note
|
||||
that each of these calls switches the write function for the lifetime
|
||||
of the connection or until it is set to a new one through
|
||||
SCSetWriteFunc.
|
||||
|
||||
|
||||
|
||||
\subsubsection{Command Execution Path}
|
||||
@ -120,6 +120,9 @@ $\langle$condat {\footnotesize ?}$\rangle\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@typedef int (*writeFunc)(struct __SConnection *pCon,@\\
|
||||
\mbox{}\verb@ char *pMessage, int iCode);@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ typedef struct __SConnection {@\\
|
||||
\mbox{}\verb@ /* object basics */@\\
|
||||
\mbox{}\verb@ pObjectDescriptor pDes;@\\
|
||||
@ -133,8 +136,7 @@ $\langle$condat {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@ int iTelnet;@\\
|
||||
\mbox{}\verb@ int iOutput; @\\
|
||||
\mbox{}\verb@ int iFiles;@\\
|
||||
\mbox{}\verb@ int (*write)(struct __SConnection *pCon,@\\
|
||||
\mbox{}\verb@ char *pMessage, int iCode);@\\
|
||||
\mbox{}\verb@ writeFunc write;@\\
|
||||
\mbox{}\verb@ mkChannel *pDataSock;@\\
|
||||
\mbox{}\verb@ char *pDataComp;@\\
|
||||
\mbox{}\verb@ int iDataPort;@\\
|
||||
@ -146,6 +148,7 @@ $\langle$condat {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@ int iDummy;@\\
|
||||
\mbox{}\verb@ int iGrab;@\\
|
||||
\mbox{}\verb@ int iErrCode;@\\
|
||||
\mbox{}\verb@ int parameterChange;@\\
|
||||
\mbox{}\verb@ SicsInterp *pSics;@\\
|
||||
\mbox{}\verb@ @\\
|
||||
\mbox{}\verb@ /* a FIFO */@\\
|
||||
@ -153,9 +156,15 @@ $\langle$condat {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ /* callback registry */@\\
|
||||
\mbox{}\verb@ int iList;@\\
|
||||
\mbox{}\verb@ @\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ /* Tasking Stuff */@\\
|
||||
\mbox{}\verb@ int iEnd;@\\
|
||||
\mbox{}\verb@ /* for keeping track of the login@\\
|
||||
\mbox{}\verb@ process on a non telnet connection.@\\
|
||||
\mbox{}\verb@ Should only be used in SCTaskFunction@\\
|
||||
\mbox{}\verb@ */@\\
|
||||
\mbox{}\verb@ int iLogin;@\\
|
||||
\mbox{}\verb@ time_t conStart;@\\
|
||||
\mbox{}\verb@ }SConnection;@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
@ -214,6 +223,10 @@ registered on this connection object.
|
||||
\item[iEnd] iEnd is a flag which is usually 0. It is set by certain
|
||||
interrupts or if the connection is broken and causes the connection task to
|
||||
end and the connection data structure to be removed from the system.
|
||||
\item[iLogin] A flag which is set when we are not yet logged in.
|
||||
\item[conStart] The time the connection was established. Used to
|
||||
timeout connections when no valid login comes within a decent time
|
||||
intervall.
|
||||
\end{description}
|
||||
Quite a few places in SICS refer to this data structure directly,
|
||||
without a function interface. The reason for this is performance. Therefore
|
||||
@ -247,6 +260,11 @@ $\langle$conint {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@ int SCSendOK(SConnection *self);@\\
|
||||
\mbox{}\verb@ int SCnoSock(SConnection *pCon);@\\
|
||||
\mbox{}\verb@ int SCWriteUUencoded(SConnection *pCon, char *pName, void *iData, int iLen);@\\
|
||||
\mbox{}\verb@ int SCWriteZipped(SConnection *pCon, char *pName, void *pData, int iDataLen);@\\
|
||||
\mbox{}\verb@ writeFunc SCGetWriteFunc(SConnection *pCon);@\\
|
||||
\mbox{}\verb@ void SCSetWriteFunc(SConnection *pCon, writeFunc x);@\\
|
||||
\mbox{}\verb@ int SCOnlySockWrite(SConnection *self, char *buffer, int iOut);@\\
|
||||
\mbox{}\verb@ int SCNotWrite(SConnection *self, char *buffer, int iOut);@\\
|
||||
\mbox{}\verb@/************************* CallBack *********************************** */@\\
|
||||
\mbox{}\verb@ int SCRegister(SConnection *pCon, SicsInterp *pSics,@\\
|
||||
\mbox{}\verb@ void *pInter, long lID);@\\
|
||||
@ -254,19 +272,20 @@ $\langle$conint {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@/******************************* Error **************************************/@\\
|
||||
\mbox{}\verb@ void SCSetInterrupt(SConnection *self, int eCode);@\\
|
||||
\mbox{}\verb@ int SCGetInterrupt(SConnection *self); @\\
|
||||
\mbox{}\verb@ void SCSetError(SConnection *pCon, int iCode);@\\
|
||||
\mbox{}\verb@ int SCGetError(SConnection *pCon); @\\
|
||||
\mbox{}\verb@/****************************** Macro ***************************************/@\\
|
||||
\mbox{}\verb@ int SCinMacro(SConnection *pCon);@\\
|
||||
\mbox{}\verb@ int SCsetMacro(SConnection *pCon, int iMode); @\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@/************************** parameters changed ? **************************/@\\
|
||||
\mbox{}\verb@ void SCparChange(SConnection *pCon);@\\
|
||||
\mbox{}\verb@/* *************************** Info *************************************** */@\\
|
||||
\mbox{}\verb@ int SCGetRights(SConnection *self);@\\
|
||||
\mbox{}\verb@ int SCSetRights(SConnection *pCon, int iNew);@\\
|
||||
\mbox{}\verb@ int SCMatchRights(SConnection *pCon, int iCode);@\\
|
||||
\mbox{}\verb@ int SCGetOutClass(SConnection *self);@\\
|
||||
\mbox{}\verb@ int SCGetGrab(SConnection *pCon);@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@/********************* simulation mode ************************************/@\\
|
||||
\mbox{}\verb@ void SCSetSimMode(SConnection *pCon, int value);@\\
|
||||
\mbox{}\verb@ int SCinSimMode(SConnection *pCon);@\\
|
||||
\mbox{}\verb@/* **************************** Invocation ******************************** */@\\
|
||||
\mbox{}\verb@ int SCInvoke(SConnection *self,SicsInterp *pInter,char *pCommand);@\\
|
||||
\mbox{}\verb@ @\\
|
||||
@ -318,6 +337,20 @@ timeout period. pPrompt is the prompt for the client, pResult is the buffer
|
||||
with the client reply. Maximum iLen bytes will be copied to
|
||||
pResult. Returns true (1) on a successfull read, else 0 (false).
|
||||
\item[SCSendOK] A short cut which sends OK to the client.
|
||||
\item[SCnoSock] Suppress output onto the client socket but keeps on
|
||||
logging output to file. This is mostly used when the socket connection
|
||||
closes with a batch file still being active.
|
||||
\item[SCWriteUUencoded] sends iData in UU encoded form. For
|
||||
communication with status clients.
|
||||
\item[SCWriteZipped] writes pData in zipped form. Works only if the
|
||||
connection is a plain connection, no telnet mode. This first sends a
|
||||
line: SICSBIN ZIP dataname datalength followed by datalength bytes of
|
||||
zipped data after the newline. Used for transferring larger amounts of
|
||||
data to status clients.
|
||||
\item[SCGetWriteFunc] gets the currently active write function.
|
||||
\item[SCSetWriteFunc] sets a new write function.
|
||||
\item[SCOnlySockWrite] write only to socket, not to log files.
|
||||
\item[SCNotWrite] do not write at all.
|
||||
\item[SCRegister] registers a callback with the connection. Parameters are:
|
||||
The interpreter to use, the interface with which the callback was
|
||||
registered and the ID of the callback. All automatic notifications to a
|
||||
@ -329,11 +362,11 @@ happen.
|
||||
\item[SCSetInterrupt] sets an interrupt on the connection.
|
||||
\item[SCGetInterrupt] retrives the current interrupt status of the
|
||||
connection.
|
||||
\item[SCSetError] sets an error code in the connection.
|
||||
\item[SCGetError] retreives the current error code on the connection.
|
||||
\item[SCinMacro] returns true if the connection is executing a tcl script,
|
||||
returns false otherwise.
|
||||
\item[SCsetMacro] sets the iMacro flag.
|
||||
\item[SCparChange] sets the flag that a parameter was changed and the
|
||||
status file needs to be rewritten.
|
||||
\item[SCGetRights] returns the current user rights associated with the
|
||||
connection.
|
||||
\item[SCGetGrab] gets the status of the control token for this connection.
|
||||
@ -344,6 +377,8 @@ connection has the control token.
|
||||
rights of the connection, 0 (false) otherwise. SCMatchRights also checks for
|
||||
the status of the control token. Suitable error messages are written to pCon
|
||||
if the user rights do not match.
|
||||
\item[SCSetSimMode] sets this connection into simulation mode.
|
||||
\item[SCinSimMode] checks for the simulation mode flag.
|
||||
\item[SCInvoke] invokes pCommand in the SICS interpreter pSics for the
|
||||
connection pCon. This function also prints the executed command into
|
||||
logfiles and into the commandlog.
|
||||
@ -366,6 +401,8 @@ logfiles and into the commandlog.
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ Mark Koennecke, September 1997@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ Mark Koennecke, Aprl 2003@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ copyright: see copyright.h@\\
|
||||
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
|
||||
\mbox{}\verb@#ifndef SICSCONNECT@\\
|
||||
|
@ -19,6 +19,7 @@ $\langle$servdat {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@ mkChannel *pServerPort;@\\
|
||||
\mbox{}\verb@ pNetRead pReader;@\\
|
||||
\mbox{}\verb@ int simMode;@\\
|
||||
\mbox{}\verb@ SConnection *dummyCon;@\\
|
||||
\mbox{}\verb@ } SicsServer;@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
@ -43,6 +44,8 @@ the SICS server is listening for connections.
|
||||
communication object.
|
||||
\item[simMode] a flag which is true when the SICS server is a simulation
|
||||
server.
|
||||
\item[dummyCon] A dummy connection to use when no other connection is
|
||||
available for some reason.
|
||||
\end{description}
|
||||
|
||||
|
||||
|
@ -60,6 +60,8 @@ time-of-flight mode.
|
||||
\mbox{}\verb@----------------------------------------------------------------------*/@\\
|
||||
\mbox{}\verb@#ifndef NXAMOR@\\
|
||||
\mbox{}\verb@#define NXAMOR@\\
|
||||
\mbox{}\verb@#include <scan.h>@\\
|
||||
\mbox{}\verb@#include <HistMem.h>@\\
|
||||
\mbox{}\verb@@$\langle$namor {\footnotesize ?}$\rangle$\verb@@\\
|
||||
\mbox{}\verb@#endif@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
|
@ -194,7 +194,7 @@ NexUs API which holds the dictionary information within a NeXus file.
|
||||
One additional data type is needed for this API:
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap1}
|
||||
$\langle$tata {\footnotesize 4a}$\rangle\equiv$
|
||||
$\langle$tata {\footnotesize ?}$\rangle\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
@ -213,7 +213,7 @@ NXdict will be used as a handle for the dictionary currently in use.
|
||||
\subsubsection{Dictionary Maintainance Function}
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap2}
|
||||
$\langle$dicman {\footnotesize 4b}$\rangle\equiv$
|
||||
$\langle$dicman {\footnotesize ?}$\rangle\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
@ -264,7 +264,7 @@ $\langle$dicman {\footnotesize 4b}$\rangle\equiv$
|
||||
\subsubsection{Data Handling functions}
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap3}
|
||||
$\langle$dicdata {\footnotesize 5}$\rangle\equiv$
|
||||
$\langle$dicdata {\footnotesize ?}$\rangle\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
@ -347,7 +347,7 @@ The NXDICT data handling functions go in pairs. The version ending in
|
||||
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap4}
|
||||
$\langle$dicutil {\footnotesize 6}$\rangle\equiv$
|
||||
$\langle$dicutil {\footnotesize ?}$\rangle\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
@ -411,7 +411,7 @@ the current approach poses a serious performance problem.
|
||||
Thus, the NXdict data structure looks like this:
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap5}
|
||||
$\langle$dicdat {\footnotesize 7}$\rangle\equiv$
|
||||
$\langle$dicdat {\footnotesize ?}$\rangle\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
@ -1155,7 +1155,7 @@ $\langle$deftok {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@ {"-type",DTYPE},@\\
|
||||
\mbox{}\verb@ {"-rank",DRANK},@\\
|
||||
\mbox{}\verb@ {"-attr",DATTR},@\\
|
||||
\mbox{}\verb@ {NULL,0} };@\\
|
||||
\mbox{}\verb@ {"",0} };@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@/*-----------------------------------------------------------------------*/@\\
|
||||
\mbox{}\verb@ static void NXDIDefToken(ParDat *sStat)@\\
|
||||
@ -1543,7 +1543,7 @@ $\langle$nxpasds {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@ iRank = atoi(pParse->pToken);@\\
|
||||
\mbox{}\verb@ break;@\\
|
||||
\mbox{}\verb@ case DDIM:@\\
|
||||
\mbox{}\verb@ iRet = NXDIParseDim(pParse, iDim);@\\
|
||||
\mbox{}\verb@ iRet = NXDIParseDim (pParse, (int *) iDim);@\\
|
||||
\mbox{}\verb@ if(iRet == NX_ERROR)@\\
|
||||
\mbox{}\verb@ {@\\
|
||||
\mbox{}\verb@ LLDdelete(iList);@\\
|
||||
@ -1599,7 +1599,7 @@ $\langle$nxpasds {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@ /* we need to create it, if we may */@\\
|
||||
\mbox{}\verb@ if(pParse->iMayCreate)@\\
|
||||
\mbox{}\verb@ {@\\
|
||||
\mbox{}\verb@ iRet = NXmakedata(hfil,pName,iType, iRank,iDim);@\\
|
||||
\mbox{}\verb@ iRet = NXmakedata (hfil, pName, iType, iRank, (int *) iDim);@\\
|
||||
\mbox{}\verb@ if(iRet != NX_OK)@\\
|
||||
\mbox{}\verb@ { @\\
|
||||
\mbox{}\verb@ /* a comment on this one has already been written! */@\\
|
||||
@ -1669,7 +1669,7 @@ $\langle$parsetype {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@ {"DFNT_UINT16",DFNT_UINT16},@\\
|
||||
\mbox{}\verb@ {"DFNT_INT32",DFNT_INT32},@\\
|
||||
\mbox{}\verb@ {"DFNT_UINT32",DFNT_UINT32},@\\
|
||||
\mbox{}\verb@ {NULL,-122} };@\\
|
||||
\mbox{}\verb@ {"",0} };@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@@\\
|
||||
@ -2737,15 +2737,15 @@ $\langle$free {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@#include "napi.h" /* make sure, napi is included */@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@/*-------------------- NXDict data types & defines ----------------------*/@\\
|
||||
\mbox{}\verb@@$\langle$tata {\footnotesize 4a}$\rangle$\verb@@\\
|
||||
\mbox{}\verb@@$\langle$tata {\footnotesize ?}$\rangle$\verb@@\\
|
||||
\mbox{}\verb@#define NXquiet 0@\\
|
||||
\mbox{}\verb@#define NXalot 1@\\
|
||||
\mbox{}\verb@/*-------------------- Dictionary Maintainance ----------------------------*/@\\
|
||||
\mbox{}\verb@@$\langle$dicman {\footnotesize 4b}$\rangle$\verb@@\\
|
||||
\mbox{}\verb@@$\langle$dicman {\footnotesize ?}$\rangle$\verb@@\\
|
||||
\mbox{}\verb@/*----------------- Dictionary added data transfer -----------------------*/ @\\
|
||||
\mbox{}\verb@@$\langle$dicdata {\footnotesize 5}$\rangle$\verb@@\\
|
||||
\mbox{}\verb@@$\langle$dicdata {\footnotesize ?}$\rangle$\verb@@\\
|
||||
\mbox{}\verb@/*-------------------- Utility Functions --------------------------------*/@\\
|
||||
\mbox{}\verb@@$\langle$dicutil {\footnotesize 6}$\rangle$\verb@@\\
|
||||
\mbox{}\verb@@$\langle$dicutil {\footnotesize ?}$\rangle$\verb@@\\
|
||||
\mbox{}\verb@#endif@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
@ -2804,7 +2804,7 @@ $\langle$free {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@ dictionaries.@\\
|
||||
\mbox{}\verb@*/@\\
|
||||
\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
|
||||
\mbox{}\verb@@$\langle$dicdat {\footnotesize 7}$\rangle$\verb@@\\
|
||||
\mbox{}\verb@@$\langle$dicdat {\footnotesize ?}$\rangle$\verb@@\\
|
||||
\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
|
||||
\mbox{}\verb@ static char *NXDIReadFile(FILE *fd)@\\
|
||||
\mbox{}\verb@ {@\\
|
||||
|
@ -428,7 +428,8 @@ Sometimes error conditions arise in lower level code which should cause all
|
||||
upper level code to finish execution. Such conditions may be the result of a
|
||||
critical hardware fault or may even be requested by a user who wants to
|
||||
abort an operation. A standard method for communicating such conditions
|
||||
through the system is necessary. SICS uses interrupts for such conditions.
|
||||
through the system is necessary.
|
||||
SICS uses interrupts for such conditions.
|
||||
The current interrupt active interrupt is located at the connection object
|
||||
and can be retrieved with {\bf SCGetInterrupt} and set with {\bf
|
||||
SCSetInterrupt}. Interrupt codes are defined in interrupt.h and are ordered
|
||||
|
@ -14,7 +14,8 @@ System, had to meet the following specifications:
|
||||
\item Enhanced portability across instrument hardware. This means that it
|
||||
should be easy to add other types of motors, counters or other hardware to
|
||||
the system.
|
||||
\item Support authorization on the command and variable level. This means
|
||||
\item Support authorization on the command and parameter modification
|
||||
level. This means
|
||||
that certain instrument settings can be protected against random changes by
|
||||
less knowledgable users.
|
||||
\item Good maintainability and extendability.
|
||||
@ -28,14 +29,20 @@ matches the above criteria.
|
||||
\section{The SINQ Hardware Setup}
|
||||
SICS had to take in account the SINQ hardware setup which had been decided
|
||||
upon earlier on. Most hardware such as motors and counters is controlled via
|
||||
RS--232 interfaces. These devices connect to a Macintosh PC which has a
|
||||
terminal server program running on it. This terminal server program collects
|
||||
request to the hardware from a TCP/IP port and forwards them to the serial
|
||||
device. The instrument control program runs on a workstation running
|
||||
DigitalUnix. Communication with the hardware happens via TCP/IP through the
|
||||
terminal server. Some hardware devices, such as the histogram memory, can handle
|
||||
RS--232 interfaces. These RS--232 interfaces are connected to a
|
||||
terminal server which allows to access such devices through the TCP/IP
|
||||
network.
|
||||
|
||||
For historical reasons the instrument control software does not access
|
||||
the terminal server directly but through another software layer, the
|
||||
SerPortServer program. The SerPortServer program is another TCP/IP
|
||||
server which allows multiple network clients to access the same
|
||||
terminal server port through a home grown protocoll. In the long run
|
||||
this additional software layer will be abolished.
|
||||
|
||||
Some hardware devices, such as the histogram memory, can handle
|
||||
TCP/IP themselves. With such devices the instrument control program
|
||||
communicates directly through TCP/IP, without a terminal server. All
|
||||
communicates directly through TCP/IP. All
|
||||
hardware devices take care of their real time needs themselves. Thus the
|
||||
only task of the instrument control program is to orchestrate the hardware
|
||||
devices. SICS is designed with this setup up in mind, but is not restricted
|
||||
@ -72,7 +79,7 @@ This is a real concern at SINQ where VMS,
|
||||
Intel-PC, Macintosh and Unix users have to be satisfied.
|
||||
As many instrument scientists still prefer
|
||||
the command line for interacting with instruments, the most used client is a
|
||||
visual command line client. Status displays are another sort of specialized
|
||||
visual command line client. Status displays are another kind of specialized
|
||||
client programs. Graphical user interfaces are under consideration for some
|
||||
instruments. As an example for a client a screen shot of the status display
|
||||
client for a powder diffractometer is given in picture \ref{dmc}
|
||||
@ -80,7 +87,7 @@ client for a powder diffractometer is given in picture \ref{dmc}
|
||||
\begin{figure}
|
||||
%% \epsfxsize=0.65\textwidth
|
||||
\epsfxsize=160mm
|
||||
%% \epsffile{dmc.eps}
|
||||
\epsffile{dmccom.eps}
|
||||
\caption{Example for a SICS client: Powder Diffractometer Status Display}\label{dmc}
|
||||
\end{figure}
|
||||
|
||||
@ -90,15 +97,18 @@ client for a powder diffractometer is given in picture \ref{dmc}
|
||||
The SICS server is the core component of the SICS system. The SICS server is
|
||||
responsible for doing all the work in instrument control. Additionally the
|
||||
server has to answer the requests of possibly multiple clients.
|
||||
The SICS server can be subdivided into three subsystems: The kernel, a database
|
||||
of SICS objects and an interpreter. The SICS server kernel takes care of
|
||||
client multitasking and the preservation of the proper I/O and error context
|
||||
for each client command executing.
|
||||
SICS objects are software modules which represent all aspects
|
||||
of an instrument: hardware devices, commands, measurement strategies
|
||||
The SICS server can be subdivided into three subsystems:
|
||||
\begin{description}
|
||||
\item[The kernel] The SICS server kernel
|
||||
takes care of client multitasking and the preservation of the proper
|
||||
I/O and error context for each client command executing.
|
||||
\item[SICS Object Database] SICS objects are software modules which
|
||||
represent all aspects of an instrument: hardware devices, commands, measurement strategies
|
||||
and data storage. This database of objects is initialized at server startup
|
||||
time from an initialization script. The third SICS server component is an
|
||||
interpreter which allows to issue commands to the objects in the objects database.
|
||||
time from an initialization script.
|
||||
\item[The Interpreter] The interpreter allows to issue commands to the
|
||||
objects in the objects database.
|
||||
\end{description}
|
||||
The schematic drawing of the SICS server's structure is given in picture
|
||||
\ref{newsics}.
|
||||
\begin{figure}
|
||||
@ -120,28 +130,29 @@ In more detail the SICS server kernel has the following tasks:
|
||||
\item Monitor HW--operations.
|
||||
\item Monitor environment devices.
|
||||
\end{itemize}
|
||||
Any server serving multiple clients has the problem how to organize multiple
|
||||
clients accessing the same server and how to stop one client reading data,
|
||||
which another client is just writing. The approach used for the SICS server
|
||||
is a combination of polling and cooperative multitasking. This scheme is
|
||||
Any program serving multiple clients has the problem how to organize multiple
|
||||
clients accessing the same server and how to prevent one client from
|
||||
reading data, while another client is writing. The approach used for
|
||||
the SICS server is a combination of polling and cooperative multitasking. This scheme is
|
||||
simple and can be implemented in an operating system independent manner. One
|
||||
way to look at the SICS server is as a series of tasks in a circular queue
|
||||
executing one after another. The servers main loop does nothing but
|
||||
executing the tasks in this circular buffer in an endless loop.
|
||||
There are several system tasks and one such
|
||||
task for each living client connection. Thus only one task executes at any
|
||||
given time and data access is efficiently serialized. One of the main system
|
||||
given time and data access is efficiently serialized.
|
||||
|
||||
One of the main system
|
||||
tasks (and the one which will be always there) is the network reader. The
|
||||
network reader has a list of open network connections and checks each of
|
||||
them for pending requests. What happens when a data is pending on an open
|
||||
them for pending requests. What happens when data is pending on an open
|
||||
network port depends on the type of port: If it is the servers main
|
||||
connection port, the network reader will try to accept and verify a new
|
||||
client connection and create the associated data structures. If the port
|
||||
belongs to an open client connection the network reader will read the
|
||||
command pending and put it onto a command stack existing for each client
|
||||
connection. When it is time for a client task to execute, it will fetch a
|
||||
command from its very own command stack and execute it. When the net reader
|
||||
finds an user interrupt pending, the interrupt is executed.
|
||||
command from its very own command stack and execute it.
|
||||
This is how the SICS server deals with client requests.
|
||||
|
||||
The scheme described above relies on the fact that most SICS command need
|
||||
@ -170,7 +181,7 @@ an hardware request all other clients requests to drive the hardware will
|
||||
return an error. The device executor is also responsible for monitoring the
|
||||
progress of an hardware operation. It does so by adding a special task into
|
||||
the system which checks the status of the operation each time this tasks
|
||||
executes. When the hardware operation is finished (one way or another) this
|
||||
executes. When the hardware operation is finished this
|
||||
device executor task will end. A special system facility allows a client
|
||||
task to wait for the device executor task to end while the rest of the task
|
||||
queue is still executing. In this way time intensive hardware operations can
|
||||
@ -190,9 +201,9 @@ Most experiments do not happen at ambient room conditions but
|
||||
require some special environment for the sample. Mostly this is temperature
|
||||
but it can also be magnetic of electric fields etc. Most of such devices
|
||||
can regulate themselves but the data acquisition program needs to monitor
|
||||
such devices. Within SICS this is done via a special system object, the
|
||||
such devices. Within SICS, this is done via a special system object, the
|
||||
environment monitor. A environment device, for example a temperature
|
||||
controller, registers it's presence with this object. Then an special system
|
||||
controller, registers it's presence with this object. Then a special system
|
||||
task will control this device when it is executing, check for possible out
|
||||
of range errors and initiates the proper error handling if such a problem is
|
||||
encountered.
|
||||
@ -241,15 +252,15 @@ to a system of protocols. There are protocols for:
|
||||
\item For checking the authorisation of the client who wants to execute the
|
||||
command.
|
||||
\end{itemize}
|
||||
|
||||
SICS uses NeXus$^{2}$, the upcoming standard for data exchange for neutron
|
||||
and x\_ray scattering as its raw data format.
|
||||
|
||||
SICS objects have the ability to notify clients and other objects of
|
||||
internal state changes. For example when a motor is driven, the motor object
|
||||
can be configured to tell SICS clients or other SICS objects about his new
|
||||
position.
|
||||
|
||||
SICS uses NeXus$^{2}$, the upcoming standard for data exchange for neutron
|
||||
and x--ray scattering as its raw data format.
|
||||
|
||||
|
||||
\section{SICS Working Examples}
|
||||
In order to get a better feeling for the internal working of SICS the course
|
||||
of a few different requests through the SICS system is traced in this
|
||||
@ -268,10 +279,10 @@ done by a special system component, the task switcher.
|
||||
\subsection{The Request for a new Client Connection}
|
||||
\begin{itemize}
|
||||
\item The network reader recognizes pending data on its main server port.
|
||||
\item The network reader accepts the connection and tries to read a
|
||||
\item The network reader accepts the connection and tries to read an
|
||||
username/password pair.
|
||||
\item If such a username/password pair comes within a suitable time
|
||||
intervals it is checked for validity. On failure the connection is closed
|
||||
\item If such an username/password pair comes within a suitable time
|
||||
interval it is checked for validity. On failure the connection is closed
|
||||
again.
|
||||
\item If a valid connection has been found: A new connection object is
|
||||
created, a new task for this client connection is introduced into the
|
||||
@ -284,7 +295,7 @@ pending commands.
|
||||
\begin{itemize}
|
||||
\item The network reader finds data pending at one of the client ports.
|
||||
\item The network reader reads the command, splits it into single lines and
|
||||
put those on the top of the client connections command stack. The network
|
||||
put those on top of the client connections command stack. The network
|
||||
reader passes control to the task switcher.
|
||||
\item In due time the client connection task executes, inspects its command
|
||||
stack, pops the command pending and forwards it together with a pointer to
|
||||
@ -301,7 +312,7 @@ task to the task switcher.
|
||||
\item The next task executes.
|
||||
\end{itemize}
|
||||
|
||||
\subsection{A Drive Command in Blocking Mode}
|
||||
\subsection{A ``Drive'' Command in Blocking Mode}
|
||||
\begin{itemize}
|
||||
\item The network reader finds data pending at one of the client ports.
|
||||
\item The network reader reads the command, splits it into single lines and
|
||||
@ -331,8 +342,8 @@ requesting the wait state. The client connection and task executing the drive co
|
||||
\item The device executor task will keep on monitoring the progress of the motor
|
||||
driving whenever the task switcher allows it to execute.
|
||||
\item In due time the device executor task will find that the motor finished
|
||||
driving. The task will then die. The clients grab of the hardware driving
|
||||
permission will be released.
|
||||
driving. The task will then finish executing. The clients grab of the
|
||||
hardware driving permission will be released.
|
||||
\item At this stage the drive command wrapper function will awake and
|
||||
continue execution. This means inspecting errors and reporting to the client
|
||||
how things worked out.
|
||||
@ -342,7 +353,7 @@ other commands.
|
||||
\item The next task executes.
|
||||
\end{itemize}
|
||||
|
||||
\subsection{A Drive Command Interrupted}
|
||||
\subsection{A ``Drive Command Interrupted}
|
||||
\begin{itemize}
|
||||
\item The network reader finds data pending at one of the client ports.
|
||||
\item The network reader reads the command, splits it into single lines and
|
||||
@ -385,7 +396,7 @@ task to the task switcher.
|
||||
\item The next task executes.
|
||||
\end{itemize}
|
||||
|
||||
\subsection{A Run Command in Non Blocking Mode}
|
||||
\subsection{A ``Run'' Command in Non Blocking Mode}
|
||||
\begin{itemize}
|
||||
\item The network reader finds data pending at one of the client ports.
|
||||
\item The network reader reads the command, splits it into single lines and
|
||||
@ -397,13 +408,13 @@ itself to the SICS interpreter.
|
||||
\item The SICS interpreter inspects the first word of the command. Using
|
||||
this key the interpreter finds the drive command wrapper function and passes
|
||||
control to that function.
|
||||
\item The run command wrapper function will check further arguments,
|
||||
\item The ``run'' command wrapper function will check further arguments,
|
||||
checks the
|
||||
clients authorisation if appropriate for the action requested. Depending on
|
||||
the checks, the wrapper function will create an error message or do its
|
||||
work.
|
||||
\item Assuming everything is OK, the motor is located in the system.
|
||||
\item The drive command wrapper function asks the device executor to run the
|
||||
\item The ``run'' command wrapper function asks the device executor to run the
|
||||
motor.
|
||||
\item The device executor verifies that nobody else is driving, then starts
|
||||
the motor and grabs hardware control. The device executor also starts a task
|
||||
@ -415,23 +426,19 @@ new commands.
|
||||
driving whenever the task switcher allows it to execute.
|
||||
\item In due time the device executor task will find that the motor finished
|
||||
driving. The task will then die silently. The clients grab of the hardware driving
|
||||
permission will be released. If errors occurred, however a they will be reported.
|
||||
\item At this stage the drive command wrapper function will awake and
|
||||
continue execution. This means inspecting errors and reporting to the client
|
||||
how things worked out.
|
||||
\item This done, control passes back through the interpreter and the connection
|
||||
task to the task switcher. The client connection is free to execute
|
||||
other commands.
|
||||
\item The next task executes.
|
||||
permission will be released. Any errors however, will be reported.
|
||||
\end{itemize}
|
||||
|
||||
All this seems to be pretty complex and time consuming. But it is the complexity needed to
|
||||
do so many things, especially the non blocking mode of operation requested
|
||||
by users. Tests have shown that the task switcher manages +900 cycles per second
|
||||
through
|
||||
the task list on a DigitalUnix machine and 50 cycles per second on a pentium 133mhz
|
||||
machine running linux. Both data were obtained with software simulation of
|
||||
hardware devices. With real SINQ hardware these numbers drop 4 cycles per
|
||||
second. This shows clearly that the communication with the hardware is the
|
||||
systems bottleneck and not the task switching scheme.
|
||||
by users. Tests have shown that the task switcher manages +900 cycles
|
||||
per second through the task list on a DigitalUnix machine and 500
|
||||
cycles per second on a pentium 2GHZ machine running linux. Both data
|
||||
were obtained with software simulation of hardware devices. With real
|
||||
SINQ hardware these numbers drop to as low as 4 cycles per second if
|
||||
the hardware is slow in responding. This shows
|
||||
clearly that the communication with the hardware is the systems
|
||||
bottleneck and not the task switching scheme.
|
||||
|
||||
|
||||
|
||||
|
@ -50,6 +50,7 @@ $\langle$pimoti {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
|
||||
\mbox{}\verb@#ifndef PIMOTOR@\\
|
||||
\mbox{}\verb@#define PIMOTOR@\\
|
||||
\mbox{}\verb@#include <motor.h>@\\
|
||||
\mbox{}\verb@@$\langle$pimoti {\footnotesize ?}$\rangle$\verb@@\\
|
||||
\mbox{}\verb@#endif@\\
|
||||
\mbox{}\verb@@\\
|
||||
|
@ -1,5 +1,6 @@
|
||||
% Copyleft (c) 1997-2000 by Mark Koennecke at PSI, Switzerland.
|
||||
%
|
||||
% major upgrade: Mark Koennecke, July 2003
|
||||
%
|
||||
%
|
||||
|
||||
@ -13,6 +14,8 @@
|
||||
\setlength{\textheight}{8.9in}
|
||||
\setlength{\textwidth}{6.2in}
|
||||
\setlength{\marginparwidth}{0.5in}
|
||||
\setlength{\parindent}{0cm}
|
||||
\setlength{\parskip}{.2cm}
|
||||
|
||||
\begin{document}
|
||||
\title{The SICS Programmers Reference}
|
||||
@ -31,7 +34,18 @@
|
||||
\include{overview}
|
||||
\include{proto}
|
||||
\include{kernelguide}
|
||||
\include{oguide}
|
||||
|
||||
|
||||
\include{command}
|
||||
%%\include{oguide}
|
||||
\include{sicsdriver}
|
||||
\include{site}
|
||||
\end{document}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,36 +1,33 @@
|
||||
\chapter{The SICS Server Client Protocol}
|
||||
This short chapter describes the command protocol between the SICS server
|
||||
and possible SICS clients. All this is very simple.
|
||||
|
||||
\section{Logging in to the SICS Server}
|
||||
In order to log in to the SICS server it needs to be known on which
|
||||
machine the server runs and at which port number the server listens for
|
||||
connection requests. Also needed is a valid username/ password pair for the
|
||||
SICS server in question. Given that the procedure for connecting to a SICS
|
||||
server requires the following steps:
|
||||
\begin{enumerate}
|
||||
\item Open a TCP/IP connection to the SICS server port at the machine
|
||||
where it is running.
|
||||
\item Immediately after opening the connection send the username/password
|
||||
pair. If everything is OK, a string OK is sent. Else the server will break
|
||||
the connection again.
|
||||
\end{enumerate}
|
||||
|
||||
\section{Sending Commands}
|
||||
After login, two means of communications exist. The communication
|
||||
protocoll is choosen through the server port the client connects too.
|
||||
The recommended way is
|
||||
to adhere to the telnet protocoll as described in RFC-854. Just a
|
||||
basic NVT (Network Virtual Terminal) with no options is
|
||||
implemented. Binary communication is not possible on a telnet port.
|
||||
|
||||
The older way of communication is to send commands directly on the
|
||||
TCP/IP port. Commands are strings terminated by a \verb+\n+. Return
|
||||
messages from the server have the same format. This scheme is
|
||||
obsolete but it has been left in because the need for a binary
|
||||
communication may arise and this would help implement such a thing.
|
||||
The SICS server actually listens for connections on two sockets, each
|
||||
implementing a different protocoll. The first type of connection
|
||||
implements the telnet protocoll. The second type uses a plain socket
|
||||
and has the advantage that binary data can be transferred.
|
||||
|
||||
\section{Connecting using Telnet}
|
||||
The SICS server implements the most primitive telnet server possible
|
||||
and does not support any of the fancy options possible with
|
||||
telnet. Using the telnet protocoll involves:
|
||||
\begin{itemize}
|
||||
\item Open a socket connection to SICS's telnet port
|
||||
\item Send a login word followed by a username and a password. The
|
||||
login word is set in SICS initialization file as the SicsOption
|
||||
TelWord.
|
||||
\item On success a welcome message is printed, otherwise SICS
|
||||
terminates the connection.
|
||||
\item Now commands can be sent, but watch for the telnet protocoll
|
||||
specification in the telnet RFC.
|
||||
\end{itemize}
|
||||
|
||||
\section{Connection using a plain Connection}
|
||||
This protocoll involves:
|
||||
\begin{itemize}
|
||||
\item Open a socket connection to SICS's plain port
|
||||
\item Send a username and a password.
|
||||
\item On success OK is printed, otherwise SICS
|
||||
terminates the connection.
|
||||
\item Now commands can be sent as strings terminated with a newline.
|
||||
\end{itemize}
|
||||
|
||||
For a list of possible commands consult the
|
||||
user documentation.
|
||||
@ -59,3 +56,8 @@ ASCII string of the form: {\bf SICSINT num} must be sent. num must be
|
||||
replaced by the number of the interrupt to issue. Again interrupt codes are
|
||||
resolved in file interrupt.h.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -76,39 +76,76 @@ recommended.
|
||||
\end{description}
|
||||
|
||||
\subsection{Building SICS}
|
||||
This document describes how to build the SICS software and where to find it.
|
||||
There are two sections: Building the SICS applications and building the Java
|
||||
clients. For both categories tarballs with all necessary files can be
|
||||
found in the /data/lnslib/src/sics directory. There are two tar files:
|
||||
sics.tar which contains the sources for the SICS server and additional C or
|
||||
F77 applications and java.tar which contains the code for the Java clients.
|
||||
A SICS distribution is best be obtained from the cvs
|
||||
repository. Access details are available on demand from Mark.Koennecke@psi.ch.
|
||||
A source distribution can be downloaded with:
|
||||
\begin{verbatim}
|
||||
cvs checkout sics
|
||||
\end{verbatim}
|
||||
This creates a new directory, sics, and copies a lot of files.
|
||||
|
||||
\subsubsection{Building the SICS Server and Applications}
|
||||
The first step is to untar the sics.tar file. As a result a directory sics
|
||||
with several subdirectories will be created. These subdirectories are:
|
||||
\subsubsection{SICS Directory Layout}
|
||||
Underneath the sics directory there are further sub directories:
|
||||
\begin{description}
|
||||
\item[hardsup] contains David Madens and other hardware drivers.
|
||||
\item[motor] contains the unix version of David Madens el734\_test program.
|
||||
\item[doc/programmer]holds programming documentation for SICS.
|
||||
\item[doc/user] The html sources for the user documentation. Also everything
|
||||
necessary for creating the printed documentation.
|
||||
\item[bin] Holds the final binary files.
|
||||
\item[tcl] Some Tcl helper code.
|
||||
\item[doc/manager]The SICS managers documentation.
|
||||
\item[difrac] The DIFRAC four circle diffraction subsystem.
|
||||
\end{description}
|
||||
For most programs makefiles are provided.
|
||||
Makefiles may need a little editing to correct the location of libraries.
|
||||
All necessary headers should be available in /data/lnslib/include and the
|
||||
libraries in /data/lnslib/lib.
|
||||
Building things within this hierarchy basically require to steps:
|
||||
\begin{enumerate}
|
||||
\item cd into the hardsup and difrac directories and type make in
|
||||
each. This builds required libraries for linking other applications.
|
||||
\item cd into the directory of the program you wish to compile and type make.
|
||||
For instance for building the SICServer, move into the main sics directory and
|
||||
type make.
|
||||
\end{enumerate}
|
||||
\item[doc] Contains documentation. Further subdirectories to doc:
|
||||
\begin{description}
|
||||
\item[user] User documentation.
|
||||
\item[manager] Manager documentation
|
||||
\item[programmer] Reference documentation for SICS programmers.
|
||||
\end{description}
|
||||
\item[matrix]A package for matrix manipulations
|
||||
\item[tcl]Tcl scripts
|
||||
\item[dummy]An example directory for a new site
|
||||
\item[psi]PSI specific parts of SICS
|
||||
\begin{description}
|
||||
\item[hardsup] Hardware support routines
|
||||
\item[sinqhm]The vxWorks histogram memory software
|
||||
\item[tecs]The tecs environment control software
|
||||
\item[motor]Utilities for the motor controller
|
||||
\item[utils]various utilities
|
||||
\begin{description}
|
||||
\item[check]The Tcl syntax checker for SICS
|
||||
\end{description}
|
||||
\end{description}
|
||||
\end{description}
|
||||
The sics directory is meant to contain the generic parts of
|
||||
SICS. Then there are site specific directories (dummy, psi) which hold
|
||||
code special for particular instruments or hardware. The selection for
|
||||
which configuration SICS is being compiled is made in the makefile, by
|
||||
linking against the appropriate site specific libraries.
|
||||
|
||||
\subsubsection{SICS Makefiles}
|
||||
The SICS makefile system is not perfect but is far better then
|
||||
compiling the whole stuff manually. There are various makefiles:
|
||||
\begin{description}
|
||||
\item[linux\_def, alpha\_def] contains the path to the HDF libraries,
|
||||
the flags necessary to run sub makefiles in sub directories etc. This
|
||||
is included by all other makefiles.
|
||||
\item[make\_gen] and children contains most of the makefile content and
|
||||
is included by the other makefiles.
|
||||
\item[makefile\_linux, makefile\_alpha] are makefiles for their
|
||||
respective platforms.
|
||||
\end{description}
|
||||
Some editing of makefiles will always be necessary. The path to the
|
||||
HDF libraries has usually to be adapted in the \_def files. If there
|
||||
is a different platfrom a new makefile has to be cloned from the
|
||||
existing ones. In order to support a new site a new make\_gen and a new
|
||||
makefile are have to be cloned. This system is similar in the
|
||||
subdirectories to the SICS directory. Once this has been setup typing:
|
||||
\begin{verbatim}
|
||||
make -f makefile_alpha clean
|
||||
\end{verbatim}
|
||||
will clean all object files etc. and
|
||||
\begin{verbatim}
|
||||
make -f makefile_alpha
|
||||
\end{verbatim}
|
||||
will build everything. May be you need to replace alpha by linux on
|
||||
some platforms. Please note, that I have been to lazy to generate
|
||||
dependencies for all the SICS files. This means that if you make
|
||||
changes to the major SICS header files (especially the kernel files)
|
||||
it is better do recompile everything. Otherwise you might find
|
||||
yourself chasing obscure bugs.
|
||||
|
||||
|
||||
\subsubsection{Building Java Clients}
|
||||
Again the first step is the untaring of tha java.tar file. This creates a
|
||||
@ -134,6 +171,12 @@ Again the first step is the untaring of tha java.tar file. This creates a
|
||||
\item[spread] Another layout manager package.
|
||||
\item[topsi] The topsi and general scan status display.
|
||||
\item[amor] The AMOR user interface program.
|
||||
\item[tas] The Triple Axis user interface program.
|
||||
\item[trics] The TRICS user interface program.
|
||||
\item[JQF] A state machine framework used for implementing a new I/O
|
||||
system.
|
||||
\item[psi] The start of a new hierarchy of SICS applications and
|
||||
library classes.
|
||||
\end{description}
|
||||
Furthermore there are some Java source file in the main directory together
|
||||
with some htm files and makefiles. For each of the Java clients a makefile
|
||||
@ -149,11 +192,11 @@ Furthermore there are some Java source file in the main directory together
|
||||
\item[Jar-File] make -f make.powder jar
|
||||
\end{description}
|
||||
|
||||
|
||||
\section{Kernel Objects and Modules}
|
||||
This section describes the modules defining the SICS kernel.
|
||||
\include{task}
|
||||
\include{nserver}
|
||||
\include{site}
|
||||
\include{ini}
|
||||
\include{passwd}
|
||||
\include{network}
|
||||
@ -171,6 +214,9 @@ This section describes the modules defining the SICS kernel.
|
||||
\include{interrupt}
|
||||
\include{ofac}
|
||||
\include{servlog}
|
||||
\include{help}
|
||||
\include{Busy}
|
||||
\include{hmcontrol}
|
||||
\subsection{The commandlog}
|
||||
This is yet another logging facility of SICS. The idea is that all I/O
|
||||
going to connections with user or manager level rights is logged.
|
||||
@ -187,6 +233,7 @@ writing to it. The rest is implemented as file statics in commandlog.c.
|
||||
This section describes the SICS objects implementing commands and objects
|
||||
common to all SICS instruments.
|
||||
\include{scan}
|
||||
\include{userscan}
|
||||
\include{center}
|
||||
\include{danu}
|
||||
\include{drive}
|
||||
@ -202,6 +249,13 @@ common to all SICS instruments.
|
||||
\include{token}
|
||||
\include{udpquieck}
|
||||
\include{xytable}
|
||||
\include{lin2ang}
|
||||
\include{lomax}
|
||||
\include{nxscript}
|
||||
\include{nxupdate}
|
||||
\include{sicsdata}
|
||||
\include{simsync}
|
||||
\include{anticollider}
|
||||
|
||||
\section{SICS Hardware Objects}
|
||||
This section deals with objects and modules representing instrument
|
||||
@ -228,24 +282,31 @@ right as utility functions. However, the preferred and supported way of
|
||||
accessing SICS hardware objects is through the interface functions.
|
||||
|
||||
\include{velo}
|
||||
\include{velodorn}
|
||||
\include{evcontroller}
|
||||
\include{itc4}
|
||||
\include{bruker}
|
||||
\include{tclev}
|
||||
\include{evdrivers}
|
||||
|
||||
\include{motor}
|
||||
\include{pimotor}
|
||||
|
||||
\include{counter}
|
||||
\include{hmdata}
|
||||
\include{histogram}
|
||||
\include{sinqhmdriv}
|
||||
\include{histsim}
|
||||
\include{choco}
|
||||
\include{switchedmotor}
|
||||
\include{tcldriveable}
|
||||
\include{rs232controller}
|
||||
\include{gpib}
|
||||
|
||||
\section{PSI Specific Hardware}
|
||||
\include{velodorn}
|
||||
\include{itc4}
|
||||
\include{bruker}
|
||||
\include{pimotor}
|
||||
\include{sinqhmdriv}
|
||||
\include{serial}
|
||||
\include{serialwait}
|
||||
\include{sps}
|
||||
\include{frame}
|
||||
\include{ecb}
|
||||
|
||||
\section{Powder Diffraction Specific Objects}
|
||||
\include{dmc}
|
||||
@ -275,6 +336,9 @@ The files nxsans.h and nxsans.c implement the NeXus writing functions for SANS.
|
||||
\include{tricsnex}
|
||||
\include{difrac}
|
||||
|
||||
\section{Triple Axis Specific Code}
|
||||
\include{tas}
|
||||
|
||||
\section{Helper Objects}
|
||||
This section describes helper objects which implement useful data
|
||||
structures or utilities.
|
||||
|
@ -79,6 +79,7 @@ $\langle$scandata {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@ (pScanData self,@\\
|
||||
\mbox{}\verb@ int iP);@\\
|
||||
\mbox{}\verb@ long lPos;@\\
|
||||
\mbox{}\verb@ int posSoft;@\\
|
||||
\mbox{}\verb@ void *pCounterData;@\\
|
||||
\mbox{}\verb@ char pCounterName[512];@\\
|
||||
\mbox{}\verb@ int iChannel;@\\
|
||||
@ -158,6 +159,8 @@ This function together with ScanDrive and the data writing functions allow for
|
||||
\item[CollectScanData] reads all the scan data into the scan's data
|
||||
structures after any scan point. Overload this if a different storage
|
||||
scheme is required especiallay for polarising scans.
|
||||
\item[posSoft] is a flag which is true if scan variable are stored with
|
||||
soft position, i.e. with zeropoints applied.
|
||||
\item[pCounterData] is a pointer to a counter structure. This defines the
|
||||
counter to use and is initialized at creation of the scan data structure.
|
||||
\item[pCountername] is the name of the counter used.
|
||||
@ -210,6 +213,7 @@ $\langle$scaninter {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@ char *pName, int iLength);@\\
|
||||
\mbox{}\verb@ int GetScanVarStep(pScanData self, int iWhich, @\\
|
||||
\mbox{}\verb@ float *fStep);@\\
|
||||
\mbox{}\verb@ int isScanVarSoft(pScanData self);@\\
|
||||
\mbox{}\verb@ int GetScanMonitor(pScanData self, int iWhich, @\\
|
||||
\mbox{}\verb@ long *lData, int iDataLen);@\\
|
||||
\mbox{}\verb@ int GetScanNP(pScanData self);@\\
|
||||
|
@ -46,7 +46,7 @@ Just one function is exported:
|
||||
\mbox{}\verb@#ifndef SERIALSICSWAIT@\\
|
||||
\mbox{}\verb@#define SERIALSICSWAIT@\\
|
||||
\mbox{}\verb@#include "sics.h"@\\
|
||||
\mbox{}\verb@#include "hardsup/serialsinq.h"@\\
|
||||
\mbox{}\verb@#include "psi/hardsup/serialsinq.h"@\\
|
||||
\mbox{}\verb@ int SerialSicsExecute(void **pData, char *pCommand, char *pReply, @\\
|
||||
\mbox{}\verb@ int iBufLen);@\\
|
||||
\mbox{}\verb@@\\
|
||||
|
640
doc/programmer/sicsdriver.tex
Normal file
640
doc/programmer/sicsdriver.tex
Normal file
@ -0,0 +1,640 @@
|
||||
\chapter{Writing SICS Device Drivers}
|
||||
This chapter deals with writing new hardware drivers for SICS. SICS
|
||||
hardware has a dual identity: Towards upper level code SICS hardware
|
||||
is represented by the logical hardware object. All the low level
|
||||
detail is handled in the hardware driver. The point of this is that
|
||||
upper level code does not need to know which type of hardware device
|
||||
is being accessed. Experience shows that this scheme covers most usage
|
||||
cases for a given hardware device. However, there were always
|
||||
exceptions mostly in order to realize special configurations. Such
|
||||
exceptions can be dealt with through special macros which implement
|
||||
commands which do
|
||||
special configuration tasks. In order to be able to write such scripts
|
||||
it is feasible to organize hardware access into three layers:
|
||||
\begin{itemize}
|
||||
\item A communication layer. This layer allows for sending commands
|
||||
and reading data along a given bus.
|
||||
\item A controller layer. If a device or several share a controller
|
||||
make the controller visible within the system. Allow for sending
|
||||
suitable commands to it.
|
||||
\item The actual SICS driver.
|
||||
\end{itemize}
|
||||
This organisation allows scripts to directly talk to devices through
|
||||
either the controller or the communication layer. If something is
|
||||
missing in the general driver interface it is usually easier to add
|
||||
some code at controller or communications level, rather then change
|
||||
all drivers present in the system.
|
||||
|
||||
All drivers use a common pattern for error handling. Please read the
|
||||
section on the motor driver where this pattern is explained in more
|
||||
detail. The same pattern is applied in most drivers.
|
||||
|
||||
Please be aware that the hardware drivers have a significant impact on
|
||||
SICS's overall performance. Most of the time SICS will be sitting
|
||||
there and wait for a counter or a motor to finish. And often the
|
||||
devices controlling such things respond pretty slow. The most often
|
||||
called function is the status check function of the driver. It is
|
||||
advisable to optimize this is good as possible. Suggestions for this
|
||||
include:
|
||||
\begin{itemize}
|
||||
\item Reduce the amount of data to be read from the controller as much
|
||||
as possible.
|
||||
\item Make the status function a state machine: in the first state a
|
||||
status request command is sent and the second state is entered. In teh
|
||||
second state, the function checks if data is available on the
|
||||
communication port and process if this is so, else it returns the
|
||||
appropriate busy code.
|
||||
\end{itemize}
|
||||
|
||||
This section describes the actual drivers. How these drivers are
|
||||
integrated into SICS is described in the chapter on the site data
|
||||
structure (see \ref{site}).
|
||||
|
||||
|
||||
\section{The Motor Driver}
|
||||
A motor driver again is represented by an interface encapsulated in a
|
||||
data structure. Polymorphy is achieved in two ways:
|
||||
\begin{itemize}
|
||||
\item Through the functions you have to define for your motor and to
|
||||
assign to the function pointers in the motor driver data structure.
|
||||
\item For the data structure, polymorphy is achieved through
|
||||
overlay. This means, if you define your own motor driver data
|
||||
structure the first fields up to KillPrivate MUST be the same as
|
||||
defined in the MotorDriver structure defined below. You MUST append
|
||||
your own fields below KillPrivate.
|
||||
\end{itemize}
|
||||
|
||||
This is the motor driver data structure which has to be implemented:
|
||||
\begin{verbatim}
|
||||
typedef struct __AbstractMoDriv {
|
||||
/* 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);
|
||||
} MotorDriver;
|
||||
\end{verbatim}
|
||||
In order not to have to repeat trivial things all the time two general
|
||||
things must be stated:
|
||||
\begin{itemize}
|
||||
\item The pointer self is always a pointer to the motor driver data
|
||||
structure.
|
||||
\item Functions return 1 on success or 0 on failure if not stated otherwise.
|
||||
\end{itemize}
|
||||
The elements of this data structure are:
|
||||
\begin{description}
|
||||
\item[fUpper,fLower] These are the motors hardware limits. These
|
||||
values are supposed to be identical to the positions of the limit
|
||||
switches on the real thing. Read them from the motor or initialize
|
||||
them from parameters when initializing the motor driver.
|
||||
\item[GetPosition] reads the position of the motor and puts the result
|
||||
into fPos. This ought to be the position from the motor
|
||||
controller. Software zeros are applied later by code in
|
||||
motor.c. GetPosition returns either OKOK when the request succeeded
|
||||
or HWFault on failure.
|
||||
\item[RunTo] Starts the motor to run towards the new position
|
||||
fNewVal. fNewVal must be a value valid for the controller. Software
|
||||
zero points have already been taken account of by code in
|
||||
motor.c. This function shall NOT wait for the completion of the
|
||||
driving operation. RunTo returns either OKOK when the request succeeded
|
||||
or HWFault on failure.
|
||||
\item[GetStatus] This function is called repeatedly by upper level
|
||||
code to poll for the progress of the driving operation. Possible
|
||||
return values of this function are:
|
||||
\begin{description}
|
||||
\item[HWFault] If there is a fault in the hardware or the status
|
||||
cannot be read.
|
||||
\item[HWPosFault] The motor is still alive but the controller was
|
||||
unable to position the motor.
|
||||
\item[HWBusy] The motor is still driving.
|
||||
\item[HWWarn] There is a warning from the controller.
|
||||
\item[HWIdle] The motor has finished driving and is idle.
|
||||
\end{description}
|
||||
\item[GetError] retrieves information about an error which occurred on
|
||||
the motor. An integer error code is returned in iCode. Up to iBufLen
|
||||
characters of descriptive error information is copied into
|
||||
buffer. This information is printed as error message by upper level
|
||||
code.
|
||||
\item[TryAndFixIt] Given an error code in iError, try to repair the
|
||||
problem as far as this is possible in software. iError should be an
|
||||
error code as returned by GetError in iCode. This function has the
|
||||
following return codes:
|
||||
\begin{description}
|
||||
\item[MOTREDO] Problem fixed, try to redo the last the operation.
|
||||
\item[MOTFAIL] The problem cannot be fixed in software.
|
||||
\end{description}
|
||||
The parameter fNew is the target position of the motor.
|
||||
\item[Halt] stops the motor immediately.
|
||||
\item[GetDriverPar] copies the value of the motor driver parameter
|
||||
name into value, if such a parameter exists.
|
||||
\item[SetDriverPar] sets the motor driver parameter name to
|
||||
newValue. Report errors to pCon.
|
||||
\item[ListDriverPar] write the names and values of all driver
|
||||
parameters to the client connection pCon.
|
||||
\item[KillPrivate] releases any memory possibly allocated for private
|
||||
fields in the motor data structure.
|
||||
\end{description}
|
||||
|
||||
In order to understand the relationship between GetError and
|
||||
TryAndFixIt it helps to look at the way how errors are handled by
|
||||
upper level code in motor.c: If an error in any function occurs,
|
||||
GetError gets called. An error message is printed. Then TryAndFixIt is
|
||||
called with the error code returned in iCode as a parameter. If
|
||||
TryAndFixIt returns MOTFAIL, the code gives up. If TryAndFixIt
|
||||
returns MOTREDO, the failed operation is retried. At max 3 retries are
|
||||
performed. If the operation does not succeed after three
|
||||
retries, a motor failure is reported.
|
||||
|
||||
The GetDriverPar, SetDriverPar and ListDriverPar functions implement
|
||||
some support for driver private configuration parameters. Such
|
||||
parameters are meant to be configured from the instrument
|
||||
initialization file. Currently there is no support to include these
|
||||
parameters into the status file. If there are
|
||||
no such parameters have these functions do nothing and return 1.
|
||||
|
||||
\section{The Counter Driver}
|
||||
A counter driver is a driver for some box which allows to count for a
|
||||
preset time or monitor and manages single counters and monitors. Such
|
||||
a driver is represented by a data structure:
|
||||
\begin{verbatim}
|
||||
typedef struct __COUNTER {
|
||||
/* variables */
|
||||
char *name;
|
||||
char *type;
|
||||
CounterMode eMode;
|
||||
float fPreset;
|
||||
float fLastCurrent;
|
||||
float fTime;
|
||||
int iNoOfMonitors;
|
||||
long lCounts[MAXCOUNT];
|
||||
int iPause;
|
||||
int iErrorCode;
|
||||
/* functions */
|
||||
int (*GetStatus)(struct __COUNTER *self, float *fControl);
|
||||
int (*Start)(struct __COUNTER *self);
|
||||
int (*Pause)(struct __COUNTER *self);
|
||||
int (*Continue)(struct __COUNTER *self);
|
||||
int (*Halt)(struct __COUNTER *self);
|
||||
int (*ReadValues)(struct __COUNTER *self);
|
||||
int (*GetError)(struct __COUNTER *self, int *iCode,
|
||||
char *error, int iErrLen);
|
||||
int (*TryAndFixIt)(struct __COUNTER *self, int iCode);
|
||||
int (*Set)(struct __COUNTER *self,char *name,
|
||||
int iCter, float fVal);
|
||||
int (*Get)(struct __COUNTER *self,char *name,
|
||||
int iCter, float *fVal);
|
||||
int (*Send)(struct __COUNTER *self, char *pText,
|
||||
char *pReply, int iReplyLen);
|
||||
void (*KillPrivate)(struct __COUNTER *self);
|
||||
void *pData; /* counter specific data goes here, ONLY for
|
||||
internal driver use!
|
||||
*/
|
||||
} CounterDriver, *pCounterDriver;
|
||||
\end{verbatim}
|
||||
Polymorphy is achieved through the function pointers. Differences in
|
||||
the data structure for different counter boxes are accounted for
|
||||
through the pData pointer. This is meant to be initialized by the
|
||||
actual counter driver to a private data structure which holds data
|
||||
relevant to this particular counter. All functions take a pointer to
|
||||
this counter driver structure as parameter self. If not stated
|
||||
otherwise functions return 1 on success and 0 on failure. The fields:
|
||||
\begin{description}
|
||||
\item[name] The counter name in SICS
|
||||
\item[type] The driver type.
|
||||
\item[eMode] The counter mode. Possible values eTimer for preset timer
|
||||
and eMonitor for preset monitor operation. This mode will be set by
|
||||
upper level code.
|
||||
\item[fPreset] The preset for either timer or monitor.
|
||||
\item[fLastCurrent] the last known value for the control variable
|
||||
during counting. Gets updated in GetStatus while counting and is used
|
||||
for reporting count status.
|
||||
\item[fTime] The time the last counting operation took. This is a time
|
||||
read from the counter box. This could be different from elapsed time
|
||||
because the count may have paused for instance because the beam was
|
||||
low.
|
||||
\item[iNoOfMonitors] is the number of monitors and counters this
|
||||
counter box supports.
|
||||
\item[lCounts] An array for storing the values of counters and
|
||||
monitors after counting. The PSI EL7373 counter box allows to read
|
||||
values only once after counting finished. This is why the values had to be
|
||||
cached in lCounts.
|
||||
\item[iPause] A flag which becomes true if the counter has been
|
||||
paused.
|
||||
\item[iErrorCode] A private variable holding error codes.
|
||||
\item[GetStatus] This function is called while upper
|
||||
level code polls for the counter to finish. It has to return the
|
||||
status of the counting operation and update the current value of the
|
||||
control variable in fControl. Possible return values are:
|
||||
\begin{description}
|
||||
\item[HWBusy] when counting.
|
||||
\item[HWIdle] when finished counting or idle.
|
||||
\item[HWNoBeam] when counting is halted due to lack of beam.
|
||||
\item[HWPause] if counting is paused.
|
||||
\item[HWFault] if the status cannot be obtained.
|
||||
\end{description}
|
||||
\item[Start] start counting in the count mode and with the preset
|
||||
previously confugured. Do NOT wait for counting to finish!
|
||||
\item[Pause] pause counting.
|
||||
\item[Continue] continue a paused counting operation.
|
||||
\item[Halt] stop counting.
|
||||
\item[ReadValues] read all counters and monitors into lCounts.
|
||||
\item[GetError] retrieves information about an error which occurred on
|
||||
the counter. An integer error code is returned in iCode. Up to iErrLen
|
||||
characters of descriptive error information is copied into
|
||||
error. This information is printed as error message by upper level
|
||||
code.
|
||||
\item[TryAndFixIt] Given an error code in iCode, try to repair the
|
||||
problem as far as this is possible in software. iError should be an
|
||||
error code as returned by GetError in iCode. This function has the
|
||||
following return codes:
|
||||
\begin{description}
|
||||
\item[COREDO] Problem fixed, try to redo the last the operation.
|
||||
\item[COTERM] The problem cannot be fixed in software.
|
||||
\end{description}
|
||||
\item[Set] set parameter name associated with counter iCter to fVal.
|
||||
\item[Get] return in fVal the value of parameter name associated with
|
||||
iCter. These two functions allow to set counter driver parameters.
|
||||
\item[Send] send pText to the counter controller and return iReplyLen
|
||||
characters of response from the counter controller in pReply. This is
|
||||
a bypass to set controller parameters manually.
|
||||
\item[KillPrivate] properly delete counter driver private data
|
||||
pData. Also close any connections to the hardware.
|
||||
\end{description}
|
||||
|
||||
|
||||
|
||||
\section{Environment Controller Driver}
|
||||
This is the driver for all sample environment controllers, be it
|
||||
temperature controllers, magnet controllers etc. An environment
|
||||
controller driver is represented by the following data structure:
|
||||
\begin{verbatim}
|
||||
typedef struct __EVDriver {
|
||||
int (*SetValue)(pEVDriver self, float fNew);
|
||||
int (*GetValue)(pEVDriver self, float *fPos);
|
||||
int (*GetValues)(pEVDriver self, float *fTarget,
|
||||
float *fPos, float *fDelta);
|
||||
int (*Send)(pEVDriver self, char *pCommand,
|
||||
char *pReplyBuffer, int iReplBufLen);
|
||||
int (*GetError)(pEVDriver self, int *iCode,
|
||||
char *pError, int iErrLen);
|
||||
int (*TryFixIt)(pEVDriver self, int iCode);
|
||||
int (*Init)(pEVDriver self);
|
||||
int (*Close)(pEVDriver self);
|
||||
void *pPrivate;
|
||||
void (*KillPrivate)(void *pData);
|
||||
} EVDriver;
|
||||
\end{verbatim}
|
||||
All functions take a pointer to their own data structure as the first
|
||||
argument (self). They return 1 on success or 0 on failure if not
|
||||
stated otherwise.
|
||||
The fields:
|
||||
\begin{description}
|
||||
\item[SetValue] set fNew as the new set value for the device. It
|
||||
should start heating or cooling or whatever then.
|
||||
\item[GetValue] reads the current value from the device into *fPos.
|
||||
\item[GetValues] is used when the readout sensor and the control
|
||||
sensor are very different. This function then reads the current set
|
||||
value, the current position and calculates the difference between
|
||||
these value into fDelta. This function does not need to be defined, it
|
||||
is replaced by a standard one based on GetValue if not present.
|
||||
\item[Send] send a command in pCommand to the controller and returns
|
||||
at max iReplBuflen bytes of result in pReplyBuffer. This is breakout
|
||||
which allows to send arbitray data to the controller.
|
||||
\item[GetError] retrieves information about an error which occurred on
|
||||
the device. An integer error code is returned in iCode. Up to iErrLen
|
||||
characters of descriptive error information is copied into
|
||||
pError. This information is printed as error message by upper level
|
||||
code.
|
||||
\item[TryAndFixIt] Given an error code in iError, try to repair the
|
||||
problem as far as this is possible in software. iError should be an
|
||||
error code as returned by GetError in iCode. This function has the
|
||||
following return codes:
|
||||
\begin{description}
|
||||
\item[DEVREDO] Problem fixed, try to redo the last the operation.
|
||||
\item[DEVFAULT] The problem cannot be fixed in software.
|
||||
\end{description}
|
||||
\item[Init] initializes a connection to a controller and puts the
|
||||
thing into the right mode.
|
||||
\item[Close] closes a connection to a controller.
|
||||
\item[pPrivate] A pointer to a driver specific data structure which
|
||||
can be filled with meaning by instances of drivers.
|
||||
\item[KillPrivate] a function which has to release all memory associated
|
||||
with pPrivate.
|
||||
\end{description}
|
||||
|
||||
|
||||
\section{Histogram Memory Drivers}
|
||||
Histogram memories are devices in which neutron events for area
|
||||
detector or time--of--flight detectors are assigned to their correct
|
||||
bins. Then these usually large data sets have to be transferred to
|
||||
SICS for further processing. In SICS, histogram memories are also able
|
||||
to do count control, i.e. count until a preset monitor or time is
|
||||
reached. This gives a slightly complicated driver interface. If this
|
||||
assumption does not hold there are two options:
|
||||
\begin{itemize}
|
||||
\item Pass in a counter as a configuration parameter and chain count
|
||||
control to this counter.
|
||||
\item Make the count control functions dummies and let HMControl do
|
||||
the rest. See hmcontrol.h and .c for details.
|
||||
\end{itemize}
|
||||
|
||||
Though never used so far the histogram memory driver has support for
|
||||
multiple banks of detectors being controlled by one histogram memory.
|
||||
|
||||
A histogram memory driver is implemented by filling in the data
|
||||
structure given below:
|
||||
\begin{verbatim}
|
||||
typedef struct __HistDriver {
|
||||
pHMdata data;
|
||||
/* counting operations data */
|
||||
CounterMode eCount;
|
||||
float fCountPreset;
|
||||
/* status flags */
|
||||
int iReconfig;
|
||||
int iUpdate;
|
||||
/* interface functions */
|
||||
int (*Configure)(pHistDriver self,
|
||||
SConnection *pCon,
|
||||
pStringDict pOpt,
|
||||
SicsInterp *pSics);
|
||||
int (*Start)(pHistDriver self,
|
||||
SConnection *pCon);
|
||||
int (*Halt)(pHistDriver self);
|
||||
int (*GetCountStatus)(pHistDriver self,
|
||||
SConnection *pCon);
|
||||
int (*GetError)(pHistDriver self,
|
||||
int *iCode,
|
||||
char *perror,
|
||||
int iErrlen);
|
||||
int (*TryAndFixIt)(pHistDriver self,
|
||||
int iCode);
|
||||
int (*GetData)(pHistDriver self,
|
||||
SConnection *pCon);
|
||||
int (*GetHistogram)(pHistDriver self,
|
||||
SConnection *pCon,
|
||||
int i,
|
||||
int iStart, int iEnd,
|
||||
HistInt *pData);
|
||||
|
||||
int (*SetHistogram)(pHistDriver self,
|
||||
SConnection *pCon,
|
||||
int i,
|
||||
int iStart, int iEnd,
|
||||
HistInt *pData);
|
||||
long (*GetMonitor)(pHistDriver self,
|
||||
int i,
|
||||
SConnection *pCon);
|
||||
float (*GetTime)(pHistDriver self,
|
||||
SConnection *pCon);
|
||||
int (*Preset)(pHistDriver self,
|
||||
SConnection *pCon,
|
||||
HistInt iVal);
|
||||
int (*Pause)(pHistDriver self,
|
||||
SConnection *pCon);
|
||||
int (*Continue)(pHistDriver self,
|
||||
SConnection *pCon);
|
||||
int (*FreePrivate)(pHistDriver self);
|
||||
void *pPriv;
|
||||
} HistDriver;
|
||||
\end{verbatim}
|
||||
All functions take a pointer to their driver data structure as an
|
||||
argument. If not stated otherwise they return 1 on success, 0 on failure.
|
||||
\begin{description}
|
||||
\item[data] Is a pointer to an HMdata object which does all the
|
||||
dimension handling, buffers histogram memory content, deals with time
|
||||
binnings etc.
|
||||
\item[eCount] A counter mode, as defined above for counters.
|
||||
\item[fCountPreset] A preset for either monitor or time.
|
||||
\item[iReconfig] A flag which will be set by upper level code when a
|
||||
reconfiguration is necessary.
|
||||
\item[iUpdate] a flag which invalidates the buffered histogram. Should
|
||||
be set 1 in each call to GetCountStatus.
|
||||
\item[Configure] configures the histogram memory to the specifications
|
||||
given in the fields of the HMdriver structure. Further driver specific
|
||||
information can be read from the options dictionary passed
|
||||
in. Configuration options are stored in the string dictionary
|
||||
pOpt. This dictionary holds name value pairs which must be interpreted
|
||||
by this routine. Then configure has to configure the histogram memory
|
||||
according to the options passed in.
|
||||
\item[Start] starts a counting operation according to the current
|
||||
settings of the counter mode parameters.
|
||||
\item[Halt] implements an emergency stop of a counting operation.
|
||||
\item[GetCountStatus] serves to monitor the status of the counting
|
||||
operation. Possible return values to this call are:
|
||||
\begin{itemize}
|
||||
\item HWBUSY when still counting.
|
||||
\item HWNoBeam when the monitor is to low.
|
||||
\item HWIDLE or OKOK when nothing is going on.
|
||||
\item HWFault when there is an error on the device.
|
||||
\end{itemize}
|
||||
\item[GetError] will be called whenever an error has been detected on
|
||||
the device. The task is to put an internal error code into the iCode
|
||||
parameter. The string parameter perror will be filled with a text description
|
||||
of the error. But maximum iErrlen characters will be transferred to the error
|
||||
string in order to protect against memory corruption. Therefore iLen must be
|
||||
the maximum field length of error.
|
||||
\item[TryAndFixIt] is the next function called in case of an error on
|
||||
the device. Its second parameter is the internal code obtained in the ICode
|
||||
parameter of the call to GetError. The task of this function is to examine
|
||||
the error code and do whatever is possible in software to fix the problem.
|
||||
TryAndFixIt returns one of the following values:
|
||||
\begin{itemize}
|
||||
\item COREDO when the error could be fixed, but the upper level code will
|
||||
need to rerun the command which failed.
|
||||
\item COTERM when the software is unable to fix the problem and a real
|
||||
mechanic with a hammer is needed (or somebody able to reboot!).
|
||||
\item MOTOK when the error was fixed and nor further action is necessary.
|
||||
\end{itemize}
|
||||
\item[GetData] transfers all the data collected in the HM into the
|
||||
host computers memory buffer.
|
||||
\item[GetHistogram] copies data between iStart and iEnd from histogram
|
||||
bank i into the data space pData. Please make sure that pData is big
|
||||
enough to hold the data.
|
||||
\item[SetHistogram] presets the histogram bank i with the data
|
||||
given in lData. A conversion from different binwidth
|
||||
to long is performed as well. iStart and iStop define the start and end of
|
||||
the stretch of histogram to replace.
|
||||
\item[GetMonitor] returns the counts in the monitor i. GetMonitor returns a
|
||||
negative value on error. The error will have been printed to pCon.
|
||||
\item[GetTime] returns the actual counting time.
|
||||
\item[Preset] initializes the histogram memory to the value given by
|
||||
iVal.
|
||||
\item[Pause] pauses data collection.
|
||||
\item[Continue] continues a paused data collection.
|
||||
\item[FreePrivate] will be called automatically by DeleteHistDriver and
|
||||
has the task to remove the private data installed by implementations of an
|
||||
actual histogram memory driver.
|
||||
\item[pPriv] is a pointer which a actual histogram memory driver may
|
||||
use to hold a driver specific data structure.
|
||||
\end{description}
|
||||
|
||||
|
||||
\section{Velocity Selector Driver}
|
||||
This is a driver for velocity selectors as used at SANS machines. A
|
||||
velocity selector is a kind of turbine which selects wavelength
|
||||
through rotation speed. Though it rotates fast it is not a chopper,
|
||||
which are handled in SICS through the general controller driver
|
||||
described below. The velocity selector driver data structure includes:
|
||||
\begin{verbatim}
|
||||
typedef struct __VelSelDriv {
|
||||
void *pPrivate;
|
||||
void (*DeletePrivate)(void *pData);
|
||||
float fTolerance;
|
||||
int (*Halt)(pVelSelDriv self);
|
||||
int (*GetError)(pVelSelDriv self,
|
||||
int *iCode, char *pError,
|
||||
int iErrlen);
|
||||
int (*TryAndFixIt)(pVelSelDriv self,
|
||||
int iCode);
|
||||
int (*GetRotation)(pVelSelDriv self,
|
||||
float *fRot);
|
||||
int (*SetRotation)(pVelSelDriv self,
|
||||
float fRot);
|
||||
int (*GetStatus)(pVelSelDriv self,
|
||||
int *iCall, float *fCur);
|
||||
int (*GetDriverText)(pVelSelDriv self,
|
||||
char *pText,
|
||||
int iTextLen);
|
||||
int (*GetLossCurrent)(pVelSelDriv self,
|
||||
float *fLoss);
|
||||
int (*Init)(pVelSelDriv self,
|
||||
SConnection *pCon);
|
||||
}VelSelDriv;
|
||||
\end{verbatim}
|
||||
All functions take a pointer to their driver data structure as an
|
||||
argument. If not stated otherwise they return 1 on success, 0 on failure.
|
||||
The fields:
|
||||
\begin{description}
|
||||
\item[pPrivate] a pointer to a driver private data structure.
|
||||
\item[DeletePrivate] a function which releases any memory associated
|
||||
with pPrivate. DeletePrivate is called with a pointer to the driver
|
||||
private data pPrivate as argument.
|
||||
\item[fTolerance] This driver assumes it has reached the target speed
|
||||
if the speed difference target speed - read speed is less then this
|
||||
tolerance value for four consecutive times.
|
||||
\item[Halt] stops the velocity selector.
|
||||
\item[GetError] returns an error code in *iCode and iErrlen
|
||||
bytes of textual description of the last error on the velocity
|
||||
selector in pError.
|
||||
\item[TryAndFixIt] tries to fix the error defined through iCode. iCode
|
||||
should be the value as returned in *iCode in GetError. This function
|
||||
returns:
|
||||
\begin{description}
|
||||
\item[VELOREDO] redo last operation, error fixed.
|
||||
\item[VELOFAIL] cannot fix the error from software.
|
||||
\end{description}
|
||||
\item[GetRotation] reads the rotation speed into *fRot.
|
||||
\item[SetRotation] sets a new rotation speed fRot for the selector. Do
|
||||
NOT wait until finished.
|
||||
\item[GetStatus] is used to poll for the status of the last driving
|
||||
operation. It returns:
|
||||
\begin{description}
|
||||
\item[VSACCEL] when the velocity selector is accelerating.
|
||||
\item[VSFAIL] if the status cannot be read.
|
||||
\item[VSOK] when the velocity seelctor has reached its target speed.
|
||||
\end{description}
|
||||
The current rotation speed is returned in *fCur. iCall is a value
|
||||
which indicates in which state the selector is:
|
||||
\begin{description}
|
||||
\item[ROTMOVE] normal running.
|
||||
\item[ROTSTART] starting the velocity selector. The Dornier velocity
|
||||
selector have a certain minimum speed. If they are standing they have
|
||||
to be started first.
|
||||
\end{description}
|
||||
\item[GetDriverText] returns iTextLen bytes of additional status
|
||||
information in pText. This is a list name: value pairs separated by
|
||||
commata. This is meant to hold additional selector readouts such as
|
||||
vacuum states, temperatures etc.
|
||||
\item[GetLossCurrent] initiates a measurement of the loss current of
|
||||
the velocity selector. The result is returned in *fLoss.
|
||||
\item[Init] initiates a connection to a velocity selector.
|
||||
\end{description}
|
||||
|
||||
It may be possible that this driver is not very general. It was
|
||||
developed for Dornier velocity selectors because these were the only
|
||||
one seen.
|
||||
|
||||
\section{General Controller Driver}
|
||||
This is driver for a SICS general controller object. SICS sports a
|
||||
general controller object which allows to read a selection of parameters and
|
||||
to set some parameters. Adapters exists which implement the driveable
|
||||
or environment interface for parameters in such a controller. The
|
||||
parameters supported are part of the drivers interface. This
|
||||
scheme is currently used to control choppers in SICS, but it is not
|
||||
restricted to this usage. The driver:
|
||||
\begin{verbatim}
|
||||
typedef struct __CODRI {
|
||||
int (*Init)(pCodri self);
|
||||
int (*Close)(pCodri self);
|
||||
int (*Delete)(pCodri self);
|
||||
int (*SetPar)(pCodri self,
|
||||
char *parname,
|
||||
float fValue);
|
||||
int (*SetPar2)(pCodri self,
|
||||
char *parname,
|
||||
char *value);
|
||||
int (*GetPar)(pCodri self,
|
||||
char *parname,
|
||||
char *pBuffer,
|
||||
int iBufLen);
|
||||
int (*CheckPar)(pCodri self,
|
||||
char *parname);
|
||||
int (*GetError)(pCodri self, int *iCode,
|
||||
char *pError,
|
||||
int iErrLen);
|
||||
int (*TryFixIt)(pCodri self, int iCode);
|
||||
int (*Halt)(pCodri self);
|
||||
char *pParList;
|
||||
void *pPrivate;
|
||||
}Codri;
|
||||
\end{verbatim}
|
||||
All functions take a pointer to their driver data structure as an
|
||||
argument. If not stated otherwise they return 1 on success, 0 on failure.
|
||||
The fields:
|
||||
\begin{description}
|
||||
\item[Init] initializes a connection to the controller and the driver.
|
||||
\item[Close] closes the connection to a controller.
|
||||
\item[Delete] releases all memory associated with this drivers private
|
||||
data structure pPrivate.
|
||||
\item[SetPar] sets the parameter parname to a new value fValue.
|
||||
\item[SetPar2] same as SetPar but with new value as text.
|
||||
\item[GetPar] read the current value of parname into pBuffer. The
|
||||
value is formatted as text. At max iBufLen bytes are copied into
|
||||
pBuffer.
|
||||
\item[CheckPar] checks the progress of setting parname. CheckPar
|
||||
returns:
|
||||
\begin{description}
|
||||
\item[HWFault] If there is a fault in the hardware or the status
|
||||
cannot be read.
|
||||
\item[HWBusy] The parameter is still driving.
|
||||
\item[HWIdle] The parameter has finished changing and is idle.
|
||||
\end{description}
|
||||
\item[GetError] returns an error code in *iCode and iErrlen
|
||||
bytes of textual description of the last error on the velocity
|
||||
selector in pError.
|
||||
\item[TryAndFixIt] tries to fix the error defined through iCode. iCode
|
||||
should be the value as returned in *iCode in GetError. This function
|
||||
returns:
|
||||
\begin{description}
|
||||
\item[CHREDO] redo last operation, error fixed.
|
||||
\item[CHFAIL] cannot fix the error from software.
|
||||
\end{description}
|
||||
\item[Halt] stop any driving parameters.
|
||||
\item[pParList] a comma separated list of parameters supported by this
|
||||
driver.
|
||||
\item[pPrivate] a driver private data structure.
|
||||
\end{description}
|
@ -102,7 +102,7 @@ $\langle$Protos {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
|
||||
\mbox{}\verb@#ifndef SINQHMDRIVER@\\
|
||||
\mbox{}\verb@#define SINQHMDRIVER@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@#include "hardsup/sinqhm.h"@\\
|
||||
\mbox{}\verb@@$\langle$SQType {\footnotesize ?}$\rangle$\verb@@\\
|
||||
\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
|
||||
\mbox{}\verb@@$\langle$Protos {\footnotesize ?}$\rangle$\verb@@\\
|
||||
|
143
doc/programmer/site.tex
Normal file
143
doc/programmer/site.tex
Normal file
@ -0,0 +1,143 @@
|
||||
\subsubsection{Site Abstraction Layer}
|
||||
With ANSTO using SICS as well it became necessary to separate the
|
||||
general parts of SICS from the installation specific components. Each
|
||||
installation will have a separate set of drivers and, to some
|
||||
extent, instrument specific commands. Such code has to be in a
|
||||
separate library. Access to this library is through an interface which
|
||||
consists of a structure containing pointers to functions which allow
|
||||
for the creation of site specific drivers and commands. Moreover, the
|
||||
site specific library has to implement a function, getSite, which
|
||||
returns the appropriate data structure for the site for which SICS is
|
||||
being compiled. This data structure looks like this:
|
||||
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap1}
|
||||
$\langle$sitedata {\footnotesize ?}$\rangle\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ typedef struct {@\\
|
||||
\mbox{}\verb@ void (*AddSiteCommands)(SicsInterp *pSics);@\\
|
||||
\mbox{}\verb@ void (*RemoveSiteCommands)(SicsInterp *pSics);@\\
|
||||
\mbox{}\verb@ pMotor (*CreateMotor)(SConnection *pCon,@\\
|
||||
\mbox{}\verb@ int argc, char *argv[]);@\\
|
||||
\mbox{}\verb@ pCounterDriver (*CreateCounterDriver)(@\\
|
||||
\mbox{}\verb@ SConnection *pCon,@\\
|
||||
\mbox{}\verb@ int argc, @\\
|
||||
\mbox{}\verb@ char *argv[]);@\\
|
||||
\mbox{}\verb@ HistDriver *(*CreateHistogramMemoryDriver)(@\\
|
||||
\mbox{}\verb@ char *name, pStringDict pOption);@\\
|
||||
\mbox{}\verb@ pVelSelDriv (*CreateVelocitySelector)(char *name, @\\
|
||||
\mbox{}\verb@ char *array, Tcl_Interp *pTcl);@\\
|
||||
\mbox{}\verb@ pCodri (*CreateControllerDriver)(SConnection *pCon,@\\
|
||||
\mbox{}\verb@ int argc,@\\
|
||||
\mbox{}\verb@ char *argv[]);@\\
|
||||
\mbox{}\verb@ pEVControl (*InstallEnvironmentController)(@\\
|
||||
\mbox{}\verb@ SicsInterp *pSics,@\\
|
||||
\mbox{}\verb@ SConnection *pCon,@\\
|
||||
\mbox{}\verb@ int argc,@\\
|
||||
\mbox{}\verb@ char *argv[]);@\\
|
||||
\mbox{}\verb@ int (*ConfigureScan)(pScanData self,@\\
|
||||
\mbox{}\verb@ char *option);@\\
|
||||
\mbox{}\verb@ void (*KillSite)(void *pData);@\\
|
||||
\mbox{}\verb@}Site, *pSite;@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
\vspace{-1ex}
|
||||
\footnotesize\addtolength{\baselineskip}{-1ex}
|
||||
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
||||
\item Macro referenced in scrap ?.
|
||||
\end{list}
|
||||
\end{minipage}\\[4ex]
|
||||
\end{flushleft}
|
||||
\begin{description}
|
||||
\item[AddSiteCommands] adds site specific object creation and
|
||||
instrument specific commands to the SICS interpreter, pSics.
|
||||
\item[RemoveSiteCommands] will be called to remove surplus object
|
||||
creation commands after the SICS interpreter has processed the
|
||||
initialization files. Please note, that SICS does not support the
|
||||
removal of objects at runtime in general. This is due to the fact that
|
||||
any possible object may be used by or linked to others and and it
|
||||
would be a bookeeping nightmare to keep track of all those relations.
|
||||
\item[CreateMotor] creates a motor using the arguments in argc and
|
||||
argv. It returns a pointer to the new motor structure on success or
|
||||
NULL in case of a failure. This function has to return a complete
|
||||
motor in order to allow for special configurations of the motor to
|
||||
take place in its initialization.
|
||||
\item[CreateCounterDriver] returns a driver for a new counter box
|
||||
driver if the parameters are valid or NULL if not. Driver arguments
|
||||
are in the argc, argv pair.
|
||||
\item[CreateHistogramMemoryDriver] creates a driver for a histogram
|
||||
memory. The driver type is specified through name.
|
||||
Driver options are in pOptions.
|
||||
\item[CreateVelocitySelector] create a driver for a velocity selector.
|
||||
The parameter name is the name of the driver, array is the name of a
|
||||
Tcl array holding configuration parameters for the driver and pTcl is
|
||||
the Tcl interpreter in which array lives.
|
||||
\item[CreateControllerDriver] creates a driver for the general
|
||||
controller module within SICS. argc and argv hold the parameters,
|
||||
starting with the name of the driver to create.
|
||||
\item[InstallEnvironmentController] installs a a sample
|
||||
environment device such as a temperature controller or magnet
|
||||
controller etc. into the interpreter pSics. pCon is a connection
|
||||
object to which errors can be
|
||||
reported, argc and argv are the controller parameters starting with
|
||||
the driver name. This method does not get away with creating a driver
|
||||
but must install the command into SICS because some environment
|
||||
devices overload the standard Wrapper function with special ones. The
|
||||
newly created object is still returned for further processing. In the
|
||||
case of failure NULL is returned. Errors will have been printed to
|
||||
pCon.
|
||||
\item[ConfigureScan] allows for modules which configure the scan
|
||||
object. option is the option to xxscan configure to process, the scan
|
||||
object to configure is passed in in self. This returns 1 on success
|
||||
and 0 on failures or options which are not recognized.
|
||||
\item[KillSite] is a function to remove the site data structure when
|
||||
SICS is done with it. pData must point to the site data structure.
|
||||
KillSite's purpose is to free all memory associated with
|
||||
the site data structure. This is mostly a cleanup thing, to keep the
|
||||
fortify logs clear off inconsequential and confusing data.
|
||||
\end{description}
|
||||
|
||||
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap2}
|
||||
\verb@"site.h"@ {\footnotesize ? }$\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@/*-----------------------------------------------------------------------@\\
|
||||
\mbox{}\verb@ S i t e A b s t r a c t i o n L a y e r@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@With ANSTO using SICS as well it became necessary to separate the@\\
|
||||
\mbox{}\verb@general parts of SICS from the installation specific components. Each@\\
|
||||
\mbox{}\verb@installation will have a separate set of drivers and, to some@\\
|
||||
\mbox{}\verb@extent, instrument specific commands. Such code has to be in a@\\
|
||||
\mbox{}\verb@separate library. Access to this library is through an interface which@\\
|
||||
\mbox{}\verb@consists of a structure containing pointers to functions which allow@\\
|
||||
\mbox{}\verb@for the creation of site specific drivers and commands. Moreover, the@\\
|
||||
\mbox{}\verb@site specific library has to implement a function, getSite, which@\\
|
||||
\mbox{}\verb@returns the appropriate data structure for the site for which SICS is@\\
|
||||
\mbox{}\verb@being compiled. @\\
|
||||
\mbox{}\verb@------------------------------------------------------------------------*/@\\
|
||||
\mbox{}\verb@#ifndef SICSSITE@\\
|
||||
\mbox{}\verb@#define SICSSITE@\\
|
||||
\mbox{}\verb@#include <sics.h>@\\
|
||||
\mbox{}\verb@#include <motor.h>@\\
|
||||
\mbox{}\verb@#include <countdriv.h>@\\
|
||||
\mbox{}\verb@#include <HistDriv.i>@\\
|
||||
\mbox{}\verb@#include <stringdict.h>@\\
|
||||
\mbox{}\verb@#include <velo.h>@\\
|
||||
\mbox{}\verb@#include <tcl.h>@\\
|
||||
\mbox{}\verb@#include <codri.h>@\\
|
||||
\mbox{}\verb@#include <evcontroller.h>@\\
|
||||
\mbox{}\verb@#include <scan.h>@\\
|
||||
\mbox{}\verb@@$\langle$sitedata {\footnotesize ?}$\rangle$\verb@@\\
|
||||
\mbox{}\verb@/*-------------------------------------------------------------------*/@\\
|
||||
\mbox{}\verb@pSite getSite(void);@\\
|
||||
\mbox{}\verb@#endif@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
\vspace{-2ex}
|
||||
\end{minipage}\\[4ex]
|
||||
\end{flushleft}
|
@ -27,7 +27,7 @@ $\langle$logint {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@ int VarlogGetVal(pVarLog self, float *fValues);@\\
|
||||
\mbox{}\verb@ int VarlogGetMean(pVarLog self, float *fMean, float *fStdDev);@\\
|
||||
\mbox{}\verb@/*------------------------------ interpreter ---------------------------*/@\\
|
||||
\mbox{}\verb@ int VarlogWrapper(pVarLog self, int *iSwitch, SConnection *pCon, @\\
|
||||
\mbox{}\verb@ int VarlogWrapper(pVarLog self,SConnection *pCon, @\\
|
||||
\mbox{}\verb@ char *subcommand, char *sub2,char *pVarName);@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
|
@ -46,6 +46,7 @@ $\langle$dh {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ int GetDornierStatus(void **pData, pDornierStatus pDornier);@\\
|
||||
\mbox{}\verb@ int DornierSend(void **pData, char *pCommand, char *pReply, int iLen);@\\
|
||||
\mbox{}\verb@ int DecodeNewDornierStatus(char *pText, pDornierStatus pDornier);@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
\vspace{-1ex}
|
||||
@ -69,6 +70,8 @@ $\langle$dh {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ Mark Koennecke, Juli 1997@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ updated to support new format fo status messages, Mark Koennecke, July 2003@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ copyright: see implementation file.@\\
|
||||
\mbox{}\verb@------------------------------------------------------------------------------*/@\\
|
||||
\mbox{}\verb@#ifndef VELODORN@\\
|
||||
|
151
doc/user/autocloud.htm
Normal file
151
doc/user/autocloud.htm
Normal file
@ -0,0 +1,151 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Autocloud</TITLE>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
<H1>Autocloud</H1>
|
||||
<P>
|
||||
With the advent of position sensitive detectors in X-ray and neutron
|
||||
diffraction the problem arises how integrated reflection intensities
|
||||
may be extratcted from the collected volumes of data. Typically a
|
||||
series of frames is measured while rotating the crystal under
|
||||
investigation in omega. Autocloud implements a novel approach for the
|
||||
extraction of reflection intensities from such data. Other currently
|
||||
used integration packages use a UB-matrix to predict the position of a
|
||||
reflection on the detector and then integrate the intensity in a box
|
||||
around the predicted position. In contrast autocloud tries to
|
||||
determine reflection
|
||||
positions and intensities directly from the data. In order to do so a
|
||||
template matching algorithm is used. One advantage of this approach is
|
||||
that crystals with magnetic or incommensurate structures can be easily
|
||||
analysed. Typically packages for intensity integration do not have
|
||||
facilities for predicting such reflections. The other advantage is ease
|
||||
of use. Data analysis with autocloud requires only two steps:
|
||||
Integration followed by indexing.
|
||||
</P>
|
||||
|
||||
<h2>Running Autocloud</h2>
|
||||
<p>
|
||||
The syntax is:
|
||||
<pre>autocloud options datafile
|
||||
</pre>
|
||||
The following options are known:
|
||||
<dL>
|
||||
<dt>-a val
|
||||
<dd>Selects the algorithm to use. The following algorithms are
|
||||
currently supported:
|
||||
<dl>
|
||||
<dt>max
|
||||
<dd>perform only a local maximum search
|
||||
<dt>template
|
||||
<dd>Perform template matching. This is the default.
|
||||
<dt>cross
|
||||
<dd>Perform template matching using the cross correlation function.
|
||||
</dl>
|
||||
<dt>-b AAxBBxCC
|
||||
<dd>For the evaluation of the initial template a preliminary box size
|
||||
is needed. This can be specified through this option. Three values
|
||||
separated by the character 'x' are required, one for each dimension in
|
||||
the order x, y, z.
|
||||
<dt>-d val
|
||||
<dd>After the correlation of the data volume with the template another
|
||||
maximum search is started in order to locate the reflections. In order
|
||||
to suppress spurious peaks, a minimum steepness of the candidate peak
|
||||
can be set with the -d option.
|
||||
<dt>-e val
|
||||
<dd>Some systems store frames a single files. With the -e option the
|
||||
end file number of the frame files can be set.
|
||||
<dt>-m val
|
||||
<dd>When the maximum search only option is set a, a threshold is
|
||||
required for suppressing spurious peaks. This threshold can be set
|
||||
with the -m option.
|
||||
<dt>-o file
|
||||
<dd>Redirects output to the file name specified. By default all output
|
||||
is written to stdout.
|
||||
<dt>-s val
|
||||
<dd>Some systems store frames a single files. With the -s option the
|
||||
start file number of the frame files can be set.
|
||||
<dt>-t type
|
||||
<dd>This option sets the type of the data file. Currently understood
|
||||
are:
|
||||
<dl>
|
||||
<dt>sxd
|
||||
<dd>For NeXus data from SXD at ISIS.
|
||||
<dt>trics
|
||||
<dd>For NeXus data files from TRICS, SINQ
|
||||
<dt>debug
|
||||
<dd>An internal format used during software testing.
|
||||
</dl>
|
||||
<dt>-v val
|
||||
<dd>Increases the verbosity of the output.
|
||||
</dl>
|
||||
</p>
|
||||
|
||||
<h2>The Autocloud Algorithm</h2>
|
||||
<p>
|
||||
The autocloud algorithm has the following steps:
|
||||
<ol>
|
||||
<li>Location of strong peaks for template evaluation.
|
||||
<li>Background Subtraction.
|
||||
<li>Evaluation of a template for volume matching.
|
||||
<li>Correlation of the template with the data volume.
|
||||
<li>Location of maxima in the correlated data.
|
||||
<li>Integration of the reflections found.
|
||||
</ol>
|
||||
</p>
|
||||
<h3>Location of Strong Peaks for Template Evaluation</h3>
|
||||
<p>
|
||||
This is basically a local maximum detection scheme. A local maxima
|
||||
must be the strongest intensity within a 7 by 7 by 7 volume. All
|
||||
maxima smaller then 10% of the largest maximum found are discarded.
|
||||
</p>
|
||||
|
||||
<h3>Background Subtraction</h3>
|
||||
<p>
|
||||
Background subtraction is done with essentially the same algorithm XDS
|
||||
uses. For each x, y coordinate in the frame values are summed along
|
||||
the third dimension. Points belonging to a local maimum are
|
||||
excluded. The background
|
||||
for this x,y coordinate is then the average of the values
|
||||
summed. The data volume is then corrected for the background with
|
||||
these values. This works well as long as the assumption holds that the
|
||||
background varies mostly across the detector and not much with the
|
||||
third dimension.
|
||||
</p>
|
||||
|
||||
<h3>Template Evaluation</h3>
|
||||
<p>
|
||||
The template to be used for template matching later on is calculated
|
||||
by summing all local maxima first. Then the limits of the reflection
|
||||
are calculated for each scanline using the Lehmann-Larsen
|
||||
algorithm. The reflection thus found is scaled to a value of 1 and
|
||||
used as the template.
|
||||
</p>
|
||||
|
||||
<h3>Template Matching</h3>
|
||||
<p>
|
||||
For the actual correlation of the template with the data two variantes
|
||||
can be used: Normal simple correlation or cross correlation.
|
||||
</p>
|
||||
|
||||
<h3>Peak Detection</h3>
|
||||
<p>
|
||||
This is again a local maximum detection within a 7 by 7 by 7
|
||||
box. Another criterium for the supression of wrong identifications is
|
||||
a minimum steepness. This means that the candidate local maximum must
|
||||
at least be higher by a certain amount (the steepness) then the points
|
||||
at the border of its 7 by 7 by 7 box.
|
||||
</p>
|
||||
|
||||
<h3>Peak Integration</h3>
|
||||
<p>
|
||||
A scale factor is calculated for each candidate reflection between the
|
||||
data and the template. The intensity is derived from this scale factor
|
||||
and the standard deviation is calculated as the squared difference
|
||||
between the scaled template and the data. This scheme is the same as
|
||||
learnt profile fitting as described by Ford for the 1- and 2d cases.
|
||||
</p>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
@ -36,7 +36,19 @@ system for instance file names are case sensitive and that had to be
|
||||
preserved. Commands defined in the scripting language are lower case by
|
||||
convention.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Most SICS objects also hold the parameters required for their proper
|
||||
operation. The general syntax for handling such parameters is:
|
||||
<pre>
|
||||
objectname parametername
|
||||
</pre>
|
||||
prints the current value of the parameter
|
||||
</p>
|
||||
<pre>
|
||||
objectname parametername newvalue
|
||||
</pre>
|
||||
sets the parameter value to newvalue if you are properly authorized.
|
||||
</p>
|
||||
<h3>Authorisation</h3>
|
||||
<p>
|
||||
A client server system is potentially open to unauthorised hackers
|
||||
|
@ -27,6 +27,8 @@ Log files are written to the log directory of the instrument account. There
|
||||
are time stamps any hour in that file and there is a new file any 24 hours.
|
||||
<DT>commandlog tail <i>[n]</i>
|
||||
<DD>prints the last n entries made into the command log. n is optional and defaults to 20. Up to 1000 lines are held in an internal buffer for this command.
|
||||
<DT>commandlog intervall
|
||||
<DD>Queries and configures the intervall in minutes at which time stamps are written to the commandlog.
|
||||
</DL>
|
||||
It is now possible to have a script executed whenever a new log file is
|
||||
started. In order to make this work a ServerOption with the name logstartfile
|
||||
|
@ -21,9 +21,6 @@ manually from the command line through the following commands:
|
||||
is minutes.
|
||||
<DT>storefocus intervall newval
|
||||
<DD>Sets the update intervall to newval minutes.
|
||||
<DT>killfile
|
||||
<DD>This command will overwrite the last data file written and thus
|
||||
effectively erase it. Therefore this command requires manager privilege.
|
||||
</DL>
|
||||
FOCUS has three detector banks which may not all be active at all
|
||||
times. Thus a way is needed to tell SICS about the configuration of
|
||||
|
@ -74,16 +74,14 @@ for its number type.
|
||||
<LI>Count. As Ceil, but a list of overflowed bins will be maintained.
|
||||
</UL>
|
||||
<DT> Rank
|
||||
<DD> Rank defines the number of histograms in memory.
|
||||
<DT> Length
|
||||
<DD> gives the length of an individual histogram.
|
||||
<DD> Rank defines the number of dimensions the detector has, minus the time channle when applicable. 1 is a linear detector, 2 a area detector etc.
|
||||
<DT> BinWidth
|
||||
<DD> determines the size of a single bin in histogram memory in bytes.
|
||||
<DT>dim0, dim1, dim2, ... dimn
|
||||
<DD>define the logical dimensions of the histogram. Must be set if the
|
||||
the sum command (see below) is to be used. This is a clutch necessary to
|
||||
cope with the different notions of dimensions in the SINQ histogram memory
|
||||
and physics.
|
||||
<DD>define the logical dimensions of the histogram.
|
||||
<dt>extrachan
|
||||
<dd>Extra time channels as used at AMOR and SANS for time-of-flight
|
||||
monitors. They get appended to the main hm data but are treated separately.
|
||||
</DL>
|
||||
</p>
|
||||
<p>
|
||||
@ -126,6 +124,8 @@ will be generated starting from start with a stepwidth of step (example: HM genb
|
||||
configured with this command. The time bin iNum is set to the value value.
|
||||
<DT>HM clearbin
|
||||
<DD>Deletes the currently active time binning information.
|
||||
<dt>HM notimebin
|
||||
<dd>returns the number of currently configured timebins.
|
||||
</DL>
|
||||
</p>
|
||||
|
||||
@ -150,6 +150,10 @@ transfer the configuration from the host computer to the actual HM.
|
||||
<DD> starts counting using the currently active values for CountMode and
|
||||
preset. This command does not block, i.e. in order to inhibit further
|
||||
commands from the console, you have to give Success afterwards.
|
||||
<DT>HM countblock
|
||||
<DD> starts counting using the currently active values for CountMode and
|
||||
preset. This command does block, i.e. you can give new commands only when
|
||||
the counting operation finishes.
|
||||
<DT>HM initval <i>val</i>
|
||||
<DD> initialises the whole histogram memory to the value val. Ususally 0 in
|
||||
order to clear the HM.
|
||||
@ -164,3 +168,5 @@ allow to retrieve a subset of a histogram between iStart and iEnd.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
@ -53,6 +53,17 @@ Optionally a psi value and a hamilton position can be specified.
|
||||
the motors to drive to that position. This command will wait for the
|
||||
diffractometer to arrive at the setting angles requested.
|
||||
Optionally a psi value and a hamilton position can be specified.
|
||||
<dt>hkl hm
|
||||
<dd>Retrieves the value of the histogram memory flag.
|
||||
<dt>hkl hm val
|
||||
<dd>Sets the histogram memory flag to val. This is a special for
|
||||
TRICS. TRICS has three detectors at 0, 45, 90 degree offset to two
|
||||
theta. If this flag is greater 0, hkl checks if the reflection to be
|
||||
calculated is on any of the three detectors and calculates two theta
|
||||
accordingly.
|
||||
<dt>hkl fromangles two-theta om chi phi
|
||||
<dd>Calculates hkl from the angles given on the command line using the
|
||||
current UB matrix and wavelength.
|
||||
</DL>
|
||||
</p>
|
||||
|
||||
|
@ -3,10 +3,14 @@
|
||||
<TITLE>Hklscan</TITLE>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
<H1>Hklscan</H1>
|
||||
<H1>Hklscan and Hklscan2d</H1>
|
||||
<P>
|
||||
Hklscan is a command which allows to scan in reciprocal space expressed as
|
||||
Miller indizes on a four circle diffractometer. Prerequisite for this is
|
||||
Miller indizes on a four circle diffractometer. Hklscan operates with
|
||||
a single detector. Hklscan2d does the same as hklscan but for the
|
||||
position sensitive detectors, saving data into NeXus files. Hklscan
|
||||
and Hklscan2d share the same syntax.
|
||||
Prerequisite for this is
|
||||
the existence of a scan object and the hkl-object for doing crystallographic
|
||||
calculations. Make sure the properties of the hkl object (UB, wavelength, NB)
|
||||
have some reasonable relation to reality, otherwise the diffractometer may
|
||||
@ -25,10 +29,15 @@ Hklscan is a command which allows to scan in reciprocal space expressed as
|
||||
<dd>executes the HKL scan. NP is the number of points to do, mode is the
|
||||
counting mode and can be either timer or monitor and preset is the preset
|
||||
value for the counter at each step.
|
||||
<dt>hklscan2d sim NP mode preset
|
||||
<dd>This command only for hklscan2d. It tries to calculate all points
|
||||
in the hkl scan and complains if it cannot reached or stays
|
||||
silent. Use this to test if your hklscan2d can be performed.
|
||||
</dl>
|
||||
Data is written automatically into a slightly modified TOPSI data format
|
||||
file. The status display with topsistatus or scanstatus might be slightly
|
||||
erratic as it uses two theta as x-axis.
|
||||
file for hklscan. The status display with topsistatus or scanstatus
|
||||
might be slightly erratic as it uses two theta as x-axis. Hklscan2d
|
||||
writes data into NeXus files.
|
||||
</P>
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
59
doc/user/lowmax.htm
Normal file
59
doc/user/lowmax.htm
Normal file
@ -0,0 +1,59 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>The Local Maximum Search Module</TITLE>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
<h1>The Local Maximum Search Module</h1>
|
||||
<p>
|
||||
This module allows to search for local maxima in two-dimensional
|
||||
datasets stored within a SICS histogram memory. All commands
|
||||
act upon the current content of the histogram memory. The following
|
||||
commands are understood:
|
||||
<dl>
|
||||
<dt>lowmax stat hm
|
||||
<dd>calculates the average and the maximum count in the frame
|
||||
currently held in histogram memory hm.
|
||||
<dt>lowmax search hm
|
||||
<dd>searches the frame held in histogram memory hm for local
|
||||
maxima. Local maxima are returned as sets of three numbers which are
|
||||
the x and y coordinates and the intensity. Each set of numbers is
|
||||
separated from the next one by the @ symbol.
|
||||
<dt>lowmax cog hm x y
|
||||
<dd>calculates the center ogf gravity for the pixel at coordinates x
|
||||
and y in histogram memory hm. Four numbers are returned: the new x and
|
||||
y coordinates, the intensity of the peak and the number of points
|
||||
contributing to the peak.
|
||||
<dt>lowmax steepness val
|
||||
<dd>accesses the steepness parameter for the peak search. With a
|
||||
parameter val sets a new value, without print the current value.
|
||||
<dt>lowmax window val
|
||||
<dd>accesses the window parameter for the peak search. With a
|
||||
parameter val sets a new value, without print the current value.
|
||||
<dt>lowmax threshold val
|
||||
<dd>accesses the thresholds parameter for the peak search. With a
|
||||
parameter val sets a new value, without print the current value.
|
||||
<dt>lowmax cogwindow val
|
||||
<dd>accesses the cogwindow parameter for the peak search. With a
|
||||
parameter val sets a new value, without print the current value.
|
||||
<dt>lowmax cogcontour val
|
||||
<dd>accesses the cogcontour parameter for the peak search. With a
|
||||
parameter val sets a new value, without print the current value.
|
||||
</dl>
|
||||
The local maximum search can be tuned through the parameters: The
|
||||
window parameter sets the size of the quadratic area for which a
|
||||
candidate pixel must be the local maximum. Threshold sets a minimum
|
||||
count rate for a local maximum. Steepness sets a minimum difference to
|
||||
the borders of the window used for the local maximum search which must
|
||||
be fulfilled.
|
||||
</p>
|
||||
<p>
|
||||
The center of gravity calculation can be tuned mainly through the
|
||||
cogcontour parameter which determines at which percentage of the
|
||||
maximum value of the peak the center of gravity calculation
|
||||
stops. Cogwindow is the size of the area in which a center of gravity
|
||||
is calculated. Can be set rather generously.
|
||||
</p>
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
||||
|
@ -7,14 +7,25 @@
|
||||
<p>
|
||||
SICS has a built in macro facility. This macro facility is aimed at instrument managers and users alike. Instrument managers may provide customised measurement procedures in this language, users may write batch files in this language. The macro language is John Ousterhout's Tool Command Language (TCL). Tcl has control constructs, variables of its own, loop constructs, associative arrays and procedures. Tcl is well documented by several books and online tutorials, therefore no details on Tcl will be given here. All SICS commands are available in the macro language. Some potentially harmful Tcl commands have been deleted from the standard Tcl interpreter. These are: exec, source, puts, vwait, exit,gets and socket. A macro or batch file can be executed with the command:</p>
|
||||
<p>
|
||||
<b> fileeval <i>name</i> </b> tries to open the file name and executes the script in this file. </p>
|
||||
<b> fileeval <i>name</i> </b> tries to open the file name and
|
||||
executes the script in this file.
|
||||
</p>
|
||||
<p>
|
||||
<b>batchrun <i>name</i></b> prepends to name a directory name
|
||||
configured in the variable batchroot and then executes that
|
||||
batchfile. The usage scenerio is that you have a directory where you
|
||||
keep batch files. Then the variable batcroot is set to contain the path
|
||||
to that directory. Batchrun then allows to start scripts in that
|
||||
directory without specifying the full path.
|
||||
Then there are some special commands which can be used within macro-sripts:
|
||||
<p>
|
||||
<b> ClientPut sometext1 ... </b> writes everything after ClientPut to
|
||||
the client which started the script. This is needed as SICS supresses
|
||||
the output from intermediate commands in scripts. Except error
|
||||
messages and warnings. With clientput this scheme can be circumvented
|
||||
and data be printed from within scripts.</p>
|
||||
<b> ClientPut sometext1 ... </b>Usally SICS suppresses any messages
|
||||
from SICS during the processing of batch files. This is in order not
|
||||
to confuse users with the output of intermediate results during
|
||||
the processing of batch files. Error messages and warnings, however,
|
||||
come through always. Clientput now allows to send messages to the
|
||||
user on purpose from within scripts.
|
||||
</p>
|
||||
<p>
|
||||
<b> SICSType object </b> allows to query the type of the object specified by object. Possible return values are<ul>
|
||||
<li> <b> DRIV </b> if the object is a SICS drivable object such as a motor
|
||||
|
@ -47,8 +47,83 @@ or equal to zero for the motor being movable.
|
||||
<li> <b> Precision </b> denotes the precision to expect from the motor in positioning. Can usually only be set by managers.
|
||||
<li> <b> AccessCode </b> specifies the level of user privilege necessary to operate the motor. Some motors are for adjustment only and can be harmful to move once the adjustment has been done. Others must be moved for the experiment. Values are 0 - 3 for internal, manager, user and spy. This parameter can only be changed by managers.
|
||||
<li> <b> Sign </b> reverses the operating sense of the motor.
|
||||
For cases where electricians and not physicists have defined the operating sense of the motor. Usually a parameter not to be changed by ordinary users.
|
||||
For cases where electricians and not physicists have defined the
|
||||
operating sense of the motor. Usually a parameter not to be changed
|
||||
by ordinary users.
|
||||
<li><b> failafter </b>This is the number of consecutive failures of
|
||||
positioning operations this motor allows before it thinks that
|
||||
something is really broken and aborts the experiment.
|
||||
<li><b> maxretry </b>When a motor finishes driving, SICS checks if the
|
||||
desired position was reached. If the position read back from the motor
|
||||
is not within precision to the desired value, the motor is
|
||||
restarted. This is done at max maxretry times. After maxretry retries,
|
||||
the motor throws an error.
|
||||
<li></b> ignorefault </b>If this is bigger then 0, positioning faults
|
||||
from the motor will be ignored.
|
||||
</ul>
|
||||
<p>
|
||||
<h2>Motor Error Handling Concepts</h2>
|
||||
<p>
|
||||
As mechanical components motors are prone to errors. SICS knows about
|
||||
two different classes of motor errors:
|
||||
<dl>
|
||||
<dt>HWFault
|
||||
<dd>This is when there is a problem communicating with the motor, a
|
||||
limit is violated etc. SICS assumes that such errors are so grave that
|
||||
no fix is possible. If such a HWFault is detected a configurable
|
||||
interrupt (see parameter InterruptMode) is set which can be used by
|
||||
upper level code to act upon the problem.
|
||||
<dt>HWPosFault
|
||||
<dd>This is a positioning failure, i.e. The motor did not reach the
|
||||
desired position. Such a positioning problem can come from two
|
||||
sources:
|
||||
<ul>
|
||||
<li>The positioning problem is reported by the motor driver. SICS then
|
||||
assumes that the driver has done something to solve the problem and
|
||||
promotes this problem to a HWFault.
|
||||
<li>The motor driver reported no error and SICS figures out by itself,
|
||||
that the desired position has not been reached. SICS thinks that this
|
||||
is the case if the difference between the desired position and the
|
||||
position read from the motor controller is greater then the parameter
|
||||
precision. If SICS detects such a problem it tries to reposition the
|
||||
motor. This is done for the number of times specified through the
|
||||
parameter maxretries. If the position has not been reached after
|
||||
maxretries repositionings, a HWFault is assumed.
|
||||
</ul>
|
||||
</dl>
|
||||
In any case lots of warnings and infos are printed.
|
||||
</p>
|
||||
<p>
|
||||
If SICS tries to drive an axis which is for some reason broken to
|
||||
often hardware damage may occur (and HAS occurred!). Now, SICS has no
|
||||
means to detect if the mispositioning of a motor is due to a concrete
|
||||
block in the path of the instrument or any other reason. What SICS can
|
||||
do though is to count how often a motor mispositions in
|
||||
sequence. This means SICS counts mispositionings if it cannot drive a
|
||||
motor, if the motor is driven succesfully, the count is cleared. If
|
||||
the count of mispositionings becomes higher then the parameter
|
||||
failafter, SICS thinks that there is something really, really wrong
|
||||
and aborts the measurement and prints an error message containing the
|
||||
string: MOTOR ALARM.
|
||||
</p>
|
||||
<p>
|
||||
There are some common pitfalls with this scheme:
|
||||
<dl>
|
||||
<dt>You want upper level code to be signalled when your critical motor
|
||||
fails.
|
||||
<dd>Solution: set the parameter interruptmode to something useful and
|
||||
check for the interrupt in upper level code.
|
||||
<dt>SICS falsly reports mispositionings.
|
||||
<dd>Solution: increase the precision parameter.
|
||||
<dt>You know that a motor is broken, you cannot fix it, but you want
|
||||
to measure anyway.
|
||||
<dd>Solution: increase the precision parameter, if SICS finds the
|
||||
positioning problem, increase maxretries, increase the failafter
|
||||
parameter. In the worst case set the ignorefault parameter to greater
|
||||
0, this will prevent all motor alarms.
|
||||
</dl>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
98
doc/user/peaksearch.htm
Normal file
98
doc/user/peaksearch.htm
Normal file
@ -0,0 +1,98 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>TRICS PSD Peak Search</TITLE>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
<H1>TRICS PSD Peak Search</H1>
|
||||
<P>
|
||||
For almost any measurement at TRICS a UB matrix has to be determined
|
||||
beforehand. In order to do this a couple of peak must be located by
|
||||
some means. This section describes how the computer can help in
|
||||
finding an initial set of peaks.
|
||||
</P>
|
||||
<p>
|
||||
The algorithm is quite simple: It consists of a big loop over ranges
|
||||
of the four circle angles two theta, omega, chi and phi. At each
|
||||
position a counting operation is performed. Then peaks are located on
|
||||
all three detectors through a local maximum search. For this, the
|
||||
<a href="lowmax.htm">local maximum search</a> module is used.
|
||||
If a candidate
|
||||
peak is found, it is refined in omega and written to a file. The
|
||||
tricky bit is the adjustement of the local maximum search parameters
|
||||
in order to minimize false maxima caused by a spicky background or
|
||||
powder lines.
|
||||
</p>
|
||||
<p>
|
||||
The peak search facility need a lot of parameters in order to
|
||||
operate. This includes angle ranges, count parameters and the maximum
|
||||
search parameters. Commands are provided for adjusting these
|
||||
parameters. The general operation of these commands follow a pattern:
|
||||
typing the command alone prints the current values of the
|
||||
parameters. In order to set new values the command name must be typed
|
||||
plus new values for all the parameters listed by this command. An
|
||||
Example:
|
||||
<pre>
|
||||
ps.sttrange
|
||||
</pre>
|
||||
prints the range in two theta for the peaksearch.
|
||||
<pre>
|
||||
ps.sttrange startval endval step
|
||||
</pre>
|
||||
sets new values for the two theta range and prints them afterwards.
|
||||
The following commands are provided:
|
||||
<dl>
|
||||
<dt>ps.sttrange
|
||||
<dd>adjustment of the two theta range for the peak search.
|
||||
<dt>ps.omrange
|
||||
<dd>adjustment of the omega range for the peak search.
|
||||
<dt>ps.chirange
|
||||
<dd>adjustment of the chi range for the peak search.
|
||||
<dt>ps.phirange
|
||||
<dd>adjustment of the phi range for the peak search.
|
||||
<dt>ps.countpar
|
||||
<dd>adjustment of the counting parameters for the peak search.
|
||||
<dt>ps.scanpar
|
||||
<dd>adjustment of the parameters used by ps.scanlist for scanning
|
||||
located peaks. See below.
|
||||
<dt>ps.maxpar
|
||||
<dd>Adjusts the maximum finding parameters for the peak search. These
|
||||
parameters need some explanation:
|
||||
<dl>
|
||||
<dt>window
|
||||
<dd>window is the size of the quadratic area which will be searched
|
||||
around each point in order to determine if it is a local maximum.
|
||||
<DT>threshold
|
||||
<dd>This is a minimum intensity a candidate local maximum must have
|
||||
before it is accepted as a peak. The value given is multiplied
|
||||
with the average counst on the data frame before use. This threshold
|
||||
is the strongest selection parameter.
|
||||
<dt>steepness
|
||||
<dd> A candidate peak should drop of towards the sides. This is
|
||||
tested for by checking if the pixels on the borders of the local
|
||||
maximum detection window are below maximum value - steepness.
|
||||
<dt>cogwindow
|
||||
<dd>In order to refine the peaks position a center of gravity
|
||||
calculation is perfomed. For this calculation pixels within the
|
||||
cogwindow around the candidate peak position are considered.
|
||||
<dt>cogcontour
|
||||
<dd>In order not to base the COG calculation on background pixels,
|
||||
only pixels above cogcontour * maxvalue are used for the
|
||||
calculation. With the spicky background at TRICS .5 seems a good value.
|
||||
</dl>
|
||||
<dt>ps.list
|
||||
<dd>lists all parameters for the peak search.
|
||||
<dt>ps.listpeaks
|
||||
<dd> lists all the peaks already found.
|
||||
<dt>ps.run filename
|
||||
<dd>starts the peak search and stores peaks identified in file
|
||||
filename.
|
||||
<dt>ps.continue
|
||||
<dd>continues a peak search which was interrupted for one reason or
|
||||
another.
|
||||
<dt>ps.scanlist
|
||||
<dd>performs an omega scan for each reflection found in the current
|
||||
peak list.
|
||||
</dl>
|
||||
</P>
|
||||
</BODY>
|
||||
</HTML>
|
@ -21,9 +21,6 @@ manually from the command line through the following commands:
|
||||
is minutes. Default is 20 minutes.
|
||||
<DT>storedata intervall <i>newval</i>
|
||||
<DD>Sets the update intervall to newval minutes.
|
||||
<DT>killfile
|
||||
<DD>This command will overwrite the last data file written and thus
|
||||
effectively erase it. Therefore this command requires manager privilege.
|
||||
</DL>
|
||||
</P>
|
||||
</BODY>
|
||||
|
16
doc/user/psddata.htm
Normal file
16
doc/user/psddata.htm
Normal file
@ -0,0 +1,16 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>TRICS PSD Data Analysis</TITLE>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
<h1>TRICS PSD Data Analysis</h1>
|
||||
<p>
|
||||
As of now two packages are provided:
|
||||
<ul>
|
||||
<li>A data analysis package based on <a href="xds.htm">XDS</a>.
|
||||
<li>An experimental package based on a
|
||||
novel <a href="auto.htm">volume matching </a> approach.
|
||||
</ul>
|
||||
</P>
|
||||
</BODY>
|
||||
</HTML>
|
@ -18,16 +18,19 @@ devices.
|
||||
<li><a href="#lsc">LakeShore Model 340</a> temperature controllers.
|
||||
<li>Oxford Instruments <a href="#itc4">ITC-4</a> or ITC-503 temperature
|
||||
controllers.
|
||||
<li><a href="#dilu">Dilution</a> Cryostat.
|
||||
<li>Haake <a href="#haake">waterbath </a> thermostat.
|
||||
<li><a href="#ltc11">The CryoFurnace</a> with its Neocera LTC-11 temperature
|
||||
controller.
|
||||
<li><a href="#euro">Eurotherm Temperature Controller</a>.
|
||||
<li><a href="#bruker">Bruker</a> Magnet Controller.
|
||||
<li>The Risoe <a href="#a1931">A1931</a> Temperature Controller.
|
||||
<li>The <a href="#el755">PSI-EL755</a> Magnet Controller.
|
||||
<li>The <a href="#psidsp">PSI-DSP</a> Magnet Controller, also known as
|
||||
SLS controller.
|
||||
SLS controller.
|
||||
</ul>
|
||||
Obsolete:
|
||||
<ul>
|
||||
<li>Old <a href="#dilu">Dilution</a> Cryostat.
|
||||
<li>The <a href="#ltc11">Neocera LTC-11</a> temperature
|
||||
controller (was used for the Cryofurnace).
|
||||
</ul>
|
||||
</p>
|
||||
<!latex-on>
|
||||
@ -65,7 +68,7 @@ for understanding SICS environment device handling. Then there will be another
|
||||
section discussing the special devices known to the system.
|
||||
</p>
|
||||
<p>
|
||||
<h2>SampleEnvironment Error Handling</h2>
|
||||
<h2>Sample Environment Error Handling</h2>
|
||||
A <a name="error"> sample</a> environment device may fail to stay at its preset value during a
|
||||
measurement. This condition will usually be detected by the emon. The question
|
||||
is how to deal with this problem. The requirements for this kind of error
|
||||
@ -190,6 +193,15 @@ handling is set. Valid values are:
|
||||
<DT>SafeValue
|
||||
<DD> The value to drive the controller to when an error has been detected and
|
||||
Safe error handling is set.
|
||||
<DT>MaxWait
|
||||
<DD> Maximal time in minutes to wait in a drive temperature command.
|
||||
If maxwait is set to 0: If the temperature is not reached within tolerance,
|
||||
it waits indefinitely.
|
||||
<DT>Settle
|
||||
<DD> Wait time [minutes] after reaching temperature. Indicates how long to wait
|
||||
after reaching temperature. If the temperatures goes again out
|
||||
of tolerance during the settling time, the time outside tolerance
|
||||
is not taken into account.
|
||||
</DL>
|
||||
</p>
|
||||
<P>
|
||||
@ -213,15 +225,17 @@ can be achieved by using the drive command.
|
||||
and <b>log frequency</b> (both below)
|
||||
</DL>
|
||||
<h3>Logging </h3>
|
||||
The values of any sample environement device can be logged. There are two
|
||||
The values of any sample environement device can be logged. There are three
|
||||
features:
|
||||
<ul>
|
||||
<li>Logging to a file wih a configurable time intervall between log
|
||||
file entries.
|
||||
<li>Sums are kept internally which allow the calculation of the mean
|
||||
value and the standard deviation at all times.
|
||||
<li>A circular buffer holding 1000 timestamps plus values is
|
||||
automatically updated.
|
||||
</ul>
|
||||
The last system is automatically switched on after the first drive or
|
||||
The last two systems are automatically switched on after the first drive or
|
||||
run command on the environment device completed.
|
||||
This system is run through the following commands.
|
||||
<DL>
|
||||
@ -233,7 +247,7 @@ standard deviation.
|
||||
values and prints them.
|
||||
<DT>name log frequency val
|
||||
<DD> With a parameter sets, without a parameter requests the logging intervall
|
||||
for the log file.
|
||||
for the log file and the circular buffer.
|
||||
This parameter specifies the time intervall in seconds
|
||||
between log records. The default is 300 seconds.
|
||||
<DT>name log file filename
|
||||
@ -243,12 +257,22 @@ Logging will happen any 5 minutes initially. The logging frequency
|
||||
of the form date time value. The name of the file must be specified relative
|
||||
to the SICS server.
|
||||
<DT>name log flush
|
||||
<DD>DigitalUnix buffers output heavily. With this command an update of
|
||||
<DD>Unix buffers output heavily. With this command an update of
|
||||
the file can be enforced.
|
||||
<DT>name log status
|
||||
<DD>Queries if logging to file is currently happening or not.
|
||||
<DT>name log close
|
||||
<DD> Stops logging data to the file.
|
||||
<dt>name log tosicsdata dataname
|
||||
<dd>copies the content of the circular buffer to a sicsdata
|
||||
buffer. This is used by graphical clients to display the content of
|
||||
the circular buffer.
|
||||
<dt>name log dump
|
||||
<dd>Prints the content of the circular log buffer to screen.
|
||||
<dt>name log dumptofile filename
|
||||
<dd>Prints the content of the circular log buffer into the file
|
||||
specified as filename. Note, this file is on the computer where the
|
||||
SICS server resides.
|
||||
</DL>
|
||||
</P>
|
||||
|
||||
@ -263,41 +287,24 @@ that special device. All of the general commands listed above work as well!
|
||||
This is <i>the</i> temperature controller for cryogenic applications and
|
||||
should replace at least the Oxford & Neocera controllers at SINQ.<p>
|
||||
The control is handled by a seperate server process TECS (TEmperature
|
||||
Control Server) and is initialized by default. If there is already an other
|
||||
device selected, it must be deleted and TECS must be reinstalled:
|
||||
Control Server) and is initialized by default on most instruments. If there is already an other
|
||||
device selected, it must be deleted with:
|
||||
<BLOCKQUOTE>
|
||||
EVFactory del temperature<br>
|
||||
EVFactory new temperature tecs
|
||||
EVFactory del temperature
|
||||
</BLOCKQUOTE>
|
||||
The sample environment device is selected automatically by a coding in the
|
||||
plug of the sensor/heater cable(s). If this does not work (plugs without
|
||||
coding or temporarely use of a wrong cable) you may select the device
|
||||
with
|
||||
and TECS must be reinstalled with:
|
||||
<BLOCKQUOTE>
|
||||
temperature device <i>device</i>
|
||||
tecs on
|
||||
</BLOCKQUOTE>
|
||||
You may want to verify the selected device with
|
||||
<BLOCKQUOTE>
|
||||
temperature device
|
||||
</BLOCKQUOTE>
|
||||
The actually known devices (April 2000) are:
|
||||
<UL>
|
||||
<LI>orange cryostats: <b>ill1</b> (50mm), <b>ill2</b> (70mm),
|
||||
<b>ill3</b> (cryofurnace), <b>ill4</b> (FOCUS), <b>ill5</b> (100 mm)
|
||||
<LI>closed cycles: <b>cti1</b>, <b>cti2</b>, <b>cti3</b>, <b>cti4</b>,
|
||||
<b>cti5</b> (maxi), <b>cti6</b> (FOCUS), <b>apd</b> (TriCS), <b>ccr4k</b> (4K)
|
||||
<LI>other: <b>hef4c</b> (He-flow cryostat 4circle), <b>sup4t</b> (4 T supraconducting magnet)
|
||||
</UL>
|
||||
(This is just an abbreavation for EVFactory new temperature tecs)<p>
|
||||
More details can be found on the <a href=http://sinq.web.psi.ch/sinq/sample_env/tecs.html>Sample Environment Home Page</a>
|
||||
<p>
|
||||
<h3><a name="itc4">ITC-4</a> and ITC-503 Temperature Controllers</h3>
|
||||
<p>
|
||||
These temperature controller were fairly popular at SINQ. They are
|
||||
manufactured by
|
||||
Oxford Instruments. At the back of this controller is a RS-232
|
||||
socket which must be connected to a Macintosh computer running the SINQ
|
||||
terminal server program via a serial cable. Please make sure with a different
|
||||
Macintosh or a PC that the serial line is OK and the ITC-4 responding before
|
||||
plugging it in.
|
||||
socket which must be connected to a terminal server via a serial cable.
|
||||
</p>
|
||||
<h4>ITC-4 Initialisation</h4>
|
||||
<p>
|
||||
@ -306,23 +313,21 @@ An ITC-4 can be configured into the system by:
|
||||
EVFactory new Temp ITC4 computer port channel
|
||||
</BLOCKQUOTE>
|
||||
This creates an ITC-4 controller object named Temp within the system. The
|
||||
ITC-4 is expected to be connected to the serial port channel at the
|
||||
Macintosh computer computer running the SINQ terminal server program
|
||||
listening at port port. For example:
|
||||
ITC-4 is expected to be connected to the serial port channel of the serial
|
||||
port server porgramm at localhost listening at the specified port. For example:
|
||||
<BLOCKQUOTE>
|
||||
EVFactory new Temp ITC4 lnsp22.psi.ch 4000 7
|
||||
EVFactory new Temp ITC4 localhost 4000 7
|
||||
</BLOCKQUOTE>
|
||||
connects Temp to the Macintosh named lnsp22, serial port 6
|
||||
(7 above is no typo!), listening at port 4000.
|
||||
connects Temp to the serial port 7, listening at port 4000.
|
||||
</P>
|
||||
<h4>ITC-4 Additional Parameters</h4>
|
||||
<p>
|
||||
The ITC-4 has a few more parameter commands:
|
||||
<DL>
|
||||
<DT>timeout
|
||||
<DD>Is the timeout for the Macintosh terminal server program waiting for
|
||||
<DD>Is the timeout for the SerPortServer waiting for
|
||||
responses from the ITC-4. Increase this parameter if error messages
|
||||
containg ?TMO appear.
|
||||
contaning ?TMO appear.
|
||||
<DT> sensor
|
||||
<DD> Sets the sensor number to be used for reading temperature.
|
||||
<DT> control
|
||||
@ -341,17 +346,17 @@ the comma.
|
||||
<h4>Installing an ITC4 step by step</h4>
|
||||
<p>
|
||||
<ol>
|
||||
<li>Connect the ITC temperature controller to port 6 on the Macintosh
|
||||
serial port extension box. Port 6 is specially configured for dealing with
|
||||
<li>Connect the ITC temperature controller to port 7 on the terminal server
|
||||
box. Port 7 is specially configured for dealing with
|
||||
the ideosyncracies of that device. No null modem is needed.
|
||||
<li>Install the ITC4 into SICS with the command: <br>
|
||||
evfactory new name Macintoshname 4000 7<br>
|
||||
Thereby replace name with the name you want to address the ITC4 in SICS. A
|
||||
good choice for a name is temperature, as such a value will be written to data files.
|
||||
evfactory new temperature localhost 4000 7<br>
|
||||
You may choose an other name than "temperature", but then it is in general not stored
|
||||
in the data file.
|
||||
Please note, that SICS won't let you use that name if it already exists. For
|
||||
instance if you already had a controller in there. Then the command:<br>
|
||||
evfactory del name <br>
|
||||
will help. Macintoshname is the name of the instrument Macintosh PC.
|
||||
will help.
|
||||
<li>Configure the upper and lowerlimits for your controller appropriatetly.
|
||||
<li>Figure out which sensor you are going to use for reading temperatures.
|
||||
Configure the sensor and the divisor parameter accordingly.
|
||||
@ -373,7 +378,7 @@ current one.
|
||||
<h4>ITC-4 Trouble Shooting</h4>
|
||||
<p>
|
||||
If the ITC-4 <b>does not respond at all</b>, make sure the serial connection to
|
||||
the Macintosh is working. Use standard RS-232 debugging procedures for doing
|
||||
is working. Use standard RS-232 debugging procedures for doing
|
||||
this. The not responding message may also come up as a failure to
|
||||
connect
|
||||
to the ITC-4 during startup.
|
||||
@ -420,9 +425,8 @@ within the tolerance. That is the temperature value you wanted after all.
|
||||
<p>
|
||||
This is sort of a bucket full of water equipped with a temperature
|
||||
control system. The RS-232 interface of this device can only be operated at
|
||||
4800 baud max. This is why it has to be connected to the serial printer port
|
||||
of the Macintosh serial port server computer. This makes the channel number to
|
||||
use for initialisation a 1 always. The driver for this device has been
|
||||
4800 baud max. This is why it has to be connected to a specially configured port.
|
||||
The driver for this device has been
|
||||
realised in the Tcl extension language of the SICS server. A prerequisite
|
||||
for the usage of this device is that the file hakle.tcl is sourced in the
|
||||
SICS initialisation file and the command inihaakearray has been published.
|
||||
@ -432,11 +436,11 @@ initialisation parameters, second install the device with evfactory. A
|
||||
command procedure is supplied for the first step. Thus the initialisation
|
||||
sequence becomes:
|
||||
<BLOCKQUOTE>
|
||||
inihaakearray name-of-array macintosh-computer name port channel<br>
|
||||
inihaakearray name-of-array localhost name port channel<br>
|
||||
evfactory new temperature tcl name-of-array
|
||||
</BLOCKQUOTE>An example for the SANS:
|
||||
<BLOCKQUOTE>
|
||||
inihaakearray eimer lnsp25.psi.ch 4000 1 <br>
|
||||
inihaakearray eimer localhost 4000 1 <br>
|
||||
evfactory new temperature tcl eimer
|
||||
</BLOCKQUOTE>
|
||||
Following this, the thermostat can be controlled with the other environment
|
||||
@ -452,35 +456,6 @@ temperature sensor val
|
||||
</BLOCKQUOTE>
|
||||
val can be either intern or extern.
|
||||
</p>
|
||||
<h3><a name="dilu">Dilution</a> Cryostat</h3>
|
||||
<p>
|
||||
This is a large ancient device for reaching very low temperatures. This
|
||||
cryostat can be configured into SICS with the command:
|
||||
<pre>
|
||||
EVFactory new Temp dillu computer port channel table.file
|
||||
</pre>
|
||||
Temp is the name of the dilution controller command in SICS, dillu is the
|
||||
keyword which selects the dilution driver, computer, port and channel are
|
||||
the parameters of the Macintosh-PC running the serial port server program.
|
||||
table.file is the fully qualified name of a file containing a translation
|
||||
table for this cryostat. The readout from the dilution controller is a
|
||||
resistance. This table allows to interpolate the temperature from the
|
||||
resistance measurements and back. Example:
|
||||
<pre>
|
||||
evfactory new temperature dillu lnsp19.psi.ch 4000 1 dilu.tem
|
||||
</pre>
|
||||
installs a new dilution controller into SICS. This controller is connected
|
||||
to port 1 at the Macintos-PC with the newtwork adress lnsp19.psi.ch. On this
|
||||
macintosh-PC runs a serial port server program listening at TCP/IP port
|
||||
4000. The name of the translation table file is dilu.tem.
|
||||
</p>
|
||||
<p>
|
||||
The dilution controller has no special commands, but two caveats: As of
|
||||
current (October 1998) setting temperatures does not work due to problems
|
||||
with the electronics. Second the dilution controller MUST be connected to
|
||||
port 1 as only this port supports the 4800 maximum baud rate this device
|
||||
digests.
|
||||
</p>
|
||||
<h3><a name="bruker">Bruker</a> Magnet Controller B-EC-1</h3>
|
||||
<p>
|
||||
This is the Controller for the large magnet at SANS. The controller is a
|
||||
@ -490,24 +465,23 @@ an external hall sensor at the magnet. In <b>current</b> mode, the output curren
|
||||
of the device is controlled. This magnet can be configured into SICS with a
|
||||
command syntax like this:
|
||||
<BLOCKQUOTE>
|
||||
evfactory new name bruker Mac-PC Mac-port Mac-channel
|
||||
evfactory new name bruker localhost port channel
|
||||
</BLOCKQUOTE>
|
||||
</p>
|
||||
<p>
|
||||
name is a placeholder for the name of the device within SICS. A good
|
||||
suggestion (which will be used throughout the rest of the text) is magnet.
|
||||
bruker is the keyword for selecting the bruker driver. Mac-PC is the name of
|
||||
the Macintosh PC to which the controller has been connected, Mac-Port is the
|
||||
port number at which the Macintosh-PC's serial port server listens.
|
||||
Mac-channel is the RS-232 channel to which the controller has been
|
||||
bruker is the keyword for selecting the bruker driver. port is the
|
||||
port number at which the serial port server listens.
|
||||
channel is the RS-232 channel to which the controller has been
|
||||
connected. For example (at SANS):
|
||||
<pre>
|
||||
evfactory new magnet bruker lnsp25.psi.ch 4000 9
|
||||
evfactory new magnet bruker localhost 4000 9
|
||||
</pre>
|
||||
</p>
|
||||
<p>
|
||||
creates a new command magnet for a Bruker magnet Controller connected to
|
||||
serial port 9 at lnsp25.
|
||||
serial port 9.
|
||||
</p>
|
||||
In addition to the standard environment controller commands this magnet
|
||||
controller understands the following special commands:
|
||||
@ -540,60 +514,6 @@ a magnetic field. This is so in order to support SICS control logic.
|
||||
You can read values at all times explicitly using magnet current or
|
||||
magnet field.
|
||||
</p>
|
||||
<h3><a name="ltc11">The CryoFurnace.</a></h3>
|
||||
<p>
|
||||
The CryoFurnace at PSI is equipped with a Neocera LTC-11 temperature
|
||||
controller. This controller can control either an heater or an analag output
|
||||
channel. Futhermore a choice of sensors can be selected for controlling the
|
||||
device. The LTC-11 behaves like a normal SICS environment control device
|
||||
plus a few additional commands. An LTC-11 can be configured into SICS with
|
||||
the following command:
|
||||
<BLOCKQUOTE>
|
||||
evfactory new name ltc11 Mac-PC Mac-port Mac-channel
|
||||
</BLOCKQUOTE>
|
||||
</p>
|
||||
<p>
|
||||
name is a placeholder for the name of the device within SICS. A good
|
||||
suggestion is temperature.
|
||||
ltc11 is the keyword for selecting the LTC-11 driver. Mac-PC is the name of
|
||||
the Macintosh PC to which the controller has been connected, Mac-Port is the
|
||||
port number at which the Macintosh-PC's serial port server listens.
|
||||
Mac-channel is the RS-232 channel to which the controller has been
|
||||
connected. For example (at DMC):
|
||||
<pre>
|
||||
evfactory new temperature ltc11 lnsp18.psi.ch 4000 6
|
||||
</pre>
|
||||
</p>
|
||||
<p>
|
||||
creates a new command magnet for a LTC-11 temperature Controller connected to
|
||||
serial port 6 at lnsp18.
|
||||
</p>
|
||||
<p>
|
||||
The additional commands understood by the LTC-11 controller are:
|
||||
<dl>
|
||||
<dt>temperature sensor
|
||||
<dd> queries the current sensor used for temperature readout.
|
||||
<dt>temperature sensor val
|
||||
<dd> selects the sensor val for temperature readout.
|
||||
<dt>temperature controlanalog
|
||||
<dd> queries the sensor used for controlling the analog channel.
|
||||
<dt>temperature controlanalog val
|
||||
<dd> selects the sensor val for controlling the analog channel.
|
||||
<dt>temperature controlheat
|
||||
<dd> queries the sensor used for controlling the heater channel.
|
||||
<dt>temperature controlheat val
|
||||
<dd> selects the sensor val for controlling the heater channel.
|
||||
<dt>temperature mode
|
||||
<DD>queries if the LTC-11 is in analog or heater control mode.
|
||||
</dl>
|
||||
</p>
|
||||
<p>
|
||||
Further notes: As the CryoFurnace is very slow and the display at the
|
||||
controller becomes unusable when the temperature is read out to often, the
|
||||
LTC-11 driver buffers the last temperature read for 5 seconds. Setting the
|
||||
mode of the LTC-11 is possible by computer, but not yet fully understood and
|
||||
therefore unusable.
|
||||
</p>
|
||||
<h3><a name="euro">The Eurotherm Temperature Controller</a></h3>
|
||||
<p>
|
||||
At SANS there is a Eurotherm temperature controller for the sample heater.
|
||||
@ -601,23 +521,22 @@ At SANS there is a Eurotherm temperature controller for the sample heater.
|
||||
with the following command. The eurotherm needs to be connected with a
|
||||
nullmodem adapter.
|
||||
<BLOCKQUOTE>
|
||||
evfactory new name euro Mac-PC Mac-port Mac-channel
|
||||
evfactory new name euro computer port channel
|
||||
</BLOCKQUOTE>
|
||||
</p>
|
||||
<p>
|
||||
name is a placeholder for the name of the device within SICS. A good
|
||||
suggestion is temperature.
|
||||
euro is the keyword for selecting the Eurotherm driver. Mac-PC is the name of
|
||||
the Macintosh PC to which the controller has been connected, Mac-Port is the
|
||||
port number at which the Macintosh-PC's serial port server listens.
|
||||
Mac-channel is the RS-232 channel to which the controller has been
|
||||
euro is the keyword for selecting the Eurotherm driver. port is the
|
||||
port number at which the serial port server listens.
|
||||
channel is the RS-232 channel to which the controller has been
|
||||
connected. <b>WARNING:</b> The eurotherm needs a RS-232 port with an unusual
|
||||
configuration: 7bits, even parity, 1 stop bit. Currently only the SANS
|
||||
Macintosh port 13 (the last in the upper serial port connection box) is
|
||||
port 13 is
|
||||
configured like this! Thus, an example for SANS and the name temperature
|
||||
looks like:
|
||||
<pre>
|
||||
evfactory new temperature euro lnsp25.psi.ch 4000 13
|
||||
evfactory new temperature euro localhost 4000 13
|
||||
</pre>
|
||||
</p>
|
||||
<p>
|
||||
@ -671,14 +590,14 @@ read back but just the set value after ramping. This is a serious
|
||||
limitation because the computer cannot recognize a faulty power supply
|
||||
or magnet. The EL755 is connected to SICS with the command:
|
||||
<BLOCKQUOTE>
|
||||
evfactory new name el755 Mac-PC Mac-port Mac-channel index
|
||||
evfactory new name el755 localhost port channel index
|
||||
</BLOCKQUOTE>
|
||||
with Mac-PC, Mac-port and Mac-channel being the usual data items for
|
||||
describing the location of the EL755-controller at the Macintosh
|
||||
with port and channel being the usual data items for
|
||||
describing the location of the EL755-controller at the
|
||||
serial port server. index is special and is the number of the power
|
||||
supply to which the magnet is connected. An example:
|
||||
<pre>
|
||||
evfactory new maggi el755 lnsa09.psi.ch 4000 5 3
|
||||
evfactory new maggi el755 localhost 4000 5 3
|
||||
</pre>
|
||||
connects to power supply 3 at the EL755-controller connected to lnsa09
|
||||
at channel 5. The magnet is then available in the system as maggi. No
|
||||
@ -718,6 +637,90 @@ configures a magnet named maggi which is connectd to port 16 at the
|
||||
terminal server psts224. maggi can now be read and driven like any
|
||||
other environment device.
|
||||
</p>
|
||||
<h3><a name="dilu">Old Dilution</a> Cryostat (Obsolete)</h3>
|
||||
<p>
|
||||
This is a large ancient device for reaching very low temperatures. This
|
||||
cryostat can be configured into SICS with the command:
|
||||
<pre>
|
||||
EVFactory new Temp dillu computer port channel table.file
|
||||
</pre>
|
||||
Temp is the name of the dilution controller command in SICS, dillu is the
|
||||
keyword which selects the dilution driver, computer, port and channel are
|
||||
the parameters of the Macintosh-PC running the serial port server program.
|
||||
table.file is the fully qualified name of a file containing a translation
|
||||
table for this cryostat. The readout from the dilution controller is a
|
||||
resistance. This table allows to interpolate the temperature from the
|
||||
resistance measurements and back. Example:
|
||||
<pre>
|
||||
evfactory new temperature dillu lnsp19.psi.ch 4000 1 dilu.tem
|
||||
</pre>
|
||||
installs a new dilution controller into SICS. This controller is connected
|
||||
to port 1 at the Macintos-PC with the newtwork adress lnsp19.psi.ch. On this
|
||||
macintosh-PC runs a serial port server program listening at TCP/IP port
|
||||
4000. The name of the translation table file is dilu.tem.
|
||||
</p>
|
||||
<p>
|
||||
The dilution controller has no special commands, but two caveats: As of
|
||||
current (October 1998) setting temperatures does not work due to problems
|
||||
with the electronics. Second the dilution controller MUST be connected to
|
||||
port 1 as only this port supports the 4800 maximum baud rate this device
|
||||
digests.
|
||||
</p>
|
||||
<h3><a name="ltc11">Old CryoFurnace Controller (Obsolete)</a></h3>
|
||||
<p>
|
||||
The CryoFurnace at PSI is equipped with a Neocera LTC-11 temperature
|
||||
controller. This controller can control either an heater or an analag output
|
||||
channel. Futhermore a choice of sensors can be selected for controlling the
|
||||
device. The LTC-11 behaves like a normal SICS environment control device
|
||||
plus a few additional commands. An LTC-11 can be configured into SICS with
|
||||
the following command:
|
||||
<BLOCKQUOTE>
|
||||
evfactory new name ltc11 computer port channel
|
||||
</BLOCKQUOTE>
|
||||
</p>
|
||||
<p>
|
||||
name is a placeholder for the name of the device within SICS. A good
|
||||
suggestion is temperature.
|
||||
ltc11 is the keyword for selecting the LTC-11 driver. Computer is the name of
|
||||
the computer running David Maden's SerPortServer program, port is the
|
||||
port number at which the SerPortServer program listens.
|
||||
Channel is the RS-232 channel to which the controller has been
|
||||
connected. For example (at DMC):
|
||||
<pre>
|
||||
evfactory new temperature ltc11 localhost 4000 6
|
||||
</pre>
|
||||
</p>
|
||||
<p>
|
||||
creates a new command magnet for a LTC-11 temperature Controller connected to
|
||||
serial port 6 at lnsp18.
|
||||
</p>
|
||||
<p>
|
||||
The additional commands understood by the LTC-11 controller are:
|
||||
<dl>
|
||||
<dt>temperature sensor
|
||||
<dd> queries the current sensor used for temperature readout.
|
||||
<dt>temperature sensor val
|
||||
<dd> selects the sensor val for temperature readout.
|
||||
<dt>temperature controlanalog
|
||||
<dd> queries the sensor used for controlling the analog channel.
|
||||
<dt>temperature controlanalog val
|
||||
<dd> selects the sensor val for controlling the analog channel.
|
||||
<dt>temperature controlheat
|
||||
<dd> queries the sensor used for controlling the heater channel.
|
||||
<dt>temperature controlheat val
|
||||
<dd> selects the sensor val for controlling the heater channel.
|
||||
<dt>temperature mode
|
||||
<DD>queries if the LTC-11 is in analog or heater control mode.
|
||||
</dl>
|
||||
</p>
|
||||
<p>
|
||||
Further notes: As the CryoFurnace is very slow and the display at the
|
||||
controller becomes unusable when the temperature is read out to often, the
|
||||
LTC-11 driver buffers the last temperature read for 5 seconds. Setting the
|
||||
mode of the LTC-11 is possible by computer, but not yet fully understood and
|
||||
therefore unusable.
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
@ -24,19 +24,20 @@ these SICS client programs. SICS Clients and the SICServer communicate
|
||||
with each other through the TCP/IP network.
|
||||
</p>
|
||||
<p>
|
||||
Currently these SICS clients are available:
|
||||
Currently the following SICS clients are available:
|
||||
<uL>
|
||||
<li> A command line control client for sending commands to the SICS
|
||||
server and displaying its repsonses.
|
||||
<li> A status display for the powder diffractometers DMC and HRPT.
|
||||
<li> A status display for TOPSI.
|
||||
<li> A status display for SANS.
|
||||
<li> A status display for SANS and SANS2.
|
||||
<li> A status display for FOCUS.
|
||||
<li> A AMOR control and status program.
|
||||
<li> A triple axis control and status program.
|
||||
<li> A SICS variable watcher. This application graphically logs the
|
||||
change of a SICS variable over time. Useful for monitoring for
|
||||
instance temperature controllers.
|
||||
<li>A graphical client for TRICS.
|
||||
</ul>
|
||||
</p>
|
||||
<p>
|
||||
@ -71,12 +72,26 @@ following commands at the command prompt:
|
||||
<DD> for the triple axis status display and control application.
|
||||
<DT>varwatch &
|
||||
<DD> for the variable watcher.
|
||||
<dt>trics-&
|
||||
<dd>for the starting the TRICS graphical client.
|
||||
</dl>
|
||||
On a PC you may find icons for starting the different programs on the
|
||||
desktop.
|
||||
Each of these clients has usage instructions online which can be displayed
|
||||
through the help/about menu entry.
|
||||
</p>
|
||||
<p>
|
||||
Another option to start SICS clients is the Java Webstart mechanism
|
||||
which is available for most platforms. Java webstart requires both
|
||||
Java and Java webstart to be installed on the computer running the
|
||||
client. Then clients can be started directly from a WWW-page. The
|
||||
advantage is that clients are automatically updated in this system as
|
||||
soon as new version have been copied to the WWW-site. Installation
|
||||
instructions for Java webstart and links to start all SICS clients
|
||||
though this mechanism can be found at:
|
||||
<a href="http://lns00.psi.ch/sics/wstart"> the SICS webstart</a>
|
||||
page. This service is only accessible within the PSI network.
|
||||
</p>
|
||||
<h2>Connecting</h2>
|
||||
<p>
|
||||
After startup any SICS client is not connected to a SICS server and thus not
|
||||
@ -101,11 +116,11 @@ the SICS server log in as the instrument user at the instrument computer and
|
||||
invoke the appropriate command to start the server. These are:
|
||||
<dl>
|
||||
<DT>DMC
|
||||
<DD>Computer = lnsa05,User = DMC
|
||||
<DD>Computer = lnsa05, User = DMC
|
||||
<DT>TOPSI
|
||||
<DD>Computer = lnsa07,User = TOPSI
|
||||
<DD>Computer = topsi, User = TOPSI
|
||||
<DT>SANS
|
||||
<DD>Computer = lnsa10,User = SANS
|
||||
<DD>Computer = sans, User = SANS
|
||||
<DT>TRICS
|
||||
<DD>Computer = lnsa18, User = TRICS
|
||||
<DT>HRPT
|
||||
@ -115,7 +130,7 @@ invoke the appropriate command to start the server. These are:
|
||||
<DT>AMOR
|
||||
<DD>Computer = lnsa14, User = AMOR
|
||||
<DT>TASP
|
||||
<DD>Computer = lnsa12, User = TASP
|
||||
<DD>Computer = tasp, User = TASP
|
||||
<DT>POLDI
|
||||
<DD>Computer = poldi, User = POLDI
|
||||
</dl>
|
||||
|
@ -11,7 +11,27 @@
|
||||
<p>
|
||||
<b> resetserver </b> resets the server after an interrupt.</p>
|
||||
<p>
|
||||
<b> dir </b> a single word command which lists all objects available in the SICS system in its current configuration.</p>
|
||||
<b> dir </b> a command which lists objects available in the SICS
|
||||
system. Dir without any options prints a list of all objects. The
|
||||
list can be restricted with:
|
||||
<dl>
|
||||
<dt>dir var
|
||||
<dd>prints all SICS primitive variables
|
||||
<dt>dir mot
|
||||
<dd>prints a list of all motors
|
||||
<dt>dir inter driv
|
||||
<dd> prints a list of all drivable objects. This is more then motors
|
||||
and includes virtual motors such as environment devices and wavelength
|
||||
as well.
|
||||
<dt>dir inter count
|
||||
<dd>Shows everything which can be counted upon.
|
||||
<dt>dir inter env
|
||||
<dd>Shows all currently configured environment devices.
|
||||
<dt>dir match wildcard
|
||||
<dd>lists all objects which match the wildcard string given in
|
||||
wildcard.
|
||||
</dl>
|
||||
</p>
|
||||
<p>
|
||||
<b> status </b> A single word command which makes SICS print its current
|
||||
status. Possible return values can be:
|
||||
@ -45,5 +65,12 @@ above and restores SICS to the state it was in when the status was saved with
|
||||
backup. If no file argument is given the system default file gets
|
||||
read.
|
||||
</p>
|
||||
<p>
|
||||
<b>killfile</b> decrements the data number used for SICS file writing
|
||||
and thus consequently overwrites the last datafile. This is useful
|
||||
when useless data files have been created during tests. As this is
|
||||
critical command in normal user operations, this command requires
|
||||
managers privilege.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
1
doc/user/tascommands.html
Normal file
1
doc/user/tascommands.html
Normal file
@ -0,0 +1 @@
|
||||
<h2><a name="Commands">TASMAD Commands</a></h2>
|
@ -72,9 +72,9 @@
|
||||
e.g. ALF1-ALF4 (carry out command given on variables between ALF1 and
|
||||
ALF4 in storage order; see section V)
|
||||
e.g. DM,ALF1-ALF4,SS,DA (a combination of the above) Variables separated
|
||||
by commas need not be typed in their order of storage in THE Program.
|
||||
by commas need not be typed in their order of storage in the program.
|
||||
|
||||
Note : that for this type of syntax (type a) the only acceptable
|
||||
Note : that for this type of syntax (type A) the only acceptable
|
||||
variable separators are ' ' (i.e. a space), ',' and '-' (' ' and ','
|
||||
are equivalent).
|
||||
|
||||
@ -87,9 +87,9 @@
|
||||
variables in storage [QK, QL] take the values 0 and 2 )
|
||||
e.g. QH=1,0,2.0,AS=3.24,CC=90 (a combination of the above)
|
||||
|
||||
In commands involving this construction type (B) THE Program echoes
|
||||
the variable names and values it has understood.
|
||||
Possible separators are ',' and ' ' ('space')
|
||||
In commands involving this construction type (B) the program echoes
|
||||
the variable names and values it has understood.
|
||||
Possible separators are ',' and ' ' ('space')
|
||||
|
||||
There is a third type of commands which requires no parameters. These
|
||||
commands are:-
|
||||
@ -159,7 +159,7 @@
|
||||
<pre>
|
||||
|
||||
CO(UNT) : Counts for a given preset TIme or MoNitor.
|
||||
This is a command of type b syntax. If the command is issued alone,
|
||||
This is a command of type B syntax. If the command is issued alone,
|
||||
the preset used will be that most recently set. However, the preset
|
||||
may also be specified on the same line as the COUNT command.
|
||||
(For use of COnt in a P.A. file, see SCan and PA).
|
||||
@ -223,11 +223,11 @@
|
||||
new position and the appropriate variable is altered in the memory.
|
||||
|
||||
A DRIVE command will fail (non destructively) if:
|
||||
l a motor or power supply is protected or fixed
|
||||
l a software or hard limit is exceeded; the soft limits may be changed
|
||||
- a motor or power supply is protected or fixed
|
||||
- a software or hard limit is exceeded; the soft limits may be changed
|
||||
if necessary using the SET command provided the value desired is
|
||||
within the allowed range.
|
||||
l there is ambiguity among the driven variables.
|
||||
- there is ambiguity among the driven variables.
|
||||
e.g. DR KI=2.662,A2=40<CR>
|
||||
sets two different targets for A2 and fails.
|
||||
|
||||
@ -332,7 +332,7 @@
|
||||
(within a certain tolerance) to the positions.
|
||||
Clear exceptions are for a power supply which has
|
||||
been turned disabled, the abort of a DRive via
|
||||
^C^C and, for instance, the incident wavevector
|
||||
Interrupt and, for instance, the incident wavevector
|
||||
after a drive of A1 or A2.
|
||||
</pre>
|
||||
<h3><a name="LOG">LOG</a></h3>
|
||||
@ -379,7 +379,7 @@
|
||||
non-zero.(This is because it no longer behaves as a flipper.)
|
||||
|
||||
Note that the ON and OFF commands are the only ones which can be used
|
||||
to change F1 and F2. Both ON and OFF are of type Asyntax.
|
||||
to change F1 and F2. Both ON and OFF are of type A syntax.
|
||||
|
||||
|
||||
</pre>
|
||||
@ -398,8 +398,9 @@
|
||||
be printed for every point in every scan until disabled.
|
||||
Typing OU with NO following variables will stop the output of ALL
|
||||
variables apart from scanned ones.
|
||||
Type A syntax. A variable that has to be output because it is scanned a
|
||||
nd has also been selected with the OUT command will only be output once.
|
||||
Type A syntax. A variable that has to be output because it is scanned
|
||||
and has also been selected with the OUT command will only be output
|
||||
once.
|
||||
|
||||
e.g. OU A3,A4<CR>
|
||||
A3 & A4 will be printed in addition to the scan variables.
|
||||
@ -546,23 +547,9 @@
|
||||
|
||||
2) data files :
|
||||
|
||||
All of this data is also output to a disk file. This file is called
|
||||
either TEMP##.SCN or SV####.SCN where # represents a digit between 0
|
||||
and 9. Both types of data files are used sequentially and thus
|
||||
periodically overwritten but obviously the TEMP##.SCN files disappear
|
||||
sooner.
|
||||
|
||||
A scan initiated from the terminal will be stored in a TEMP file
|
||||
(unless the appropriate SWITCH is on ) while scans input from .JOB files
|
||||
are always saved permanently. The TEMP files are lost ( but see SAVE).
|
||||
For more details on data files see section VI below.
|
||||
|
||||
All SV####.SCN files are copied to the mainframe computer automatically
|
||||
and transfered to the SPECTRA database for Backup and archiving. They
|
||||
can be accessed by the SPECTRA program or by the 3-axis programs (PKFIT
|
||||
or FILING).
|
||||
Programs for manipulating data files are described in another manual
|
||||
(PKFIT, FILING, LOOK, LIST, LHEAD etc.)
|
||||
All tas####.dat files are copied to the mainframe computer
|
||||
automatically.
|
||||
|
||||
3) Scan output :
|
||||
|
||||
@ -602,7 +589,7 @@
|
||||
|
||||
As with the DRIVE command, scans in Q-E space are carried out at fixed
|
||||
KI (FX=1) or fixed KF (FX=2). During a scan with Kf fixed (i.e.FX=2)
|
||||
THE Program will automatically check and adjust A5 and A6; for Ki
|
||||
the program will automatically check and adjust A5 and A6; for Ki
|
||||
fixed (FX=1) however, MAD Program will not adjust at check and adjust
|
||||
at every point A1 and A2 because these variables are not likely to
|
||||
move in a Ki-fix scan.
|
||||
@ -680,9 +667,9 @@
|
||||
described below. In response to the command <em>SW</em>, MAD
|
||||
generates output of the following form:
|
||||
|
||||
1 Powder Mode OFF
|
||||
2 Polarization mode OFF
|
||||
Give Switch Number to change or RETURN to finish >
|
||||
1 Powder Mode OFF
|
||||
2 Polarization mode OFF
|
||||
Give Switch Number to change or RETURN to finish >
|
||||
|
||||
To change a value of one switch, enter the appropriate number
|
||||
(from 1 to 2) and hit <Return>. To make no change, type
|
||||
@ -847,7 +834,7 @@ however, corresponds to a transmission minimum for Ki neutrons.
|
||||
by SET.
|
||||
|
||||
The following list gives the variable identifiers and definitions,
|
||||
where the order is as the variables are stored in THE Program.
|
||||
where the order is as the variables are stored in the program.
|
||||
|
||||
|
||||
P.A Variables : Variables marked with an asterisk are not recognized
|
||||
|
1
doc/user/tasvariables.html
Normal file
1
doc/user/tasvariables.html
Normal file
File diff suppressed because one or more lines are too long
@ -345,6 +345,7 @@ H H L
|
||||
%html histogram.htm 2
|
||||
%html nextrics.htm 2
|
||||
%html peaksearch.htm 2
|
||||
%html lowmax.htm 2
|
||||
%html trscan.htm 2
|
||||
|
||||
%html psddata.htm 1
|
||||
|
@ -11,6 +11,7 @@ TRICS with a PSD requires the following special features.
|
||||
histogram memory</a>.
|
||||
<li><a href="nextrics.htm">NeXus</a> data handling for TRICS.
|
||||
<li>A <a href="peaksearch.htm">peak search</a> command.
|
||||
<li>A <a href="lowmax.htm">local maximum search</a> command.
|
||||
<li>A TRICS specific <a href="trscan.htm">count and scan</a> command.
|
||||
</ul>
|
||||
</p>
|
||||
|
@ -41,7 +41,11 @@ This means the log file has been started at August, 8, 2001 at 00:01:01.
|
||||
There is a new log file daily. Load appropriate files into the editor and
|
||||
look what really happened.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Another good ideas is to use the unix command grep on assorted log
|
||||
files. A grep for the strings ERROR or WARNING will more ofteh then
|
||||
not give an indication for the nature of the problem.
|
||||
</p>
|
||||
<p>
|
||||
The log files show you all commands given and all the responses of the system.
|
||||
Additionally there are hourly time stamps in the file which allow to narrow
|
||||
@ -63,12 +67,8 @@ The log files show you all commands given and all the responses of the system.
|
||||
<dt>EL737__BAD_BSY
|
||||
<dd>A counting operation was aborted while the beam was off. Unfortunately,
|
||||
the counter box does not respond to commands in this state and ignores the
|
||||
stop command sent to it during the abort operation. This can be resolved by
|
||||
the command:
|
||||
<pre>
|
||||
counter stop
|
||||
</pre>
|
||||
when the beam is on again.
|
||||
stop command sent to it during the abort operation. This can be
|
||||
safely ignored, SICS fixes this condition.
|
||||
</dl>
|
||||
</p>
|
||||
<h2>Starting SICS</h2>
|
||||
|
34
doc/user/trscan.htm
Normal file
34
doc/user/trscan.htm
Normal file
@ -0,0 +1,34 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>TRICS specific Count and Scan Command </TITLE>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
<H1>PSD-TRICS Count and Tricsscan Command</H1>
|
||||
<P>
|
||||
Two special commands have been defined for TRICS with a PSD:
|
||||
<dl>
|
||||
<dt>count <tt>mode preset </tt>
|
||||
<dd>counts with all three detectors. The parameter mode defines which
|
||||
counting mode is used, supported are <b>preset</b> for counting up to a
|
||||
preset monitor or <b>timer</b> for counting for a specified time intervall.
|
||||
The second prameter preset is either the preset monitor or the preset
|
||||
counting time, depending on the mode choosen. Both parameters are
|
||||
optional, if they are notc specified values from the last run will be used.
|
||||
count does not store any data.
|
||||
<dt>tricsscan <tt>start step np mode preset</tt>
|
||||
<dd>This command creates a new data file and then performs a scan in omega,
|
||||
storing meausured data after each step. <tt>start step np</tt> define the
|
||||
scan range in omega. Start is the start position, step the step width to
|
||||
use and np is the number of steps to do. The optional parameters mode and
|
||||
preset have the same meaning as in the count command described above.
|
||||
Mode and preset how data is collected at each step in omega.
|
||||
<dt>psdrefscan filename step np mode preset
|
||||
<dd>reads reflection HKL values from file filename and performs
|
||||
tricsscans for each reflection. These will be done eith step width
|
||||
step, the number of steps np with counting mode mode and a preset of
|
||||
preset. These parameters have the same meaning as described above.
|
||||
</dl>
|
||||
</P>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
104
doc/user/userrefman
Normal file
104
doc/user/userrefman
Normal file
@ -0,0 +1,104 @@
|
||||
\documentclass[12pt,a4paper]{report}
|
||||
%%\usepackage[dvips]{graphics}
|
||||
%%\usepackage{epsf}
|
||||
\setlength{\textheight}{24cm}
|
||||
\setlength{\textwidth}{16cm}
|
||||
\setlength{\headheight}{0cm}
|
||||
\setlength{\headsep}{0cm}
|
||||
\setlength{\topmargin}{0cm}
|
||||
\setlength{\oddsidemargin}{0cm}
|
||||
\setlength{\evensidemargin}{0cm}
|
||||
\setlength{\hoffset}{0cm}
|
||||
\setlength{\marginparwidth}{0cm}
|
||||
|
||||
\begin{document}
|
||||
%html -d hr " "
|
||||
%html -s report
|
||||
\begin{center}
|
||||
\begin{huge}
|
||||
SICS Master User Manual\\
|
||||
\end{huge}
|
||||
\today \\
|
||||
Dr. Mark K\"onnecke \\
|
||||
Labor f\"ur Neutronenstreuung\\
|
||||
Paul Scherrer Institut\\
|
||||
CH--5232 Villigen--PSI\\
|
||||
Switzerland\\
|
||||
\end{center}
|
||||
\clearpage
|
||||
\clearpage
|
||||
\tableofcontents
|
||||
\clearpage
|
||||
|
||||
\chapter{Introduction}
|
||||
This is the master user manual for SICS. It gives an overview over all
|
||||
command implemented, independent of a specific instrument. This is to
|
||||
be used as the source for more instrument specific user manuals and
|
||||
gives an overview of the commands available within SICS. Please note,
|
||||
that many instruments have special commands realized as scripts in the
|
||||
SICS built in scripting language. Only the most common of such
|
||||
commands are listed here.
|
||||
|
||||
\chapter{System Commands and Concepts}
|
||||
%html sicsinvoc.htm 2
|
||||
%html basic.htm 2
|
||||
%html logging.htm 2
|
||||
%html logbook.htm 3
|
||||
%html commandlog.htm 3
|
||||
%html batch.htm 2
|
||||
%html macro.htm 3
|
||||
%html buffer.htm 3
|
||||
%html token.htm 2
|
||||
%html system.htm 2
|
||||
%html config.htm 2
|
||||
%html madsim.htm 2
|
||||
%html trouble.htm 2
|
||||
|
||||
|
||||
\chapter{Hardware Related Commands}
|
||||
%html drive.htm 1
|
||||
%html motor.htm 2
|
||||
%html chopper.htm 2
|
||||
%html counter.htm 2
|
||||
%html count.htm 2
|
||||
%html histogram.htm 2
|
||||
%html samenv.htm 2
|
||||
%html ctrl.htm 2
|
||||
%html velocity.htm 2
|
||||
%html velolambda.htm 2
|
||||
|
||||
\chapter{Common User Commands}
|
||||
%html topscan.htm 2
|
||||
%html hkl.htm 2
|
||||
%html optimise.htm 2
|
||||
%html xytable.htm 2
|
||||
%html lowmax.htm 2
|
||||
|
||||
\chapter{PSI Specific Commands}
|
||||
\section{Commands specific to the TOF--diffractometer FOCUS}
|
||||
%html focussps.htm 3
|
||||
%html fowrite.htm 3
|
||||
|
||||
\section{Reflectometer AMOR specific Commands}
|
||||
%html amor2t.htm 3
|
||||
%html amorstore.htm 3
|
||||
%html amortof.htm 3
|
||||
|
||||
\section{TRICS Specific Commands}
|
||||
%html hklscan.htm 3
|
||||
%html trscan.htm 3
|
||||
%html mesure.htm 3
|
||||
%html nextrics.htm 3
|
||||
%html peaksearch.htm 3
|
||||
|
||||
\section{Fourier Diffractometer POLDI Specific Commands}
|
||||
%html poldiscan.htm 2
|
||||
%html poldiwrite.htm 3
|
||||
|
||||
\section{Triple Axis Spectrometer Specific Commands}
|
||||
%html tasmad.html 3
|
||||
%html tasvariables.html 3
|
||||
%html tascommands.html 3
|
||||
|
||||
|
||||
\end{document}
|
359
doc/user/xds.htm
Normal file
359
doc/user/xds.htm
Normal file
@ -0,0 +1,359 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>TRICS Data Analysis with XDS</TITLE>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
<H1>TRICS Data Analysis with XDS</H1>
|
||||
<P>
|
||||
A set of programs exist for TRICS data analysis which have been derived from
|
||||
the XDS package designed and written by Wolfgang Kabsch. Due to the different
|
||||
diffraction geometry at TRICS the program had to be subdivided. Data Analysis
|
||||
with this system requires four steps:
|
||||
<ol>
|
||||
<li>Location of strong diffraction spots with the program <b>spots</b>.
|
||||
<li>Indexing of diffraction spots and refining of a UB matrix with programs of
|
||||
your choice.
|
||||
<li>Integration of the diffraction spots with the program <b>reflex</b>.
|
||||
<li>Optionally, reflections collected in various runs can be merged
|
||||
with the program <b>xscale</b>.
|
||||
</ol>
|
||||
The main limitation of this software is that only reflections at normal
|
||||
lattice positions can be analysed. Magnetic or superstructure reflections
|
||||
will not be integrated due to the fact that XDS uses predicted reflection
|
||||
positions for integration and has no facilities to predict either magnetic
|
||||
or superstructure reflections.
|
||||
</P>
|
||||
<h2>LEGAL STUFF</h2>
|
||||
<p>
|
||||
The programs <b>spots</b>, <b>reflex</b>and <b>xscale</b> are no
|
||||
official versions of XDS. The responsability for these programs lies
|
||||
with PSI and not with Wolfang
|
||||
Kabsch. Binaries of the above mentioned programs may be distributed, but
|
||||
according to an agreement with Wolgang Kabsch the source code may not be
|
||||
redistributed. If you are interested in an official version of XDS, please
|
||||
contact Wolgang Kabsch directly.
|
||||
</p>
|
||||
|
||||
<h2><b>Spots</b> and <b>reflex</b> Control File</h2>
|
||||
<p>
|
||||
The programs <b>spots</b> and <b>reflex</b> both require a control file
|
||||
to be specified as a command line parameter. The format of this control
|
||||
file resembles a Windows .ini file and is common for both programs. The syntax
|
||||
is: keyword = value.
|
||||
</p>
|
||||
|
||||
<h2>Running <b>spots</b></h2>
|
||||
<p>
|
||||
The purpose of <b>spots</b> is to search for strong diffraction spots
|
||||
in the data and write them out in a format suitable for
|
||||
indexing. spots can be started by typing:
|
||||
<pre>
|
||||
spots controlfile
|
||||
</pre>
|
||||
at the unix command prompt. All necessary parameters live in the
|
||||
control file. spots recognizes the following keywords in the control
|
||||
file:
|
||||
<dl>
|
||||
<dt>numfiles
|
||||
<dd>The number of files to process.
|
||||
<dt>fileXX
|
||||
<dd>Replace XX by the number of the file. For instance file00 is the
|
||||
first file to process. The value for this keyword is the filename to
|
||||
process.
|
||||
<dt>numdetectors
|
||||
<dd>The number of detectors to process. TRICS can have up to three
|
||||
detector banks, if the electronics group finally makes them available
|
||||
by an act of grace.
|
||||
<dt>det1dist, det2dist, det3dist
|
||||
<dd> The respective distances of the detectors from the sample
|
||||
positions.
|
||||
<dt>det1x, det2x, det3x
|
||||
<dd>The number of pixels each detector supports in the x-direction.
|
||||
<dt>det1y, det2y, det3y
|
||||
<dd>The number of pixels each detector supports in the y-direction.
|
||||
<dt>
|
||||
<dt>det1pixx, det2pixx,det3pixx
|
||||
<dd>The size of a detector pixel in x-direction in mm for each detector.
|
||||
<dt>det1pixy, det2pixy,det3pixy
|
||||
<dd>The size of a detector pixel in y-direction in mm for each
|
||||
detector.
|
||||
<dt>wavelength
|
||||
<dd>The neutron wavelength.
|
||||
<dt>bifile
|
||||
<dd>Switches on the writing of reflection positions converted to
|
||||
bissecting positions as from a normal four circle diffractometer. The
|
||||
value is the name of the file to which to write the list.
|
||||
<dt>nbfile
|
||||
<dd>Switches on the writing of reflection positions converted to
|
||||
normal beam positions as from a normal beamdiffractometer. The
|
||||
value is the name of the file to which to write the list.
|
||||
<dt>xyzfile
|
||||
<dd>Switches on the writing of reflection positions in XYZ format. The
|
||||
value is the name of the file to which to write the list.
|
||||
</dl>
|
||||
bifile, nbfile or xyzfile are choices. Chhose the one which fits best
|
||||
with your preferred indexing program.
|
||||
</p>
|
||||
<h2>Indexing and UB Matrix Refinement</h2>
|
||||
<p>
|
||||
For indexing a variety of programs are available:
|
||||
<ul>
|
||||
<li>The ancient combination of index and rafin from ILL. For a
|
||||
description see the four circle single detector section.
|
||||
<li><b>orient</b> A modern indexing program extracted from Difrac. It
|
||||
has originally been written by R. A. Jacobsen, Ames Research
|
||||
laboratory. orient will not only index the reflections found and
|
||||
determine a UB matrix. It will also refine the UB matrix based on the
|
||||
reflections given to it and tries to determine the space group as
|
||||
well.
|
||||
</ul>
|
||||
</p>
|
||||
<h3>Running <b>orient</b></h3>
|
||||
<p>
|
||||
In order to start orient, type <b>orient</b> at the unix prompt. A
|
||||
selection dialog for the file type will show up. Select 2, then give
|
||||
the path to the file created with the spots option bifile. You will
|
||||
also be asked for the neutron wavelength. The following dialogs are
|
||||
self explaining. When orient finishes, the new UB matrix can be found
|
||||
in either the LPT1 or printer.out file.
|
||||
</p>
|
||||
|
||||
<h2>Running <b>reflex</b></h2>
|
||||
<p>
|
||||
<b>reflex</b> is controlled through the same style control.ini file as
|
||||
used by spots. The options specified for <b>spots</b> have to be
|
||||
present in the control file for reflex as well. Additionally the
|
||||
following options are required:
|
||||
<dl>
|
||||
<dt>ub1, ub2, ub3
|
||||
<dd>The three rows of the UB-matrix as determined by one of the
|
||||
indexing programs.
|
||||
<dt>axis=0 0 -1
|
||||
<dd>These are the coordinates of the rotation axis in XDS's own
|
||||
coordinate system. Leave this at the values stated,
|
||||
everything else is shit if you are using TRICS.
|
||||
<dt>beam=0 1 0
|
||||
<dd>These are the coordinates of the incoming neutron beam in XDS's own
|
||||
coordinate system. Leave this at the values stated,
|
||||
everything else is shit if you are using TRICS.
|
||||
<dt>polarisation=.5 1 0 0
|
||||
<DD>Some values for handling X-ray polarisation. Leave at the values
|
||||
given.
|
||||
<dt>spacegroup
|
||||
<dd>Set this to the space group selected. Expected is the number of
|
||||
the space group as given in the international tables.
|
||||
<dt>divergence
|
||||
<dd>The beam divergence. See below for a comment.
|
||||
<dt>mosaic
|
||||
<dd>The crystal mosaic. mosaic and divergence together determine the
|
||||
size of the box in reciprocal space which will be integrated for each
|
||||
reflection. reflex writes a representation of the integration box and
|
||||
of the reflection to its output file (PROFIT.LP). Inspect this
|
||||
carefully. If reflections are cut of in the reflection box or the
|
||||
reflection box is to large, modify these values in order to achieve a
|
||||
good fit. As more experience is gathered, the instrument scientist
|
||||
will be able to provide you with reasonable defaults for these values.
|
||||
</dl>
|
||||
reflex is run by typing <b> reflex control.ini</b> at the unix
|
||||
prompt. control.ini is the name of the control file. PROFIT.LP is the
|
||||
main log file which shows what has been done. PROFIT.HKL is a binary
|
||||
file holding the reflections integrated.
|
||||
</p>
|
||||
|
||||
<h2>Running <b>xscale</b></h2>
|
||||
<p>
|
||||
xscale has not been modified since it has been received from
|
||||
W. Kabsch. Therefore the original documentation, reproduced below is
|
||||
still valid.
|
||||
<pre>
|
||||
C***********************************************************************
|
||||
C********************** DESCRIPTION OF FILES ***************************
|
||||
C***********************************************************************
|
||||
C *
|
||||
C XSCALE.INP (formatted sequential) *
|
||||
C ========== *
|
||||
C *
|
||||
C This file contains the input parameters you have to provide to run *
|
||||
C the XSCALE program.(free format) *
|
||||
C *
|
||||
C line # DESCRIPTION OF INPUT PARAMETERS *
|
||||
C *
|
||||
C 1 Resolution shell limits (Angstrom). Only the high resolution*
|
||||
C limit of each shell is given. Up to NRES (20) resolution *
|
||||
C shells will be accepted. The shell limits must be specified *
|
||||
C in decreasing order. The resolution shells are used to *
|
||||
C report statistical properties of the data sets as a function*
|
||||
C of resolution. *
|
||||
C 2 Space group number and unit cell parameters *
|
||||
C (Angstrom and degrees) *
|
||||
C 3... Each line describes a reflection file used for scaling *
|
||||
C and contains the following items: *
|
||||
C >Optional control character - or * of the following meaning *
|
||||
C -: ignore this data set (this line will be skipped) *
|
||||
C *: put all data sets to the same scale as this one; *
|
||||
C default is the first data set. *
|
||||
C >File name of data set used for scaling. *
|
||||
C The name must not be longer than 50 characters and *
|
||||
C intervening blanks are not allowed. *
|
||||
C >File type must be one of the three following keywords *
|
||||
C DIRECT: the file is of type XDS.HKL as generated by XDS. *
|
||||
C UNIQUE: the file is of type UNIQUE.HKL as produced by XDS.*
|
||||
C OLDHKL: the ASCII file consists of free format records *
|
||||
C H,K,L,INTENSITY,SIGMA *
|
||||
C The standard deviation SIGMA may be omitted and *
|
||||
C is estimated then as SIGMA=0.1*INTENSITY *
|
||||
C Reflection data files of type UNIQUE or OLDHKL *
|
||||
C may be unsorted and the reflection indices need *
|
||||
C not be the asymmetric indices. This simplifies *
|
||||
C the scaling of data sets generated by other *
|
||||
C programs than XDS. *
|
||||
C >Resolution window for accepting reflections from this file *
|
||||
C low resolution limit (Angstrom) *
|
||||
C high resolution limit (Angstrom) *
|
||||
C >Frame separation (mandatory for data sets of type DIRECT) *
|
||||
C specifying the maximum number of frames between FRIEDEL- *
|
||||
C pairs to be included in the estimated anomalous intensity *
|
||||
C difference. *
|
||||
C >Number of batches (optional for data sets of type DIRECT) *
|
||||
C This number gives the number of subdivisions of the *
|
||||
C rotation range covering the data set. Typically, it is *
|
||||
C the total rotation range divided by 2.5...5 degrees, but *
|
||||
C should not exceed a value of 36. This leads to at most *
|
||||
C 9*36=324 scaling factors for a single data set. The total *
|
||||
C number of scaling factors from all data sets together *
|
||||
C must not exceed the value given by "MAXFAC" (1000). *
|
||||
C >SAVE=file-name (optional); default file-name is XSCALE.HKL *
|
||||
C The type of the SAVE-file produced is UNIQUE. Symmetry *
|
||||
C related reflections from input data sets sharing the same *
|
||||
C SAVE-file are used after scaling to estimate a mean *
|
||||
C intensity, an anomalous intensity difference, and their *
|
||||
C standard deviations. Scaling factors for each data set *
|
||||
C are determined from all symmetry related reflections *
|
||||
C regardless whether they go to different SAVE-files. *
|
||||
C *
|
||||
C***********************************************************************
|
||||
C *
|
||||
C XSCALE.LP (formatted sequential) *
|
||||
C ========= *
|
||||
C *
|
||||
C This file contains the printed messages and results from running the *
|
||||
C XSCALE-program. *
|
||||
C *
|
||||
C***********************************************************************
|
||||
C *
|
||||
C Description of XSCALE input file format of type DIRECT as produced *
|
||||
C by XDS. *
|
||||
C *
|
||||
C XDS.HKL (unformatted direct access) *
|
||||
C ======= *
|
||||
C *
|
||||
C The corrected reflection intensities are saved on this unformatted *
|
||||
C direct access file of record length 68 bytes for each reflection. *
|
||||
C The file is sorted with respect to the unique reflection indices. *
|
||||
C This means: *
|
||||
C For each reflection with the original indices H,K,L all symmetry *
|
||||
C equivalent indices are generated including Friedel related ones. *
|
||||
C Among all these indices we choose the unique reflection indices *
|
||||
C HA,KA,LA in the following order: HA is the largest H-index, among *
|
||||
C those with the same HA-value select those with the largest K-index *
|
||||
C which is KA, and finally the largest L-index which is called LA. *
|
||||
C The unique indices HA,KA,LA thus found are packed into a 32-bit *
|
||||
C word KEY=(LA+511)+(KA+511)*1024+(HA+511)*1048576 . *
|
||||
C The reflections are then sorted in growing values of KEY. *
|
||||
C *
|
||||
C Record structure *
|
||||
C *
|
||||
C 16bit-WORD # CONTENTS *
|
||||
C 1 HA (The last record is indicated by HA=10000) *
|
||||
C 2 KA HA,KA,LA are the unique reflection indices. *
|
||||
C 3 LA Any two reflections have the same unique *
|
||||
C indices if and only if they are related by *
|
||||
C symmetry. (HA,KA,LA are integer*2) *
|
||||
C 4 H Original reflection indices H,K,L. *
|
||||
C 5 K H,K,L are integer*2. *
|
||||
C 6 L *
|
||||
C 7 S Identifying number of symmetry operator used *
|
||||
C to go from original to unique indices. *
|
||||
C (integer*2). A negative sign indicates that *
|
||||
C a mirror operation has been applied. This *
|
||||
C information may be useful if a special *
|
||||
C treatment for anomalous differences is *
|
||||
C required which goes beyond the method of *
|
||||
C the XDS-program. *
|
||||
C 8 IPEAK Percentage of observed reflection intensity. *
|
||||
C A value less than 100 indicates either a *
|
||||
C reflection overlap or bad spots in the profile*
|
||||
C 9 ICORR Percentage of correlation (integer*2) between *
|
||||
C observed and expected reflection profile. *
|
||||
C 10,11 FFADD LP-corrected intensity of this reflection *
|
||||
C obtained by straight summation of counts *
|
||||
C within spot region ( background subtracted). *
|
||||
C The intensity is also corrected for radiation *
|
||||
C damage and absorption. (real*4) *
|
||||
C 12,13 SDADD Standard deviation of FFADD.(real*4) *
|
||||
C 14,15 RLP Reciprocal LP-correction factor (real*4) *
|
||||
C 16 ABSCAY Combined absorption and decay correction *
|
||||
C factor*1000 (integer*2). *
|
||||
C In case you want to remove this calculated *
|
||||
C correction, divide intensities and standard *
|
||||
C deviations by ABSCAY/1000.0 . *
|
||||
C 17 IALFA IALFA and IBETA (both integer*2) are polar- *
|
||||
C 18 IBETA coordinates of the spindle axis in units of a *
|
||||
C hundreth of a degree. The lab coordinates of *
|
||||
C the spindle axis are: *
|
||||
C Ux=sin(BETA)*cos(ALPHA) *
|
||||
C Uy=sin(BETA)*sin(ALPHA) *
|
||||
C Uz=cos(BETA) *
|
||||
C where ALPHA=IALFA/5729.578, *
|
||||
C BETA =IBETA/5729.578. *
|
||||
C 19 IFRM Frame number at diffraction of this reflection*
|
||||
C (integer*2) *
|
||||
C 20 PHI Calculated spindle position for this *
|
||||
C reflection at diffraction in units of a *
|
||||
C hundreth of a degree. (integer*2) *
|
||||
C 21 IX, Calculated detector x- and y-coordinates for *
|
||||
C 22 IY this reflection at diffraction in units of a *
|
||||
C tenth of a pixel times 512.0/NX and 512.0/NY, *
|
||||
C respectively. NX, NY are the numbers of pixels*
|
||||
C along the detector X- and Y-axis. *
|
||||
C IX,IY are integer*2. *
|
||||
C 23-28 S0 Laboratory coordinates of direct beam wave- *
|
||||
C vector ( rec. Angstroem). S0 points from the *
|
||||
C x-ray source towards the crystal. *
|
||||
C 29-34 S1 Laboratory coordinates of scattered beam wave-*
|
||||
C vector. Length is 1.0/lambda (rec. Angstroem) *
|
||||
C S0 and S1 are real*4 arrays of length 3. S1 *
|
||||
C points from the crystal towards the detector. *
|
||||
C At diffraction, laboratory coordinates of the *
|
||||
C reflection H,K,L are: S1(.)-S0(.) *
|
||||
C *
|
||||
C***********************************************************************
|
||||
C *
|
||||
C Description of XSCALE input file format of type UNIQUE as produced *
|
||||
C by XDS. *
|
||||
C *
|
||||
C UNIQUE.HKL (formatted sequential) *
|
||||
C ========== *
|
||||
C *
|
||||
C DESCRIPTION OF SHORT OUTPUT FILE *
|
||||
C *
|
||||
C Symmetry related reflections are averaged and written with *
|
||||
C FORMAT(3I5,4E12.4). Each record consists of *
|
||||
C *
|
||||
C HA,KA,LA,INTENSITY,STANDARD DEVIATION OF INTENSITY, *
|
||||
C ANOMALOUS INTENSITY DIFFERENCE,STANDARD DEVIATION OF DIFFERENCE *
|
||||
C *
|
||||
C where HA,KA,LA are the unique reflection indices. The file is sorted *
|
||||
C with respect to these unique reflection indices. The last record *
|
||||
C is indicated by HA=10000. *
|
||||
C Unobserved ANOMALOUS INTENSITY DIFFERENCE and its STANDARD DEVIATION *
|
||||
C are both set to zero. *
|
||||
C *
|
||||
C***********************************************************************
|
||||
</pre>
|
||||
xscale can be started by typing <b>xscale</b> at the unix
|
||||
prompt. Please note that xscale expects an input file named XSCALE.INP
|
||||
in the current directory.
|
||||
</p>
|
||||
</BODY>
|
||||
</HTML>
|
7
drive.c
7
drive.c
@ -6,7 +6,6 @@
|
||||
|
||||
Mark Koennecke, December 1996
|
||||
|
||||
Copyright:
|
||||
|
||||
Labor fuer Neutronenstreuung
|
||||
Paul Scherrer Institut
|
||||
@ -364,12 +363,16 @@
|
||||
}
|
||||
|
||||
/* check the completion status */
|
||||
if(!(eOld == eScanning || eOld == eBatch))
|
||||
{
|
||||
eOld = eEager;
|
||||
}
|
||||
if(iRet == DEVERROR)
|
||||
{
|
||||
sprintf(pBueffel,"Driving finished with problem");
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
ClearExecutor(GetExecutor());
|
||||
SetStatus(eOld);
|
||||
SetStatus(eOld);
|
||||
return 0;
|
||||
}
|
||||
else if(iRet == DEVINT)
|
||||
|
1
dummy/cd_obj
Normal file
1
dummy/cd_obj
Normal file
@ -0,0 +1 @@
|
||||
cd ../obj/$SICS_VERSION/dummy
|
102
dummy/dummy.c
Normal file
102
dummy/dummy.c
Normal file
@ -0,0 +1,102 @@
|
||||
/*------------------------------------------------------------------------
|
||||
D U M M Y
|
||||
|
||||
This is an empty site interface for SICS. Can be used as a starting
|
||||
point for own site specific stuff.
|
||||
|
||||
copyright: see file COPYRIGHT
|
||||
|
||||
Mark Koennecke, June 2003
|
||||
-----------------------------------------------------------------------*/
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <fortify.h>
|
||||
#include <sics.h>
|
||||
#include <motor.h>
|
||||
#include <tcl.h>
|
||||
#include <site.h>
|
||||
|
||||
static pSite siteDummy = NULL;
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
static void AddDummyCommands(SicsInterp *pInter){
|
||||
}
|
||||
/*---------------------------------------------------------------------*/
|
||||
static void RemoveDummyCommands(SicsInterp *pSics){
|
||||
}
|
||||
/*-------------------------------------------------------------------*/
|
||||
static pMotor CreateDummyMotor(SConnection *pCon, int argc, char *argv[]){
|
||||
pMotor pNew = NULL;
|
||||
return pNew;
|
||||
}
|
||||
/*-------------------------------------------------------------------*/
|
||||
static pCounterDriver CreateDummyCounterDriver(SConnection *pCon,
|
||||
int argc,
|
||||
char *argv[]){
|
||||
pCounterDriver pNew = NULL;
|
||||
return pNew;
|
||||
}
|
||||
/*-------------------------------------------------------------------*/
|
||||
static HistDriver *CreateDummyHistMem(char *name, pStringDict pOptions){
|
||||
HistDriver *pNew = NULL;
|
||||
|
||||
return pNew;
|
||||
}
|
||||
/*-------------------------------------------------------------------*/
|
||||
static pVelSelDriv CreateDummyVelSelDriv(char *name, char *array,
|
||||
Tcl_Interp *pTcl){
|
||||
pVelSelDriv pNew = NULL;
|
||||
return pNew;
|
||||
}
|
||||
/*-------------------------------------------------------------------*/
|
||||
static pCodri CreateDummyController(SConnection *pCon,int argc, char *argv[]){
|
||||
pCodri pNew = NULL;
|
||||
return pNew;
|
||||
}
|
||||
/*------------------------------------------------------------------*/
|
||||
static pEVControl InstallDummyEnvironmentController(SicsInterp *pSics,
|
||||
SConnection *pCon,
|
||||
int argc, char *argv[]){
|
||||
pEVControl pNew = NULL;
|
||||
pEVDriver pDriv = NULL;
|
||||
|
||||
return pNew;
|
||||
}
|
||||
/*-----------------------------------------------------------------*/
|
||||
static int ConfigureDummyScan(pScanData self, char *option){
|
||||
return 0;
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
static void KillDummySite(void *site){
|
||||
free(site);
|
||||
siteDummy = NULL;
|
||||
}
|
||||
/*---------------------------------------------------------------------
|
||||
The scheme here goes along the lines of the singleton design pattern
|
||||
---------------------------------------------------------------------*/
|
||||
pSite getSite(void){
|
||||
if(siteDummy == NULL){
|
||||
siteDummy = (pSite)malloc(sizeof(Site));
|
||||
/*
|
||||
we cannot go on if we do not even have enough memory to allocate
|
||||
the site data structure
|
||||
*/
|
||||
assert(siteDummy);
|
||||
/*
|
||||
initializing function pointers
|
||||
*/
|
||||
siteDummy->AddSiteCommands = AddDummyCommands;
|
||||
siteDummy->RemoveSiteCommands = RemoveDummyCommands;
|
||||
siteDummy->CreateMotor = CreateDummyMotor;
|
||||
siteDummy->CreateCounterDriver = CreateDummyCounterDriver;
|
||||
siteDummy->CreateHistogramMemoryDriver = CreateDummyHistMem;
|
||||
siteDummy->CreateVelocitySelector = CreateDummyVelSelDriv;
|
||||
siteDummy->CreateControllerDriver = CreateDummyController;
|
||||
siteDummy->InstallEnvironmentController =
|
||||
InstallDummyEnvironmentController;
|
||||
siteDummy->ConfigureScan = ConfigureDummyScan;
|
||||
siteDummy->KillSite = KillDummySite;
|
||||
}
|
||||
return siteDummy;
|
||||
}
|
||||
|
@ -1,18 +1,23 @@
|
||||
#---------------------------------------------------------------------------
|
||||
# Makefile for the Matrix library
|
||||
#-------------------------------------------------------------------------
|
||||
# common part of the makefile for the Dummy specific parts of SICS
|
||||
#
|
||||
# Mark Koennecke, November 1996
|
||||
#--------------------------------------------------------------------------
|
||||
# Mark Koennecke, June 2003
|
||||
#-------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .o .f
|
||||
|
||||
OBJ= matadd.o matcreat.o matdet.o matdump.o matdurbn.o materr.o \
|
||||
matinv.o matmul.o matsolve.o matsub.o matsubx.o mattoepz.o \
|
||||
mattran.o
|
||||
VPATH=$(SRC)
|
||||
ROOT=..
|
||||
|
||||
libmatrix.a: $(OBJ)
|
||||
- rm -f libmatrix.a
|
||||
ar cr libmatrix.a $(OBJ)
|
||||
ranlib libmatrix.a
|
||||
OBJ=dummy.o
|
||||
|
||||
all: libdummy.a
|
||||
|
||||
libdummy.a: $(OBJ)
|
||||
rm -f libdummy.a
|
||||
ar cr libdummy.a $(OBJ)
|
||||
ranlib libdummy.a
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
rm -f *.a
|
||||
rm -f *.o
|
||||
|
@ -1,3 +1,6 @@
|
||||
#include makefile_alpha
|
||||
include makefile_linux
|
||||
# this makefile delegates to a version specific makefile
|
||||
|
||||
# where root is
|
||||
S_UP=..
|
||||
|
||||
include ../make_forward
|
||||
|
13
dummy/makefile_alpha_dummy
Normal file
13
dummy/makefile_alpha_dummy
Normal file
@ -0,0 +1,13 @@
|
||||
#---------------------------------------------------------------------------
|
||||
# Makefile for the Dummy specific part of SICS
|
||||
# machine-dependent part for Tru64 Unix
|
||||
#
|
||||
# Mark Koennecke, June 2003
|
||||
#--------------------------------------------------------------------------
|
||||
|
||||
CC = cc
|
||||
CFLAGS = -std1 -g $(DFORTIFY) -I$(SRC)..
|
||||
|
||||
DUMMY=_dummy
|
||||
include ../alpha_def
|
||||
include make_gen
|
13
dummy/makefile_linux_dummy
Normal file
13
dummy/makefile_linux_dummy
Normal file
@ -0,0 +1,13 @@
|
||||
#---------------------------------------------------------------------------
|
||||
# Makefile for the Dummy specific part of SICS
|
||||
# machine-dependent part for Redhat Linux with AFS at PSI
|
||||
#
|
||||
# Mark Koennecke, June 2003
|
||||
#--------------------------------------------------------------------------
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = -g $(DFORTIFY) -I../$(SRC)
|
||||
|
||||
DUMMY=_dummy
|
||||
include ../$(SRC)linux_def
|
||||
include $(SRC)make_gen
|
@ -244,4 +244,4 @@
|
||||
|
||||
return self->iTextLen;
|
||||
}
|
||||
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include "fortify.h"
|
||||
#include "sics.h"
|
||||
#include "status.h"
|
||||
#include "ecb.h"
|
||||
#include "psi/ecb.h"
|
||||
#include "countdriv.h"
|
||||
|
||||
/*------------------ our private data structure ------------------------*/
|
||||
@ -579,11 +579,8 @@ pCounterDriver MakeECBCounter(char *ecb){
|
||||
self->Set = ECBSet;
|
||||
self->Get = ECBGet;
|
||||
self->Send = ECBSend;
|
||||
self->KillPrivate = NULL;
|
||||
|
||||
self->pData = pPriv;
|
||||
return self;
|
||||
}
|
||||
/*=====================================================================*/
|
||||
void KillECBCounter(struct __COUNTER *self){
|
||||
DeleteCounterDriver(self);
|
||||
}
|
||||
|
232
emergency.dat
232
emergency.dat
@ -1,187 +1,45 @@
|
||||
*************************** TOPSI Data File ********************************
|
||||
Title = TopsiTupsiTapsi
|
||||
User = Daniel_the_Clementine
|
||||
File Creation Stardate: 1999-11-08 09:44:59
|
||||
****************************************************************************
|
||||
Monochromator Lamda = 5.321338
|
||||
Monochromator A1 = 52.500000
|
||||
Monochromator A2 = 105.000000
|
||||
----------------------------------------------------------------------------
|
||||
Sample STL = 30.000000
|
||||
Sample STU = 30.000000
|
||||
Sample SGL = 20.000000
|
||||
Sample SGU = -12.500000
|
||||
**************************** DATA ******************************************
|
||||
Scanning Variables: th,
|
||||
237 Points, Mode: Timer, Preset 1.000000
|
||||
NP th Counts Monitor1 Monitor2 Monitor3 Time
|
||||
0 -59.000 8967 2203 10317 -1 2.0
|
||||
1 -58.500 24367 11758 8524 -1 2.0
|
||||
2 -58.000 2455 520 23410 -1 2.0
|
||||
3 -57.500 16845 16818 4483 -1 2.0
|
||||
4 -57.000 12219 9072 11783 -1 2.0
|
||||
5 -56.500 28352 27019 19294 -1 2.0
|
||||
6 -56.000 29441 29823 15374 -1 2.0
|
||||
7 -55.500 3482 23668 8995 -1 2.0
|
||||
8 -55.000 7653 21770 6216 -1 2.0
|
||||
9 -54.500 22414 206 3127 -1 2.0
|
||||
10 -54.000 22308 13424 15312 -1 2.0
|
||||
11 -53.500 31961 24537 14256 -1 2.0
|
||||
12 -53.000 18488 18078 2742 -1 2.0
|
||||
13 -52.500 14057 23799 3926 -1 2.0
|
||||
14 -52.000 18097 2806 9211 -1 2.0
|
||||
15 -51.500 28233 25260 13072 -1 2.0
|
||||
16 -51.000 21618 26521 10543 -1 2.0
|
||||
17 -50.500 5095 12725 21073 -1 2.0
|
||||
18 -50.000 32440 21399 7314 -1 2.0
|
||||
19 -49.500 6996 25072 18849 -1 2.0
|
||||
20 -49.000 31303 6051 3042 -1 2.0
|
||||
21 -48.500 27013 13357 20680 -1 2.0
|
||||
22 -48.000 14947 28958 22289 -1 2.0
|
||||
23 -47.500 29783 24413 7797 -1 2.0
|
||||
24 -47.000 26747 15699 25531 -1 2.0
|
||||
25 -46.500 12336 2208 20547 -1 2.0
|
||||
26 -46.000 19676 21318 26255 -1 2.0
|
||||
27 -45.500 20815 19049 23542 -1 2.0
|
||||
28 -45.000 16255 22528 30097 -1 2.0
|
||||
29 -44.500 23663 17143 23994 -1 2.0
|
||||
30 -44.000 447 23307 26391 -1 2.0
|
||||
31 -43.500 61 4986 32302 -1 2.0
|
||||
32 -43.000 725 25244 26342 -1 2.0
|
||||
33 -42.500 11437 11039 14620 -1 2.0
|
||||
34 -42.000 18858 22070 9507 -1 2.0
|
||||
35 -41.500 329 15969 15174 -1 2.0
|
||||
36 -41.000 7289 19423 18739 -1 2.0
|
||||
37 -40.500 8959 9184 27569 -1 2.0
|
||||
38 -40.000 4456 6701 899 -1 2.0
|
||||
39 -39.500 11317 29003 14210 -1 2.0
|
||||
40 -39.000 22539 10217 8882 -1 2.0
|
||||
41 -38.500 31787 15015 9555 -1 2.0
|
||||
42 -38.000 20965 16300 18351 -1 2.0
|
||||
43 -37.500 7782 26149 19653 -1 2.0
|
||||
44 -37.000 5106 164 16266 -1 2.0
|
||||
45 -37.500 31404 197 25099 -1 2.0
|
||||
46 -36.000 10518 28778 24342 -1 2.0
|
||||
47 -35.500 32571 15848 20934 -1 2.0
|
||||
48 -35.000 22802 21241 4339 -1 2.0
|
||||
49 -34.500 23764 16205 21089 -1 2.0
|
||||
50 -34.000 4053 9211 18542 -1 2.0
|
||||
51 -33.500 14949 5395 9089 -1 2.0
|
||||
52 -33.000 16281 25424 19573 -1 2.0
|
||||
53 -32.500 978 27620 7378 -1 2.0
|
||||
54 -32.000 10248 24563 20563 -1 2.0
|
||||
55 -31.500 2236 15305 6143 -1 2.0
|
||||
56 -31.000 13120 3545 2625 -1 2.0
|
||||
57 -30.500 4537 3687 17839 -1 2.0
|
||||
58 -30.000 2266 15530 24194 -1 2.0
|
||||
59 -29.500 3456 20267 3096 -1 2.0
|
||||
60 -29.000 11541 32236 5092 -1 2.0
|
||||
61 -28.500 6980 20951 7388 -1 2.0
|
||||
62 -28.000 22631 2493 11540 -1 2.0
|
||||
63 -27.500 16811 11356 7860 -1 2.0
|
||||
64 -27.000 6930 17529 16204 -1 2.0
|
||||
65 -26.500 11038 282 17728 -1 2.0
|
||||
66 -26.000 20100 25974 555 -1 2.0
|
||||
67 -25.500 30249 3996 7380 -1 2.0
|
||||
68 -25.000 28588 5663 12665 -1 2.0
|
||||
69 -24.500 13425 3290 13412 -1 2.0
|
||||
70 -24.000 4138 22752 10315 -1 2.0
|
||||
71 -23.500 28412 22392 29737 -1 2.0
|
||||
72 -23.000 18525 1627 2157 -1 2.0
|
||||
73 -22.500 27074 27983 8105 -1 2.0
|
||||
74 -22.000 3380 16856 12275 -1 2.0
|
||||
75 -21.500 4915 24006 25568 -1 2.0
|
||||
76 -21.000 20292 31432 26115 -1 2.0
|
||||
77 -20.500 17069 18090 23943 -1 2.0
|
||||
78 -20.000 2399 10997 29689 -1 2.0
|
||||
79 -19.500 10180 32626 12604 -1 2.0
|
||||
80 -19.000 7473 742 19456 -1 2.0
|
||||
81 -18.500 1286 26046 20661 -1 2.0
|
||||
82 -18.000 27396 6856 26963 -1 2.0
|
||||
83 -18.500 7143 22820 6703 -1 2.0
|
||||
84 -17.000 13604 21180 9791 -1 2.0
|
||||
85 -16.500 27401 23433 14650 -1 2.0
|
||||
86 -16.000 7216 22059 1067 -1 2.0
|
||||
87 -15.500 14771 20933 6550 -1 2.0
|
||||
88 -15.000 30580 30932 8549 -1 2.0
|
||||
89 -14.500 3837 32065 12476 -1 2.0
|
||||
90 -14.000 27580 9840 29148 -1 2.0
|
||||
91 -13.500 18736 25441 17455 -1 2.0
|
||||
92 -13.000 10307 3555 19345 -1 2.0
|
||||
93 -12.500 22085 5448 10997 -1 2.0
|
||||
94 -12.000 23104 4689 20380 -1 2.0
|
||||
95 -11.500 28275 946 16402 -1 2.0
|
||||
96 -11.000 2765 31198 12550 -1 2.0
|
||||
97 -10.500 20287 18196 18437 -1 2.0
|
||||
98 -10.000 31076 27146 13449 -1 2.0
|
||||
99 -9.500 28128 18678 5336 -1 2.0
|
||||
100 -9.000 22690 23550 25646 -1 2.0
|
||||
101 -8.500 9440 17697 7736 -1 2.0
|
||||
102 -8.000 23979 10751 23454 -1 2.0
|
||||
103 -7.500 24646 13443 7229 -1 2.0
|
||||
104 -7.000 12236 29309 22210 -1 2.0
|
||||
105 -6.500 1978 30473 12315 -1 2.0
|
||||
106 -6.000 25529 9575 22042 -1 2.0
|
||||
107 -5.500 5510 21070 14813 -1 2.0
|
||||
108 -5.000 10715 9672 15845 -1 2.0
|
||||
109 -4.500 8664 13059 9118 -1 2.0
|
||||
110 -4.000 10959 3201 31106 -1 2.0
|
||||
111 -3.500 9995 22587 18352 -1 2.0
|
||||
112 -3.000 20850 475 30334 -1 2.0
|
||||
113 -2.500 30093 11040 23411 -1 2.0
|
||||
114 -2.000 13119 25138 18651 -1 2.0
|
||||
115 -1.500 4971 4297 11160 -1 2.0
|
||||
116 -1.000 8726 3183 31489 -1 2.0
|
||||
117 -0.500 18446 21037 19501 -1 2.0
|
||||
118 0.000 9062 32379 29094 -1 2.0
|
||||
119 0.500 11737 30969 32729 -1 2.0
|
||||
120 1.000 20493 6427 30256 -1 2.0
|
||||
121 1.500 6626 26327 5231 -1 2.0
|
||||
122 2.000 17959 24455 10201 -1 2.0
|
||||
123 2.500 1690 6872 26058 -1 2.0
|
||||
124 3.000 1428 8842 30822 -1 2.0
|
||||
125 3.500 20391 15793 233 -1 2.0
|
||||
126 4.000 27505 2793 19380 -1 2.0
|
||||
127 4.500 25529 8906 12652 -1 2.0
|
||||
128 5.000 22449 18729 31299 -1 2.0
|
||||
129 5.500 2271 11631 5890 -1 2.0
|
||||
130 6.000 19444 3930 20025 -1 2.0
|
||||
131 6.500 6477 18542 11756 -1 2.0
|
||||
132 7.000 4883 23126 20964 -1 2.0
|
||||
133 7.500 11552 4103 15970 -1 2.0
|
||||
134 8.000 11088 13492 18414 -1 2.0
|
||||
135 8.500 30551 9442 12392 -1 2.0
|
||||
136 9.000 23880 23836 4140 -1 2.0
|
||||
137 9.500 30123 6831 14659 -1 2.0
|
||||
138 10.000 18811 13865 27447 -1 2.0
|
||||
139 10.500 4816 32454 23184 -1 2.0
|
||||
140 11.000 15177 2169 7295 -1 2.0
|
||||
141 11.500 29719 15533 895 -1 2.0
|
||||
142 12.000 9374 3451 31626 -1 2.0
|
||||
143 12.500 27917 21136 914 -1 2.0
|
||||
144 13.000 22986 22982 13140 -1 2.0
|
||||
145 13.500 10555 30271 21159 -1 2.0
|
||||
146 14.000 31378 24222 13613 -1 2.0
|
||||
147 14.500 4540 17455 21485 -1 2.0
|
||||
148 15.000 6958 29953 20952 -1 2.0
|
||||
149 15.500 2692 10112 10141 -1 2.0
|
||||
150 16.000 12111 16276 16440 -1 2.0
|
||||
151 16.500 11830 16190 18383 -1 2.0
|
||||
152 17.000 27350 25157 8275 -1 2.0
|
||||
153 17.500 1731 11965 16119 -1 2.0
|
||||
154 18.000 1210 13792 26771 -1 2.0
|
||||
155 18.500 29700 12691 30492 -1 2.0
|
||||
156 19.000 13695 27689 10750 -1 2.0
|
||||
157 19.500 28582 6713 14151 -1 2.0
|
||||
158 20.000 27710 13427 9036 -1 2.0
|
||||
159 20.500 8972 3465 23792 -1 2.0
|
||||
160 21.000 10690 29536 79 -1 2.0
|
||||
161 21.500 18244 5150 1718 -1 2.0
|
||||
162 22.000 27184 12686 29979 -1 2.0
|
||||
163 22.500 14291 16273 24814 -1 2.0
|
||||
164 23.000 20684 28748 2161 -1 2.0
|
||||
165 23.500 1670 17064 23710 -1 2.0
|
||||
166 24.000 23359 13766 12725 -1 2.0
|
||||
167 24.500 11176 5672 7659 -1 2.0
|
||||
168 25.000 3798 31993 1096 -1 2.0
|
||||
END-OF-DATA
|
||||
RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
|
||||
0 1 0
|
||||
ILL TAS data in the new ASCII format follow after the line VV...V
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
42 0
|
||||
SIMTAS oksana 06-Nov-2003 09:12:43
|
||||
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
|
||||
INSTR: SIMTAS
|
||||
EXPNO:
|
||||
USER_: oksana
|
||||
LOCAL: roessli
|
||||
FILE_: 0
|
||||
DATE_: 06-Nov-2003 09:12:43
|
||||
TITLE: ceb6
|
||||
COMND: sc qh 0.90 0.90 0.90 2.25 dqh 0 0 0 0.1 np 15 mn 120000
|
||||
POSQE: QH= 0.9000, QK= 0.9000, QL= 0.9000, EN= 2.2500, UN=MEV
|
||||
STEPS: DQH= 0.0000, DQK= 0.0000, DQL= 0.0000, DEN= 0.1000,
|
||||
PARAM: DM= 3.3540, DA= 3.3540, SM=-1, SS= 1, SA=-1
|
||||
PARAM: FX= 2, KFIX= 1.5000
|
||||
PARAM: ALF1=800.0000, ALF2= 80.0000, ALF3=800.0000, ALF4=800.0000
|
||||
PARAM: BET1=400.0000, BET2=400.0000, BET3=400.0000, BET4=400.0000
|
||||
PARAM: ETAM= 15.0000, ETAA= 30.0000
|
||||
PARAM: AS= 4.1400, BS= 4.1400, CS= 4.1400
|
||||
PARAM: AA= 90.0000, BB= 90.0000, CC= 90.0000
|
||||
PARAM: AX= 1.0000, AY= 1.0000, AZ= 0.0000
|
||||
PARAM: BX= 0.0000, BY= 0.0000, BZ= 1.0000
|
||||
VARIA: A1 = 46.6390, A2 = 53.8900, A3 =-50.6720,
|
||||
VARIA: A4 =129.7100, A5 =112.5900, A6 =141.0470,
|
||||
VARIA: MCV = 66.4000, SRO =175.5000, ACH = 6.0000,
|
||||
VARIA: MTL = 17.0000, MTU = 18.8000, STL = 30.0000,
|
||||
VARIA: STU = 30.0000, STL = 30.0000, ATU = 16.9400,
|
||||
VARIA: MGL = 10.0000, SGL = 16.0000, SGU = 16.0000,
|
||||
VARIA: AGL = 10.0000, ATL = 17.0000, TT = 39.4383,
|
||||
VARIA: I1 =-999.9900, I2 =-999.9900, I3 =-999.9900,
|
||||
ZEROS: A1 = 0.0890, A2 = 0.3400, A3 =-227.9720,
|
||||
ZEROS: A4 = 0.4600, A5 =-87.4100, A6 = 0.0470,
|
||||
ZEROS: MCV = -0.1000, SRO = -0.0000, ACH = -0.0000,
|
||||
ZEROS: MTL = -0.0000, MTU = 1.8000, STL = -0.0000,
|
||||
ZEROS: STU = -0.0000, STL = -0.0000, ATU = -0.0000,
|
||||
ZEROS: MGL = -0.0000, SGL = -0.0000, SGU = -0.0000,
|
||||
ZEROS: AGL = -0.0000, ATL = -0.0000,
|
||||
PARAM: MN=120000.000000
|
||||
FORMT: (I4,1X,F9.4,1X,F9.4,1X,F9.4,1X,F9.4,1X,F8.0,1X,F8.0,1X,F9.2,1X,F8.0,1X,F8.0,1X,F9.4,1X,F9.4,1X,F9.4,1X,F9.4)
|
||||
DATA_:
|
||||
PNT QH QK QL EN M1 M2 TIME CNTS M3 A2 A3 A4 TT
|
||||
|
@ -25,9 +25,9 @@
|
||||
typedef struct __EVDriver *pEVDriver;
|
||||
|
||||
#include "evdriver.i"
|
||||
#include "hardsup/el734_def.h"
|
||||
#include "hardsup/el734fix.h"
|
||||
#include "hardsup/serialsinq.h"
|
||||
#include "psi/hardsup/el734_def.h"
|
||||
#include "psi/hardsup/el734fix.h"
|
||||
#include "psi/hardsup/serialsinq.h"
|
||||
#include "eurodriv.h"
|
||||
|
||||
#define INVALIDANSWER -1005
|
||||
|
787
evcontroller.c
787
evcontroller.c
@ -6,6 +6,14 @@
|
||||
|
||||
Mark Koennecke, Juli 1997
|
||||
|
||||
Implemented calling site specific initialisation routines.
|
||||
Mark Koennecke, July 2003
|
||||
|
||||
Implemented scripted out of tolerance handling and retrieval of
|
||||
driver name.
|
||||
Mark Koennecke, December 2003
|
||||
|
||||
|
||||
Copyright:
|
||||
|
||||
Labor fuer Neutronenstreuung
|
||||
@ -54,23 +62,10 @@
|
||||
#include "evcontroller.i"
|
||||
#include "evdriver.i"
|
||||
#include "simev.h"
|
||||
#include "itc4.h"
|
||||
#include "dilludriv.h"
|
||||
#include "tclev.h"
|
||||
#include "bruker.h"
|
||||
#include "ltc11.h"
|
||||
#include "eurodriv.h"
|
||||
#include "el755driv.h"
|
||||
#include "A1931.h"
|
||||
#include "tecsdriv.h"
|
||||
#include "chadapter.h"
|
||||
#include "status.h"
|
||||
|
||||
/*
|
||||
from slsmagnet.c
|
||||
*/
|
||||
extern pEVDriver CreateSLSDriv(int argc, char *argv[]);
|
||||
|
||||
#include "site.h"
|
||||
/*--------------------- Functions needed to implement interfaces -----------*/
|
||||
static long EVIDrive(void *pData, SConnection *pCon, float fVal)
|
||||
{
|
||||
@ -249,7 +244,7 @@ extern pEVDriver CreateSLSDriv(int argc, char *argv[]);
|
||||
}
|
||||
|
||||
now = time(NULL);
|
||||
tmo = (int)(ObVal(self->pParam, MAXWAIT) * 60);
|
||||
tmo = (int)(ObVal(self->pParam, MAXWAIT));
|
||||
/* based on this: logic ! */
|
||||
if (tmo>0 && now > self->start+tmo ) /* time out */
|
||||
{
|
||||
@ -266,14 +261,14 @@ extern pEVDriver CreateSLSDriv(int argc, char *argv[]);
|
||||
iCount++;
|
||||
return HWBusy;
|
||||
}
|
||||
tmo = (int)(ObVal(self->pParam, SETTLE) * 60);
|
||||
tmo = (int)(ObVal(self->pParam, SETTLE));
|
||||
if (self->lastt <= 0) /* lastt negative: -seconds already waited */
|
||||
{
|
||||
self->lastt += now;
|
||||
if (tmo>0)
|
||||
{
|
||||
sprintf(pBueffel,"%s inside tolerance, wait %.2f min. to settle",
|
||||
self->pName, (self->lastt + tmo - now)/60.0);
|
||||
sprintf(pBueffel,"%s inside tolerance, wait %.2f sec. to settle",
|
||||
self->pName, (self->lastt + tmo - now)*1.0);
|
||||
SCWrite(pCon,pBueffel,eStatus);
|
||||
}
|
||||
return HWBusy;
|
||||
@ -344,35 +339,45 @@ extern pEVDriver CreateSLSDriv(int argc, char *argv[]);
|
||||
|
||||
return iRes;
|
||||
}
|
||||
|
||||
/*---------------------------- Error Handlers --------------------------------*/
|
||||
static int ErrLazy(void *pData)
|
||||
{
|
||||
pEVControl self = NULL;
|
||||
static void ErrWrite(char *txt)
|
||||
{
|
||||
pExeList pExe;
|
||||
SConnection *pCon = NULL;
|
||||
|
||||
pExe = GetExecutor();
|
||||
pCon = GetExeOwner(pExe);
|
||||
|
||||
if(pCon)
|
||||
{
|
||||
SCWrite(pCon,txt,eWarning);
|
||||
}
|
||||
else
|
||||
{
|
||||
ServerWriteGlobal(txt,eWarning);
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static void ErrReport(pEVControl self)
|
||||
{
|
||||
float fPos, fDelta;
|
||||
char pBueffel[256];
|
||||
|
||||
self->pDriv->GetValues(self->pDriv,&self->fTarget,&fPos,&fDelta);
|
||||
sprintf(pBueffel,"WARNING: %s is out of range by %g",self->pName,fDelta);
|
||||
ErrWrite(pBueffel);
|
||||
self->iWarned = 1;
|
||||
}
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static int ErrLazy(void *pData)
|
||||
{
|
||||
pEVControl self = NULL;
|
||||
|
||||
self = (pEVControl)pData;
|
||||
assert(self);
|
||||
|
||||
|
||||
self->pDriv->GetValues(self->pDriv,&self->fTarget,&fPos,&fDelta);
|
||||
sprintf(pBueffel,"WARNING: %s is out of range by %g",self->pName,fDelta);
|
||||
pExe = GetExecutor();
|
||||
pCon = GetExeOwner(pExe);
|
||||
if(!self->iWarned)
|
||||
{
|
||||
if(pCon)
|
||||
{
|
||||
SCWrite(pCon,pBueffel,eWarning);
|
||||
}
|
||||
else
|
||||
{
|
||||
ServerWriteGlobal(pBueffel,eWarning);
|
||||
}
|
||||
}
|
||||
self->iWarned = 1;
|
||||
ErrReport(self);
|
||||
return 1;
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@ -380,33 +385,14 @@ extern pEVDriver CreateSLSDriv(int argc, char *argv[]);
|
||||
{
|
||||
pEVControl self = NULL;
|
||||
pExeList pExe;
|
||||
SConnection *pCon = NULL;
|
||||
float fPos, fDelta;
|
||||
char pBueffel[256];
|
||||
int iRet;
|
||||
|
||||
self = (pEVControl)pData;
|
||||
assert(self);
|
||||
|
||||
self->pDriv->GetValues(self->pDriv,&self->fTarget,&fPos,&fDelta);
|
||||
sprintf(pBueffel,"WARNING: %s is out of range by %g",self->pName,fDelta);
|
||||
ErrReport(self);
|
||||
|
||||
pExe = GetExecutor();
|
||||
pCon = GetExeOwner(pExe);
|
||||
|
||||
if(!self->iWarned)
|
||||
{
|
||||
if(pCon)
|
||||
{
|
||||
SCWrite(pCon,pBueffel,eWarning);
|
||||
}
|
||||
else
|
||||
{
|
||||
ServerWriteGlobal(pBueffel,eWarning);
|
||||
}
|
||||
}
|
||||
self->iWarned = 1;
|
||||
|
||||
|
||||
if(IsCounting(pExe))
|
||||
{
|
||||
SCWrite(GetExeOwner(pExe),"Pausing till OK",eError);
|
||||
@ -425,38 +411,59 @@ extern pEVDriver CreateSLSDriv(int argc, char *argv[]);
|
||||
ContinueExecution(pExe);
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static int ErrScript(void *pData)
|
||||
{
|
||||
pEVControl self = NULL;
|
||||
int iRet;
|
||||
Tcl_Interp *pTcl = NULL;
|
||||
pExeList pExe;
|
||||
char pBueffel[256];
|
||||
|
||||
self = (pEVControl)pData;
|
||||
assert(self);
|
||||
|
||||
ErrReport(self);
|
||||
|
||||
pExe = GetExecutor();
|
||||
if(self->errorScript != NULL)
|
||||
{
|
||||
pTcl = InterpGetTcl(pServ->pSics);
|
||||
iRet = Tcl_Eval(pTcl,self->errorScript);
|
||||
if(iRet != TCL_OK)
|
||||
{
|
||||
snprintf(pBueffel,255,
|
||||
"ERROR: %s while processing errorscript for %s",
|
||||
pTcl->result,self->pName);
|
||||
ErrWrite(pBueffel);
|
||||
}
|
||||
/*
|
||||
assume that everything is fine again after the script
|
||||
returns
|
||||
*/
|
||||
self->eMode = EVMonitor;
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(pBueffel,255,
|
||||
"ERROR: script error handling requested for %s, but no script given",
|
||||
self->pName);
|
||||
ErrWrite(pBueffel);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int ErrInterrupt(void *pData)
|
||||
{
|
||||
pEVControl self = NULL;
|
||||
pExeList pExe;
|
||||
SConnection *pCon = NULL;
|
||||
float fPos,fDelta;
|
||||
char pBueffel[256];
|
||||
int iRet;
|
||||
|
||||
|
||||
self = (pEVControl)pData;
|
||||
assert(self);
|
||||
|
||||
/* report problem */
|
||||
self->pDriv->GetValues(self->pDriv,&self->fTarget,&fPos,&fDelta);
|
||||
sprintf(pBueffel,"WARNING: %s is out of range by %g",self->pName,fDelta);
|
||||
pExe = GetExecutor();
|
||||
pCon = GetExeOwner(pExe);
|
||||
if(!self->iWarned)
|
||||
{
|
||||
if(pCon)
|
||||
{
|
||||
SCWrite(pCon,pBueffel,eWarning);
|
||||
}
|
||||
else
|
||||
{
|
||||
ServerWriteGlobal(pBueffel,eWarning);
|
||||
}
|
||||
}
|
||||
self->iWarned = 1;
|
||||
ErrReport(self);
|
||||
|
||||
/* interrupt */
|
||||
SetInterrupt((int)ObVal(self->pParam,INTERRUPT));
|
||||
@ -466,31 +473,13 @@ extern pEVDriver CreateSLSDriv(int argc, char *argv[]);
|
||||
static int ErrRun(void *pData)
|
||||
{
|
||||
pEVControl self = NULL;
|
||||
pExeList pExe;
|
||||
SConnection *pCon = NULL;
|
||||
float fPos, fDelta;
|
||||
char pBueffel[256];
|
||||
int iRet;
|
||||
|
||||
self = (pEVControl)pData;
|
||||
assert(self);
|
||||
|
||||
/* report problem */
|
||||
self->pDriv->GetValues(self->pDriv,&self->fTarget,&fPos,&fDelta);
|
||||
sprintf(pBueffel,"WARNING: %s is out of range by %g",self->pName,fDelta);
|
||||
pExe = GetExecutor();
|
||||
pCon = GetExeOwner(pExe);
|
||||
if(pCon)
|
||||
{
|
||||
SCWrite(pCon,pBueffel,eWarning);
|
||||
SCWrite(pCon,"Driving to a safe place",eWarning);
|
||||
}
|
||||
else
|
||||
{
|
||||
ServerWriteGlobal(pBueffel,eWarning);
|
||||
ServerWriteGlobal("Driving to a safe place",eWarning);
|
||||
}
|
||||
|
||||
ErrReport(self);
|
||||
|
||||
ErrWrite("Running to safe value");
|
||||
self->pDriv->SetValue(self->pDriv, ObVal(self->pParam,SAFEVALUE));
|
||||
self->eMode = EVIdle;
|
||||
return 1;
|
||||
@ -524,6 +513,10 @@ extern pEVDriver CreateSLSDriv(int argc, char *argv[]);
|
||||
iStatus = ErrRun(pData);
|
||||
return iStatus;
|
||||
break;
|
||||
case 4: /* invoke a script */
|
||||
iStatus = ErrScript(pData);
|
||||
return iStatus;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
|
||||
@ -820,6 +813,14 @@ extern pEVDriver CreateSLSDriv(int argc, char *argv[]);
|
||||
{
|
||||
VarlogDelete(self->pLog);
|
||||
}
|
||||
if(self->driverName != NULL)
|
||||
{
|
||||
free(self->driverName);
|
||||
}
|
||||
if(self->errorScript != NULL)
|
||||
{
|
||||
free(self->errorScript);
|
||||
}
|
||||
free(self);
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@ -948,43 +949,55 @@ extern pEVDriver CreateSLSDriv(int argc, char *argv[]);
|
||||
assert(self);
|
||||
assert(pCon);
|
||||
|
||||
sprintf(pBueffel,"Parameter listing for %s",self->pName);
|
||||
snprintf(pBueffel,255,"Parameter listing for %s",self->pName);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
|
||||
sprintf(pBueffel,"%s.%s = %g ",self->pName, "tolerance",
|
||||
snprintf(pBueffel,255,"%s.%s = %g ",self->pName, "tolerance",
|
||||
ObVal(self->pParam,TOLERANCE));
|
||||
SCWrite(pCon,pBueffel, eValue);
|
||||
sprintf(pBueffel,"%s.%s = %g",self->pName, "access",
|
||||
snprintf(pBueffel,255,"%s.%s = %g",self->pName, "access",
|
||||
ObVal(self->pParam,ACCESS));
|
||||
SCWrite(pCon,pBueffel, eValue);
|
||||
sprintf(pBueffel,"%s.%s = %g",self->pName, "ErrorHandler",
|
||||
snprintf(pBueffel,255,"%s.%s = %g",self->pName, "ErrorHandler",
|
||||
ObVal(self->pParam,ERRORHANDLER));
|
||||
SCWrite(pCon,pBueffel, eValue);
|
||||
sprintf(pBueffel,"%s.%s = %g",self->pName, "interrupt",
|
||||
snprintf(pBueffel,255,"%s.%s = %g",self->pName, "interrupt",
|
||||
ObVal(self->pParam,INTERRUPT));
|
||||
SCWrite(pCon,pBueffel, eValue);
|
||||
sprintf(pBueffel,"%s.%s = %g",self->pName, "UpperLimit",
|
||||
snprintf(pBueffel,255,"%s.%s = %g",self->pName, "UpperLimit",
|
||||
ObVal(self->pParam,UPLIMIT));
|
||||
SCWrite(pCon,pBueffel, eValue);
|
||||
sprintf(pBueffel,"%s.%s = %g",self->pName, "LowerLimit",
|
||||
snprintf(pBueffel,255,"%s.%s = %g",self->pName, "LowerLimit",
|
||||
ObVal(self->pParam,LOWLIMIT));
|
||||
SCWrite(pCon,pBueffel, eValue);
|
||||
sprintf(pBueffel,"%s.%s = %g",self->pName, "SafeValue",
|
||||
snprintf(pBueffel,255,"%s.%s = %g",self->pName, "SafeValue",
|
||||
ObVal(self->pParam,SAFEVALUE));
|
||||
SCWrite(pCon,pBueffel, eValue);
|
||||
sprintf(pBueffel,"%s.%s = %g",self->pName, "MaxWait",
|
||||
snprintf(pBueffel,255,"%s.%s = %g (sec)",self->pName, "MaxWait",
|
||||
ObVal(self->pParam,MAXWAIT));
|
||||
SCWrite(pCon,pBueffel, eValue);
|
||||
sprintf(pBueffel,"%s.%s = %g",self->pName, "Settle",
|
||||
snprintf(pBueffel,255,"%s.%s = %g (sec)",self->pName, "Settle",
|
||||
ObVal(self->pParam,SETTLE));
|
||||
SCWrite(pCon,pBueffel, eValue);
|
||||
EVCGetPos(self,pCon,&fPos);
|
||||
sprintf(pBueffel,"%s.%s = %g",self->pName, "CurrentValue",
|
||||
snprintf(pBueffel,255,"%s.%s = %g",self->pName, "CurrentValue",
|
||||
fPos);
|
||||
SCWrite(pCon,pBueffel, eValue);
|
||||
sprintf(pBueffel,"%s.%s = %g",self->pName, "TargetValue",
|
||||
snprintf(pBueffel,255,"%s.%s = %g",self->pName, "TargetValue",
|
||||
self->fTarget);
|
||||
SCWrite(pCon,pBueffel, eValue);
|
||||
snprintf(pBueffel,255,"%s.driver = %s",self->pName, self->driverName);
|
||||
SCWrite(pCon,pBueffel, eValue);
|
||||
if(self->errorScript != NULL)
|
||||
{
|
||||
snprintf(pBueffel,255,"%s.errorScript = %s", self->pName,
|
||||
self->errorScript);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(pBueffel,255,"%s.errorScript = UNDEFINED", self->pName);
|
||||
}
|
||||
SCWrite(pCon,pBueffel, eValue);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -1122,6 +1135,35 @@ extern pEVDriver CreateSLSDriv(int argc, char *argv[]);
|
||||
}
|
||||
else /* parameter request */
|
||||
{
|
||||
/*
|
||||
catch case of errorScript
|
||||
*/
|
||||
strtolower(argv[1]);
|
||||
if(strcmp(argv[1],"errorscript") == 0)
|
||||
{
|
||||
if(self->errorScript != NULL)
|
||||
{
|
||||
snprintf(pBueffel,255,"%s.errorScript = %s",self->pName,
|
||||
self->errorScript);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(pBueffel,255,"%s.errorScript = UNDEFINED",
|
||||
self->pName);
|
||||
}
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
catch case for drivername
|
||||
*/
|
||||
if(strcmp(argv[1],"driver") == 0)
|
||||
{
|
||||
snprintf(pBueffel,255,"%s.driver = %s", self->pName,
|
||||
self->driverName);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
}
|
||||
iRet = EVCGetPar(self,argv[1],&fPos);
|
||||
if(!iRet)
|
||||
{
|
||||
@ -1140,6 +1182,21 @@ extern pEVDriver CreateSLSDriv(int argc, char *argv[]);
|
||||
}
|
||||
else /* try to set parameter */
|
||||
{
|
||||
/*
|
||||
first catch case of errorScript
|
||||
*/
|
||||
strtolower(argv[1]);
|
||||
if(strcmp(argv[1],"errorscript") == 0)
|
||||
{
|
||||
Arg2Text(argc-2,&argv[2],pBueffel,255);
|
||||
if(self->errorScript != NULL)
|
||||
{
|
||||
free(self->errorScript);
|
||||
}
|
||||
self->errorScript = strdup(pBueffel);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
iRet = Tcl_GetDouble(pSics->pTcl,argv[2],&dVal);
|
||||
if(iRet != TCL_OK)
|
||||
{
|
||||
@ -1156,6 +1213,114 @@ extern pEVDriver CreateSLSDriv(int argc, char *argv[]);
|
||||
}
|
||||
return 0; /* not reached */
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static pEVControl InstallCommonControllers(SicsInterp *pSics,
|
||||
SConnection *pCon,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
pEVControl pNew = NULL;
|
||||
pEVDriver pDriv = NULL;
|
||||
char pBueffel[512],pError[132];
|
||||
int iRet;
|
||||
int (*Wrapper)(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]) = EVControlWrapper;
|
||||
|
||||
if(strcmp(argv[3],"sim") == 0) /* SIM driver */
|
||||
{
|
||||
/* Create a Sim Driver */
|
||||
pDriv = CreateSIMEVDriver(argc-4,&argv[4]);
|
||||
if(!pDriv)
|
||||
{
|
||||
SCWrite(pCon,
|
||||
"ERROR: failed to create Environment Device driver",
|
||||
eError);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if(strcmp(argv[3],"tcl") == 0) /* Tcl driver */
|
||||
{
|
||||
/* Create a Tcl driver */
|
||||
pDriv = CreateTclDriver(argc-4,&argv[4],argv[2], pCon);
|
||||
if(!pDriv)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: failed to create TCL device driver",eError);
|
||||
return NULL;
|
||||
}
|
||||
/* got a driver, initialise everything */
|
||||
pNew = CreateEVController(pDriv,argv[2],&iRet);
|
||||
if(!pNew)
|
||||
{
|
||||
SCWrite(pCon,"ERROR creating Environment Controller",eError);
|
||||
DeleteEVDriver(pDriv);
|
||||
return NULL;
|
||||
}
|
||||
if(!iRet)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: problem initialising Environment controller",
|
||||
eError);
|
||||
pDriv->GetError(pDriv,&iRet,pError,131);
|
||||
sprintf(pBueffel,"HW reported: %s",pError);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
}
|
||||
Wrapper = TclEnvironmentWrapper;
|
||||
pNew->iTcl = 1;
|
||||
/* make ev parameters available to Tcl */
|
||||
UpdateTclVariable(pNew->pDriv,"tolerance",
|
||||
ObVal(pNew->pParam,TOLERANCE));
|
||||
UpdateTclVariable(pNew->pDriv,"upperlimit",
|
||||
ObVal(pNew->pParam,UPLIMIT));
|
||||
UpdateTclVariable(pNew->pDriv,"lowerlimit",
|
||||
ObVal(pNew->pParam,LOWLIMIT));
|
||||
}
|
||||
else if(strcmp(argv[3],"gencon") == 0) /* general controller */
|
||||
{
|
||||
/* Create a driver */
|
||||
pDriv = MakeControllerEnvironmentDriver(argc-4,&argv[4]);
|
||||
if(!pDriv)
|
||||
{
|
||||
SCWrite(pCon,
|
||||
"ERROR: failed to create Controller Environment driver",
|
||||
eError);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
return NULL; /* not recognized */
|
||||
}
|
||||
|
||||
|
||||
if(pNew == NULL) /* not yet initialized */
|
||||
{
|
||||
pNew = CreateEVController(pDriv,argv[2],&iRet);
|
||||
if(!pNew)
|
||||
{
|
||||
SCWrite(pCon,"ERROR creating Environment Controller",eError);
|
||||
DeleteEVDriver(pDriv);
|
||||
return NULL;
|
||||
}
|
||||
if(!iRet)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: problem initialising Environment controller",
|
||||
eError);
|
||||
pDriv->GetError(pDriv,&iRet,pError,131);
|
||||
sprintf(pBueffel,"HW reported: %s",pError);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
}
|
||||
}
|
||||
|
||||
/* install command */
|
||||
iRet = AddCommand(pSics,argv[2],Wrapper,
|
||||
DeleteEVController,
|
||||
pNew);
|
||||
if(!iRet)
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: duplicate command %s not created",
|
||||
argv[2]);
|
||||
DeleteEVController((void *)pNew);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return NULL;
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
/*-------------------------------------------------------------------------
|
||||
EVControlFactory implements a SICS command which creates and deletes
|
||||
Controllers at run-time. Syntax:
|
||||
@ -1169,10 +1334,10 @@ extern pEVDriver CreateSLSDriv(int argc, char *argv[]);
|
||||
int argc, char *argv[])
|
||||
{
|
||||
pEVControl pNew = NULL;
|
||||
pEVDriver pDriv = NULL;
|
||||
char pBueffel[512],pError[132];
|
||||
int iRet;
|
||||
CommandList *pCom = NULL;
|
||||
pSite site = NULL;
|
||||
|
||||
assert(pSics);
|
||||
assert(pCon);
|
||||
@ -1229,384 +1394,30 @@ extern pEVDriver CreateSLSDriv(int argc, char *argv[]);
|
||||
pCom = FindCommand(pSics,argv[2]);
|
||||
if(pCom)
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: environment device %s already installed, delete first",
|
||||
sprintf(pBueffel,
|
||||
"ERROR: environment device %s already installed, delete first",
|
||||
argv[2]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
if(strcmp(argv[3],"sim") == 0) /* SIM driver */
|
||||
pNew = InstallCommonControllers(pSics,pCon,argc,argv);
|
||||
if(pNew == NULL)
|
||||
{
|
||||
/* Create a Sim Driver */
|
||||
|
||||
pDriv = CreateSIMEVDriver(argc-4,&argv[4]);
|
||||
if(!pDriv)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: failed to create Environment Device driver",eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
site = getSite();
|
||||
if(site != NULL){
|
||||
pNew = site->InstallEnvironmentController(pSics,pCon,argc,argv);
|
||||
} else {
|
||||
pNew = NULL;
|
||||
}
|
||||
if(pNew == NULL){
|
||||
sprintf(pBueffel,"ERROR: %s not recognized as a valid driver type",
|
||||
argv[3]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if(strcmp(argv[3],"tecs") == 0) /* TECS temperature server */
|
||||
{
|
||||
/* Create a driver */
|
||||
pDriv = CreateTecsDriver(argc-4,&argv[4]);
|
||||
if(!pDriv)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: failed to create TECS device driver",eError);
|
||||
return 0;
|
||||
}
|
||||
/* got a driver, initialise everything */
|
||||
pNew = CreateEVController(pDriv,argv[2],&iRet);
|
||||
if(!pNew)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: failed to initialize Tecs",eError);
|
||||
SCWrite(pCon,"ERROR creating Environment Controller",eError);
|
||||
return 0;
|
||||
}
|
||||
if(!iRet)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: problem initialising Environment controller",
|
||||
eError);
|
||||
pDriv->GetError(pDriv,&iRet,pError,131);
|
||||
sprintf(pBueffel,"HW reported: %s",pError);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
}
|
||||
/* set a few parameters */
|
||||
EVCSetPar(pNew,"upperlimit",300.0,pCon);
|
||||
EVCSetPar(pNew,"lowerlimit",1.0,pCon);
|
||||
/* install command */
|
||||
iRet = AddCommand(pSics,argv[2],TecsWrapper,DeleteEVController,
|
||||
pNew);
|
||||
if(!iRet)
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: duplicate command %s not created",argv[2]);
|
||||
DeleteEVController((void *)pNew);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
EVRegisterController(FindEMON(pSics),argv[2],pNew, pCon);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
else if(strcmp(argv[3],"itc4") == 0) /* ITC4 driver */
|
||||
{
|
||||
/* Create a driver */
|
||||
pDriv = CreateITC4Driver(argc-4,&argv[4]);
|
||||
if(!pDriv)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: failed to create ITC4 device driver",eError);
|
||||
return 0;
|
||||
}
|
||||
/* got a driver, initialise everything */
|
||||
pNew = CreateEVController(pDriv,argv[2],&iRet);
|
||||
if(!pNew)
|
||||
{
|
||||
SCWrite(pCon,"ERROR creating Environment Controller",eError);
|
||||
return 0;
|
||||
}
|
||||
if(!iRet)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: problem initialising Environment controller",
|
||||
eError);
|
||||
pDriv->GetError(pDriv,&iRet,pError,131);
|
||||
sprintf(pBueffel,"HW reported: %s",pError);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
}
|
||||
/* set a few parameters */
|
||||
EVCSetPar(pNew,"upperlimit",300.0,pCon);
|
||||
EVCSetPar(pNew,"lowerlimit",1.0,pCon);
|
||||
/* install command */
|
||||
iRet = AddCommand(pSics,argv[2],ITC4Wrapper,DeleteEVController,
|
||||
pNew);
|
||||
if(!iRet)
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: duplicate command %s not created",argv[2]);
|
||||
DeleteEVController((void *)pNew);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
EVRegisterController(FindEMON(pSics),argv[2],pNew, pCon);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
else if(strcmp(argv[3],"bruker") == 0) /* Bruker Magnet Controller driver */
|
||||
{
|
||||
/* Create a driver */
|
||||
pDriv = CreateBrukerDriver(argc-4,&argv[4]);
|
||||
if(!pDriv)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: failed to create Bruker Controller device driver",eError);
|
||||
return 0;
|
||||
}
|
||||
/* got a driver, initialise everything */
|
||||
pNew = CreateEVController(pDriv,argv[2],&iRet);
|
||||
if(!pNew)
|
||||
{
|
||||
SCWrite(pCon,"ERROR creating Environment Controller",eError);
|
||||
return 0;
|
||||
}
|
||||
if(!iRet)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: problem initialising Environment controller",
|
||||
eError);
|
||||
pDriv->GetError(pDriv,&iRet,pError,131);
|
||||
sprintf(pBueffel,"HW reported: %s",pError);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
}
|
||||
|
||||
/* set a few parameters */
|
||||
EVCSetPar(pNew,"upperlimit",45.0,pCon);
|
||||
EVCSetPar(pNew,"lowerlimit",0.0,pCon);
|
||||
/* install command */
|
||||
iRet = AddCommand(pSics,argv[2],BrukerAction,DeleteEVController,
|
||||
pNew);
|
||||
if(!iRet)
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: duplicate command %s not created",argv[2]);
|
||||
DeleteEVController((void *)pNew);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
EVRegisterController(FindEMON(pSics),argv[2],pNew, pCon);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
else if(strcmp(argv[3],"ltc11") == 0)
|
||||
/* Neocera LTC-11 temperature controller*/
|
||||
{
|
||||
/* Create a driver */
|
||||
pDriv = CreateLTC11Driver(argc-4,&argv[4]);
|
||||
if(!pDriv)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: failed to create LTC-11 device driver",eError);
|
||||
return 0;
|
||||
}
|
||||
/* got a driver, initialise everything */
|
||||
pNew = CreateEVController(pDriv,argv[2],&iRet);
|
||||
if(!pNew)
|
||||
{
|
||||
SCWrite(pCon,"ERROR creating Environment Controller",eError);
|
||||
return 0;
|
||||
}
|
||||
if(!iRet)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: problem initialising Environment controller",
|
||||
eError);
|
||||
pDriv->GetError(pDriv,&iRet,pError,131);
|
||||
sprintf(pBueffel,"HW reported: %s",pError);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
}
|
||||
/* set a few parameters */
|
||||
EVCSetPar(pNew,"upperlimit",500.,pCon);
|
||||
EVCSetPar(pNew,"lowerlimit",1.5,pCon);
|
||||
/* install command */
|
||||
iRet = AddCommand(pSics,argv[2],LTC11Action,DeleteEVController,
|
||||
pNew);
|
||||
if(!iRet)
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: duplicate command %s not created",argv[2]);
|
||||
DeleteEVController((void *)pNew);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
EVRegisterController(FindEMON(pSics),argv[2],pNew, pCon);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}else if(strcmp(argv[3],"a1931") == 0)
|
||||
/* Risoe A1931 temperature controller*/
|
||||
{
|
||||
/* Create a driver */
|
||||
pDriv = CreateA1931Driver(argc-4,&argv[4]);
|
||||
if(!pDriv)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: failed to create A1931 device driver",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
/* got a driver, initialise everything */
|
||||
pNew = CreateEVController(pDriv,argv[2],&iRet);
|
||||
if(!pNew)
|
||||
{
|
||||
SCWrite(pCon,"ERROR creating Environment Controller",eError);
|
||||
return 0;
|
||||
}
|
||||
if(!iRet)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: problem initialising Environment controller",
|
||||
eError);
|
||||
pDriv->GetError(pDriv,&iRet,pError,131);
|
||||
sprintf(pBueffel,"HW reported: %s",pError);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
}
|
||||
/* install command */
|
||||
iRet = AddCommand(pSics,argv[2],A1931Action,DeleteEVController,
|
||||
pNew);
|
||||
if(!iRet)
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: duplicate command %s not created",argv[2]);
|
||||
DeleteEVController((void *)pNew);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
EVRegisterController(FindEMON(pSics),argv[2],pNew, pCon);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
else if(strcmp(argv[3],"tcl") == 0) /* Tcl driver */
|
||||
{
|
||||
/* Create a driver */
|
||||
pDriv = CreateTclDriver(argc-4,&argv[4],argv[2], pCon);
|
||||
if(!pDriv)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: failed to create TCL device driver",eError);
|
||||
return 0;
|
||||
}
|
||||
/* got a driver, initialise everything */
|
||||
pNew = CreateEVController(pDriv,argv[2],&iRet);
|
||||
if(!pNew)
|
||||
{
|
||||
SCWrite(pCon,"ERROR creating Environment Controller",eError);
|
||||
DeleteEVDriver(pDriv);
|
||||
return 0;
|
||||
}
|
||||
if(!iRet)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: problem initialising Environment controller",
|
||||
eError);
|
||||
pDriv->GetError(pDriv,&iRet,pError,131);
|
||||
sprintf(pBueffel,"HW reported: %s",pError);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
}
|
||||
/* install command */
|
||||
iRet = AddCommand(pSics,argv[2],TclEnvironmentWrapper,DeleteEVController,
|
||||
pNew);
|
||||
if(!iRet)
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: duplicate command %s not created",argv[2]);
|
||||
DeleteEVController((void *)pNew);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
pNew->iTcl = 1;
|
||||
/* make ev parameters available to Tcl */
|
||||
UpdateTclVariable(pNew->pDriv,"tolerance",
|
||||
ObVal(pNew->pParam,TOLERANCE));
|
||||
UpdateTclVariable(pNew->pDriv,"upperlimit",
|
||||
ObVal(pNew->pParam,UPLIMIT));
|
||||
UpdateTclVariable(pNew->pDriv,"lowerlimit",
|
||||
ObVal(pNew->pParam,LOWLIMIT));
|
||||
|
||||
/* register controller for monitoring */
|
||||
EVRegisterController(FindEMON(pSics),argv[2],pNew, pCon);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
else if(strcmp(argv[3],"dillu") == 0) /* dillution driver */
|
||||
{
|
||||
/* Create a driver */
|
||||
pDriv = CreateDILLUDriv(argc-4,&argv[4]);
|
||||
if(!pDriv)
|
||||
{
|
||||
SCWrite(pCon,
|
||||
"ERROR: failed to create Dillution device driver",eError);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if(strcmp(argv[3],"gencon") == 0) /* general controller */
|
||||
{
|
||||
/* Create a driver */
|
||||
pDriv = MakeControllerEnvironmentDriver(argc-4,&argv[4]);
|
||||
if(!pDriv)
|
||||
{
|
||||
SCWrite(pCon,
|
||||
"ERROR: failed to create Controller Environment driver",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if(strcmp(argv[3],"euro") == 0) /* dillution driver */
|
||||
{
|
||||
/* Create a driver */
|
||||
pDriv = CreateEURODriv(argc-4,&argv[4]);
|
||||
if(!pDriv)
|
||||
{
|
||||
SCWrite(pCon,
|
||||
"ERROR: failed to create Eurotherm device driver",eError);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if(strcmp(argv[3],"psi-dsp") == 0) /* PSI-DSP magnet driver */
|
||||
{
|
||||
/* Create a driver */
|
||||
pDriv = CreateSLSDriv(argc-4,&argv[4]);
|
||||
if(!pDriv)
|
||||
{
|
||||
SCWrite(pCon,
|
||||
"ERROR: failed to create PSI-DSP device driver",eError);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if(strcmp(argv[3],"el755") == 0) /* EL755 magnet driver */
|
||||
{
|
||||
/* Create a driver */
|
||||
pDriv = CreateEL755Driv(argc-4,&argv[4]);
|
||||
if(!pDriv)
|
||||
{
|
||||
SCWrite(pCon,
|
||||
"ERROR: failed to create EL755 device driver",eError);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: %s not recognized as a valid driver type",
|
||||
argv[3]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
/* got a driver, initialise everything */
|
||||
pNew = CreateEVController(pDriv,argv[2],&iRet);
|
||||
if(!pNew)
|
||||
{
|
||||
SCWrite(pCon,"ERROR creating Environment Controller",eError);
|
||||
return 0;
|
||||
}
|
||||
if(!iRet)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: problem initialising Environment controller",
|
||||
eError);
|
||||
pDriv->GetError(pDriv,&iRet,pError,131);
|
||||
sprintf(pBueffel,"HW reported: %s",pError);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
}
|
||||
|
||||
/* set a few parameters */
|
||||
if(strcmp(argv[3],"euro") == 0)
|
||||
{
|
||||
EVCSetPar(pNew,"upperlimit",750.0,pCon);
|
||||
EVCSetPar(pNew,"lowerlimit",15.0,pCon);
|
||||
}
|
||||
else if(strcmp(argv[3],"el755") == 0)
|
||||
{
|
||||
EVCSetPar(pNew,"upperlimit",10.,pCon);
|
||||
EVCSetPar(pNew,"lowerlimit",-10.,pCon);
|
||||
}
|
||||
else
|
||||
{
|
||||
EVCSetPar(pNew,"upperlimit",4.0,pCon);
|
||||
EVCSetPar(pNew,"lowerlimit",0.05,pCon);
|
||||
}
|
||||
/* install command */
|
||||
iRet = AddCommand(pSics,argv[2],EVControlWrapper,DeleteEVController,
|
||||
pNew);
|
||||
if(!iRet)
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: duplicate command %s not created",argv[2]);
|
||||
DeleteEVController((void *)pNew);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
EVRegisterController(FindEMON(pSics),argv[2],pNew, pCon);
|
||||
EVRegisterController(FindEMON(pSics),argv[2],pNew, pCon);
|
||||
pNew->driverName = strdup(argv[3]);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
#line 211 "evcontroller.w"
|
||||
#line 222 "evcontroller.w"
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
E N V I R O N M E N T C O N T R O L L E R
|
||||
@ -14,7 +14,7 @@
|
||||
#define SICSEVCONTROL
|
||||
#include "varlog.h"
|
||||
|
||||
#line 133 "evcontroller.w"
|
||||
#line 144 "evcontroller.w"
|
||||
|
||||
/*--------------------------- live & death --------------------------------*/
|
||||
typedef struct __EVControl *pEVControl;
|
||||
@ -44,6 +44,6 @@
|
||||
|
||||
|
||||
|
||||
#line 224 "evcontroller.w"
|
||||
#line 235 "evcontroller.w"
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
#line 228 "evcontroller.w"
|
||||
#line 239 "evcontroller.w"
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
Environment controller datastructure
|
||||
@ -18,6 +18,7 @@
|
||||
#define MAXWAIT 7
|
||||
#define SETTLE 8
|
||||
|
||||
|
||||
#line 29 "evcontroller.w"
|
||||
|
||||
typedef struct __EVControl {
|
||||
@ -29,9 +30,11 @@
|
||||
pEVDriver pDriv;
|
||||
EVMode eMode;
|
||||
float fTarget;
|
||||
time_t start;
|
||||
time_t lastt;
|
||||
time_t start;
|
||||
time_t lastt;
|
||||
char *pName;
|
||||
char *driverName;
|
||||
char *errorScript;
|
||||
ObPar *pParam;
|
||||
int iLog;
|
||||
pVarLog pLog;
|
||||
@ -42,5 +45,5 @@
|
||||
void (*KillPrivate)(void *pData);
|
||||
} EVControl;
|
||||
|
||||
#line 244 "evcontroller.w"
|
||||
#line 257 "evcontroller.w"
|
||||
|
||||
|
@ -41,7 +41,11 @@ $\langle$evdata {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@ pEVDriver pDriv;@\\
|
||||
\mbox{}\verb@ EVMode eMode;@\\
|
||||
\mbox{}\verb@ float fTarget;@\\
|
||||
\mbox{}\verb@ time_t start;@\\
|
||||
\mbox{}\verb@ time_t lastt;@\\
|
||||
\mbox{}\verb@ char *pName;@\\
|
||||
\mbox{}\verb@ char *driverName;@\\
|
||||
\mbox{}\verb@ char *errorScript;@\\
|
||||
\mbox{}\verb@ ObPar *pParam;@\\
|
||||
\mbox{}\verb@ int iLog;@\\
|
||||
\mbox{}\verb@ pVarLog pLog;@\\
|
||||
@ -69,8 +73,13 @@ reached its target value. Then there is a pointer to a callback
|
||||
interface. The fifth field is a pointer to the driver for
|
||||
the actual hardware. Next is the mode the device is in. Of course there
|
||||
must be floating point value which defines the current target value for the
|
||||
device. pName is a pointer to a string representing the name of the
|
||||
controller. Then there is a
|
||||
device. start and lastt are used to control the settling time.
|
||||
|
||||
pName is a pointer to a string representing the name of the
|
||||
controller. driverName is the name of the driver used by this
|
||||
device. errorScript is the name of a script command to run when the
|
||||
controller goes out of tolerance.
|
||||
Then there is a
|
||||
parameter array. iLog is a boolean which says if data should be logged
|
||||
for this controller or not. pLog is the a pointer to a Varlog structure
|
||||
holding the logging information. Then there is a switch, iWarned, which is
|
||||
@ -94,6 +103,8 @@ $\langle$evdriv {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@ typedef struct __EVDriver {@\\
|
||||
\mbox{}\verb@ int (*SetValue)(pEVDriver self, float fNew);@\\
|
||||
\mbox{}\verb@ int (*GetValue)(pEVDriver self, float *fPos);@\\
|
||||
\mbox{}\verb@ int (*GetValues)(pEVDriver self, float *fTarget,@\\
|
||||
\mbox{}\verb@ float *fPos, float *fDelta);@\\
|
||||
\mbox{}\verb@ int (*Send)(pEVDriver self, char *pCommand,@\\
|
||||
\mbox{}\verb@ char *pReplyBuffer, int iReplBufLen); @\\
|
||||
\mbox{}\verb@ int (*GetError)(pEVDriver self, int *iCode,@\\
|
||||
@ -290,6 +301,8 @@ See the documentation for commands understood.
|
||||
\mbox{}\verb@#define UPLIMIT 4@\\
|
||||
\mbox{}\verb@#define LOWLIMIT 5@\\
|
||||
\mbox{}\verb@#define SAFEVALUE 6@\\
|
||||
\mbox{}\verb@#define MAXWAIT 7@\\
|
||||
\mbox{}\verb@#define SETTLE 8@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@@$\langle$evdata {\footnotesize ?}$\rangle$\verb@@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
|
@ -36,7 +36,11 @@ used by EVControl:
|
||||
pEVDriver pDriv;
|
||||
EVMode eMode;
|
||||
float fTarget;
|
||||
time_t start;
|
||||
time_t lastt;
|
||||
char *pName;
|
||||
char *driverName;
|
||||
char *errorScript;
|
||||
ObPar *pParam;
|
||||
int iLog;
|
||||
pVarLog pLog;
|
||||
@ -57,8 +61,13 @@ reached its target value. Then there is a pointer to a callback
|
||||
interface. The fifth field is a pointer to the driver for
|
||||
the actual hardware. Next is the mode the device is in. Of course there
|
||||
must be floating point value which defines the current target value for the
|
||||
device. pName is a pointer to a string representing the name of the
|
||||
controller. Then there is a
|
||||
device. start and lastt are used to control the settling time.
|
||||
|
||||
pName is a pointer to a string representing the name of the
|
||||
controller. driverName is the name of the driver used by this
|
||||
device. errorScript is the name of a script command to run when the
|
||||
controller goes out of tolerance.
|
||||
Then there is a
|
||||
parameter array. iLog is a boolean which says if data should be logged
|
||||
for this controller or not. pLog is the a pointer to a Varlog structure
|
||||
holding the logging information. Then there is a switch, iWarned, which is
|
||||
@ -77,6 +86,8 @@ used:
|
||||
typedef struct __EVDriver {
|
||||
int (*SetValue)(pEVDriver self, float fNew);
|
||||
int (*GetValue)(pEVDriver self, float *fPos);
|
||||
int (*GetValues)(pEVDriver self, float *fTarget,
|
||||
float *fPos, float *fDelta);
|
||||
int (*Send)(pEVDriver self, char *pCommand,
|
||||
char *pReplyBuffer, int iReplBufLen);
|
||||
int (*GetError)(pEVDriver self, int *iCode,
|
||||
@ -240,6 +251,8 @@ See the documentation for commands understood.
|
||||
#define UPLIMIT 4
|
||||
#define LOWLIMIT 5
|
||||
#define SAFEVALUE 6
|
||||
#define MAXWAIT 7
|
||||
#define SETTLE 8
|
||||
|
||||
@<evdata@>
|
||||
@}
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
#line 247 "evcontroller.w"
|
||||
#line 260 "evcontroller.w"
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
Environment device driver datastructure
|
||||
@ -12,13 +12,13 @@
|
||||
#define DEVREDO 2
|
||||
|
||||
|
||||
#line 76 "evcontroller.w"
|
||||
#line 85 "evcontroller.w"
|
||||
|
||||
typedef struct __EVDriver {
|
||||
int (*SetValue)(pEVDriver self, float fNew);
|
||||
int (*GetValue)(pEVDriver self, float *fPos);
|
||||
int (*GetValues)(pEVDriver self, float *fTarget,
|
||||
float *fPos, float *fDelta);
|
||||
float *fPos, float *fDelta);
|
||||
int (*Send)(pEVDriver self, char *pCommand,
|
||||
char *pReplyBuffer, int iReplBufLen);
|
||||
int (*GetError)(pEVDriver self, int *iCode,
|
||||
@ -30,7 +30,7 @@
|
||||
void (*KillPrivate)(void *pData);
|
||||
} EVDriver;
|
||||
|
||||
#line 258 "evcontroller.w"
|
||||
#line 271 "evcontroller.w"
|
||||
|
||||
/*-------------------- life & death of a driver --------------------------*/
|
||||
pEVDriver CreateEVDriver(int argc, char *argv[]);
|
||||
|
10
event.h
10
event.h
@ -1,5 +1,5 @@
|
||||
|
||||
#line 77 "event.w"
|
||||
#line 79 "event.w"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
E V E N T
|
||||
@ -18,7 +18,7 @@
|
||||
|
||||
int Text2Event(char *pText);
|
||||
|
||||
#line 90 "event.w"
|
||||
#line 92 "event.w"
|
||||
|
||||
|
||||
|
||||
@ -39,18 +39,18 @@
|
||||
#define FILELOADED 12
|
||||
#define MOTEND 13
|
||||
|
||||
#line 92 "event.w"
|
||||
#line 94 "event.w"
|
||||
|
||||
|
||||
/*--------------- Signals for the Signalfunction of each task ------------*/
|
||||
|
||||
#line 62 "event.w"
|
||||
#line 64 "event.w"
|
||||
|
||||
#define SICSINT 300
|
||||
#define SICSBROADCAST 301
|
||||
#define TOKENGRAB 302
|
||||
#define TOKENRELEASE 303
|
||||
|
||||
#line 95 "event.w"
|
||||
#line 97 "event.w"
|
||||
|
||||
#endif
|
||||
|
40
event.tex
40
event.tex
@ -1,3 +1,13 @@
|
||||
\newcommand{\NWtarget}[2]{#2}
|
||||
\newcommand{\NWlink}[2]{#2}
|
||||
\newcommand{\NWtxtMacroDefBy}{Macro defined by}
|
||||
\newcommand{\NWtxtMacroRefIn}{Macro referenced in}
|
||||
\newcommand{\NWtxtMacroNoRef}{Macro never referenced}
|
||||
\newcommand{\NWtxtDefBy}{Defined by}
|
||||
\newcommand{\NWtxtRefIn}{Referenced in}
|
||||
\newcommand{\NWtxtNoRef}{Not referenced}
|
||||
\newcommand{\NWtxtFileDefBy}{File defined by}
|
||||
\newcommand{\NWsep}{${\diamond}$}
|
||||
\subsection{SICS Events}
|
||||
This section lists the callback events known to Sics, their purpose, and
|
||||
their associated event datastructures when applicable. See the
|
||||
@ -12,17 +22,17 @@ This module defines several event related functions as well.
|
||||
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap1}
|
||||
$\langle$eFunc {\footnotesize ?}$\rangle\equiv$
|
||||
$\langle\,$eFunc\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ int Text2Event(char *pText);@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\mbox{}\verb@@{\NWsep}
|
||||
\end{list}
|
||||
\vspace{-1ex}
|
||||
\footnotesize\addtolength{\baselineskip}{-1ex}
|
||||
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
||||
\item Macro referenced in scrap ?.
|
||||
\item \NWtxtMacroRefIn\ \NWlink{nuweb?}{?}.
|
||||
\end{list}
|
||||
\end{minipage}\\[4ex]
|
||||
\end{flushleft}
|
||||
@ -31,7 +41,7 @@ if the event code is not known, else the apropriate event code.
|
||||
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap2}
|
||||
$\langle$VE {\footnotesize ?}$\rangle\equiv$
|
||||
$\langle\,$VE\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
@ -48,12 +58,13 @@ $\langle$VE {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@#define COUNTSTART 10@\\
|
||||
\mbox{}\verb@#define COUNTEND 11@\\
|
||||
\mbox{}\verb@#define FILELOADED 12@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\mbox{}\verb@#define MOTEND 13@\\
|
||||
\mbox{}\verb@@{\NWsep}
|
||||
\end{list}
|
||||
\vspace{-1ex}
|
||||
\footnotesize\addtolength{\baselineskip}{-1ex}
|
||||
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
||||
\item Macro referenced in scrap ?.
|
||||
\item \NWtxtMacroRefIn\ \NWlink{nuweb?}{?}.
|
||||
\end{list}
|
||||
\end{minipage}\\[4ex]
|
||||
\end{flushleft}
|
||||
@ -76,6 +87,7 @@ fiffractometer has been measured.
|
||||
\item[COUNTSTART] is an event which signals the start of a counting
|
||||
operation.
|
||||
\item[COUNTEND] is an event signalling the end of a counting operation.
|
||||
\item[MOTEND] signals the end of a driving operation.
|
||||
\end{description}
|
||||
|
||||
Furthermore event contains system wide signal codes which are interpreted in
|
||||
@ -86,7 +98,7 @@ possible codes are defined.
|
||||
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap3}
|
||||
$\langle$VSIG {\footnotesize ?}$\rangle\equiv$
|
||||
$\langle\,$VSIG\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
@ -94,12 +106,12 @@ $\langle$VSIG {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@#define SICSBROADCAST 301@\\
|
||||
\mbox{}\verb@#define TOKENGRAB 302@\\
|
||||
\mbox{}\verb@#define TOKENRELEASE 303@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\mbox{}\verb@@{\NWsep}
|
||||
\end{list}
|
||||
\vspace{-1ex}
|
||||
\footnotesize\addtolength{\baselineskip}{-1ex}
|
||||
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
||||
\item Macro referenced in scrap ?.
|
||||
\item \NWtxtMacroRefIn\ \NWlink{nuweb?}{?}.
|
||||
\end{list}
|
||||
\end{minipage}\\[4ex]
|
||||
\end{flushleft}
|
||||
@ -114,7 +126,7 @@ data is the string to send.
|
||||
\end{description}
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap4}
|
||||
\verb@"event.h"@ {\footnotesize ? }$\equiv$
|
||||
\verb@"event.h"@\nobreak\ {\footnotesize \NWtarget{nuweb?}{?} }$\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
@ -130,14 +142,14 @@ data is the string to send.
|
||||
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
|
||||
\mbox{}\verb@#ifndef SICSEVENT@\\
|
||||
\mbox{}\verb@#define SICSEVENT@\\
|
||||
\mbox{}\verb@@$\langle$eFunc {\footnotesize ?}$\rangle$\verb@@\\
|
||||
\mbox{}\verb@@\hbox{$\langle\,$eFunc\nobreak\ {\footnotesize \NWlink{nuweb?}{?}}$\,\rangle$}\verb@@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@@$\langle$VE {\footnotesize ?}$\rangle$\verb@@\\
|
||||
\mbox{}\verb@@\hbox{$\langle\,$VE\nobreak\ {\footnotesize \NWlink{nuweb?}{?}}$\,\rangle$}\verb@@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@/*--------------- Signals for the Signalfunction of each task ------------*/@\\
|
||||
\mbox{}\verb@@$\langle$VSIG {\footnotesize ?}$\rangle$\verb@ @\\
|
||||
\mbox{}\verb@@\hbox{$\langle\,$VSIG\nobreak\ {\footnotesize \NWlink{nuweb?}{?}}$\,\rangle$}\verb@ @\\
|
||||
\mbox{}\verb@#endif@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\mbox{}\verb@@{\NWsep}
|
||||
\end{list}
|
||||
\vspace{-2ex}
|
||||
\end{minipage}\\[4ex]
|
||||
|
2
event.w
2
event.w
@ -31,6 +31,7 @@ if the event code is not known, else the apropriate event code.
|
||||
#define COUNTSTART 10
|
||||
#define COUNTEND 11
|
||||
#define FILELOADED 12
|
||||
#define MOTEND 13
|
||||
@}
|
||||
\begin{description}
|
||||
\item[VALUECHANGE] This is a variable changing its value. As event data a pointer to the
|
||||
@ -51,6 +52,7 @@ fiffractometer has been measured.
|
||||
\item[COUNTSTART] is an event which signals the start of a counting
|
||||
operation.
|
||||
\item[COUNTEND] is an event signalling the end of a counting operation.
|
||||
\item[MOTEND] signals the end of a driving operation.
|
||||
\end{description}
|
||||
|
||||
Furthermore event contains system wide signal codes which are interpreted in
|
||||
|
22
fitcenter.c
22
fitcenter.c
@ -102,17 +102,21 @@
|
||||
GetScanVarName(self->pScan,0,self->pName,131);
|
||||
|
||||
/* correct fAxis for softzero points and sign
|
||||
when the scan variable is a motor */
|
||||
pMot = FindMotor(pServ->pSics,self->pName);
|
||||
if(pMot)
|
||||
when the scan variable is a motor
|
||||
*/
|
||||
if(!isScanVarSoft(self->pScan))
|
||||
{
|
||||
i = MotorGetPar(pMot,"softzero",&fZero);
|
||||
i = MotorGetPar(pMot,"sign",&fSign);
|
||||
assert(i);
|
||||
for(i = 0; i < self->iNP; i++)
|
||||
pMot = FindMotor(pServ->pSics,self->pName);
|
||||
if(pMot)
|
||||
{
|
||||
self->fAxis[i] -= fZero;
|
||||
self->fAxis[i] *= fSign;
|
||||
i = MotorGetPar(pMot,"softzero",&fZero);
|
||||
i = MotorGetPar(pMot,"sign",&fSign);
|
||||
assert(i);
|
||||
for(i = 0; i < self->iNP; i++)
|
||||
{
|
||||
self->fAxis[i] -= fZero;
|
||||
self->fAxis[i] *= fSign;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
152
help.c
Normal file
152
help.c
Normal file
@ -0,0 +1,152 @@
|
||||
/*-----------------------------------------------------------------------
|
||||
Implementation file for the SICS help system.
|
||||
|
||||
copyright: see file COPYRIGHT
|
||||
|
||||
Mark Koennecke, December 2003
|
||||
-----------------------------------------------------------------------*/
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include "fortify.h"
|
||||
#include "sics.h"
|
||||
#include "help.h"
|
||||
|
||||
extern char *stptok(const char *s, char *tok, size_t toklen, char *brk);
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
#define PATHSEP ":"
|
||||
#define DIRSEP "/"
|
||||
static char *helpDirs = NULL;
|
||||
static char *defaultFile="master.txt";
|
||||
/*----------------------------------------------------------------------*/
|
||||
void KillHelp(void *pData){
|
||||
if(helpDirs != NULL){
|
||||
free(helpDirs);
|
||||
helpDirs = NULL;
|
||||
}
|
||||
if(defaultFile != NULL){
|
||||
free(defaultFile);
|
||||
defaultFile = NULL;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static FILE *findHelpFile(char *name){
|
||||
FILE *fd = NULL;
|
||||
char pBueffel[256];
|
||||
char dir[132];
|
||||
char *pPtr;
|
||||
|
||||
if(helpDirs == NULL){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pPtr = helpDirs;
|
||||
while( (pPtr = stptok(pPtr,dir,131,PATHSEP)) != NULL){
|
||||
strcpy(pBueffel,dir);
|
||||
strcat(pBueffel,DIRSEP);
|
||||
strncat(pBueffel,name,(254-strlen(pBueffel)));
|
||||
fd = fopen(pBueffel,"r");
|
||||
if(fd != NULL){
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
this means: not found!
|
||||
*/
|
||||
return NULL;
|
||||
}
|
||||
/*----------------------------------------------------------------------*/
|
||||
static void printHelpFile(SConnection *pCon, FILE *fd){
|
||||
char line[132];
|
||||
|
||||
while(fgets(line,131,fd) != NULL){
|
||||
SCWrite(pCon,line,eValue);
|
||||
}
|
||||
}
|
||||
/*----------------------------------------------------------------------*/
|
||||
static void configureHelp(SConnection *pCon,
|
||||
char *option, char *parameter){
|
||||
char *pPtr = NULL;
|
||||
int length;
|
||||
|
||||
strtolower(option);
|
||||
if(strcmp(option,"adddir") == 0){
|
||||
if(parameter == NULL){
|
||||
SCWrite(pCon,helpDirs,eValue);
|
||||
return;
|
||||
} else {
|
||||
pPtr = helpDirs;
|
||||
if(pPtr != NULL){
|
||||
length = strlen(pPtr) + strlen(PATHSEP) + strlen(parameter) + 2;
|
||||
helpDirs = (char *)malloc(length*sizeof(char));
|
||||
memset(helpDirs,0,length*sizeof(char));
|
||||
strcpy(helpDirs,pPtr);
|
||||
strcat(helpDirs,PATHSEP);
|
||||
strcat(helpDirs,parameter);
|
||||
free(pPtr);
|
||||
} else {
|
||||
helpDirs=strdup(parameter);
|
||||
}
|
||||
}
|
||||
} else if(strcmp(option,"defaultfile") == 0){
|
||||
if(parameter == NULL){
|
||||
SCWrite(pCon,defaultFile,eValue);
|
||||
return;
|
||||
} else {
|
||||
if(defaultFile != NULL){
|
||||
free(defaultFile);
|
||||
}
|
||||
defaultFile = strdup(parameter);
|
||||
}
|
||||
} else {
|
||||
SCWrite(pCon,"Unknown option to configure",eWarning);
|
||||
SCWrite(pCon,"Known options: defaultfile, adddir",eWarning);
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
int SicsHelp(SConnection *pCon,SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]){
|
||||
char helpFile[256];
|
||||
FILE *fd = NULL;
|
||||
|
||||
strncpy(helpFile,defaultFile,255);
|
||||
|
||||
if(argc > 1){
|
||||
strtolower(argv[1]);
|
||||
/*
|
||||
check for configure
|
||||
*/
|
||||
if(strcmp(argv[1],"configure") == 0){
|
||||
if(argc < 3){
|
||||
SCWrite(pCon,"ERROR: need an option to configure",eError);
|
||||
return 0;
|
||||
}
|
||||
if(argc > 3){
|
||||
configureHelp(pCon,argv[2],argv[3]);
|
||||
} else {
|
||||
configureHelp(pCon,argv[2],NULL);
|
||||
}
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
the parameter is a help file name
|
||||
*/
|
||||
strncpy(helpFile,argv[1],255);
|
||||
strncat(helpFile,".txt",255);
|
||||
}
|
||||
|
||||
/*
|
||||
print the helpFile
|
||||
*/
|
||||
fd = findHelpFile(helpFile);
|
||||
if(fd == NULL){
|
||||
SCWrite(pCon,"ERROR: failed to locate helpFile:",eError);
|
||||
SCWrite(pCon,helpFile,eError);
|
||||
return 0;
|
||||
}
|
||||
printHelpFile(pCon,fd);
|
||||
fclose(fd);
|
||||
}
|
17
help.h
Normal file
17
help.h
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
Header file for the SICS help system.
|
||||
|
||||
copyright: see file COPYRIGHT
|
||||
|
||||
Mark Koennecke, December 2003
|
||||
-----------------------------------------------------------------------*/
|
||||
#ifndef SICSHELP
|
||||
#define SICSHELP
|
||||
|
||||
int SicsHelp(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
|
||||
void KillHelp(void *pData);
|
||||
#endif
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user