- 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:
cvs
2004-11-17 10:50:15 +00:00
parent f7c8ae30c6
commit 0f4e959e22
46 changed files with 3675 additions and 834 deletions

21
confvirtmot.h Normal file
View 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
View 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
View 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
View 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
@}

View File

@ -837,7 +837,7 @@ static void writeToLogFiles(SConnection *self, char *buffer)
This version writes only to configured log files but not to sockets.
Used for automatic file execution for the WWW interface
*/
static int SCFileWrite(SConnection *self, char *buffer, int iOut)
int SCFileWrite(SConnection *self, char *buffer, int iOut)
{
int i, iPtr, iRet;
char pBueffel[80];
@ -1557,6 +1557,54 @@ static void writeToLogFiles(SConnection *self, char *buffer)
}
return 1;
}
/*----------------------------------------------------------------------*/
int SCUnregisterID(SConnection *pCon, long ID)
{
int iRet;
Item sItem;
if(!VerifyConnection(pCon))
{
return 0;
}
iRet = LLDnodePtr2First(pCon->iList);
while(iRet != 0)
{
LLDnodeDataTo(pCon->iList,&sItem);
if(sItem.lID == ID )
{
LLDnodeDelete(pCon->iList);
LLDnodePtr2Prev(pCon->iList);
}
iRet = LLDnodePtr2Next(pCon->iList);
}
return 1;
}
/*----------------------------------------------------------------------*/
long SCgetCallbackID(SConnection *pCon, void *pData)
{
int iRet;
Item sItem;
pICallBack pInter;
if(!VerifyConnection(pCon))
{
return 0;
}
pInter = (pICallBack)pData;
iRet = LLDnodePtr2First(pCon->iList);
while(iRet != 0)
{
LLDnodeDataTo(pCon->iList,&sItem);
if(sItem.pInterface == pInter)
{
return sItem.lID;
}
iRet = LLDnodePtr2Next(pCon->iList);
}
return -1;
}
/*---------------------- The callback data structure --------------------*/
typedef struct {
SConnection *pCon;
@ -1656,7 +1704,8 @@ static void writeToLogFiles(SConnection *self, char *buffer)
/* get CallBack interface */
pDum = (pDummy)pCom->pData;
assert(pDum);
pInterface = (pICallBack)pDum->pDescriptor->GetInterface(pDum,CALLBACKINTERFACE);
pInterface = (pICallBack)pDum->pDescriptor->GetInterface(pDum,
CALLBACKINTERFACE);
if(!pInterface)
{
sprintf(pBueffel,"ERROR: %s does not support CallBacks",
@ -1772,7 +1821,7 @@ static void writeToLogFiles(SConnection *self, char *buffer)
else
{
SCWrite(self,"ERROR: Bad login",eError);
printf("Bad login string %s\n", pPtr);
}
}
free(pPtr);

View File

@ -53,6 +53,7 @@ typedef int (*writeFunc)(struct __SConnection *pCon,
int iGrab;
int iErrCode;
int parameterChange;
int sicsError;
SicsInterp *pSics;
/* a FIFO */
@ -96,11 +97,23 @@ typedef int (*writeFunc)(struct __SConnection *pCon,
writeFunc SCGetWriteFunc(SConnection *pCon);
void SCSetWriteFunc(SConnection *pCon, writeFunc x);
int SCOnlySockWrite(SConnection *self, char *buffer, int iOut);
int SCFileWrite(SConnection *self, char *buffer, int iOut);
int SCNotWrite(SConnection *self, char *buffer, int iOut);
/************************* CallBack *********************************** */
int SCRegister(SConnection *pCon, SicsInterp *pSics,
void *pInter, long lID);
int SCUnregister(SConnection *pCon, void *pInter);
/**
* delete a callback with the given ID
*/
int SCUnregisterID(SConnection *pCon, long ID);
/**
* retrieve the ID of a callback on the callback interface
* given in pData. This, together with SCUnregisterID allows to
* ceanly remove all callbacks on a connection
* returns -1 if no ID can be found.
*/
long SCgetCallbackID(SConnection *pCon, void *pData);
/******************************* Error **************************************/
void SCSetInterrupt(SConnection *self, int eCode);
int SCGetInterrupt(SConnection *self);

View File

@ -12,6 +12,9 @@ initialisation file. Such special commands are described here.
<DL>
<DT>MakeRuenBuffer
<DD>MakeRuenBuffer makes the R&#252;nBuffer system available.
<dt>MakeBatchManager [name]
<DD>Installs the new batch buffer management system. If no name is
given, the default will be exe.
<DT>MakeDrive
<DD>MakeDrive craetes the drive command.
<DT>MakeScanCommand name countername headfile recoverfil

View File

@ -28,25 +28,33 @@ Author: Mark K\"onnecke
This document gives an overview about all the hardware and software systems
involved in SINQ instrument control. It describes the relationships between
the various pieces and points to additional documentation, if available.
A copy of all documents referred in this paper is stored at: /data/lnslib/distribution/sics/doclib. If they exist in electronic form, this is. The SICS user
and manager information is available on the WWW starting from http://lns00.psi.ch/.
A copy of all documents referred in this paper is stored at:
/afs/psi.ch/project/sinq/commmon/share/sicsdoc.
If they exist in electronic form, this is. The SICS user
and manager information is available on the WWW starting from
http://lns00.psi.ch/.
\section{Hardware Overview}
For each SINQ instrument the following computing hardware is available:
\begin{itemize}
\item A dedicated instrument workstation. Most of them are Compaq Alpha stations
running True64Unix. One workstation is still running OpenVMS. Two instruments,
POLDI and RITA--2, are controlled through Intel--PC's running Linux.
\item A dedicated instrument workstation. Most of them are Intel x86
machines running Linux. Three instruments use alpha workstations
running Tru64Unix.
\item A TCP/IP terminal server providing access to serial ports.
\item Optionally, there are 1-3 histogram memory computers installed for those
instruments which have area detectors. These histogram memory computers are
Motorolla 6800 VME board processors running the vxWorks realtime
operating system.
operating system. Two types of boards are in use: the older Motorolla
MVME1603 boards with 16 MB of memory and MEN-A12 boards with 512MB
memory.
\item Optionally there are National Instruments ENET-100 GPIB/TCPIP
converters in use in order to access GPIB devices, especially those
which came with the Risoe instruments.
\end{itemize}
Most instrument hardware is accessed through RS--232 interfaces and the terminal
server. Histogram memories are accessed through the TCP/IP network. Generally
ethernet is used as the main instrument bus.
Most instrument hardware is accessed through RS--232 interfaces and
the terminal server. Histogram memories are accessed through the
TCP/IP network . Generally ethernet is used as the main instrument bus.
In addition to the computers at the instrument the following systems are
available:
@ -54,8 +62,9 @@ In addition to the computers at the instrument the following systems are
\item A True64Unix laboratory server (lnsa15) for data management and
primary data anlalysis.
\item True64Unix PSI server systems for data processing.
\item A dual processor linux science server (lnsl15).
\item The PSI Linux Login cluster (llc)
\item A WWW--server currently installed on lns00.
\item pss123 is a Sun workstation holding the vxWorks development environment.
\end{itemize}
\section{Software Overview}
@ -75,7 +84,8 @@ The main software component at the instrument is the Sinq Instrument Control
debugging. Clients to this SerPortServer such as the SICS server communicate
with the server through a special ASCII protocoll transported through TCP/IP.
The only documentation
for both the SerPortServer and the ASCII protocoll is the source code.
for both the SerPortServer and the ASCII protocoll is the source
code. And David Maden.
There exists another support program, the FileSync server, on any instrument
computer. This is a little Java server which listens at a UDP port for a
@ -88,8 +98,8 @@ Then there is the TecsServer. This is a server which maintains and configures
Lakeshore temperature controllers used as standard temperature controllers
at SINQ. The only documentation for this program is Markus Zolliker.
On many instruments there are histogram memory computers. These usually run the
following programs:
On many instruments there are histogram memory computers. These
usually run the following programs:
\begin{description}
\item[bootUtil] a utility running when the histogram memory is booted which
starts all the other tasks and configures the histogram memory from its
@ -114,30 +124,22 @@ The SICS software is described in a variety of documentation:
described in the "SICS Manager Manual".
\item The programming concepts of SICS are discussed in the "SICS Programmers
Reference".
\item An 90\% complete description of SICS source code modules is available
\item An 97\% complete description of SICS source code modules is available
as "SICS Reference Manual".
\end{itemize}
One instrument, TASP, is run with the TASMAD software from ILL which runs
on VMS systems. A user documentation for this system is available at: \newline
\centerline{http://sinq.web.psi.ch/sinq/doc/tasmad.html}
Some configuration issues are explained in this docuement as well. Further
documentation exists only in form of David Maden and an analysis of the
source code.
The RITA--2 instrument from Ris\o{ } runs the TASCOM software.
This software is quite well documented in various documents which can be
obtained at WHGA/247 or directly from the Ris\o{ } team and Per Skarup.
obtained at WHGA/112 or directly from the Ris\o{ } team and Per Skarup.
\subsection{Facilities at the Laboratory Server(LNSA15)}
\subsection{Central Facilities}
\subsubsection{Central Data Repository}
Under the /data/lnslib/data directory there exists a central storage area for
Under the /afs/psi.ch/project/sinqdata directory there exists a
central storage area for
data files measured at the instruments. Newly measured data files are
automatically mirrored to this area once a measurement has finished.
Not surprisingly there is a subdirectory for each instrument at SINQ.
These instrument directories contain further subdirectories for each year
of SINQ operation which hold the actual data files.
There are directories for each year of SINQ operation. These contain
subdirectories for the various instruments.
\subsubsection{The SINQ File Database}
Right early on it was decided to separate the file archival function from the
@ -155,20 +157,15 @@ which is part of the source distribution for the system. Here only an
The SINQ File Database consists of the following components:
\begin{itemize}
\item The database itself. This is the SQL database system mSQL from
Hughes Technology.
\item Any night the unix utility cron starts a shell script which is
responsible for updating the database. This is done with two special
utility programs:
\begin{itemize}
\item nx\_dbupdate scans a given directory for new files which are not
yet in the database. If such a file is found, the data fields for the
database are extracted and entered into the database.
\item The Java program ScanScan does the same job as nx\_dbupdate for
ASCII files.
\end{itemize}
\item The database itself. The database is installed on the central
database server PSIP0 provided by central computing. The database
software is oracle.
\item Any night a database update program is started as a cron
job. This programs runs on the linux server lnsl15. The program
itself is a tcl script which uses oratcl for accessing the Oracle
database server and nxinter for accessing NeXus files.
\item A querying system. Curently the only query interface is a WWW--interface
installed at the WWW--server.
installed at the WWW--server lns00.
\end{itemize}
@ -189,28 +186,19 @@ This document also explains how to get hold the source code for most
of the software used at SINQ.
\subsubsection{Backup}
The laboratory server is also the central backup server for SINQ. Backups are
performed with the Legato networker software onto a tape jukebox holding
5 tapes with 20GB capacity each. Currently only the /home (holding
user home directories) and the /lnsarchive hierarchy are backed up.
This backup system is a protection against a major harddisk failure. It is no
archive system. Though backup tapes are held as long as possible it
cannot be guaranteed that files older then half a year can be recovered.
The backup software is described in the documentation coming with the
system. No further documentation exists, but the setup can be viewed
through the nwadmin application.
Most user files and the raw data is stored within the AFS network file
system. These files are backed up by central computing. Data files of
older years are additionally archived in the PSI archive system.
The instrument accounts on the instrument computers must be backed up
as well because they sometimes contain valuable scripts. Unfortunately
there are not enough Networker licenses to go round and there is no
reliable linux client software for our version of Legato Networker.
Therefore the data in the instrument accounts is copied nightly to a
special account on lnsa15 which is subjected to the normal
backup. More details:
The instrument and guest accounts on the instrument computers should
be backed up
too because they sometimes contain valuable scripts. These are local
accounts, thus they are not covered through the AFS backup. Data from
these accounts is synchronized nightly onto a special account on the
linux server lnsl15.
\begin{itemize}
\item There is a script which does the copying. It is {\bf backupinst}
in either /data/lnslib/bin or
/afs/.psi.ch/project/sinq/linux/bin. This script is called with {\bf
in /afs/.psi.ch/project/sinq/linux/bin. This script is called with {\bf
backupinst INST} where INST must be replaced by the instrument name in
capitals. This script essentially calls rsync with appropriate
arguments to synchronize the instrument account minus the data
@ -221,8 +209,8 @@ instrument computer must have an entry in crontab reading like:
0 3 * * * /data/lnslib/bin/backupinst TOPSI >/tmp/topsi.log 2>&1
\end{verbatim}
Please replace paths and instrument names to match the instrument.
\item The backup account on lnsa15 is named SINQINST, password:
333SINQINST555. It contains a directory for each supported
\item The backup account on lnsl15 is named SINQINST, password:
SINQINSTLNS. It contains a directory for each supported
instruments. For backupinst to work properly there must be a line in
the .rhosts file of this account for each instrument computer which
reads:
@ -237,16 +225,12 @@ linux instrument computers, not the DNS alias.
At SINQ the PSI EL--734 motor controllers are used. These motor controllers
hold a set of parameters for each motor. As a safeguard against instrument
scientists gone wild or a loss of parameters due some electronic or
electrical incident these motor parameters are saved weekly. This happens
on wednesdays mornings. The unix utility crom triggers the process and
starts the script savemot which in turn does all necessary things. The
actual saving of the motor parameters is accomplished with David Maden's
el734 program. The saved parameters end up in the /data/lnslib/motors
hierarchy. There exists a directory for each backup date which in turn
holds a subdirectory for each instrument which holds the files with
the saved parameters. All necessary shell scripts and programs can be
found in the /data/lnslib/motors/bin directory.
electrical incident these motor parameters should be saved
regularly. To this purpose there exits motor subdirectories in each
instrument account. Motors are either saved into this directory
through a script in this directory or from SICS (TASP,
MORPHEUS). Motor parameter backup is a responsability of the
instrument scientists and must be triggered manually.
\subsubsection{License Server}
Unfortunately some people use the proprietary IDL programming system. This
@ -275,19 +259,18 @@ Unfortunately some people use the proprietary IDL programming system. This
\subsection{Software at the WWW--server}
The WWW--server running at lns00 does not provide static information only but also
active content calculated at runtime. The following services are
implemented:
The WWW--server running at lns00 does not provide static information
only but also active content calculated at runtime. The following
services are implemented:
\begin{itemize}
\item Keyword search in the SICS documentation.
\item Searching the SINQ file database for files matching various criteria.
\item Display of the current instrument status for a couple of instruments.
\item Display of the current instrument status for most instruments.
\item An experimental WWW control system for powder diffractometers.
\end{itemize}
Most of these services are provided through java servlets. In order to do this
a servlet engine was needed. The combination Apache WWW-server and Apache
JServ was choosen. However, it is planned to exchange the latter component
by the Jakarta engine in the near future.
Jakarta Tomcat was choosen.
The database search servlets are described in more detail in the document:
\newline \centerline{The SINQ File Database}
@ -299,8 +282,7 @@ The SICS documentation searching system is built on top of the program SWISH-E w
from http://sunsite.berkeley.edu/SWISH-E.
The actual search is performed through a TCL--cgi script which calls the swishe
application with appropriate parameters. This script can be found as
swishsearch.cgi together with a batch file to start it properly
(swishsearch.bat) in the cgi-bin directory of the WWW hierarchy on lns00.
swishsearch.cgi in the cgi-bin directory of the WWW hierarchy on lns00.
Prerequisite for such a search is the existence of an index file. This must
be created offline after any major change to the documentation. In order to
create this index, cd into the sics directory of the WWW hierarchy and run:
@ -321,12 +303,12 @@ In order to understand the system better it is useful to look at the flow
\begin{enumerate}
\item Data Files are generated by the instrument control programs at the
instrument computer.
\item Data Files are automatically mirrored to the central repository
on the laboratory server lnsa15. This happens through the FileSync server,
a shell script and last not least the unix rsync utility. All this is installed
at the instrument computer.
\item Data Files are automatically mirrored to the central AFS
repository. This happens through the FileSync server,
a shell script and last not least the unix rsync utility. All this is
installed at the instrument computer.
\item Nightly new files are scanned for relevant information and their
characteristics are entered into the database system on lnsa15.
characteristics are entered into the database system from lnsl15.
\end{enumerate}
@ -341,7 +323,7 @@ The SICS Java clients access the SICS servers on the selected instruments
laboratory server lnsa15.
\subsection{WWW Services}
The file search service on the WWW--server lns00 accesses the database
server running on the laboratory server lnsa15.
server PSIP0.
The instrument status display servlets on the WWW--server lns00 access the
SICS instrument control servers on the appropriate instrument computers
@ -349,9 +331,6 @@ The instrument status display servlets on the WWW--server lns00 access the
\section{Maintainance Tasks}
\subsection{Yearly Maintainance}
The only maintainance task at SINQ shutdown is to disable the cron job on
lnsa15 which performs the motor parameter backup.
Whith each new year a couple of things must be done in order to keep the
system ship shape:
@ -369,13 +348,10 @@ Whith each new year a couple of things must be done in order to keep the
\end{itemize}
\item On the laboratory server lnsa15:
\begin{itemize}
\item Reenable the motor parameter backup cron job.
\item Create new subdirectories for the new year in the data hierarchy.
\item In /data/lnslib/lib/nxdb create new configuration files for the new
year. Edit them to point to the new years subdirectory. Edit the
updatenxdb shell script to use the newly created configuration files.
Keep the old ones as they may come in handy if the whole database may
require an update.
\item Create a new year hierarchy for the new year.
\item Store the old years data into the PSI archive.
\item Move the old years data into the non backed up AFS area.
\item Make the new year the backed up data on AFS.
\end{itemize}
\item On the WWW--server lns00:
\begin{itemize}
@ -391,10 +367,14 @@ Do these things quite early on in the year. People start measuring background
In order to keep up with ageing 1-2 computers have to be exchanged any year.
A instrument computer change requires the following adaptions:
\begin{enumerate}
\item Start with a PC with the PSI Linux distribution installed.
\item Create two local user accounts: INST and instlnsg.
\item Copy the SICS software to the instrument computer.
\item Edit the instrument configuration file and change all occurences of
the old computers name to the new name.
\item On lnsa15 as user lnslib: enter the new computer name into the
.rhosts file. This is required for the mirroring to work.
\item Install the cron job for backing up the local instrument
accounts.
\item Make an entry in the .rhosts file of the SINQINST account on lnsl15.
\item For the Java clients edit lnet/SINQConfig.java to point to the
new computer and rebuild all clients. Redistribute them as well.
\item For the WWW status, adapt the sics.conf file on lns00 and restart

59
doc/user/exeman.html Normal file
View 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>

View File

@ -14,23 +14,7 @@ to be solved are:
<li>Measure a couple of reflections.
<li>Furthermore there are some specialities.
</ul>
There are two ways to achieve all this:
The older way uses some built in SICS functionality plus some external
programs inherited from the ILL. This is called the ILL operation.
Then a complete
four circle package called DIFRAC from P. White and Eric Gabe was
integrated into SICS.
This is The Difrac way of operation.
</p>
<h2>DIFRAC</h2>
<p>
The DIFRAC commands are accessed by prepending the difrac commands
with <b>dif</b>. For example: "dif td" calls the difrac td
command. For more information on DIFRAC commands see the separate
<a href="diftrics.htm">DIFRAC manual</a>.
</p>
<h2>ILL operation</h2>
<h3>Locate Reflections</h3>
<p>
If you know x-ray single crystal diffractometers you'll expect sophisticated

View File

@ -26,7 +26,23 @@ Two special commands have been defined for TRICS with a PSD:
<dd>reads reflection HKL values from file filename and performs
tricsscans for each reflection. These will be done eith step width
step, the number of steps np with counting mode mode and a preset of
preset. These parameters have the same meaning as described above.
preset. These parameters have the same meaning as described above. If the
{\bf hkl nb 1} command has been given before the invocation of this scan,
reflections will be searched in normal beam geometry. psdrefscan, however,
will only print the normal four circle angles, though.
<dt>detscan start step np mode preset
<dd>Detscan performs a scan in two theta. This may be useful for detector
calibrations. Arguments as described above.
<dt>phscan start step np mode preset
<dd>Phscan performs a scan in phi. This can be usefule for orienting a
crystal. Arguments as described above.
<dt>o2tscan2d start step np mode preset
<dd>O2tscan2d performs a omega - two-theta scan with the PSD.
Arguments as described above.
<dt>hklscan2d
<dd> For a scan in reciprocal space with the PSD, see the
documentation for <a href="hklscan.htm">hklscan</a>. Please note that
for a PSD HKL scan, all commans have to start with hklscan2d.
</dl>
</P>

View File

@ -60,6 +60,9 @@
"COUNTEND",
"FILELOADED",
"MOTEND",
"BATCHSTART",
"BATCHAREA",
"BATCHEND",
NULL
};

13
event.h
View File

@ -1,5 +1,5 @@
#line 79 "event.w"
#line 85 "event.w"
/*----------------------------------------------------------------------------
E V E N T
@ -18,7 +18,7 @@
int Text2Event(char *pText);
#line 92 "event.w"
#line 98 "event.w"
@ -38,19 +38,22 @@
#define COUNTEND 11
#define FILELOADED 12
#define MOTEND 13
#define BATCHSTART 14
#define BATCHAREA 15
#define BATCHEND 16
#line 94 "event.w"
#line 100 "event.w"
/*--------------- Signals for the Signalfunction of each task ------------*/
#line 64 "event.w"
#line 70 "event.w"
#define SICSINT 300
#define SICSBROADCAST 301
#define TOKENGRAB 302
#define TOKENRELEASE 303
#line 97 "event.w"
#line 103 "event.w"
#endif

View File

@ -1,13 +1,3 @@
\newcommand{\NWtarget}[2]{#2}
\newcommand{\NWlink}[2]{#2}
\newcommand{\NWtxtMacroDefBy}{Macro defined by}
\newcommand{\NWtxtMacroRefIn}{Macro referenced in}
\newcommand{\NWtxtMacroNoRef}{Macro never referenced}
\newcommand{\NWtxtDefBy}{Defined by}
\newcommand{\NWtxtRefIn}{Referenced in}
\newcommand{\NWtxtNoRef}{Not referenced}
\newcommand{\NWtxtFileDefBy}{File defined by}
\newcommand{\NWsep}{${\diamond}$}
\subsection{SICS Events}
This section lists the callback events known to Sics, their purpose, and
their associated event datastructures when applicable. See the
@ -22,17 +12,17 @@ This module defines several event related functions as well.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle\,$eFunc\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$
$\langle$eFunc {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ int Text2Event(char *pText);@\\
\mbox{}\verb@@{\NWsep}
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item \NWtxtMacroRefIn\ \NWlink{nuweb?}{?}.
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
@ -41,7 +31,7 @@ if the event code is not known, else the apropriate event code.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle\,$VE\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$
$\langle$VE {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
@ -59,12 +49,15 @@ $\langle\,$VE\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$
\mbox{}\verb@#define COUNTEND 11@\\
\mbox{}\verb@#define FILELOADED 12@\\
\mbox{}\verb@#define MOTEND 13@\\
\mbox{}\verb@@{\NWsep}
\mbox{}\verb@#define BATCHSTART 14@\\
\mbox{}\verb@#define BATCHAREA 15@\\
\mbox{}\verb@#define BATCHEND 16@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item \NWtxtMacroRefIn\ \NWlink{nuweb?}{?}.
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
@ -88,6 +81,9 @@ fiffractometer has been measured.
operation.
\item[COUNTEND] is an event signalling the end of a counting operation.
\item[MOTEND] signals the end of a driving operation.
\item[BATCHSTART] signals starting batch processing a new buffer
\item[BATCHAREA] signals that a new area of the batch file is processing.
\item[BATCHEND] signals the end of the batch buffers processing.
\end{description}
Furthermore event contains system wide signal codes which are interpreted in
@ -98,7 +94,7 @@ possible codes are defined.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
$\langle\,$VSIG\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$
$\langle$VSIG {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
@ -106,12 +102,12 @@ $\langle\,$VSIG\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$
\mbox{}\verb@#define SICSBROADCAST 301@\\
\mbox{}\verb@#define TOKENGRAB 302@\\
\mbox{}\verb@#define TOKENRELEASE 303@\\
\mbox{}\verb@@{\NWsep}
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item \NWtxtMacroRefIn\ \NWlink{nuweb?}{?}.
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
@ -126,7 +122,7 @@ data is the string to send.
\end{description}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap4}
\verb@"event.h"@\nobreak\ {\footnotesize \NWtarget{nuweb?}{?} }$\equiv$
\verb@"event.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
@ -142,14 +138,14 @@ data is the string to send.
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSEVENT@\\
\mbox{}\verb@#define SICSEVENT@\\
\mbox{}\verb@@\hbox{$\langle\,$eFunc\nobreak\ {\footnotesize \NWlink{nuweb?}{?}}$\,\rangle$}\verb@@\\
\mbox{}\verb@@$\langle$eFunc {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@@\hbox{$\langle\,$VE\nobreak\ {\footnotesize \NWlink{nuweb?}{?}}$\,\rangle$}\verb@@\\
\mbox{}\verb@@$\langle$VE {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------- Signals for the Signalfunction of each task ------------*/@\\
\mbox{}\verb@@\hbox{$\langle\,$VSIG\nobreak\ {\footnotesize \NWlink{nuweb?}{?}}$\,\rangle$}\verb@ @\\
\mbox{}\verb@@$\langle$VSIG {\footnotesize ?}$\rangle$\verb@ @\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@{\NWsep}
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]

View File

@ -32,6 +32,9 @@ if the event code is not known, else the apropriate event code.
#define COUNTEND 11
#define FILELOADED 12
#define MOTEND 13
#define BATCHSTART 14
#define BATCHAREA 15
#define BATCHEND 16
@}
\begin{description}
\item[VALUECHANGE] This is a variable changing its value. As event data a pointer to the
@ -53,6 +56,9 @@ fiffractometer has been measured.
operation.
\item[COUNTEND] is an event signalling the end of a counting operation.
\item[MOTEND] signals the end of a driving operation.
\item[BATCHSTART] signals starting batch processing a new buffer
\item[BATCHAREA] signals that a new area of the batch file is processing.
\item[BATCHEND] signals the end of the batch buffers processing.
\end{description}
Furthermore event contains system wide signal codes which are interpreted in

221
exe.w Normal file
View 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
View 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
View 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
View 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
View 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
View 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

View File

@ -109,13 +109,9 @@
pMot = FindMotor(pServ->pSics,self->pName);
if(pMot)
{
i = MotorGetPar(pMot,"softzero",&fZero);
i = MotorGetPar(pMot,"sign",&fSign);
assert(i);
for(i = 0; i < self->iNP; i++)
{
self->fAxis[i] -= fZero;
self->fAxis[i] *= fSign;
self->fAxis[i] = MotorHardToSoftPosition(pMot,self->fAxis[i]);
}
}
}
@ -349,7 +345,8 @@
SCWrite(pCon,"Driving to center done",eStatus);
break;
default:
SCWrite(pCon,"WARNING: driving to center finished with problems",
SCWrite(pCon,
"WARNING: driving to center finished with problems",
eWarning);
break;
@ -370,7 +367,8 @@
if(argc < 2)
{
SCWrite(pCon,"ERROR: MakeFit expected the name of a scan command as a parameter",
SCWrite(pCon,
"ERROR: MakeFit expected the name of a scan command as a parameter",
eError);
return 0;
}
@ -408,7 +406,8 @@
iRet1 = AddCommand(pSics,"center",CenterWrapper,NULL,self);
if(!iRet || !iRet1)
{
sprintf(pBueffel,"ERROR: duplicate commands peak and center not created",argv[2]);
sprintf(pBueffel,
"ERROR: duplicate commands peak and center not created",argv[2]);
SCWrite(pCon,pBueffel,eError);
DeleteFitCenter((void *)self);
return 0;
@ -435,11 +434,15 @@
break;
case -1:
SCWrite(pCon,"WARNING: could not find left hand half width",eWarning);
SCWrite(pCon,"Fit Results most certainly dodgy, SICS suggests measuring a full peak",eWarning);
SCWrite(pCon,
"Fit Results most certainly dodgy, SICS suggests measuring a full peak",
eWarning);
break;
case -2:
SCWrite(pCon,"WARNING: could not find right hand half width",eError);
SCWrite(pCon,"Fit Results most certainly dodgy, SICS suggests measuring a full peak",eWarning);
SCWrite(pCon,
"Fit Results most certainly dodgy, SICS suggests measuring a full peak",
eWarning);
break;
case -3:
SCWrite(pCon,"ERROR: No counts found in Fit!",eError);

61
hkl.c
View File

@ -35,10 +35,7 @@
#include "hkl.h"
#include "hkl.i"
#include "splitter.h"
/*
the space we leave in omega in order to allow for a scan to be done
*/
#define SCANBORDER 3.
/*
the tolerance in chi we give before we allow to fix omega with phi
*/
@ -62,6 +59,7 @@
self->fUB[0], self->fUB[1], self->fUB[2], self->fUB[3], self->fUB[4],
self->fUB[5], self->fUB[6], self->fUB[7], self->fUB[8]);
fprintf(fd,"%s hm %d\n",name, self->iHM);
fprintf(fd,"%s scantolerance %f\n", name,self->scanTolerance);
return 1;
}
@ -106,6 +104,7 @@
pNew->fUB[4] = 1.;
pNew->fUB[8] = 1.;
pNew->UBinv = NULL;
pNew->scanTolerance = 2.5;
return pNew;
}
@ -433,12 +432,12 @@ static int checkBisecting(pHKL self,
a omega scan
*/
MotorGetPar(self->pOmega,"softlowerlim",&fLimit);
if((float)om < fLimit + SCANBORDER){
if((float)om < fLimit + self->scanTolerance){
iTest = 0;
} else {
iTest = 1;
MotorGetPar(self->pOmega,"softupperlim",&fLimit);
if((float)om > fLimit - SCANBORDER){
if((float)om > fLimit - self->scanTolerance){
iTest = 0;
} else {
iTest = 1;
@ -512,11 +511,11 @@ static int tryOmegaTweak(pHKL self, MATRIX z1, double *stt, double *om,
omTarget = -9999;
MotorGetPar(self->pOmega,"softlowerlim",&fLower);
MotorGetPar(self->pOmega,"softupperlim",&fUpper);
if(*om < fLower + SCANBORDER) {
omTarget = fLower + SCANBORDER + .5;
if(*om < fLower + self->scanTolerance) {
omTarget = fLower + self->scanTolerance;
}
if(*om > fUpper - SCANBORDER){
omTarget = fUpper - SCANBORDER - .5;
if(*om > fUpper - self->scanTolerance){
omTarget = fUpper - self->scanTolerance;
}
if(omTarget < -7000){
return 0;
@ -1309,6 +1308,9 @@ ente:
sprintf(pBueffel,"Last HKL: %f %f %f ",
self->fLastHKL[0], self->fLastHKL[1],self->fLastHKL[2]);
SCWrite(pCon,pBueffel,eValue);
snprintf(pBueffel,510,"%s.scantolerance = %f", argv[0],
self->scanTolerance);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
/*----------- current */
@ -1370,8 +1372,9 @@ ente:
{
if(argc < 3)
{
SCWrite(pCon,"ERROR: Insufficient number of arguments to HKL lambda",eError);
return 0;
snprintf(pBueffel,132,"%s.lambda = %f", argv[0],self->fLambda);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
if(!SCMatchRights(pCon,usUser))
{
@ -1393,6 +1396,16 @@ ente:
SCSendOK(pCon);
return 1;
}
/*------------- getub*/
else if(strcmp(argv[1],"getub") == 0)
{
snprintf(pBueffel,510,"%s.ub = %f %f %f %f %f %f %f %f %f",
argv[0], self->fUB[0], self->fUB[1], self->fUB[2],
self->fUB[3], self->fUB[4], self->fUB[5],
self->fUB[6], self->fUB[7], self->fUB[8]);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
/*------- lambdavar*/
else if(strcmp(argv[1],"lambdavar") == 0)
{
@ -1547,6 +1560,30 @@ ente:
SCSendOK(pCon);
return 1;
}
/*------------- scantolerance */
else if(strcmp(argv[1],"scantolerance") == 0)
{
if(argc < 3)
{
snprintf(pBueffel,510,"%s.scantolerance = %f",argv[0],
self->scanTolerance);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
if(!SCMatchRights(pCon,usUser))
{
return 0;
}
if(!isNumeric(argv[2]))
{
sprintf(pBueffel,"ERROR: %s was not recognized as a number", argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
self->scanTolerance = atof(argv[2]);
SCSendOK(pCon);
return 1;
}
/*------------- calculate */
else if(strcmp(argv[1],"calc") == 0)
{

1
hkl.i
View File

@ -24,6 +24,7 @@
pMotor pNu;
pSelVar pMono;
long lID;
float scanTolerance;
} HKL;

View File

@ -32,6 +32,7 @@ $\langle$hkldat {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ pMotor pNu;@\\
\mbox{}\verb@ pSelVar pMono;@\\
\mbox{}\verb@ long lID;@\\
\mbox{}\verb@ float scanTolerance;@\\
\mbox{}\verb@ } HKL;@\\
\mbox{}\verb@@$\diamond$
\end{list}
@ -61,7 +62,9 @@ checking.
\item[pPhi] the phi axis motor.
\item[pNu] the nu axis motor for normal beam geometry.
This is detector tilt.
\item[pMono] The selector variable doing the wavelength.
\item[pMono] The selector variable doing the wavelength.
\item[scanTolerance] The hkl module refuses to position a reflection if it is
to close to omega limits for scanning. This is the tolerance to use.
\end{description}
The wavelength is a bit tricky. As it would be to time consuming to read two

5
hkl.w
View File

@ -27,6 +27,7 @@ The object uses the following object data structure:
pMotor pNu;
pSelVar pMono;
long lID;
float scanTolerance;
} HKL;
@}
@ -49,7 +50,9 @@ checking.
\item[pPhi] the phi axis motor.
\item[pNu] the nu axis motor for normal beam geometry.
This is detector tilt.
\item[pMono] The selector variable doing the wavelength.
\item[pMono] The selector variable doing the wavelength.
\item[scanTolerance] The hkl module refuses to position a reflection if it is
to close to omega limits for scanning. This is the tolerance to use.
\end{description}
The wavelength is a bit tricky. As it would be to time consuming to read two

5
lld.c
View File

@ -647,6 +647,11 @@ long LLDnodeLong( int List )
return *((long *) &ListControl[ List ].current->data );
}
float LLDnodeFloat( int List )
{
return *((float *) &ListControl[ List ].current->data );
}
void * LLDnodePtr( int List )
{
return *((void **) &ListControl[ List ].current->data );

1
lld.h
View File

@ -120,6 +120,7 @@ int LLDnodePtr2Prev( int List );
*/
int LLDnodeInt( int List );
long LLDnodeLong( int List );
float LLDnodeFloat( int List );
void * LLDnodePtr( int List );
void FAR * LLDnodeFptr( int List );

View File

@ -1,6 +1,6 @@
/*--------------------------------------------------------------------------
All you need to evaluate macros with SICS.
All you need to evaluate macros with SICS
The implmentation for the macro stuff is complex and non intuitive.
This is the price to pay for adding the extremly powerful and
@ -138,6 +138,7 @@
pSinter = pSics->pInter;
pCon = pSics->pCon[pSics->iStack];
lastCommand = pSics->lastUnknown[pSics->iStack];
pCon->sicsError = 0;
assert(pSinter);
assert(pCon);
@ -200,6 +201,7 @@
else
{
Tcl_SetVar(pInter,SICSERROR,"yes",TCL_GLOBAL_ONLY);
pCon->sicsError = 1;
return TCL_ERROR;
}
}
@ -948,7 +950,6 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp,
SCWrite(pCon,pStart,eError);
}
iRet = InterpExecute(pSics,pCon,pCommand);
SicsWait(1);
SCWrite(pCon,"TRANSACTIONFINISHED",eError);
return iRet;
}

View File

@ -22,12 +22,12 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \
scan.o fitcenter.o telnet.o token.o wwildcard.o\
tclev.o hkl.o integrate.o optimise.o dynstring.o nxutil.o \
mesure.o uubuffer.o commandlog.o udpquieck.o \
rmtrail.o help.o nxupdate.o\
rmtrail.o help.o nxupdate.o confvirtualmot.o \
simchop.o choco.o chadapter.o trim.o scaldate.o \
hklscan.o xytable.o \
hklscan.o xytable.o exebuf.o exeman.o\
circular.o maximize.o sicscron.o \
d_sign.o d_mod.o tcldrivable.o \
synchronize.o definealias.o \
synchronize.o definealias.o oscillate.o \
hmcontrol.o userscan.o rs232controller.o lomax.o \
fourlib.o motreg.o motreglist.o anticollider.o \
s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) \

View File

@ -6,9 +6,9 @@
# Markus Zolliker, March 2003
#==========================================================================
# assign if the National Instrument GPIB driver is available
#NI= -DHAVENI
#NIOBJ= nigpib.o
#NILIB=$(SINQDIR)/linux/lib/cib.o
NI= -DHAVENI
NIOBJ= nigpib.o
NILIB=$(SINQDIR)/linux/lib/cib.o
# The variable SRC is needed for the case, where source and objects are
# separated. In the case where objects are mixed up with sources, SRC

131
mesure.c
View File

@ -26,14 +26,11 @@
#include "evcontroller.h"
#include "mesure.h"
#include "nxscript.h"
#include "lld.h"
extern void SNXFormatTime(char *pBueffel, int iLen);
#define ANGERR 0.2
/* nxutil.h
*/
/*
#define MESSDEBUG 1
@ -71,7 +68,16 @@
float fPosition[4]; /* the real positions after driving */
int iCompact; /* true if compact scan ouput. */
int psiMode; /* 1 for psi scan mode, 0 else */
int stepList; /* a list of stepwidth ranges */
} Mesure;
/*---------------------------------------------------------------------
Entries for the stepwidth range list
----------------------------------------------------------------------*/
typedef struct {
float start;
float end;
float stepWidth;
}StepEntry;
/*--------------------------------------------------------------------------*/
pMesure CreateMesure(pHKL pCryst, pScanData pScanner, pMotor pOmega,
char *pOm, char *po2t, char *pFileRoot,
@ -121,6 +127,7 @@
pNew->lCounts = (long *)malloc(90*sizeof(long));
#endif
pNew->lCounts = (long *)malloc(50*sizeof(long));
pNew->stepList = LLDcreate(sizeof(StepEntry));
return pNew;
}
/*------------------------------------------------------------------------*/
@ -150,6 +157,7 @@
MesureClose(self);
if(self->lCounts)
free(self->lCounts);
LLDdelete(self->stepList);
free(self);
}
/*------------------------------------------------------------------------*/
@ -351,12 +359,46 @@
return 1;
}
/*------------------------------------------------------------------------*/
static void addStepRange(pMesure self, float start, float end, float step)
{
StepEntry se;
assert(self != NULL);
se.start = start;
se.end = end;
se.stepWidth = step;
LLDnodeAppendFrom(self->stepList,&se);
}
/*------------------------------------------------------------------------*/
static float determineStepWidth(pMesure self, float two_theta)
{
float stepWidth;
StepEntry se;
int iRet;
assert(self != NULL);
stepWidth = self->fStep;
iRet = LLDnodePtr2First(self->stepList);
while(iRet != 0)
{
LLDnodeDataTo(self->stepList,&se);
if(two_theta > se.start && two_theta < se.end)
{
stepWidth = se.stepWidth;
break;
}
iRet = LLDnodePtr2Next(self->stepList);
}
return stepWidth;
}
/*--------------------------------------------------------------------------*/
int MesureReflection(pMesure self, float fHKL[3], float fPsi,
SConnection *pCon)
{
int iRet, i;
float fStart;
float fStart, stepWidth;
float fDelta, fSet[4];
char pBueffel[132];
@ -402,19 +444,25 @@
{
return iRet;
}
fStart -= (self->np/2)*self->fStep;
stepWidth = determineStepWidth(self,self->fPosition[0]);
if(stepWidth != self->fStep)
{
snprintf(pBueffel,130,"Using stepwidth %f",stepWidth);
SCWrite(pCon,pBueffel,eWarning);
}
fStart -= (self->np/2)*stepWidth;
/* set the scan up */
ClearScanVar(self->pScanner);
if(self->iMode == 0)
{
AddScanVar(self->pScanner, pServ->pSics,pCon,self->pCOmega,
fStart, self->fStep);
fStart, stepWidth);
}
else
{
AddScanVar(self->pScanner, pServ->pSics,pCon,self->pO2T,
fStart, self->fStep);
fStart, stepWidth);
}
/* do the scan */
@ -435,7 +483,7 @@
{
int iRet, i;
float fStart, fDelta;
float fStart, fDelta, stepWidth;
char pBueffel[132];
assert(self);
@ -479,19 +527,25 @@
{
return iRet;
}
fStart -= (self->np/2)*self->fStep;
stepWidth = determineStepWidth(self,self->fPosition[0]);
if(stepWidth != self->fStep)
{
snprintf(pBueffel,130,"Using stepwidth %f",stepWidth);
SCWrite(pCon,pBueffel,eWarning);
}
fStart -= (self->np/2)*stepWidth;
/* set the scan up */
ClearScanVar(self->pScanner);
if(self->iMode == 0)
{
AddScanVar(self->pScanner, pServ->pSics,pCon,self->pCOmega,
fStart, self->fStep);
fStart, stepWidth);
}
else
{
AddScanVar(self->pScanner, pServ->pSics,pCon,self->pO2T,
fStart, self->fStep);
fStart, stepWidth);
}
/* do the scan */
@ -1142,7 +1196,7 @@
char pBueffel[1024];
pMesure self = NULL;
double d;
float fVal, fHKL[3];
float fVal, fHKL[3], start, end, step;
self = (pMesure)pData;
assert(self);
@ -1389,6 +1443,55 @@
return 1;
}
}
else if(strcmp(argv[1],"addrange") == 0)
{
if(argc < 5)
{
SCWrite(pCon,"ERROR: not enough arguments to addrange",eError);
return 0;
}
if(!SCMatchRights(pCon,usUser))
{
return 0;
}
iRet = Tcl_GetDouble(pSics->pTcl,argv[2],&d);
if(iRet != TCL_OK)
{
snprintf(pBueffel,131,
"ERROR: expected numeric value but got %s",argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
start = (float)d;
iRet = Tcl_GetDouble(pSics->pTcl,argv[3],&d);
if(iRet != TCL_OK)
{
snprintf(pBueffel,131,
"ERROR: expected numeric value but got %s",argv[3]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
end = (float)d;
iRet = Tcl_GetDouble(pSics->pTcl,argv[4],&d);
if(iRet != TCL_OK)
{
snprintf(pBueffel,131,
"ERROR: expected numeric value but got %s",argv[4]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
step = (float)d;
addStepRange(self,start,end,step);
SCSendOK(pCon);
return 1;
}
else if(strcmp(argv[1],"clearrange") == 0)
{
LLDdelete(self->stepList);
self->stepList = LLDcreate(sizeof(StepEntry));
SCSendOK(pCon);
return 1;
}
/*------ can be other pars */
else
{

21
motor.c
View File

@ -271,6 +271,8 @@ static int reportAndFixError(pMotor self, SConnection *pCon)
newStatus = statusRunTo(self,pCon);
break;
case MOTOK:
snprintf(pBueffel,255,"WARNING: %s on %s",pError,self->name);
SCWrite(pCon,pBueffel,eWarning);
newStatus = HWIdle;
break;
default:
@ -954,6 +956,21 @@ extern void KillPiPiezo(void *pData);
*fHard = fVal*ObVal(self->ParArray,SIGN);
return 0;
}
/*------------------------------------------------------------------------*/
float MotorHardToSoftPosition(pMotor self, float fValue)
{
/* apply zeropoint */
if(ObVal(self->ParArray,SIGN) < 0.)
{
fValue += ObVal(self->ParArray,SZERO);
}
else
{
fValue -= ObVal(self->ParArray,SZERO);
}
/* apply sign */
return fValue*ObVal(self->ParArray,SIGN);
}
/* ------------------------------------------------------------------------*/
int MotorGetSoftPosition(pMotor self, SConnection *pCon, float *fVal)
{
@ -970,7 +987,6 @@ extern void KillPiPiezo(void *pData);
*fVal = fValue;
return 0;
}
/* apply zeropoint */
if(ObVal(self->ParArray,SIGN) < 0.)
{
@ -983,7 +999,10 @@ extern void KillPiPiezo(void *pData);
*fVal = fValue;
/* apply sign */
/* *fVal = MotorHardToSoftPosition(self,fValue); */
*fVal = fValue*ObVal(self->ParArray,SIGN);
return 1;
}
/*---------------------------------------------------------------------------*/

View File

@ -46,6 +46,7 @@
/* Where are we ? */
int MotorGetSoftPosition(pMotor self,SConnection *pCon, float *fVal);
int MotorGetHardPosition(pMotor self,SConnection *pCon, float *fVal);
float MotorHardToSoftPosition(pMotor self, float fHard);
/* creation */
int MotorCreate(SConnection *pCon, SicsInterp *pSics, void *pData,

264
napi.c
View File

@ -23,13 +23,12 @@
----------------------------------------------------------------------------*/
static const char* rscid = "$Id: napi.c,v 1.7 2003/05/23 15:06:47 cvs Exp $"; /* Revision interted by CVS */
static const char* rscid = "$Id: napi.c,v 1.8 2004/11/17 10:50:16 cvs Exp $"; /* Revision interted by CVS */
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <time.h>
#include "fortify.h"
#include "napi.h"
/*
@ -71,13 +70,13 @@ static const char* rscid = "$Id: napi.c,v 1.7 2003/05/23 15:06:47 cvs Exp $"; /*
/*------------------------------------------------------------------------
HDF-5 cache size special stuff
-------------------------------------------------------------------------*/
static long cacheSize = 1024000; /* 1MB, HDF-5 default */
long nx_cacheSize = 1024000; /* 1MB, HDF-5 default */
NXstatus CALLING_STYLE NXsetcache(long newVal)
{
if(newVal > 0)
{
cacheSize = newVal;
nx_cacheSize = newVal;
return NX_OK;
}
return NX_ERROR;
@ -98,7 +97,7 @@ NXstatus CALLING_STYLE NXsetcache(long newVal)
/*---------------------------------------------------------------------*/
void CALLING_STYLE NXMSetError(void *pData, void (*NewError)(void *pD, char *text))
NX_EXTERNAL void CALLING_STYLE NXMSetError(void *pData, void (*NewError)(void *pD, char *text))
{
NXpData = pData;
NXIReportError = NewError;
@ -126,6 +125,7 @@ NXstatus CALLING_STYLE NXsetcache(long newVal)
NXhandle hdf5_handle;
NXhandle hdf4_handle;
pNexusFunction fHandle;
NXstatus retstat;
/* configure fortify
iFortifyScope = Fortify_EnterScope();
@ -165,7 +165,11 @@ NXstatus CALLING_STYLE NXsetcache(long newVal)
if (hdf_type==1) {
/* HDF4 type */
#ifdef HDF4
NX4open((const char *)filename,am,&hdf4_handle);
retstat = NX4open((const char *)filename,am,&hdf4_handle);
if(retstat != NX_OK){
free(fHandle);
return retstat;
}
fHandle->pNexusData=hdf4_handle;
fHandle->nxclose=NX4close;
fHandle->nxflush=NX4flush;
@ -194,13 +198,21 @@ NXstatus CALLING_STYLE NXsetcache(long newVal)
fHandle->nxsameID=NX4sameID;
fHandle->nxinitgroupdir=NX4initgroupdir;
fHandle->nxinitattrdir=NX4initattrdir;
#endif
*gHandle = fHandle;
return NX_OK;
#else
NXIReportError (NXpData,"ERROR: Attempt to create HDF4 file when not linked with HDF4");
*gHandle = NULL;
retstat = NX_ERROR;
#endif /* HDF4 */
return retstat;
} else if (hdf_type==2) {
/* HDF5 type */
#ifdef HDF5
NX5open(filename,am,&hdf5_handle);
retstat = NX5open(filename,am,&hdf5_handle);
if(retstat != NX_OK){
free(fHandle);
return retstat;
}
fHandle->pNexusData=hdf5_handle;
fHandle->nxclose=NX5close;
fHandle->nxflush=NX5flush;
@ -229,11 +241,16 @@ NXstatus CALLING_STYLE NXsetcache(long newVal)
fHandle->nxsameID=NX5sameID;
fHandle->nxinitgroupdir=NX5initgroupdir;
fHandle->nxinitattrdir=NX5initattrdir;
#endif
*gHandle = fHandle;
return NX_OK;
#else
NXIReportError (NXpData,"ERROR: Attempt to create HDF5 file when not linked with HDF5");
*gHandle = NULL;
retstat = NX_ERROR;
#endif /* HDF5 */
return retstat;
} else {
NXIReportError (NXpData,"ERROR: Format not readable by this NeXus library");
NXIReportError (NXpData,
"ERROR: Format not readable by this NeXus library");
*gHandle = NULL;
return NX_ERROR;
}
@ -539,6 +556,229 @@ NXstatus CALLING_STYLE NXsetcache(long newVal)
pNexusFunction pFunc = (pNexusFunction)fid;
return pFunc->nxinitgroupdir(pFunc->pNexusData);
}
/*------------------------------------------------------------------------
Implementation of NXopenpath.
--------------------------------------------------------------------------*/
static int isDataSetOpen(NXhandle hfil)
{
NXlink id;
/*
This uses the (sensible) feauture that NXgetdataID returns NX_ERROR
when no dataset is open
*/
if(NXgetdataID(hfil,&id) == NX_ERROR)
{
return 0;
}
else
{
return 1;
}
}
/*----------------------------------------------------------------------*/
static int isRoot(NXhandle hfil)
{
NXlink id;
/*
This uses the feauture that NXgetgroupID returns NX_ERROR
when we are at root level
*/
if(NXgetgroupID(hfil,&id) == NX_ERROR)
{
return 1;
}
else
{
return 0;
}
}
/*--------------------------------------------------------------------
copies the next path element into element.
returns a pointer into path beyond the extracted path
---------------------------------------------------------------------*/
static char *extractNextPath(char *path, NXname element)
{
char *pPtr, *pStart;
int length;
pPtr = path;
/*
skip over leading /
*/
if(*pPtr == '/')
{
pPtr++;
}
pStart = pPtr;
/*
find next /
*/
pPtr = strchr(pStart,'/');
if(pPtr == NULL)
{
/*
this is the last path element
*/
strcpy(element,pStart);
return NULL;
} else {
length = pPtr - pStart;
strncpy(element,pStart,length);
element[length] = '\0';
}
return pPtr + 1;
}
/*-------------------------------------------------------------------*/
static NXstatus gotoRoot(NXhandle hfil)
{
int status;
if(isDataSetOpen(hfil))
{
status = NXclosedata(hfil);
if(status == NX_ERROR)
{
return status;
}
}
while(!isRoot(hfil))
{
status = NXclosegroup(hfil);
if(status == NX_ERROR)
{
return status;
}
}
return NX_OK;
}
/*--------------------------------------------------------------------*/
static int isRelative(char *path)
{
if(path[0] == '.' && path[1] == '.')
return 1;
else
return 0;
}
/*------------------------------------------------------------------*/
static NXstatus moveOneDown(NXhandle hfil)
{
if(isDataSetOpen(hfil))
{
return NXclosedata(hfil);
}
else
{
return NXclosegroup(hfil);
}
}
/*-------------------------------------------------------------------
returns a pointer to the remaining path string to move up
--------------------------------------------------------------------*/
static char *moveDown(NXhandle hfil, char *path, int *code)
{
int status;
NXname pathElem;
char *pPtr;
*code = NX_OK;
if(path[0] == '/')
{
*code = gotoRoot(hfil);
return path;
}
else
{
pPtr = path;
while(isRelative(pPtr))
{
status = moveOneDown(hfil);
if(status == NX_ERROR)
{
*code = status;
return pPtr;
}
pPtr += 3;
}
return pPtr;
}
}
/*--------------------------------------------------------------------*/
static NXstatus stepOneUp(NXhandle hfil, char *name)
{
int status, datatype;
NXname name2, xclass;
char pBueffel[256];
/*
catch the case when we are there: i.e. no further stepping
necessary. This can happen with paths like ../
*/
if(strlen(name) < 1)
{
return NX_OK;
}
NXinitgroupdir(hfil);
while(NXgetnextentry(hfil,name2,xclass,&datatype) != NX_EOD)
{
if(strcmp(name2,name) == 0)
{
if(strcmp(xclass,"SDS") == 0)
{
return NXopendata(hfil,name);
}
else
{
return NXopengroup(hfil,name,xclass);
}
}
}
snprintf(pBueffel,255,"ERROR: NXopenpath cannot step into %s",name);
NXIReportError (NXpData, pBueffel);
return NX_ERROR;
}
/*---------------------------------------------------------------------*/
NXstatus CALLING_STYLE NXopenpath(NXhandle hfil, CONSTCHAR *path)
{
int status, run = 1;
NXname pathElement;
char *pPtr;
if(hfil == NULL || path == NULL)
{
NXIReportError(NXpData,
"ERROR: NXopendata needs both a file handle and a path string");
return NX_ERROR;
}
pPtr = moveDown(hfil,(char *)path,&status);
if(status != NX_OK)
{
NXIReportError (NXpData,
"ERROR: NXopendata failed to move down in hierarchy");
return status;
}
while(run == 1)
{
pPtr = extractNextPath(pPtr, pathElement);
status = stepOneUp(hfil,pathElement);
if(status != NX_OK)
{
return status;
}
if(pPtr == NULL)
{
run = 0;
}
}
return NX_OK;
}
/*----------------------------------------------------------------------
F77 - API - Support - Routines
----------------------------------------------------------------------*/

11
napi.h
View File

@ -20,6 +20,8 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
For further information, see <http://www.neutron.anl.gov/NeXus/>
$Id: napi.h,v 1.7 2004/11/17 10:50:16 cvs Exp $
----------------------------------------------------------------------------*/
@ -27,7 +29,7 @@
#define NEXUSAPI
/* NeXus HDF45 */
#define NEXUS_VERSION "2.0.0." /* major.minor.patch */
#define NEXUS_VERSION "2.1.0" /* major.minor.patch */
#define CONSTCHAR const char
@ -78,6 +80,7 @@ typedef struct {
NX_INT32 32 bit integer
NX_UINT32 32 bit unsigned integer
NX_CHAR 8 bit character
NX_BINARY lump of binary data == NX_UINT8
--------------------------------------------------------------------------*/
@ -92,6 +95,7 @@ typedef struct {
#define NX_INT32 24
#define NX_UINT32 25
#define NX_CHAR 4
#define NX_BINARY 21
/* Map NeXus compression methods to HDF compression methods */
#define NX_COMP_NONE 100
@ -141,6 +145,7 @@ typedef struct {
# define NXclose MANGLE(nxiclose)
# define NXmakegroup MANGLE(nximakegroup)
# define NXopengroup MANGLE(nxiopengroup)
# define NXopenpath MANGLE(nxiopenpath)
# define NXclosegroup MANGLE(nxiclosegroup)
# define NXmakedata MANGLE(nximakedata)
# define NXcompmakedata MANGLE(nxicompmakedata)
@ -211,6 +216,7 @@ typedef struct {
# define NXflush MANGLE(NXIFLUSH)
# define NXmakegroup MANGLE(NXIMAKEGROUP)
# define NXopengroup MANGLE(NXIOPENGROUP)
# define NXopenpath MANGLE(NXIOPENPATH)
# define NXclosegroup MANGLE(NXICLOSEGROUP)
# define NXmakedata MANGLE(NXIMAKEDATA)
# define NXcompress MANGLE(NXICOMPRESS)
@ -263,6 +269,8 @@ NX_EXTERNAL NXstatus CALLING_STYLE NXflush(NXhandle* pHandle);
NX_EXTERNAL NXstatus CALLING_STYLE NXmakegroup (NXhandle handle, CONSTCHAR *name, char* NXclass);
NX_EXTERNAL NXstatus CALLING_STYLE NXopengroup (NXhandle handle, CONSTCHAR *name, char* NXclass);
NX_EXTERNAL NXstatus CALLING_STYLE NXopenpath (NXhandle handle, CONSTCHAR *path);
NX_EXTERNAL NXstatus CALLING_STYLE NXclosegroup(NXhandle handle);
NX_EXTERNAL NXstatus CALLING_STYLE NXmakedata (NXhandle handle, CONSTCHAR* label, int datatype, int rank, int dim[]);
@ -301,6 +309,7 @@ NX_EXTERNAL NXstatus CALLING_STYLE NXfree(void** data);
A non Nexus standard function to set an error handler
*/
NX_EXTERNAL void CALLING_STYLE NXMSetError(void *pData, void (*ErrFunc)(void *pD, char *text));
NX_EXTERNAL void CALLING_STYLE NXNXNXReportError(void *pData,char *text);
/*
another special function for setting the default cache size for HDF-5

1261
napi5.c

File diff suppressed because it is too large Load Diff

View File

@ -472,7 +472,7 @@ int NETReadTillTermNew(mkChannel *self, int timeout,
return -1;
}
maxTime = time(NULL) + (time_t)ceil((double)timeout/1000);
maxTime = time(NULL) + (time_t)ceil((double)timeout/1000 +1);
length = strlen(pTerm);
memset(pBuffer,0,iBufLen);
@ -503,6 +503,8 @@ int NETReadTillTermNew(mkChannel *self, int timeout,
}
pBuffer[bufPtr] = c;
bufPtr++;
} else {
return -1;
}
/*
wait for more data

View File

@ -321,6 +321,7 @@ extern VerifyChannel(mkChannel *self); /* defined in network.c */
else
{
pEnd++;
pPtr = pEnd;
}
break;
}

View File

@ -856,6 +856,7 @@ static void makeLink(SConnection *pCon, SicsInterp *pSics,
pNXScript self,
int argc, char *argv[]){
int status;
char pBueffel[256];
if(argc < 4){
SCWrite(pCon,"ERROR: insufficient number of arguments to makelink",
@ -866,7 +867,9 @@ static void makeLink(SConnection *pCon, SicsInterp *pSics,
status = NXDaliaslink(self->fileHandle, self->dictHandle,
argv[2],argv[3]);
if(status != NX_OK){
SCWrite(pCon,"ERROR: linking failed",eError);
snprintf(pBueffel,255,"ERROR: linking %s against %s failed",
argv[2], argv[3]);
SCWrite(pCon,pBueffel,eError);
return;
}

13
ofac.c
View File

@ -104,6 +104,9 @@
#include "help.h"
#include "site.h"
#include "nxupdate.h"
#include "confvirtmot.h"
#include "exeman.h"
#include "oscillate.h"
/*----------------------- Server options creation -------------------------*/
static int IFServerOption(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
@ -279,6 +282,13 @@
AddCommand(pInter,"DrivableInvoke", TclDrivableInvoke,NULL,NULL);
AddCommand(pInter,"UpdateFactory",UpdateFactory,NULL,NULL);
AddCommand(pInter,"allowexec",AllowExec,NULL,NULL);
AddCommand(pInter,"MakeConfigurableMotor",
MakeConfigurableVirtualMotor,NULL,NULL);
AddCommand(pInter,"MakeBatchManager",
MakeExeManager,NULL,NULL);
AddCommand(pInter,"MakeOscillator",
MakeOscillator,NULL,NULL);
/*
install site specific commands
@ -335,6 +345,9 @@
RemoveCommand(pSics,"MakeTclInt");
RemoveCommand(pSics,"UpdateFactory");
RemoveCommand(pSics,"allowexec");
RemoveCommand(pSics,"MakeConfigurableMotor");
RemoveCommand(pSics,"MakeBatchManager");
RemoveCommand(pSics,"MakeOscillator");
/*
remove site specific installation commands

231
oscillate.c Normal file
View 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
View 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
View 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
@}

View File

@ -228,6 +228,7 @@ int readRS232TillTerm(prs232 self, void *data, int *datalen){
}
else if(iRet == -1)
{
printf("Incomplete read: %s\n", (char *)data);
return INCOMPLETE;
}
*datalen = strlen((char *)data);
@ -592,7 +593,7 @@ int RS232Action(SConnection *pCon, SicsInterp *pSics,
}
else if(strcmp(argv[1],"timeout") == 0)
{
if(checkSet(pCon,argc,usMugger))
if(checkSet(pCon,argc,usUser))
{
setRS232Timeout(self,atoi(argv[2]));
SCSendOK(pCon);

2
scan.c
View File

@ -290,6 +290,8 @@ static char *fixExtension(char *filename)
self->lPos = ftell(self->fd);
fclose(fd);
fclose(self->fd);
self->fd = NULL;
return 1;
}
/*--------------------------------------------------------------------------*/