- 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.
|
This version writes only to configured log files but not to sockets.
|
||||||
Used for automatic file execution for the WWW interface
|
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;
|
int i, iPtr, iRet;
|
||||||
char pBueffel[80];
|
char pBueffel[80];
|
||||||
@ -1557,6 +1557,54 @@ static void writeToLogFiles(SConnection *self, char *buffer)
|
|||||||
}
|
}
|
||||||
return 1;
|
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 --------------------*/
|
/*---------------------- The callback data structure --------------------*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
SConnection *pCon;
|
SConnection *pCon;
|
||||||
@ -1656,7 +1704,8 @@ static void writeToLogFiles(SConnection *self, char *buffer)
|
|||||||
/* get CallBack interface */
|
/* get CallBack interface */
|
||||||
pDum = (pDummy)pCom->pData;
|
pDum = (pDummy)pCom->pData;
|
||||||
assert(pDum);
|
assert(pDum);
|
||||||
pInterface = (pICallBack)pDum->pDescriptor->GetInterface(pDum,CALLBACKINTERFACE);
|
pInterface = (pICallBack)pDum->pDescriptor->GetInterface(pDum,
|
||||||
|
CALLBACKINTERFACE);
|
||||||
if(!pInterface)
|
if(!pInterface)
|
||||||
{
|
{
|
||||||
sprintf(pBueffel,"ERROR: %s does not support CallBacks",
|
sprintf(pBueffel,"ERROR: %s does not support CallBacks",
|
||||||
@ -1772,7 +1821,7 @@ static void writeToLogFiles(SConnection *self, char *buffer)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
SCWrite(self,"ERROR: Bad login",eError);
|
SCWrite(self,"ERROR: Bad login",eError);
|
||||||
|
printf("Bad login string %s\n", pPtr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(pPtr);
|
free(pPtr);
|
||||||
|
13
conman.h
13
conman.h
@ -53,6 +53,7 @@ typedef int (*writeFunc)(struct __SConnection *pCon,
|
|||||||
int iGrab;
|
int iGrab;
|
||||||
int iErrCode;
|
int iErrCode;
|
||||||
int parameterChange;
|
int parameterChange;
|
||||||
|
int sicsError;
|
||||||
SicsInterp *pSics;
|
SicsInterp *pSics;
|
||||||
|
|
||||||
/* a FIFO */
|
/* a FIFO */
|
||||||
@ -96,11 +97,23 @@ typedef int (*writeFunc)(struct __SConnection *pCon,
|
|||||||
writeFunc SCGetWriteFunc(SConnection *pCon);
|
writeFunc SCGetWriteFunc(SConnection *pCon);
|
||||||
void SCSetWriteFunc(SConnection *pCon, writeFunc x);
|
void SCSetWriteFunc(SConnection *pCon, writeFunc x);
|
||||||
int SCOnlySockWrite(SConnection *self, char *buffer, int iOut);
|
int SCOnlySockWrite(SConnection *self, char *buffer, int iOut);
|
||||||
|
int SCFileWrite(SConnection *self, char *buffer, int iOut);
|
||||||
int SCNotWrite(SConnection *self, char *buffer, int iOut);
|
int SCNotWrite(SConnection *self, char *buffer, int iOut);
|
||||||
/************************* CallBack *********************************** */
|
/************************* CallBack *********************************** */
|
||||||
int SCRegister(SConnection *pCon, SicsInterp *pSics,
|
int SCRegister(SConnection *pCon, SicsInterp *pSics,
|
||||||
void *pInter, long lID);
|
void *pInter, long lID);
|
||||||
int SCUnregister(SConnection *pCon, void *pInter);
|
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 **************************************/
|
/******************************* Error **************************************/
|
||||||
void SCSetInterrupt(SConnection *self, int eCode);
|
void SCSetInterrupt(SConnection *self, int eCode);
|
||||||
int SCGetInterrupt(SConnection *self);
|
int SCGetInterrupt(SConnection *self);
|
||||||
|
@ -12,6 +12,9 @@ initialisation file. Such special commands are described here.
|
|||||||
<DL>
|
<DL>
|
||||||
<DT>MakeRuenBuffer
|
<DT>MakeRuenBuffer
|
||||||
<DD>MakeRuenBuffer makes the RünBuffer system available.
|
<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
|
<DT>MakeDrive
|
||||||
<DD>MakeDrive craetes the drive command.
|
<DD>MakeDrive craetes the drive command.
|
||||||
<DT>MakeScanCommand name countername headfile recoverfil
|
<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
|
This document gives an overview about all the hardware and software systems
|
||||||
involved in SINQ instrument control. It describes the relationships between
|
involved in SINQ instrument control. It describes the relationships between
|
||||||
the various pieces and points to additional documentation, if available.
|
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
|
A copy of all documents referred in this paper is stored at:
|
||||||
and manager information is available on the WWW starting from http://lns00.psi.ch/.
|
/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}
|
\section{Hardware Overview}
|
||||||
For each SINQ instrument the following computing hardware is available:
|
For each SINQ instrument the following computing hardware is available:
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item A dedicated instrument workstation. Most of them are Compaq Alpha stations
|
\item A dedicated instrument workstation. Most of them are Intel x86
|
||||||
running True64Unix. One workstation is still running OpenVMS. Two instruments,
|
machines running Linux. Three instruments use alpha workstations
|
||||||
POLDI and RITA--2, are controlled through Intel--PC's running Linux.
|
running Tru64Unix.
|
||||||
\item A TCP/IP terminal server providing access to serial ports.
|
\item A TCP/IP terminal server providing access to serial ports.
|
||||||
\item Optionally, there are 1-3 histogram memory computers installed for those
|
\item Optionally, there are 1-3 histogram memory computers installed for those
|
||||||
instruments which have area detectors. These histogram memory computers are
|
instruments which have area detectors. These histogram memory computers are
|
||||||
Motorolla 6800 VME board processors running the vxWorks realtime
|
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}
|
\end{itemize}
|
||||||
Most instrument hardware is accessed through RS--232 interfaces and the terminal
|
Most instrument hardware is accessed through RS--232 interfaces and
|
||||||
server. Histogram memories are accessed through the TCP/IP network. Generally
|
the terminal server. Histogram memories are accessed through the
|
||||||
ethernet is used as the main instrument bus.
|
TCP/IP network . Generally ethernet is used as the main instrument bus.
|
||||||
|
|
||||||
In addition to the computers at the instrument the following systems are
|
In addition to the computers at the instrument the following systems are
|
||||||
available:
|
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
|
\item A True64Unix laboratory server (lnsa15) for data management and
|
||||||
primary data anlalysis.
|
primary data anlalysis.
|
||||||
\item True64Unix PSI server systems for data processing.
|
\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 A WWW--server currently installed on lns00.
|
||||||
\item pss123 is a Sun workstation holding the vxWorks development environment.
|
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
|
||||||
\section{Software Overview}
|
\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
|
debugging. Clients to this SerPortServer such as the SICS server communicate
|
||||||
with the server through a special ASCII protocoll transported through TCP/IP.
|
with the server through a special ASCII protocoll transported through TCP/IP.
|
||||||
The only documentation
|
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
|
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
|
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
|
Lakeshore temperature controllers used as standard temperature controllers
|
||||||
at SINQ. The only documentation for this program is Markus Zolliker.
|
at SINQ. The only documentation for this program is Markus Zolliker.
|
||||||
|
|
||||||
On many instruments there are histogram memory computers. These usually run the
|
On many instruments there are histogram memory computers. These
|
||||||
following programs:
|
usually run the following programs:
|
||||||
\begin{description}
|
\begin{description}
|
||||||
\item[bootUtil] a utility running when the histogram memory is booted which
|
\item[bootUtil] a utility running when the histogram memory is booted which
|
||||||
starts all the other tasks and configures the histogram memory from its
|
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".
|
described in the "SICS Manager Manual".
|
||||||
\item The programming concepts of SICS are discussed in the "SICS Programmers
|
\item The programming concepts of SICS are discussed in the "SICS Programmers
|
||||||
Reference".
|
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".
|
as "SICS Reference Manual".
|
||||||
\end{itemize}
|
\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.
|
The RITA--2 instrument from Ris\o{ } runs the TASCOM software.
|
||||||
This software is quite well documented in various documents which can be
|
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}
|
\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
|
data files measured at the instruments. Newly measured data files are
|
||||||
automatically mirrored to this area once a measurement has finished.
|
automatically mirrored to this area once a measurement has finished.
|
||||||
Not surprisingly there is a subdirectory for each instrument at SINQ.
|
There are directories for each year of SINQ operation. These contain
|
||||||
These instrument directories contain further subdirectories for each year
|
subdirectories for the various instruments.
|
||||||
of SINQ operation which hold the actual data files.
|
|
||||||
|
|
||||||
\subsubsection{The SINQ File Database}
|
\subsubsection{The SINQ File Database}
|
||||||
Right early on it was decided to separate the file archival function from the
|
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:
|
The SINQ File Database consists of the following components:
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item The database itself. This is the SQL database system mSQL from
|
\item The database itself. The database is installed on the central
|
||||||
Hughes Technology.
|
database server PSIP0 provided by central computing. The database
|
||||||
\item Any night the unix utility cron starts a shell script which is
|
software is oracle.
|
||||||
responsible for updating the database. This is done with two special
|
\item Any night a database update program is started as a cron
|
||||||
utility programs:
|
job. This programs runs on the linux server lnsl15. The program
|
||||||
\begin{itemize}
|
itself is a tcl script which uses oratcl for accessing the Oracle
|
||||||
\item nx\_dbupdate scans a given directory for new files which are not
|
database server and nxinter for accessing NeXus files.
|
||||||
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 A querying system. Curently the only query interface is a WWW--interface
|
\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}
|
\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.
|
of the software used at SINQ.
|
||||||
|
|
||||||
\subsubsection{Backup}
|
\subsubsection{Backup}
|
||||||
The laboratory server is also the central backup server for SINQ. Backups are
|
Most user files and the raw data is stored within the AFS network file
|
||||||
performed with the Legato networker software onto a tape jukebox holding
|
system. These files are backed up by central computing. Data files of
|
||||||
5 tapes with 20GB capacity each. Currently only the /home (holding
|
older years are additionally archived in the PSI archive system.
|
||||||
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.
|
|
||||||
|
|
||||||
The instrument accounts on the instrument computers must be backed up
|
The instrument and guest accounts on the instrument computers should
|
||||||
as well because they sometimes contain valuable scripts. Unfortunately
|
be backed up
|
||||||
there are not enough Networker licenses to go round and there is no
|
too because they sometimes contain valuable scripts. These are local
|
||||||
reliable linux client software for our version of Legato Networker.
|
accounts, thus they are not covered through the AFS backup. Data from
|
||||||
Therefore the data in the instrument accounts is copied nightly to a
|
these accounts is synchronized nightly onto a special account on the
|
||||||
special account on lnsa15 which is subjected to the normal
|
linux server lnsl15.
|
||||||
backup. More details:
|
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item There is a script which does the copying. It is {\bf backupinst}
|
\item There is a script which does the copying. It is {\bf backupinst}
|
||||||
in either /data/lnslib/bin or
|
in /afs/.psi.ch/project/sinq/linux/bin. This script is called with {\bf
|
||||||
/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
|
backupinst INST} where INST must be replaced by the instrument name in
|
||||||
capitals. This script essentially calls rsync with appropriate
|
capitals. This script essentially calls rsync with appropriate
|
||||||
arguments to synchronize the instrument account minus the data
|
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
|
0 3 * * * /data/lnslib/bin/backupinst TOPSI >/tmp/topsi.log 2>&1
|
||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
Please replace paths and instrument names to match the instrument.
|
Please replace paths and instrument names to match the instrument.
|
||||||
\item The backup account on lnsa15 is named SINQINST, password:
|
\item The backup account on lnsl15 is named SINQINST, password:
|
||||||
333SINQINST555. It contains a directory for each supported
|
SINQINSTLNS. It contains a directory for each supported
|
||||||
instruments. For backupinst to work properly there must be a line in
|
instruments. For backupinst to work properly there must be a line in
|
||||||
the .rhosts file of this account for each instrument computer which
|
the .rhosts file of this account for each instrument computer which
|
||||||
reads:
|
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
|
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
|
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
|
scientists gone wild or a loss of parameters due some electronic or
|
||||||
electrical incident these motor parameters are saved weekly. This happens
|
electrical incident these motor parameters should be saved
|
||||||
on wednesdays mornings. The unix utility crom triggers the process and
|
regularly. To this purpose there exits motor subdirectories in each
|
||||||
starts the script savemot which in turn does all necessary things. The
|
instrument account. Motors are either saved into this directory
|
||||||
actual saving of the motor parameters is accomplished with David Maden's
|
through a script in this directory or from SICS (TASP,
|
||||||
el734 program. The saved parameters end up in the /data/lnslib/motors
|
MORPHEUS). Motor parameter backup is a responsability of the
|
||||||
hierarchy. There exists a directory for each backup date which in turn
|
instrument scientists and must be triggered manually.
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
||||||
\subsubsection{License Server}
|
\subsubsection{License Server}
|
||||||
Unfortunately some people use the proprietary IDL programming system. This
|
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}
|
\subsection{Software at the WWW--server}
|
||||||
The WWW--server running at lns00 does not provide static information only but also
|
The WWW--server running at lns00 does not provide static information
|
||||||
active content calculated at runtime. The following services are
|
only but also active content calculated at runtime. The following
|
||||||
implemented:
|
services are implemented:
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item Keyword search in the SICS documentation.
|
\item Keyword search in the SICS documentation.
|
||||||
\item Searching the SINQ file database for files matching various criteria.
|
\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.
|
\item An experimental WWW control system for powder diffractometers.
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
Most of these services are provided through java servlets. In order to do this
|
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
|
a servlet engine was needed. The combination Apache WWW-server and Apache
|
||||||
JServ was choosen. However, it is planned to exchange the latter component
|
Jakarta Tomcat was choosen.
|
||||||
by the Jakarta engine in the near future.
|
|
||||||
|
|
||||||
The database search servlets are described in more detail in the document:
|
The database search servlets are described in more detail in the document:
|
||||||
\newline \centerline{The SINQ File Database}
|
\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.
|
from http://sunsite.berkeley.edu/SWISH-E.
|
||||||
The actual search is performed through a TCL--cgi script which calls the swishe
|
The actual search is performed through a TCL--cgi script which calls the swishe
|
||||||
application with appropriate parameters. This script can be found as
|
application with appropriate parameters. This script can be found as
|
||||||
swishsearch.cgi together with a batch file to start it properly
|
swishsearch.cgi in the cgi-bin directory of the WWW hierarchy on lns00.
|
||||||
(swishsearch.bat) 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
|
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
|
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:
|
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}
|
\begin{enumerate}
|
||||||
\item Data Files are generated by the instrument control programs at the
|
\item Data Files are generated by the instrument control programs at the
|
||||||
instrument computer.
|
instrument computer.
|
||||||
\item Data Files are automatically mirrored to the central repository
|
\item Data Files are automatically mirrored to the central AFS
|
||||||
on the laboratory server lnsa15. This happens through the FileSync server,
|
repository. This happens through the FileSync server,
|
||||||
a shell script and last not least the unix rsync utility. All this is installed
|
a shell script and last not least the unix rsync utility. All this is
|
||||||
at the instrument computer.
|
installed at the instrument computer.
|
||||||
\item Nightly new files are scanned for relevant information and their
|
\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}
|
\end{enumerate}
|
||||||
|
|
||||||
|
|
||||||
@ -341,7 +323,7 @@ The SICS Java clients access the SICS servers on the selected instruments
|
|||||||
laboratory server lnsa15.
|
laboratory server lnsa15.
|
||||||
\subsection{WWW Services}
|
\subsection{WWW Services}
|
||||||
The file search service on the WWW--server lns00 accesses the database
|
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
|
The instrument status display servlets on the WWW--server lns00 access the
|
||||||
SICS instrument control servers on the appropriate instrument computers
|
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}
|
\section{Maintainance Tasks}
|
||||||
\subsection{Yearly Maintainance}
|
\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
|
Whith each new year a couple of things must be done in order to keep the
|
||||||
system ship shape:
|
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}
|
\end{itemize}
|
||||||
\item On the laboratory server lnsa15:
|
\item On the laboratory server lnsa15:
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item Reenable the motor parameter backup cron job.
|
\item Create a new year hierarchy for the new year.
|
||||||
\item Create new subdirectories for the new year in the data hierarchy.
|
\item Store the old years data into the PSI archive.
|
||||||
\item In /data/lnslib/lib/nxdb create new configuration files for the new
|
\item Move the old years data into the non backed up AFS area.
|
||||||
year. Edit them to point to the new years subdirectory. Edit the
|
\item Make the new year the backed up data on AFS.
|
||||||
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.
|
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
\item On the WWW--server lns00:
|
\item On the WWW--server lns00:
|
||||||
\begin{itemize}
|
\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.
|
In order to keep up with ageing 1-2 computers have to be exchanged any year.
|
||||||
A instrument computer change requires the following adaptions:
|
A instrument computer change requires the following adaptions:
|
||||||
\begin{enumerate}
|
\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
|
\item Edit the instrument configuration file and change all occurences of
|
||||||
the old computers name to the new name.
|
the old computers name to the new name.
|
||||||
\item On lnsa15 as user lnslib: enter the new computer name into the
|
\item Install the cron job for backing up the local instrument
|
||||||
.rhosts file. This is required for the mirroring to work.
|
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
|
\item For the Java clients edit lnet/SINQConfig.java to point to the
|
||||||
new computer and rebuild all clients. Redistribute them as well.
|
new computer and rebuild all clients. Redistribute them as well.
|
||||||
\item For the WWW status, adapt the sics.conf file on lns00 and restart
|
\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>Measure a couple of reflections.
|
||||||
<li>Furthermore there are some specialities.
|
<li>Furthermore there are some specialities.
|
||||||
</ul>
|
</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>
|
</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>
|
<h3>Locate Reflections</h3>
|
||||||
<p>
|
<p>
|
||||||
If you know x-ray single crystal diffractometers you'll expect sophisticated
|
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
|
<dd>reads reflection HKL values from file filename and performs
|
||||||
tricsscans for each reflection. These will be done eith step width
|
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
|
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>
|
</dl>
|
||||||
</P>
|
</P>
|
||||||
|
|
||||||
|
3
event.c
3
event.c
@ -60,6 +60,9 @@
|
|||||||
"COUNTEND",
|
"COUNTEND",
|
||||||
"FILELOADED",
|
"FILELOADED",
|
||||||
"MOTEND",
|
"MOTEND",
|
||||||
|
"BATCHSTART",
|
||||||
|
"BATCHAREA",
|
||||||
|
"BATCHEND",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
13
event.h
13
event.h
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
#line 79 "event.w"
|
#line 85 "event.w"
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------
|
/*----------------------------------------------------------------------------
|
||||||
E V E N T
|
E V E N T
|
||||||
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
int Text2Event(char *pText);
|
int Text2Event(char *pText);
|
||||||
|
|
||||||
#line 92 "event.w"
|
#line 98 "event.w"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -38,19 +38,22 @@
|
|||||||
#define COUNTEND 11
|
#define COUNTEND 11
|
||||||
#define FILELOADED 12
|
#define FILELOADED 12
|
||||||
#define MOTEND 13
|
#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 ------------*/
|
/*--------------- Signals for the Signalfunction of each task ------------*/
|
||||||
|
|
||||||
#line 64 "event.w"
|
#line 70 "event.w"
|
||||||
|
|
||||||
#define SICSINT 300
|
#define SICSINT 300
|
||||||
#define SICSBROADCAST 301
|
#define SICSBROADCAST 301
|
||||||
#define TOKENGRAB 302
|
#define TOKENGRAB 302
|
||||||
#define TOKENRELEASE 303
|
#define TOKENRELEASE 303
|
||||||
|
|
||||||
#line 97 "event.w"
|
#line 103 "event.w"
|
||||||
|
|
||||||
#endif
|
#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}
|
\subsection{SICS Events}
|
||||||
This section lists the callback events known to Sics, their purpose, and
|
This section lists the callback events known to Sics, their purpose, and
|
||||||
their associated event datastructures when applicable. See the
|
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{flushleft} \small
|
||||||
\begin{minipage}{\linewidth} \label{scrap1}
|
\begin{minipage}{\linewidth} \label{scrap1}
|
||||||
$\langle\,$eFunc\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$
|
$\langle$eFunc {\footnotesize ?}$\rangle\equiv$
|
||||||
\vspace{-1ex}
|
\vspace{-1ex}
|
||||||
\begin{list}{}{} \item
|
\begin{list}{}{} \item
|
||||||
\mbox{}\verb@@\\
|
\mbox{}\verb@@\\
|
||||||
\mbox{}\verb@ int Text2Event(char *pText);@\\
|
\mbox{}\verb@ int Text2Event(char *pText);@\\
|
||||||
\mbox{}\verb@@{\NWsep}
|
\mbox{}\verb@@$\diamond$
|
||||||
\end{list}
|
\end{list}
|
||||||
\vspace{-1ex}
|
\vspace{-1ex}
|
||||||
\footnotesize\addtolength{\baselineskip}{-1ex}
|
\footnotesize\addtolength{\baselineskip}{-1ex}
|
||||||
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
||||||
\item \NWtxtMacroRefIn\ \NWlink{nuweb?}{?}.
|
\item Macro referenced in scrap ?.
|
||||||
\end{list}
|
\end{list}
|
||||||
\end{minipage}\\[4ex]
|
\end{minipage}\\[4ex]
|
||||||
\end{flushleft}
|
\end{flushleft}
|
||||||
@ -41,7 +31,7 @@ if the event code is not known, else the apropriate event code.
|
|||||||
|
|
||||||
\begin{flushleft} \small
|
\begin{flushleft} \small
|
||||||
\begin{minipage}{\linewidth} \label{scrap2}
|
\begin{minipage}{\linewidth} \label{scrap2}
|
||||||
$\langle\,$VE\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$
|
$\langle$VE {\footnotesize ?}$\rangle\equiv$
|
||||||
\vspace{-1ex}
|
\vspace{-1ex}
|
||||||
\begin{list}{}{} \item
|
\begin{list}{}{} \item
|
||||||
\mbox{}\verb@@\\
|
\mbox{}\verb@@\\
|
||||||
@ -59,12 +49,15 @@ $\langle\,$VE\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$
|
|||||||
\mbox{}\verb@#define COUNTEND 11@\\
|
\mbox{}\verb@#define COUNTEND 11@\\
|
||||||
\mbox{}\verb@#define FILELOADED 12@\\
|
\mbox{}\verb@#define FILELOADED 12@\\
|
||||||
\mbox{}\verb@#define MOTEND 13@\\
|
\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}
|
\end{list}
|
||||||
\vspace{-1ex}
|
\vspace{-1ex}
|
||||||
\footnotesize\addtolength{\baselineskip}{-1ex}
|
\footnotesize\addtolength{\baselineskip}{-1ex}
|
||||||
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
||||||
\item \NWtxtMacroRefIn\ \NWlink{nuweb?}{?}.
|
\item Macro referenced in scrap ?.
|
||||||
\end{list}
|
\end{list}
|
||||||
\end{minipage}\\[4ex]
|
\end{minipage}\\[4ex]
|
||||||
\end{flushleft}
|
\end{flushleft}
|
||||||
@ -88,6 +81,9 @@ fiffractometer has been measured.
|
|||||||
operation.
|
operation.
|
||||||
\item[COUNTEND] is an event signalling the end of a counting operation.
|
\item[COUNTEND] is an event signalling the end of a counting operation.
|
||||||
\item[MOTEND] signals the end of a driving operation.
|
\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}
|
\end{description}
|
||||||
|
|
||||||
Furthermore event contains system wide signal codes which are interpreted in
|
Furthermore event contains system wide signal codes which are interpreted in
|
||||||
@ -98,7 +94,7 @@ possible codes are defined.
|
|||||||
|
|
||||||
\begin{flushleft} \small
|
\begin{flushleft} \small
|
||||||
\begin{minipage}{\linewidth} \label{scrap3}
|
\begin{minipage}{\linewidth} \label{scrap3}
|
||||||
$\langle\,$VSIG\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$
|
$\langle$VSIG {\footnotesize ?}$\rangle\equiv$
|
||||||
\vspace{-1ex}
|
\vspace{-1ex}
|
||||||
\begin{list}{}{} \item
|
\begin{list}{}{} \item
|
||||||
\mbox{}\verb@@\\
|
\mbox{}\verb@@\\
|
||||||
@ -106,12 +102,12 @@ $\langle\,$VSIG\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$
|
|||||||
\mbox{}\verb@#define SICSBROADCAST 301@\\
|
\mbox{}\verb@#define SICSBROADCAST 301@\\
|
||||||
\mbox{}\verb@#define TOKENGRAB 302@\\
|
\mbox{}\verb@#define TOKENGRAB 302@\\
|
||||||
\mbox{}\verb@#define TOKENRELEASE 303@\\
|
\mbox{}\verb@#define TOKENRELEASE 303@\\
|
||||||
\mbox{}\verb@@{\NWsep}
|
\mbox{}\verb@@$\diamond$
|
||||||
\end{list}
|
\end{list}
|
||||||
\vspace{-1ex}
|
\vspace{-1ex}
|
||||||
\footnotesize\addtolength{\baselineskip}{-1ex}
|
\footnotesize\addtolength{\baselineskip}{-1ex}
|
||||||
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
||||||
\item \NWtxtMacroRefIn\ \NWlink{nuweb?}{?}.
|
\item Macro referenced in scrap ?.
|
||||||
\end{list}
|
\end{list}
|
||||||
\end{minipage}\\[4ex]
|
\end{minipage}\\[4ex]
|
||||||
\end{flushleft}
|
\end{flushleft}
|
||||||
@ -126,7 +122,7 @@ data is the string to send.
|
|||||||
\end{description}
|
\end{description}
|
||||||
\begin{flushleft} \small
|
\begin{flushleft} \small
|
||||||
\begin{minipage}{\linewidth} \label{scrap4}
|
\begin{minipage}{\linewidth} \label{scrap4}
|
||||||
\verb@"event.h"@\nobreak\ {\footnotesize \NWtarget{nuweb?}{?} }$\equiv$
|
\verb@"event.h"@ {\footnotesize ? }$\equiv$
|
||||||
\vspace{-1ex}
|
\vspace{-1ex}
|
||||||
\begin{list}{}{} \item
|
\begin{list}{}{} \item
|
||||||
\mbox{}\verb@@\\
|
\mbox{}\verb@@\\
|
||||||
@ -142,14 +138,14 @@ data is the string to send.
|
|||||||
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
|
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
|
||||||
\mbox{}\verb@#ifndef SICSEVENT@\\
|
\mbox{}\verb@#ifndef SICSEVENT@\\
|
||||||
\mbox{}\verb@#define 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@@\\
|
||||||
\mbox{}\verb@@\hbox{$\langle\,$VE\nobreak\ {\footnotesize \NWlink{nuweb?}{?}}$\,\rangle$}\verb@@\\
|
\mbox{}\verb@@$\langle$VE {\footnotesize ?}$\rangle$\verb@@\\
|
||||||
\mbox{}\verb@@\\
|
\mbox{}\verb@@\\
|
||||||
\mbox{}\verb@/*--------------- Signals for the Signalfunction of each task ------------*/@\\
|
\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@#endif@\\
|
||||||
\mbox{}\verb@@{\NWsep}
|
\mbox{}\verb@@$\diamond$
|
||||||
\end{list}
|
\end{list}
|
||||||
\vspace{-2ex}
|
\vspace{-2ex}
|
||||||
\end{minipage}\\[4ex]
|
\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 COUNTEND 11
|
||||||
#define FILELOADED 12
|
#define FILELOADED 12
|
||||||
#define MOTEND 13
|
#define MOTEND 13
|
||||||
|
#define BATCHSTART 14
|
||||||
|
#define BATCHAREA 15
|
||||||
|
#define BATCHEND 16
|
||||||
@}
|
@}
|
||||||
\begin{description}
|
\begin{description}
|
||||||
\item[VALUECHANGE] This is a variable changing its value. As event data a pointer to the
|
\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.
|
operation.
|
||||||
\item[COUNTEND] is an event signalling the end of a counting operation.
|
\item[COUNTEND] is an event signalling the end of a counting operation.
|
||||||
\item[MOTEND] signals the end of a driving operation.
|
\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}
|
\end{description}
|
||||||
|
|
||||||
Furthermore event contains system wide signal codes which are interpreted in
|
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);
|
pMot = FindMotor(pServ->pSics,self->pName);
|
||||||
if(pMot)
|
if(pMot)
|
||||||
{
|
{
|
||||||
i = MotorGetPar(pMot,"softzero",&fZero);
|
|
||||||
i = MotorGetPar(pMot,"sign",&fSign);
|
|
||||||
assert(i);
|
|
||||||
for(i = 0; i < self->iNP; i++)
|
for(i = 0; i < self->iNP; i++)
|
||||||
{
|
{
|
||||||
self->fAxis[i] -= fZero;
|
self->fAxis[i] = MotorHardToSoftPosition(pMot,self->fAxis[i]);
|
||||||
self->fAxis[i] *= fSign;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -349,7 +345,8 @@
|
|||||||
SCWrite(pCon,"Driving to center done",eStatus);
|
SCWrite(pCon,"Driving to center done",eStatus);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
SCWrite(pCon,"WARNING: driving to center finished with problems",
|
SCWrite(pCon,
|
||||||
|
"WARNING: driving to center finished with problems",
|
||||||
eWarning);
|
eWarning);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -370,7 +367,8 @@
|
|||||||
|
|
||||||
if(argc < 2)
|
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);
|
eError);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -408,7 +406,8 @@
|
|||||||
iRet1 = AddCommand(pSics,"center",CenterWrapper,NULL,self);
|
iRet1 = AddCommand(pSics,"center",CenterWrapper,NULL,self);
|
||||||
if(!iRet || !iRet1)
|
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);
|
SCWrite(pCon,pBueffel,eError);
|
||||||
DeleteFitCenter((void *)self);
|
DeleteFitCenter((void *)self);
|
||||||
return 0;
|
return 0;
|
||||||
@ -435,11 +434,15 @@
|
|||||||
break;
|
break;
|
||||||
case -1:
|
case -1:
|
||||||
SCWrite(pCon,"WARNING: could not find left hand half width",eWarning);
|
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;
|
break;
|
||||||
case -2:
|
case -2:
|
||||||
SCWrite(pCon,"WARNING: could not find right hand half width",eError);
|
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;
|
break;
|
||||||
case -3:
|
case -3:
|
||||||
SCWrite(pCon,"ERROR: No counts found in Fit!",eError);
|
SCWrite(pCon,"ERROR: No counts found in Fit!",eError);
|
||||||
|
61
hkl.c
61
hkl.c
@ -35,10 +35,7 @@
|
|||||||
#include "hkl.h"
|
#include "hkl.h"
|
||||||
#include "hkl.i"
|
#include "hkl.i"
|
||||||
#include "splitter.h"
|
#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
|
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[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]);
|
self->fUB[5], self->fUB[6], self->fUB[7], self->fUB[8]);
|
||||||
fprintf(fd,"%s hm %d\n",name, self->iHM);
|
fprintf(fd,"%s hm %d\n",name, self->iHM);
|
||||||
|
fprintf(fd,"%s scantolerance %f\n", name,self->scanTolerance);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,6 +104,7 @@
|
|||||||
pNew->fUB[4] = 1.;
|
pNew->fUB[4] = 1.;
|
||||||
pNew->fUB[8] = 1.;
|
pNew->fUB[8] = 1.;
|
||||||
pNew->UBinv = NULL;
|
pNew->UBinv = NULL;
|
||||||
|
pNew->scanTolerance = 2.5;
|
||||||
|
|
||||||
return pNew;
|
return pNew;
|
||||||
}
|
}
|
||||||
@ -433,12 +432,12 @@ static int checkBisecting(pHKL self,
|
|||||||
a omega scan
|
a omega scan
|
||||||
*/
|
*/
|
||||||
MotorGetPar(self->pOmega,"softlowerlim",&fLimit);
|
MotorGetPar(self->pOmega,"softlowerlim",&fLimit);
|
||||||
if((float)om < fLimit + SCANBORDER){
|
if((float)om < fLimit + self->scanTolerance){
|
||||||
iTest = 0;
|
iTest = 0;
|
||||||
} else {
|
} else {
|
||||||
iTest = 1;
|
iTest = 1;
|
||||||
MotorGetPar(self->pOmega,"softupperlim",&fLimit);
|
MotorGetPar(self->pOmega,"softupperlim",&fLimit);
|
||||||
if((float)om > fLimit - SCANBORDER){
|
if((float)om > fLimit - self->scanTolerance){
|
||||||
iTest = 0;
|
iTest = 0;
|
||||||
} else {
|
} else {
|
||||||
iTest = 1;
|
iTest = 1;
|
||||||
@ -512,11 +511,11 @@ static int tryOmegaTweak(pHKL self, MATRIX z1, double *stt, double *om,
|
|||||||
omTarget = -9999;
|
omTarget = -9999;
|
||||||
MotorGetPar(self->pOmega,"softlowerlim",&fLower);
|
MotorGetPar(self->pOmega,"softlowerlim",&fLower);
|
||||||
MotorGetPar(self->pOmega,"softupperlim",&fUpper);
|
MotorGetPar(self->pOmega,"softupperlim",&fUpper);
|
||||||
if(*om < fLower + SCANBORDER) {
|
if(*om < fLower + self->scanTolerance) {
|
||||||
omTarget = fLower + SCANBORDER + .5;
|
omTarget = fLower + self->scanTolerance;
|
||||||
}
|
}
|
||||||
if(*om > fUpper - SCANBORDER){
|
if(*om > fUpper - self->scanTolerance){
|
||||||
omTarget = fUpper - SCANBORDER - .5;
|
omTarget = fUpper - self->scanTolerance;
|
||||||
}
|
}
|
||||||
if(omTarget < -7000){
|
if(omTarget < -7000){
|
||||||
return 0;
|
return 0;
|
||||||
@ -1309,6 +1308,9 @@ ente:
|
|||||||
sprintf(pBueffel,"Last HKL: %f %f %f ",
|
sprintf(pBueffel,"Last HKL: %f %f %f ",
|
||||||
self->fLastHKL[0], self->fLastHKL[1],self->fLastHKL[2]);
|
self->fLastHKL[0], self->fLastHKL[1],self->fLastHKL[2]);
|
||||||
SCWrite(pCon,pBueffel,eValue);
|
SCWrite(pCon,pBueffel,eValue);
|
||||||
|
snprintf(pBueffel,510,"%s.scantolerance = %f", argv[0],
|
||||||
|
self->scanTolerance);
|
||||||
|
SCWrite(pCon,pBueffel,eValue);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
/*----------- current */
|
/*----------- current */
|
||||||
@ -1370,8 +1372,9 @@ ente:
|
|||||||
{
|
{
|
||||||
if(argc < 3)
|
if(argc < 3)
|
||||||
{
|
{
|
||||||
SCWrite(pCon,"ERROR: Insufficient number of arguments to HKL lambda",eError);
|
snprintf(pBueffel,132,"%s.lambda = %f", argv[0],self->fLambda);
|
||||||
return 0;
|
SCWrite(pCon,pBueffel,eValue);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
if(!SCMatchRights(pCon,usUser))
|
if(!SCMatchRights(pCon,usUser))
|
||||||
{
|
{
|
||||||
@ -1393,6 +1396,16 @@ ente:
|
|||||||
SCSendOK(pCon);
|
SCSendOK(pCon);
|
||||||
return 1;
|
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*/
|
/*------- lambdavar*/
|
||||||
else if(strcmp(argv[1],"lambdavar") == 0)
|
else if(strcmp(argv[1],"lambdavar") == 0)
|
||||||
{
|
{
|
||||||
@ -1547,6 +1560,30 @@ ente:
|
|||||||
SCSendOK(pCon);
|
SCSendOK(pCon);
|
||||||
return 1;
|
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 */
|
/*------------- calculate */
|
||||||
else if(strcmp(argv[1],"calc") == 0)
|
else if(strcmp(argv[1],"calc") == 0)
|
||||||
{
|
{
|
||||||
|
1
hkl.i
1
hkl.i
@ -24,6 +24,7 @@
|
|||||||
pMotor pNu;
|
pMotor pNu;
|
||||||
pSelVar pMono;
|
pSelVar pMono;
|
||||||
long lID;
|
long lID;
|
||||||
|
float scanTolerance;
|
||||||
} HKL;
|
} HKL;
|
||||||
|
|
||||||
|
|
||||||
|
3
hkl.tex
3
hkl.tex
@ -32,6 +32,7 @@ $\langle$hkldat {\footnotesize ?}$\rangle\equiv$
|
|||||||
\mbox{}\verb@ pMotor pNu;@\\
|
\mbox{}\verb@ pMotor pNu;@\\
|
||||||
\mbox{}\verb@ pSelVar pMono;@\\
|
\mbox{}\verb@ pSelVar pMono;@\\
|
||||||
\mbox{}\verb@ long lID;@\\
|
\mbox{}\verb@ long lID;@\\
|
||||||
|
\mbox{}\verb@ float scanTolerance;@\\
|
||||||
\mbox{}\verb@ } HKL;@\\
|
\mbox{}\verb@ } HKL;@\\
|
||||||
\mbox{}\verb@@$\diamond$
|
\mbox{}\verb@@$\diamond$
|
||||||
\end{list}
|
\end{list}
|
||||||
@ -62,6 +63,8 @@ checking.
|
|||||||
\item[pNu] the nu axis motor for normal beam geometry.
|
\item[pNu] the nu axis motor for normal beam geometry.
|
||||||
This is detector tilt.
|
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}
|
\end{description}
|
||||||
|
|
||||||
The wavelength is a bit tricky. As it would be to time consuming to read two
|
The wavelength is a bit tricky. As it would be to time consuming to read two
|
||||||
|
3
hkl.w
3
hkl.w
@ -27,6 +27,7 @@ The object uses the following object data structure:
|
|||||||
pMotor pNu;
|
pMotor pNu;
|
||||||
pSelVar pMono;
|
pSelVar pMono;
|
||||||
long lID;
|
long lID;
|
||||||
|
float scanTolerance;
|
||||||
} HKL;
|
} HKL;
|
||||||
@}
|
@}
|
||||||
|
|
||||||
@ -50,6 +51,8 @@ checking.
|
|||||||
\item[pNu] the nu axis motor for normal beam geometry.
|
\item[pNu] the nu axis motor for normal beam geometry.
|
||||||
This is detector tilt.
|
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}
|
\end{description}
|
||||||
|
|
||||||
The wavelength is a bit tricky. As it would be to time consuming to read two
|
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 );
|
return *((long *) &ListControl[ List ].current->data );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float LLDnodeFloat( int List )
|
||||||
|
{
|
||||||
|
return *((float *) &ListControl[ List ].current->data );
|
||||||
|
}
|
||||||
|
|
||||||
void * LLDnodePtr( int List )
|
void * LLDnodePtr( int List )
|
||||||
{
|
{
|
||||||
return *((void **) &ListControl[ List ].current->data );
|
return *((void **) &ListControl[ List ].current->data );
|
||||||
|
1
lld.h
1
lld.h
@ -120,6 +120,7 @@ int LLDnodePtr2Prev( int List );
|
|||||||
*/
|
*/
|
||||||
int LLDnodeInt( int List );
|
int LLDnodeInt( int List );
|
||||||
long LLDnodeLong( int List );
|
long LLDnodeLong( int List );
|
||||||
|
float LLDnodeFloat( int List );
|
||||||
void * LLDnodePtr( int List );
|
void * LLDnodePtr( int List );
|
||||||
void FAR * LLDnodeFptr( 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.
|
The implmentation for the macro stuff is complex and non intuitive.
|
||||||
This is the price to pay for adding the extremly powerful and
|
This is the price to pay for adding the extremly powerful and
|
||||||
@ -138,6 +138,7 @@
|
|||||||
pSinter = pSics->pInter;
|
pSinter = pSics->pInter;
|
||||||
pCon = pSics->pCon[pSics->iStack];
|
pCon = pSics->pCon[pSics->iStack];
|
||||||
lastCommand = pSics->lastUnknown[pSics->iStack];
|
lastCommand = pSics->lastUnknown[pSics->iStack];
|
||||||
|
pCon->sicsError = 0;
|
||||||
|
|
||||||
assert(pSinter);
|
assert(pSinter);
|
||||||
assert(pCon);
|
assert(pCon);
|
||||||
@ -200,6 +201,7 @@
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Tcl_SetVar(pInter,SICSERROR,"yes",TCL_GLOBAL_ONLY);
|
Tcl_SetVar(pInter,SICSERROR,"yes",TCL_GLOBAL_ONLY);
|
||||||
|
pCon->sicsError = 1;
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -948,7 +950,6 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp,
|
|||||||
SCWrite(pCon,pStart,eError);
|
SCWrite(pCon,pStart,eError);
|
||||||
}
|
}
|
||||||
iRet = InterpExecute(pSics,pCon,pCommand);
|
iRet = InterpExecute(pSics,pCon,pCommand);
|
||||||
SicsWait(1);
|
|
||||||
SCWrite(pCon,"TRANSACTIONFINISHED",eError);
|
SCWrite(pCon,"TRANSACTIONFINISHED",eError);
|
||||||
return iRet;
|
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\
|
scan.o fitcenter.o telnet.o token.o wwildcard.o\
|
||||||
tclev.o hkl.o integrate.o optimise.o dynstring.o nxutil.o \
|
tclev.o hkl.o integrate.o optimise.o dynstring.o nxutil.o \
|
||||||
mesure.o uubuffer.o commandlog.o udpquieck.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 \
|
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 \
|
circular.o maximize.o sicscron.o \
|
||||||
d_sign.o d_mod.o tcldrivable.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 \
|
hmcontrol.o userscan.o rs232controller.o lomax.o \
|
||||||
fourlib.o motreg.o motreglist.o anticollider.o \
|
fourlib.o motreg.o motreglist.o anticollider.o \
|
||||||
s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) \
|
s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) \
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
# Markus Zolliker, March 2003
|
# Markus Zolliker, March 2003
|
||||||
#==========================================================================
|
#==========================================================================
|
||||||
# assign if the National Instrument GPIB driver is available
|
# assign if the National Instrument GPIB driver is available
|
||||||
#NI= -DHAVENI
|
NI= -DHAVENI
|
||||||
#NIOBJ= nigpib.o
|
NIOBJ= nigpib.o
|
||||||
#NILIB=$(SINQDIR)/linux/lib/cib.o
|
NILIB=$(SINQDIR)/linux/lib/cib.o
|
||||||
|
|
||||||
# The variable SRC is needed for the case, where source and objects are
|
# 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
|
# separated. In the case where objects are mixed up with sources, SRC
|
||||||
|
129
mesure.c
129
mesure.c
@ -26,14 +26,11 @@
|
|||||||
#include "evcontroller.h"
|
#include "evcontroller.h"
|
||||||
#include "mesure.h"
|
#include "mesure.h"
|
||||||
#include "nxscript.h"
|
#include "nxscript.h"
|
||||||
|
#include "lld.h"
|
||||||
|
|
||||||
extern void SNXFormatTime(char *pBueffel, int iLen);
|
extern void SNXFormatTime(char *pBueffel, int iLen);
|
||||||
#define ANGERR 0.2
|
#define ANGERR 0.2
|
||||||
|
|
||||||
/* nxutil.h
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#define MESSDEBUG 1
|
#define MESSDEBUG 1
|
||||||
|
|
||||||
@ -71,7 +68,16 @@
|
|||||||
float fPosition[4]; /* the real positions after driving */
|
float fPosition[4]; /* the real positions after driving */
|
||||||
int iCompact; /* true if compact scan ouput. */
|
int iCompact; /* true if compact scan ouput. */
|
||||||
int psiMode; /* 1 for psi scan mode, 0 else */
|
int psiMode; /* 1 for psi scan mode, 0 else */
|
||||||
|
int stepList; /* a list of stepwidth ranges */
|
||||||
} Mesure;
|
} Mesure;
|
||||||
|
/*---------------------------------------------------------------------
|
||||||
|
Entries for the stepwidth range list
|
||||||
|
----------------------------------------------------------------------*/
|
||||||
|
typedef struct {
|
||||||
|
float start;
|
||||||
|
float end;
|
||||||
|
float stepWidth;
|
||||||
|
}StepEntry;
|
||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
pMesure CreateMesure(pHKL pCryst, pScanData pScanner, pMotor pOmega,
|
pMesure CreateMesure(pHKL pCryst, pScanData pScanner, pMotor pOmega,
|
||||||
char *pOm, char *po2t, char *pFileRoot,
|
char *pOm, char *po2t, char *pFileRoot,
|
||||||
@ -121,6 +127,7 @@
|
|||||||
pNew->lCounts = (long *)malloc(90*sizeof(long));
|
pNew->lCounts = (long *)malloc(90*sizeof(long));
|
||||||
#endif
|
#endif
|
||||||
pNew->lCounts = (long *)malloc(50*sizeof(long));
|
pNew->lCounts = (long *)malloc(50*sizeof(long));
|
||||||
|
pNew->stepList = LLDcreate(sizeof(StepEntry));
|
||||||
return pNew;
|
return pNew;
|
||||||
}
|
}
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
@ -150,6 +157,7 @@
|
|||||||
MesureClose(self);
|
MesureClose(self);
|
||||||
if(self->lCounts)
|
if(self->lCounts)
|
||||||
free(self->lCounts);
|
free(self->lCounts);
|
||||||
|
LLDdelete(self->stepList);
|
||||||
free(self);
|
free(self);
|
||||||
}
|
}
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
@ -351,12 +359,46 @@
|
|||||||
|
|
||||||
return 1;
|
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,
|
int MesureReflection(pMesure self, float fHKL[3], float fPsi,
|
||||||
SConnection *pCon)
|
SConnection *pCon)
|
||||||
{
|
{
|
||||||
int iRet, i;
|
int iRet, i;
|
||||||
float fStart;
|
float fStart, stepWidth;
|
||||||
float fDelta, fSet[4];
|
float fDelta, fSet[4];
|
||||||
char pBueffel[132];
|
char pBueffel[132];
|
||||||
|
|
||||||
@ -402,19 +444,25 @@
|
|||||||
{
|
{
|
||||||
return iRet;
|
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 */
|
/* set the scan up */
|
||||||
ClearScanVar(self->pScanner);
|
ClearScanVar(self->pScanner);
|
||||||
if(self->iMode == 0)
|
if(self->iMode == 0)
|
||||||
{
|
{
|
||||||
AddScanVar(self->pScanner, pServ->pSics,pCon,self->pCOmega,
|
AddScanVar(self->pScanner, pServ->pSics,pCon,self->pCOmega,
|
||||||
fStart, self->fStep);
|
fStart, stepWidth);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddScanVar(self->pScanner, pServ->pSics,pCon,self->pO2T,
|
AddScanVar(self->pScanner, pServ->pSics,pCon,self->pO2T,
|
||||||
fStart, self->fStep);
|
fStart, stepWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* do the scan */
|
/* do the scan */
|
||||||
@ -435,7 +483,7 @@
|
|||||||
{
|
{
|
||||||
|
|
||||||
int iRet, i;
|
int iRet, i;
|
||||||
float fStart, fDelta;
|
float fStart, fDelta, stepWidth;
|
||||||
char pBueffel[132];
|
char pBueffel[132];
|
||||||
|
|
||||||
assert(self);
|
assert(self);
|
||||||
@ -479,19 +527,25 @@
|
|||||||
{
|
{
|
||||||
return iRet;
|
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 */
|
/* set the scan up */
|
||||||
ClearScanVar(self->pScanner);
|
ClearScanVar(self->pScanner);
|
||||||
if(self->iMode == 0)
|
if(self->iMode == 0)
|
||||||
{
|
{
|
||||||
AddScanVar(self->pScanner, pServ->pSics,pCon,self->pCOmega,
|
AddScanVar(self->pScanner, pServ->pSics,pCon,self->pCOmega,
|
||||||
fStart, self->fStep);
|
fStart, stepWidth);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddScanVar(self->pScanner, pServ->pSics,pCon,self->pO2T,
|
AddScanVar(self->pScanner, pServ->pSics,pCon,self->pO2T,
|
||||||
fStart, self->fStep);
|
fStart, stepWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* do the scan */
|
/* do the scan */
|
||||||
@ -1142,7 +1196,7 @@
|
|||||||
char pBueffel[1024];
|
char pBueffel[1024];
|
||||||
pMesure self = NULL;
|
pMesure self = NULL;
|
||||||
double d;
|
double d;
|
||||||
float fVal, fHKL[3];
|
float fVal, fHKL[3], start, end, step;
|
||||||
|
|
||||||
self = (pMesure)pData;
|
self = (pMesure)pData;
|
||||||
assert(self);
|
assert(self);
|
||||||
@ -1389,6 +1443,55 @@
|
|||||||
return 1;
|
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 */
|
/*------ can be other pars */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
21
motor.c
21
motor.c
@ -271,6 +271,8 @@ static int reportAndFixError(pMotor self, SConnection *pCon)
|
|||||||
newStatus = statusRunTo(self,pCon);
|
newStatus = statusRunTo(self,pCon);
|
||||||
break;
|
break;
|
||||||
case MOTOK:
|
case MOTOK:
|
||||||
|
snprintf(pBueffel,255,"WARNING: %s on %s",pError,self->name);
|
||||||
|
SCWrite(pCon,pBueffel,eWarning);
|
||||||
newStatus = HWIdle;
|
newStatus = HWIdle;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -954,6 +956,21 @@ extern void KillPiPiezo(void *pData);
|
|||||||
*fHard = fVal*ObVal(self->ParArray,SIGN);
|
*fHard = fVal*ObVal(self->ParArray,SIGN);
|
||||||
return 0;
|
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)
|
int MotorGetSoftPosition(pMotor self, SConnection *pCon, float *fVal)
|
||||||
{
|
{
|
||||||
@ -970,7 +987,6 @@ extern void KillPiPiezo(void *pData);
|
|||||||
*fVal = fValue;
|
*fVal = fValue;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* apply zeropoint */
|
/* apply zeropoint */
|
||||||
if(ObVal(self->ParArray,SIGN) < 0.)
|
if(ObVal(self->ParArray,SIGN) < 0.)
|
||||||
{
|
{
|
||||||
@ -983,7 +999,10 @@ extern void KillPiPiezo(void *pData);
|
|||||||
*fVal = fValue;
|
*fVal = fValue;
|
||||||
|
|
||||||
/* apply sign */
|
/* apply sign */
|
||||||
|
/* *fVal = MotorHardToSoftPosition(self,fValue); */
|
||||||
|
|
||||||
*fVal = fValue*ObVal(self->ParArray,SIGN);
|
*fVal = fValue*ObVal(self->ParArray,SIGN);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
1
motor.h
1
motor.h
@ -46,6 +46,7 @@
|
|||||||
/* Where are we ? */
|
/* Where are we ? */
|
||||||
int MotorGetSoftPosition(pMotor self,SConnection *pCon, float *fVal);
|
int MotorGetSoftPosition(pMotor self,SConnection *pCon, float *fVal);
|
||||||
int MotorGetHardPosition(pMotor self,SConnection *pCon, float *fVal);
|
int MotorGetHardPosition(pMotor self,SConnection *pCon, float *fVal);
|
||||||
|
float MotorHardToSoftPosition(pMotor self, float fHard);
|
||||||
|
|
||||||
/* creation */
|
/* creation */
|
||||||
int MotorCreate(SConnection *pCon, SicsInterp *pSics, void *pData,
|
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 <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "fortify.h"
|
|
||||||
#include "napi.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
|
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)
|
NXstatus CALLING_STYLE NXsetcache(long newVal)
|
||||||
{
|
{
|
||||||
if(newVal > 0)
|
if(newVal > 0)
|
||||||
{
|
{
|
||||||
cacheSize = newVal;
|
nx_cacheSize = newVal;
|
||||||
return NX_OK;
|
return NX_OK;
|
||||||
}
|
}
|
||||||
return NX_ERROR;
|
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;
|
NXpData = pData;
|
||||||
NXIReportError = NewError;
|
NXIReportError = NewError;
|
||||||
@ -126,6 +125,7 @@ NXstatus CALLING_STYLE NXsetcache(long newVal)
|
|||||||
NXhandle hdf5_handle;
|
NXhandle hdf5_handle;
|
||||||
NXhandle hdf4_handle;
|
NXhandle hdf4_handle;
|
||||||
pNexusFunction fHandle;
|
pNexusFunction fHandle;
|
||||||
|
NXstatus retstat;
|
||||||
|
|
||||||
/* configure fortify
|
/* configure fortify
|
||||||
iFortifyScope = Fortify_EnterScope();
|
iFortifyScope = Fortify_EnterScope();
|
||||||
@ -165,7 +165,11 @@ NXstatus CALLING_STYLE NXsetcache(long newVal)
|
|||||||
if (hdf_type==1) {
|
if (hdf_type==1) {
|
||||||
/* HDF4 type */
|
/* HDF4 type */
|
||||||
#ifdef HDF4
|
#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->pNexusData=hdf4_handle;
|
||||||
fHandle->nxclose=NX4close;
|
fHandle->nxclose=NX4close;
|
||||||
fHandle->nxflush=NX4flush;
|
fHandle->nxflush=NX4flush;
|
||||||
@ -194,13 +198,21 @@ NXstatus CALLING_STYLE NXsetcache(long newVal)
|
|||||||
fHandle->nxsameID=NX4sameID;
|
fHandle->nxsameID=NX4sameID;
|
||||||
fHandle->nxinitgroupdir=NX4initgroupdir;
|
fHandle->nxinitgroupdir=NX4initgroupdir;
|
||||||
fHandle->nxinitattrdir=NX4initattrdir;
|
fHandle->nxinitattrdir=NX4initattrdir;
|
||||||
#endif
|
|
||||||
*gHandle = fHandle;
|
*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) {
|
} else if (hdf_type==2) {
|
||||||
/* HDF5 type */
|
/* HDF5 type */
|
||||||
#ifdef HDF5
|
#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->pNexusData=hdf5_handle;
|
||||||
fHandle->nxclose=NX5close;
|
fHandle->nxclose=NX5close;
|
||||||
fHandle->nxflush=NX5flush;
|
fHandle->nxflush=NX5flush;
|
||||||
@ -229,11 +241,16 @@ NXstatus CALLING_STYLE NXsetcache(long newVal)
|
|||||||
fHandle->nxsameID=NX5sameID;
|
fHandle->nxsameID=NX5sameID;
|
||||||
fHandle->nxinitgroupdir=NX5initgroupdir;
|
fHandle->nxinitgroupdir=NX5initgroupdir;
|
||||||
fHandle->nxinitattrdir=NX5initattrdir;
|
fHandle->nxinitattrdir=NX5initattrdir;
|
||||||
#endif
|
|
||||||
*gHandle = fHandle;
|
*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 {
|
} else {
|
||||||
NXIReportError (NXpData,"ERROR: Format not readable by this NeXus library");
|
NXIReportError (NXpData,
|
||||||
|
"ERROR: Format not readable by this NeXus library");
|
||||||
*gHandle = NULL;
|
*gHandle = NULL;
|
||||||
return NX_ERROR;
|
return NX_ERROR;
|
||||||
}
|
}
|
||||||
@ -539,6 +556,229 @@ NXstatus CALLING_STYLE NXsetcache(long newVal)
|
|||||||
pNexusFunction pFunc = (pNexusFunction)fid;
|
pNexusFunction pFunc = (pNexusFunction)fid;
|
||||||
return pFunc->nxinitgroupdir(pFunc->pNexusData);
|
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
|
F77 - API - Support - Routines
|
||||||
----------------------------------------------------------------------*/
|
----------------------------------------------------------------------*/
|
||||||
|
11
napi.h
11
napi.h
@ -21,13 +21,15 @@
|
|||||||
|
|
||||||
For further information, see <http://www.neutron.anl.gov/NeXus/>
|
For further information, see <http://www.neutron.anl.gov/NeXus/>
|
||||||
|
|
||||||
|
$Id: napi.h,v 1.7 2004/11/17 10:50:16 cvs Exp $
|
||||||
|
|
||||||
----------------------------------------------------------------------------*/
|
----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#ifndef NEXUSAPI
|
#ifndef NEXUSAPI
|
||||||
#define NEXUSAPI
|
#define NEXUSAPI
|
||||||
|
|
||||||
/* NeXus HDF45 */
|
/* NeXus HDF45 */
|
||||||
#define NEXUS_VERSION "2.0.0." /* major.minor.patch */
|
#define NEXUS_VERSION "2.1.0" /* major.minor.patch */
|
||||||
|
|
||||||
#define CONSTCHAR const char
|
#define CONSTCHAR const char
|
||||||
|
|
||||||
@ -78,6 +80,7 @@ typedef struct {
|
|||||||
NX_INT32 32 bit integer
|
NX_INT32 32 bit integer
|
||||||
NX_UINT32 32 bit unsigned integer
|
NX_UINT32 32 bit unsigned integer
|
||||||
NX_CHAR 8 bit character
|
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_INT32 24
|
||||||
#define NX_UINT32 25
|
#define NX_UINT32 25
|
||||||
#define NX_CHAR 4
|
#define NX_CHAR 4
|
||||||
|
#define NX_BINARY 21
|
||||||
|
|
||||||
/* Map NeXus compression methods to HDF compression methods */
|
/* Map NeXus compression methods to HDF compression methods */
|
||||||
#define NX_COMP_NONE 100
|
#define NX_COMP_NONE 100
|
||||||
@ -141,6 +145,7 @@ typedef struct {
|
|||||||
# define NXclose MANGLE(nxiclose)
|
# define NXclose MANGLE(nxiclose)
|
||||||
# define NXmakegroup MANGLE(nximakegroup)
|
# define NXmakegroup MANGLE(nximakegroup)
|
||||||
# define NXopengroup MANGLE(nxiopengroup)
|
# define NXopengroup MANGLE(nxiopengroup)
|
||||||
|
# define NXopenpath MANGLE(nxiopenpath)
|
||||||
# define NXclosegroup MANGLE(nxiclosegroup)
|
# define NXclosegroup MANGLE(nxiclosegroup)
|
||||||
# define NXmakedata MANGLE(nximakedata)
|
# define NXmakedata MANGLE(nximakedata)
|
||||||
# define NXcompmakedata MANGLE(nxicompmakedata)
|
# define NXcompmakedata MANGLE(nxicompmakedata)
|
||||||
@ -211,6 +216,7 @@ typedef struct {
|
|||||||
# define NXflush MANGLE(NXIFLUSH)
|
# define NXflush MANGLE(NXIFLUSH)
|
||||||
# define NXmakegroup MANGLE(NXIMAKEGROUP)
|
# define NXmakegroup MANGLE(NXIMAKEGROUP)
|
||||||
# define NXopengroup MANGLE(NXIOPENGROUP)
|
# define NXopengroup MANGLE(NXIOPENGROUP)
|
||||||
|
# define NXopenpath MANGLE(NXIOPENPATH)
|
||||||
# define NXclosegroup MANGLE(NXICLOSEGROUP)
|
# define NXclosegroup MANGLE(NXICLOSEGROUP)
|
||||||
# define NXmakedata MANGLE(NXIMAKEDATA)
|
# define NXmakedata MANGLE(NXIMAKEDATA)
|
||||||
# define NXcompress MANGLE(NXICOMPRESS)
|
# 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 NXmakegroup (NXhandle handle, CONSTCHAR *name, char* NXclass);
|
||||||
NX_EXTERNAL NXstatus CALLING_STYLE NXopengroup (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 NXclosegroup(NXhandle handle);
|
||||||
|
|
||||||
NX_EXTERNAL NXstatus CALLING_STYLE NXmakedata (NXhandle handle, CONSTCHAR* label, int datatype, int rank, int dim[]);
|
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
|
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 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
|
another special function for setting the default cache size for HDF-5
|
||||||
|
@ -472,7 +472,7 @@ int NETReadTillTermNew(mkChannel *self, int timeout,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
maxTime = time(NULL) + (time_t)ceil((double)timeout/1000);
|
maxTime = time(NULL) + (time_t)ceil((double)timeout/1000 +1);
|
||||||
length = strlen(pTerm);
|
length = strlen(pTerm);
|
||||||
memset(pBuffer,0,iBufLen);
|
memset(pBuffer,0,iBufLen);
|
||||||
|
|
||||||
@ -503,6 +503,8 @@ int NETReadTillTermNew(mkChannel *self, int timeout,
|
|||||||
}
|
}
|
||||||
pBuffer[bufPtr] = c;
|
pBuffer[bufPtr] = c;
|
||||||
bufPtr++;
|
bufPtr++;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
wait for more data
|
wait for more data
|
||||||
|
1
nread.c
1
nread.c
@ -321,6 +321,7 @@ extern VerifyChannel(mkChannel *self); /* defined in network.c */
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
pEnd++;
|
pEnd++;
|
||||||
|
pPtr = pEnd;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -856,6 +856,7 @@ static void makeLink(SConnection *pCon, SicsInterp *pSics,
|
|||||||
pNXScript self,
|
pNXScript self,
|
||||||
int argc, char *argv[]){
|
int argc, char *argv[]){
|
||||||
int status;
|
int status;
|
||||||
|
char pBueffel[256];
|
||||||
|
|
||||||
if(argc < 4){
|
if(argc < 4){
|
||||||
SCWrite(pCon,"ERROR: insufficient number of arguments to makelink",
|
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,
|
status = NXDaliaslink(self->fileHandle, self->dictHandle,
|
||||||
argv[2],argv[3]);
|
argv[2],argv[3]);
|
||||||
if(status != NX_OK){
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
13
ofac.c
13
ofac.c
@ -104,6 +104,9 @@
|
|||||||
#include "help.h"
|
#include "help.h"
|
||||||
#include "site.h"
|
#include "site.h"
|
||||||
#include "nxupdate.h"
|
#include "nxupdate.h"
|
||||||
|
#include "confvirtmot.h"
|
||||||
|
#include "exeman.h"
|
||||||
|
#include "oscillate.h"
|
||||||
/*----------------------- Server options creation -------------------------*/
|
/*----------------------- Server options creation -------------------------*/
|
||||||
static int IFServerOption(SConnection *pCon, SicsInterp *pSics, void *pData,
|
static int IFServerOption(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||||
int argc, char *argv[])
|
int argc, char *argv[])
|
||||||
@ -279,6 +282,13 @@
|
|||||||
AddCommand(pInter,"DrivableInvoke", TclDrivableInvoke,NULL,NULL);
|
AddCommand(pInter,"DrivableInvoke", TclDrivableInvoke,NULL,NULL);
|
||||||
AddCommand(pInter,"UpdateFactory",UpdateFactory,NULL,NULL);
|
AddCommand(pInter,"UpdateFactory",UpdateFactory,NULL,NULL);
|
||||||
AddCommand(pInter,"allowexec",AllowExec,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
|
install site specific commands
|
||||||
@ -335,6 +345,9 @@
|
|||||||
RemoveCommand(pSics,"MakeTclInt");
|
RemoveCommand(pSics,"MakeTclInt");
|
||||||
RemoveCommand(pSics,"UpdateFactory");
|
RemoveCommand(pSics,"UpdateFactory");
|
||||||
RemoveCommand(pSics,"allowexec");
|
RemoveCommand(pSics,"allowexec");
|
||||||
|
RemoveCommand(pSics,"MakeConfigurableMotor");
|
||||||
|
RemoveCommand(pSics,"MakeBatchManager");
|
||||||
|
RemoveCommand(pSics,"MakeOscillator");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
remove site specific installation commands
|
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)
|
else if(iRet == -1)
|
||||||
{
|
{
|
||||||
|
printf("Incomplete read: %s\n", (char *)data);
|
||||||
return INCOMPLETE;
|
return INCOMPLETE;
|
||||||
}
|
}
|
||||||
*datalen = strlen((char *)data);
|
*datalen = strlen((char *)data);
|
||||||
@ -592,7 +593,7 @@ int RS232Action(SConnection *pCon, SicsInterp *pSics,
|
|||||||
}
|
}
|
||||||
else if(strcmp(argv[1],"timeout") == 0)
|
else if(strcmp(argv[1],"timeout") == 0)
|
||||||
{
|
{
|
||||||
if(checkSet(pCon,argc,usMugger))
|
if(checkSet(pCon,argc,usUser))
|
||||||
{
|
{
|
||||||
setRS232Timeout(self,atoi(argv[2]));
|
setRS232Timeout(self,atoi(argv[2]));
|
||||||
SCSendOK(pCon);
|
SCSendOK(pCon);
|
||||||
|
2
scan.c
2
scan.c
@ -290,6 +290,8 @@ static char *fixExtension(char *filename)
|
|||||||
self->lPos = ftell(self->fd);
|
self->lPos = ftell(self->fd);
|
||||||
|
|
||||||
fclose(fd);
|
fclose(fd);
|
||||||
|
fclose(self->fd);
|
||||||
|
self->fd = NULL;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
|
Reference in New Issue
Block a user