- New batch file management module
- New oscillator module - Bug fixes SKIPPED: psi/buffer.c psi/el734hp.c psi/el737hpdriv.c psi/make_gen psi/nextrics.c psi/nxamor.c psi/pimotor.c psi/polterwrite.c psi/psi.c psi/swmotor2.c psi/tasscan.c psi/tricssupport.c psi/tricssupport.h psi/tecs/make_gen psi/utils/ecb_load_new/ecb_load.c psi/utils/ecb_load_new/ecb_load.h psi/utils/ecb_load_new/ecbdriv_els.c psi/utils/ecb_load_new/gpib_els.c psi/utils/ecb_load_new/makefile psi/utils/ecb_load_new/makefile_EGPIB psi/utils/ecb_load_new/makefile_GPIB
This commit is contained in:
21
confvirtmot.h
Normal file
21
confvirtmot.h
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
A configurable virtual motor object. At motor start a script is called
|
||||
which returns the motors and positions to drive as a comma separated
|
||||
list holding entries of the form mot=value.
|
||||
|
||||
COPYRIGHT: see file COPYRIGHT
|
||||
|
||||
Mark Koennecke, August 2004
|
||||
-------------------------------------------------------------------------*/
|
||||
#ifndef CONFIGURABLEVIRTUALMOTOR
|
||||
#define CONFIGURABLEVIRTUALMOTOR
|
||||
|
||||
#include "sics.h"
|
||||
|
||||
int MakeConfigurableVirtualMotor(SConnection *pCon, SicsInterp *pSics,
|
||||
void *data, int aargc, char *argv[]);
|
||||
int ConfigurableVirtualMotorAction(SConnection *pCon, SicsInterp *pSics,
|
||||
void *data, int argc, char *argv[]);
|
||||
#endif
|
||||
|
19
confvirtmot.i
Normal file
19
confvirtmot.i
Normal file
@ -0,0 +1,19 @@
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
Configurable Virtual Motor. This is an generated file describing the
|
||||
internal data structure of this object. Do not edit.
|
||||
-----------------------------------------------------------------------*/
|
||||
|
||||
typedef struct __CONFVIRTMOT {
|
||||
pObjectDescriptor pDes;
|
||||
pIDrivable pDriv;
|
||||
char *scriptName;
|
||||
char *readScript;
|
||||
int motorList;
|
||||
float targetValue;
|
||||
int targetReached;
|
||||
char scriptError[512];
|
||||
int parseOK;
|
||||
}ConfigurableVirtualMotor, *pConfigurableVirtualMotor;
|
||||
|
||||
|
467
confvirtualmot.c
Normal file
467
confvirtualmot.c
Normal file
@ -0,0 +1,467 @@
|
||||
/*-----------------------------------------------------------------------
|
||||
A configurable virtual motor object. At motor start a script is called
|
||||
which returns the motors and positions to drive as a comma separated
|
||||
list holding entries of the form mot=value.
|
||||
|
||||
This is the implementation file.
|
||||
|
||||
COPYRIGHT: see file COPYRIGHT
|
||||
|
||||
Mark Koennecke, August 2004
|
||||
-------------------------------------------------------------------------*/
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "fortify.h"
|
||||
#include <tcl.h>
|
||||
#include "lld.h"
|
||||
#include "splitter.h"
|
||||
#include "confvirtmot.h"
|
||||
#include "confvirtmot.i"
|
||||
|
||||
extern char *stptok(char *s, char *t, int len, char *brk);
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
An internal data structure which holds information required to control
|
||||
the real motors
|
||||
----------------------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
char name[132];
|
||||
void *data;
|
||||
pIDrivable pDriv;
|
||||
float value;
|
||||
int running;
|
||||
} RealMotor, *pRealMotor;
|
||||
/*---------------------------------------------------------------------*/
|
||||
static int HaltMotors(void *pData){
|
||||
pConfigurableVirtualMotor self = (pConfigurableVirtualMotor)pData;
|
||||
RealMotor tuktuk;
|
||||
int iRet;
|
||||
|
||||
iRet = LLDnodePtr2First(self->motorList);
|
||||
while(iRet != 0)
|
||||
{
|
||||
LLDnodeDataTo(self->motorList,&tuktuk);
|
||||
tuktuk.pDriv->Halt(tuktuk.data);
|
||||
iRet = LLDnodePtr2Next(self->motorList);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*----------------------------------------------------------------------*/
|
||||
static char *invokeMotorScript(pConfigurableVirtualMotor self,
|
||||
float newValue){
|
||||
char pBueffel[512];
|
||||
Tcl_Interp *pTcl;
|
||||
int status;
|
||||
|
||||
self->parseOK = 1;
|
||||
if(self->scriptName == NULL){
|
||||
snprintf(self->scriptError,511,
|
||||
"ERROR: no script configured for configurable virtual motor");
|
||||
self->parseOK = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
snprintf(pBueffel,510,"%s %f",self->scriptName, newValue);
|
||||
pTcl = InterpGetTcl(pServ->pSics);
|
||||
|
||||
status = Tcl_Eval(pTcl, pBueffel);
|
||||
if(status != TCL_OK){
|
||||
snprintf(self->scriptError,510,"ERROR: Tcl subsystem reported %s",
|
||||
Tcl_GetStringResult(pTcl));
|
||||
self->parseOK = 0;
|
||||
return NULL;
|
||||
}
|
||||
return Tcl_GetStringResult(pTcl);
|
||||
}
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
static int parseEntry(pConfigurableVirtualMotor self,
|
||||
char *entry){
|
||||
RealMotor tuktuk;
|
||||
char *pPtr = NULL;
|
||||
char number[80], pError[256];
|
||||
CommandList *pCom = NULL;
|
||||
int status;
|
||||
|
||||
pPtr = entry;
|
||||
pPtr = stptok(pPtr,tuktuk.name,131,"=");
|
||||
if(pPtr == NULL){
|
||||
snprintf(self->scriptError,510,"ERROR: cannot interpret %s, %s", entry,
|
||||
"require format: motor=value");
|
||||
self->parseOK = 0;
|
||||
return 0;
|
||||
}
|
||||
tuktuk.pDriv = (pIDrivable)FindDrivable(pServ->pSics,tuktuk.name);
|
||||
pCom = FindCommand(pServ->pSics,tuktuk.name);
|
||||
if(!pCom){
|
||||
snprintf(self->scriptError,510,"ERROR: %s not found",tuktuk.name);
|
||||
self->parseOK = 0;
|
||||
return 0;
|
||||
}
|
||||
tuktuk.data = pCom->pData;
|
||||
|
||||
if(tuktuk.pDriv == NULL){
|
||||
snprintf(self->scriptError,510,"ERROR: %s is not drivable",tuktuk.name);
|
||||
self->parseOK = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
pPtr = stptok(pPtr,number,79,"=");
|
||||
tuktuk.value = atof(number);
|
||||
|
||||
LLDnodeAppendFrom(self->motorList,&tuktuk);
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*----------------------------------------------------------------------*/
|
||||
static int parseCommandList(pConfigurableVirtualMotor self,
|
||||
char *commandList){
|
||||
char pEntry[256], *pPtr;
|
||||
int status;
|
||||
|
||||
LLDdelete(self->motorList);
|
||||
self->motorList = LLDcreate(sizeof(RealMotor));
|
||||
|
||||
pPtr = commandList;
|
||||
while((pPtr = stptok(pPtr,pEntry,255,",")) != NULL){
|
||||
status = parseEntry(self,pEntry);
|
||||
if(status != 1){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static int startMotorList(pConfigurableVirtualMotor self, SConnection *pCon){
|
||||
RealMotor tuktuk;
|
||||
int status, iRet;
|
||||
|
||||
iRet = LLDnodePtr2First(self->motorList);
|
||||
while(iRet != 0)
|
||||
{
|
||||
LLDnodeDataTo(self->motorList,&tuktuk);
|
||||
status = tuktuk.pDriv->SetValue(tuktuk.data,pCon,tuktuk.value);
|
||||
if(status != 1){
|
||||
return status;
|
||||
}
|
||||
tuktuk.running = 1;
|
||||
LLDnodeDataFrom(self->motorList,&tuktuk);
|
||||
iRet = LLDnodePtr2Next(self->motorList);
|
||||
}
|
||||
return OKOK;
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
static long ConfSetValue(void *pData, SConnection *pCon, float newValue){
|
||||
pConfigurableVirtualMotor self = (pConfigurableVirtualMotor)pData;
|
||||
char *commandList = NULL;
|
||||
int status;
|
||||
|
||||
assert(self != NULL);
|
||||
|
||||
commandList = invokeMotorScript(self,newValue);
|
||||
if(commandList == NULL){
|
||||
SCWrite(pCon,self->scriptError,eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
status = parseCommandList(self,commandList);
|
||||
if(status != 1){
|
||||
SCWrite(pCon,self->scriptError,eError);
|
||||
return 0;
|
||||
}
|
||||
self->targetValue = newValue;
|
||||
self->targetReached = 0;
|
||||
|
||||
status = startMotorList(self,pCon);
|
||||
if(status != OKOK){
|
||||
HaltMotors(self);
|
||||
}
|
||||
return OKOK;
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static int ConfCheckLimits(void *pData, float fVal, char *error, int errLen){
|
||||
pConfigurableVirtualMotor self = (pConfigurableVirtualMotor)pData;
|
||||
char *commandList = NULL;
|
||||
int status, iRet;
|
||||
RealMotor tuktuk;
|
||||
|
||||
assert(self != NULL);
|
||||
|
||||
if(self->targetValue != fVal){
|
||||
commandList = invokeMotorScript(self,fVal);
|
||||
if(commandList == NULL){
|
||||
strncpy(error,self->scriptError,errLen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
status = parseCommandList(self,commandList);
|
||||
if(status != 1){
|
||||
strncpy(error,self->scriptError,errLen);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
iRet = LLDnodePtr2First(self->motorList);
|
||||
while(iRet != 0)
|
||||
{
|
||||
LLDnodeDataTo(self->motorList,&tuktuk);
|
||||
status = tuktuk.pDriv->CheckLimits(tuktuk.data,fVal,error,errLen);
|
||||
if(status != 1){
|
||||
return status;
|
||||
}
|
||||
iRet = LLDnodePtr2Next(self->motorList);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
static int ConfCheckStatus(void *pData, SConnection *pCon){
|
||||
pConfigurableVirtualMotor self = (pConfigurableVirtualMotor)pData;
|
||||
RealMotor tuktuk;
|
||||
int iRet, status, result;
|
||||
|
||||
result = HWIdle;
|
||||
iRet = LLDnodePtr2First(self->motorList);
|
||||
while(iRet != 0)
|
||||
{
|
||||
LLDnodeDataTo(self->motorList,&tuktuk);
|
||||
if(tuktuk.running == 1){
|
||||
status = tuktuk.pDriv->CheckStatus(tuktuk.data, pCon);
|
||||
switch(status){
|
||||
case HWIdle:
|
||||
tuktuk.running = 0;
|
||||
LLDnodeDataFrom(self->motorList,&tuktuk);
|
||||
break;
|
||||
case HWBusy:
|
||||
result = HWBusy;
|
||||
break;
|
||||
case HWFault:
|
||||
case HWPosFault:
|
||||
return status;
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
this is a programming error and has to be fixed
|
||||
*/
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
iRet = LLDnodePtr2Next(self->motorList);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/*---------------------------------------------------------------------*/
|
||||
static float invokeReadScript(pConfigurableVirtualMotor self,
|
||||
SConnection *pCon){
|
||||
Tcl_Interp *pTcl;
|
||||
int status;
|
||||
|
||||
pTcl = InterpGetTcl(pServ->pSics);
|
||||
|
||||
status = Tcl_Eval(pTcl, self->readScript);
|
||||
if(status != TCL_OK){
|
||||
snprintf(self->scriptError,510,"ERROR: Tcl subsystem reported %s",
|
||||
Tcl_GetStringResult(pTcl));
|
||||
}
|
||||
return atof(Tcl_GetStringResult(pTcl));
|
||||
}
|
||||
/*---------------------------------------------------------------------*/
|
||||
static void checkMotorValues(pConfigurableVirtualMotor self,
|
||||
SConnection *pCon){
|
||||
int iRet;
|
||||
float value;
|
||||
RealMotor tuktuk;
|
||||
char pBueffel[512];
|
||||
|
||||
iRet = LLDnodePtr2First(self->motorList);
|
||||
while(iRet != 0)
|
||||
{
|
||||
LLDnodeDataTo(self->motorList,&tuktuk);
|
||||
value = tuktuk.pDriv->GetValue(tuktuk.data,pCon);
|
||||
value -= tuktuk.value;
|
||||
if(value < .0){
|
||||
value *= -1;
|
||||
}
|
||||
if(value > .1) {
|
||||
snprintf(pBueffel,510,"WARNING: motor %s of position by %f",
|
||||
tuktuk.name,value);
|
||||
SCWrite(pCon,pBueffel,eWarning);
|
||||
return;
|
||||
}
|
||||
iRet = LLDnodePtr2Next(self->motorList);
|
||||
}
|
||||
self->targetReached = 1;
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static float ConfGetValue(void *pData, SConnection *pCon){
|
||||
pConfigurableVirtualMotor self = (pConfigurableVirtualMotor)pData;
|
||||
float currentValue = -9999.99;
|
||||
|
||||
assert(self != NULL);
|
||||
|
||||
if(self->readScript != NULL){
|
||||
currentValue = invokeReadScript(self,pCon);
|
||||
} else {
|
||||
if(self->targetReached == 1){
|
||||
return self->targetValue;
|
||||
} else {
|
||||
checkMotorValues(self,pCon);
|
||||
if(self->targetReached){
|
||||
currentValue = self->targetValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return currentValue;
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static void *GetConfigurableVirtualMotorInterface(void *pData, int iID){
|
||||
pConfigurableVirtualMotor self = NULL;
|
||||
|
||||
self = (pConfigurableVirtualMotor)pData;
|
||||
assert(self);
|
||||
if(iID == DRIVEID){
|
||||
return self->pDriv;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static void KillConfigurableVirtualMotor(void *data){
|
||||
pConfigurableVirtualMotor self = NULL;
|
||||
|
||||
self = (pConfigurableVirtualMotor)data;
|
||||
if(self != NULL){
|
||||
if(self->pDes != NULL){
|
||||
DeleteDescriptor(self->pDes);
|
||||
self->pDes = NULL;
|
||||
}
|
||||
LLDdelete(self->motorList);
|
||||
if(self->scriptName != NULL){
|
||||
free(self->scriptName);
|
||||
self->scriptName = NULL;
|
||||
}
|
||||
if(self->readScript != NULL){
|
||||
free(self->readScript);
|
||||
self->readScript = NULL;
|
||||
}
|
||||
free(self);
|
||||
self = NULL;
|
||||
}
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
int MakeConfigurableVirtualMotor(SConnection *pCon, SicsInterp *pSics,
|
||||
void *data, int argc, char *argv[]){
|
||||
pConfigurableVirtualMotor pNew = NULL;
|
||||
char pBueffel[512];
|
||||
|
||||
if(argc < 2){
|
||||
SCWrite(pCon,"ERROR: need name to create configurable motor",eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pNew = (pConfigurableVirtualMotor)malloc(sizeof(ConfigurableVirtualMotor));
|
||||
if(pNew == NULL){
|
||||
SCWrite(pCon,"ERROR: no memory to create configurable virtual motor",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
memset(pNew,0,sizeof(ConfigurableVirtualMotor));
|
||||
|
||||
pNew->pDes = CreateDescriptor("ConfigurableVirtualMotor");
|
||||
pNew->pDriv = CreateDrivableInterface();
|
||||
pNew->motorList = LLDcreate(sizeof(RealMotor));
|
||||
if(pNew->pDes == NULL || pNew->pDriv == NULL || pNew->motorList < 0){
|
||||
SCWrite(pCon,"ERROR: no memory to create configurable virtual motor",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
assign functions
|
||||
*/
|
||||
pNew->pDes->GetInterface = GetConfigurableVirtualMotorInterface;
|
||||
pNew->pDriv->Halt = HaltMotors;
|
||||
pNew->pDriv->CheckLimits = ConfCheckLimits;
|
||||
pNew->pDriv->SetValue = ConfSetValue;
|
||||
pNew->pDriv->CheckStatus = ConfCheckStatus;
|
||||
pNew->pDriv->GetValue = ConfGetValue;
|
||||
|
||||
/*
|
||||
install command
|
||||
*/
|
||||
if( AddCommand(pSics,argv[1],ConfigurableVirtualMotorAction,
|
||||
KillConfigurableVirtualMotor,pNew) != 1){
|
||||
snprintf(pBueffel,510,"ERROR: duplicate command %s not created",
|
||||
argv[1]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
} else {
|
||||
SCSendOK(pCon);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
int ConfigurableVirtualMotorAction(SConnection *pCon, SicsInterp *pSics,
|
||||
void *data, int argc, char *argv[]){
|
||||
pConfigurableVirtualMotor self = NULL;
|
||||
char pBueffel[512];
|
||||
float value;
|
||||
|
||||
self = (pConfigurableVirtualMotor)data;
|
||||
assert(self != NULL);
|
||||
|
||||
if(argc > 1){
|
||||
strtolower(argv[1]);
|
||||
if(strcmp(argv[1],"drivescript") == 0){
|
||||
if(argc > 2){
|
||||
/* set case */
|
||||
Arg2Text(argc-2,&argv[2],pBueffel,510);
|
||||
self->scriptName = strdup(pBueffel);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
} else {
|
||||
/* inquiry */
|
||||
if(self->scriptName == NULL){
|
||||
snprintf(pBueffel,510,"%s.drivescript = UNDEFINED", argv[0]);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
} else {
|
||||
snprintf(pBueffel,510,"%s.drivescript = %s", argv[0],
|
||||
self->scriptName);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}else if(strcmp(argv[1],"readscript") == 0){
|
||||
if(argc > 2){
|
||||
/* set case */
|
||||
Arg2Text(argc-2,&argv[2],pBueffel,510);
|
||||
self->readScript = strdup(pBueffel);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
} else {
|
||||
/* inquiry */
|
||||
if(self->readScript == NULL){
|
||||
snprintf(pBueffel,510,"%s.readscript = UNDEFINED", argv[0]);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
} else {
|
||||
snprintf(pBueffel,510,"%s.readscript = %s", argv[0],
|
||||
self->readScript);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
snprintf(pBueffel,5120,"ERROR: subcommand %s to %s unknown",
|
||||
argv[1],argv[0]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
value = self->pDriv->GetValue(self,pCon);
|
||||
snprintf(pBueffel,510,"%s = %f", argv[0],value);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
}
|
||||
}
|
76
confvirtualmot.w
Normal file
76
confvirtualmot.w
Normal file
@ -0,0 +1,76 @@
|
||||
\subsection{Configurable Virtual Motor}
|
||||
This is an object which can help in realizing complex scans in space.
|
||||
In principle this object implements a virtual motor. When this motor is
|
||||
started a script is called with the desired new position as a parameter.
|
||||
This script is supposed to either return an error or a comma separated
|
||||
list of strings motor=value. The name of this script is a configurable
|
||||
parameter. The object then takes care of starting all the motors (or
|
||||
better Drivables) and watching over them during the driving operation.
|
||||
|
||||
This objects data structure:
|
||||
@d confvirt @{
|
||||
typedef struct __CONFVIRTMOT {
|
||||
pObjectDescriptor pDes;
|
||||
pIDrivable pDriv;
|
||||
char *scriptName;
|
||||
char *readScript;
|
||||
int motorList;
|
||||
float targetValue;
|
||||
int targetReached;
|
||||
char scriptError[512];
|
||||
int parseOK;
|
||||
}ConfigurableVirtualMotor, *pConfigurableVirtualMotor;
|
||||
@}
|
||||
The fields are:
|
||||
\begin{description}
|
||||
\item[pDes] The standard object descriptor.
|
||||
\item[pDriv] The drivable interface
|
||||
\item[scriptName] The name of the program to calculate the new positions
|
||||
of the real motors.
|
||||
\item[readScript] A script to read back the current value of the virtual motor.
|
||||
\item[motorList] A list of the motors to start and control.
|
||||
\item[targetValue] The target value we wanted to have.
|
||||
\item[targetReached] A flag which becomes true when a check has showed that
|
||||
all desired motors have reached their targets.
|
||||
\item[scriptError] A temporary buffer holding all errors encountered
|
||||
during processing of the script.
|
||||
\item[parseOK] a flag which indicates if parsing and execution of the
|
||||
script went OK.
|
||||
\end{description}
|
||||
|
||||
|
||||
All the magic of this object is hidden in the implementation of the methods
|
||||
of the drivable interface. Additioanlly there is the standard interpreter
|
||||
interface.
|
||||
|
||||
@o confvirtmot.i @{
|
||||
/*-----------------------------------------------------------------------
|
||||
Configurable Virtual Motor. This is an generated file describing the
|
||||
internal data structure of this object. Do not edit.
|
||||
-----------------------------------------------------------------------*/
|
||||
@< confvirt @>
|
||||
|
||||
@}
|
||||
|
||||
@o confvirtmot.h @{
|
||||
/*-----------------------------------------------------------------------
|
||||
A configurable virtual motor object. At motor start a script is called
|
||||
which returns the motors and positions to drive as a comma separated
|
||||
list holding entries of the form mot=value.
|
||||
|
||||
COPYRIGHT: see file COPYRIGHT
|
||||
|
||||
Mark Koennecke, August 2004
|
||||
-------------------------------------------------------------------------*/
|
||||
#ifndef CONFIGURABLEVIRTUALMOTOR
|
||||
#define CONFIGURABLEVIRTUALMOTOR
|
||||
|
||||
#include "sics.h"
|
||||
|
||||
int MakeConfigurableVirtualMotor(SConnection *pCon, SicsInterp *pSics,
|
||||
void *data, int aargc, char *argv[]);
|
||||
int ConfigurableVirtualMotorAction(SConnection *pCon, SicsInterp *pSics,
|
||||
void *data, int argc, char *argv[]);
|
||||
#endif
|
||||
|
||||
@}
|
55
conman.c
55
conman.c
@ -837,7 +837,7 @@ static void writeToLogFiles(SConnection *self, char *buffer)
|
||||
This version writes only to configured log files but not to sockets.
|
||||
Used for automatic file execution for the WWW interface
|
||||
*/
|
||||
static int SCFileWrite(SConnection *self, char *buffer, int iOut)
|
||||
int SCFileWrite(SConnection *self, char *buffer, int iOut)
|
||||
{
|
||||
int i, iPtr, iRet;
|
||||
char pBueffel[80];
|
||||
@ -1557,6 +1557,54 @@ static void writeToLogFiles(SConnection *self, char *buffer)
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*----------------------------------------------------------------------*/
|
||||
int SCUnregisterID(SConnection *pCon, long ID)
|
||||
{
|
||||
int iRet;
|
||||
Item sItem;
|
||||
|
||||
if(!VerifyConnection(pCon))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
iRet = LLDnodePtr2First(pCon->iList);
|
||||
while(iRet != 0)
|
||||
{
|
||||
LLDnodeDataTo(pCon->iList,&sItem);
|
||||
if(sItem.lID == ID )
|
||||
{
|
||||
LLDnodeDelete(pCon->iList);
|
||||
LLDnodePtr2Prev(pCon->iList);
|
||||
}
|
||||
iRet = LLDnodePtr2Next(pCon->iList);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*----------------------------------------------------------------------*/
|
||||
long SCgetCallbackID(SConnection *pCon, void *pData)
|
||||
{
|
||||
int iRet;
|
||||
Item sItem;
|
||||
pICallBack pInter;
|
||||
|
||||
if(!VerifyConnection(pCon))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
pInter = (pICallBack)pData;
|
||||
iRet = LLDnodePtr2First(pCon->iList);
|
||||
while(iRet != 0)
|
||||
{
|
||||
LLDnodeDataTo(pCon->iList,&sItem);
|
||||
if(sItem.pInterface == pInter)
|
||||
{
|
||||
return sItem.lID;
|
||||
}
|
||||
iRet = LLDnodePtr2Next(pCon->iList);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*---------------------- The callback data structure --------------------*/
|
||||
typedef struct {
|
||||
SConnection *pCon;
|
||||
@ -1656,7 +1704,8 @@ static void writeToLogFiles(SConnection *self, char *buffer)
|
||||
/* get CallBack interface */
|
||||
pDum = (pDummy)pCom->pData;
|
||||
assert(pDum);
|
||||
pInterface = (pICallBack)pDum->pDescriptor->GetInterface(pDum,CALLBACKINTERFACE);
|
||||
pInterface = (pICallBack)pDum->pDescriptor->GetInterface(pDum,
|
||||
CALLBACKINTERFACE);
|
||||
if(!pInterface)
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: %s does not support CallBacks",
|
||||
@ -1772,7 +1821,7 @@ static void writeToLogFiles(SConnection *self, char *buffer)
|
||||
else
|
||||
{
|
||||
SCWrite(self,"ERROR: Bad login",eError);
|
||||
|
||||
printf("Bad login string %s\n", pPtr);
|
||||
}
|
||||
}
|
||||
free(pPtr);
|
||||
|
13
conman.h
13
conman.h
@ -53,6 +53,7 @@ typedef int (*writeFunc)(struct __SConnection *pCon,
|
||||
int iGrab;
|
||||
int iErrCode;
|
||||
int parameterChange;
|
||||
int sicsError;
|
||||
SicsInterp *pSics;
|
||||
|
||||
/* a FIFO */
|
||||
@ -96,11 +97,23 @@ typedef int (*writeFunc)(struct __SConnection *pCon,
|
||||
writeFunc SCGetWriteFunc(SConnection *pCon);
|
||||
void SCSetWriteFunc(SConnection *pCon, writeFunc x);
|
||||
int SCOnlySockWrite(SConnection *self, char *buffer, int iOut);
|
||||
int SCFileWrite(SConnection *self, char *buffer, int iOut);
|
||||
int SCNotWrite(SConnection *self, char *buffer, int iOut);
|
||||
/************************* CallBack *********************************** */
|
||||
int SCRegister(SConnection *pCon, SicsInterp *pSics,
|
||||
void *pInter, long lID);
|
||||
int SCUnregister(SConnection *pCon, void *pInter);
|
||||
/**
|
||||
* delete a callback with the given ID
|
||||
*/
|
||||
int SCUnregisterID(SConnection *pCon, long ID);
|
||||
/**
|
||||
* retrieve the ID of a callback on the callback interface
|
||||
* given in pData. This, together with SCUnregisterID allows to
|
||||
* ceanly remove all callbacks on a connection
|
||||
* returns -1 if no ID can be found.
|
||||
*/
|
||||
long SCgetCallbackID(SConnection *pCon, void *pData);
|
||||
/******************************* Error **************************************/
|
||||
void SCSetInterrupt(SConnection *self, int eCode);
|
||||
int SCGetInterrupt(SConnection *self);
|
||||
|
@ -12,6 +12,9 @@ initialisation file. Such special commands are described here.
|
||||
<DL>
|
||||
<DT>MakeRuenBuffer
|
||||
<DD>MakeRuenBuffer makes the RünBuffer system available.
|
||||
<dt>MakeBatchManager [name]
|
||||
<DD>Installs the new batch buffer management system. If no name is
|
||||
given, the default will be exe.
|
||||
<DT>MakeDrive
|
||||
<DD>MakeDrive craetes the drive command.
|
||||
<DT>MakeScanCommand name countername headfile recoverfil
|
||||
|
176
doc/master.tex
176
doc/master.tex
@ -28,25 +28,33 @@ Author: Mark K\"onnecke
|
||||
This document gives an overview about all the hardware and software systems
|
||||
involved in SINQ instrument control. It describes the relationships between
|
||||
the various pieces and points to additional documentation, if available.
|
||||
A copy of all documents referred in this paper is stored at: /data/lnslib/distribution/sics/doclib. If they exist in electronic form, this is. The SICS user
|
||||
and manager information is available on the WWW starting from http://lns00.psi.ch/.
|
||||
A copy of all documents referred in this paper is stored at:
|
||||
/afs/psi.ch/project/sinq/commmon/share/sicsdoc.
|
||||
If they exist in electronic form, this is. The SICS user
|
||||
and manager information is available on the WWW starting from
|
||||
http://lns00.psi.ch/.
|
||||
|
||||
|
||||
\section{Hardware Overview}
|
||||
For each SINQ instrument the following computing hardware is available:
|
||||
\begin{itemize}
|
||||
\item A dedicated instrument workstation. Most of them are Compaq Alpha stations
|
||||
running True64Unix. One workstation is still running OpenVMS. Two instruments,
|
||||
POLDI and RITA--2, are controlled through Intel--PC's running Linux.
|
||||
\item A dedicated instrument workstation. Most of them are Intel x86
|
||||
machines running Linux. Three instruments use alpha workstations
|
||||
running Tru64Unix.
|
||||
\item A TCP/IP terminal server providing access to serial ports.
|
||||
\item Optionally, there are 1-3 histogram memory computers installed for those
|
||||
instruments which have area detectors. These histogram memory computers are
|
||||
Motorolla 6800 VME board processors running the vxWorks realtime
|
||||
operating system.
|
||||
operating system. Two types of boards are in use: the older Motorolla
|
||||
MVME1603 boards with 16 MB of memory and MEN-A12 boards with 512MB
|
||||
memory.
|
||||
\item Optionally there are National Instruments ENET-100 GPIB/TCPIP
|
||||
converters in use in order to access GPIB devices, especially those
|
||||
which came with the Risoe instruments.
|
||||
\end{itemize}
|
||||
Most instrument hardware is accessed through RS--232 interfaces and the terminal
|
||||
server. Histogram memories are accessed through the TCP/IP network. Generally
|
||||
ethernet is used as the main instrument bus.
|
||||
Most instrument hardware is accessed through RS--232 interfaces and
|
||||
the terminal server. Histogram memories are accessed through the
|
||||
TCP/IP network . Generally ethernet is used as the main instrument bus.
|
||||
|
||||
In addition to the computers at the instrument the following systems are
|
||||
available:
|
||||
@ -54,8 +62,9 @@ In addition to the computers at the instrument the following systems are
|
||||
\item A True64Unix laboratory server (lnsa15) for data management and
|
||||
primary data anlalysis.
|
||||
\item True64Unix PSI server systems for data processing.
|
||||
\item A dual processor linux science server (lnsl15).
|
||||
\item The PSI Linux Login cluster (llc)
|
||||
\item A WWW--server currently installed on lns00.
|
||||
\item pss123 is a Sun workstation holding the vxWorks development environment.
|
||||
\end{itemize}
|
||||
|
||||
\section{Software Overview}
|
||||
@ -75,7 +84,8 @@ The main software component at the instrument is the Sinq Instrument Control
|
||||
debugging. Clients to this SerPortServer such as the SICS server communicate
|
||||
with the server through a special ASCII protocoll transported through TCP/IP.
|
||||
The only documentation
|
||||
for both the SerPortServer and the ASCII protocoll is the source code.
|
||||
for both the SerPortServer and the ASCII protocoll is the source
|
||||
code. And David Maden.
|
||||
|
||||
There exists another support program, the FileSync server, on any instrument
|
||||
computer. This is a little Java server which listens at a UDP port for a
|
||||
@ -88,8 +98,8 @@ Then there is the TecsServer. This is a server which maintains and configures
|
||||
Lakeshore temperature controllers used as standard temperature controllers
|
||||
at SINQ. The only documentation for this program is Markus Zolliker.
|
||||
|
||||
On many instruments there are histogram memory computers. These usually run the
|
||||
following programs:
|
||||
On many instruments there are histogram memory computers. These
|
||||
usually run the following programs:
|
||||
\begin{description}
|
||||
\item[bootUtil] a utility running when the histogram memory is booted which
|
||||
starts all the other tasks and configures the histogram memory from its
|
||||
@ -114,30 +124,22 @@ The SICS software is described in a variety of documentation:
|
||||
described in the "SICS Manager Manual".
|
||||
\item The programming concepts of SICS are discussed in the "SICS Programmers
|
||||
Reference".
|
||||
\item An 90\% complete description of SICS source code modules is available
|
||||
\item An 97\% complete description of SICS source code modules is available
|
||||
as "SICS Reference Manual".
|
||||
\end{itemize}
|
||||
|
||||
|
||||
One instrument, TASP, is run with the TASMAD software from ILL which runs
|
||||
on VMS systems. A user documentation for this system is available at: \newline
|
||||
\centerline{http://sinq.web.psi.ch/sinq/doc/tasmad.html}
|
||||
Some configuration issues are explained in this docuement as well. Further
|
||||
documentation exists only in form of David Maden and an analysis of the
|
||||
source code.
|
||||
|
||||
The RITA--2 instrument from Ris\o{ } runs the TASCOM software.
|
||||
This software is quite well documented in various documents which can be
|
||||
obtained at WHGA/247 or directly from the Ris\o{ } team and Per Skarup.
|
||||
obtained at WHGA/112 or directly from the Ris\o{ } team and Per Skarup.
|
||||
|
||||
\subsection{Facilities at the Laboratory Server(LNSA15)}
|
||||
\subsection{Central Facilities}
|
||||
\subsubsection{Central Data Repository}
|
||||
Under the /data/lnslib/data directory there exists a central storage area for
|
||||
Under the /afs/psi.ch/project/sinqdata directory there exists a
|
||||
central storage area for
|
||||
data files measured at the instruments. Newly measured data files are
|
||||
automatically mirrored to this area once a measurement has finished.
|
||||
Not surprisingly there is a subdirectory for each instrument at SINQ.
|
||||
These instrument directories contain further subdirectories for each year
|
||||
of SINQ operation which hold the actual data files.
|
||||
There are directories for each year of SINQ operation. These contain
|
||||
subdirectories for the various instruments.
|
||||
|
||||
\subsubsection{The SINQ File Database}
|
||||
Right early on it was decided to separate the file archival function from the
|
||||
@ -155,20 +157,15 @@ which is part of the source distribution for the system. Here only an
|
||||
|
||||
The SINQ File Database consists of the following components:
|
||||
\begin{itemize}
|
||||
\item The database itself. This is the SQL database system mSQL from
|
||||
Hughes Technology.
|
||||
\item Any night the unix utility cron starts a shell script which is
|
||||
responsible for updating the database. This is done with two special
|
||||
utility programs:
|
||||
\begin{itemize}
|
||||
\item nx\_dbupdate scans a given directory for new files which are not
|
||||
yet in the database. If such a file is found, the data fields for the
|
||||
database are extracted and entered into the database.
|
||||
\item The Java program ScanScan does the same job as nx\_dbupdate for
|
||||
ASCII files.
|
||||
\end{itemize}
|
||||
\item The database itself. The database is installed on the central
|
||||
database server PSIP0 provided by central computing. The database
|
||||
software is oracle.
|
||||
\item Any night a database update program is started as a cron
|
||||
job. This programs runs on the linux server lnsl15. The program
|
||||
itself is a tcl script which uses oratcl for accessing the Oracle
|
||||
database server and nxinter for accessing NeXus files.
|
||||
\item A querying system. Curently the only query interface is a WWW--interface
|
||||
installed at the WWW--server.
|
||||
installed at the WWW--server lns00.
|
||||
\end{itemize}
|
||||
|
||||
|
||||
@ -189,28 +186,19 @@ This document also explains how to get hold the source code for most
|
||||
of the software used at SINQ.
|
||||
|
||||
\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. 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.
|
||||
The backup software is described in the documentation coming with the
|
||||
system. No further documentation exists, but the setup can be viewed
|
||||
through the nwadmin application.
|
||||
Most user files and the raw data is stored within the AFS network file
|
||||
system. These files are backed up by central computing. Data files of
|
||||
older years are additionally archived in the PSI archive system.
|
||||
|
||||
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:
|
||||
The instrument and guest accounts on the instrument computers should
|
||||
be backed up
|
||||
too because they sometimes contain valuable scripts. These are local
|
||||
accounts, thus they are not covered through the AFS backup. Data from
|
||||
these accounts is synchronized nightly onto a special account on the
|
||||
linux server lnsl15.
|
||||
\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
|
||||
in /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
|
||||
@ -221,8 +209,8 @@ instrument computer must have an entry in crontab reading like:
|
||||
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
|
||||
\item The backup account on lnsl15 is named SINQINST, password:
|
||||
SINQINSTLNS. 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:
|
||||
@ -237,16 +225,12 @@ linux instrument computers, not the DNS alias.
|
||||
At SINQ the PSI EL--734 motor controllers are used. These motor controllers
|
||||
hold a set of parameters for each motor. As a safeguard against instrument
|
||||
scientists gone wild or a loss of parameters due some electronic or
|
||||
electrical incident these motor parameters are saved weekly. This happens
|
||||
on wednesdays mornings. The unix utility crom triggers the process and
|
||||
starts the script savemot which in turn does all necessary things. The
|
||||
actual saving of the motor parameters is accomplished with David Maden's
|
||||
el734 program. The saved parameters end up in the /data/lnslib/motors
|
||||
hierarchy. There exists a directory for each backup date which in turn
|
||||
holds a subdirectory for each instrument which holds the files with
|
||||
the saved parameters. All necessary shell scripts and programs can be
|
||||
found in the /data/lnslib/motors/bin directory.
|
||||
|
||||
electrical incident these motor parameters should be saved
|
||||
regularly. To this purpose there exits motor subdirectories in each
|
||||
instrument account. Motors are either saved into this directory
|
||||
through a script in this directory or from SICS (TASP,
|
||||
MORPHEUS). Motor parameter backup is a responsability of the
|
||||
instrument scientists and must be triggered manually.
|
||||
|
||||
\subsubsection{License Server}
|
||||
Unfortunately some people use the proprietary IDL programming system. This
|
||||
@ -275,19 +259,18 @@ Unfortunately some people use the proprietary IDL programming system. This
|
||||
|
||||
|
||||
\subsection{Software at the WWW--server}
|
||||
The WWW--server running at lns00 does not provide static information only but also
|
||||
active content calculated at runtime. The following services are
|
||||
implemented:
|
||||
The WWW--server running at lns00 does not provide static information
|
||||
only but also active content calculated at runtime. The following
|
||||
services are implemented:
|
||||
\begin{itemize}
|
||||
\item Keyword search in the SICS documentation.
|
||||
\item Searching the SINQ file database for files matching various criteria.
|
||||
\item Display of the current instrument status for a couple of instruments.
|
||||
\item Display of the current instrument status for most instruments.
|
||||
\item An experimental WWW control system for powder diffractometers.
|
||||
\end{itemize}
|
||||
Most of these services are provided through java servlets. In order to do this
|
||||
a servlet engine was needed. The combination Apache WWW-server and Apache
|
||||
JServ was choosen. However, it is planned to exchange the latter component
|
||||
by the Jakarta engine in the near future.
|
||||
Jakarta Tomcat was choosen.
|
||||
|
||||
The database search servlets are described in more detail in the document:
|
||||
\newline \centerline{The SINQ File Database}
|
||||
@ -299,8 +282,7 @@ The SICS documentation searching system is built on top of the program SWISH-E w
|
||||
from http://sunsite.berkeley.edu/SWISH-E.
|
||||
The actual search is performed through a TCL--cgi script which calls the swishe
|
||||
application with appropriate parameters. This script can be found as
|
||||
swishsearch.cgi together with a batch file to start it properly
|
||||
(swishsearch.bat) in the cgi-bin directory of the WWW hierarchy on lns00.
|
||||
swishsearch.cgi in the cgi-bin directory of the WWW hierarchy on lns00.
|
||||
Prerequisite for such a search is the existence of an index file. This must
|
||||
be created offline after any major change to the documentation. In order to
|
||||
create this index, cd into the sics directory of the WWW hierarchy and run:
|
||||
@ -321,12 +303,12 @@ In order to understand the system better it is useful to look at the flow
|
||||
\begin{enumerate}
|
||||
\item Data Files are generated by the instrument control programs at the
|
||||
instrument computer.
|
||||
\item Data Files are automatically mirrored to the central repository
|
||||
on the laboratory server lnsa15. This happens through the FileSync server,
|
||||
a shell script and last not least the unix rsync utility. All this is installed
|
||||
at the instrument computer.
|
||||
\item Data Files are automatically mirrored to the central AFS
|
||||
repository. This happens through the FileSync server,
|
||||
a shell script and last not least the unix rsync utility. All this is
|
||||
installed at the instrument computer.
|
||||
\item Nightly new files are scanned for relevant information and their
|
||||
characteristics are entered into the database system on lnsa15.
|
||||
characteristics are entered into the database system from lnsl15.
|
||||
\end{enumerate}
|
||||
|
||||
|
||||
@ -341,7 +323,7 @@ The SICS Java clients access the SICS servers on the selected instruments
|
||||
laboratory server lnsa15.
|
||||
\subsection{WWW Services}
|
||||
The file search service on the WWW--server lns00 accesses the database
|
||||
server running on the laboratory server lnsa15.
|
||||
server PSIP0.
|
||||
|
||||
The instrument status display servlets on the WWW--server lns00 access the
|
||||
SICS instrument control servers on the appropriate instrument computers
|
||||
@ -349,9 +331,6 @@ The instrument status display servlets on the WWW--server lns00 access the
|
||||
|
||||
\section{Maintainance Tasks}
|
||||
\subsection{Yearly Maintainance}
|
||||
The only maintainance task at SINQ shutdown is to disable the cron job on
|
||||
lnsa15 which performs the motor parameter backup.
|
||||
|
||||
|
||||
Whith each new year a couple of things must be done in order to keep the
|
||||
system ship shape:
|
||||
@ -369,13 +348,10 @@ Whith each new year a couple of things must be done in order to keep the
|
||||
\end{itemize}
|
||||
\item On the laboratory server lnsa15:
|
||||
\begin{itemize}
|
||||
\item Reenable the motor parameter backup cron job.
|
||||
\item Create new subdirectories for the new year in the data hierarchy.
|
||||
\item In /data/lnslib/lib/nxdb create new configuration files for the new
|
||||
year. Edit them to point to the new years subdirectory. Edit the
|
||||
updatenxdb shell script to use the newly created configuration files.
|
||||
Keep the old ones as they may come in handy if the whole database may
|
||||
require an update.
|
||||
\item Create a new year hierarchy for the new year.
|
||||
\item Store the old years data into the PSI archive.
|
||||
\item Move the old years data into the non backed up AFS area.
|
||||
\item Make the new year the backed up data on AFS.
|
||||
\end{itemize}
|
||||
\item On the WWW--server lns00:
|
||||
\begin{itemize}
|
||||
@ -391,10 +367,14 @@ Do these things quite early on in the year. People start measuring background
|
||||
In order to keep up with ageing 1-2 computers have to be exchanged any year.
|
||||
A instrument computer change requires the following adaptions:
|
||||
\begin{enumerate}
|
||||
\item Start with a PC with the PSI Linux distribution installed.
|
||||
\item Create two local user accounts: INST and instlnsg.
|
||||
\item Copy the SICS software to the instrument computer.
|
||||
\item Edit the instrument configuration file and change all occurences of
|
||||
the old computers name to the new name.
|
||||
\item On lnsa15 as user lnslib: enter the new computer name into the
|
||||
.rhosts file. This is required for the mirroring to work.
|
||||
\item Install the cron job for backing up the local instrument
|
||||
accounts.
|
||||
\item Make an entry in the .rhosts file of the SINQINST account on lnsl15.
|
||||
\item For the Java clients edit lnet/SINQConfig.java to point to the
|
||||
new computer and rebuild all clients. Redistribute them as well.
|
||||
\item For the WWW status, adapt the sics.conf file on lns00 and restart
|
||||
|
59
doc/user/exeman.html
Normal file
59
doc/user/exeman.html
Normal file
@ -0,0 +1,59 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>The Batch Buffer Manager</TITLE>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
<H1>The Batch Buffer Manager</H1>
|
||||
<P>
|
||||
The batch buffer manager handles the execution of batch files. It can
|
||||
execute batch files directly. Additionally, batch files can be added
|
||||
into a queue for later processing. The batch buffer manager supports
|
||||
the following command described below. Please note, that the examples
|
||||
assume that the batch manager has been configured into SICS under the
|
||||
name of exe.
|
||||
<dl>
|
||||
<dt>exe buffername
|
||||
<dd>directly load the buffer stored in the file buffername and execute
|
||||
it. The file is searched in the batch buffer search path.
|
||||
<dt>exe batchpath [newpath]
|
||||
<dd>Without an argument, this command lists the directories which are
|
||||
searched for batch files. With an argument, a new search path is
|
||||
set. It is possible to specify multiple directories by separating them
|
||||
with colons.
|
||||
<dt>exe syspath [newpath]
|
||||
<dd>Without an argument, this command lists the system directories which are
|
||||
searched for batch files. With an argument, a new system search path is
|
||||
set. It is possible to specify multiple directories by separating them
|
||||
with colons.
|
||||
<dt>exe info
|
||||
<dd>prints the name of the currently executing batch buffer
|
||||
<dt>exe info stack
|
||||
<dd>prints the stack of nested batch files (i.e. batch files calling
|
||||
each other).
|
||||
<dt>exe info range [name]
|
||||
<dd>Without an argument prints the range of code currently being
|
||||
executed. With a parameter, prints the range of code executing in
|
||||
named buffer within the stack of nested buffers. The reply looks like:
|
||||
number of start character = number of end character = line number.
|
||||
<dt>exe info text [name]
|
||||
<dd>Without an argument prints the code text currently being
|
||||
executed. With a parameter, prints the range of code text executing in the
|
||||
named buffer within the stack of nested buffers.
|
||||
<dt>exe enqueue buffername
|
||||
<dd>Appends buffername to the queue of batch buffers to execute.
|
||||
<dt>exe clear
|
||||
<dt>Clears the queue of batch buffers
|
||||
<dt>exe queue
|
||||
<dd>Prints the content of the batch buffer queue.
|
||||
<dt>exe run
|
||||
<dd>Starts executing the batch buffers in the queue.
|
||||
<dt>exe print buffername
|
||||
<dd>Prints the content of the batch buffer buffername to the screen.
|
||||
<dt>exe interest
|
||||
<dd>Switches on automatic notification about starting batch files,
|
||||
executing a new bit of code or for finishing a batch file. This is
|
||||
most useful for SICS clients watching the progress of the experiment.
|
||||
</dl>
|
||||
</P>
|
||||
</BODY>
|
||||
</HTML>
|
@ -14,23 +14,7 @@ to be solved are:
|
||||
<li>Measure a couple of reflections.
|
||||
<li>Furthermore there are some specialities.
|
||||
</ul>
|
||||
There are two ways to achieve all this:
|
||||
The older way uses some built in SICS functionality plus some external
|
||||
programs inherited from the ILL. This is called the ILL operation.
|
||||
Then a complete
|
||||
four circle package called DIFRAC from P. White and Eric Gabe was
|
||||
integrated into SICS.
|
||||
This is The Difrac way of operation.
|
||||
</p>
|
||||
<h2>DIFRAC</h2>
|
||||
<p>
|
||||
The DIFRAC commands are accessed by prepending the difrac commands
|
||||
with <b>dif</b>. For example: "dif td" calls the difrac td
|
||||
command. For more information on DIFRAC commands see the separate
|
||||
<a href="diftrics.htm">DIFRAC manual</a>.
|
||||
</p>
|
||||
|
||||
<h2>ILL operation</h2>
|
||||
<h3>Locate Reflections</h3>
|
||||
<p>
|
||||
If you know x-ray single crystal diffractometers you'll expect sophisticated
|
||||
|
@ -26,7 +26,23 @@ Two special commands have been defined for TRICS with a PSD:
|
||||
<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.
|
||||
preset. These parameters have the same meaning as described above. If the
|
||||
{\bf hkl nb 1} command has been given before the invocation of this scan,
|
||||
reflections will be searched in normal beam geometry. psdrefscan, however,
|
||||
will only print the normal four circle angles, though.
|
||||
<dt>detscan start step np mode preset
|
||||
<dd>Detscan performs a scan in two theta. This may be useful for detector
|
||||
calibrations. Arguments as described above.
|
||||
<dt>phscan start step np mode preset
|
||||
<dd>Phscan performs a scan in phi. This can be usefule for orienting a
|
||||
crystal. Arguments as described above.
|
||||
<dt>o2tscan2d start step np mode preset
|
||||
<dd>O2tscan2d performs a omega - two-theta scan with the PSD.
|
||||
Arguments as described above.
|
||||
<dt>hklscan2d
|
||||
<dd> For a scan in reciprocal space with the PSD, see the
|
||||
documentation for <a href="hklscan.htm">hklscan</a>. Please note that
|
||||
for a PSD HKL scan, all commans have to start with hklscan2d.
|
||||
</dl>
|
||||
</P>
|
||||
|
||||
|
3
event.c
3
event.c
@ -60,6 +60,9 @@
|
||||
"COUNTEND",
|
||||
"FILELOADED",
|
||||
"MOTEND",
|
||||
"BATCHSTART",
|
||||
"BATCHAREA",
|
||||
"BATCHEND",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
13
event.h
13
event.h
@ -1,5 +1,5 @@
|
||||
|
||||
#line 79 "event.w"
|
||||
#line 85 "event.w"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
E V E N T
|
||||
@ -18,7 +18,7 @@
|
||||
|
||||
int Text2Event(char *pText);
|
||||
|
||||
#line 92 "event.w"
|
||||
#line 98 "event.w"
|
||||
|
||||
|
||||
|
||||
@ -38,19 +38,22 @@
|
||||
#define COUNTEND 11
|
||||
#define FILELOADED 12
|
||||
#define MOTEND 13
|
||||
#define BATCHSTART 14
|
||||
#define BATCHAREA 15
|
||||
#define BATCHEND 16
|
||||
|
||||
#line 94 "event.w"
|
||||
#line 100 "event.w"
|
||||
|
||||
|
||||
/*--------------- Signals for the Signalfunction of each task ------------*/
|
||||
|
||||
#line 64 "event.w"
|
||||
#line 70 "event.w"
|
||||
|
||||
#define SICSINT 300
|
||||
#define SICSBROADCAST 301
|
||||
#define TOKENGRAB 302
|
||||
#define TOKENRELEASE 303
|
||||
|
||||
#line 97 "event.w"
|
||||
#line 103 "event.w"
|
||||
|
||||
#endif
|
||||
|
44
event.tex
44
event.tex
@ -1,13 +1,3 @@
|
||||
\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
|
||||
@ -22,17 +12,17 @@ This module defines several event related functions as well.
|
||||
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap1}
|
||||
$\langle\,$eFunc\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$
|
||||
$\langle$eFunc {\footnotesize ?}$\rangle\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ int Text2Event(char *pText);@\\
|
||||
\mbox{}\verb@@{\NWsep}
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
\vspace{-1ex}
|
||||
\footnotesize\addtolength{\baselineskip}{-1ex}
|
||||
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
||||
\item \NWtxtMacroRefIn\ \NWlink{nuweb?}{?}.
|
||||
\item Macro referenced in scrap ?.
|
||||
\end{list}
|
||||
\end{minipage}\\[4ex]
|
||||
\end{flushleft}
|
||||
@ -41,7 +31,7 @@ if the event code is not known, else the apropriate event code.
|
||||
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap2}
|
||||
$\langle\,$VE\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$
|
||||
$\langle$VE {\footnotesize ?}$\rangle\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
@ -59,12 +49,15 @@ $\langle\,$VE\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$
|
||||
\mbox{}\verb@#define COUNTEND 11@\\
|
||||
\mbox{}\verb@#define FILELOADED 12@\\
|
||||
\mbox{}\verb@#define MOTEND 13@\\
|
||||
\mbox{}\verb@@{\NWsep}
|
||||
\mbox{}\verb@#define BATCHSTART 14@\\
|
||||
\mbox{}\verb@#define BATCHAREA 15@\\
|
||||
\mbox{}\verb@#define BATCHEND 16@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
\vspace{-1ex}
|
||||
\footnotesize\addtolength{\baselineskip}{-1ex}
|
||||
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
||||
\item \NWtxtMacroRefIn\ \NWlink{nuweb?}{?}.
|
||||
\item Macro referenced in scrap ?.
|
||||
\end{list}
|
||||
\end{minipage}\\[4ex]
|
||||
\end{flushleft}
|
||||
@ -88,6 +81,9 @@ fiffractometer has been measured.
|
||||
operation.
|
||||
\item[COUNTEND] is an event signalling the end of a counting operation.
|
||||
\item[MOTEND] signals the end of a driving operation.
|
||||
\item[BATCHSTART] signals starting batch processing a new buffer
|
||||
\item[BATCHAREA] signals that a new area of the batch file is processing.
|
||||
\item[BATCHEND] signals the end of the batch buffers processing.
|
||||
\end{description}
|
||||
|
||||
Furthermore event contains system wide signal codes which are interpreted in
|
||||
@ -98,7 +94,7 @@ possible codes are defined.
|
||||
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap3}
|
||||
$\langle\,$VSIG\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$
|
||||
$\langle$VSIG {\footnotesize ?}$\rangle\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
@ -106,12 +102,12 @@ $\langle\,$VSIG\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$
|
||||
\mbox{}\verb@#define SICSBROADCAST 301@\\
|
||||
\mbox{}\verb@#define TOKENGRAB 302@\\
|
||||
\mbox{}\verb@#define TOKENRELEASE 303@\\
|
||||
\mbox{}\verb@@{\NWsep}
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
\vspace{-1ex}
|
||||
\footnotesize\addtolength{\baselineskip}{-1ex}
|
||||
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
||||
\item \NWtxtMacroRefIn\ \NWlink{nuweb?}{?}.
|
||||
\item Macro referenced in scrap ?.
|
||||
\end{list}
|
||||
\end{minipage}\\[4ex]
|
||||
\end{flushleft}
|
||||
@ -126,7 +122,7 @@ data is the string to send.
|
||||
\end{description}
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap4}
|
||||
\verb@"event.h"@\nobreak\ {\footnotesize \NWtarget{nuweb?}{?} }$\equiv$
|
||||
\verb@"event.h"@ {\footnotesize ? }$\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
@ -142,14 +138,14 @@ data is the string to send.
|
||||
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
|
||||
\mbox{}\verb@#ifndef SICSEVENT@\\
|
||||
\mbox{}\verb@#define SICSEVENT@\\
|
||||
\mbox{}\verb@@\hbox{$\langle\,$eFunc\nobreak\ {\footnotesize \NWlink{nuweb?}{?}}$\,\rangle$}\verb@@\\
|
||||
\mbox{}\verb@@$\langle$eFunc {\footnotesize ?}$\rangle$\verb@@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@@\hbox{$\langle\,$VE\nobreak\ {\footnotesize \NWlink{nuweb?}{?}}$\,\rangle$}\verb@@\\
|
||||
\mbox{}\verb@@$\langle$VE {\footnotesize ?}$\rangle$\verb@@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@/*--------------- Signals for the Signalfunction of each task ------------*/@\\
|
||||
\mbox{}\verb@@\hbox{$\langle\,$VSIG\nobreak\ {\footnotesize \NWlink{nuweb?}{?}}$\,\rangle$}\verb@ @\\
|
||||
\mbox{}\verb@@$\langle$VSIG {\footnotesize ?}$\rangle$\verb@ @\\
|
||||
\mbox{}\verb@#endif@\\
|
||||
\mbox{}\verb@@{\NWsep}
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
\vspace{-2ex}
|
||||
\end{minipage}\\[4ex]
|
||||
|
6
event.w
6
event.w
@ -32,6 +32,9 @@ if the event code is not known, else the apropriate event code.
|
||||
#define COUNTEND 11
|
||||
#define FILELOADED 12
|
||||
#define MOTEND 13
|
||||
#define BATCHSTART 14
|
||||
#define BATCHAREA 15
|
||||
#define BATCHEND 16
|
||||
@}
|
||||
\begin{description}
|
||||
\item[VALUECHANGE] This is a variable changing its value. As event data a pointer to the
|
||||
@ -53,6 +56,9 @@ fiffractometer has been measured.
|
||||
operation.
|
||||
\item[COUNTEND] is an event signalling the end of a counting operation.
|
||||
\item[MOTEND] signals the end of a driving operation.
|
||||
\item[BATCHSTART] signals starting batch processing a new buffer
|
||||
\item[BATCHAREA] signals that a new area of the batch file is processing.
|
||||
\item[BATCHEND] signals the end of the batch buffers processing.
|
||||
\end{description}
|
||||
|
||||
Furthermore event contains system wide signal codes which are interpreted in
|
||||
|
221
exe.w
Normal file
221
exe.w
Normal file
@ -0,0 +1,221 @@
|
||||
\subsection{The Exe Batch Processing System}
|
||||
This is a reimplementation of the batch processing scheme in SICS. It
|
||||
addresses a couple of shortcomings of the fileeval command which is
|
||||
already implemented. In the long run fileeval should be replaced by
|
||||
this system. In contrast to fileeval the following feautures will be
|
||||
provided: \begin{itemize}
|
||||
\item A list of directories to search for batch files
|
||||
\item Better feedback about which batch file, which line, which
|
||||
segement of text is executing. This even for the case when batch files
|
||||
are nested.
|
||||
\item Callbacks when batch processing proceeds. This in order to
|
||||
allow a download mode in sicsed.
|
||||
\item Means of downloading a batch file.
|
||||
\end{itemize}
|
||||
|
||||
The source code for this is divided into two parts:\begin{itemize}
|
||||
\item A buffer handling component. This handles everything for
|
||||
managing and executing a single buffer.
|
||||
\item A control module which handles the management of the batch
|
||||
buffers.
|
||||
\end{itemize}
|
||||
|
||||
\subsubsection{Single Buffer Handling Code}
|
||||
For each batch buffer there is a data structure:
|
||||
@d exebufdat @{
|
||||
typedef struct __EXEBUF{
|
||||
char *name;
|
||||
pDynString bufferContent;
|
||||
int start;
|
||||
int end;
|
||||
int lineno;
|
||||
} ExeBuf;
|
||||
@}
|
||||
The items are:
|
||||
\begin{description}
|
||||
\item[name] The name of the batch buffer.
|
||||
\item[bufferContent] The text of the buffer in a dynamic string.
|
||||
\item[start] The start index of the currently executing part of the text
|
||||
\item[end] The end index of the currently executing text.
|
||||
\item[lineno] The currently executing line.
|
||||
\end{description}
|
||||
|
||||
The interface to this buffer system comprises:
|
||||
@d exebufint @{
|
||||
typedef struct __EXEBUF *pExeBuf;
|
||||
|
||||
/**
|
||||
* create an exe buffer
|
||||
* @@param The name to use for the exe buffer
|
||||
* @@return A new exe buffer or NULL if out of memory
|
||||
*/
|
||||
pExeBuf exeBufCreate(char *name);
|
||||
/**
|
||||
* delete an exe buffer
|
||||
* @@param data The exe buffer to delete
|
||||
*/
|
||||
void exeBufKill(void *data);
|
||||
void exeBufDelete(pExeBuf data);
|
||||
/**
|
||||
* add a a line to the exe buffer
|
||||
* @@param self The exe buffer the line is to be added to
|
||||
* @@param line The text to add
|
||||
* @@return 1 on success, 0 when out of memory
|
||||
*/
|
||||
int exeBufAppend(pExeBuf self, char *line);
|
||||
/**
|
||||
* load an exe buffer from a file
|
||||
* @@param self The exe buffer to load
|
||||
* @@param filename The name of the file to load
|
||||
* @@return 1 on success, 0 if the file could not be opened or
|
||||
* memory is exhausted.
|
||||
*/
|
||||
int exeBufLoad(pExeBuf self, char *filename);
|
||||
/**
|
||||
* save an exe buffer to a file.
|
||||
* @@param self The exe buffer to laod
|
||||
* @@param filename The name of the file to laod
|
||||
* @@return 1 on success, 0 if the file could not be opened.
|
||||
*/
|
||||
int exeBufSave(pExeBuf self, char *filename);
|
||||
/**
|
||||
* process an exe buffer
|
||||
* @@param self The exe buffer to process
|
||||
* @@param pSics The SICS interpreter to use for processing
|
||||
* @@param pCon The connection object providing the environment for
|
||||
* processing this buffer.
|
||||
* @@pCall The callback interface to use for automatic notifications
|
||||
* @@return 1 on success, 0 on error
|
||||
*/
|
||||
int exeBufProcess(pExeBuf self, SicsInterp *pSics,
|
||||
SConnection *pCon, pICallBack pCall);
|
||||
/**
|
||||
* retrieves the executing range
|
||||
* @@param self The exe buffer to query
|
||||
* @@param start The start of the executing range
|
||||
* @@param end The end of the executing range
|
||||
* @@param lineno The current line number
|
||||
*/
|
||||
void exeBufRange(pExeBuf self, int *start, int *end, int *lineno);
|
||||
/**
|
||||
* retrieves some portion of text
|
||||
* @@param self The exe buffer to query
|
||||
* @@param start The start index from which to copy
|
||||
* @@param end The end pointer until which to copy
|
||||
* @@return A dynamic string holding the currently executing text. It is
|
||||
* the clients task to delete this buffer sfter use. Or NULL if out of
|
||||
* memory.
|
||||
*/
|
||||
pDynString exeBufText(pExeBuf self, int start, int end);
|
||||
/**
|
||||
* retrieves the name of the batch buffer
|
||||
* @@param self The exe buffer to query
|
||||
* @@return A pointer to the buffer name. Do not delete! The name
|
||||
* is still owned by the exe beuffer.
|
||||
*/
|
||||
char *exeBufName(pExeBuf self);
|
||||
@}
|
||||
|
||||
|
||||
\subsubsection{Managing exe Buffers}
|
||||
This section describes the interface to the management module for
|
||||
batch buffers. This management module is called the exe manager. This
|
||||
module also provides the interpreter interface to
|
||||
the batch buffer system. The batch buffer system can operate in two
|
||||
modes of operation:
|
||||
\begin{itemize}
|
||||
\item It keeps track of nested batch buffers, i.e. batch buffers which
|
||||
call each other through exe calls in the batch buffer itself.
|
||||
\item The management module also provides a stack for batch
|
||||
buffers. This stack can be preloaded and then can be executed
|
||||
sequentially by the exe manager. In order to do this provisions are
|
||||
made for loading batch buffers from files or through commands.
|
||||
\end{itemize}
|
||||
Moreover the exe manager provides commands to view the current stack
|
||||
and to find out what is currently being executed.
|
||||
|
||||
For all this we need a data structure:
|
||||
@d exemandat @{
|
||||
typedef struct __EXEMAN{
|
||||
pObjectDescriptor pDes;
|
||||
pICallBack pCall;
|
||||
char *sysPath;
|
||||
char *batchPath;
|
||||
pDynar exeStack;
|
||||
int exeStackPtr;
|
||||
int runList;
|
||||
pExeBuf uploadBuffer;
|
||||
}ExeMan, *pExeMan;
|
||||
@}
|
||||
The fields:
|
||||
\begin{itemize}
|
||||
\item[pDes] The standard object descriptor.
|
||||
\item[pCall] A callback interface to allow for automatic notifications
|
||||
about the operation of this module.
|
||||
\item[batchPath] The search path for batch buffers.
|
||||
\item[exeStack] The stack of nested batch buffers.
|
||||
\item[exeStackPtr] A pointer into exeStack.
|
||||
\item[runList] The list of buffers to run when running batch buffers.
|
||||
\item[uploadBuffer] A exe buffer to which data is uploaded. Also serves
|
||||
as a flag if uploading is possible. In this case uploadBuffer must be
|
||||
not NULL.
|
||||
\end{itemize}
|
||||
|
||||
The public interface to the exe manager are the interpreter interface
|
||||
functions. All the rest are module private functions.
|
||||
|
||||
@d exemanint @{
|
||||
int MakeExeManager(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
int ExeManagerWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
@}
|
||||
|
||||
@o exeman.i -d @{
|
||||
/*-------------------------------------------------------------------
|
||||
Internal header file for the exe manager module. Do not edit. This
|
||||
is automatically generated from exe.w
|
||||
-------------------------------------------------------------------*/
|
||||
@<exemandat@>
|
||||
@}
|
||||
|
||||
@o exeman.h @{
|
||||
/**
|
||||
* The batch buffer manager module. For more information see exe.tex.
|
||||
*
|
||||
* copyright: see file COPYRIGHT
|
||||
*
|
||||
* Mark Koennecke, November 2004
|
||||
*/
|
||||
#ifndef EXEMAN
|
||||
#define EXEMAN
|
||||
@<exemanint@>
|
||||
#endif
|
||||
@}
|
||||
|
||||
@o exebuf.i -d @{
|
||||
/*--------------------------------------------------------------------
|
||||
Internal header file for the exe buffer module. Do not edit. This is
|
||||
automatically generated from exe.w
|
||||
---------------------------------------------------------------------*/
|
||||
@<exebufdat@>
|
||||
|
||||
@}
|
||||
|
||||
@o exebuf.h -d @{
|
||||
/**
|
||||
* Buffer handling code for the Exe Buffer batch file processing
|
||||
* module.
|
||||
*
|
||||
* copyright: see file COPYRIGHT
|
||||
*
|
||||
* Mark Koennecke, November 2004
|
||||
*/
|
||||
#ifndef EXEBUF
|
||||
#define EXEBUF
|
||||
#include <sics.h>
|
||||
#include "dynstring.h"
|
||||
@<exebufint@>
|
||||
|
||||
#endif
|
||||
@}
|
231
exebuf.c
Normal file
231
exebuf.c
Normal file
@ -0,0 +1,231 @@
|
||||
/**
|
||||
* Implementation file for the exe buffer buffer handling system.
|
||||
*
|
||||
* copyright: see file COPYRIGHT
|
||||
*
|
||||
* More information in exe.tex
|
||||
*
|
||||
* Mark Koennecke, November 2004
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <tcl.h>
|
||||
#include "fortify.h"
|
||||
#include "sics.h"
|
||||
#include "exebuf.h"
|
||||
#include "dynstring.h"
|
||||
#include "exebuf.i"
|
||||
#include "status.h"
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
pExeBuf exeBufCreate(char *name){
|
||||
pExeBuf pNew = NULL;
|
||||
|
||||
pNew = (pExeBuf)malloc(sizeof(ExeBuf));
|
||||
if(pNew == NULL){
|
||||
return NULL;
|
||||
}
|
||||
memset(pNew,0,sizeof(ExeBuf));
|
||||
pNew->name = strdup(name);
|
||||
pNew->bufferContent = CreateDynString(1024,1024);
|
||||
if(!pNew->bufferContent){
|
||||
return NULL;
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
/*----------------------------------------------------------------------*/
|
||||
void exeBufKill(void *data){
|
||||
exeBufDelete((pExeBuf)data);
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
void exeBufDelete(pExeBuf self){
|
||||
if(self == NULL){
|
||||
return;
|
||||
}
|
||||
if(self->name != NULL){
|
||||
free(self->name);
|
||||
self->name = NULL;
|
||||
}
|
||||
if(self->bufferContent != NULL){
|
||||
DeleteDynString(self->bufferContent);
|
||||
self->bufferContent = NULL;
|
||||
}
|
||||
free(self);
|
||||
}
|
||||
/*----------------------------------------------------------------------*/
|
||||
int exeBufAppend(pExeBuf self, char *line){
|
||||
int status;
|
||||
assert(self);
|
||||
|
||||
status = DynStringConcat(self->bufferContent,line);
|
||||
DynStringConcatChar(self->bufferContent,'\n');
|
||||
return status;
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static char *locateName(char *filename){
|
||||
char *pPtr;
|
||||
int i;
|
||||
|
||||
pPtr = filename + strlen(filename) -1;
|
||||
for(i = strlen(filename) -1; i > 0; i--,pPtr--){
|
||||
if(*pPtr == '/'){
|
||||
pPtr++;
|
||||
return pPtr;
|
||||
}
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
int exeBufLoad(pExeBuf self, char *filename){
|
||||
char line[256];
|
||||
FILE *fd = NULL;
|
||||
int status;
|
||||
|
||||
assert(self);
|
||||
fd = fopen(filename,"r");
|
||||
if(fd == NULL){
|
||||
return 0;
|
||||
}
|
||||
while(fgets(line,255,fd) != NULL){
|
||||
status = exeBufAppend(self,line);
|
||||
if(status != 1){
|
||||
fclose(fd);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
fclose(fd);
|
||||
if(self->name != NULL){
|
||||
free(self->name);
|
||||
}
|
||||
self->name = strdup(locateName(filename));
|
||||
return 1;
|
||||
}
|
||||
/*----------------------------------------------------------------------*/
|
||||
int exeBufSave(pExeBuf self, char *filename){
|
||||
FILE *fd = NULL;
|
||||
|
||||
fd = fopen(filename,"w");
|
||||
if(fd == NULL){
|
||||
return 0;
|
||||
}
|
||||
fputs(GetCharArray(self->bufferContent),fd);
|
||||
fclose(fd);
|
||||
self->name = strdup(locateName(filename));
|
||||
return 1;
|
||||
}
|
||||
/*================ process batch buffer ==============================*/
|
||||
static pDynString findBlockEnd(pExeBuf self){
|
||||
pDynString command = NULL;
|
||||
char *buffer = NULL;
|
||||
int i;
|
||||
|
||||
assert(self);
|
||||
|
||||
command = CreateDynString(80,80);
|
||||
if(command == NULL){
|
||||
return NULL;
|
||||
}
|
||||
buffer = GetCharArray(self->bufferContent);
|
||||
if(self->end != 0){
|
||||
self->start = self->end + 1;
|
||||
}
|
||||
for(i = self->start; i < strlen(buffer); i++){
|
||||
DynStringConcatChar(command,buffer[i]);
|
||||
if(buffer[i] == '\n'){
|
||||
self->lineno++;
|
||||
if(Tcl_CommandComplete(GetCharArray(command))){
|
||||
self->end = i;
|
||||
return command;
|
||||
}
|
||||
}
|
||||
}
|
||||
DeleteDynString(command);
|
||||
return NULL;
|
||||
}
|
||||
/*---------------------------------------------------------------------*/
|
||||
int exeBufProcess(pExeBuf self, SicsInterp *pSics,
|
||||
SConnection *pCon, pICallBack pCall){
|
||||
pDynString command = NULL;
|
||||
Tcl_Interp *pTcl = NULL;
|
||||
int status;
|
||||
|
||||
assert(self);
|
||||
assert(pSics);
|
||||
|
||||
self->start = 0;
|
||||
self->end = 0;
|
||||
self->lineno = 0;
|
||||
pTcl = InterpGetTcl(pSics);
|
||||
|
||||
InvokeCallBack(pCall,BATCHSTART,self->name);
|
||||
|
||||
while((command = findBlockEnd(self)) != NULL){
|
||||
InvokeCallBack(pCall,BATCHAREA,NULL);
|
||||
status = Tcl_Eval(pTcl,GetCharArray(command));
|
||||
if(status != TCL_OK){
|
||||
if(pCon->sicsError == 0){
|
||||
/*
|
||||
Tcl Error
|
||||
*/
|
||||
if(strlen(pTcl->result) >= 2){
|
||||
SCWrite(pCon,pTcl->result,eError);
|
||||
}
|
||||
SCWrite(pCon,"ERROR: Tcl error in block:",eError);
|
||||
SCWrite(pCon,GetCharArray(command),eError);
|
||||
SCWrite(pCon,"ERROR: end of Tcl error block",eError);
|
||||
} else {
|
||||
/*
|
||||
SICS error: has already been reported
|
||||
*/
|
||||
pCon->sicsError = 0;
|
||||
}
|
||||
}
|
||||
DeleteDynString(command);
|
||||
if(SCGetInterrupt(pCon) >= eAbortBatch){
|
||||
SCWrite(pCon,"ERROR: batch processing interrupted",eError);
|
||||
SetStatus(eEager);
|
||||
return 0;
|
||||
} else {
|
||||
SCSetInterrupt(pCon,eContinue);
|
||||
}
|
||||
}
|
||||
InvokeCallBack(pCall,BATCHEND,self->name);
|
||||
return 1;
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
void exeBufRange(pExeBuf self, int *start, int *end, int *lineno){
|
||||
assert(self);
|
||||
*start = self->start;
|
||||
*end = self->end;
|
||||
*lineno = self->lineno;
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
pDynString exeBufText(pExeBuf self, int start, int end){
|
||||
pDynString result = NULL;
|
||||
char *pPtr;
|
||||
int i;
|
||||
|
||||
assert(self);
|
||||
|
||||
result = CreateDynString(256,132);
|
||||
if(result == NULL){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pPtr = GetCharArray(self->bufferContent);
|
||||
if(end >= strlen(pPtr)){
|
||||
end = strlen(pPtr) -1;
|
||||
}
|
||||
for(i = start; i < end; i++){
|
||||
DynStringConcatChar(result,pPtr[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
char *exeBufName(pExeBuf self){
|
||||
assert(self);
|
||||
return self->name;
|
||||
}
|
||||
|
||||
|
95
exebuf.h
Normal file
95
exebuf.h
Normal file
@ -0,0 +1,95 @@
|
||||
|
||||
#line 205 "exe.w"
|
||||
|
||||
/**
|
||||
* Buffer handling code for the Exe Buffer batch file processing
|
||||
* module.
|
||||
*
|
||||
* copyright: see file COPYRIGHT
|
||||
*
|
||||
* Mark Koennecke, November 2004
|
||||
*/
|
||||
#ifndef EXEBUF
|
||||
#define EXEBUF
|
||||
#include <sics.h>
|
||||
#include "dynstring.h"
|
||||
|
||||
#line 44 "exe.w"
|
||||
|
||||
typedef struct __EXEBUF *pExeBuf;
|
||||
|
||||
/**
|
||||
* create an exe buffer
|
||||
* @param The name to use for the exe buffer
|
||||
* @return A new exe buffer or NULL if out of memory
|
||||
*/
|
||||
pExeBuf exeBufCreate(char *name);
|
||||
/**
|
||||
* delete an exe buffer
|
||||
* @param data The exe buffer to delete
|
||||
*/
|
||||
void exeBufKill(void *data);
|
||||
void exeBufDelete(pExeBuf data);
|
||||
/**
|
||||
* add a a line to the exe buffer
|
||||
* @param self The exe buffer the line is to be added to
|
||||
* @param line The text to add
|
||||
* @return 1 on success, 0 when out of memory
|
||||
*/
|
||||
int exeBufAppend(pExeBuf self, char *line);
|
||||
/**
|
||||
* load an exe buffer from a file
|
||||
* @param self The exe buffer to load
|
||||
* @param filename The name of the file to load
|
||||
* @return 1 on success, 0 if the file could not be opened or
|
||||
* memory is exhausted.
|
||||
*/
|
||||
int exeBufLoad(pExeBuf self, char *filename);
|
||||
/**
|
||||
* save an exe buffer to a file.
|
||||
* @param self The exe buffer to laod
|
||||
* @param filename The name of the file to laod
|
||||
* @return 1 on success, 0 if the file could not be opened.
|
||||
*/
|
||||
int exeBufSave(pExeBuf self, char *filename);
|
||||
/**
|
||||
* process an exe buffer
|
||||
* @param self The exe buffer to process
|
||||
* @param pSics The SICS interpreter to use for processing
|
||||
* @param pCon The connection object providing the environment for
|
||||
* processing this buffer.
|
||||
* @pCall The callback interface to use for automatic notifications
|
||||
* @return 1 on success, 0 on error
|
||||
*/
|
||||
int exeBufProcess(pExeBuf self, SicsInterp *pSics,
|
||||
SConnection *pCon, pICallBack pCall);
|
||||
/**
|
||||
* retrieves the executing range
|
||||
* @param self The exe buffer to query
|
||||
* @param start The start of the executing range
|
||||
* @param end The end of the executing range
|
||||
* @param lineno The current line number
|
||||
*/
|
||||
void exeBufRange(pExeBuf self, int *start, int *end, int *lineno);
|
||||
/**
|
||||
* retrieves some portion of text
|
||||
* @param self The exe buffer to query
|
||||
* @param start The start index from which to copy
|
||||
* @param end The end pointer until which to copy
|
||||
* @return A dynamic string holding the currently executing text. It is
|
||||
* the clients task to delete this buffer sfter use. Or NULL if out of
|
||||
* memory.
|
||||
*/
|
||||
pDynString exeBufText(pExeBuf self, int start, int end);
|
||||
/**
|
||||
* retrieves the name of the batch buffer
|
||||
* @param self The exe buffer to query
|
||||
* @return A pointer to the buffer name. Do not delete! The name
|
||||
* is still owned by the exe beuffer.
|
||||
*/
|
||||
char *exeBufName(pExeBuf self);
|
||||
|
||||
#line 218 "exe.w"
|
||||
|
||||
|
||||
#endif
|
21
exebuf.i
Normal file
21
exebuf.i
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
#line 196 "exe.w"
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
Internal header file for the exe buffer module. Do not edit. This is
|
||||
automatically generated from exe.w
|
||||
---------------------------------------------------------------------*/
|
||||
|
||||
#line 25 "exe.w"
|
||||
|
||||
typedef struct __EXEBUF{
|
||||
char *name;
|
||||
pDynString bufferContent;
|
||||
int start;
|
||||
int end;
|
||||
int lineno;
|
||||
} ExeBuf;
|
||||
|
||||
#line 201 "exe.w"
|
||||
|
||||
|
765
exeman.c
Normal file
765
exeman.c
Normal file
@ -0,0 +1,765 @@
|
||||
/**
|
||||
* Implementation file for the exe buffer buffer manager.
|
||||
*
|
||||
* copyright: see file COPYRIGHT
|
||||
*
|
||||
* More information in exe.tex
|
||||
*
|
||||
* Mark Koennecke, November 2004
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <tcl.h>
|
||||
#include "fortify.h"
|
||||
#include "sics.h"
|
||||
#include "exebuf.h"
|
||||
#include "exeman.h"
|
||||
#include "sdynar.h"
|
||||
#include "dynstring.h"
|
||||
#include "lld.h"
|
||||
#include "exeman.i"
|
||||
#include "splitter.h"
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
static void KillExeMan(void *data){
|
||||
pExeMan self = (pExeMan)data;
|
||||
if(!self){
|
||||
return;
|
||||
}
|
||||
if(self->pDes){
|
||||
DeleteDescriptor(self->pDes);
|
||||
}
|
||||
if(self->pCall){
|
||||
DeleteCallBackInterface(self->pCall);
|
||||
}
|
||||
if(self->batchPath){
|
||||
free(self->batchPath);
|
||||
}
|
||||
if(self->sysPath){
|
||||
free(self->sysPath);
|
||||
}
|
||||
if(self->exeStack){
|
||||
DeleteDynar(self->exeStack);
|
||||
}
|
||||
LLDdelete(self->runList);
|
||||
free(self);
|
||||
}
|
||||
/*-----------------------------------------------------------------*/
|
||||
static int SaveExeMan(void *data, char *name, FILE *fd){
|
||||
pExeMan self = (pExeMan)data;
|
||||
|
||||
if(!self){
|
||||
return 0;
|
||||
}
|
||||
fprintf(fd,"%s batchpath %s\n",name,self->batchPath);
|
||||
fprintf(fd,"%s syspath %s\n",name,self->sysPath);
|
||||
return 1;
|
||||
}
|
||||
/*-----------------------------------------------------------------*/
|
||||
static void *ExeManInterface(void *data, int interfaceID){
|
||||
pExeMan self = (pExeMan)data;
|
||||
|
||||
if(self == NULL){
|
||||
return NULL;
|
||||
}
|
||||
if(interfaceID == CALLBACKINTERFACE){
|
||||
return self->pCall;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
/*------------------------------------------------------------------*/
|
||||
int MakeExeManager(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]){
|
||||
pExeMan pNew = NULL;
|
||||
int status;
|
||||
|
||||
pNew = (pExeMan)malloc(sizeof(ExeMan));
|
||||
if(!pNew){
|
||||
SCWrite(pCon,"ERROR: out of memory creating exe Manager",eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(pNew,0,sizeof(ExeMan));
|
||||
pNew->pDes = CreateDescriptor("ExeManager");
|
||||
pNew->pCall = CreateCallBackInterface();
|
||||
pNew->sysPath = strdup("./");
|
||||
pNew->batchPath = strdup("./");
|
||||
pNew->exeStack = CreateDynar(1,10,10,exeBufKill);
|
||||
pNew->exeStackPtr = -1;
|
||||
pNew->runList = LLDcreate(sizeof(pExeBuf));
|
||||
if(!pNew->pDes || !pNew->pCall || ! pNew->batchPath ||
|
||||
!pNew->exeStack || pNew->runList < 0){
|
||||
SCWrite(pCon,"ERROR: out of memory creating exe Manager",eError);
|
||||
return 0;
|
||||
}
|
||||
pNew->pDes->SaveStatus = SaveExeMan;
|
||||
pNew->pDes->GetInterface = ExeManInterface;
|
||||
|
||||
if(argc > 1){
|
||||
status = AddCommand(pSics,
|
||||
argv[1],
|
||||
ExeManagerWrapper,
|
||||
KillExeMan,
|
||||
pNew);
|
||||
} else {
|
||||
status = AddCommand(pSics,
|
||||
"exe",
|
||||
ExeManagerWrapper,
|
||||
KillExeMan,
|
||||
pNew);
|
||||
}
|
||||
if(status != 1) {
|
||||
SCWrite(pCon,"ERROR: duplicate exe manager not created",eError);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*======================== buffer execution ==========================*/
|
||||
static int fileExists(char *path){
|
||||
FILE *fd = NULL;
|
||||
int status = 0;
|
||||
|
||||
fd = fopen(path,"r");
|
||||
if(fd != NULL){
|
||||
fclose(fd);
|
||||
status = 1;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
extern char *stptok(char *s, char *t, int len, char *brk);
|
||||
|
||||
static pDynString locateBatchBuffer(pExeMan self, char *name){
|
||||
pDynString result = NULL;
|
||||
char pPath[132], *pPtr = NULL;
|
||||
|
||||
result = CreateDynString(256,256);
|
||||
if(!result){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pPtr = self->batchPath;
|
||||
while((pPtr = stptok(pPtr,pPath,131,":")) != NULL){
|
||||
DynStringCopy(result,pPath);
|
||||
DynStringConcatChar(result,'/');
|
||||
DynStringConcat(result,name);
|
||||
if(fileExists(GetCharArray(result))){
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
pPtr = self->sysPath;
|
||||
while((pPtr = stptok(pPtr,pPath,131,":")) != NULL){
|
||||
DynStringCopy(result,pPath);
|
||||
DynStringConcatChar(result,'/');
|
||||
DynStringConcat(result,name);
|
||||
if(fileExists(GetCharArray(result))){
|
||||
return result;
|
||||
}
|
||||
}
|
||||
DeleteDynString(result);
|
||||
return NULL;
|
||||
}
|
||||
/*-------------------------------------------------------------------*/
|
||||
static int runBatchBuffer(pExeMan self, SConnection *pCon,
|
||||
SicsInterp *pSics, char *name){
|
||||
pDynString filePath = NULL;
|
||||
char pBueffel[256];
|
||||
pExeBuf buffer = NULL;
|
||||
int status;
|
||||
|
||||
filePath = locateBatchBuffer(self,name);
|
||||
if(filePath == NULL){
|
||||
snprintf(pBueffel,255,"ERROR: batch buffer %s not found in path",
|
||||
name);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
buffer = exeBufCreate(name);
|
||||
if(!buffer){
|
||||
DeleteDynString(filePath);
|
||||
SCWrite(pCon,"ERROR: out of memory creating batch buffer",eError);
|
||||
return 0;
|
||||
}
|
||||
status = exeBufLoad(buffer,GetCharArray(filePath));
|
||||
if(!status){
|
||||
DeleteDynString(filePath);
|
||||
SCWrite(pCon,"ERROR: failed to load batch buffer",eError);
|
||||
return 0;
|
||||
}
|
||||
DeleteDynString(filePath);
|
||||
|
||||
self->exeStackPtr++;
|
||||
DynarPut(self->exeStack,self->exeStackPtr,buffer);
|
||||
status = exeBufProcess(buffer,pSics,pCon,self->pCall);
|
||||
self->exeStackPtr--;
|
||||
return status;
|
||||
}
|
||||
/*========================== path management ========================*/
|
||||
static int handleBatchPath(pExeMan self, SConnection *pCon, int argc,
|
||||
char *argv[]){
|
||||
char pBuffer[1024];
|
||||
|
||||
if(strcmp(argv[1],"batchpath") == 0) {
|
||||
if(argc > 2) {
|
||||
if(!SCMatchRights(pCon,usUser)){
|
||||
return 0;
|
||||
}
|
||||
if(self->batchPath != NULL){
|
||||
free(self->batchPath);
|
||||
}
|
||||
self->batchPath = strdup(argv[2]);
|
||||
SCSendOK(pCon);
|
||||
SCparChange(pCon);
|
||||
return 1;
|
||||
} else {
|
||||
snprintf(pBuffer,1023,"%s.batchpath = %s", argv[0],self->batchPath);
|
||||
SCWrite(pCon,pBuffer,eValue);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if(strcmp(argv[1],"syspath") == 0) {
|
||||
if(argc > 2) {
|
||||
if(!SCMatchRights(pCon,usMugger)){
|
||||
return 0;
|
||||
}
|
||||
if(self->sysPath != NULL){
|
||||
free(self->sysPath);
|
||||
}
|
||||
self->sysPath = strdup(argv[2]);
|
||||
SCSendOK(pCon);
|
||||
SCparChange(pCon);
|
||||
return 1;
|
||||
} else {
|
||||
snprintf(pBuffer,1023,"%s.syspath = %s", argv[0],self->sysPath);
|
||||
SCWrite(pCon,pBuffer,eValue);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
/*=========================== callbacks ==============================*/
|
||||
typedef struct {
|
||||
SConnection *pCon;
|
||||
pExeMan exe;
|
||||
}exeInfo, *pExeInfo;
|
||||
/*------------------------------------------------------------------*/
|
||||
static void killExeInfo(void *pData){
|
||||
pExeInfo self = (pExeInfo)pData;
|
||||
if(self != NULL){
|
||||
free(self);
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------------*/
|
||||
static pExeInfo makeExeInfo(SConnection *pCon, pExeMan self){
|
||||
pExeInfo pNew = NULL;
|
||||
pNew = malloc(sizeof(exeInfo));
|
||||
if(pNew == NULL){
|
||||
SCWrite(pCon,
|
||||
"ERROR: failed to allocate info structure for registering callbacks",
|
||||
eError);
|
||||
return NULL;
|
||||
}
|
||||
pNew->pCon = pCon;
|
||||
pNew->exe = self;
|
||||
return pNew;
|
||||
}
|
||||
/*------------------------------------------------------------------*/
|
||||
static int BufferCallback(int iEvent, void *pEvent, void *pUser){
|
||||
pExeInfo self = (pExeInfo)pUser;
|
||||
char *name = (char *)pEvent;
|
||||
char pBueffel[132];
|
||||
|
||||
if(iEvent == BATCHSTART){
|
||||
snprintf(pBueffel,131,"BATCHSTART=%s",name);
|
||||
SCWrite(self->pCon,pBueffel,eWarning);
|
||||
return 1;
|
||||
}
|
||||
if(iEvent == BATCHEND){
|
||||
snprintf(pBueffel,131,"BATCHEND=%s",name);
|
||||
SCWrite(self->pCon,pBueffel,eWarning);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*-------------------------------------------------------------------*/
|
||||
static int LineCallBack(int iEvent, void *pEvent, void *pUser){
|
||||
pExeInfo self = (pExeInfo)pUser;
|
||||
char pBueffel[256];
|
||||
int start, end, lineno;
|
||||
void *pPtr = NULL;
|
||||
pExeBuf buf = NULL;
|
||||
|
||||
assert(self);
|
||||
if(iEvent == BATCHAREA){
|
||||
DynarGet(self->exe->exeStack,self->exe->exeStackPtr,&pPtr);
|
||||
buf = (pExeBuf)pPtr;
|
||||
assert(buf);
|
||||
exeBufRange(buf,&start,&end,&lineno);
|
||||
snprintf(pBueffel,255,"%s.range = %d = %d",exeBufName(buf),
|
||||
start,end);
|
||||
SCWrite(self->pCon,pBueffel,eWarning);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
static void registerCallbacks(SConnection *pCon, SicsInterp *pSics,
|
||||
pExeMan self){
|
||||
pExeInfo info = NULL;
|
||||
long lID;
|
||||
|
||||
info = makeExeInfo(pCon,self);
|
||||
if(info == NULL){
|
||||
return;
|
||||
}
|
||||
lID = RegisterCallback(self->pCall, BATCHSTART, BufferCallback,
|
||||
info, killExeInfo);
|
||||
SCRegister(pCon,pSics, self->pCall,lID);
|
||||
lID = RegisterCallback(self->pCall, BATCHEND, BufferCallback,
|
||||
info, NULL);
|
||||
SCRegister(pCon,pSics, self->pCall,lID);
|
||||
lID = RegisterCallback(self->pCall, BATCHAREA, LineCallBack,
|
||||
info, killExeInfo);
|
||||
SCRegister(pCon,pSics, self->pCall,lID);
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
static void unregisterCallbacks(SConnection *pCon, pExeMan self){
|
||||
long lID;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < 3; i++){
|
||||
lID = SCgetCallbackID(pCon,self->pCall);
|
||||
if(lID >= 0){
|
||||
RemoveCallback(self->pCall,lID);
|
||||
SCUnregisterID(pCon,lID);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*========================= uploading ===============================*/
|
||||
static int startUpload(pExeMan self, SConnection *pCon){
|
||||
if(SCGetRights(pCon) > usUser){
|
||||
SCWrite(pCon,"ERROR: no permission to upload buffers",eError);
|
||||
return 0;
|
||||
}
|
||||
if(self->uploadBuffer != NULL){
|
||||
SCWrite(pCon,"ERRO: another upload is still in progress",eError);
|
||||
return 0;
|
||||
}
|
||||
self->uploadBuffer = exeBufCreate("upload");
|
||||
if(self->uploadBuffer == NULL){
|
||||
SCWrite(pCon,"ERROR: failed to create upload buffer",eError);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------*/
|
||||
static int appendLine(pExeMan self, SConnection *pCon,
|
||||
int argc, char *argv[]){
|
||||
char pLine[1024];
|
||||
|
||||
if(SCGetRights(pCon) > usUser){
|
||||
SCWrite(pCon,"ERROR: no permission to upload buffers",eError);
|
||||
return 0;
|
||||
}
|
||||
if(self->uploadBuffer == NULL){
|
||||
SCWrite(pCon,"ERROR: no upload in operation",eError);
|
||||
return 0;
|
||||
}
|
||||
Arg2Text(argc-2,&argv[2],pLine,1023);
|
||||
exeBufAppend(self->uploadBuffer,pLine);
|
||||
return 1;
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
static int uploadSave(pExeMan self, SConnection *pCon,
|
||||
int argc, char *argv[]){
|
||||
int status;
|
||||
|
||||
if(SCGetRights(pCon) > usUser){
|
||||
SCWrite(pCon,"ERROR: no permission to save buffers",eError);
|
||||
return 0;
|
||||
}
|
||||
if(argc < 3) {
|
||||
SCWrite(pCon,"ERROR: no file given to save upload buffer to",eError);
|
||||
return 0;
|
||||
}
|
||||
if(self->uploadBuffer == NULL){
|
||||
SCWrite(pCon,"ERROR: no upload buffer to save exists",eError);
|
||||
return 0;
|
||||
}
|
||||
status = exeBufSave(self->uploadBuffer,argv[2]);
|
||||
if(status == 0){
|
||||
SCWrite(pCon,"ERROR: failed to save exe buffer, destroyed...",eError);
|
||||
}
|
||||
exeBufDelete(self->uploadBuffer);
|
||||
self->uploadBuffer = NULL;
|
||||
return status;
|
||||
}
|
||||
/*=========================== info ===================================*/
|
||||
static void printExeStack(pExeMan self, SConnection *pCon){
|
||||
int i, j;
|
||||
pDynString txt = NULL;
|
||||
pExeBuf buf;
|
||||
void *pPtr = NULL;
|
||||
|
||||
txt = CreateDynString(80,80);
|
||||
if(txt == NULL){
|
||||
SCWrite(pCon,"ERROR: failed to allocate memory in printExeStack",eError);
|
||||
return;
|
||||
}
|
||||
for(i = 0; i <= self->exeStackPtr; i++){
|
||||
DynarGet(self->exeStack,i,&pPtr);
|
||||
buf = (pExeBuf)pPtr;
|
||||
assert(buf);
|
||||
for(j = 0; j < i; j++){
|
||||
DynStringConcat(txt," ");
|
||||
}
|
||||
DynStringConcat(txt,exeBufName(buf));
|
||||
DynStringConcatChar(txt,'\n');
|
||||
}
|
||||
SCWrite(pCon,GetCharArray(txt),eValue);
|
||||
DeleteDynString(txt);
|
||||
}
|
||||
/*-----------------------------------------------------------------*/
|
||||
static int locateBuffer(pExeMan self, char *name){
|
||||
int i;
|
||||
pExeBuf buf;
|
||||
void *pPtr = NULL;
|
||||
|
||||
for(i = 0; i <= self->exeStackPtr; i++){
|
||||
DynarGet(self->exeStack,i,&pPtr);
|
||||
buf = (pExeBuf)pPtr;
|
||||
if(strcmp(name,exeBufName(buf)) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
/*------------------------------------------------------------------*/
|
||||
static void printExeRange(pExeMan self, SConnection *pCon,
|
||||
int argc, char *argv[]){
|
||||
int start, end, lineno, bufNo;
|
||||
pExeBuf buf;
|
||||
void *pPtr = NULL;
|
||||
char pBueffel[256];
|
||||
|
||||
if(argc > 3) {
|
||||
bufNo = locateBuffer(self,argv[3]);
|
||||
} else {
|
||||
bufNo = self->exeStackPtr;
|
||||
}
|
||||
if(bufNo < 0){
|
||||
SCWrite(pCon,"ERROR: named buffer not found",eError);
|
||||
return;
|
||||
}
|
||||
DynarGet(self->exeStack,bufNo,&pPtr);
|
||||
buf = (pExeBuf)pPtr;
|
||||
assert(buf);
|
||||
exeBufRange(buf,&start,&end,&lineno);
|
||||
snprintf(pBueffel,255,"%s.range = %d = %d = %d",exeBufName(buf),
|
||||
start,end,lineno);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
}
|
||||
/*------------------------------------------------------------------*/
|
||||
static void printExeText(pExeMan self, SConnection *pCon,
|
||||
int argc, char *argv[]){
|
||||
int start, end, lineno, bufNo;
|
||||
pExeBuf buf;
|
||||
void *pPtr = NULL;
|
||||
pDynString txt;
|
||||
|
||||
if(argc > 3) {
|
||||
bufNo = locateBuffer(self,argv[3]);
|
||||
} else {
|
||||
bufNo = self->exeStackPtr;
|
||||
}
|
||||
if(bufNo < 0){
|
||||
SCWrite(pCon,"ERROR: named buffer not found",eError);
|
||||
return;
|
||||
}
|
||||
DynarGet(self->exeStack,bufNo,&pPtr);
|
||||
buf = (pExeBuf)pPtr;
|
||||
assert(buf);
|
||||
exeBufRange(buf,&start,&end,&lineno);
|
||||
txt = exeBufText(buf,start,end);
|
||||
if(txt != NULL){
|
||||
SCWrite(pCon,GetCharArray(txt),eValue);
|
||||
DeleteDynString(txt);
|
||||
} else {
|
||||
SCWrite(pCon,"ERROR: failed to allocate text buffer for operation",eError);
|
||||
}
|
||||
}
|
||||
/*------------------------------------------------------------------*/
|
||||
static void printQueue(pExeMan self, SConnection *pCon){
|
||||
pExeBuf buf= NULL;
|
||||
pDynString text = NULL;
|
||||
int status;
|
||||
|
||||
text = CreateDynString(80,80);
|
||||
if(text == NULL){
|
||||
SCWrite(pCon,"ERROR: out of memory",eError);
|
||||
return;
|
||||
}
|
||||
|
||||
status = LLDnodePtr2First(self->runList);
|
||||
while(status != 0) {
|
||||
LLDnodeDataTo(self->runList,&buf);
|
||||
if(buf != NULL){
|
||||
DynStringConcat(text,exeBufName(buf));
|
||||
DynStringConcatChar(text,'\n');
|
||||
}
|
||||
status = LLDnodePtr2Next(self->runList);
|
||||
}
|
||||
SCWrite(pCon,GetCharArray(text),eValue);
|
||||
DeleteDynString(text);
|
||||
}
|
||||
/*-------------------------------------------------------------------*/
|
||||
static int infoHandler(pExeMan self, SConnection *pCon,
|
||||
int argc, char *argv[]){
|
||||
char pBueffel[256];
|
||||
pExeBuf buf;
|
||||
void *pPtr = NULL;
|
||||
|
||||
if(self->exeStackPtr < 0){
|
||||
SCWrite(pCon,"Idle",eValue);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(argc < 3){
|
||||
if(self->exeStackPtr >= 0){
|
||||
DynarGet(self->exeStack,self->exeStackPtr,&pPtr);
|
||||
buf = (pExeBuf)pPtr;
|
||||
if(buf != NULL){
|
||||
snprintf(pBueffel,255,"Executing %s",exeBufName(buf));
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
strtolower(argv[2]);
|
||||
if(strcmp(argv[2],"stack") == 0){
|
||||
printExeStack(self,pCon);
|
||||
return 1;
|
||||
} else if(strcmp(argv[2],"range") == 0){
|
||||
printExeRange(self,pCon,argc,argv);
|
||||
return 1;
|
||||
} else if(strcmp(argv[2],"text") == 0){
|
||||
printExeText(self,pCon,argc,argv);
|
||||
return 1;
|
||||
} else {
|
||||
SCWrite(pCon,"ERROR: subcommand to info unknown",eError);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*=========================== print ==================================*/
|
||||
static int printBuffer(pExeMan self, SConnection *pCon,
|
||||
int argc, char *argv[]){
|
||||
pDynString filePath = NULL;
|
||||
char pLine[512];
|
||||
FILE *fd = NULL;
|
||||
|
||||
if(argc < 3){
|
||||
SCWrite(pCon,"ERROR: argument required for exe print",eError);
|
||||
return 0;
|
||||
}
|
||||
filePath = locateBatchBuffer(self,argv[2]);
|
||||
if(filePath == NULL){
|
||||
snprintf(pLine,255,"ERROR: batch buffer %s not found in path",
|
||||
argv[2]);
|
||||
SCWrite(pCon,pLine,eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fd = fopen(GetCharArray(filePath),"r");
|
||||
if(fd == NULL){
|
||||
SCWrite(pCon,"ERROR: failed to open file for printing",eError);
|
||||
DeleteDynString(filePath);
|
||||
return 0;
|
||||
}
|
||||
while(fgets(pLine,511,fd) != NULL){
|
||||
SCWrite(pCon,pLine,eValue);
|
||||
}
|
||||
fclose(fd);
|
||||
DeleteDynString(filePath);
|
||||
return 1;
|
||||
}
|
||||
/*========================== run stack ===============================*/
|
||||
static int enqueueBuffer(pExeMan self, SConnection *pCon,
|
||||
int argc, char *argv[]){
|
||||
pExeBuf buf = NULL;
|
||||
int status;
|
||||
pDynString filePath = NULL;
|
||||
|
||||
if(SCGetRights(pCon) > usUser){
|
||||
SCWrite(pCon,"ERROR: no permission to enque buffers",eError);
|
||||
return 0;
|
||||
}
|
||||
if(argc < 3) {
|
||||
SCWrite(pCon,"ERROR: no buffer file given to enqueue ",eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
filePath = locateBatchBuffer(self,argv[2]);
|
||||
if(filePath == NULL){
|
||||
SCWrite(pCon,"ERROR: failed to locate buffer to enqueue",eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
buf = exeBufCreate("enqueue");
|
||||
if(buf == NULL){
|
||||
SCWrite(pCon,"ERROR: out of memory",eError);
|
||||
return NULL;
|
||||
}
|
||||
status = exeBufLoad(buf,GetCharArray(filePath));
|
||||
DeleteDynString(filePath);
|
||||
if(status != 1) {
|
||||
SCWrite(pCon,"ERROR: failed to load buffer",eError);
|
||||
return 0;
|
||||
}
|
||||
LLDnodeAppendFrom(self->runList,&buf);
|
||||
return 1;
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
static void clearQueue(pExeMan self){
|
||||
pExeBuf buf = NULL;
|
||||
int status;
|
||||
|
||||
status = LLDnodePtr2First(self->runList);
|
||||
while(status != 0) {
|
||||
LLDnodeDataTo(self->runList,&buf);
|
||||
if(buf != NULL){
|
||||
exeBufDelete(buf);
|
||||
}
|
||||
LLDnodeDelete(self->runList);
|
||||
status = LLDnodePtr2Next(self->runList);
|
||||
}
|
||||
/*
|
||||
A second time round. This is a workaround for some
|
||||
dodgy behaviour of the list system.
|
||||
*/
|
||||
status = LLDnodePtr2First(self->runList);
|
||||
while(status != 0) {
|
||||
LLDnodeDataTo(self->runList,&buf);
|
||||
if(buf != NULL){
|
||||
exeBufDelete(buf);
|
||||
}
|
||||
LLDnodeDelete(self->runList);
|
||||
status = LLDnodePtr2Next(self->runList);
|
||||
}
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
static int execQueue(pExeMan self, SConnection *pCon, SicsInterp *pSics){
|
||||
pExeBuf buf = NULL;
|
||||
int status;
|
||||
|
||||
if(self->exeStackPtr >= 0){
|
||||
SCWrite(pCon,
|
||||
"ERROR: cannot start queue while batch buffers are still running",eError);
|
||||
return 0;
|
||||
}
|
||||
if(!SCMatchRights(pCon,usUser)){
|
||||
return 0;
|
||||
}
|
||||
|
||||
while(LLDnodePtr2First(self->runList) != 0){
|
||||
LLDnodeDataTo(self->runList,&buf);
|
||||
LLDnodeDelete(self->runList);
|
||||
self->exeStackPtr++;
|
||||
if(buf == NULL){
|
||||
SCWrite(pCon,
|
||||
"ERROR: serious trouble, buffer not in queue, inform programmer",eError);
|
||||
return 0;
|
||||
}
|
||||
DynarPut(self->exeStack,self->exeStackPtr,buf);
|
||||
status = exeBufProcess(buf,pSics,pCon,self->pCall);
|
||||
self->exeStackPtr--;
|
||||
if(SCGetInterrupt(pCon) >= eAbortBatch){
|
||||
SCWrite(pCon,"ERROR: queue processing interrupted",eError);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*========================== interpreter action =======================*/
|
||||
int ExeManagerWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]){
|
||||
pExeMan self = NULL;
|
||||
char pBufferName[256];
|
||||
int status;
|
||||
|
||||
self = (pExeMan)pData;
|
||||
assert(self != NULL);
|
||||
|
||||
strncpy(pBufferName,argv[1],255);
|
||||
if(argc > 1){
|
||||
strtolower(argv[1]);
|
||||
status = handleBatchPath(self,pCon,argc,argv);
|
||||
if(status >= 0){
|
||||
return status;
|
||||
}
|
||||
if(strcmp(argv[1],"interest") == 0){
|
||||
registerCallbacks(pCon,pSics,self);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
} else if(strcmp(argv[1],"uninterest") == 0){
|
||||
unregisterCallbacks(pCon,self);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}else if(strcmp(argv[1],"upload") == 0){
|
||||
status = startUpload(self,pCon);
|
||||
if(status){
|
||||
SCSendOK(pCon);
|
||||
}
|
||||
return status;
|
||||
}else if(strcmp(argv[1],"append") == 0){
|
||||
status = appendLine(self,pCon,argc,argv);
|
||||
if(status){
|
||||
SCSendOK(pCon);
|
||||
}
|
||||
return status;
|
||||
}else if(strcmp(argv[1],"save") == 0){
|
||||
status = uploadSave(self,pCon,argc,argv);
|
||||
if(status){
|
||||
SCSendOK(pCon);
|
||||
}
|
||||
return status;
|
||||
}else if(strcmp(argv[1],"info") == 0){
|
||||
status = infoHandler(self,pCon,argc,argv);
|
||||
if(status){
|
||||
SCSendOK(pCon);
|
||||
}
|
||||
return status;
|
||||
}else if(strcmp(argv[1],"print") == 0){
|
||||
status = printBuffer(self,pCon,argc,argv);
|
||||
return status;
|
||||
}else if(strcmp(argv[1],"enqueue") == 0){
|
||||
status = enqueueBuffer(self,pCon,argc,argv);
|
||||
if(status){
|
||||
SCSendOK(pCon);
|
||||
}
|
||||
return status;
|
||||
}else if(strcmp(argv[1],"clear") == 0){
|
||||
clearQueue(self);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}else if(strcmp(argv[1],"queue") == 0){
|
||||
printQueue(self,pCon);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}else if(strcmp(argv[1],"run") == 0){
|
||||
status = execQueue(self,pCon,pSics);
|
||||
if(status){
|
||||
SCSendOK(pCon);
|
||||
}
|
||||
return status;
|
||||
} else {
|
||||
return runBatchBuffer(self,pCon,pSics,pBufferName);
|
||||
}
|
||||
} else {
|
||||
SCWrite(pCon,"ERROR: need argument to manage batch buffers",eError);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
17
exeman.h
Normal file
17
exeman.h
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
/**
|
||||
* The batch buffer manager module. For more information see exe.tex.
|
||||
*
|
||||
* copyright: see file COPYRIGHT
|
||||
*
|
||||
* Mark Koennecke, November 2004
|
||||
*/
|
||||
#ifndef EXEMAN
|
||||
#define EXEMAN
|
||||
|
||||
int MakeExeManager(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
int ExeManagerWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
|
||||
#endif
|
23
fitcenter.c
23
fitcenter.c
@ -109,13 +109,9 @@
|
||||
pMot = FindMotor(pServ->pSics,self->pName);
|
||||
if(pMot)
|
||||
{
|
||||
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;
|
||||
self->fAxis[i] = MotorHardToSoftPosition(pMot,self->fAxis[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -349,7 +345,8 @@
|
||||
SCWrite(pCon,"Driving to center done",eStatus);
|
||||
break;
|
||||
default:
|
||||
SCWrite(pCon,"WARNING: driving to center finished with problems",
|
||||
SCWrite(pCon,
|
||||
"WARNING: driving to center finished with problems",
|
||||
eWarning);
|
||||
break;
|
||||
|
||||
@ -370,7 +367,8 @@
|
||||
|
||||
if(argc < 2)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: MakeFit expected the name of a scan command as a parameter",
|
||||
SCWrite(pCon,
|
||||
"ERROR: MakeFit expected the name of a scan command as a parameter",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
@ -408,7 +406,8 @@
|
||||
iRet1 = AddCommand(pSics,"center",CenterWrapper,NULL,self);
|
||||
if(!iRet || !iRet1)
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: duplicate commands peak and center not created",argv[2]);
|
||||
sprintf(pBueffel,
|
||||
"ERROR: duplicate commands peak and center not created",argv[2]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
DeleteFitCenter((void *)self);
|
||||
return 0;
|
||||
@ -435,11 +434,15 @@
|
||||
break;
|
||||
case -1:
|
||||
SCWrite(pCon,"WARNING: could not find left hand half width",eWarning);
|
||||
SCWrite(pCon,"Fit Results most certainly dodgy, SICS suggests measuring a full peak",eWarning);
|
||||
SCWrite(pCon,
|
||||
"Fit Results most certainly dodgy, SICS suggests measuring a full peak",
|
||||
eWarning);
|
||||
break;
|
||||
case -2:
|
||||
SCWrite(pCon,"WARNING: could not find right hand half width",eError);
|
||||
SCWrite(pCon,"Fit Results most certainly dodgy, SICS suggests measuring a full peak",eWarning);
|
||||
SCWrite(pCon,
|
||||
"Fit Results most certainly dodgy, SICS suggests measuring a full peak",
|
||||
eWarning);
|
||||
break;
|
||||
case -3:
|
||||
SCWrite(pCon,"ERROR: No counts found in Fit!",eError);
|
||||
|
61
hkl.c
61
hkl.c
@ -35,10 +35,7 @@
|
||||
#include "hkl.h"
|
||||
#include "hkl.i"
|
||||
#include "splitter.h"
|
||||
/*
|
||||
the space we leave in omega in order to allow for a scan to be done
|
||||
*/
|
||||
#define SCANBORDER 3.
|
||||
|
||||
/*
|
||||
the tolerance in chi we give before we allow to fix omega with phi
|
||||
*/
|
||||
@ -62,6 +59,7 @@
|
||||
self->fUB[0], self->fUB[1], self->fUB[2], self->fUB[3], self->fUB[4],
|
||||
self->fUB[5], self->fUB[6], self->fUB[7], self->fUB[8]);
|
||||
fprintf(fd,"%s hm %d\n",name, self->iHM);
|
||||
fprintf(fd,"%s scantolerance %f\n", name,self->scanTolerance);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -106,6 +104,7 @@
|
||||
pNew->fUB[4] = 1.;
|
||||
pNew->fUB[8] = 1.;
|
||||
pNew->UBinv = NULL;
|
||||
pNew->scanTolerance = 2.5;
|
||||
|
||||
return pNew;
|
||||
}
|
||||
@ -433,12 +432,12 @@ static int checkBisecting(pHKL self,
|
||||
a omega scan
|
||||
*/
|
||||
MotorGetPar(self->pOmega,"softlowerlim",&fLimit);
|
||||
if((float)om < fLimit + SCANBORDER){
|
||||
if((float)om < fLimit + self->scanTolerance){
|
||||
iTest = 0;
|
||||
} else {
|
||||
iTest = 1;
|
||||
MotorGetPar(self->pOmega,"softupperlim",&fLimit);
|
||||
if((float)om > fLimit - SCANBORDER){
|
||||
if((float)om > fLimit - self->scanTolerance){
|
||||
iTest = 0;
|
||||
} else {
|
||||
iTest = 1;
|
||||
@ -512,11 +511,11 @@ static int tryOmegaTweak(pHKL self, MATRIX z1, double *stt, double *om,
|
||||
omTarget = -9999;
|
||||
MotorGetPar(self->pOmega,"softlowerlim",&fLower);
|
||||
MotorGetPar(self->pOmega,"softupperlim",&fUpper);
|
||||
if(*om < fLower + SCANBORDER) {
|
||||
omTarget = fLower + SCANBORDER + .5;
|
||||
if(*om < fLower + self->scanTolerance) {
|
||||
omTarget = fLower + self->scanTolerance;
|
||||
}
|
||||
if(*om > fUpper - SCANBORDER){
|
||||
omTarget = fUpper - SCANBORDER - .5;
|
||||
if(*om > fUpper - self->scanTolerance){
|
||||
omTarget = fUpper - self->scanTolerance;
|
||||
}
|
||||
if(omTarget < -7000){
|
||||
return 0;
|
||||
@ -1309,6 +1308,9 @@ ente:
|
||||
sprintf(pBueffel,"Last HKL: %f %f %f ",
|
||||
self->fLastHKL[0], self->fLastHKL[1],self->fLastHKL[2]);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
snprintf(pBueffel,510,"%s.scantolerance = %f", argv[0],
|
||||
self->scanTolerance);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
}
|
||||
/*----------- current */
|
||||
@ -1370,8 +1372,9 @@ ente:
|
||||
{
|
||||
if(argc < 3)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: Insufficient number of arguments to HKL lambda",eError);
|
||||
return 0;
|
||||
snprintf(pBueffel,132,"%s.lambda = %f", argv[0],self->fLambda);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
}
|
||||
if(!SCMatchRights(pCon,usUser))
|
||||
{
|
||||
@ -1393,6 +1396,16 @@ ente:
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
/*------------- getub*/
|
||||
else if(strcmp(argv[1],"getub") == 0)
|
||||
{
|
||||
snprintf(pBueffel,510,"%s.ub = %f %f %f %f %f %f %f %f %f",
|
||||
argv[0], self->fUB[0], self->fUB[1], self->fUB[2],
|
||||
self->fUB[3], self->fUB[4], self->fUB[5],
|
||||
self->fUB[6], self->fUB[7], self->fUB[8]);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
}
|
||||
/*------- lambdavar*/
|
||||
else if(strcmp(argv[1],"lambdavar") == 0)
|
||||
{
|
||||
@ -1547,6 +1560,30 @@ ente:
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
/*------------- scantolerance */
|
||||
else if(strcmp(argv[1],"scantolerance") == 0)
|
||||
{
|
||||
if(argc < 3)
|
||||
{
|
||||
snprintf(pBueffel,510,"%s.scantolerance = %f",argv[0],
|
||||
self->scanTolerance);
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
}
|
||||
if(!SCMatchRights(pCon,usUser))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if(!isNumeric(argv[2]))
|
||||
{
|
||||
sprintf(pBueffel,"ERROR: %s was not recognized as a number", argv[2]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
self->scanTolerance = atof(argv[2]);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
/*------------- calculate */
|
||||
else if(strcmp(argv[1],"calc") == 0)
|
||||
{
|
||||
|
5
hkl.tex
5
hkl.tex
@ -32,6 +32,7 @@ $\langle$hkldat {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@ pMotor pNu;@\\
|
||||
\mbox{}\verb@ pSelVar pMono;@\\
|
||||
\mbox{}\verb@ long lID;@\\
|
||||
\mbox{}\verb@ float scanTolerance;@\\
|
||||
\mbox{}\verb@ } HKL;@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
@ -61,7 +62,9 @@ checking.
|
||||
\item[pPhi] the phi axis motor.
|
||||
\item[pNu] the nu axis motor for normal beam geometry.
|
||||
This is detector tilt.
|
||||
\item[pMono] The selector variable doing the wavelength.
|
||||
\item[pMono] The selector variable doing the wavelength.
|
||||
\item[scanTolerance] The hkl module refuses to position a reflection if it is
|
||||
to close to omega limits for scanning. This is the tolerance to use.
|
||||
\end{description}
|
||||
|
||||
The wavelength is a bit tricky. As it would be to time consuming to read two
|
||||
|
5
hkl.w
5
hkl.w
@ -27,6 +27,7 @@ The object uses the following object data structure:
|
||||
pMotor pNu;
|
||||
pSelVar pMono;
|
||||
long lID;
|
||||
float scanTolerance;
|
||||
} HKL;
|
||||
@}
|
||||
|
||||
@ -49,7 +50,9 @@ checking.
|
||||
\item[pPhi] the phi axis motor.
|
||||
\item[pNu] the nu axis motor for normal beam geometry.
|
||||
This is detector tilt.
|
||||
\item[pMono] The selector variable doing the wavelength.
|
||||
\item[pMono] The selector variable doing the wavelength.
|
||||
\item[scanTolerance] The hkl module refuses to position a reflection if it is
|
||||
to close to omega limits for scanning. This is the tolerance to use.
|
||||
\end{description}
|
||||
|
||||
The wavelength is a bit tricky. As it would be to time consuming to read two
|
||||
|
5
lld.c
5
lld.c
@ -647,6 +647,11 @@ long LLDnodeLong( int List )
|
||||
return *((long *) &ListControl[ List ].current->data );
|
||||
}
|
||||
|
||||
float LLDnodeFloat( int List )
|
||||
{
|
||||
return *((float *) &ListControl[ List ].current->data );
|
||||
}
|
||||
|
||||
void * LLDnodePtr( int List )
|
||||
{
|
||||
return *((void **) &ListControl[ List ].current->data );
|
||||
|
1
lld.h
1
lld.h
@ -120,6 +120,7 @@ int LLDnodePtr2Prev( int List );
|
||||
*/
|
||||
int LLDnodeInt( int List );
|
||||
long LLDnodeLong( int List );
|
||||
float LLDnodeFloat( int List );
|
||||
void * LLDnodePtr( int List );
|
||||
void FAR * LLDnodeFptr( int List );
|
||||
|
||||
|
5
macro.c
5
macro.c
@ -1,6 +1,6 @@
|
||||
/*--------------------------------------------------------------------------
|
||||
|
||||
All you need to evaluate macros with SICS.
|
||||
All you need to evaluate macros with SICS
|
||||
|
||||
The implmentation for the macro stuff is complex and non intuitive.
|
||||
This is the price to pay for adding the extremly powerful and
|
||||
@ -138,6 +138,7 @@
|
||||
pSinter = pSics->pInter;
|
||||
pCon = pSics->pCon[pSics->iStack];
|
||||
lastCommand = pSics->lastUnknown[pSics->iStack];
|
||||
pCon->sicsError = 0;
|
||||
|
||||
assert(pSinter);
|
||||
assert(pCon);
|
||||
@ -200,6 +201,7 @@
|
||||
else
|
||||
{
|
||||
Tcl_SetVar(pInter,SICSERROR,"yes",TCL_GLOBAL_ONLY);
|
||||
pCon->sicsError = 1;
|
||||
return TCL_ERROR;
|
||||
}
|
||||
}
|
||||
@ -948,7 +950,6 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp,
|
||||
SCWrite(pCon,pStart,eError);
|
||||
}
|
||||
iRet = InterpExecute(pSics,pCon,pCommand);
|
||||
SicsWait(1);
|
||||
SCWrite(pCon,"TRANSACTIONFINISHED",eError);
|
||||
return iRet;
|
||||
}
|
||||
|
6
make_gen
6
make_gen
@ -22,12 +22,12 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \
|
||||
scan.o fitcenter.o telnet.o token.o wwildcard.o\
|
||||
tclev.o hkl.o integrate.o optimise.o dynstring.o nxutil.o \
|
||||
mesure.o uubuffer.o commandlog.o udpquieck.o \
|
||||
rmtrail.o help.o nxupdate.o\
|
||||
rmtrail.o help.o nxupdate.o confvirtualmot.o \
|
||||
simchop.o choco.o chadapter.o trim.o scaldate.o \
|
||||
hklscan.o xytable.o \
|
||||
hklscan.o xytable.o exebuf.o exeman.o\
|
||||
circular.o maximize.o sicscron.o \
|
||||
d_sign.o d_mod.o tcldrivable.o \
|
||||
synchronize.o definealias.o \
|
||||
synchronize.o definealias.o oscillate.o \
|
||||
hmcontrol.o userscan.o rs232controller.o lomax.o \
|
||||
fourlib.o motreg.o motreglist.o anticollider.o \
|
||||
s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) \
|
||||
|
@ -6,9 +6,9 @@
|
||||
# Markus Zolliker, March 2003
|
||||
#==========================================================================
|
||||
# assign if the National Instrument GPIB driver is available
|
||||
#NI= -DHAVENI
|
||||
#NIOBJ= nigpib.o
|
||||
#NILIB=$(SINQDIR)/linux/lib/cib.o
|
||||
NI= -DHAVENI
|
||||
NIOBJ= nigpib.o
|
||||
NILIB=$(SINQDIR)/linux/lib/cib.o
|
||||
|
||||
# The variable SRC is needed for the case, where source and objects are
|
||||
# separated. In the case where objects are mixed up with sources, SRC
|
||||
|
131
mesure.c
131
mesure.c
@ -26,14 +26,11 @@
|
||||
#include "evcontroller.h"
|
||||
#include "mesure.h"
|
||||
#include "nxscript.h"
|
||||
#include "lld.h"
|
||||
|
||||
extern void SNXFormatTime(char *pBueffel, int iLen);
|
||||
#define ANGERR 0.2
|
||||
|
||||
/* nxutil.h
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
#define MESSDEBUG 1
|
||||
|
||||
@ -71,7 +68,16 @@
|
||||
float fPosition[4]; /* the real positions after driving */
|
||||
int iCompact; /* true if compact scan ouput. */
|
||||
int psiMode; /* 1 for psi scan mode, 0 else */
|
||||
int stepList; /* a list of stepwidth ranges */
|
||||
} Mesure;
|
||||
/*---------------------------------------------------------------------
|
||||
Entries for the stepwidth range list
|
||||
----------------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
float start;
|
||||
float end;
|
||||
float stepWidth;
|
||||
}StepEntry;
|
||||
/*--------------------------------------------------------------------------*/
|
||||
pMesure CreateMesure(pHKL pCryst, pScanData pScanner, pMotor pOmega,
|
||||
char *pOm, char *po2t, char *pFileRoot,
|
||||
@ -121,6 +127,7 @@
|
||||
pNew->lCounts = (long *)malloc(90*sizeof(long));
|
||||
#endif
|
||||
pNew->lCounts = (long *)malloc(50*sizeof(long));
|
||||
pNew->stepList = LLDcreate(sizeof(StepEntry));
|
||||
return pNew;
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
@ -150,6 +157,7 @@
|
||||
MesureClose(self);
|
||||
if(self->lCounts)
|
||||
free(self->lCounts);
|
||||
LLDdelete(self->stepList);
|
||||
free(self);
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
@ -351,12 +359,46 @@
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
static void addStepRange(pMesure self, float start, float end, float step)
|
||||
{
|
||||
StepEntry se;
|
||||
assert(self != NULL);
|
||||
|
||||
se.start = start;
|
||||
se.end = end;
|
||||
se.stepWidth = step;
|
||||
LLDnodeAppendFrom(self->stepList,&se);
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
static float determineStepWidth(pMesure self, float two_theta)
|
||||
{
|
||||
float stepWidth;
|
||||
StepEntry se;
|
||||
int iRet;
|
||||
|
||||
assert(self != NULL);
|
||||
|
||||
stepWidth = self->fStep;
|
||||
iRet = LLDnodePtr2First(self->stepList);
|
||||
while(iRet != 0)
|
||||
{
|
||||
LLDnodeDataTo(self->stepList,&se);
|
||||
if(two_theta > se.start && two_theta < se.end)
|
||||
{
|
||||
stepWidth = se.stepWidth;
|
||||
break;
|
||||
}
|
||||
iRet = LLDnodePtr2Next(self->stepList);
|
||||
}
|
||||
return stepWidth;
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int MesureReflection(pMesure self, float fHKL[3], float fPsi,
|
||||
SConnection *pCon)
|
||||
{
|
||||
int iRet, i;
|
||||
float fStart;
|
||||
float fStart, stepWidth;
|
||||
float fDelta, fSet[4];
|
||||
char pBueffel[132];
|
||||
|
||||
@ -402,19 +444,25 @@
|
||||
{
|
||||
return iRet;
|
||||
}
|
||||
fStart -= (self->np/2)*self->fStep;
|
||||
stepWidth = determineStepWidth(self,self->fPosition[0]);
|
||||
if(stepWidth != self->fStep)
|
||||
{
|
||||
snprintf(pBueffel,130,"Using stepwidth %f",stepWidth);
|
||||
SCWrite(pCon,pBueffel,eWarning);
|
||||
}
|
||||
fStart -= (self->np/2)*stepWidth;
|
||||
|
||||
/* set the scan up */
|
||||
ClearScanVar(self->pScanner);
|
||||
if(self->iMode == 0)
|
||||
{
|
||||
AddScanVar(self->pScanner, pServ->pSics,pCon,self->pCOmega,
|
||||
fStart, self->fStep);
|
||||
fStart, stepWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddScanVar(self->pScanner, pServ->pSics,pCon,self->pO2T,
|
||||
fStart, self->fStep);
|
||||
fStart, stepWidth);
|
||||
}
|
||||
|
||||
/* do the scan */
|
||||
@ -435,7 +483,7 @@
|
||||
{
|
||||
|
||||
int iRet, i;
|
||||
float fStart, fDelta;
|
||||
float fStart, fDelta, stepWidth;
|
||||
char pBueffel[132];
|
||||
|
||||
assert(self);
|
||||
@ -479,19 +527,25 @@
|
||||
{
|
||||
return iRet;
|
||||
}
|
||||
fStart -= (self->np/2)*self->fStep;
|
||||
|
||||
stepWidth = determineStepWidth(self,self->fPosition[0]);
|
||||
if(stepWidth != self->fStep)
|
||||
{
|
||||
snprintf(pBueffel,130,"Using stepwidth %f",stepWidth);
|
||||
SCWrite(pCon,pBueffel,eWarning);
|
||||
}
|
||||
fStart -= (self->np/2)*stepWidth;
|
||||
|
||||
/* set the scan up */
|
||||
ClearScanVar(self->pScanner);
|
||||
if(self->iMode == 0)
|
||||
{
|
||||
AddScanVar(self->pScanner, pServ->pSics,pCon,self->pCOmega,
|
||||
fStart, self->fStep);
|
||||
fStart, stepWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddScanVar(self->pScanner, pServ->pSics,pCon,self->pO2T,
|
||||
fStart, self->fStep);
|
||||
fStart, stepWidth);
|
||||
}
|
||||
|
||||
/* do the scan */
|
||||
@ -1142,7 +1196,7 @@
|
||||
char pBueffel[1024];
|
||||
pMesure self = NULL;
|
||||
double d;
|
||||
float fVal, fHKL[3];
|
||||
float fVal, fHKL[3], start, end, step;
|
||||
|
||||
self = (pMesure)pData;
|
||||
assert(self);
|
||||
@ -1389,6 +1443,55 @@
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if(strcmp(argv[1],"addrange") == 0)
|
||||
{
|
||||
if(argc < 5)
|
||||
{
|
||||
SCWrite(pCon,"ERROR: not enough arguments to addrange",eError);
|
||||
return 0;
|
||||
}
|
||||
if(!SCMatchRights(pCon,usUser))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
iRet = Tcl_GetDouble(pSics->pTcl,argv[2],&d);
|
||||
if(iRet != TCL_OK)
|
||||
{
|
||||
snprintf(pBueffel,131,
|
||||
"ERROR: expected numeric value but got %s",argv[2]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
start = (float)d;
|
||||
iRet = Tcl_GetDouble(pSics->pTcl,argv[3],&d);
|
||||
if(iRet != TCL_OK)
|
||||
{
|
||||
snprintf(pBueffel,131,
|
||||
"ERROR: expected numeric value but got %s",argv[3]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
end = (float)d;
|
||||
iRet = Tcl_GetDouble(pSics->pTcl,argv[4],&d);
|
||||
if(iRet != TCL_OK)
|
||||
{
|
||||
snprintf(pBueffel,131,
|
||||
"ERROR: expected numeric value but got %s",argv[4]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
step = (float)d;
|
||||
addStepRange(self,start,end,step);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
else if(strcmp(argv[1],"clearrange") == 0)
|
||||
{
|
||||
LLDdelete(self->stepList);
|
||||
self->stepList = LLDcreate(sizeof(StepEntry));
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
/*------ can be other pars */
|
||||
else
|
||||
{
|
||||
|
21
motor.c
21
motor.c
@ -271,6 +271,8 @@ static int reportAndFixError(pMotor self, SConnection *pCon)
|
||||
newStatus = statusRunTo(self,pCon);
|
||||
break;
|
||||
case MOTOK:
|
||||
snprintf(pBueffel,255,"WARNING: %s on %s",pError,self->name);
|
||||
SCWrite(pCon,pBueffel,eWarning);
|
||||
newStatus = HWIdle;
|
||||
break;
|
||||
default:
|
||||
@ -954,6 +956,21 @@ extern void KillPiPiezo(void *pData);
|
||||
*fHard = fVal*ObVal(self->ParArray,SIGN);
|
||||
return 0;
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
float MotorHardToSoftPosition(pMotor self, float fValue)
|
||||
{
|
||||
/* apply zeropoint */
|
||||
if(ObVal(self->ParArray,SIGN) < 0.)
|
||||
{
|
||||
fValue += ObVal(self->ParArray,SZERO);
|
||||
}
|
||||
else
|
||||
{
|
||||
fValue -= ObVal(self->ParArray,SZERO);
|
||||
}
|
||||
/* apply sign */
|
||||
return fValue*ObVal(self->ParArray,SIGN);
|
||||
}
|
||||
/* ------------------------------------------------------------------------*/
|
||||
int MotorGetSoftPosition(pMotor self, SConnection *pCon, float *fVal)
|
||||
{
|
||||
@ -970,7 +987,6 @@ extern void KillPiPiezo(void *pData);
|
||||
*fVal = fValue;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* apply zeropoint */
|
||||
if(ObVal(self->ParArray,SIGN) < 0.)
|
||||
{
|
||||
@ -983,7 +999,10 @@ extern void KillPiPiezo(void *pData);
|
||||
*fVal = fValue;
|
||||
|
||||
/* apply sign */
|
||||
/* *fVal = MotorHardToSoftPosition(self,fValue); */
|
||||
|
||||
*fVal = fValue*ObVal(self->ParArray,SIGN);
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
1
motor.h
1
motor.h
@ -46,6 +46,7 @@
|
||||
/* Where are we ? */
|
||||
int MotorGetSoftPosition(pMotor self,SConnection *pCon, float *fVal);
|
||||
int MotorGetHardPosition(pMotor self,SConnection *pCon, float *fVal);
|
||||
float MotorHardToSoftPosition(pMotor self, float fHard);
|
||||
|
||||
/* creation */
|
||||
int MotorCreate(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
|
264
napi.c
264
napi.c
@ -23,13 +23,12 @@
|
||||
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
static const char* rscid = "$Id: napi.c,v 1.7 2003/05/23 15:06:47 cvs Exp $"; /* Revision interted by CVS */
|
||||
static const char* rscid = "$Id: napi.c,v 1.8 2004/11/17 10:50:16 cvs Exp $"; /* Revision interted by CVS */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "fortify.h"
|
||||
#include "napi.h"
|
||||
|
||||
/*
|
||||
@ -71,13 +70,13 @@ static const char* rscid = "$Id: napi.c,v 1.7 2003/05/23 15:06:47 cvs Exp $"; /*
|
||||
/*------------------------------------------------------------------------
|
||||
HDF-5 cache size special stuff
|
||||
-------------------------------------------------------------------------*/
|
||||
static long cacheSize = 1024000; /* 1MB, HDF-5 default */
|
||||
long nx_cacheSize = 1024000; /* 1MB, HDF-5 default */
|
||||
|
||||
NXstatus CALLING_STYLE NXsetcache(long newVal)
|
||||
{
|
||||
if(newVal > 0)
|
||||
{
|
||||
cacheSize = newVal;
|
||||
nx_cacheSize = newVal;
|
||||
return NX_OK;
|
||||
}
|
||||
return NX_ERROR;
|
||||
@ -98,7 +97,7 @@ NXstatus CALLING_STYLE NXsetcache(long newVal)
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
|
||||
void CALLING_STYLE NXMSetError(void *pData, void (*NewError)(void *pD, char *text))
|
||||
NX_EXTERNAL void CALLING_STYLE NXMSetError(void *pData, void (*NewError)(void *pD, char *text))
|
||||
{
|
||||
NXpData = pData;
|
||||
NXIReportError = NewError;
|
||||
@ -126,6 +125,7 @@ NXstatus CALLING_STYLE NXsetcache(long newVal)
|
||||
NXhandle hdf5_handle;
|
||||
NXhandle hdf4_handle;
|
||||
pNexusFunction fHandle;
|
||||
NXstatus retstat;
|
||||
|
||||
/* configure fortify
|
||||
iFortifyScope = Fortify_EnterScope();
|
||||
@ -165,7 +165,11 @@ NXstatus CALLING_STYLE NXsetcache(long newVal)
|
||||
if (hdf_type==1) {
|
||||
/* HDF4 type */
|
||||
#ifdef HDF4
|
||||
NX4open((const char *)filename,am,&hdf4_handle);
|
||||
retstat = NX4open((const char *)filename,am,&hdf4_handle);
|
||||
if(retstat != NX_OK){
|
||||
free(fHandle);
|
||||
return retstat;
|
||||
}
|
||||
fHandle->pNexusData=hdf4_handle;
|
||||
fHandle->nxclose=NX4close;
|
||||
fHandle->nxflush=NX4flush;
|
||||
@ -194,13 +198,21 @@ NXstatus CALLING_STYLE NXsetcache(long newVal)
|
||||
fHandle->nxsameID=NX4sameID;
|
||||
fHandle->nxinitgroupdir=NX4initgroupdir;
|
||||
fHandle->nxinitattrdir=NX4initattrdir;
|
||||
#endif
|
||||
*gHandle = fHandle;
|
||||
return NX_OK;
|
||||
#else
|
||||
NXIReportError (NXpData,"ERROR: Attempt to create HDF4 file when not linked with HDF4");
|
||||
*gHandle = NULL;
|
||||
retstat = NX_ERROR;
|
||||
#endif /* HDF4 */
|
||||
return retstat;
|
||||
} else if (hdf_type==2) {
|
||||
/* HDF5 type */
|
||||
#ifdef HDF5
|
||||
NX5open(filename,am,&hdf5_handle);
|
||||
retstat = NX5open(filename,am,&hdf5_handle);
|
||||
if(retstat != NX_OK){
|
||||
free(fHandle);
|
||||
return retstat;
|
||||
}
|
||||
fHandle->pNexusData=hdf5_handle;
|
||||
fHandle->nxclose=NX5close;
|
||||
fHandle->nxflush=NX5flush;
|
||||
@ -229,11 +241,16 @@ NXstatus CALLING_STYLE NXsetcache(long newVal)
|
||||
fHandle->nxsameID=NX5sameID;
|
||||
fHandle->nxinitgroupdir=NX5initgroupdir;
|
||||
fHandle->nxinitattrdir=NX5initattrdir;
|
||||
#endif
|
||||
*gHandle = fHandle;
|
||||
return NX_OK;
|
||||
#else
|
||||
NXIReportError (NXpData,"ERROR: Attempt to create HDF5 file when not linked with HDF5");
|
||||
*gHandle = NULL;
|
||||
retstat = NX_ERROR;
|
||||
#endif /* HDF5 */
|
||||
return retstat;
|
||||
} else {
|
||||
NXIReportError (NXpData,"ERROR: Format not readable by this NeXus library");
|
||||
NXIReportError (NXpData,
|
||||
"ERROR: Format not readable by this NeXus library");
|
||||
*gHandle = NULL;
|
||||
return NX_ERROR;
|
||||
}
|
||||
@ -539,6 +556,229 @@ NXstatus CALLING_STYLE NXsetcache(long newVal)
|
||||
pNexusFunction pFunc = (pNexusFunction)fid;
|
||||
return pFunc->nxinitgroupdir(pFunc->pNexusData);
|
||||
}
|
||||
/*------------------------------------------------------------------------
|
||||
Implementation of NXopenpath.
|
||||
--------------------------------------------------------------------------*/
|
||||
static int isDataSetOpen(NXhandle hfil)
|
||||
{
|
||||
NXlink id;
|
||||
|
||||
/*
|
||||
This uses the (sensible) feauture that NXgetdataID returns NX_ERROR
|
||||
when no dataset is open
|
||||
*/
|
||||
if(NXgetdataID(hfil,&id) == NX_ERROR)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/*----------------------------------------------------------------------*/
|
||||
static int isRoot(NXhandle hfil)
|
||||
{
|
||||
NXlink id;
|
||||
|
||||
/*
|
||||
This uses the feauture that NXgetgroupID returns NX_ERROR
|
||||
when we are at root level
|
||||
*/
|
||||
if(NXgetgroupID(hfil,&id) == NX_ERROR)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/*--------------------------------------------------------------------
|
||||
copies the next path element into element.
|
||||
returns a pointer into path beyond the extracted path
|
||||
---------------------------------------------------------------------*/
|
||||
static char *extractNextPath(char *path, NXname element)
|
||||
{
|
||||
char *pPtr, *pStart;
|
||||
int length;
|
||||
|
||||
pPtr = path;
|
||||
/*
|
||||
skip over leading /
|
||||
*/
|
||||
if(*pPtr == '/')
|
||||
{
|
||||
pPtr++;
|
||||
}
|
||||
pStart = pPtr;
|
||||
|
||||
/*
|
||||
find next /
|
||||
*/
|
||||
pPtr = strchr(pStart,'/');
|
||||
if(pPtr == NULL)
|
||||
{
|
||||
/*
|
||||
this is the last path element
|
||||
*/
|
||||
strcpy(element,pStart);
|
||||
return NULL;
|
||||
} else {
|
||||
length = pPtr - pStart;
|
||||
strncpy(element,pStart,length);
|
||||
element[length] = '\0';
|
||||
}
|
||||
return pPtr + 1;
|
||||
}
|
||||
/*-------------------------------------------------------------------*/
|
||||
static NXstatus gotoRoot(NXhandle hfil)
|
||||
{
|
||||
int status;
|
||||
|
||||
if(isDataSetOpen(hfil))
|
||||
{
|
||||
status = NXclosedata(hfil);
|
||||
if(status == NX_ERROR)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
}
|
||||
while(!isRoot(hfil))
|
||||
{
|
||||
status = NXclosegroup(hfil);
|
||||
if(status == NX_ERROR)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return NX_OK;
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
static int isRelative(char *path)
|
||||
{
|
||||
if(path[0] == '.' && path[1] == '.')
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
/*------------------------------------------------------------------*/
|
||||
static NXstatus moveOneDown(NXhandle hfil)
|
||||
{
|
||||
if(isDataSetOpen(hfil))
|
||||
{
|
||||
return NXclosedata(hfil);
|
||||
}
|
||||
else
|
||||
{
|
||||
return NXclosegroup(hfil);
|
||||
}
|
||||
}
|
||||
/*-------------------------------------------------------------------
|
||||
returns a pointer to the remaining path string to move up
|
||||
--------------------------------------------------------------------*/
|
||||
static char *moveDown(NXhandle hfil, char *path, int *code)
|
||||
{
|
||||
int status;
|
||||
NXname pathElem;
|
||||
char *pPtr;
|
||||
|
||||
*code = NX_OK;
|
||||
|
||||
if(path[0] == '/')
|
||||
{
|
||||
*code = gotoRoot(hfil);
|
||||
return path;
|
||||
}
|
||||
else
|
||||
{
|
||||
pPtr = path;
|
||||
while(isRelative(pPtr))
|
||||
{
|
||||
status = moveOneDown(hfil);
|
||||
if(status == NX_ERROR)
|
||||
{
|
||||
*code = status;
|
||||
return pPtr;
|
||||
}
|
||||
pPtr += 3;
|
||||
}
|
||||
return pPtr;
|
||||
}
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
static NXstatus stepOneUp(NXhandle hfil, char *name)
|
||||
{
|
||||
int status, datatype;
|
||||
NXname name2, xclass;
|
||||
char pBueffel[256];
|
||||
|
||||
/*
|
||||
catch the case when we are there: i.e. no further stepping
|
||||
necessary. This can happen with paths like ../
|
||||
*/
|
||||
if(strlen(name) < 1)
|
||||
{
|
||||
return NX_OK;
|
||||
}
|
||||
|
||||
NXinitgroupdir(hfil);
|
||||
while(NXgetnextentry(hfil,name2,xclass,&datatype) != NX_EOD)
|
||||
{
|
||||
|
||||
if(strcmp(name2,name) == 0)
|
||||
{
|
||||
if(strcmp(xclass,"SDS") == 0)
|
||||
{
|
||||
return NXopendata(hfil,name);
|
||||
}
|
||||
else
|
||||
{
|
||||
return NXopengroup(hfil,name,xclass);
|
||||
}
|
||||
}
|
||||
}
|
||||
snprintf(pBueffel,255,"ERROR: NXopenpath cannot step into %s",name);
|
||||
NXIReportError (NXpData, pBueffel);
|
||||
return NX_ERROR;
|
||||
}
|
||||
/*---------------------------------------------------------------------*/
|
||||
NXstatus CALLING_STYLE NXopenpath(NXhandle hfil, CONSTCHAR *path)
|
||||
{
|
||||
int status, run = 1;
|
||||
NXname pathElement;
|
||||
char *pPtr;
|
||||
|
||||
if(hfil == NULL || path == NULL)
|
||||
{
|
||||
NXIReportError(NXpData,
|
||||
"ERROR: NXopendata needs both a file handle and a path string");
|
||||
return NX_ERROR;
|
||||
}
|
||||
|
||||
pPtr = moveDown(hfil,(char *)path,&status);
|
||||
if(status != NX_OK)
|
||||
{
|
||||
NXIReportError (NXpData,
|
||||
"ERROR: NXopendata failed to move down in hierarchy");
|
||||
return status;
|
||||
}
|
||||
|
||||
while(run == 1)
|
||||
{
|
||||
pPtr = extractNextPath(pPtr, pathElement);
|
||||
status = stepOneUp(hfil,pathElement);
|
||||
if(status != NX_OK)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
if(pPtr == NULL)
|
||||
{
|
||||
run = 0;
|
||||
}
|
||||
}
|
||||
return NX_OK;
|
||||
}
|
||||
/*----------------------------------------------------------------------
|
||||
F77 - API - Support - Routines
|
||||
----------------------------------------------------------------------*/
|
||||
|
11
napi.h
11
napi.h
@ -20,6 +20,8 @@
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
For further information, see <http://www.neutron.anl.gov/NeXus/>
|
||||
|
||||
$Id: napi.h,v 1.7 2004/11/17 10:50:16 cvs Exp $
|
||||
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
@ -27,7 +29,7 @@
|
||||
#define NEXUSAPI
|
||||
|
||||
/* NeXus HDF45 */
|
||||
#define NEXUS_VERSION "2.0.0." /* major.minor.patch */
|
||||
#define NEXUS_VERSION "2.1.0" /* major.minor.patch */
|
||||
|
||||
#define CONSTCHAR const char
|
||||
|
||||
@ -78,6 +80,7 @@ typedef struct {
|
||||
NX_INT32 32 bit integer
|
||||
NX_UINT32 32 bit unsigned integer
|
||||
NX_CHAR 8 bit character
|
||||
NX_BINARY lump of binary data == NX_UINT8
|
||||
|
||||
--------------------------------------------------------------------------*/
|
||||
|
||||
@ -92,6 +95,7 @@ typedef struct {
|
||||
#define NX_INT32 24
|
||||
#define NX_UINT32 25
|
||||
#define NX_CHAR 4
|
||||
#define NX_BINARY 21
|
||||
|
||||
/* Map NeXus compression methods to HDF compression methods */
|
||||
#define NX_COMP_NONE 100
|
||||
@ -141,6 +145,7 @@ typedef struct {
|
||||
# define NXclose MANGLE(nxiclose)
|
||||
# define NXmakegroup MANGLE(nximakegroup)
|
||||
# define NXopengroup MANGLE(nxiopengroup)
|
||||
# define NXopenpath MANGLE(nxiopenpath)
|
||||
# define NXclosegroup MANGLE(nxiclosegroup)
|
||||
# define NXmakedata MANGLE(nximakedata)
|
||||
# define NXcompmakedata MANGLE(nxicompmakedata)
|
||||
@ -211,6 +216,7 @@ typedef struct {
|
||||
# define NXflush MANGLE(NXIFLUSH)
|
||||
# define NXmakegroup MANGLE(NXIMAKEGROUP)
|
||||
# define NXopengroup MANGLE(NXIOPENGROUP)
|
||||
# define NXopenpath MANGLE(NXIOPENPATH)
|
||||
# define NXclosegroup MANGLE(NXICLOSEGROUP)
|
||||
# define NXmakedata MANGLE(NXIMAKEDATA)
|
||||
# define NXcompress MANGLE(NXICOMPRESS)
|
||||
@ -263,6 +269,8 @@ NX_EXTERNAL NXstatus CALLING_STYLE NXflush(NXhandle* pHandle);
|
||||
|
||||
NX_EXTERNAL NXstatus CALLING_STYLE NXmakegroup (NXhandle handle, CONSTCHAR *name, char* NXclass);
|
||||
NX_EXTERNAL NXstatus CALLING_STYLE NXopengroup (NXhandle handle, CONSTCHAR *name, char* NXclass);
|
||||
NX_EXTERNAL NXstatus CALLING_STYLE NXopenpath (NXhandle handle, CONSTCHAR *path);
|
||||
|
||||
NX_EXTERNAL NXstatus CALLING_STYLE NXclosegroup(NXhandle handle);
|
||||
|
||||
NX_EXTERNAL NXstatus CALLING_STYLE NXmakedata (NXhandle handle, CONSTCHAR* label, int datatype, int rank, int dim[]);
|
||||
@ -301,6 +309,7 @@ NX_EXTERNAL NXstatus CALLING_STYLE NXfree(void** data);
|
||||
A non Nexus standard function to set an error handler
|
||||
*/
|
||||
NX_EXTERNAL void CALLING_STYLE NXMSetError(void *pData, void (*ErrFunc)(void *pD, char *text));
|
||||
NX_EXTERNAL void CALLING_STYLE NXNXNXReportError(void *pData,char *text);
|
||||
|
||||
/*
|
||||
another special function for setting the default cache size for HDF-5
|
||||
|
@ -472,7 +472,7 @@ int NETReadTillTermNew(mkChannel *self, int timeout,
|
||||
return -1;
|
||||
}
|
||||
|
||||
maxTime = time(NULL) + (time_t)ceil((double)timeout/1000);
|
||||
maxTime = time(NULL) + (time_t)ceil((double)timeout/1000 +1);
|
||||
length = strlen(pTerm);
|
||||
memset(pBuffer,0,iBufLen);
|
||||
|
||||
@ -503,6 +503,8 @@ int NETReadTillTermNew(mkChannel *self, int timeout,
|
||||
}
|
||||
pBuffer[bufPtr] = c;
|
||||
bufPtr++;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
wait for more data
|
||||
|
1
nread.c
1
nread.c
@ -321,6 +321,7 @@ extern VerifyChannel(mkChannel *self); /* defined in network.c */
|
||||
else
|
||||
{
|
||||
pEnd++;
|
||||
pPtr = pEnd;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -856,6 +856,7 @@ static void makeLink(SConnection *pCon, SicsInterp *pSics,
|
||||
pNXScript self,
|
||||
int argc, char *argv[]){
|
||||
int status;
|
||||
char pBueffel[256];
|
||||
|
||||
if(argc < 4){
|
||||
SCWrite(pCon,"ERROR: insufficient number of arguments to makelink",
|
||||
@ -866,7 +867,9 @@ static void makeLink(SConnection *pCon, SicsInterp *pSics,
|
||||
status = NXDaliaslink(self->fileHandle, self->dictHandle,
|
||||
argv[2],argv[3]);
|
||||
if(status != NX_OK){
|
||||
SCWrite(pCon,"ERROR: linking failed",eError);
|
||||
snprintf(pBueffel,255,"ERROR: linking %s against %s failed",
|
||||
argv[2], argv[3]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return;
|
||||
}
|
||||
|
||||
|
13
ofac.c
13
ofac.c
@ -104,6 +104,9 @@
|
||||
#include "help.h"
|
||||
#include "site.h"
|
||||
#include "nxupdate.h"
|
||||
#include "confvirtmot.h"
|
||||
#include "exeman.h"
|
||||
#include "oscillate.h"
|
||||
/*----------------------- Server options creation -------------------------*/
|
||||
static int IFServerOption(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
@ -279,6 +282,13 @@
|
||||
AddCommand(pInter,"DrivableInvoke", TclDrivableInvoke,NULL,NULL);
|
||||
AddCommand(pInter,"UpdateFactory",UpdateFactory,NULL,NULL);
|
||||
AddCommand(pInter,"allowexec",AllowExec,NULL,NULL);
|
||||
AddCommand(pInter,"MakeConfigurableMotor",
|
||||
MakeConfigurableVirtualMotor,NULL,NULL);
|
||||
AddCommand(pInter,"MakeBatchManager",
|
||||
MakeExeManager,NULL,NULL);
|
||||
AddCommand(pInter,"MakeOscillator",
|
||||
MakeOscillator,NULL,NULL);
|
||||
|
||||
|
||||
/*
|
||||
install site specific commands
|
||||
@ -335,6 +345,9 @@
|
||||
RemoveCommand(pSics,"MakeTclInt");
|
||||
RemoveCommand(pSics,"UpdateFactory");
|
||||
RemoveCommand(pSics,"allowexec");
|
||||
RemoveCommand(pSics,"MakeConfigurableMotor");
|
||||
RemoveCommand(pSics,"MakeBatchManager");
|
||||
RemoveCommand(pSics,"MakeOscillator");
|
||||
|
||||
/*
|
||||
remove site specific installation commands
|
||||
|
231
oscillate.c
Normal file
231
oscillate.c
Normal file
@ -0,0 +1,231 @@
|
||||
/*-----------------------------------------------------------------------
|
||||
Oscillator runs a motor back and forth between its software limits.
|
||||
|
||||
copyright: see file COPYRIGHT
|
||||
|
||||
Mark Koennecke, November 2004
|
||||
------------------------------------------------------------------------*/
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <tcl.h>
|
||||
#include "fortify.h"
|
||||
#include "sics.h"
|
||||
#include "task.h"
|
||||
#include "oscillate.h"
|
||||
/*================== real work =========================================*/
|
||||
static void StopOscillation(pOscillator self){
|
||||
assert(self != NULL);
|
||||
if(self->taskID > 0){
|
||||
self->pMot->pDriver->Halt(self->pMot->pDriver);
|
||||
self->stopFlag = 1;
|
||||
MotorSetPar(self->pMot,self->pCon,"accesscode",(float)self->oldRights);
|
||||
self->taskID = -1;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------*/
|
||||
static int OscillationTask(void *data){
|
||||
pOscillator self = (pOscillator)data;
|
||||
int status, code, errStatus;
|
||||
char error[256];
|
||||
float pos;
|
||||
|
||||
|
||||
assert(self);
|
||||
if(self->stopFlag == 1){
|
||||
return 0;
|
||||
}
|
||||
|
||||
status = self->pMot->pDriver->GetStatus(self->pMot->pDriver);
|
||||
switch(status){
|
||||
case HWFault:
|
||||
case HWPosFault:
|
||||
self->pMot->pDriver->GetError(self->pMot->pDriver,&code,error,255);
|
||||
SCWrite(self->pCon,error,eError);
|
||||
if(self->nextTargetFlag == 1){
|
||||
pos = self->lowerLimit;
|
||||
} else {
|
||||
pos = self->upperLimit;
|
||||
}
|
||||
errStatus = self->pMot->pDriver->TryAndFixIt(self->pMot->pDriver,code,pos);
|
||||
self->errorCount++;
|
||||
if(errStatus == MOTFAIL){
|
||||
MotorRun(self->pMot,self->pCon,pos);
|
||||
}
|
||||
break;
|
||||
case HWBusy:
|
||||
break;
|
||||
case HWIdle:
|
||||
if(self->nextTargetFlag == 1){
|
||||
pos = self->upperLimit;
|
||||
self->nextTargetFlag = 0;
|
||||
} else {
|
||||
pos = self->lowerLimit;
|
||||
self->nextTargetFlag = 1;
|
||||
}
|
||||
MotorRun(self->pMot,self->pCon,pos);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
static int StartOscillation(pOscillator self, SConnection *pCon){
|
||||
float fval;
|
||||
int status;
|
||||
char error[80], pBueffel[255];
|
||||
|
||||
assert(self);
|
||||
|
||||
if(self->taskID > 0){
|
||||
SCWrite(pCon,"ERROR: oscillation already running",eError);
|
||||
return 1;
|
||||
}
|
||||
|
||||
MotorGetPar(self->pMot,"softlowerlim",&self->lowerLimit);
|
||||
self->lowerLimit += .5;
|
||||
MotorGetPar(self->pMot,"softupperlim",&self->upperLimit);
|
||||
self->upperLimit -= .5;
|
||||
MotorGetPar(self->pMot,"accesscode",&fval);
|
||||
self->oldRights = (int)fval;
|
||||
MotorSetPar(self->pMot,self->pCon,"accesscode",(float)usInternal);
|
||||
self->nextTargetFlag = 0;
|
||||
self->errorCount = 0;
|
||||
self->stopFlag = 0;
|
||||
|
||||
/*
|
||||
check reachability of limits
|
||||
*/
|
||||
status = MotorCheckBoundary(self->pMot,self->lowerLimit,&fval,error,79);
|
||||
if(!status){
|
||||
snprintf(pBueffel,255,"ERROR: cannot reach %f: %s reported",
|
||||
self->lowerLimit,error);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
status = MotorCheckBoundary(self->pMot,self->upperLimit,&fval,error,79);
|
||||
if(!status){
|
||||
snprintf(pBueffel,255,"ERROR: cannot reach %f: %s reported",
|
||||
self->upperLimit,error);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
start task
|
||||
*/
|
||||
self->taskID = TaskRegister(pServ->pTasker,
|
||||
OscillationTask,
|
||||
NULL,
|
||||
NULL,
|
||||
self,
|
||||
10);
|
||||
if(self->taskID < 0){
|
||||
SCWrite(pCon,"ERROR: failed to start oscillation task",eError);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*===================== life and death =================================*/
|
||||
static void KillOscillator(void *data){
|
||||
pOscillator self = (pOscillator)data;
|
||||
if(self != NULL){
|
||||
StopOscillation(self);
|
||||
if(self->pDes != NULL){
|
||||
DeleteDescriptor(self->pDes);
|
||||
}
|
||||
if(self->pCon != NULL){
|
||||
SCDeleteConnection(self->pCon);
|
||||
}
|
||||
free(self);
|
||||
}
|
||||
}
|
||||
/*========================================================================*/
|
||||
int MakeOscillator(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]){
|
||||
pOscillator pNew = NULL;
|
||||
pMotor pMot = NULL;
|
||||
char pBueffel[132];
|
||||
int status;
|
||||
|
||||
if(argc < 3){
|
||||
SCWrite(pCon,"ERROR: insufficient number of arguments to MakeOscilator",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pMot = FindMotor(pSics,argv[2]);
|
||||
if(pMot == NULL){
|
||||
snprintf(pBueffel,131,"ERROR: %s is no motor",argv[2]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pNew = (pOscillator)malloc(sizeof(Oscillator));
|
||||
if(pNew == NULL){
|
||||
SCWrite(pCon,"ERROR: out of memory creating oscillator",eError);
|
||||
return 0;
|
||||
}
|
||||
memset(pNew,0,sizeof(Oscillator));
|
||||
pNew->pDes = CreateDescriptor("Oscillator");
|
||||
pNew->pMot = pMot;
|
||||
pNew->pCon = SCCreateDummyConnection(pSics);
|
||||
if(!pNew->pDes || !pNew->pCon){
|
||||
SCWrite(pCon,"ERROR: out of memory creating oscillator",eError);
|
||||
return 0;
|
||||
}
|
||||
SCSetWriteFunc(pNew->pCon,SCFileWrite);
|
||||
SCSetRights(pNew->pCon,usInternal);
|
||||
|
||||
status = AddCommand(pSics,argv[1],
|
||||
OscillatorWrapper,
|
||||
KillOscillator,
|
||||
pNew);
|
||||
if(!status){
|
||||
snprintf(pBueffel,131,"ERROR: duplicate command %s not created",argv[1]);
|
||||
SCWrite(pCon,pBueffel,eError);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*========================================================================*/
|
||||
int OscillatorWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]){
|
||||
pOscillator self = (pOscillator)pData;
|
||||
char pBueffel[256];
|
||||
|
||||
assert(self);
|
||||
if(argc < 2){
|
||||
SCWrite(pCon,"ERROR: need start/stop argument for oscillator",eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!SCMatchRights(pCon,usUser)){
|
||||
return 0;
|
||||
}
|
||||
|
||||
strtolower(argv[1]);
|
||||
if(strcmp(argv[1],"start") == 0){
|
||||
return StartOscillation(self,pCon);
|
||||
} else if(strcmp(argv[1],"stop") == 0) {
|
||||
StopOscillation(self);
|
||||
snprintf(pBueffel,255,"Oscillation stopped with %d errors, %s",
|
||||
self->errorCount,
|
||||
"see commandlog for details");
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
} else if(strcmp(argv[1],"status") == 0) {
|
||||
if(self->taskID > 0){
|
||||
snprintf(pBueffel,255,"Oscillation running, %d errors so far, %s",
|
||||
self->errorCount,
|
||||
" error details in commandlog");
|
||||
} else {
|
||||
snprintf(pBueffel,255,"Oscillation stopped");
|
||||
}
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
} else {
|
||||
SCWrite(pCon,"ERROR: invalid sub command for oscillator requested",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
34
oscillate.h
Normal file
34
oscillate.h
Normal file
@ -0,0 +1,34 @@
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
Oscillator runs a motor back and forth between its software limits.
|
||||
|
||||
copyright: see file COPYRIGHT
|
||||
|
||||
Mark Koennecke, November 2004
|
||||
------------------------------------------------------------------------*/
|
||||
#ifndef SICSOSCILLATOR
|
||||
#define SICSOSCILLATOR
|
||||
#include "motor.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
pObjectDescriptor pDes;
|
||||
pMotor pMot;
|
||||
int oldRights;
|
||||
float upperLimit;
|
||||
float lowerLimit;
|
||||
int nextTargetFlag;
|
||||
long taskID;
|
||||
int stopFlag;
|
||||
SConnection *pCon;
|
||||
int errorCount;
|
||||
} Oscillator, *pOscillator;
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
int MakeOscillator(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
int OscillatorWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
|
||||
#endif
|
||||
|
70
oscillate.w
Normal file
70
oscillate.w
Normal file
@ -0,0 +1,70 @@
|
||||
\subsection{Motor Oscillation}
|
||||
This module allows to oscillate a motor, i.e. drive between two
|
||||
positions back and forth automatically. This is required for instance
|
||||
in order to control a radial collimator or in order to prevent
|
||||
preferred orientation effects in powder measurements. The oscialltion
|
||||
can be started and stoped through commands. When starting, this module
|
||||
takes over the motor in order to prevent it being driven by a
|
||||
user. The limits of the oscillation are given through the current
|
||||
software limits. When running, a special SICS task watches the motor
|
||||
and makes it run the other way when it has arrived at one of its
|
||||
boundaries. When oscillation is stopped, the motor is stopped, the
|
||||
task stopped and the control of the motor is returned to the user.
|
||||
|
||||
In order to this, a data structure the following data structure is
|
||||
required:
|
||||
@d oscdat @{
|
||||
typedef struct {
|
||||
pObjectDescriptor pDes;
|
||||
pMotor pMot;
|
||||
int oldRights;
|
||||
float upperLimit;
|
||||
float lowerLimit;
|
||||
int nextTargetFlag;
|
||||
long taskID;
|
||||
int stopFlag;
|
||||
SConnection *pCon;
|
||||
int errorCount;
|
||||
} Oscillator, *pOscillator;
|
||||
@}
|
||||
The fields:
|
||||
\begin{description}
|
||||
\item[pDes] The SICS object descriptor.
|
||||
\item[pMot] The motor controlled through this module.
|
||||
\item[oldRights] The old user rights code for the motor. Must be saved
|
||||
in order to restore when stopping the oscillation.
|
||||
\item[upperLimit] The uper limit of the oscillation.
|
||||
\item[lowerLimit] the lower limits of the oscillation.
|
||||
\item[nextTargetFlag] A flag which decides which limit is the next one
|
||||
to drive to.
|
||||
\item[taskID] The ID of the control task.
|
||||
\item[stopFlag] A flag to signal the control task to stop.
|
||||
\item[pCon] A dummy connection object to use for writing. Is
|
||||
configured to write to log files.
|
||||
\end{description}
|
||||
|
||||
The interface to this module is just the interpreter interface. The
|
||||
rest is module local.
|
||||
|
||||
@o oscillate.h @{
|
||||
/*-----------------------------------------------------------------------
|
||||
Oscillator runs a motor back and forth between its software limits.
|
||||
|
||||
copyright: see file COPYRIGHT
|
||||
|
||||
Mark Koennecke, November 2004
|
||||
------------------------------------------------------------------------*/
|
||||
#ifndef SICSOSCILLATOR
|
||||
#define SICSOSCILLATOR
|
||||
#include "motor.h"
|
||||
|
||||
@<oscdat@>
|
||||
/*---------------------------------------------------------------------*/
|
||||
int MakeOscillator(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
int OscillatorWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
|
||||
#endif
|
||||
|
||||
@}
|
@ -228,6 +228,7 @@ int readRS232TillTerm(prs232 self, void *data, int *datalen){
|
||||
}
|
||||
else if(iRet == -1)
|
||||
{
|
||||
printf("Incomplete read: %s\n", (char *)data);
|
||||
return INCOMPLETE;
|
||||
}
|
||||
*datalen = strlen((char *)data);
|
||||
@ -592,7 +593,7 @@ int RS232Action(SConnection *pCon, SicsInterp *pSics,
|
||||
}
|
||||
else if(strcmp(argv[1],"timeout") == 0)
|
||||
{
|
||||
if(checkSet(pCon,argc,usMugger))
|
||||
if(checkSet(pCon,argc,usUser))
|
||||
{
|
||||
setRS232Timeout(self,atoi(argv[2]));
|
||||
SCSendOK(pCon);
|
||||
|
Reference in New Issue
Block a user