Initial revision

This commit is contained in:
cvs
2000-02-07 10:38:55 +00:00
commit fdc6b051c9
846 changed files with 230218 additions and 0 deletions

2722
.log Normal file

File diff suppressed because it is too large Load Diff

27
.rfl Normal file
View File

@ -0,0 +1,27 @@
1 14.0 1.0 -3.0 34.93 17.4662365.2f -120.3757635.2f 57.86 0.00 0.00
2 25.0 20.0 3.0 121.37 60.6874285.2f -161.7680215.2f 151.81 0.00 0.00
3 14.0 1.0 -1.0 30.08 15.0386245.2f -105.8243565.2f 57.33 0.00 0.00
4 13.0 1.0 0.0 26.43 13.2171475.2f -97.0895085.2f 62.61 0.00 0.00
5 13.0 1.0 -2.0 30.17 15.0827995.2f -114.8090905.2f 59.43 0.00 0.00
6 0.0 7.0 1.0 38.10 19.0499325.2f 168.9476015.2f 154.39 0.00 0.00
7 -1.0 7.0 1.0 39.00 19.4981695.2f 166.0153055.2f 154.70 0.00 0.00
8 1.0 7.0 1.0 37.31 18.6574575.2f 172.0074465.2f 154.08 0.00 0.00
9 1.0 2.0 2.0 13.43 6.7168745.2f 176.1939855.2f -170.37 0.00 0.00
1 14.0 1.0 -3.0 34.93 17.47 -120.38 57.86 0.00 0.00
2 25.0 20.0 3.0 121.37 60.69 -161.77 151.81 0.00 0.00
3 14.0 1.0 -1.0 30.08 15.04 -105.82 57.33 0.00 0.00
4 13.0 1.0 0.0 26.43 13.22 -97.09 62.61 0.00 0.00
5 13.0 1.0 -2.0 30.17 15.08 -114.81 59.43 0.00 0.00
6 0.0 7.0 1.0 38.10 19.05 168.95 154.39 0.00 0.00
7 -1.0 7.0 1.0 39.00 19.50 166.02 154.70 0.00 0.00
8 1.0 7.0 1.0 37.31 18.66 172.01 154.08 0.00 0.00
9 1.0 2.0 2.0 13.43 6.72 176.19 -170.37 0.00 0.00
1 14.0 1.0 -3.0 34.93 17.47 -120.38 57.86 0.00 0.00
2 25.0 20.0 3.0 121.37 60.69 -161.77 151.81 0.00 0.00
3 14.0 1.0 -1.0 30.08 15.04 -105.82 57.33 0.00 0.00
4 13.0 1.0 0.0 26.43 13.22 -97.09 62.61 0.00 0.00
5 13.0 1.0 -2.0 30.17 15.08 -114.81 59.43 0.00 0.00
6 0.0 7.0 1.0 38.10 19.05 168.95 154.39 0.00 0.00
7 -1.0 7.0 1.0 39.00 19.50 166.02 154.70 0.00 0.00
8 1.0 7.0 1.0 37.31 18.66 172.01 154.08 0.00 0.00
9 1.0 2.0 2.0 13.43 6.72 176.19 -170.37 0.00 0.00

161
Components.txt Normal file
View File

@ -0,0 +1,161 @@
SICS components in this directory
1.) SICS core
- SCinter.* SICS-Interpreter
- Scommon.h common definitions
- conman.* Connection object and management
- devexec.* Device executor
- ifile.* options database
- interrupt.h Interrupt system
intserv.c
intcli.*
- macro.* link between Sics and Tcl
initcl.c
- network.* network protocoll handling
- obdes.* Object descriptor
- ofac.* Object factory, creates objects at startup
- passwd.* password database
- script.* some commands to access SICS internals from
Tcl-scripts.
- nserver.* server startup and closing, main loop
- servlog.* manages the server log
- nserver.c server main program
- interface.* object interface descriptions
- event.* SICS event description
- callback.* The callback system
- costa.* Command stack used for queing commands.
- ecode.* Text version of error codes.
- task.* Cooperative multitasker.
2.) SICS core Objects
- buffer.* LNS-RuenBueffer
- ruli.* RuenBueffer stack management
- configfu.h Prototype for some configuration commands
- status.* Status handling object
- sicsexit.* Exit command
- commandlog.* The commandlog
- danu.c The data file number management
- emon.* Environment control monitoring
- evcontroller.* General environment controller class.
- evdriver.* General environement controller driver.
- perfmon.* Performance measure.
- token.* The token system for access control.
- udpquieck.* send a UDP message when a data file changed.
3.) SICS Objects
- counter.* Single counter object
- drive.* Drive command
- motor.* logical motor
- mumo.* multiple motor object (SANS)
comentry.*
mumoconf.*
- o2t.* Omega2Theta variable for TOPSI
- selector.* Handles a crystal monochromator with energy
selvar.* and lambda variables
- sicsvar.* primitive text, float or integer variables
- histmem.* histogram memory object
- nxdata.c some general NeXus data storage utilities
and the DMC storage routine
- nxutil.* NeXus utility routines.
- velo.* The velocity selector
- amor2t.* The AMOR Reflectometer two-theta movement
- choco.* A generalized controller with driveable
- chadapter.* parameters realized in chadapter.
- dmc.c special command initialization for DMC
- faverage.* Special command to average FOCUS-TOF data
online for status display.
- fitcenter.* Rough fitting and driving to center of
peaks.
- fowrite.* FOCUS TOF NeXus file writing.
- hkl.* Four circle angle calculation and driving.
- hklscan.* Scanning in reciprocal space for 4-circle.
- integrate.* Gabe integrtaion of scanned peaks.
- itc4.* Special things for ITC4, ITC-503 temperature
controllers.
- mesure.* Measuring reflection list on a 4-circle.
- nextrics.* Writing NeXus files for TRICS in rotation
camera mode.
- optimse.* General automatic peak optimisation using
center-of-gravity.
- pimotor.* Physik Instrument DC-804 step motor controller,
a child of motor.
- sanswave.* wavelength calculation for SANS using a
velocity selector.
- scan.* General purpose scanning utility.
- scontroller.* Access a serial port directly using SICS
- serial.* ways.
- sps.* Dealing with Siemens Siematic SPS controllers.
Probably SINQ specific.
- varlog.* log an environment controller
- xytable.* A general purpose table of x-y values.
- a2t. * AMOR two theta movement
- amorstat.* AMOR status display support
- nxamor.* AMOR data file writing
- amorscan.* AMOR specific scan functions.
4.) SICS Hardware driver
- countdriv.* EL737 counter driver
- modriv.* EL734 motor driver
el734driv.c
el734dc.c
- bruker.c Driver for the Bruker Magnet
- simcter.c Simulated counter
- simdriv.c Simulated motor
- histsim.c Simualted histogram memory
- histdriv.c histogram driver general
- sinqhmdriv.c SinQ histogram memory driver
- velosim.c Simulated velocity selector
- velodornier.c Dornier velocity selector
- dilludriv.* Driver for the old dillution cryostat
- docho.* Dornier chopper control system
- itc4driv.* Driver for ITC-4 - ITC-503 temperature
controllers.
- ltc11.* Driver for the Kyocera LTC-11 temperature
controller.
- pipiezo.* Driver for a Physik Instrument Piezo motor
controller.
- simchop.* simulated chopper.
- simev.* simulated environment controller.
- tclev.v necessary code for defining a environment
controller driver in Tcl.
5.) Utility
some of these are freeware files from the net
- Dbg.* Don Libbes Tcl-Debugger
- bit.h Bit-Array handling macros
- defines.h, lld*.* Linked list package
- fortify.* memory debugging package
ufortify.*
- fupa.* helps interpreting object commands
- obpar.* manages array of object parameters
- splitter.* command analysis code
- strdup.*, string duplication
- strrepl.c string replacement
- stringdict.* a String Dictionary
- dynstring.* Dynamic Strings.
- sdynar.* Dynmaic array.
- uubuffer.* uuencode something into a buffer.
6.) Subdirectorys
- hardsup additional HW handling code
- tcl SICS commands implemented in Tcl
- user user documentation
- user/general general SICS commands
- user/DMC DMC specific commands
- status status display clients
- fourcircle four circle diffraction related stuff
- ninx The ILL program INX modified for NeXus

1206
Dbg.c Normal file

File diff suppressed because it is too large Load Diff

46
Dbg.h Normal file
View File

@ -0,0 +1,46 @@
/* Dbg.h - Tcl Debugger include file
Written by: Don Libes, NIST, 3/23/93
Design and implementation of this program was paid for by U.S. tax
dollars. Therefore it is public domain. However, the author and NIST
would appreciate credit if this program or parts of it are used.
*/
/* _DEBUG or _DBG is just too likely, use something more unique */
#ifndef _NIST_DBG
#define _NIST_DBG
#include "tcl.h"
typedef int (Dbg_InterProc) _ANSI_ARGS_((Tcl_Interp *interp));
typedef int (Dbg_IgnoreFuncsProc) _ANSI_ARGS_((
Tcl_Interp *interp,
char *funcname));
typedef void (Dbg_OutputProc) _ANSI_ARGS_((
Tcl_Interp *interp,
char *output));
EXTERN char *Dbg_VarName;
EXTERN char *Dbg_DefaultCmdName;
/* trivial interface, creates a "debug" command in your interp */
EXTERN int Dbg_Init _ANSI_ARGS_((Tcl_Interp *));
EXTERN void Dbg_On _ANSI_ARGS_((Tcl_Interp *interp,
int immediate));
EXTERN void Dbg_Off _ANSI_ARGS_((Tcl_Interp *interp));
EXTERN char **Dbg_ArgcArgv _ANSI_ARGS_((int argc,char *argv[],
int copy));
EXTERN int Dbg_Active _ANSI_ARGS_((Tcl_Interp *interp));
EXTERN Dbg_InterProc *Dbg_Interactor _ANSI_ARGS_((
Tcl_Interp *interp,
Dbg_InterProc *interactor));
EXTERN Dbg_IgnoreFuncsProc *Dbg_IgnoreFuncs _ANSI_ARGS_((
Tcl_Interp *interp,
Dbg_IgnoreFuncsProc *));
EXTERN Dbg_OutputProc *Dbg_Output _ANSI_ARGS_((
Tcl_Interp *interp,
Dbg_OutputProc *));
#endif /* _NIST_DBG */

64
Dbg_cmd.c Normal file
View File

@ -0,0 +1,64 @@
/* Dbg_cmd.c - Tcl Debugger default command, used if app writer wants a
quick and reasonable default.
Written by: Don Libes, NIST, 3/23/93
Design and implementation of this program was paid for by U.S. tax
dollars. Therefore it is public domain. However, the author and NIST
would appreciate credit if this program or parts of it are used.
*/
#include "tclInt.h"
#include "Dbg.h"
char *Dbg_DefaultCmdName = "debug";
/*ARGSUSED*/
static int
App_DebugCmd(clientData, interp, argc, argv)
ClientData clientData;
Tcl_Interp *interp;
int argc;
char **argv;
{
int now = 0; /* soon if 0, now if 1 */
if (argc > 3) goto usage;
argv++;
while (*argv) {
if (0 == strcmp(*argv,"-now")) {
now = 1;
argv++;
}
else break;
}
if (!*argv) {
if (now) {
Dbg_On(interp,1);
} else {
goto usage;
}
} else if (0 == strcmp(*argv,"0")) {
Dbg_Off(interp);
} else {
Dbg_On(interp,now);
}
return(TCL_OK);
usage:
interp->result = "usage: [[-now] 1|0]";
return TCL_ERROR;
}
int
Dbg_Init(interp)
Tcl_Interp *interp;
{
Tcl_CreateCommand(interp,Dbg_DefaultCmdName,App_DebugCmd,
(ClientData)0,(void (*)())0);
return TCL_OK;
}

93
HistDriv.i Normal file
View File

@ -0,0 +1,93 @@
#line 468 "histogram.w"
/*---------------------------------------------------------------------------
H I S T D R I V
internal header file which includes the definition of the Histogram memory
driver structure.
Mark Koennecke, April 1997
----------------------------------------------------------------------------*/
#ifndef SICSHISTDRIV
#define SICSHISTDRIV
#define MAXCHAN 4096
#line 81 "histogram.w"
typedef struct __HistDriver {
/* configuration data */
HistMode eHistMode;
OverFlowMode eFlow;
int iRank;
int iDims[MAXDIM];
int nDim;
int iLength;
int iBinWidth;
float fTime[MAXCHAN];
int iTimeChan;
/* counting operations data */
CounterMode eCount;
float fCountPreset;
/* status flags */
int iReconfig;
int iUpdate;
/* interface functions */
int (*Configure)(pHistDriver self,
SConnection *pCon,
pStringDict pOpt,
SicsInterp *pSics);
int (*Start)(pHistDriver self,
SConnection *pCon);
int (*Halt)(pHistDriver self);
int (*GetCountStatus)(pHistDriver self,
SConnection *pCon);
int (*GetError)(pHistDriver self,
int *iCode,
char *perror,
int iErrlen);
int (*TryAndFixIt)(pHistDriver self,
int iCode);
int (*GetData)(pHistDriver self,
SConnection *pCon);
int (*GetHistogram)(pHistDriver self,
SConnection *pCon,
int i,
int iStart, int iEnd,
HistInt *pData);
int (*SetHistogram)(pHistDriver self,
SConnection *pCon,
int i,
int iStart, int iEnd,
HistInt *pData);
long (*GetMonitor)(pHistDriver self,
int i,
SConnection *pCon);
float (*GetTime)(pHistDriver self,
SConnection *pCon);
int (*Preset)(pHistDriver self,
SConnection *pCon,
HistInt iVal);
int (*Pause)(pHistDriver self,
SConnection *pCon);
int (*Continue)(pHistDriver self,
SConnection *pCon);
int (*FreePrivate)(pHistDriver self);
void *pPriv;
} HistDriver;
#line 480 "histogram.w"
#line 238 "histogram.w"
pHistDriver CreateHistDriver(pStringDict pDict);
void DeleteHistDriver(pHistDriver self);
int HistDriverConfig(pHistDriver self, pStringDict pOpt,
SConnection *pCon);
#line 481 "histogram.w"
#endif

94
HistMem.h Normal file
View File

@ -0,0 +1,94 @@
#line 441 "histogram.w"
/*--------------------------------------------------------------------------
H I S T M E M
header for the histogram memory object for SICS.
copyright: see implementation file.
Mark Koennecke, April 1997
-----------------------------------------------------------------------------*/
#ifndef SICSHISTMEM
#define SICSHISTMEM
#define MAXDIM 3
typedef struct __HistDriver *pHistDriver;
typedef struct __HistMem *pHistMem;
/*-------------------------------------------------------------------------*/
typedef int HistInt;
/*
32 bit integer on a DigitalUnix
*/
#line 9 "histogram.w"
typedef enum {
eHTransparent,
eHNormal,
eHTOF,
eHStrobo,
eHRPT
} HistMode;
#line 33 "histogram.w"
typedef enum {
eOIgnore,
eOCeil,
eOCount,
eReflect
} OverFlowMode;
#line 461 "histogram.w"
/*--------------------------------------------------------------------------*/
#line 302 "histogram.w"
pHistMem CreateHistMemory(char *drivername);
void DeleteHistMemory(void *self);
#line 318 "histogram.w"
int HistGetOption(pHistMem self, char *name, char *result, int iResultLen);
int HistSetOption(pHistMem self, char *name, char *value);
int HistConfigure(pHistMem self, SConnection *pCon, SicsInterp *pSics);
#line 346 "histogram.w"
float GetHistPreset(pHistMem self);
int SetHistPreset(pHistMem self, float fVal);
CounterMode GetHistCountMode(pHistMem self);
int SetHistCountMode(pHistMem self, CounterMode eNew);
long GetHistMonitor(pHistMem self, int i, SConnection *pCon);
const float *GetHistTimeBin(pHistMem self, int *iLength);
int GetHistLength(pHistMem self);
int GetHistDim(pHistMem self, int iDim[MAXDIM], int *nDim);
float GetHistCountTime(pHistMem self,SConnection *pCon);
int HistDoCount(pHistMem self, SConnection *pCon);
int HistBlockCount(pHistMem self, SConnection *pCon);
#line 375 "histogram.w"
int SetHistogram(pHistMem self, SConnection *pCon,
int i,int iStart, int iEnd, HistInt *lData);
int GetHistogram(pHistMem self, SConnection *pCon,
int i,int iStart, int iEnd, HistInt *lData, int iDataLen);
HistInt *GetHistogramPointer(pHistMem self,SConnection *pCon);
int PresetHistogram(pHistMem self, SConnection *pCon, HistInt lVal);
#line 410 "histogram.w"
int MakeHistMemory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int HistAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
#line 463 "histogram.w"
#endif

35
HistMem.i Normal file
View File

@ -0,0 +1,35 @@
#line 486 "histogram.w"
/*---------------------------------------------------------------------------
H I S T M E M -- Internal
internal header file which includes the definition of the Histogram memory
data structure.
Mark Koennecke, April 1997
----------------------------------------------------------------------------*/
#ifndef SICSHISTMEMINT
#define SICSHISTMEMINT
#line 260 "histogram.w"
typedef struct __HistMem {
pObjectDescriptor pDes;
int iAccess;
int iExponent;
pHistDriver pDriv;
int iInit;
pICountable pCountInt;
pICallBack pCall;
pStringDict pOption;
HistInt *iLocalData;
int iLocalLength;
int iLocalUpdate;
time_t tLocal;
int iUpdateIntervall;
} HistMem;
#line 496 "histogram.w"
#endif

78
Makefile Normal file
View File

@ -0,0 +1,78 @@
#----------------------------------------------------------------------------
# Makefile for SICS
#
# Mark Koennecke 1996-2000
#---------------------------------------------------------------------------
BINTARGET=$(HOME)/bin/sics
#FORTIFYOBJ = fortify.o strdup.o
FORTIFYOBJ =
CC=cc
#CC=gcc
TCLOBJ=initcl.o
#TCLOBJ=init8.o
#comment and uncomment according if a difrac version is required
#DIFOBJ=
#DIFIL=
DIFOBJ=difrac.o -Ldifrac -ldif -lfor
DIFIL= difrac.o
COBJ = Sclient.o network.o ifile.o intcli.o $(FORTIFYOBJ)
SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \
servlog.o sicvar.o nserver.o SICSmain.o \
sicsexit.o costa.o task.o $(FORTIFYOBJ)\
macro.o ofac.o obpar.o obdes.o drive.o status.o intserv.o \
devexec.o mumo.o mumoconf.o selector.o selvar.o fupa.o lld.o \
lld_blob.o buffer.o strrepl.o ruli.o $(TCLOBJ) \
script.o o2t.o alias.o napi.o nxdata.o stringdict.o sdynar.o\
histmem.o histdriv.o histsim.o sinqhmdriv.o interface.o callback.o \
event.o emon.o evcontroller.o evdriver.o simev.o perfmon.o \
danu.o itc4driv.o itc4.o nxdict.o nxsans.o varlog.o stptok.o nread.o \
dilludriv.o scan.o fitcenter.o telnet.o token.o scontroller.o serial.o \
tclev.o hkl.o integrate.o optimise.o dynstring.o nextrics.o nxutil.o \
mesure.o uubuffer.o serialwait.o commandlog.o sps.o udpquieck.o \
sanswave.o faverage.o bruker.o rmtrail.o fowrite.o ltc11.o \
simchop.o choco.o chadapter.o docho.o trim.o eurodriv.o scaldate.o \
hklscan.o xytable.o amor2t.o nxamor.o amorscan.o amorstat.o \
circular.o el755driv.o maximize.o sicscron.o qcbo.o
MOTOROBJ = motor.o el734driv.o simdriv.o el734dc.o pipiezo.o pimotor.o
COUNTEROBJ = countdriv.o simcter.o counter.o
DMCOBJ = dmc.o
VELOOBJ = velo.o velosim.o velodorn.o velodornier.o
.SUFFIXES:
.SUFFIXES: .tcl .htm .c .o
CFLAGS = -I/data/koenneck/include -Ihardsup -std1 -g -warnprotos -c
#CFLAGS = -I/data/koenneck/include -DFORTIFY -Ihardsup -g -std1 -warnprotos -c
#CFLAGS = -I/data/koenneck/include -Ihardsup -std1 -warnprotos -c
LIBS = -L/data/koenneck/lib -Lhardsup -lhlib -ltcl7.6 -lmfhdf -ldf \
/data/koenneck/lib/libjpeg.a -lz -lm -ll -lc
# for cygnus
#CFLAGS = -I../HDF411/include -Ihardsup -DFORTIFY -DCYGNUS -g -c
#LIBS= -L../HDF411/lib -Lhardsup -lhlib -ltcl80 \
# -lmfhdf -ldf -ljpeg -lz -lm
.c.o:
$(CC) $(CFLAGS) $*.c
all: server
server: $(SOBJ) $(MOTOROBJ) $(COUNTEROBJ) $(DMCOBJ) $(VELOOBJ) $(DIFIL)
$(CC) -g -o SICServer $(SOBJ) $(MOTOROBJ) $(COUNTEROBJ) $(DMCOBJ) \
$(VELOOBJ) $(DIFOBJ) $(LIBS)
cp SICServer $(BINTARGET)
clean:
- rm *.o
- rm SICServer
Dbg.o: Dbg.c
cc -g -I/data/koenneck/include -c Dbg.c
Dbg_cmd.o: Dbg_cmd.c

528
SCinter.c Normal file
View File

@ -0,0 +1,528 @@
/*---------------------------------------------------------------------------
Implementation file for the SICS-interpreter.
Mark Koennecke, November 1996
Copyright:
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5423 Villigen-PSI
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
#include <string.h>
#include <tcl.h>
#include "fortify.h"
#include "conman.h"
#include "splitter.h"
#include "Scommon.h"
#include "SCinter.h"
#include "obdes.h"
#include "devexec.h"
#include "servlog.h"
#include "macro.h"
#define MAXLEN 256
#define MAXPAR 100
/*--------------------------------------------------------------------------*/
SicsInterp *InitInterp(void)
{
SicsInterp *pInter = NULL;
int i;
pInter = (SicsInterp *)malloc(sizeof(SicsInterp));
if(!pInter)
{
SICSLogWrite("Error allocating memory for Interpreter",eInternal);
return NULL;
}
pInter->pCList = NULL;
pInter->pTcl = (void *)MacroInit(pInter);
if(!pInter->pTcl)
{
free(pInter);
return NULL;
}
pInter->argv = NULL;
pInter->argv = (char **)malloc(MAXPAR*sizeof(char *));
if(pInter->argv == NULL)
{
free(pInter);
return NULL;
}
for(i = 0; i < MAXPAR; i++)
{
pInter->argv[i] = (char *)malloc(MAXLEN*sizeof(char));
if(pInter->argv[i] == NULL)
{
free(pInter);
return NULL;
}
}
pInter->iDeleting = 0;
return pInter;
}
/*------------------------------------------------------------------------*/
int AddCommand(SicsInterp *pInterp, char *pName, ObjectFunc pFunc,
KillFunc pKFunc, void *pData)
{
CommandList *pNew = NULL;
char pBueffel[512];
assert(pName);
assert(pFunc);
assert(pInterp);
strcpy(pBueffel,pName);
strtolower(pBueffel);
if(FindCommand(pInterp,pBueffel) != NULL)
{
return 0;
}
/* new memory */
pNew = (CommandList *)malloc(sizeof(CommandList));
if(!pNew)
{
sprintf(pBueffel,
"Out of memory creating command - %s -", pName);
SICSLogWrite(pBueffel,eInternal);
return 0;
}
/* if no data given, initialise with Dummy struct */
if(!pData)
{
pData = (void *)CreateDummy(pBueffel);
if(!pKFunc)
{
pKFunc = KillDummy;
}
}
/* initialise datastructures */
pNew->pName = strdup(pBueffel);
pNew->OFunc = pFunc;
pNew->KFunc = pKFunc;
pNew->pData = pData;
pNew->pNext = pInterp->pCList;
if(pInterp->pCList)
{
pInterp->pCList->pPrevious = pNew;
}
pNew->pPrevious = NULL;
/* update headpointer */
pInterp->pCList = pNew;
return 1;
}
/*------------------------------------------------------------------------*/
int RemoveCommand(SicsInterp *pInterp, char *pName)
{
CommandList *pVictim = NULL;
char pBueffel[256];
assert(pInterp);
assert(pName);
strcpy(pBueffel,pName);
strtolower(pBueffel);
if(pInterp->iDeleting)
{
return 0;
}
/* find our victim */
pVictim = FindCommand(pInterp, pBueffel);
if(!pVictim)
return 0;
/* found, remove it */
/* kall KillFunction first */
if(pVictim->KFunc)
{
pVictim->KFunc(pVictim->pData);
}
/* delete and unlink data */
if(pVictim->pName)
{
free(pVictim->pName);
}
if(pVictim->pPrevious)
{
pVictim->pPrevious->pNext = pVictim->pNext;
}
if(pVictim->pNext)
{
pVictim->pNext->pPrevious = pVictim->pPrevious;
}
/* adjust headpointer if necessary */
if(pVictim == pInterp->pCList)
{
pInterp->pCList = pVictim->pNext;
}
free(pVictim);
return 1;
}
#define MAXLEN 256
#define MAXCOM 50
extern char *stptok(char *s, char *tok, unsigned int toklen, char *brk);
extern char *SkipSpace(char *pPtr);
/*------------------------------------------------------------------------*/
int InterpExecute(SicsInterp *self,SConnection *pCon, char *pText)
{
int iCount = 0;
int iRet;
int i;
char pBueffel[1024];
CommandList *pCommand = NULL;
char pBrk[] = {" \r\n\0"};
char *pPtr;
assert(self);
assert(pCon);
/* write info to Log */
if(pCon->pSock)
{
sprintf(pBueffel,"Executing -> %s <- from socket %d",pText,
pCon->pSock->sockid);
SICSLogWrite(pBueffel,eCommand);
}
else
{
if(!pCon->iDummy)
{
printf("Executing -> %s <- from dummy socket\n", pText);
}
else
{
sprintf(pBueffel,"Executing -> %s <- from sicscron",pText);
SICSLogWrite(pBueffel,eCommand);
}
}
/* convert to argc, argv */
pPtr = SkipSpace(pText);
if(pPtr)
{
pPtr = stptok(pPtr,self->argv[0],255,pBrk);
}
while(pPtr != NULL)
{
iCount++;
pPtr = SkipSpace(pPtr);
if(!pPtr)
{
break;
}
pPtr = stptok(pPtr,self->argv[iCount],255,pBrk);
}
self->argv[iCount][0] = '\0';
/* the first one must be the target object. If not given an empty
command string was given which will be silently ignored */
if(iCount < 1)
{
return 1;
}
/* find it */
pCommand = FindCommand(self,self->argv[0]);
if(!pCommand)
{
sprintf(pBueffel,"ERROR: Object -> %s <- NOT found",
self->argv[0]);
SCWrite(pCon,pBueffel,eError);
return -1;
}
/* invoke the command */
self->eOut = eStatus;
Tcl_ResetResult((Tcl_Interp *)self->pTcl);
MacroPush(pCon);
iRet = pCommand->OFunc(pCon, self, pCommand->pData, iCount, self->argv);
MacroPop();
return iRet;
}
/*------------------------------------------------------------------------*/
CommandList *FindCommand(SicsInterp *self, char *pName)
{
CommandList *pCurrent = NULL;
char pBueffel[256];
assert(self);
if(self->iDeleting)
{
return NULL;
}
strcpy(pBueffel,pName);
strtolower(pBueffel);
pCurrent = self->pCList;
while(pCurrent)
{
if(strcmp(pCurrent->pName, pBueffel) == 0 )
{
return pCurrent;
}
pCurrent = pCurrent->pNext;
}
return NULL;
}
/*------------------------------------------------------------------------*/
int WriteSicsStatus(SicsInterp *self, char *file)
{
CommandList *pCurrent = NULL;
FILE *fd = NULL;
Dummy *pDum = NULL;
assert(self);
assert(file);
/* open file */
fd = fopen(file,"w");
if(!fd)
{
return 0;
}
/* remove it, as I found garbage from previous runs in the
status file
*/
fclose(fd);
remove(file);
fd = fopen(file,"w");
if(!fd)
{
return 0;
}
/* cycle through the list */
pCurrent = self->pCList;
while(pCurrent)
{
pDum = (Dummy *)pCurrent->pData;
if(pDum)
{
pDum->pDescriptor->SaveStatus(pCurrent->pData,pCurrent->pName,fd);
}
pCurrent = pCurrent->pNext;
}
fclose(fd);
return 1;
}
/*------------------------------------------------------------------------*/
void DeleteInterp(SicsInterp *self)
{
CommandList *pCurrent = NULL;
CommandList *pTemp;
Tcl_Interp *pTcl = NULL;
int i;
assert(self);
self->iDeleting = 1;
/* delete Commandlist */
pCurrent = self->pCList;
while(pCurrent)
{
if(pCurrent->KFunc)
{
pCurrent->KFunc(pCurrent->pData);
}
if(pCurrent->pName)
{
free(pCurrent->pName);
}
pTemp = pCurrent->pNext;
free(pCurrent);
pCurrent = pTemp;
}
/* clear Tcl_Interpreter. Must be AFTER deleting command list because
some devices may have Tcl drivers which need to be accessed for
proper closing of devices.
*/
pTcl = (Tcl_Interp *)self->pTcl;
if(pTcl)
{
Tcl_DeleteInterp(pTcl);
}
for(i = 0; i < MAXPAR; i++)
{
free(self->argv[i]);
}
free(self->argv);
free(self);
}
/*--------------------------------------------------------------------------*/
int ListObjects(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
CommandList *pCurrent;
char pBueffel[256];
int iNum = 0;
assert(pSics);
assert(pCon);
pCurrent = pSics->pCList;
while(pCurrent)
{
if(iNum == 0)
{
strcpy(pBueffel,pCurrent->pName);
iNum++;
}
else if(iNum < 4)
{
strcat(pBueffel," ");
strcat(pBueffel,pCurrent->pName);
iNum++;
}
else
{
strcat(pBueffel," ");
strcat(pBueffel,pCurrent->pName);
strcat(pBueffel,"\r\n");
SCWrite(pCon,pBueffel,eStatus);
iNum = 0;
}
pCurrent = pCurrent->pNext;
}
/* write final entries */
if(strlen(pBueffel) > 2)
{
strcat(pBueffel,"\r\n");
SCWrite(pCon,pBueffel,eStatus);
}
return 1;
}
/*---------------------------------------------------------------------------*/
int InterpWrite(SicsInterp *pSics, char *buffer)
{
Tcl_Interp *pTcl = NULL;
assert(pSics);
pTcl = (Tcl_Interp *)pSics->pTcl;
Tcl_SetResult(pTcl,buffer,TCL_VOLATILE);
return 1;
}
/*---------------------------------------------------------------------------*/
Tcl_Interp *InterpGetTcl(SicsInterp *pSics)
{
Tcl_Interp *pTcl = NULL;
pTcl = (Tcl_Interp *)pSics->pTcl;
return pTcl;
}
/*---------------------------------------------------------------------------*/
void strtolower(char *pText)
{
assert(pText);
while(*pText != '\0')
{
*pText = tolower(*pText);
pText++;
}
}
/*---------------------------------------------------------------------------*/
void argtolower(int argc, char *argv[])
{
int i;
for(i = 0; i < argc; i++)
{
strtolower(argv[i]);
}
}
/*------------------------------------------------------------------------*/
char *FindAlias(SicsInterp *self, void *pData)
{
CommandList *pCurrent = NULL;
assert(self);
if(self->iDeleting)
{
return NULL;
}
pCurrent = self->pCList;
while(pCurrent)
{
if(pCurrent->pData == pData)
{
return pCurrent->pName;
}
pCurrent = pCurrent->pNext;
}
return NULL;
}
/*---------------------------------------------------------------------------*/
void *FindCommandData(SicsInterp *pSics, char *name, char *cclass)
{
CommandList *pCom;
pDummy pDum = NULL;
pCom = FindCommand(pSics,name);
if(!pCom)
{
return NULL;
}
if(!pCom->pData)
return NULL;
pDum = (pDummy)pCom->pData;
if(strcmp(pDum->pDescriptor->name,cclass) == 0)
{
return pCom->pData;
}
return NULL;
}

133
SCinter.h Normal file
View File

@ -0,0 +1,133 @@
/*--------------------------------------------------------------------------
The SICS needs an interpreter. This is it.
Mark Koennecke, November 1996
copyright: see implementation file
---------------------------------------------------------------------------*/
#ifndef SICSINTERPRETER
#define SICSINTERPRETER
#include "Scommon.h"
typedef struct __SConnection *pSConnection;
typedef struct __SINTER *pSicsInterp;
typedef int (*ObjectFunc)(pSConnection pCon, pSicsInterp pInter, void
*pData, int argc, char *argv[]);
typedef void (*KillFunc)(void *pData);
typedef struct __Clist {
char *pName;
ObjectFunc OFunc;
KillFunc KFunc;
void *pData;
struct __Clist *pNext;
struct __Clist *pPrevious;
} CommandList;
typedef struct __SINTER
{
CommandList *pCList;
OutCode eOut;
void *pTcl;
char **argv;
int iDeleting;
}SicsInterp;
/*-------------------------------------------------------------------------*/
SicsInterp *InitInterp(void);
/* makes a new interpreter. Returns him on success, else NULL
*/
/*------------------------------------------------------------------------*/
int AddCommand(SicsInterp *pInterp, char *pName, ObjectFunc pFunc,
KillFunc pKFunc, void *pData);
/* adds a new command, Returns True or False, depending on success
Parameters:
pInterp : the interpreter to add the command to.
pName : the commands name
pFunc : the object function to call when this command is
invoked. Definition of type: see above
pKFunc : function to call in order to delete command data.
type definition: above
pData : pointer to the command's own datastructure. Will be
passed as pData with each call to Ofunc.
*/
/*-------------------------------------------------------------------------*/
int RemoveCommand(SicsInterp *pInterp, char *pName);
/* kills the command name from the interpreter pInterp
*/
/*-------------------------------------------------------------------------*/
int InterpExecute(SicsInterp *self,pSConnection pCon,char *pCommand);
/*
executes a command in the interpreter self. Essentially converts
pCommand in an argc, argv[] pair, sets various status things and
invokes the object function. Takes care of status and error reporting
afterwards.
Parameters:
self : interpreter to invoke command in.
The connection pCon will be used for I/O and status reporting.
The command to invoke is the string pCommand.
Returns -1 if the command can not be found.
If the command is found, 1 is returned on success, 0 on failure in
the command.
----------------------------------------------------------------------------*/
CommandList *FindCommand(SicsInterp *pInterp, char *name);
/*
Searches the Interpreters pInterp command list for a command
with name. Returns ist datastructure if found, NULL else
*/
/*-------------------------------------------------------------------------*/
int WriteSicsStatus(SicsInterp *pSics,char *file);
/*
SICS needs a way to save the status of each object into a file.
This is done by invoking for each object the object descriptor
function SaveStatus. This function does just that.
Parameters:
pSics : the interpreter to use.
file : the file to write the information to.
Returns: 1 on success, 0 on failure.
---------------------------------------------------------------------------*/
int InterpWrite(SicsInterp *pSics, char *buffer);
/*
writes result to Tcl, used for Macro mechanism.
This is an internal function and should not be used.
----------------------------------------------------------------------------*/
void DeleteInterp(SicsInterp *self);
/*
deletes the interpreter self aand clears all asoociated datastructures.
self will no longer be valid after this.
--------------------------------------------------------------------------- */
void strtolower(char *pText);
/*
strtolower converts a string to lowercase
--------------------------------------------------------------------------- */
void argtolower(int argc, char *argv[]);
/*
converts an argc, argv[] pair to lowercase
*/
/*--------------------------------------------------------------------------
FindAlias tries to find an alias to the datastructure given as second
parameter. Returns the command name on success, else NULL. Be warned, this
is very special
*/
char *FindAlias(SicsInterp *pSics, void *pData);
/*-------------------------------------------------------------------------
FindCommandData finds a command with the name given. It tests the name in the
ObjectDescriptor to be of name class. If all this succeeds a pointer
to the commands data structure is retuned. Else NULL
*/
void *FindCommandData(SicsInterp *pSics, char *name, char *comclass);
#endif

87
SICSmain.c Normal file
View File

@ -0,0 +1,87 @@
/*--------------------------------------------------------------------------
THE SICS SERVER
This file contains the main entry point into the world of SICS.
Mark Koennecke, October 1996
Copyright: see copyright.h
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5423 Villigen-PSI
----------------------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "nserver.h"
/***************************** Necessary Globals ****************************/
IPair *pSICSOptions = NULL;
pServer pServ = NULL;
/* ========================= Less dreadful file statics =================== */
#define DEFAULTINIFILE "servo.tcl"
/*---------------------------------------------------------------------------
The Servers Main program. May take one argument: the name of an
initialisation file
*/
int main(int argc, char *argv[])
{
int iRet;
/* initialise, will die on you if problems */
if(argc >= 2)
{
iRet = InitServer(argv[1],&pServ);
}
else
{
iRet = InitServer(NULL,&pServ);
}
if(!iRet)
{
printf("Unrecoverable error on server startup, exiting.........");
exit(1);
}
RunServer(pServ);
StopServer(pServ);
pServ = NULL;
exit(0);
}
/*--------------------------------------------------------------------------*/
SicsInterp *GetInterpreter(void)
{
return pServ->pSics;
}
/*--------------------------------------------------------------------------*/
pExeList GetExecutor(void)
{
return pServ->pExecutor;
}
/*------------------------------------------------------------------------*/
void StopExit(void)
{
if(pServ)
{
StopServer(pServ);
}
}
/*-------------------------------------------------------------------------*/
pTaskMan GetTasker(void)
{
return pServ->pTasker;
}

81
Scommon.h Normal file
View File

@ -0,0 +1,81 @@
/*-------------------------------------------------------------------------
Some common types and functions for SICS
Mark Koennecke, October 1996
Copyright:
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5423 Villigen-PSI
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
----------------------------------------------------------------------------*/
#ifndef SICSCOMMON
#define SICSCOMMON
/* this enum defines the output types in SICS */
typedef enum {
eInternal,
eCommand,
eHWError,
eInError,
eStatus,
eValue,
eWarning,
eError
} OutCode;
#include "interrupt.h"
/* define some user rights codes */
#define usInternal 0
#define usMugger 1
#define usUser 2
#define usSpy 3
/* status and error codes */
#define OKOK 1
#define HWIdle 2
#define HWBusy 3
#define HWFault 4
#define HWPosFault 5
#define HWCrash 6
#define NOMEMORY 7
#define HWNoBeam 8
#define HWPause 9
#define HWWarn 10
/*
Sics uses some server options for some server configuration parameters.
These options are held in the global variable pSICSOptions.
*/
#include "ifile.h"
extern IPair *pSICSOptions;
#endif

16
access.c Normal file
View File

@ -0,0 +1,16 @@
/* ------------------------------------------------------------------------
The Accesscode names for SICS
Mark Koennecke, November 1996
----------------------------------------------------------------------------*/
#ifndef PCODE
#define PCODE
static char *aCode[] = {
"internal",
"mugger",
"user",
"spy",
NULL };
static int iCodes = 4;
#endif

214
alias.c Normal file
View File

@ -0,0 +1,214 @@
/*-----------------------------------------------------------------------
A L I A S
Copyright:
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5423 Villigen-PSI
First Version: 1998, Mark Koennecke
updated: November 1999, Mark Koennecke
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
----------------------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include <tcl.h>
#include <assert.h>
#include "fortify.h"
#include "sics.h"
#include "splitter.h"
#include "alias.h"
/*
Usage: SicsAlias object newname
*/
int SicsAlias(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
CommandList *pCom = NULL;
char pBueffel[256];
int iRet;
if(!SCMatchRights(pCon,usMugger))
{
SCWrite(pCon,"ERROR: aliasing only allowed to Managers",
eError);
return 0;
}
if(argc < 3)
{
SCWrite(pCon,"ERROR: insufficient number of arguments to SicsAlias",
eError);
return 0;
}
argtolower(argc,argv);
/* first parameter should be an registered SICS object */
pCom = FindCommand(pSics,argv[1]);
if(!pCom)
{
sprintf(pBueffel,"ERROR: cannot find %s, no alias created",argv[1]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/* alright: create the alias */
iRet = AddCommand(pSics,argv[2],pCom->OFunc,NULL,pCom->pData);
if(!iRet)
{
sprintf(pBueffel,"ERROR: duplicate command %s not created",argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
return 1;
}
/*--------------------------------------------------------------------
Make Alias: a command which installs a general alias into SICS.
*/
typedef struct {
pObjectDescriptor pDes;
char *pCommand;
}Alias, *pAlias;
/*----------------------------------------------------------------------*/
static void FreeAlias(void *pData)
{
pAlias self = (pAlias)pData;
if(!self)
return;
if(self->pDes)
DeleteDescriptor(self->pDes);
if(self->pCommand)
free(self->pCommand);
free(self);
}
/*----------------------------------------------------------------------
In order to make alias most general alias tries to find the interfaces
defined by the object corresponding to the first word in the command.
Note: does not work, the object pointer with which a interface function
will be called refers to the alias and not the proper thing: core dump!
Therefore disabled!
*/
static void *AliasInterface(void *pData, int iID)
{
CommandList *pCom = NULL;
pDummy pDum = NULL;
char *pPtr = NULL;
pAlias self = (pAlias)pData;
assert(self);
pPtr = strtok(self->pCommand," \t\n");
pCom = FindCommand(pServ->pSics,pPtr);
if(!pCom)
return NULL;
pDum = (pDummy)pCom->pData;
if(!pDum)
return NULL;
return pDum->pDescriptor->GetInterface(pDum,iID);
}
/*-----------------------------------------------------------------------*/
static int AliasAction(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[])
{
pAlias self = NULL;
int status;
char pLine[512];
char *pPtr;
Tcl_DString command;
self = (pAlias)pData;
assert(self);
/*
build command by appending the alias command and any possible
arguments given.
*/
Tcl_DStringInit(&command);
Tcl_DStringAppend(&command, self->pCommand,-1);
Tcl_DStringAppend(&command," ",-1);
Arg2Text(argc-1,&argv[1],pLine,511);
Tcl_DStringAppend(&command,pLine,-1);
/* execute the command on the current connection */
status = SCInvoke(pCon,pSics,Tcl_DStringValue(&command));
/* finish */
Tcl_DStringFree(&command);
return status;
}
/*-----------------------------------------------------------------------*/
int MakeAlias(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
char pBueffel[512];
int iRet;
pAlias pNew = NULL;
if(argc < 3)
{
SCWrite(pCon,"ERROR: insufficient number of arguments to alias",
eError);
return 0;
}
Arg2Text(argc-2,&argv[2],pBueffel,511);
/* create data structure */
pNew = (pAlias)malloc(sizeof(Alias));
if(!pNew)
{
SCWrite(pCon,"ERROR: out of memory while creating alias",eError);
return 0;
}
pNew->pDes = CreateDescriptor("Alias");
pNew->pCommand = strdup(pBueffel);
if( !pNew->pDes || !pNew->pCommand)
{
SCWrite(pCon,"ERROR: out of memory while creating alias",eError);
return 0;
}
iRet = AddCommand(pSics,
argv[1],
AliasAction,
FreeAlias,
pNew);
if(!iRet)
{
FreeAlias(pNew);
SCWrite(pCon,"ERROR: duplicate object name NOT created",eError);
return 0;
}
return 1;
}

20
alias.h Normal file
View File

@ -0,0 +1,20 @@
/*------------------------------------------------------------------------
A L I A S
Implementation of the alias command. This is a configuration command
which allows additional names "aliases" for an existing object.
Mark Koennecke, March 1997
copyright: see implementation file
-------------------------------------------------------------------------*/
#ifndef SICSALIAS
#define SICSALIAS
int SicsAlias(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int MakeAlias(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
#endif

210
amor.dic Normal file
View File

@ -0,0 +1,210 @@
##NXDICT-1.0
#----------------------------------------------------------------------------
# NeXus dictionary file for the SINQ instrument AMOR
#
# DO NOT EDIT WHEN YOU DO NOT KNOW WHAT YOU ARE DOING!
# This file determines the placement of data items in the AMOR NeXus
# data file. Your data may not be readable if this file is messed up.
#
# Mark Koennecke, September 1999
#----------------------------------------------------------------------------
# AMOR may have variable time binning. In order
# to cope with that, we use NXDICT's text replacement feature and define
# these things
timebin = 512
detsize = 255
scanlength = 10
#---------- NXentry level
etitle=/entry1,NXentry/SDS title -type DFNT_CHAR -rank 1 -dim {132}
estart=/entry1,NXentry/SDS start_time -type DFNT_CHAR -rank 1 -dim {132}
eend=/entry1,NXentry/SDS end_time -type DFNT_CHAR -rank 1 -dim {132}
#----------------- NXinstrument
iname=/entry1,NXentry/reflectometer,NXinstrument/SDS name -type DFNT_CHAR \
-rank 1 -dim {132}
#----------------- NXsource
sname=/entry1,NXentry/reflectometer,NXinstrument/SINQ,NXsource/SDS name \
-type DFNT_CHAR -rank 1 -dim {132}
stype=/entry1,NXentry/reflectometer,NXinstrument/SINQ,NXsource/SDS type \
-type DFNT_CHAR -rank 1 -dim {132}
#----------------- Chopper
cname=/entry1,NXentry/reflectometer,NXinstrument/chopper,NXchopper/SDS name \
-type DFNT_CHAR -rank 1 -dim {132}
crot=/entry1,NXentry/reflectometer,NXinstrument/chopper,NXchopper/SDS \
rotation_speed -attr {units,rpm}
#---------------- frame overlap mirror
fomname=/entry1,NXentry/reflectometer,NXinstrument/frame_overlap_mirror,NXfilter/SDS name \
-type DFNT_CHAR -rank 1 -dim {132}
fomh=/entry1,NXentry/reflectometer,NXinstrument/frame_overlap_mirror,NXfilter/SDS \
omega_height -attr {units,mm}
fomom=/entry1,NXentry/reflectometer,NXinstrument/frame_overlap_mirror,NXfilter/SDS \
omega -attr {units,degree}
fodist=/entry1,NXentry/reflectometer,NXinstrument/frame_overlap_mirror,NXfilter/SDS \
distance -attr {units,mm}
#-------------- first slit
d1l=/entry1,NXentry/reflectometer,NXinstrument/diaphragm1,NXfilter/SDS left \
-attr {units,mm}
d1r=/entry1,NXentry/reflectometer,NXinstrument/diaphragm1,NXfilter/SDS right \
-attr {units,mm}
d1t=/entry1,NXentry/reflectometer,NXinstrument/diaphragm1,NXfilter/SDS top \
-attr {units,mm}
d1b=/entry1,NXentry/reflectometer,NXinstrument/diaphragm1,NXfilter/SDS bottom \
-attr {units,mm}
d1dist=/entry1,NXentry/reflectometer,NXinstrument/diaphragm1,NXfilter/SDS distance \
-attr {units,mm}
#---------- polarizing mirror
polname=/entry1,NXentry/reflectometer,NXinstrument/polarizer,NXfilter/SDS name \
-type DFNT_CHAR -rank 1 -dim {132}
polz=/entry1,NXentry/reflectometer,NXinstrument/polarizer,NXfilter/SDS height \
-attr {units,mm}
polzom=/entry1,NXentry/reflectometer,NXinstrument/polarizer,NXfilter/SDS omega_height \
-attr {units,mm}
polom=/entry1,NXentry/reflectometer,NXinstrument/polarizer,NXfilter/SDS omega \
-attr {units,degree}
poly=/entry1,NXentry/reflectometer,NXinstrument/polarizer,NXfilter/SDS y_position \
-attr {units,mm}
poldist=/entry1,NXentry/reflectometer,NXinstrument/polarizer,NXfilter/SDS distance \
-attr {units,mm}
#-------------- second slit
d2l=/entry1,NXentry/reflectometer,NXinstrument/diaphragm2,NXfilter/SDS left \
-attr {units,mm}
d2r=/entry1,NXentry/reflectometer,NXinstrument/diaphragm2,NXfilter/SDS right \
-attr {units,mm}
d2t=/entry1,NXentry/reflectometer,NXinstrument/diaphragm2,NXfilter/SDS top \
-attr {units,mm}
d2b=/entry1,NXentry/reflectometer,NXinstrument/diaphragm2,NXfilter/SDS bottom \
-attr {units,mm}
d2dist=/entry1,NXentry/reflectometer,NXinstrument/diaphragm2,NXfilter/SDS distance \
-attr {units,mm}
#-------------- third slit
d3l=/entry1,NXentry/reflectometer,NXinstrument/diaphragm3,NXfilter/SDS left \
-attr {units,mm}
d3r=/entry1,NXentry/reflectometer,NXinstrument/diaphragm3,NXfilter/SDS right \
-attr {units,mm}
d3t=/entry1,NXentry/reflectometer,NXinstrument/diaphragm3,NXfilter/SDS top \
-attr {units,mm}
d3b=/entry1,NXentry/reflectometer,NXinstrument/diaphragm3,NXfilter/SDS bottom \
-attr {units,mm}
d3dist=/entry1,NXentry/reflectometer,NXinstrument/diaphragm3,NXfilter/SDS distance \
-attr {units,mm}
#---------------- sample table
saname=/entry1,NXentry/sample,NXsample/SDS name \
-type DFNT_CHAR -rank 1 -dim {132}
somheight=/entry1,NXentry/sample,NXsample/SDS omega_height \
-attr {units,mm}
schi=/entry1,NXentry/sample,NXsample/SDS chi \
-attr {units,degree}
somega=/entry1,NXentry/sample,NXsample/SDS omega \
-attr {units,degree}
stheight=/entry1,NXentry/sample,NXsample/SDS table_height \
-attr {units,mm}
stdist=/entry1,NXentry/sample,NXsample/SDS distance \
-attr {units,mm}
#------------ fourth slit
d4l=/entry1,NXentry/reflectometer,NXinstrument/diaphragm4,NXfilter/SDS left \
-attr {units,mm}
d4r=/entry1,NXentry/reflectometer,NXinstrument/diaphragm4,NXfilter/SDS right \
-attr {units,mm}
d4t=/entry1,NXentry/reflectometer,NXinstrument/diaphragm4,NXfilter/SDS top \
-attr {units,mm}
d4b=/entry1,NXentry/reflectometer,NXinstrument/diaphragm4,NXfilter/SDS bottom \
-attr {units,mm}
d4dist=/entry1,NXentry/reflectometer,NXinstrument/diaphragm4,NXfilter/SDS distance \
-attr {units,mm}
#------------ analyzer
anname=/entry1,NXentry/reflectometer,NXinstrument/polarizer,NXfilter/SDS name \
-type DFNT_CHAR -rank 1 -dim {132}
anoz=/entry1,NXentry/reflectometer,NXinstrument/analyzer,NXfilter/SDS omega_height \
-attr {units,mm}
anom=/entry1,NXentry/reflectometer,NXinstrument/analyzer,NXfilter/SDS omega \
-attr {units,degree}
antz=/entry1,NXentry/reflectometer,NXinstrument/analyzer,NXfilter/SDS height \
-attr {units,mm}
andist=/entry1,NXentry/reflectometer,NXinstrument/analyzer,NXfilter/SDS distance \
-attr {units,mm}
#--------------- fifth slit!!
d5l=/entry1,NXentry/reflectometer,NXinstrument/diaphragm5,NXfilter/SDS left \
-attr {units,mm}
d5r=/entry1,NXentry/reflectometer,NXinstrument/diaphragm5,NXfilter/SDS right \
-attr {units,mm}
d5t=/entry1,NXentry/reflectometer,NXinstrument/diaphragm5,NXfilter/SDS top \
-attr {units,mm}
d5b=/entry1,NXentry/reflectometer,NXinstrument/diaphragm5,NXfilter/SDS bottom \
-attr {units,mm}
d5dist=/entry1,NXentry/reflectometer,NXinstrument/diaphragm5,NXfilter/SDS distance \
-attr {units,mm}
#---------- count control
cnmode=/entry1,NXentry/reflectometer,NXinstrument/counter,NXmonitor/SDS count_mode \
-type DFNT_CHAR -rank 1 -dim {30}
cnpreset=/entry1,NXentry/reflectometer,NXinstrument/counter,NXmonitor/SDS preset \
-attr {units,countsOrseconds}
cntime=/entry1,NXentry/reflectometer,NXinstrument/counter,NXmonitor/SDS time \
-attr {units,seconds}
cnmon1=/entry1,NXentry/reflectometer,NXinstrument/counter,NXmonitor/SDS monitor1 \
-type DFNT_INT32 -attr {units,counts}
cnmon2=/entry1,NXentry/reflectometer,NXinstrument/counter,NXmonitor/SDS monitor2 \
-type DFNT_INT32 -attr {units,counts}
#-------------- detector-TOF mode
dettype=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS type \
-type DFNT_CHAR -rank 1 -dim {132}
dety=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS y_detector \
-type DFNT_FLOAT32 -rank 1 -dim {$(detsize)} -attr {axis,1} \
-attr {units,mm}
detxx=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS x_detector \
-type DFNT_FLOAT32 -rank 1 -dim {$(detsize)} -attr {axis,2} \
-attr {units,mm}
detz=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS z \
-type DFNT_FLOAT32 -rank 1 -dim {$(detsize)} -attr {axis,2} \
-attr {units,mm}
detx=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS x \
-type DFNT_FLOAT32 -attr {units,mm}
detom=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS omega \
-type DFNT_FLOAT32 -attr {units,degree}
detheight=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS height \
-type DFNT_FLOAT32 -attr {units,mm}
detdist=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS distance \
-type DFNT_FLOAT32 -attr {units,mm}
dettime=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS time_binning \
-type DFNT_FLOAT32 -rank 1 -dim {$(timebin)} -attr {axis,3} \
-attr {units,ms}
spinup=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS spinup \
-type DFNT_INT32 -rank 3 -dim {$(detsize),$(detsize),$(timebin)} \
-attr {signal,1}
spindown=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS spindown \
-type DFNT_INT32 -rank 3 -dim {$(detsize),$(detsize),$(timebin)} \
-attr {signal,1}
#------------ detector: scan mode
scanroot=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS
sdetx=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS x \
-type DFNT_FLOAT32 -attr {units,mm}
sdetom=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS omega \
-type DFNT_FLOAT32 -attr {units,degree}
sdetheight=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS height \
-type DFNT_FLOAT32 -attr {units,mm}
spinupup=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS spinup_upper \
-type DFNT_INT32 -rank 1 -dim {$(scanlength)} -attr {signal,1}
spindownup=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS \
spindown_upper \
-type DFNT_INT32 -rank 1 -dim {$(scanlength)} -attr {signal,2}
spinuplo=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS spinup_lower \
-type DFNT_INT32 -rank 1 -dim {$(scanlength)} -attr {signal,3}
spindownlo=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS \
spindown_lower \
-type DFNT_INT32 -rank 1 -dim {$(scanlength)} -attr {signal,4}
somega=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS \
omega -attr {units,degree} \
-type DFNT_FLOAT32 -rank 1 -dim {$(scanlength)} -attr {axis,1}
smonitor1=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS \
monitor1 \
-type DFNT_INT32 -rank 1 -dim {$(scanlength)}
smonitor2=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS \
monitor2 \
-type DFNT_INT32 -rank 1 -dim {$(scanlength)}
stime=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS \
time \
-type DFNT_FLOAT32 -rank 1 -dim {$(scanlength)} -attr {units,s}
sdetdist=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS distance \
-type DFNT_FLOAT32 -attr {units,mm}
#------------------- data vGroup
dana=/entry1,NXentry/TOF,NXdata/NXVGROUP
sdana=/entry1,NXentry/scan,NXdata/NXVGROUP

634
amor2t.c Normal file
View File

@ -0,0 +1,634 @@
/*---------------------------------------------------------------------------
A M O R 2 T
A class for controlling the two theta movement of the reflectometer
AMOR at SINQ. It is not clear if this class may be useful for other
reflectometers, too. At AMOR the two theta movement of the detector is
realized by translating the detector along x and z. Also it can be
tilted in omega. Furthermore the height of two diaphragms has to be
adjusted when moving two theta as well. In polarizing mode the analyzer
mirror has to be moved as well.
copyright: see copyright.h
Mark Koennecke, September 1999
---------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include "fortify.h"
#include <tcl.h>
#include "sics.h"
#include "motor.h"
#include "obpar.h"
#define DEBUG 1
#define MAXMOT 9
#define MAXPAR 8
#include "amor2t.i"
#include "amor2t.h"
/*
Defines for accessing various motors and variables. Definition of motor: see
annotated AMOR drawing.
*/
/* monochromator omega */
#define MOTMOM 0
/* sample omega */
#define MOTSOM 1
/* detector height movement */
#define MOTCOZ 2
/* detector movement along main axis */
#define MOTCOX 3
/* sample holder height movement */
#define MOTSTZ 4
/* whole sample table height movement */
#define MOTSOZ 5
/* lift for diaphragm 4*/
#define MOTD4B 6
/* lift for diaphragm 5 */
#define MOTD5B 7
/* detector omega movement */
#define MOTCOM 8
/* distance detector sample */
#define PARDS 0
/* constant height of sample: height = PARDH + MOTSOZ + MOTSTZ */
#define PARDH 1
/* distance diaphragm 4 - sample */
#define PARDD4 2
/* distance to diaphragm 5 */
#define PARDD5 3
/* interrupt to issue when a motor fails on this */
#define PARINT 4
/* base height of counter station */
#define PARDDH 5
/* height of D4 */
#define PARD4H 6
/* height of D5 */
#define PARD5H 7
/*======================================================================
The core of it all: The calculation of the settings for the various
motors.
========================================================================*/
static int CalculateAMORE(pAmor2T self, SConnection *pCon, float fNew)
{
float fMOM, fSOM, fSTZ, fSOZ;
double fAngle, fX, fZ, fBase, fPIR;
float fCOZ, fCOX, fCOM;
int iRet;
#ifdef DEBUG
char pBueffel[132];
#endif
/* get the necessary angles first */
iRet = MotorGetSoftPosition(self->aEngine[MOTMOM],pCon,&fMOM);
if(iRet != 1)
{
return iRet;
}
iRet = MotorGetSoftPosition(self->aEngine[MOTSOM],pCon,&fSOM);
if(iRet != 1)
{
return iRet;
}
iRet = MotorGetSoftPosition(self->aEngine[MOTSTZ],pCon,&fSTZ);
if(iRet != 1)
{
return iRet;
}
iRet = MotorGetSoftPosition(self->aEngine[MOTSOZ],pCon,&fSOZ);
if(iRet != 1)
{
return iRet;
}
/* calculate base height of sample table */
fBase = fSTZ + fSOZ + ObVal(self->aParameter,PARDH);
fPIR = 180. / 3.1415926;
/* calculation for detector */
fAngle = fNew - 2*fMOM;
if(fAngle < 0)
{
fAngle = fAngle + 360.;
}
fAngle /= fPIR;
fX = ObVal(self->aParameter,PARDS)*cos(fAngle);
fZ = ObVal(self->aParameter,PARDS)*sin(fAngle);
self->toStart[0].pMot = self->aEngine[MOTCOX];
strcpy(self->toStart[0].pName,self->aEngine[MOTCOX]->name);
self->toStart[0].fTarget = fX - ObVal(self->aParameter,PARDS);
self->toStart[1].pMot = self->aEngine[MOTCOZ];
strcpy(self->toStart[1].pName,self->aEngine[MOTCOZ]->name);
self->toStart[1].fTarget = fZ + fBase -
ObVal(self->aParameter,PARDDH);
self->toStart[2].pMot = self->aEngine[MOTCOM];
strcpy(self->toStart[2].pName,self->aEngine[MOTCOM]->name);
self->toStart[2].fTarget = fNew - 2*fMOM;
self->iStart = 3;
/* calculation for diaphragm 4 */
fZ = ObVal(self->aParameter,PARDD4) * sin(fAngle);
self->toStart[3].pMot = self->aEngine[MOTD4B];
strcpy(self->toStart[3].pName,self->aEngine[MOTD4B]->name);
self->toStart[3].fTarget = fBase + fZ -
ObVal(self->aParameter,PARD4H);
self->iStart = 4;
/* calculation for diaphragm 5 */
fZ = ObVal(self->aParameter,PARDD5) * sin(fAngle);
self->toStart[4].pMot = self->aEngine[MOTD5B];
strcpy(self->toStart[4].pName,self->aEngine[MOTD5B]->name);
self->toStart[4].fTarget = fBase + fZ -
ObVal(self->aParameter,PARD5H);
self->iStart = 5;
#ifdef DEBUG
sprintf(pBueffel,"2T COZ COX COM D4B D5B ");
SCWrite(pCon,pBueffel,eValue);
sprintf(pBueffel,"%6.2f %6.2f %6.2f %6.2f %6.2f %6.2f",
fNew, self->toStart[1].fTarget, self->toStart[0].fTarget,
self->toStart[2].fTarget, self->toStart[3].fTarget,
self->toStart[4].fTarget);
SCWrite(pCon,pBueffel,eValue);
#endif
return 1;
}
/*========================================================================
Definition of interface functions.
=========================================================================*/
static long A2TSetValue(void *pData, SConnection *pCon, float fNew)
{
int i, iRet;
pIDrivable pDriv = NULL;
pAmor2T self = (pAmor2T) pData;
assert(self);
/* calculation */
iRet = CalculateAMORE(self,pCon,fNew);
if(iRet != 1)
{
return iRet;
}
/* start them all */
for(i = 0; i < self->iStart; i++)
{
pDriv = self->toStart[i].pMot->pDescriptor->GetInterface(
self->toStart[i].pMot,DRIVEID);
if(pDriv != NULL)
{
iRet = pDriv->SetValue(self->toStart[i].pMot,pCon,
self->toStart[i].fTarget);
if(iRet != OKOK)
{
return iRet;
}
}
}
return OKOK;
}
/*-------------------------------------------------------------------------*/
static int A2THalt(void *pData)
{
int i, iRet;
pIDrivable pDriv = NULL;
pAmor2T self = (pAmor2T) pData;
assert(self);
/* stop them all */
for(i = 0; i < self->iStart; i++)
{
pDriv = self->toStart[i].pMot->pDescriptor->GetInterface(
self->toStart[i].pMot,DRIVEID);
if(pDriv != NULL)
{
iRet = pDriv->Halt(self->toStart[i].pMot);
}
}
return OKOK;
}
/*-----------------------------------------------------------------------*/
static int A2TCheck(void *pData, float fNew, char *error, int iErrLen)
{
int i, iRet;
pIDrivable pDriv = NULL;
pAmor2T self = (pAmor2T) pData;
SConnection *pDumCon = NULL;
assert(self);
pDumCon = SCCreateDummyConnection(pServ->pSics);
assert(pDumCon);
/* calculation */
iRet = CalculateAMORE(self,pDumCon,fNew);
SCDeleteConnection(pDumCon);
if(iRet != 1)
{
return iRet;
}
/* check them all */
for(i = 0; i < self->iStart; i++)
{
pDriv = self->toStart[i].pMot->pDescriptor->GetInterface(
self->toStart[i].pMot,DRIVEID);
if(pDriv != NULL)
{
iRet = pDriv->CheckLimits(self->toStart[i].pMot,
self->toStart[i].fTarget,
error,iErrLen);
if(iRet != 1)
{
return iRet;
}
}
}
return 1;
}
/*------------------------------------------------------------------------*/
static int A2TStatus(void *pData, SConnection *pCon)
{
int i, iRet;
pIDrivable pDriv = NULL;
pAmor2T self = (pAmor2T) pData;
assert(self);
/* check them all */
for(i = 0; i < self->iStart; i++)
{
pDriv = self->toStart[i].pMot->pDescriptor->GetInterface(
self->toStart[i].pMot,DRIVEID);
if(pDriv != NULL)
{
iRet = pDriv->CheckStatus(self->toStart[i].pMot,pCon);
if( (iRet != OKOK) && (iRet != HWIdle) )
{
return iRet;
}
}
}
return iRet;
}
/*------------------------------------------------------------------------*/
static float A2TGetValue(void *pData, SConnection *pCon)
{
float fVal, fMOM, fResult;
int iRet;
pIDrivable pDriv = NULL;
pAmor2T self = (pAmor2T) pData;
assert(self);
/* get COM */
pDriv = self->aEngine[MOTCOM]->pDescriptor->GetInterface(
self->aEngine[MOTCOM],DRIVEID);
if(pDriv)
{
fVal = pDriv->GetValue(self->aEngine[MOTCOM],pCon);
if(fVal < -9000)
{
return fVal;
}
}
/* get MOM */
pDriv = self->aEngine[MOTCOM]->pDescriptor->GetInterface(
self->aEngine[MOTMOM],DRIVEID);
if(pDriv)
{
fMOM = pDriv->GetValue(self->aEngine[MOTMOM],pCon);
if(fMOM < -9000)
{
return fMOM;
}
}
/* retrocalculate 2 theta */
fResult = fVal + 2*fMOM;
return fResult;
}
/*-----------------------------------------------------------------------*/
static void *A2TGetInterface(void *pData, int iID)
{
pAmor2T self = (pAmor2T) pData;
assert(self);
if(iID == DRIVEID)
{
return self->pDriv;
}
return NULL;
}
/*------------------------------------------------------------------------*/
static int A2TSave(void *pData, char *name, FILE *fd)
{
int i;
pAmor2T self = (pAmor2T) pData;
assert(self);
fprintf(fd,"%s detectord %f \n", name, ObVal(self->aParameter,PARDS));
fprintf(fd,"%s sampleh %f \n", name, ObVal(self->aParameter,PARDH));
fprintf(fd,"%s d4d %f \n", name, ObVal(self->aParameter,PARDD4));
fprintf(fd,"%s d5d %f \n", name, ObVal(self->aParameter,PARDD5));
fprintf(fd,"%s interrupt %f \n", name, ObVal(self->aParameter,PARINT));
fprintf(fd,"%s detectorh %f \n", name, ObVal(self->aParameter,PARDDH));
fprintf(fd,"%s d4h %f \n", name, ObVal(self->aParameter,PARD4H));
fprintf(fd,"%s d5h %f \n", name, ObVal(self->aParameter,PARD5H));
return 1;
}
/*------------------------------------------------------------------------*/
static void A2TKill(void *pData)
{
pAmor2T self = (pAmor2T) pData;
if(self == NULL)
return;
if(self->pDes)
DeleteDescriptor(self->pDes);
if(self->pDriv)
free(self->pDriv);
if(self->aParameter)
ObParDelete(self->aParameter);
free(self);
}
/*--------------------------------------------------------------------------
Initialization: All is done from the Factory function. This takes an Tcl
array as parameter which is supposed to hold the names of all motors.
This must fail if one of the motors cannot be accessed.
--------------------------------------------------------------------------*/
int Amor2TFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
pAmor2T pNew = NULL;
int i, iRet;
char pBueffel[512];
char *pMot = NULL;
if(argc < 3)
{
SCWrite(pCon,
"ERROR: Insufficient number of arguments to Amor2tFactory",
eError);
return 0;
}
/* allocate space ..............*/
pNew = (pAmor2T)malloc(sizeof(Amor2T));
if(!pNew)
{
SCWrite(pCon,"ERROR: out of memory in Amor2TFactory",eError);
return 0;
}
memset(pNew,0,sizeof(Amor2T));
pNew->pDes = CreateDescriptor("Amor2T");
pNew->aParameter = ObParCreate(MAXPAR);
pNew->pDriv = CreateDrivableInterface();
if( (!pNew->pDes) || (!pNew->aParameter) || (!pNew->pDriv) )
{
SCWrite(pCon,"ERROR: out of memory in Amor2TFactory",eError);
A2TKill(pNew);
return 0;
}
/* find the motors*/
pMot = Tcl_GetVar2(pSics->pTcl,argv[2],"mom",TCL_GLOBAL_ONLY);
if(!pMot)
{
SCWrite(pCon,"ERROR: no value for mom motr found",eError);
A2TKill(pNew);
return 0;
}
pNew->aEngine[MOTMOM] = FindMotor(pSics,pMot);
if(!pNew->aEngine[MOTMOM])
{
sprintf(pBueffel,"ERROR: motor %s NOT found!", pMot);
A2TKill(pNew);
return 0;
}
pMot = Tcl_GetVar2(pSics->pTcl,argv[2],"som",TCL_GLOBAL_ONLY);
if(!pMot)
{
SCWrite(pCon,"ERROR: no value for som motor found",eError);
A2TKill(pNew);
return 0;
}
pNew->aEngine[MOTSOM] = FindMotor(pSics,pMot);
if(!pNew->aEngine[MOTSOM])
{
sprintf(pBueffel,"ERROR: motor %s NOT found!", pMot);
A2TKill(pNew);
return 0;
}
pMot = Tcl_GetVar2(pSics->pTcl,argv[2],"coz",TCL_GLOBAL_ONLY);
if(!pMot)
{
SCWrite(pCon,"ERROR: no value for coz motor found",eError);
A2TKill(pNew);
return 0;
}
pNew->aEngine[MOTCOZ] = FindMotor(pSics,pMot);
if(!pNew->aEngine[MOTCOZ])
{
sprintf(pBueffel,"ERROR: motor %s NOT found!", pMot);
A2TKill(pNew);
return 0;
}
pMot = Tcl_GetVar2(pSics->pTcl,argv[2],"cox",TCL_GLOBAL_ONLY);
if(!pMot)
{
SCWrite(pCon,"ERROR: no value for cox motor found",eError);
A2TKill(pNew);
return 0;
}
pNew->aEngine[MOTCOX] = FindMotor(pSics,pMot);
if(!pNew->aEngine[MOTCOX])
{
sprintf(pBueffel,"ERROR: motor %s NOT found!", pMot);
A2TKill(pNew);
return 0;
}
pMot = Tcl_GetVar2(pSics->pTcl,argv[2],"stz",TCL_GLOBAL_ONLY);
if(!pMot)
{
SCWrite(pCon,"ERROR: no value for stz motor found",eError);
A2TKill(pNew);
return 0;
}
pNew->aEngine[MOTSTZ] = FindMotor(pSics,pMot);
if(!pNew->aEngine[MOTSTZ])
{
sprintf(pBueffel,"ERROR: motor %s NOT found!", pMot);
A2TKill(pNew);
return 0;
}
pMot = Tcl_GetVar2(pSics->pTcl,argv[2],"soz",TCL_GLOBAL_ONLY);
if(!pMot)
{
SCWrite(pCon,"ERROR: no value for soz motor found",eError);
A2TKill(pNew);
return 0;
}
pNew->aEngine[MOTSOZ] = FindMotor(pSics,pMot);
if(!pNew->aEngine[MOTSOZ])
{
sprintf(pBueffel,"ERROR: motor %s NOT found!", pMot);
A2TKill(pNew);
return 0;
}
pMot = Tcl_GetVar2(pSics->pTcl,argv[2],"d4b",TCL_GLOBAL_ONLY);
if(!pMot)
{
SCWrite(pCon,"ERROR: no value for d4b motor found",eError);
A2TKill(pNew);
return 0;
}
pNew->aEngine[MOTD4B] = FindMotor(pSics,pMot);
if(!pNew->aEngine[MOTD4B])
{
sprintf(pBueffel,"ERROR: motor %s NOT found!", pMot);
A2TKill(pNew);
return 0;
}
pMot = Tcl_GetVar2(pSics->pTcl,argv[2],"d5b",TCL_GLOBAL_ONLY);
if(!pMot)
{
SCWrite(pCon,"ERROR: no value for d5b motor found",eError);
A2TKill(pNew);
return 0;
}
pNew->aEngine[MOTD5B] = FindMotor(pSics,pMot);
if(!pNew->aEngine[MOTD5B])
{
sprintf(pBueffel,"ERROR: motor %s NOT found!", pMot);
A2TKill(pNew);
return 0;
}
pMot = Tcl_GetVar2(pSics->pTcl,argv[2],"com",TCL_GLOBAL_ONLY);
if(!pMot)
{
SCWrite(pCon,"ERROR: no value for com motor found",eError);
A2TKill(pNew);
return 0;
}
pNew->aEngine[MOTCOM] = FindMotor(pSics,pMot);
if(!pNew->aEngine[MOTCOM])
{
sprintf(pBueffel,"ERROR: motor %s NOT found!", pMot);
A2TKill(pNew);
return 0;
}
/* initialize parameters */
ObParInit(pNew->aParameter,PARDS,"detectord",400.,usMugger);
ObParInit(pNew->aParameter,PARDH,"sampleh",50.,usMugger);
ObParInit(pNew->aParameter,PARDD4,"d4d",100.,usMugger);
ObParInit(pNew->aParameter,PARDD5,"d5d",200.,usMugger);
ObParInit(pNew->aParameter,PARINT,"interrupt",0.,usMugger);
ObParInit(pNew->aParameter,PARDDH,"detectorh",40.,usMugger);
ObParInit(pNew->aParameter,PARD4H,"d4h",40.,usMugger);
ObParInit(pNew->aParameter,PARD5H,"d5h",400.,usMugger);
/* initialize interfaces */
pNew->pDes->GetInterface = A2TGetInterface;
pNew->pDes->SaveStatus = A2TSave;
pNew->pDriv->Halt = A2THalt;
pNew->pDriv->CheckLimits = A2TCheck;
pNew->pDriv->SetValue = A2TSetValue;
pNew->pDriv->CheckStatus = A2TStatus;
pNew->pDriv->GetValue = A2TGetValue;
/* install command */
iRet = AddCommand(pSics,argv[1],
Amor2TAction,A2TKill,pNew);
if(!iRet)
{
sprintf(pBueffel,"ERROR: duplicate command %s NOT created",
argv[1]);
SCWrite(pCon,pBueffel,eError);
A2TKill(pNew);
return 0;
}
return 1;
}
/*----------------------------------------------------------------------*/
int Amor2TAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
pAmor2T self = (pAmor2T)pData;
char pBueffel[256];
float fVal;
double dVal;
ObPar *pPar = NULL;
int iRet;
assert(self);
if(argc > 1)
{
strtolower(argv[1]);
if(argc >= 3)
{
iRet = Tcl_GetDouble(pSics->pTcl,argv[2],&dVal);
if(iRet != TCL_OK)
{
sprintf(pBueffel,"ERROR: failed to convert %s to number",
argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = ObParSet(self->aParameter,argv[0],argv[1],(float)dVal,pCon);
if(iRet)
{
SCSendOK(pCon);
}
return iRet;
}
else
{
pPar = ObParFind(self->aParameter,argv[1]);
if(!pPar)
{
sprintf(pBueffel,"ERROR: parameter %s NOT found",argv[1]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
sprintf(pBueffel,"%s.%s = %f",argv[0],pPar->name, pPar->fVal);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
}
else
{
fVal = self->pDriv->GetValue(self,pCon);
sprintf(pBueffel," %s = %f", argv[0], fVal);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
}

22
amor2t.h Normal file
View File

@ -0,0 +1,22 @@
/*-------------------------------------------------------------------------
A m o r 2 T
A class for controlling the two theta movement of a reflectometer.
Especially the AMOR reflectometer at SINQ. For details see the file
amor2t.tex. DO NOT TOUCH! This file is automatically created from amor2t.w
with nuweb.
Mark Koennecke, September 1999
---------------------------------------------------------------------------*/
#ifndef AMOR2T
#define AMOR2T
typedef struct __AMOR2T *pAmor2T;
int Amor2TFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int Amor2TAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
void Amor2TKill(void *pData);
#endif

27
amor2t.i Normal file
View File

@ -0,0 +1,27 @@
/*--------------------------------------------------------------------------
A m o r 2 T . i
Internal data structure definitions for Amor2T. For details see amor2t.tex.
DO NOT TOUCH! This file is automatically created from amor2t.w.
Mark Koennecke, September 1999
----------------------------------------------------------------------------*/
typedef struct {
pMotor pMot;
char pName[80];
float fTarget;
}MotEntry, *pMotEntry;
typedef struct __AMOR2T {
pObjectDescriptor pDes;
pIDrivable pDriv;
pMotor aEngine[MAXMOT];
MotEntry toStart[MAXMOT];
int iStart;
ObPar *aParameter;
}Amor2T;

176
amor2t.tex Normal file
View File

@ -0,0 +1,176 @@
\subsection{AMOR Two Theta}
AMOR is SINQ's new reflectometer. It has the peculiar feature that the
two theta movement of the detector is expressed in translations along
the reflectometer base axis and the detector height. Additionally the
detector is tilted. The height of two diaphragms has to be adjusted as
well. And, in polarizing mode, the analyzer has to be operated as
well. Quite a complicated movement. I fear this module may only be
useful for AMOR, but may be, other reflectometers may profit as well.
This object implements this complex movement as a virtual motor.
The following formulas are used for the necessary calculations:
\begin{eqnarray}
delta height & = & h_{s} - R \sin \alpha \\
delta x & = & |x_{c} - x_{s}| - R \cos \alpha \\
omega & = & -2 MOM + 2 SOM \\
\end{eqnarray}
with
\begin{eqnarray}
h_{s} & = & \tan(2MOM)|x_{c} - x_{s}| \\
R & = & \sqrt{hs^{2} - |x_{c} - x_{s}|^{2}} \\
\alpha & = & 180 -90 - \beta - 2SOM \\
\beta & = & 180 - 90 - 2MOM \\
MOM & = & polarizer \omega \\
SOM & = & sample \omega \\
x_{c} & = & counter position \\
x_{s} & = & sample position\\
\end{eqnarray}
The same equations hold true for the calculations of the diaphragm
heights, just replace the distances. The equations for the analyzer
are not yet known.
Due to this complicated movement this module needs to know about a lot
of motors and a lot of parameters. The distances of the various
components need to be modified at run time in order to allow for
configuration changes. These are not motorized but must be entered
manually.
\subsubsection{Data Structures}
Consequently data structures are complex. The first data structure
used is an entry in an array of motors to start:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$putput {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct {@\\
\mbox{}\verb@ pMotor pMot;@\\
\mbox{}\verb@ char pName[80];@\\
\mbox{}\verb@ float fTarget;@\\
\mbox{}\verb@ }MotEntry, *pMotEntry;@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{description}
\item[pMot] is a pointer to the motors data structure.
\item[pName] is the name of the motor to start.
\item[fTarget] is the target value for the motor.
\end{description}
The next data structure is the class data structure for amor2t:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$amoredata {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __AMOR2T {@\\
\mbox{}\verb@ pObjectDescriptor pDes;@\\
\mbox{}\verb@ pIDrivable pDriv;@\\
\mbox{}\verb@ pMotor aEngine[MAXMOT];@\\
\mbox{}\verb@ MotEntry toStart[MAXMOT];@\\
\mbox{}\verb@ int iStart;@\\
\mbox{}\verb@ ObPar *aParameter;@\\
\mbox{}\verb@ }Amor2T;@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{description}
\item[pDes] The standard SICS object descriptor.
\item[pDriv] The drivable interface. The functions defined for the
drivable interface implement most of the work of this class.
\item[aEngine] An array of pointers to the motor data structures this
class has to deal with. The proper initialization of this is taken
care of during the initialization of the object.
\item[toStart] An array of motors to start when all calculations have
been performed.
\item[iStart] The number of valid entries in toStart.
\item[aParameter] An array of parameters for this object.
\end{description}
\subsubsection{The Interface}
The interface to this module is quite primitive. Most of the
functionality is hidden in the drivable interface. So there are only
functions for interacting with the interpreter.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
$\langle$amorinterface {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __AMOR2T *pAmor2T;@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int Amor2TFactory(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ int Amor2TAction(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ void Amor2TKill(void *pData); @\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap4}
\verb@"amor2t.i"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------@\\
\mbox{}\verb@ A m o r 2 T . i@\\
\mbox{}\verb@ Internal data structure definitions for Amor2T. For details see amor2t.tex.@\\
\mbox{}\verb@ DO NOT TOUCH! This file is automatically created from amor2t.w.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, September 1999@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@@$\langle$putput {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\langle$amoredata {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap5}
\verb@"amor2t.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-------------------------------------------------------------------------@\\
\mbox{}\verb@ A m o r 2 T@\\
\mbox{}\verb@ A class for controlling the two theta movement of a reflectometer. @\\
\mbox{}\verb@ Especially the AMOR reflectometer at SINQ. For details see the file @\\
\mbox{}\verb@ amor2t.tex. DO NOT TOUCH! This file is automatically created from amor2t.w@\\
\mbox{}\verb@ with nuweb.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, September 1999@\\
\mbox{}\verb@---------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef AMOR2T@\\
\mbox{}\verb@#define AMOR2T@\\
\mbox{}\verb@@$\langle$amorinterface {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif @\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

122
amor2t.w Normal file
View File

@ -0,0 +1,122 @@
\subsection{AMOR Two Theta}
AMOR is SINQ's new reflectometer. It has the peculiar feature that the
two theta movement of the detector is expressed in translations along
the reflectometer base axis and the detector height. Additionally the
detector is tilted. The height of two diaphragms has to be adjusted as
well. And, in polarizing mode, the analyzer has to be operated as
well. Quite a complicated movement. I fear this module may only be
useful for AMOR, but may be, other reflectometers may profit as well.
This object implements this complex movement as a virtual motor.
The following formulas are used for the necessary calculations:
\begin{eqnarray}
delta height & = & h_{s} - R \sin \alpha \\
delta x & = & |x_{c} - x_{s}| - R \cos \alpha \\
omega & = & -2 MOM + 2 SOM \\
\end{eqnarray}
with
\begin{eqnarray}
h_{s} & = & \tan(2MOM)|x_{c} - x_{s}| \\
R & = & \sqrt{hs^{2} - |x_{c} - x_{s}|^{2}} \\
\alpha & = & 180 -90 - \beta - 2SOM \\
\beta & = & 180 - 90 - 2MOM \\
MOM & = & polarizer \omega \\
SOM & = & sample \omega \\
x_{c} & = & counter position \\
x_{s} & = & sample position\\
\end{eqnarray}
The same equations hold true for the calculations of the diaphragm
heights, just replace the distances. The equations for the analyzer
are not yet known.
Due to this complicated movement this module needs to know about a lot
of motors and a lot of parameters. The distances of the various
components need to be modified at run time in order to allow for
configuration changes. These are not motorized but must be entered
manually.
\subsubsection{Data Structures}
Consequently data structures are complex. The first data structure
used is an entry in an array of motors to start:
@d putput @{
typedef struct {
pMotor pMot;
char pName[80];
float fTarget;
}MotEntry, *pMotEntry;
@}
\begin{description}
\item[pMot] is a pointer to the motors data structure.
\item[pName] is the name of the motor to start.
\item[fTarget] is the target value for the motor.
\end{description}
The next data structure is the class data structure for amor2t:
@d amoredata @{
typedef struct __AMOR2T {
pObjectDescriptor pDes;
pIDrivable pDriv;
pMotor aEngine[MAXMOT];
MotEntry toStart[MAXMOT];
int iStart;
ObPar *aParameter;
}Amor2T;
@}
\begin{description}
\item[pDes] The standard SICS object descriptor.
\item[pDriv] The drivable interface. The functions defined for the
drivable interface implement most of the work of this class.
\item[aEngine] An array of pointers to the motor data structures this
class has to deal with. The proper initialization of this is taken
care of during the initialization of the object.
\item[toStart] An array of motors to start when all calculations have
been performed.
\item[iStart] The number of valid entries in toStart.
\item[aParameter] An array of parameters for this object.
\end{description}
\subsubsection{The Interface}
The interface to this module is quite primitive. Most of the
functionality is hidden in the drivable interface. So there are only
functions for interacting with the interpreter.
@d amorinterface @{
typedef struct __AMOR2T *pAmor2T;
int Amor2TFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int Amor2TAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
void Amor2TKill(void *pData);
@}
@o amor2t.i @{
/*--------------------------------------------------------------------------
A m o r 2 T . i
Internal data structure definitions for Amor2T. For details see amor2t.tex.
DO NOT TOUCH! This file is automatically created from amor2t.w.
Mark Koennecke, September 1999
----------------------------------------------------------------------------*/
@<putput@>
@<amoredata@>
@}
@o amor2t.h @{
/*-------------------------------------------------------------------------
A m o r 2 T
A class for controlling the two theta movement of a reflectometer.
Especially the AMOR reflectometer at SINQ. For details see the file
amor2t.tex. DO NOT TOUCH! This file is automatically created from amor2t.w
with nuweb.
Mark Koennecke, September 1999
---------------------------------------------------------------------------*/
#ifndef AMOR2T
#define AMOR2T
@<amorinterface@>
#endif
@}

23
amorpar.tcl Normal file
View File

@ -0,0 +1,23 @@
#--------------------------------------------------------------------------
# A SICS-tcl-macro script for formatting the parameters for the
# reflectometer AMOR's status display.
#
# Mark Koennecke, October 1999
#-------------------------------------------------------------------------
proc amorpar {} {
lappend list "amorpar == "
lappend list [lastscancommand] ";"
catch {scan getvars} msg
lappend list $msg ";"
lappend list [xxxscan getfile] ";"
lappend list [sicstime] ";"
set ret [catch {temperature} msg]
if {$ret == 0} {
lappend list $msg
}
set ret [catch {magnet} msg]
if {$ret == 0} {
lappend list $msg
}
return [join $list]
}

140
amorscan.c Normal file
View File

@ -0,0 +1,140 @@
/*-------------------------------------------------------------------------
A M O R S C A N
An adaption of the general scan routine to deal with special issues at
the reflectometer AMOR at SINQ.
copyright: see copyright.h
Mark Koennecke, September 1999
--------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include "fortify.h"
#include "sics.h"
#include "scan.h"
#include "scan.i"
#include "HistMem.h"
#include "nxamor.h"
#include "amorscan.h"
/*--------------------------------------------------------------------*/
static int AmorHeader(pScanData self)
{
return WriteAmorHeader(self->pFile, self->pCon);
}
/*--------------------------------------------------------------------*/
static int AmorPoints(pScanData self, int iP)
{
/* write only at last scan point */
if((iP+1) >= self->iNP)
{
return WriteAmorScan(self->pFile,self->pCon,self);
}
}
/*--------------------------------------------------------------------*/
static int AmorCollect(pScanData self, int iP)
{
pVarEntry pVar = NULL;
void *pDings;
int i, iRet, status;
float fVal;
char pStatus[512], pItem[20];
char pHead[512];
CountEntry sCount;
assert(self);
assert(self->pCon);
/* prepare output header */
sprintf(pHead,"%-5.5s","NP");
sprintf(pStatus,"%-5d",iP);
/* loop over all scan variables */
status = 1;
for(i = 0; i < self->iScanVar; i++)
{
DynarGet(self->pScanVar,i,&pDings);
pVar = (pVarEntry)pDings;
if(pVar)
{
fVal = pVar->pInter->GetValue(pVar->pObject,self->pCon);
pVar->fData[iP] = fVal;
sprintf(pItem,"%-10.10s",pVar->Name);
strcat(pHead,pItem);
sprintf(pItem,"%-10.3f",fVal);
strcat(pStatus,pItem);
}
}
/* store counter data */
/* monitors */
for(i = 1; i < 10; i++)
{
sCount.Monitors[i-1] = GetMonitor((pCounter)self->pCounterData,i,
self->pCon);
}
if( self->iChannel != 0 && self->iChannel != -10 )
{
sCount.Monitors[self->iChannel - 1] =
GetCounts((pCounter)self->pCounterData,
self->pCon);
}
/* counter1 */
strcat(pHead,"Counter1 ");
sCount.lCount = GetCounts((pCounter)self->pCounterData,self->pCon);
sprintf(pItem,"%-15d",sCount.lCount);
strcat(pStatus,pItem);
/*
WARNING
Assignements have to be checked when the Schlumpfes are
ready putting the counter box together.
*/
/* counter2 */
strcat(pHead,"Counter2 ");
sCount.Monitors[0] = GetMonitor((pCounter)self->pCounterData,
1,self->pCon);
sprintf(pItem,"%-15d",sCount.Monitors[0]);
strcat(pStatus,pItem);
/* monitors */
sCount.Monitors[3] = GetMonitor((pCounter)self->pCounterData,
2,self->pCon);
sCount.Monitors[4] = GetMonitor((pCounter)self->pCounterData,
3,self->pCon);
/* get time */
sCount.fTime = GetCountTime((pCounter)self->pCounterData,
self->pCon);
strcat(pHead,"Monitor1 ");
sprintf(pItem,"%-12d",sCount.Monitors[3]);
strcat(pStatus,pItem);
strcat(pHead,"Monitor2 ");
sprintf(pItem,"%-12d",sCount.Monitors[4]);
strcat(pStatus,pItem);
strcat(pHead,"Time ");
sprintf(pItem,"%-6.1f",sCount.fTime);
strcat(pStatus,pItem);
/* write progress */
strcat(pHead,"\n");
strcat(pStatus,"\n");
SCWrite(self->pCon,pHead,eWarning);
SCWrite(self->pCon,pStatus,eWarning);
/* stow away */
DynarReplace(self->pCounts,self->iCounts,&sCount,sizeof(CountEntry));
self->iCounts++;
return 1;
}
/*-----------------------------------------------------------------------*/
int ConfigureAmor(pScanData self)
{
self->WriteHeader = AmorHeader;
self->WriteScanPoints = AmorPoints;
self->CollectScanData = AmorCollect;
strcpy(self->ext,".hdf");
return 1;
}

15
amorscan.h Normal file
View File

@ -0,0 +1,15 @@
/*-----------------------------------------------------------------------
A M O R S C A N
Adaption of the scan command to do things specific to the
reflectometer AMOR at SINQ.
Mark Koennecke, September 1999
-----------------------------------------------------------------------*/
#ifndef AMORSCAN
#define AMORSCAN
int ConfigureAmor(pScanData pScan);
#endif

71
amorscan.tex Normal file
View File

@ -0,0 +1,71 @@
\subsection{Amor Scan}
This is a special adaption of the general scan routines for the
reflectometer AMOR at SINQ. It works by replacing the configurable
routines in the general scan command with special ones, suited to the
reflectometers purpose. There are several adaptions to the standard
scan command:
\begin{itemize}
\item Data is written to NeXus files instead of ASCII files.
\item There are two counters to keep track of.
\item Furthermore stubs are provided for dealing with spin flippers.
\end{itemize}
In order to keep track of counters and monitors the following
convention has been devised:
\begin{itemize}
\item GetCounts gets the main detector.
\item GetMonitor 0 the second detector
\item GetMonitor 1 the first detector other spin
\item GetMonitor 2 the second detector other spin
\item GetMonitor 3 the first monitor
\item GetMonitor 4 the second monitor
\end{itemize}
Thus the monitor channels are used to keep the additional counter
information.
This module provides only one external function:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$amorscan {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ int ConfigureAmor(pScanData pScan);@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
which configures the variable fields and function pointers in pScan to
functions defined in this module. These then do the right thing. This
module is also an example of how the scan command can be configured to do
tricks based on the syntax and hooks defined in scan.*.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
\verb@"amorscan.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-----------------------------------------------------------------------@\\
\mbox{}\verb@ A M O R S C A N@\\
\mbox{}\verb@ Adaption of the scan command to do things specific to the@\\
\mbox{}\verb@ reflectometer AMOR at SINQ.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, September 1999@\\
\mbox{}\verb@-----------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef AMORSCAN@\\
\mbox{}\verb@#define AMORSCAN@\\
\mbox{}\verb@@$\langle$amorscan {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

57
amorscan.w Normal file
View File

@ -0,0 +1,57 @@
\subsection{Amor Scan}
This is a special adaption of the general scan routines for the
reflectometer AMOR at SINQ. It works by replacing the configurable
routines in the general scan command with special ones, suited to the
reflectometers purpose. There are several adaptions to the standard
scan command:
\begin{itemize}
\item Data is written to NeXus files instead of ASCII files.
\item There are two counters to keep track of.
\item Furthermore stubs are provided for dealing with spin flippers.
\end{itemize}
In order to keep track of counters and monitors the following
convention has been devised:
\begin{itemize}
\item GetCounts gets the main detector.
\item GetMonitor 0 the second detector
\item GetMonitor 1 the first detector other spin
\item GetMonitor 2 the second detector other spin
\item GetMonitor 3 the first monitor
\item GetMonitor 4 the second monitor
\end{itemize}
Thus the monitor channels are used to keep the additional counter
information.
This module provides only one external function:
@d amorscan @{
int ConfigureAmor(pScanData pScan);
@}
which configures the variable fields and function pointers in pScan to
functions defined in this module. These then do the right thing. This
module is also an example of how the scan command can be configured to do
tricks based on the syntax and hooks defined in scan.*.
@o amorscan.h @{
/*-----------------------------------------------------------------------
A M O R S C A N
Adaption of the scan command to do things specific to the
reflectometer AMOR at SINQ.
Mark Koennecke, September 1999
-----------------------------------------------------------------------*/
#ifndef AMORSCAN
#define AMORSCAN
@<amorscan@>
#endif
@}

772
amorstat.c Normal file
View File

@ -0,0 +1,772 @@
/*--------------------------------------------------------------------------
A M O R S T A T U S
The implementation file for the amor status display facilitator module. The
reflectometer AMOR needs some advanced feautures for its status display.
These needs are taken care of here.
copyright: see copyright.h
Mark Koennecke, September 1999
--------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <tcl.h>
#include "fortify.h"
#include "sics.h"
#include "counter.h"
#include "HistMem.h"
#include "scan.h"
#include "lld.h"
#include "amorstat.i"
#include "amorstat.h"
/*-------------------------------------------------------------------------
A static which determines if we are in TOF or scan mode.
*/
static int iTOF = 0;
static pHistMem pHMHM = NULL;
/*-------------------------------------------------------------------------*/
static int HMCountStartCallback(int iEvent, void *pEvent, void *pUser)
{
SConnection *pCon = (SConnection *)pUser;
const float *fTime = NULL;
int *iTime = NULL;
int iLength, iRet, i;
assert(pCon);
if(iEvent == COUNTSTART)
{
/* send current time binning */
iTOF = 1;
fTime = GetHistTimeBin(pHMHM,&iLength);
iTime = (int *)malloc((iLength+1)*sizeof(int));
if( (!fTime) || (!iTime))
{
return 0;
}
iTime[0] = htonl(iLength);
for(i = 0 ; i < iLength; i++)
{
iTime[i+1] = htonl((int)(fTime[i]*65536.));
}
/* send new time binning to all clients */
SCWrite(pCon,"TOFClear",eError);
SCWriteUUencoded(pCon,"arrowaxis_time",iTime,
(iLength+1)*sizeof(int));
free(iTime);
}
return 1;
}
/*-------------------------------------------------------------------------*/
static int ScanStartCallback(int iEvent, void *pEvent, void *pUser)
{
float *fAxis = NULL;
int *iAxis = NULL;
int iLength, iRet, i;
char pBueffel[80], pName[40];
SConnection *pCon = (SConnection *)pUser;
pScanData pScan = (pScanData)pEvent;
assert(pCon);
assert(pScan);
if(iEvent == SCANSTART)
{
iTOF = 0;
/* send current axis */
iLength = GetScanNP(pScan);
fAxis = (float *)malloc((iLength+1)*sizeof(float));
iAxis = (int *)malloc((iLength+1)*sizeof(int));
if( (!fAxis) || (!iAxis))
{
return 0;
}
iAxis[0] = htonl(iLength);
GetScanVar(pScan,0,fAxis,iLength);
GetScanVarName(pScan,0,pName,39);
sprintf(pBueffel,"arrowaxis_%s",pName);
for(i = 0 ; i < iLength; i++)
{
iAxis[i+1] = htonl((int)(fAxis[i]*65536.));
}
/* send new axis to client */
SCWrite(pCon,"SCANClear",eError);
SCWriteUUencoded(pCon,pBueffel,iAxis,
(iLength+1)*sizeof(int));
free(iAxis);
free(fAxis);
}
return 1;
}
/*------------------------------------------------------------------------*/
static int ScanPointCallback(int iEvent, void *pEvent, void *pUser)
{
long *lData = NULL;
int *iData = NULL;
int iLength, iRet, i;
SConnection *pCon = (SConnection *)pUser;
pScanData pScan = (pScanData)pEvent;
assert(pCon);
assert(pScan);
if( (iEvent == SCANPOINT) || (iEvent == SCANEND) )
{
/* send current data */
iTOF = 0;
iLength = GetScanNP(pScan);
lData = (long *)malloc((iLength+1)*sizeof(long));
iData = (int *)malloc((iLength+1)*sizeof(int));
if( (!lData) || (!iData))
{
return 0;
}
iData[0] = htonl(iLength);
GetScanCounts(pScan,lData,iLength);
for(i = 0 ; i < iLength; i++)
{
iData[i+1] = htonl((int)(lData[i]));
}
/* send counts to client */
SCWriteUUencoded(pCon,"arrow_spinupup",iData,
(iLength+1)*sizeof(int));
/* send counts for other detector */
GetScanMonitor(pScan,0,lData,iLength);
for(i = 0 ; i < iLength; i++)
{
iData[i+1] = htonl((int)(lData[i]));
}
SCWriteUUencoded(pCon,"arrow_spinuplo",iData,
(iLength+1)*sizeof(int));
/* to do: check for polarization and send spinlo */
free(iData);
free(lData);
}
return 1;
}
/*------------------------------------------------------------------------*/
static int SendLoadedData(pAmorStat self, SConnection *pCon)
{
int i, iRet, *iData = NULL;
char pBueffel[80];
UserData ud;
SCWrite(pCon,"loaded_CLEAR",eValue);
iRet = LLDnodePtr2First(self->iUserList);
while(iRet != 0)
{
LLDnodeDataTo(self->iUserList,&ud);
iData = (int *)malloc((ud.iNP*2 + 1)*sizeof(int));
if(!iData)
{
return 0;
}
iData[0] = htonl(ud.iNP);
for(i = 0; i < ud.iNP; i++)
{
iData[i+1] = htonl((int)(ud.fX[i]*65536));
iData[i+1+ud.iNP] = htonl((int)(ud.fY[i]*65536));
}
sprintf(pBueffel,"loaded_%s",ud.name);
SCWriteUUencoded(pCon,pBueffel,iData,(ud.iNP*2+1)*sizeof(int));
iRet = LLDnodePtr2Next(self->iUserList);
}
}
/*------------------------------------------------------------------------*/
static int LoadCallback(int iEvent, void *pEvent, void *pUser)
{
pAmorStat pAS = NULL;
SConnection *pCon = NULL;
if(iEvent == FILELOADED)
{
pAS = (pAmorStat)pEvent;
pCon = (SConnection *)pUser;
assert(pAS);
assert(pCon);
SendLoadedData(pAS,pCon);
}
return 1;
}
/*-------------------------------------------------------------------------*/
static void ClearUserData(pAmorStat self)
{
int iRet;
UserData ud;
iRet = LLDnodePtr2First(self->iUserList);
while(iRet != NULL)
{
LLDnodeDataTo(self->iUserList,&ud);
if(ud.fX != NULL)
free(ud.fX);
if(ud.fY != NULL)
free(ud.fY);
if(ud.name != NULL)
free(ud.name);
iRet = LLDnodePtr2Next(self->iUserList);
}
LLDdelete(self->iUserList);
self->iUserList = LLDcreate(sizeof(UserData));
}
/*----------------------------------------------------------------------*/
void KillAmorStatus(void *pData)
{
pAmorStat self = (pAmorStat)pData;
if(!self)
return;
if(self->iUserList >= 0)
{
ClearUserData(self);
LLDdelete(self->iUserList);
}
if(self->pDes)
DeleteDescriptor(self->pDes);
if(self->pCall)
DeleteCallBackInterface(self->pCall);
free(self);
}
/*------------------------------------------------------------------*/
int AmorStatusFactory(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[])
{
pAmorStat pNew = NULL;
CommandList *pCom = NULL;
char pBueffel[256];
int iRet;
/* check number of arguments */
if(argc < 4)
{
sprintf(pBueffel,"ERROR: insufficient number of arguments to %s",
argv[0]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/* allocate a new data structure */
pNew = (pAmorStat)malloc(sizeof(AmorStat));
if(!pNew)
{
sprintf(pBueffel,"ERROR: out of memory in %s",argv[0]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
memset(pNew,0,sizeof(AmorStat));
pNew->pDes = CreateDescriptor("AmorStatus");
pNew->iUserList = LLDcreate(sizeof(UserData));
pNew->pCall = CreateCallBackInterface();
if( (!pNew->pDes) || (pNew->iUserList < 0) || (!pNew->pCall) )
{
sprintf(pBueffel,"ERROR: out of memory in %s",argv[0]);
SCWrite(pCon,pBueffel,eError);
KillAmorStatus(pNew);
return 0;
}
/* to locate the HM and the scan object */
pCom = FindCommand(pSics,argv[2]);
if(pCom)
{
if(pCom->pData)
{
if(!iHasType(pCom->pData,"ScanObject"))
{
sprintf(pBueffel,"ERROR: %s is NO scan object",argv[2]);
SCWrite(pCon,pBueffel,eError);
KillAmorStatus(pNew);
return 0;
}
}
else
{
sprintf(pBueffel,"ERROR: %s is NO scan object",argv[2]);
SCWrite(pCon,pBueffel,eError);
KillAmorStatus(pNew);
return 0;
}
}
else
{
sprintf(pBueffel,"ERROR: %s NOT found",argv[2]);
SCWrite(pCon,pBueffel,eError);
KillAmorStatus(pNew);
return 0;
}
pNew->pScan = (pScanData)pCom->pData;
pCom = FindCommand(pSics,argv[3]);
if(pCom)
{
if(pCom->pData)
{
if(!iHasType(pCom->pData,"HistMem"))
{
sprintf(pBueffel,"ERROR: %s is NO histogram memory object",
argv[3]);
SCWrite(pCon,pBueffel,eError);
KillAmorStatus(pNew);
return 0;
}
}
else
{
sprintf(pBueffel,"ERROR: %s is NO histogram memory object",
argv[3]);
SCWrite(pCon,pBueffel,eError);
KillAmorStatus(pNew);
return 0;
}
}
else
{
sprintf(pBueffel,"ERROR: %s NOT found",argv[3]);
SCWrite(pCon,pBueffel,eError);
KillAmorStatus(pNew);
return 0;
}
pNew->pHM = (pHistMem)pCom->pData;
pHMHM = (pHistMem)pCom->pData;
/* install command */
iRet = AddCommand(pSics,argv[1],
AmorStatusAction,KillAmorStatus,pNew);
if(!iRet)
{
sprintf(pBueffel,"ERROR: duplicate command %s NOT created",
argv[1]);
SCWrite(pCon,pBueffel,eError);
KillAmorStatus(pNew);
return 0;
}
return 1;
}
/*------------------------------------------------------------------*/
static int RegisterInterest(pAmorStat self, SConnection *pCon)
{
long lID;
pDummy pDum = NULL;
pICallBack pCall = NULL;
assert(self);
assert(pCon);
/* Register all the callbacks. Dependent on the state of
iTOF invoke the apropriate callbacks in order to force
an initial update.
*/
/* file load callback */
lID = RegisterCallback(self->pCall, FILELOADED, LoadCallback,
pCon, NULL);
SCRegister(pCon,pServ->pSics, self->pCall,lID);
SendLoadedData(self,pCon);
/* scan object */
pDum = (pDummy)self->pScan;
pCall = pDum->pDescriptor->GetInterface(pDum,CALLBACKINTERFACE);
if(pCall)
{
lID = RegisterCallback(pCall,SCANSTART,ScanStartCallback,
pCon, NULL);
SCRegister(pCon,pServ->pSics,pCall,lID);
lID = RegisterCallback(pCall,SCANPOINT,ScanPointCallback,
pCon, NULL);
SCRegister(pCon,pServ->pSics,pCall,lID);
lID = RegisterCallback(pCall,SCANEND,ScanPointCallback,
pCon, NULL);
SCRegister(pCon,pServ->pSics,pCall,lID);
if(iTOF == 0)
{
ScanStartCallback(SCANSTART,pDum,pCon);
ScanPointCallback(SCANPOINT,pDum,pCon);
}
}
pDum = (pDummy)self->pHM;
pCall = pDum->pDescriptor->GetInterface(pDum,CALLBACKINTERFACE);
if(pCall)
{
lID = RegisterCallback(pCall,COUNTSTART,HMCountStartCallback,
pCon, NULL);
SCRegister(pCon,pServ->pSics,pCall,lID);
if(iTOF == 1)
{
HMCountStartCallback(COUNTSTART,pDum,pCon);
}
}
return 1;
}
/*-----------------------------------------------------------------*/
static int FileLoad(pAmorStat self, SConnection *pCon,
char *name, double dScale)
{
char pBueffel[256], pDummy[50];
FILE *fd = NULL;
UserData ud;
int iNP, i;
float fDummy;
/* open the file */
fd = fopen(name,"r");
if(!fd)
{
sprintf(pBueffel,"ERROR: cannot open %s for reading",name);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/* skip first line */
if(fgets(pBueffel,255,fd) == NULL)
{
SCWrite(pCon,"ERROR: premature end of file",eError);
fclose(fd);
return 0;
}
/* read number of points in second line */
if(fgets(pBueffel,255,fd) == NULL)
{
SCWrite(pCon,"ERROR: premature end of file",eError);
fclose(fd);
return 0;
}
sscanf(pBueffel,"%s %d",pDummy, &iNP);
/* allocate data */
ud.iNP = iNP;
ud.fX = (float *)malloc(iNP*sizeof(float));
ud.fY = (float *)malloc(iNP*sizeof(float));
ud.name = strdup(name);
/* skip two lines */
if(fgets(pBueffel,255,fd) == NULL)
{
SCWrite(pCon,"ERROR: premature end of file",eError);
fclose(fd);
return 0;
}
if(fgets(pBueffel,255,fd) == NULL)
{
SCWrite(pCon,"ERROR: premature end of file",eError);
fclose(fd);
return 0;
}
/* loop reading data */
for(i = 0; i < iNP; i++)
{
if(fgets(pBueffel,255,fd) == NULL)
{
SCWrite(pCon,"WARNING: premature end of file",eError);
break;
}
sscanf(pBueffel," %f %f %f",&ud.fX[i],&fDummy, &ud.fY[i]);
ud.fY[i] *= dScale;
}
fclose(fd);
/* enter ud into list */
LLDnodeInsertFrom(self->iUserList,&ud);
return 1;
}
/*-----------------------------------------------------------------
Collapse creates a 2D image from the detector by summing all time
channels together in any given detector.
*/
static int Collapse(pAmorStat self, SConnection *pCon)
{
HistInt *lData = NULL;
int i, i2, i3, iDim[MAXDIM], iIdx, iSum;
int *iImage = NULL, *iPtr;
/* get size of our problem */
GetHistDim(self->pHM,iDim,&i3);
assert(i3 == 3);
/* get data */
lData = GetHistogramPointer(self->pHM,pCon);
if(!lData)
{
return 0;
}
/* allocate some data */
iImage = (int *)malloc((2 + iDim[0]*iDim[1])*sizeof(int));
if(iImage == NULL)
{
SCWrite(pCon,"ERROR: failed to allocate memory in Collapse",eError);
return 0;
}
memset(iImage,0,(2 + iDim[0]*iDim[1])*sizeof(int));
/* first two numbers are the dimension of the image */
iImage[0] = htonl(iDim[0]);
iImage[1] = htonl(iDim[1]);
/* loop the loop */
for(i = 0; i < iDim[0]; i++)
{
for(i2 = 0; i2 < iDim[1]; i2++)
{
iPtr = lData + i*iDim[1]*iDim[2] +
i2*iDim[2];
iIdx = i*iDim[1] + i2;
for(i3 = 0, iSum = 0; i3 < iDim[2]; i3++)
{
iSum += iPtr[i3];
}
iImage[iIdx+2] = htonl(iSum);
}
}
/* send image */
SCWriteUUencoded(pCon,"arrow_image",iImage,
(iDim[0]*iDim[1]+2)*sizeof(int));
free(iImage);
return 1;
}
/*-------------------------------------------------------------------
SubSample sums histogram data in the area defined by the rectangle
x1,y1 x2, y2. Summing is along the time axis.
*/
static int SubSample(pAmorStat self, SConnection *pCon,
char *name, int x1, int x2, int y1, int y2)
{
int iDim[MAXDIM], i, i2, i3, *iSum = NULL, iLang, *iPtr;
HistInt *lData = NULL;
int iLimit;
char pBueffel[132];
/* get histogram data */
GetHistDim(self->pHM,iDim,&i3);
assert(i3 == 3);
lData = GetHistogramPointer(self->pHM,pCon);
if(!lData)
{
return 0;
}
/* check limits */
if(x2 < x1)
x2 = x1 + 1;
if(y2 < y1)
y2 = y1 + 1;
iLimit = 0;
if( x1 > iDim[0])
{
iLimit = 1;
x1 = iDim[0] - 1;
}
if(x1 < 0)
{
iLimit = 1;
x1 = 0;
}
if( x2 > iDim[0])
{
iLimit = 2;
x2 = iDim[0] - 1;
}
if(x2 < 0)
{
iLimit = 2;
x2 = 0;
}
if( y1 > iDim[1])
{
iLimit = 3;
y1 = iDim[1] - 1;
}
if(y1 < 0)
{
iLimit = 3;
y1 = 0;
}
if( y2 > iDim[1])
{
iLimit = 4;
y2 = iDim[1] - 1;
}
if(y2 < 0)
{
iLimit = 4;
y2 = 0;
}
if(iLimit != 0)
{
switch(iLimit)
{
case 1:
strcpy(pBueffel,"WARNING: limit violation on x1");
break;
case 2:
strcpy(pBueffel,"WARNING: limit violation on x2");
break;
case 3:
strcpy(pBueffel,"WARNING: limit violation on y1");
break;
case 4:
strcpy(pBueffel,"WARNING: limit violation on y2");
break;
}
SCWrite(pCon,pBueffel,eWarning);
}
/* allocate space for result */
iSum = (int *)malloc((iDim[2]+1)*sizeof(int));
if(!iSum)
{
SCWrite(pCon,"ERROR: out of memory in SubSample",eError);
return 0;
}
memset(iSum,0,(iDim[2]+1)*sizeof(int));
/* do it! */
iSum[0] = iDim[2];
for(i = x1; i < x2; i++)
{
for(i2 = x1; i2 < y2; i2++)
{
iPtr = lData + i*iDim[1]*iDim[2] +
i2*iDim[2];
for(i3 = 0; i3 < iDim[2]; i3++)
{
iSum[i3+1] += iPtr[i3];
}
}
}
/* network byte order */
for(i = 0; i < iDim[2]+1; i++)
{
iSum[i] = htonl(iSum[i]);
}
/* send */
sprintf(pBueffel,"arrowsum_%s",name);
SCWriteUUencoded(pCon,pBueffel,iSum,(iDim[2]+1)*sizeof(int));
free(iSum);
return 1;
}
/*------------------------------------------------------------------*/
int AmorStatusAction(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[])
{
pAmorStat self = (pAmorStat)pData;
char pBueffel[512];
double dScale;
int iRet;
int x1, x2, y1, y2;
assert(self);
if(argc < 2)
{
sprintf(pBueffel,"ERROR: need argument to %s",argv[0]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
strtolower(argv[1]);
if(strcmp(argv[1],"interest") == 0)
{
RegisterInterest(self,pCon);
SCSendOK(pCon);
return 1;
}
else if(strcmp(argv[1],"load") == 0)
{
if(argc < 4)
{
sprintf(pBueffel,
"ERROR: need filename and scale argument to %s load",
argv[0]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = Tcl_GetDouble(pSics->pTcl,argv[3],&dScale);
if(iRet != TCL_OK)
{
sprintf(pBueffel,"ERROR: cannot convert %s to scale factor",
argv[3]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
FileLoad(self,pCon,argv[2],dScale);
InvokeCallBack(self->pCall, FILELOADED,self);
SCSendOK(pCon);
}
else if(strcmp(argv[1],"collapse") == 0)
{
iRet = Collapse(self,pCon);
if(iRet)
{
SCSendOK(pCon);
}
return iRet;
}
else if(strcmp(argv[1],"sample") == 0)
{
if(argc < 7)
{
SCWrite(pCon,"ERROR: insufficent number of arguments to sample",
eError);
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl,argv[3],&x1);
if(iRet != TCL_OK)
{
sprintf(pBueffel,"ERROR: cannot convert %s to int", argv[3]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl,argv[6],&y2);
if(iRet != TCL_OK)
{
sprintf(pBueffel,"ERROR: cannot convert %s to int", argv[6]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl,argv[4],&x2);
if(iRet != TCL_OK)
{
sprintf(pBueffel,"ERROR: cannot convert %s to int", argv[4]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl,argv[5],&y1);
if(iRet != TCL_OK)
{
sprintf(pBueffel,"ERROR: cannot convert %s to int", argv[5]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = SubSample(self,pCon,argv[2],x1,x2,y1,y2);
if(iRet)
SCSendOK(pCon);
return iRet;
}
else if(strcmp(argv[1],"sendloaded") == 0)
{
SendLoadedData(self,pCon);
return 1;
}
else if(strcmp(argv[1],"clear") == 0)
{
ClearUserData(self);
InvokeCallBack(self->pCall, FILELOADED,self);
SCSendOK(pCon);
}
return 1;
}

21
amorstat.h Normal file
View File

@ -0,0 +1,21 @@
/*------------------------------------------------------------------------
A M O R S T A T U S
Public definitions for the AMOR status display
facilitator object. DO NOT CHANGE. This file is automatically
created from amorstat.w.
Mark Koennecke, September 1999
---------------------------------------------------------------------*/
#ifndef AMORSTATUS
#define AMORSTATUS
int AmorStatusFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int AmorStatusAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
void KillAmorStatus(void *pData);
#endif

29
amorstat.i Normal file
View File

@ -0,0 +1,29 @@
/*------------------------------------------------------------------------
A M O R S T A T U S
Internal data structure definitions for the AMOR status display
facilitator object. DO NOT CHANGE. This file is automatically
created from amorstat.w.
Mark Koennecke, September 1999
---------------------------------------------------------------------*/
/*---------------------------------------------------------------------*/
typedef struct {
float *fX, *fY;
int iNP;
char *name;
}UserData, *pUserData;
/*---------------------------------------------------------------------*/
typedef struct __AMORSTAT {
pObjectDescriptor pDes;
pICallBack pCall;
int iUserList;
pScanData pScan;
pHistMem pHM;
int iTOF;
}AmorStat, *pAmorStat;

138
amorstat.tex Normal file
View File

@ -0,0 +1,138 @@
\subsection{Amor Status Display Support}
The reflectometer AMOR has a few unique status display requirements:
\begin{itemize}
\item In scan mode up to four detector counts curves must be shown for
the two counters in spin-up or spin-down mode. This needs to be
updated after each scan point.
\item Additionally user defined curves may need to be displayed.
\item The usual helper information muste be displayed.
\item In TOF mode it must be possible to define a region on the
detector whose summed counts are displayed versus the time
binning. This must be sent on request.
\end{itemize}
In order to cover all this a special object within SICS is required
which deals with all this and packages information in a status display
compliant way.
In order to do this the amorstatus object registers callbacks both
with the histogram memory and the scan object. These callback
functions are then responsible for updating the status displays. In
order for amorstatus to be able to do this, the client must register
itself with a special command.
In order to achieve all this some data structures are needed:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$asdata {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*---------------------------------------------------------------------*/@\\
\mbox{}\verb@ typedef struct {@\\
\mbox{}\verb@ float *fX, *fY;@\\
\mbox{}\verb@ int iNP;@\\
\mbox{}\verb@ char *name;@\\
\mbox{}\verb@ }UserData, *pUserData; @\\
\mbox{}\verb@/*---------------------------------------------------------------------*/@\\
\mbox{}\verb@ typedef struct __AMORSTAT {@\\
\mbox{}\verb@ pObjectDescriptor pDes;@\\
\mbox{}\verb@ pICallBack pCall;@\\
\mbox{}\verb@ int iUserList;@\\
\mbox{}\verb@ pScanData pScan;@\\
\mbox{}\verb@ pHistMem pHM;@\\
\mbox{}\verb@ int iTOF;@\\
\mbox{}\verb@ }AmorStat, *pAmorStat;@\\
\mbox{}\verb@ @\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
The fourth data structure is the amor status object data structure. It
has the following fields:
\begin{description}
\item[pDes] The standard SICS object descriptor.
\item[pCall] The callback interface.
\item[iUserList] A list of user data loaded data.
\item[pScan] A pointer to the scan object.
\item[pHM] A pointer to the histogram memory.
\item[iTOF] A flag which is true if we are taking measurements in TOF
mode.
\end{description}
In terms of a function interface this object has not much to
offer. Its main purpose is really as an interface to the status
display clients and thus it is configured through the interpreter
interface function. No need for other SICS objects to access it.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$asinter {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ int AmorStatusFactory(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ int AmorStatusAction(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ void KillAmorStatus(void *pData);@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
\verb@"amorstat.i"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*------------------------------------------------------------------------@\\
\mbox{}\verb@ A M O R S T A T U S@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Internal data structure definitions for the AMOR status display @\\
\mbox{}\verb@ facilitator object. DO NOT CHANGE. This file is automatically@\\
\mbox{}\verb@ created from amorstat.w.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, September 1999@\\
\mbox{}\verb@---------------------------------------------------------------------*/@\\
\mbox{}\verb@@$\langle$asdata {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@ @\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap4}
\verb@"amorstat.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*------------------------------------------------------------------------@\\
\mbox{}\verb@ A M O R S T A T U S@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Public definitions for the AMOR status display @\\
\mbox{}\verb@ facilitator object. DO NOT CHANGE. This file is automatically@\\
\mbox{}\verb@ created from amorstat.w.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, September 1999@\\
\mbox{}\verb@---------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef AMORSTATUS@\\
\mbox{}\verb@#define AMORSTATUS@\\
\mbox{}\verb@@$\langle$asinter {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

102
amorstat.w Normal file
View File

@ -0,0 +1,102 @@
\subsection{Amor Status Display Support}
The reflectometer AMOR has a few unique status display requirements:
\begin{itemize}
\item In scan mode up to four detector counts curves must be shown for
the two counters in spin-up or spin-down mode. This needs to be
updated after each scan point.
\item Additionally user defined curves may need to be displayed.
\item The usual helper information muste be displayed.
\item In TOF mode it must be possible to define a region on the
detector whose summed counts are displayed versus the time
binning. This must be sent on request.
\end{itemize}
In order to cover all this a special object within SICS is required
which deals with all this and packages information in a status display
compliant way.
In order to do this the amorstatus object registers callbacks both
with the histogram memory and the scan object. These callback
functions are then responsible for updating the status displays. In
order for amorstatus to be able to do this, the client must register
itself with a special command.
In order to achieve all this some data structures are needed:
@d asdata @{
/*---------------------------------------------------------------------*/
typedef struct {
float *fX, *fY;
int iNP;
char *name;
}UserData, *pUserData;
/*---------------------------------------------------------------------*/
typedef struct __AMORSTAT {
pObjectDescriptor pDes;
pICallBack pCall;
int iUserList;
pScanData pScan;
pHistMem pHM;
int iTOF;
}AmorStat, *pAmorStat;
@}
The fourth data structure is the amor status object data structure. It
has the following fields:
\begin{description}
\item[pDes] The standard SICS object descriptor.
\item[pCall] The callback interface.
\item[iUserList] A list of user data loaded data.
\item[pScan] A pointer to the scan object.
\item[pHM] A pointer to the histogram memory.
\item[iTOF] A flag which is true if we are taking measurements in TOF
mode.
\end{description}
In terms of a function interface this object has not much to
offer. Its main purpose is really as an interface to the status
display clients and thus it is configured through the interpreter
interface function. No need for other SICS objects to access it.
@d asinter @{
int AmorStatusFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int AmorStatusAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
void KillAmorStatus(void *pData);
@}
@o amorstat.i @{
/*------------------------------------------------------------------------
A M O R S T A T U S
Internal data structure definitions for the AMOR status display
facilitator object. DO NOT CHANGE. This file is automatically
created from amorstat.w.
Mark Koennecke, September 1999
---------------------------------------------------------------------*/
@<asdata@>
@}
@o amorstat.h @{
/*------------------------------------------------------------------------
A M O R S T A T U S
Public definitions for the AMOR status display
facilitator object. DO NOT CHANGE. This file is automatically
created from amorstat.w.
Mark Koennecke, September 1999
---------------------------------------------------------------------*/
#ifndef AMORSTATUS
#define AMORSTATUS
@<asinter@>
#endif
@}

268
amortest.tcl Normal file
View File

@ -0,0 +1,268 @@
# --------------------------------------------------------------------------
# Initialization script for a simulated AMOR instrument
#
#
# Dr. Mark Koennecke September,1999 - ??, ????
#---------------------------------------------------------------------------
#------------ our home
set home /data/koenneck/src/sics
#----------- first all the server options are set
ServerOption ReadTimeOut 100
# timeout when checking for commands. In the main loop SICS checks for
# pending commands on each connection with the above timeout, has
# PERFORMANCE impact!
ServerOption AcceptTimeOut 100
# timeout when checking for connection req.
# Similar to above, but for connections
ServerOption ReadUserPasswdTimeout 7000
# time to wiat for a user/passwd to be sent from a client. Increase this
# if there is a problem connecting to a server due to network overload\
ServerOption LogFileDir $home/tmp
#LogFileDir is the directory where the command log is going
ServerOption LogFileBaseName $home/tmp/server
# the path and base name of the internal server logfile to which all
# activity will be logged.
ServerOption statusfile $home/tmp/sicsstatus.tcl
ServerOption ServerPort 2911
# the port number the server is going to listen at. The client MUST know
# this number in order to connect. It is in client.ini
ServerOption InterruptPort 2914
# The UDP port where the server will wait for Interrupts from clients.
# Obviously, clients wishing to interrupt need to know this number.
# Telnet options
ServerOption TelnetPort 1301
ServerOption TelWord sicslogin
ServerOption DefaultTclDirectory $home/tcl
ServerOption DefaultCommandFile topsicom.tcl
#------ a port for broadcasting UDP messages
ServerOption QuieckPort 2108
#---------------------------------------------------------------------------
# U S E R S
# than the SICS users are specified
# Syntax: SicsUser name password userRightsCode
SicsUser Mugger Diethelm 1
SicsUser User Rosy 2
SicsUser Spy 007 1
#--------------------------------------------------------------------------
# G E N E R A L V A R I A B L E S
# now a few general variables are created
# Syntax: VarMake name type access
# type can be one of: Text, Int, Float
#access can be one of: Internal, Mugger, user, Spy
VarMake Instrument Text Internal
Instrument AMOR
Instrument lock
VarMake Title Text User
VarMake sample Text User
sample "DanielSulfid"
Title "Amore mio in SINQ"
VarMake User Text User
User The reflective looser
VarMake lastscancommand Text User
VarMake Adress Text User
VarMake phone Text User
VarMake fax Text User
VarMake email Text User
VarMake sample_mur Float User
#--------------------------------------------------------------------------
# B u i l d i n g B l o c k s
#--------------------------------------------------------------------------
#
#=================== Chopper
VarMake chopperrotation Float User
chopperrotation 10000.
ClientPut "Starting motor initialization ....."
#=================== frame overlap mirror
VarMake fomname Text Mugger
fomname Super Duper Mirror
fomname lock
VarMake fomdist Float Mugger
fomdist 120
Motor FTZ SIM 0. 120. .1 2. # fom height
Motor FOM SIM -30. 30. .1 2. # fom omega
#================== first diaphragm
VarMake d1dist Float Mugger
d1dist 200.
Motor D1L SIM 0. 120. .1 2. # left
Motor D1R SIM 0. 120. .1 2. # right
Motor D1T SIM 0. 120. .1 2. # top
Motor D1B SIM 0. 1000. .1 2. # bottom
#================== polarizer
VarMake polname Text Mugger
polname Daniels Special Edition Polarizer
polname lock
VarMake poldist Float Mugger
fomdist 200
Motor MOZ SIM 0. 1000. .1 2. # pol table height
Motor MTY SIM -60. 60. .1 2. # pol y movement
Motor MOM SIM -30. 30. .1 2. # pol omega
Motor MTZ SIM -30. 30. .1 2. # pol omega height
#=================== diaphragm 2
VarMake d2dist Float Mugger
d2dist 200.
Motor D2L SIM 0. 120. .1 2. # left
Motor D2R SIM 0. 120. .1 2. # right
Motor D2T SIM 0. 120. .1 2. # top
Motor D2B SIM 0. 1000. .1 2. # bottom
#==================== diaphragm 3
VarMake d3dist Float Mugger
d3dist 200.
Motor D3L SIM 0. 120. .1 2. # left
Motor D3R SIM 0. 120. .1 2. # right
Motor D3T SIM 0. 120. .1 2. # top
Motor D3B SIM 0. 1000. .1 2. # bottom
#===================== sample table
VarMake sampledist Float Mugger
sampledist 200
Motor STZ SIM -50. 50. .1 2. # sample height
Motor SOM SIM -30. 30. .1 2. # sample omega
Motor SCH SIM -30. 30. .1 2. # sample chi
Motor SOZ SIM 0. 1000. .1 2. # table height
#====================== diaphragm 4
VarMake d4dist Float Mugger
d4dist 200.
Motor D4L SIM 0. 120. .1 2. # left
Motor D4R SIM 0. 120. .1 2. # right
Motor D4T SIM 0. 120. .1 2. # top
Motor D4B SIM 0. 1000. .1 2. # bottom
#======================= analyzer
VarMake ananame Text Mugger
ananame Daniels Special Edition Analyzer
ananame lock
VarMake anadist Float Mugger
anadist 200
Motor AOZ SIM 0. 1000. .1 2. # analyzer table height
Motor AOM SIM -30. 30. .1 2. # analyzer omega
Motor ATZ SIM -30. 30. .1 2. # analyzer omega height
#======================== diaphragm 5
VarMake d5dist Float Mugger
d5dist 200.
Motor D5L SIM 0. 120. .1 2. # left
Motor D5R SIM 0. 120. .1 2. # right
Motor D5T SIM 0. 120. .1 2. # top
Motor D5B SIM 0. 1000. .1 2. # bottom
#======================== counter
VarMake detectordist Float Mugger
detectordist 200.
MakeCounter counter SIM
Motor COZ SIM 0. 1000. .1 2. # counter table height
Motor C3Z SIM 0. 300. .1 2. # counter height
Motor COM SIM -30. 30. .1 2. # counter omega
Motor COX SIM -100. 100. .1 2. # counter x
ClientPut "Motors initialized"
#======================== histogram memory
MakeHM hm SIM
hm configure HistMode TOF
hm configure OverFlowMode Ceil
hm configure Rank 1
hm configure dim0 128
hm configure dim1 128
hm configure Length 16384
hm configure BinWidth 4
hm preset 100.
hm CountMode Timer
hm configure Counter counter
hm configure init 0
hm genbin 0. 35. 100
hm init
ClientPut "Histogram Memory Initialized"
#--------------------------------------------------------------------------
# D a t a S t o r a g e
#------------------------------------------------------------------------
VarMake SicsDataPath Text Mugger
SicsDataPath $home/
SicsDataPath lock
VarMake SicsDataPrefix Text Mugger
SicsDataPrefix amortest
SicsDataPrefix lock
VarMake SicsDataPostFix Text Mugger
SicsDataPostFix ".hdf"
SicsDataPostFix lock
MakeDataNumber SicsDataNumber $home/danu.dat
MakeStoreAmor hm
#--------------------------------------------------------------------------
# C o m m a n d I n i t i a l i z a t i o n
#-------------------------------------------------------------------------
#======= logbook
source tcl/log.tcl
Publish LogBook Spy
#======== Drive
MakeDrive
#======== scan
source $home/tcl/topsicom.tcl
source $home/tcl/cscan.tcl
Publish cscan User
Publish sscan User
Publish sftime Spy
Publish scan Spy
Publish ScanCounts Spy
Publish TextStatus Spy
Publish otUnknown Spy
MakeScanCommand xxxscan counter topsi.hdd recover.bin
xxxscan configure amor
#========== peak & center
MakePeakCenter xxxscan
source /data/koenneck/src/sics/countf.tcl
#========== serial port general purpose
SerialInit
Publish serialport User
Publish p1 User
#=========== the optimiser
MakeOptimise opti counter
#=========== Amor2T
set a2t(mom) mom
set a2t(som) som
set a2t(coz) coz
set a2t(cox) cox
set a2t(stz) stz
set a2t(soz) soz
set a2t(d4b) d4b
set a2t(d5b) d5b
set a2t(com) com
MakeAmor2T a2t a2t
#=========== Status Display Support
MakeAmorStatus amorstatus xxxscan hm
source amorpar.tcl
Publish amorpar Spy
ClientPut "Done Initializing"

7
ati.tcl Normal file
View File

@ -0,0 +1,7 @@
drive mom 3.
scan var a2t 0. .2
scan var som 0. .1
scan preset 1
scan mode timer
scan np 20
scan run

46
author.txt Normal file
View File

@ -0,0 +1,46 @@
Copyright:
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5423 Villigen-PSI
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
----------------------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <tcl.h>
#include "fortify.h"
#include "lld.h"
#include "lld_blob.h"
#include "lld_str.h"
#include "conman.h"
#include "obdes.h"
#include "fupa.h"
#include "motor.h"
#include "datadmc.h"
#include "countdriv.h"
#include "counter.h"

211
autofile.tcl Normal file
View File

@ -0,0 +1,211 @@
#----------------------------------------------------------------------------
# This is part of the WWW-interface to SICS. This interface allows to
# create batch files to be run automatically by SICS. These files are
# stored in a special directory as files with the ending .sip by the
# CGI-scripts or servlets creating them. Now, a system is needed which
# checks this directory regularly for new files and executes them in SICS.
# This is the purpose of the SICS-Tcl macros defined in this file.
#
# First edition: Mark Koennecke, December 1999
#----------------------------------------------------------------------------
#----------- !!!! the path where the automatic files reside
set autofpath "/data/koenneck/tmp/auto"
#------- a variable which defines if we should operate and the current file.
set __autofile_run 0
set __auto_exe_file ""
#!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# There is a name command between the Tcl internal scan command and the
# SICS scan command. The Tcl internal has to be renamed. The following
# variable defines the name of the Tcl scan command
set tclscan stscan
#---------- do initializing things when called first time
set ret [catch [catch {autofile} msg]
if {$ret != 0} {
VarMake autofilepath Text Mugger
autofilepath $autofpath
autofilepath lock
Publish autofileexecute User
Publish autofile Mugger
Publish autostart User
Publish autoadd User
Publish autoend User
#------- for automatic file name creation
catch {MakeDataNumber autonumber $autofpath/autonumber.dat}
#------- check any 30 seconds
sicscron 30 autofileexecute
}
#--------------------------------------------------------------------------
proc autofile { {action null} } {
upvar #0 __autofile_run ar
if { [string compare $action start] == 0} {
set ar 1
return OK
} elseif { [string compare $action stop] == 0 } {
set ar 0
return OK
} else {
if {$ar == 1} {
return on
} else {
return off
}
}
}
#--------------------------------------------------------------------------
proc autofileexecute { } {
upvar #0 __autofile_run ar
upvar #0 __auto_exe_file aef
upvar #0 tclscan filescan
#--------- no operation if not activated
if {$ar != 1} {
return
}
#--------- aquire a list of candidate batch files
set tmp [autofilepath]
set ltmp [split $tmp =]
set tmp [lindex $ltmp 1]
set tmp2 [string trim $tmp]/*.inp
set ret [catch {set filelist [glob $tmp2]} msg]
if {$ret != 0} {
return "Nothing to do"
}
if { [llength $filelist] < 1 } {
return "Nothing to do"
}
#--------- now, in each file the second line contains the order number,
# find the lowest one which is the next one to execute
set minnum 999999
set file2exe null
foreach fil $filelist {
set f [open $fil r]
gets $f
set numline [gets $f]
set ret [catch {$filescan $numline "# %d" numi} msg]
close $f
if { $ret == 0 } {
if { $numi < $minnum } {
set minnum $numi
set file2exe $fil
}
} else {
ClientPut $msg
}
}
#------------ having found an input file, execute it
if { [string compare $file2exe null] != 0 } {
set aef $file2exe
set ret [catch {interneval $file2exe} msg]
#------ after execution rename it with a different extension
set fil2 [file rootname $file2exe].old
file rename -force $file2exe $fil2
if {$ret != 0 } {
error $msg
} else {
return $msg
}
}
return "Invalid autobatch files"
}
#=========================================================================
# File management functions
#
# autostart creates a fresh file. The data is stored in a SICS runbuffer.
# autoadd adds a line to the runbuffer
# autoend writes the file to disk then.
#=========================================================================
proc autostart {} {
catch {buf del autobuffer}
Buf new autobuffer
}
proc autoadd args {
autobuffer append $args
}
proc autoend {} {
upvar #0 autofpath ap
autonumber incr
set txt [autonumber]
set l [split $txt =]
set txt [string trim [lindex $l 1]]
set fil [format "$ap/auto%7.7d.inp" $txt]
set filnum [format "# %d" $txt]
autobuffer ins 1 $filnum
autobuffer save $fil
Buf del autobuffer
}
#============================================================================
# file list management
#============================================================================
proc buildsortedlist {filar} {
upvar #0 autofpath ap
upvar $filar list
set i 0
#----------- build arrays of all relevant files
set ret [catch {set l1 [glob $ap/*.inp]}]
if { $ret == 0 } {
foreach fil $l1 {
set list($i)
incr i
set f [open $fil r]
set $fil(title) [gets $f]
set txt [gets $f]
close $f
set ret [catch {$filescan $txt "# %d" numi} msg]
if { $ret == 0} {
set fil(no) $numi
}else {
set fil(no) -10
}
}
}
set ret [catch {set l1 [glob $ap/*.old]}]
if { $ret == 0 } {
foreach fil $l1 {
set list($i)
incr i
set f [open $fil r]
set $fil(title) [gets $f]
set txt [gets $f]
close $f
set ret [catch {$filescan $txt "# %d" numi} msg]
if { $ret == 0} {
set fil(no) $numi
}else {
set fil(no) -10
}
}
}
set nfil i
#--------- now selection sort this list
for {set i 0} { i < $nfil} {incr i} {
set min $i
set ff $list($min)
for {set j [expr $i + 1]} {$j < $nfil} {incr j} {
set ff $list($j)
set fff $list($min)
if { $ff(no) < $fff(no)} {
set min $j
}
}
set t $list($min)
set list($min) $list($min)
set list($i) $t
}
}
proc autolist {} {
}

137
backup.tcl Normal file
View File

@ -0,0 +1,137 @@
# RuenBuffer Renate
Buf new Renate
Renate append Alle Fische sind schon da
Renate append Alle Nixen auch
Renate append Nur die dummen Neutronen kommen nicht
Renate append Und die Schluempfe kriegen es auch nicht gebacken
# RuenBuffer Kunigunde
Buf new Kunigunde
Kunigunde append Alle Fische sind schon da
Kunigunde append Alle Nixen auch
Kunigunde append Nur die dummen Neutronen kommen nicht
Kunigunde append Und die Schluempfe kriegen es auch nicht gebacken
# RuenBuffer Walter
Buf new Walter
Walter append Alle Fische sind schon da
Walter append Alle Nixen auch
Walter append Nur die dummen Neutronen kommen nicht
Walter append Und die Schluempfe kriegen es auch nicht gebacken
# RuenBuffer Willi
Buf new Willi
Willi append Alle Nixen auch
Willi append Und die Schluempfe kriegen es auch nicht gebacken
# RuenBuffer Heinz
Buf new Heinz
Heinz append GGG Fische sind schon da
Heinz append GGG Nixen auch
Heinz append Nur die dummen Neutronen kommen schon
Heinz append Und die Schluempfe kriegen es auch schon gebacken
Curve SoftLowerLim 0.000000
Curve SoftUpperLim 1000.000000
Curve SoftZero 0.000000
Curve Fixed -1.000000
Curve InterruptMode 0.000000
Curve AccessCode 2.000000
TwoTheta SoftLowerLim -140.000000
TwoTheta SoftUpperLim 140.000000
TwoTheta SoftZero 0.000000
TwoTheta Fixed -1.000000
TwoTheta InterruptMode 0.000000
TwoTheta AccessCode 2.000000
Theta SoftLowerLim -70.000000
Theta SoftUpperLim 70.000000
Theta SoftZero 0.000000
Theta Fixed -1.000000
Theta InterruptMode 0.000000
Theta AccessCode 2.000000
bsy SoftLowerLim -50.000000
bsy SoftUpperLim 50.000000
bsy SoftZero 0.000000
bsy Fixed -1.000000
bsy InterruptMode 0.000000
bsy AccessCode 2.000000
bsx SoftLowerLim -50.000000
bsx SoftUpperLim 50.000000
bsx SoftZero 0.000000
bsx Fixed -1.000000
bsx InterruptMode 0.000000
bsx AccessCode 2.000000
dphi SoftLowerLim 0.000000
dphi SoftUpperLim 360.000000
dphi SoftZero 0.000000
dphi Fixed -1.000000
dphi InterruptMode 0.000000
dphi AccessCode 2.000000
dsy SoftLowerLim -50.000000
dsy SoftUpperLim 50.000000
dsy SoftZero 0.000000
dsy Fixed -1.000000
dsy InterruptMode 0.000000
dsy AccessCode 2.000000
dsd SoftLowerLim 0.000000
dsd SoftUpperLim 18000.000000
dsd SoftZero 0.000000
dsd Fixed -1.000000
dsd InterruptMode 0.000000
dsd AccessCode 2.000000
saz SoftLowerLim 0.000000
saz SoftUpperLim 30.000000
saz SoftZero 0.000000
saz Fixed -1.000000
saz InterruptMode 0.000000
saz AccessCode 2.000000
say SoftLowerLim -22.000000
say SoftUpperLim 22.000000
say SoftZero 0.000000
say Fixed -1.000000
say InterruptMode 0.000000
say AccessCode 2.000000
sax SoftLowerLim -30.000000
sax SoftUpperLim 30.000000
sax SoftZero 0.000000
sax Fixed -1.000000
sax InterruptMode 0.000000
sax AccessCode 2.000000
som SoftLowerLim -180.000000
som SoftUpperLim 360.000000
som SoftZero 0.000000
som Fixed -1.000000
som InterruptMode 0.000000
som AccessCode 2.000000
sphi SoftLowerLim -22.000000
sphi SoftUpperLim 22.000000
sphi SoftZero 0.000000
sphi Fixed -1.000000
sphi InterruptMode 0.000000
sphi AccessCode 2.000000
schi SoftLowerLim -22.000000
schi SoftUpperLim 22.000000
schi SoftZero 0.000000
schi Fixed -1.000000
schi InterruptMode 0.000000
schi AccessCode 2.000000
comment (null)
comment setAccess 2
environment (null)
environment setAccess 2
SubTitle (null)
SubTitle setAccess 2
User set
User setAccess 2
Title Alle meine Entchen sind schon da
Title setAccess 2
Instrument set
Instrument setAccess 0

47
bare.tcl Normal file
View File

@ -0,0 +1,47 @@
# --------------------------------------------------------------------------
# Initialization script for a simulated TOPSI instrument
#
#
# Dr. Mark Koennecke February, 1996
#---------------------------------------------------------------------------
# O P T I O N S
# --------------- Initialize Tcl internals --------------------------------
# first all the server options are set
ServerOption ReadTimeOut 10
# timeout when checking for commands. In the main loop SICS checks for
# pending commands on each connection with the above timeout, has
# PERFORMANCE impact!
ServerOption AcceptTimeOut 10
# timeout when checking for connection req.
# Similar to above, but for connections
ServerOption ReadUserPasswdTimeout 500000
# time to wiat for a user/passwd to be sent from a client. Increase this
# if there is a problem connecting to a server due to network overload\
ServerOption LogFileBaseName /data/koenneck/src/sics/tmp/server
# the path and base name of the internal server logfile to which all
# activity will be logged.
ServerOption ServerPort 2910
# the port number the server is going to listen at. The client MUST know
# this number in order to connect. It is in client.ini
ServerOption InterruptPort 2913
# The UDP port where the server will wait for Interrupts from clients.
# Obviously, clients wishing to interrupt need to know this number.
#---------------------------------------------------------------------------
# U S E R S
# than the SICS users are specified
# Syntax: SicsUser name password userRightsCode
SicsUser Mugger Diethelm 1
SicsUser User Rosy 2
SicsUser Spy 007 3

791
base.tcl Normal file
View File

@ -0,0 +1,791 @@
crunch_skip begin
DOC "class Base" {
NAME
Base - The basic class inherited by all obTcl objects
SYNOPSIS
Base new <obj>
- Creates an object of the simplest possible class.
DESCRIPTION
All classes inherits the Base class automatically. The Base class
provides methods that are essential for manipulating obTcl-objects,
such as `info' and `destroy'.
METHODS
Base provides the following generic methods to all objects:
new - EXPERIMENTAL! Arranges to create a new object of
the class of the invoking object.
instance - EXPERIMENTAL! Arranges to create a new object of
the class of the invoking object. This method
differs from `new' by NOT automatically invoking
the `init' method of the new object.
One possible usage: Create a replacement for the
normal class object -a replacement which has no
hard-coded methods (this will need careful design
though).
init - Does nothing. The init method is automatically
invoked whenever an object is created with `new'.
destroy - Frees all instance variables of the object, and
the object itself.
class - Returns the class of the object.
set name ?value?
- Sets the instance variable `name' to value.
If no value is specified, the current value is
returned. Mainly used for debugging purposes.
info <cmd> - Returns information about the object. See INFO
below.
eval <script> - Evaluates `script' in the context of the object.
Useful for debugging purposes. Not meant to be
used for other purposes (create a method instead).
One useful trick (if you use the Tcl-debugger in
this package) is to enter:
obj eval bp
to be able to examine `obj's view of the world
(breakpoints must be enabled, of course).
unknown <method> <args>
- Automatically invoked when unknown methods are
invoked. the Base class defines this method to
print an error message, but this can be overridden
by derived classes.
option <opt> <default> ?<section1> <body1>? ?<section2> <body2>?..
- Define an option handler.
See OPTION HANDLER below for a description.
conf_verify <args>
conf_init <args>
- Set options. <args> are option-value pairs.
See OPTION HANDLER below for a description.
configure <args>
- Set options. <args> are option-value pairs.
See OPTION HANDLER below for a description.
cget <opt> - Get option value.
See OPTION HANDLER below for a description.
verify_unknown <args>
init_unknown <args>
configure_unknown <args>
cget_unknown <opt>
- These methods are automatically invoked when a requested
option has not been defined.
See OPTION HANDLER below for a description.
INFO
The method `info' can be used to inspect an object. In the list below
(I) means the command is only applicable to object instances, whereas
(C) means that the command can be applied either to the class object, or
to the object instance, if that is more convenient.
Existing commands:
instvars - (I) Returns the names of all existing instance variables.
iclassvars - (I) List instance class variables
classvars - (C) List class variables.
objects - (C) List objects of this class.
methods - (C) List methods defined in this class.
sysmethods - (C) List system methods defined in this class.
cached - (C) List cached methods for this class.
body <method> - (C) List the body of a method.
args <method> - (C) List formal parameters for a method.
options - (I) List the current option values in the format
"option-value pairs".
defaults - (C) List the current default values in the format
"option-value pairs". These values are the initial
values each new object will be given.
OPTION HANDLER
The method `option' is used to define options. It should be used on
the class-object, which serves as a repository for default values
and for code sections to run to verify and make use of new default values.
option <opt> <default> ?<section1> <body1>? ?<section2> <body2>?..
Define an option for this class.
Defining an option results in an instance variable
of the same name (with the leading '-' stripped)
being defined. This variable will be initiated
with the value <default>.
The sections `verify', `init' and `configure' can be defined.
`verify' is used to verify new parameters without affecting
the object. It is typically called by an object's init method
before all parts of the object have been created.
`init' is used for rare situations where some action should be taken
just after the object has been fully created. I.e when setting
the option variable via `verify' was not sufficient.
The `configure' section is invoked when the configure method is
called to re-configure an object.
Example usage:
class Graph
Graph inherit Widget
Graph option {-width} 300 verify {
if { $width >= 600 } {
error "width must be less than 600"
}
} configure {
$self.grf configure -width $width
}
Note 1: The `verify' section should never attempt
to access structures in the object (i.e widgets), since
it is supposed to be callable before they exist!
Use the `configure' section to manipulate the object.
Note 2: Using "break" or "error" in the verify section results
in the newly specified option value being rejected.
conf_verify <args>
Invoke all "verify" sections for options-value pairs
specified in <args>.
conf_init <args>
Invoke all "init" sections for options-value pairs
specified in <args>.
Example usage:
Graph method init { args } {
instvar width
# Set any option variables from $args
#
eval $self conf_verify $args ;# Set params
next -width $width ;# Get frame
CreateRestOfObject ;# Bogus
# Option handlers that wish to affect the
# object during init may declare an "init"
# section. Run any such sections now:
#
eval $self conf_init $args
}
Graph .graph -width 400 ;# Set width initially
configure <args>
Invoke all "configure" sections for options-value pairs
specified in <args>.
Example usage:
# First create object
#
Graph .graph -width 300
# Use `configure' to configure the object
#
.graph configure -width 200
cget <opt>
Returns the current value of option <opt>.
Example usage:
.graph cget -width
<sect>_unknown <args>
These methods are called when attempting to invoke sections
for unknown options. In this way a class may define methods
to catch usage of "configure", "cget", etc. for undefined
options.
Example:
Graph method configure_unknown { opt args } {
eval {$self-cmd configure $opt} $args
}
See the definitions of the Base and Widget classes for their
usage of these methods.
}
crunch_skip end
#----------------------------------------------------------------------
# Define the Base class. This class provides introspection etc.
#
# It also provides "set", which gives access to object
# internal variables, and 'eval' which lets you run arbitrary scripts in
# the objects context. You may wish to remove those methods if you
# want to disallow this.
class Base
Base method init args {}
Base method destroy args {
otFreeObj $self
}
Base method class args {
return $iclass
}
# Note: The `set' method takes on the class of the caller, so
# instvars will use the callers scope.
#
Base method set args {
set class $iclass
# instvar [lindex $args 0]
set var [lindex $args 0]
regexp -- {^([^(]*)\(.*\)$} $var m var
instvar $var
return [eval set $args]
}
Base method eval l {
return [eval $l]
}
Base method info { cmd args } {
switch $cmd {
"instvars" {return [eval {otObjInfoVars\
_oIV_${iclass}:${self}: _oIV_${iclass}:${self}:} $args]}
"iclassvars" {otObjInfoVars _oICV_${iclass}: _oICV_${iclass}: $args}
"classvars" {otObjInfoVars _oDCV_${iclass}: _oDCV_${iclass}: $args}
"objects" {otObjInfoObjects $iclass}
"methods" {otClassInfoMethods $iclass}
"sysmethods" {otClassInfoSysMethods $iclass}
"cached" {otClassInfoCached $iclass}
"body" {otClassInfoBody $iclass $args}
"args" {otClassInfoArgs $iclass $args}
"options" {$iclass::collectOptions values ret
return [array get ret] }
"defaults" {$iclass::collectOptions defaults ret
return [array get ret] }
default {
return -code error \
-errorinfo "Undefined command 'info $cmd'" \
"Undefined command 'info $cmd'"
}
}
}
Base method unknown args {
return -code error \
-errorinfo "Undefined method '$method' invoked" \
"Undefined method '$method' invoked"
}
#------- START EXPERIMENTAL
Base method new { obj args } {
eval {otNew $iclass $obj} $args
}
Base method instance { obj args } {
eval {otInstance $iclass $obj} $args
}
Base method sys_method args {
eval {otMkMethod S $iclass} $args
}
Base method method args {
eval {otMkMethod N $iclass} $args
}
Base method del_method args {
eval {otRmMethod $iclass} $args
}
Base method inherit args {
eval {otInherit $iclass} $args
}
# class AnonInst - inherit from this class to be able to generate
# anonymous objects. Example:
#
# class Foo
# Foo inherit AnonInst
# set obj [Foo new]
#
# NOTE: EXPERIMENTAL!!!
class AnonInst
AnonInst method anonPrefix p {
iclassvar _prefix
set _prefix $p
}
AnonInst method new {{obj {}} args} {
iclassvar _count _prefix
if ![info exists _count] {
set _count 0
}
if ![info exists _prefix] {
set _prefix "$iclass"
}
if ![string compare "" $obj] {
set obj $_prefix[incr _count]
}
eval next {$obj} $args
return $obj
}
#------- END EXPERIMENTAL
#----------------------------------------------------------------------
# Configure stuff
#----------------------------------------------------------------------
# The configuaration stuff is, for various reasons, probably the most
# change-prone part of obTcl.
#
# After fiddling around with various methods for handling options,
# this is what I came up with. It uses one method for each class and option,
# plus one dispatch-method for each of "conf_init", "conf_verify", "configure"
# and "cget" per class. Any extra sections in the `option' handler
# results in another dispatch-method being created.
# Attempts at handling undefined options are redirected to
#
# <section_name>_unknown
#
# Note:
# Every new object is initialized by a call to `initialize'.
# This is done in the proc "new", before `init' is called, to guarantee
# that initial defaults are set before usage. `initialize' calls "next", so
# all inherited classes are given a chance to set their initial defaults.
#
# Sections and their used (by convention):
#
# verify - Called at beginning of object initialization to verify
# specified options.
# init - Called at end of the class' `init' method.
# Use for special configuration.
# configure
# - This section should use the new value to configure
# the object.
#
# MkSectMethod - Define a method which does:
# For each option specified, call the handler for the specified section
# and option. If this fails, call the <section>_unknown handler.
# If this fails too, return an error.
# Note that the normal call of the method `unknown' is avoided by
# telling the unknown handler to avoid this (by means of the global array
# "_obTcl_unknBarred").
#
proc otMkSectMethod { class name sect } {
$class sys_method $name args "
array set Opts \$args
foreach i \[array names Opts\] {
global _obTcl_unknBarred
set _obTcl_unknBarred(\$class::${sect}:\$i) 1
if \[catch {\$class::$sect:\$i \$Opts(\$i)} err\] {
if \[catch {\$class::${sect}_unknown\
\$i \$Opts(\$i)}\] {
unset _obTcl_unknBarred(\$class::${sect}:\$i)
error \"Unable to do '$sect \$i \$Opts(\$i)'\n\
\t\$err
\"
}
}
unset _obTcl_unknBarred(\$class::${sect}:\$i)
}
"
}
# Note: MkOptHandl is really a part of `option' below.
#
proc otMkOptHandl {} {
uplevel 1 {
$iclass sys_method "cget" opt "
classvar classOptions
if \[catch {$iclass::cget:\$opt} ret\] {
if \[catch {\$class::cget_unknown \$opt} ret\] {
error \"Unable to do 'cget \$opt'\"
}
}
return \$ret
"
otMkSectMethod $iclass conf_init init
$iclass sys_method initialize {} {
next
classvar optDefaults
eval instvar [array names optDefaults]
foreach i [array names optDefaults] {
set $i $optDefaults($i)
}
}
# arr - Out-param
#
$iclass sys_method collectOptions { mode arr } {
classvar classOptions optDefaults
upvar 1 $arr ret
next $mode ret
eval instvar [array names optDefaults]
foreach i [array names optDefaults] {
if [string compare "defaults" $mode] {
set ret(-$i) [set $classOptions(-$i)]
} else {
set ret(-$i) $optDefaults($i)
}
}
}
otMkSectMethod $iclass conf_verify verify
otMkSectMethod $iclass configure configure
set _optPriv(section,cget) 1
set _optPriv(section,init) 1
set _optPriv(section,initialize) 1
set _optPriv(section,verify) 1
set _optPriv(section,configure) 1
}
}
otMkSectMethod Base configure configure
# _optPriv is used for internal option handling house keeping
# Note: checking for existence of a proc is not always a good idea,
# since it may simply be a cached pointer to a inherited method.
#
Base method option { opt dflt args } {
classvar_of_class $iclass optDefaults classOptions _optPriv
set var [string range $opt 1 end]
set optDefaults($var) $dflt
set classOptions($opt) $var
array set tmp $args
if ![info exists _optPriv(initialize)] {
otMkOptHandl
set _optPriv(initialize) 1
}
foreach i [array names tmp] {
if ![info exists _optPriv(section,$i)] {
otMkSectMethod $iclass $i $i
set _optPriv(section,$i) 1
}
$iclass sys_method "$i:$opt" _val "
instvar $var
set _old_val \$[set var]
set $var \$_val
set ret \[catch {$tmp($i)} res\]
if {\$ret != 0 && \$ret != 2 } {
set $var \$_old_val
return -code \$ret -errorinfo \$res \$res
}
return \$res
"
set _optPriv($i:$opt) 1
}
if ![info exists _optPriv(cget:$opt)] {
$iclass sys_method "cget:$opt" {} "
instvar $var
return \$[set var]
"
set _optPriv(cget:$opt) 1
}
if ![info exists tmp(verify)] {
$iclass sys_method "verify:$opt" _val "
instvar $var
set $var \$_val
"
set _optPriv(verify:$opt) 1
}
if ![info exists tmp(configure)] {
$iclass sys_method "configure:$opt" _val "
instvar $var
set $var \$_val
"
set _optPriv(configure:$opt) 1
}
if ![info exists tmp(init)] {
$iclass sys_method "init:$opt" _val {}
set _optPriv(init:$opt) 1
}
}
# Default methods for non-compulsory
# standard sections in an option definition:
#
Base sys_method init_unknown { opt val } {}
Base sys_method verify_unknown { opt val } {}
# Catch initialize for classes which have no option handlers:
#
Base sys_method initialize {} {}
# Catch conf_init in case no option handlers have been defined.
#
Base sys_method conf_init {} {}
crunch_skip begin
#----------------------------------------------------------------------
#
# class Widget
# Base class for obTcl's Tk-widgets.
#
DOC "class Widget (Tk) base class for widgets" {
NAME
Widget - A base class for mega-widgets
SYNOPSIS
Widget new <obj> ?tk_widget_type? ?config options?
Widget <obj> ?tk_widget_type? ?config options?
DESCRIPTION
The widget class provides a base class for Tk-objects.
This class knows about widget naming conventions, so, for example,
destroying a Widget object will destroy any descendants of this object.
The `new' method need not be specified if the object name starts with a
leading ".". Thus giving syntactical compatibility with Tk for
creating widgets.
If `tk_widget_type' is not specified, the widget will be created as
a `frame'. If the type is specified it must be one of the existing
Tk-widget types, for example: button, radiobutton, text, etc.
See the Tk documentation for available widget types.
The normal case is to use a frame as the base for a mega-widget.
This is also the recommended way, since it results in the Tk class-name
of the frame being automatically set to the objects class name -thus
resulting in "winfo class <obj>" returning the mega-widget's class
name.
In order to create mega-widgets, derive new classes from this class.
METHODS
The following methods are defined in Widget:
init ?<args>? - Creates a frame widget, and configures it if any
configuration options are present. Automatically
invoked by the creation process, so there is no
need to call it (provided that you use 'next' in
the init-method of the derived class).
destroy - Destroys the object and associated tk-widget.
For Tk-compatibility, the function `destroy' can be
used instead, example:
destroy <obj>
Note: If you plan to mix Tk-widgets transparently
with mega-widgets, you should use the _function_
`destroy'.
Any descendant objects of <obj> will also be
destroyed (this goes for both Tk-widgets and
mega-widgets).
set - Overrides the `set' method of the Base class to
allow objects of type `scrollbar' to work correctly.
unknown - Overrides the `unknown' method of the Base class.
Directs any unknown methods to the main frame of
the Widget object.
unknown_opt - Overrides the same method from the Base class.
Automatically called from the option handling system.
Directs any unknown options to the main frame of the
Widget object.
In addition, all non-shadowed methods from the Base class can be used.
Any method that cannot be resolved is passed on to the associated
Tk-widget. This behaviour can be altered for any derived classes
by defining a new `unknown' method (thus shadowing Widget's own
`unknown' method). The same technique can be used to override
the `unknown_opt' method.
EXAMPLES
A simple example of deriving a class MegaButton which consists of
a button widget initiated with the text "MEGA" (yes, I know, it's
silly).
class MegaButton
MegaButton inherit Widget
MegaButton method init { args } {
#
# Allow the Widget class to create a button for us
# (we need to specify widget type `button')
#
eval next button $args
$self configure -text "MEGA"
}
frame .f
MegaButton .f.b -background red -foreground white
pack .f .f.b
This example shows how to specify a Tk-widget type (button), although
I advice against specifying anything (thus using a frame).
See DESCRIPTION above for the reasoning behind this. Also note that
`eval' is used to split $args into separate arguments for passing to
the init method of the Widget class.
A more realistic example:
class ScrolledText
ScrolledText inherit Widget
ScrolledText method init { args } {
next
text $self.t -yscrollcommand "$self.sb set"
scrollbar $self.sb -command "$self.t yview"
pack $self.sb -side right -fill y
pack $self.t -side left
eval $self configure $args
}
ScrolledText method unknown { args } {
eval {$self.t $method} $args
}
ScrolledText .st
.st insert end [exec cat /etc/passwd]
pack .st
This creates a new class, ScrolledText, containing a text window
and a vertical scrollbar. It arranges for all unknown methods to
be directed to the text widget; thus allowing `.st insert' to work
normally (along with any other text methods).
NOTES
Widget binds the "destroy" method to the <Destroy> event of
the holding window, so be careful not to remove this binding
inadvertently.
}
crunch_skip end
class Widget
# init Create a tk-widget of specified type (or frame if not specified).
# If the corresponding Tk-widget already exists, it will be used.
# Otherwise the Tk-widget will be created.
# The tk-widget will be named $self if $self has a leading ".",
# otherwise a "." is prepended to $self to form the wigdet name.
# The instvar `win' will contain the widgets window name, and
# the instvar `wincmd' will contain the name of the widget's associated
# command.
Widget method init args {
instvar win wincmd
next
set first "[lindex $args 0]"
set c1 "[string index $first 0]"
if { ![string compare "" "$c1"] || ![string compare "-" "$c1"] } {
set type frame
set cl "-class $iclass"
} else {
set type $first
set args [lrange $args 1 end]
set cl ""
}
if [string compare "" [info commands $self-cmd]] {
set win $self
set wincmd $self-cmd
} else {
if ![string compare "." [string index $self 0]] {
rename $self _ooTmp
eval $type $self $cl $args
rename $self $self-cmd
rename _ooTmp $self
set win $self
set wincmd $self-cmd
} else {
eval $type .$self $cl $args
set win .$self
#set wincmd .$self-cmd
set wincmd .$self
}
}
bind $win <Destroy> "\
if { !\[string compare \"%W\" \"$self\"\] && !\[catch {info args $self}\] } {
$self destroy -obj_only }"
return $self
}
# Just for the case when there are no option-handlers defined:
#
Widget sys_method configure args {
instvar wincmd
eval {$wincmd configure} $args
}
Widget sys_method cget opt {
instvar wincmd
eval {$wincmd cget} $opt
}
Widget sys_method configure_unknown { opt args } {
instvar wincmd
eval {$wincmd configure $opt} $args
}
Widget sys_method cget_unknown opt {
instvar wincmd
$wincmd cget $opt
}
Widget sys_method init_unknown { opt val } {
puts "init_unknown: $opt $val (iclass=$iclass class=$class)"
}
Widget sys_method unknown args {
instvar wincmd
eval {$wincmd $method} $args
}
# Note: no "next" used! Does the `Base::destroy' stuff here for performance.
#
Widget method destroy args {
instvar win wincmd
# Must copy vars since they are destroyed by `otFreeObj'
set wp $win
set w $wincmd
otFreeObj $self
catch {bind $w <Destroy> {}}
if [string compare "-obj_only" $args] {
if [string compare $w $wp] {
rename $w $wp
}
if [string compare "-keepwin" $args] {
destroy $wp
}
}
}
# The method `set' defined here shadows the `set' method from Base.
# This allows wrapper objects around Tk-scrollbars to work correctly.
#
Widget sys_method set args {
instvar wincmd
eval {$wincmd set} $args
}
Widget sys_method base_set args {
eval Base::set $args
}

20
beam.tcl Normal file
View File

@ -0,0 +1,20 @@
#------------------------------------------------------------------------
# install a SPS-Controller
MakeSPS sps1 lnsp25.psi.ch 4000 7
#----------------- the beam command
proc beam {} {
#---------- read the SPS
set ret [catch {SPS1 adc 3} msg]
if {$ret != 0} {
ClientPut $msg
ClientPut "ERROR: SPS reading failed"
return
}
#--------- convert the data
set l [split $msg "="]
set raw [lindex $l 1]
set val [expr $raw/13.96]
return [format "beam = %f" $val]
}
Publish beam Spy

20
beamdt.tcl Normal file
View File

@ -0,0 +1,20 @@
#------------------------------------------------------------------------
# install a SPS-Controller
MakeSPS sps1 lnsp23.psi.ch 4000 6
#----------------- the beam command
proc beam {} {
#---------- read the SPS
set ret [catch {SPS1 adc 7} msg]
if {$ret != 0} {
ClientPut $msg
ClientPut "ERROR: SPS reading failed"
return
}
#--------- convert the data
set l [split $msg "="]
set raw [lindex $l 1]
set val [expr $raw/13.96]
return [format "beam = %f" $val]
}
Publish beam Spy

17
bit.h Normal file
View File

@ -0,0 +1,17 @@
/*--------------------------------------------------------------------------
Macros for handling bits in a character array. Stolen somewhere on the
internet. Working!
Dr. Mark Koennecke 15.6.1994
----------------------------------------------------------------------------*/
#include <limits.h> /* for CHAR_BIT */
#define BITMASK(bit) (1 << ((bit) % CHAR_BIT))
#define BITSLOT(bit) ((bit) / CHAR_BIT)
#define BITSET(ary, bit) ((ary)[BITSLOT(bit)] |= BITMASK(bit))
#define BITTEST(ary, bit) ((ary)[BITSLOT(bit)] & BITMASK(bit))
#define BITUNSET(ary, bit) ((ary)[BITSLOT(bit)] ^= BITMASK(bit))

999
bruker.c Normal file
View File

@ -0,0 +1,999 @@
/*-------------------------------------------------------------------------
B r u k e r
An environment control driver and an additonal wrapper function for
controlling a Bruker B-EC-1 magnet controller. This controller can
either control a current or control the current through an external hall
sensor mesuring the magnetic field. In both cases both values: the field
and the current must be readable.
copyright: see copyright.h
Mark Koennecke, October 1998
---------------------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <tcl.h>
#include <math.h>
#include <assert.h>
#include "fortify.h"
#include "sics.h"
#include "obpar.h"
#include "evcontroller.h"
#include "evcontroller.i"
#include "evdriver.i"
#include "hardsup/serialsinq.h"
#include "hardsup/el734_errcodes.h"
#include "hardsup/el734fix.h"
#include "bruker.h"
/*
#define debug 1
*/
/*-----------------------------------------------------------------------
The Bruker Data Structure
*/
typedef struct {
void *pData;
char *pHost;
int iPort;
int iChannel;
int iMode;
int iLastError;
} BrukerDriv, *pBrukerDriv;
/*-----------------------------------------------------------------------
A couple of defines for Bruker modes and special error conditions
*/
#define FIELD 100
#define CURRENT 200
/* errors */
#define NOFUNC -1601
#define BADARG -1602
#define NOACCESS -1603
#define BADRANGE -1604
#define ERRPENDING -1605
#define NOPOWER -1606
#define NOTFIELD -1607
#define BADINTERN -1608
#define NOCONN -1609
#define BTIMEOUT -1610
#define NOPOLUNIT -1620
/* polarity */
#define PPLUS 0
#define PMINUS 1
#define PBUSY 3
/* rmtrail.c */
extern char *rmtrail(char *p);
/*---------------------------------------------------------------------------
This Bruker thing has a lot of internal error conditions and a few nasty
habits. Such as to lock up after an error ocurred until the error is reset.
Or to switch the power off, when a current above the limit is requested
after setting a bad value for the magnetic field. These problems can be
detected by analysing the return values from the Bruker. Usually the Bruker
returns the command given to the user plus additional values if requested.
On an error a string of the type E0n is appended to the command echo with
n being a small integer. In order to handle this all commands to the Bruker
are processed through this special function which takes care of the error
handling.
*/
static int BrukerCommand(pBrukerDriv self, char *pCommand,
char *pReplyBuffer, int iReplyLen)
{
int iTest, iCode;
char *pPtr;
assert(self);
assert(iReplyLen > 20); /* so small a buffer will hide errors */
if(self->pData == NULL)
{
self->iLastError = NOCONN;
return 0;
}
/* send the command to the Bruker */
rmtrail(pCommand);
iTest = SerialWriteRead(&(self->pData), pCommand,pReplyBuffer, iReplyLen);
#ifdef debug
printf("Comm: %s , Reply %s\n",pCommand,pReplyBuffer);
#endif
if(iTest != 1) /* communication error */
{
self->iLastError = iTest;
return 0;
}
/* identify timeout */
if(strstr(pReplyBuffer,"?TMO") != NULL)
{
self->iLastError = BTIMEOUT;
return 0;
}
/* try to find a E0 response indicating a Bruker error */
if( (pPtr = strstr(pReplyBuffer,"E0")) == NULL)
{
return 1;
}
/* decode the error */
sscanf(pPtr+1,"%x",&iCode);
switch(iCode)
{
case 1:
self->iLastError = NOFUNC;
break;
case 2:
self->iLastError = BADARG;
break;
case 4:
self->iLastError = NOACCESS;
break;
case 5:
self->iLastError = BADRANGE;
break;
case 7:
self->iLastError = ERRPENDING;
break;
case 9:
self->iLastError = NOPOWER;
break;
case 10:
self->iLastError = NOTFIELD;
break;
default:
self->iLastError = BADINTERN;
break;
}
return 0;
}
/*-------------------------------------------------------------------------*/
int BrukerReadField(pEVControl pEva, float *fField)
{
pBrukerDriv self = NULL;
int iRet;
char pBueffel[80];
char pCommand[6];
char *pPtr,*pSign;
int iSign = 1;
float fVal;
self = (pBrukerDriv)pEva->pDriv->pPrivate;
assert(self);
if(self->pData == NULL)
{
self->iLastError = NOCONN;
return 0;
}
strcpy(pCommand,"CUF/");
iRet = BrukerCommand(self,pCommand,pBueffel,79);
if(!iRet)
{
*fField = -99;
return 0;
}
pPtr = pBueffel+4; /* skip over echo */
/* deal with obstructing sign */
if( (pSign = strchr(pPtr,'+')) != NULL)
{
*pSign = ' ';
iSign = 1;
}
if( (pSign = strchr(pPtr,'-')) != NULL)
{
*pSign = ' ';
iSign = -1;
}
sscanf(pPtr,"%f",&fVal);
*fField = iSign * fVal;
return 1;
}
/*-------------------------------------------------------------------------*/
int BrukerReadCurrent(pEVControl pEva, float *fField)
{
pBrukerDriv self = NULL;
int iRet, iSign = 1;
char pBueffel[80];
char pCommand[6];
char *pPtr, *pSign = NULL;
float fVal;
self = (pBrukerDriv)pEva->pDriv->pPrivate;
assert(self);
if(self->pData == NULL)
{
self->iLastError = NOCONN;
return 0;
}
strcpy(pCommand,"CHN/");
iRet = BrukerCommand(self,pCommand,pBueffel,79);
if(!iRet)
{
*fField = -99;
return 0;
}
pPtr = pBueffel+4; /* skip over echo */
/* deal with obstructing sign */
if( (pSign = strchr(pPtr,'+')) != NULL)
{
*pSign = ' ';
iSign = 1;
}
if( (pSign = strchr(pPtr,'-')) != NULL)
{
*pSign = ' ';
iSign = -1;
}
sscanf(pPtr,"%f",&fVal);
*fField = iSign * fVal;
return 1;
}
/*-------------------------------------------------------------------------*/
static int BrukerGet(pEVDriver pEva, float *fValue)
{
pBrukerDriv self = NULL;
int iRet, iSign = 1;
char pBueffel[80];
char pCommand[6];
char *pPtr, *pSign = NULL;
float fVal;
self = (pBrukerDriv)pEva->pPrivate;
assert(self);
if(self->pData == NULL)
{
self->iLastError = NOCONN;
return 0;
}
if(self->iMode == FIELD)
{
strcpy(pCommand,"CUF/");
iRet = BrukerCommand(self,pCommand,pBueffel,79);
}
else if(self->iMode == CURRENT)
{
strcpy(pCommand,"CUR/");
iRet = BrukerCommand(self,pCommand,pBueffel,79);
}
else
{
/* programming error */
assert(1);
}
if(!iRet)
{
*fValue = -99;
return 0;
}
pPtr = pBueffel+4; /* skip over echo */
/* deal with obstructing sign */
if( (pSign = strchr(pPtr,'+')) != NULL)
{
*pSign = ' ';
iSign = 1;
}
if( (pSign = strchr(pPtr,'-')) != NULL)
{
*pSign = ' ';
iSign = -1;
}
sscanf(pPtr,"%f",&fVal);
*fValue = iSign * fVal;
return 1;
}
/*-------------------------------------------------------------------------*/
static int BrukerRun(pEVDriver pEva, float fVal)
{
pBrukerDriv self = NULL;
int iRet;
char pBueffel[80];
char pCommand[40];
char *pPtr;
self = (pBrukerDriv)pEva->pPrivate;
assert(self);
if(self->pData == NULL)
{
self->iLastError = NOCONN;
return 0;
}
if(self->iMode == FIELD)
{
sprintf(pCommand,"PTF=%-6.2f",fVal);
iRet = BrukerCommand(self,pCommand,pBueffel,79);
}
else if(self->iMode == CURRENT)
{
sprintf(pCommand,"PNT=%-6.2f",fVal);
iRet = BrukerCommand(self,pCommand,pBueffel,79);
}
else
{
/* programming error */
assert(1);
}
if(!iRet)
{
return 0;
}
return 1;
}
/*------------------------------------------------------------------------*/
static int BrukerError(pEVDriver pEva, int *iCode, char *pError,
int iErrLen)
{
pBrukerDriv self = NULL;
self = (pBrukerDriv)pEva->pPrivate;
assert(self);
*iCode = self->iLastError;
switch(*iCode)
{
case NOFUNC:
strncpy(pError,
"Function not supported",
iErrLen);
break;
case BADINTERN:
case BADARG:
strncpy(pError,
"Programming problem, reset Controller & contact Programmer",
iErrLen);
break;
case NOTFIELD:
strncpy(pError,"Bruker not switched to field mode",iErrLen);
break;
case BADRANGE:
strncpy(pError,"Requested value out of range",iErrLen);
break;
case NOACCESS:
strncpy(pError,"No Access, check key position at Controller",
iErrLen);
break;
case ERRPENDING:
strncpy(pError,"Error condition pending in Bruker Controller",
iErrLen);
break;
case NOPOWER:
strncpy(pError,
"Power OFF as consequence of some error in Bruker Controller",
iErrLen);
break;
case NOCONN:
strncpy(pError,"No Connection to Bruker Controller",iErrLen);
break;
case BTIMEOUT:
strncpy(pError,"Timeout at serial port",iErrLen);
break;
case NOPOLUNIT:
strncpy(pError,"No polarity switching unit, try setting negative current",
iErrLen);
break;
default:
SerialError(*iCode,pError,iErrLen);
break;
}
return 1;
}
/*---------------------------------------------------------------------------*/
static int BrukerSend(pEVDriver pEva, char *pCommand, char *pReply,
int iReplyLen)
{
pBrukerDriv self = NULL;
int iRet;
self = (pBrukerDriv)pEva->pPrivate;
assert(self);
if(self->pData == NULL)
{
self->iLastError = NOCONN;
return 0;
}
iRet = SerialWriteRead(&(self->pData),pCommand, pReply, iReplyLen);
if(iRet != 1)
{
self->iLastError = iRet;
return 0;
}
return 1;
}
/*--------------------------------------------------------------------------*/
static int BrukerInit(pEVDriver pEva)
{
pBrukerDriv self = NULL;
int iRet;
char pBueffel[80], pCommand[20];
self = (pBrukerDriv)pEva->pPrivate;
assert(self);
/* open port connection */
self->pData = NULL;
iRet = SerialOpen(&(self->pData),self->pHost, self->iPort, self->iChannel);
if(iRet != 1)
{
self->iLastError = iRet;
return 0;
}
/* configure serial port terminators */
SerialSendTerm(&(self->pData),"\r");
SerialATerm(&(self->pData),"1\r\n");
/* set power on */
strcpy(pCommand,"DCP=1");
iRet = SerialWriteRead(&(self->pData),pCommand,pBueffel,80);
if(iRet != 1)
{
self->iLastError = iRet;
return 0;
}
/* switch to current mode as default init mode */
self->iMode = CURRENT;
strcpy(pCommand,"EXT=0");
iRet = SerialWriteRead(&(self->pData),pCommand,pBueffel,80);
if(iRet != 1)
{
self->iLastError = iRet;
return 0;
}
return 1;
}
/*-------------------------------------------------------------------------*/
static int BrukerClose(pEVDriver pEva)
{
pBrukerDriv self = NULL;
self = (pBrukerDriv)pEva->pPrivate;
assert(self);
SerialClose(&(self->pData));
self->pData = 0;
return 1;
}
/*---------------------------------------------------------------------------*/
static int BrukerFix(pEVDriver self, int iError)
{
pBrukerDriv pMe = NULL;
int iRet;
char pCommand[20], pBueffel[80];
assert(self);
pMe = (pBrukerDriv )self->pPrivate;
assert(pMe);
switch(iError)
{
/* network errors */
case EL734__BAD_FLUSH:
case EL734__BAD_RECV:
case EL734__BAD_RECV_NET:
case EL734__BAD_RECV_UNKN:
case EL734__BAD_RECVLEN:
case EL734__BAD_RECV1:
case EL734__BAD_RECV1_PIPE:
case EL734__BAD_RNG:
case EL734__BAD_SEND:
case EL734__BAD_SEND_PIPE:
case EL734__BAD_SEND_NET:
case EL734__BAD_SEND_UNKN:
case EL734__BAD_SENDLEN:
BrukerClose(self);
iRet = BrukerInit(self);
if(iRet)
{
return DEVREDO;
}
else
{
return DEVFAULT;
}
break;
case EL734__FORCED_CLOSED:
case NOCONN:
iRet = BrukerInit(self);
if(iRet)
{
return DEVREDO;
}
else
{
return DEVFAULT;
}
break;
/* fixable Bruker Errors */
case ERRPENDING:
strcpy(pCommand,"RST=0");
iRet = BrukerCommand(pMe,pCommand, pBueffel,79);
if(iRet)
{
return DEVREDO;
}
else
{
return DEVFAULT;
}
break;
case NOPOWER:
strcpy(pCommand,"RST=0");
iRet = BrukerCommand(pMe,pCommand, pBueffel,79);
strcpy(pCommand,"DCP=1");
iRet = BrukerCommand(pMe,pCommand, pBueffel,79);
if(iRet)
{
return DEVREDO;
}
else
{
return DEVFAULT;
}
break;
case NOTFIELD:
strcpy(pCommand,"EXT=2");
iRet = BrukerCommand(pMe,pCommand, pBueffel,79);
if(iRet)
{
return DEVREDO;
}
else
{
return DEVFAULT;
}
break;
/* handable protocoll errors */
case EL734__BAD_TMO:
case BTIMEOUT:
case NOFUNC:
return DEVREDO;
break;
default:
return DEVFAULT;
break;
}
return DEVFAULT;
}
/*------------------------------------------------------------------------*/
void KillBruker(void *pData)
{
pBrukerDriv pMe = NULL;
pMe = (pBrukerDriv)pData;
assert(pMe);
if(pMe->pHost)
{
free(pMe->pHost);
}
free(pMe);
}
/*------------------------------------------------------------------------*/
pEVDriver CreateBrukerDriver(int argc, char *argv[])
{
pEVDriver pNew = NULL;
pBrukerDriv pSim = NULL;
/* check for arguments */
if(argc < 3)
{
return NULL;
}
pNew = CreateEVDriver(argc,argv);
pSim = (pBrukerDriv)malloc(sizeof(BrukerDriv));
memset(pSim,0,sizeof(BrukerDriv));
if(!pNew || !pSim)
{
return NULL;
}
pNew->pPrivate = pSim;
pNew->KillPrivate = KillBruker;
/* initalise pBrukerDriver */
pSim->iLastError = 0;
pSim->pHost = strdup(argv[0]);
pSim->iPort = atoi(argv[1]);
pSim->iChannel = atoi(argv[2]);
/* initialise function pointers */
pNew->SetValue = BrukerRun;
pNew->GetValue = BrukerGet;
pNew->Send = BrukerSend;
pNew->GetError = BrukerError;
pNew->TryFixIt = BrukerFix;
pNew->Init = BrukerInit;
pNew->Close = BrukerClose;
return pNew;
}
/*-------------------------------------------------------------------------*/
int BrukerSetMode(pEVControl pEva, SConnection *pCon, int iMode)
{
pBrukerDriv self = NULL;
int iRet;
char pBueffel[80];
char pCommand[6];
char *pPtr;
self = (pBrukerDriv)pEva->pDriv->pPrivate;
assert(self);
if(self->pData == NULL)
{
self->iLastError = NOCONN;
return 0;
}
if(iMode == CURRENT)
{
strcpy(pCommand,"EXT=0");
}
else if(iMode == FIELD)
{
strcpy(pCommand,"EXT=2");
}
else
{
SCWrite(pCon,"ERROR: Internal: invalid mode for Bruker given",eError);
return 0;
}
iRet = BrukerCommand(self,pCommand,pBueffel,79);
if(!iRet)
{
strcpy(pBueffel,"ERROR:");
BrukerError(pEva->pDriv,&iRet,(pBueffel+7),70);
SCWrite(pCon,pBueffel,eError);
return 0;
}
self->iMode = iMode;
return 1;
}
/*-------------------------------------------------------------------------*/
int BrukerGetPolarity(pEVControl pEva, SConnection *pCon, int *iMode)
{
pBrukerDriv self = NULL;
int iRet;
char pBueffel[80];
char pCommand[6];
char *pPtr;
self = (pBrukerDriv)pEva->pDriv->pPrivate;
assert(self);
if(self->pData == NULL)
{
self->iLastError = NOCONN;
return 0;
}
strcpy(pCommand,"POL/");
iRet = BrukerCommand(self,pCommand,pBueffel,79);
if(!iRet)
{
strcpy(pBueffel,"ERROR:");
BrukerError(pEva->pDriv,&iRet,(pBueffel+7),70);
SCWrite(pCon,pBueffel,eError);
return 0;
}
pPtr = pBueffel+4;
sscanf(pPtr,"%d",iMode);
return 1;
}
/*------------------------------------------------------------------------*/
int BrukerSetPolarity(pEVControl pEva, SConnection *pCon, int iMode)
{
pBrukerDriv self = NULL;
int iRet;
char pBueffel[80];
char pCommand[6];
char *pPtr;
self = (pBrukerDriv)pEva->pDriv->pPrivate;
assert(self);
if(self->pData == NULL)
{
self->iLastError = NOCONN;
return 0;
}
if(iMode == PPLUS)
{
strcpy(pCommand,"POL=0");
}
else if(iMode == PMINUS)
{
strcpy(pCommand,"POL=1");
}
else
{
assert(1); /* programming error */
}
iRet = BrukerCommand(self,pCommand,pBueffel,79);
if( (strstr(pBueffel,"POL=0E01") != NULL) ||
(strstr(pBueffel,"POL=1E01") != NULL) )
{
self->iLastError = NOPOLUNIT;
iRet = 0;
}
if(!iRet)
{
strcpy(pBueffel,"ERROR:");
BrukerError(pEva->pDriv,&iRet,(pBueffel+6),70);
SCWrite(pCon,pBueffel,eError);
return 0;
}
return 1;
}
/*--------------------------------------------------------------------------
handle Bruker specific commands:
- polarity for switching polarity
- field for reading field
- current for reading current
- mode for setting and retrieving the current control mode
- list append our own stuff to the rest
in all other cases fall back and call EVControllerWrapper to handle it or
eventually throw an error.
*/
int BrukerAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
pEVControl self = NULL;
int iRet, iMode;
char pBueffel[256];
pBrukerDriv pMe = NULL;
float fVal;
self = (pEVControl)pData;
assert(self);
pMe = (pBrukerDriv)self->pDriv->pPrivate;
assert(pMe);
if(argc > 1)
{
strtolower(argv[1]);
/*------ polarity */
if(strcmp(argv[1],"polarity") == 0)
{
if(argc > 2) /* set case */
{
strtolower(argv[2]);
if(strcmp(argv[2],"plus") == 0)
{
iMode = PPLUS;
}
else if(strcmp(argv[2],"minus") == 0)
{
iMode = PMINUS;
}
else
{
sprintf(pBueffel,"ERROR: %s is no knwon polarity mode", argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/* check permission */
if(!SCMatchRights(pCon,usUser))
{
return 0;
}
/* do it */
iRet = BrukerSetPolarity(self,pCon,iMode);
if(iRet)
{
SCSendOK(pCon);
return 1;
}
else
{
return 0;
}
}
else /* get case */
{
iRet = BrukerGetPolarity(self,pCon,&iMode);
if(iRet)
{
if(iMode == PPLUS)
{
sprintf(pBueffel,"%s.polarity = plus",argv[0]);
}
else if (iMode == PMINUS)
{
sprintf(pBueffel,"%s.polarity = minus",argv[0]);
}
else
{
assert(1); /* programming problem */
}
SCWrite(pCon,pBueffel,eValue);
return 1;
}
}
}
/*-------- control mode */
else if(strcmp(argv[1],"mode") == 0)
{
if(argc > 2) /* set case */
{
strtolower(argv[2]);
if(strcmp(argv[2],"field") == 0)
{
iMode = FIELD;
}
else if(strcmp(argv[2],"current") == 0)
{
iMode = CURRENT;
}
else
{
sprintf(pBueffel,"ERROR: %s is no known control mode", argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/* check permission */
if(!SCMatchRights(pCon,usUser))
{
return 0;
}
/* do it */
iRet = BrukerSetMode(self,pCon,iMode);
if(iRet)
{
SCSendOK(pCon);
return 1;
}
else
{
return 0;
}
}
else /* get case */
{
if(pMe->iMode == FIELD)
{
sprintf(pBueffel,"%s.mode = field",argv[0]);
}
else if (pMe->iMode == CURRENT)
{
sprintf(pBueffel,"%s.mode = current",argv[0]);
}
else
{
assert(1); /* programming problem */
}
SCWrite(pCon,pBueffel,eValue);
return 1;
}
}
/*-----------field */
else if(strcmp(argv[1],"field") == 0)
{
iRet = BrukerReadField(self,&fVal);
if(!iRet)
{
strcpy(pBueffel,"ERROR: ");
self->pDriv->GetError(self->pDriv,&iMode,pBueffel+7,240);
SCWrite(pCon,pBueffel,eError);
return 0;
}
sprintf(pBueffel,"%s.field = %f Tesla",argv[0],fVal);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
/*----------- current */
else if(strcmp(argv[1],"current") == 0)
{
iRet = BrukerReadCurrent(self,&fVal);
if(!iRet)
{
strcpy(pBueffel,"ERROR: ");
self->pDriv->GetError(self->pDriv,&iMode,pBueffel+7,240);
SCWrite(pCon,pBueffel,eError);
return 0;
}
sprintf(pBueffel,"%s.current = %f A",argv[0],fVal);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
/*--------- list */
else if(strcmp(argv[1],"list") == 0)
{
/* print generals first */
EVControlWrapper(pCon,pSics,pData,argc,argv);
/* print our add on stuff */
iRet = BrukerReadCurrent(self,&fVal);
if(!iRet)
{
strcpy(pBueffel,"ERROR: ");
self->pDriv->GetError(self->pDriv,&iMode,pBueffel+7,240);
SCWrite(pCon,pBueffel,eError);
}
else
{
sprintf(pBueffel,"%s.current = %f A",argv[0],fVal);
SCWrite(pCon,pBueffel,eValue);
}
iRet = BrukerReadField(self,&fVal);
if(!iRet)
{
strcpy(pBueffel,"ERROR: ");
self->pDriv->GetError(self->pDriv,&iMode,pBueffel+7,240);
SCWrite(pCon,pBueffel,eError);
}
else
{
sprintf(pBueffel,"%s.field = %f Tesla",argv[0],fVal);
SCWrite(pCon,pBueffel,eValue);
}
if(pMe->iMode == FIELD)
{
sprintf(pBueffel,"%s.mode = field",argv[0]);
}
else if (pMe->iMode == CURRENT)
{
sprintf(pBueffel,"%s.mode = current",argv[0]);
}
else
{
sprintf(pBueffel,"ERROR: Programming error");
}
SCWrite(pCon,pBueffel,eValue);
iRet = BrukerGetPolarity(self,pCon,&iMode);
if(iRet)
{
if(iMode == PPLUS)
{
sprintf(pBueffel,"%s.polarity = plus",argv[0]);
}
else if (iMode == PMINUS)
{
sprintf(pBueffel,"%s.polarity = minus",argv[0]);
}
else if(iMode == PBUSY)
{
sprintf(pBueffel,"%s.polarity = busy",argv[0]);
}
else
{
sprintf(pBueffel,"ERROR: Programming problem");
}
SCWrite(pCon,pBueffel,eValue);
}
else
{
SCWrite(pCon,"ERROR: cannot read polarity",eError);
}
return 1;
}
else
{
return EVControlWrapper(pCon,pSics,pData,argc,argv);
}
}
return EVControlWrapper(pCon,pSics,pData,argc,argv);
}

25
bruker.h Normal file
View File

@ -0,0 +1,25 @@
/*-------------------------------------------------------------------------
B r u k e r
An environment control driver and an additonal wrapper function for
controlling a Bruker B-EC-1 magnet controller. This controller can
either control a current or control the current through an external hall
sensor mesuring the magnetic field. In both cases both values: the field
and the current must be readable.
copyright: see copyright.h
Mark Koennecke, October 1998
---------------------------------------------------------------------------*/
#ifndef BRUKERMAGNET
#define BRUKERMAGNET
pEVDriver CreateBrukerDriver(int argc, char *argv[]);
int BrukerReadField(pEVControl self, float *fField);
int BrukerReadCurrent(pEVControl self, float *fCurrent);
int BrukerAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
#endif

64
bruker.tex Normal file
View File

@ -0,0 +1,64 @@
\subsubsection{Bruker Magnet Controller B-EC-1}
SANS is using a Bruker magnet controller. This controller is integrated
into SICS as a derivate of an environment controller. The Bruker controller
can be operated in two modes: in the first the current is controlled,
in the second the current
is controlled by an external hall sensor giving the magnetic field. Whatever
is the controlling sensor, the magnetic field and the current need to be
read. Furthermore this device supports switching the polarity. All this is
achieved with a special driver and an additional wrapper function for
handling extra commands. All this is implemented in the file bruker.h
and bruker.c. The functions defined are:
\begin{verbatim}
pEVDriver CreateBrukerDriver(int argc, char *argv[]);
int BrukerReadField(pEVControl self, float *fField);
int BrukerReadCurrent(pEVControl self, float *fCurrent);
int BrukerAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
\end{verbatim}
\begin{description}
\item[CreateBrukerDriver] creates a driver for the bruker magnet
controller.
\item[BrukerReadField] reads the current magnetic field.
\item[BrukerReadCurrent] reads the current current in Ampere.
\item[BrukerAction] a special SICS interpreter wrapper function for
the Bruker Magnet. This function handles the few special Bruker
commands and passes everything else to the standard environment
controller handler function.
\end{description}

64
bruker.w Normal file
View File

@ -0,0 +1,64 @@
\subsubsection{Bruker Magnet Controller B-EC-1}
SANS is using a Bruker magnet controller. This controller is integrated
into SICS as a derivate of an environment controller. The Bruker controller
can be operated in two modes: in the first the current is controlled,
in the second the current
is controlled by an external hall sensor giving the magnetic field. Whatever
is the controlling sensor, the magnetic field and the current need to be
read. Furthermore this device supports switching the polarity. All this is
achieved with a special driver and an additional wrapper function for
handling extra commands. All this is implemented in the file bruker.h
and bruker.c. The functions defined are:
\begin{verbatim}
pEVDriver CreateBrukerDriver(int argc, char *argv[]);
int BrukerReadField(pEVControl self, float *fField);
int BrukerReadCurrent(pEVControl self, float *fCurrent);
int BrukerAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
\end{verbatim}
\begin{description}
\item[CreateBrukerDriver] creates a driver for the bruker magnet
controller.
\item[BrukerReadField] reads the current magnetic field.
\item[BrukerReadCurrent] reads the current current in Ampere.
\item[BrukerAction] a special SICS interpreter wrapper function for
the Bruker Magnet. This function handles the few special Bruker
commands and passes everything else to the standard environment
controller handler function.
\end{description}

593
buffer.c Normal file
View File

@ -0,0 +1,593 @@
/*--------------------------------------------------------------------------
L N S R \"U N B U F F E R
Mark Koennecke, January 1997
Copyright:
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5423 Villigen-PSI
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
----------------------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <tcl.h>
#include "fortify.h"
#include "lld.h"
#include "lld_blob.h"
#include "lld_str.h"
#include "conman.h"
#include "obdes.h"
#include "buffer.h"
#include "fupa.h"
#include "splitter.h"
#include "ruli.h"
#include "qcbo.h"
/*-------------------------------------------------------------------------*/
static int SaveBuffer(void *pData, char *name, FILE *fd)
{
pRuenBuffer self = NULL;
int iRet;
char *pPtr = NULL;
assert(fd);
assert(pData);
self = (pRuenBuffer)pData;
fprintf(fd,"# RuenBuffer %s\n",name);
fprintf(fd,"Buf new %s\n",name);
iRet = LLDnodePtr2First(self->iLineList);
while(iRet != 0)
{
pPtr = (char *)LLDnodePtr(self->iLineList);
fprintf(fd,"%s append %s\n",name,pPtr);
iRet = LLDnodePtr2Next(self->iLineList);
}
return 1;
}
/*--------------------------------------------------------------------------*/
pRuenBuffer CreateRuenBuffer(char *name)
{
pRuenBuffer pNew = NULL;
pNew = (pRuenBuffer)malloc(sizeof(RuenBuffer));
if(!pNew)
{
return NULL;
}
pNew->pDes = CreateDescriptor("SicsRuenBuffer");
if(!pNew->pDes)
{
free(pNew);
return NULL;
}
pNew->name = strdup(name);
Fortify_CheckAllMemory();
pNew->iLineList = LLDblobCreate();
if(pNew->iLineList == -1)
{
DeleteDescriptor(pNew->pDes);
free(pNew->name);
free(pNew);
return NULL;
}
pNew->pDes->SaveStatus = SaveBuffer;
return pNew;
}
/*--------------------------------------------------------------------------*/
static void DeleteLineBuffer(int iList)
{
int iRet;
char *pPtr;
iRet = LLDnodePtr2First(iList);
while(iRet != 0)
{
pPtr = (char *)LLDnodePtr(iList);
free(pPtr);
iRet = LLDnodePtr2Next(iList);
}
LLDdelete(iList);
}
/*-------------------------------------------------------------------------*/
void DeleteRuenBuffer(void *self)
{
int iRet;
pRuenBuffer pOld = (pRuenBuffer)self;
assert(pOld);
/* delete line buffer */
DeleteLineBuffer(pOld->iLineList);
if(pOld->name)
{
free(pOld->name);
}
if(pOld->pDes)
{
DeleteDescriptor(pOld->pDes);
}
free(pOld);
}
/*--------------------------------------------------------------------------*/
pRuenBuffer CopyRuenBuffer(pRuenBuffer pOld, char *name)
{
pRuenBuffer pNew = NULL;
int iRet;
char *pPtr;
pNew = CreateRuenBuffer(name);
if(!pNew)
{
return NULL;
}
/* copy list*/
iRet = LLDnodePtr2First(pOld->iLineList);
while(iRet != 0)
{
pPtr = (char *)LLDnodePtr(pOld->iLineList);
LLDstringAdd(pNew->iLineList,pPtr);
iRet = LLDnodePtr2Next(pOld->iLineList);
}
return pNew;
}
/*-------------------------------------------------------------------------*/
int BufferAppendLine(pRuenBuffer self, char *line)
{
assert(self);
return LLDstringAppend(self->iLineList,line);
}
/*------------------------------------------------------------------------*/
int BufferDel(pRuenBuffer self, int i)
{
int iNum;
int iRet;
assert(self);
iRet = LLDnodePtr2First(self->iLineList);
iNum = 0;
while(iRet != 0)
{
if(iNum == i)
{
LLDstringDelete(self->iLineList);
return 1;
}
iNum++;
iRet = LLDnodePtr2Next(self->iLineList);
}
return 0;
}
/*------------------------------------------------------------------------*/
int BufferInsertAfter(pRuenBuffer self, int i, char *line)
{
int iNum;
int iRet;
assert(self);
iRet = LLDnodePtr2First(self->iLineList);
iNum = 0;
while(iRet != 0)
{
if(iNum == i)
{
LLDstringInsert(self->iLineList, line);
return 1;
}
iNum++;
iRet = LLDnodePtr2Next(self->iLineList);
}
return 0;
}
/*------------------------------------------------------------------------*/
int BufferPrint(pRuenBuffer self, SConnection *pCon)
{
int iRet;
char *pPtr = NULL;
char pBueffel[512];
int iCount = 1;
iRet = LLDnodePtr2First(self->iLineList);
sprintf(pBueffel,"Listing for Bueffer %s",self->name);
SCWrite(pCon,pBueffel,eValue);
while(iRet != 0)
{
pPtr = (char *)LLDnodePtr(self->iLineList);
sprintf(pBueffel,"[%d] %s",iCount,pPtr);
SCWrite(pCon,pBueffel,eValue);
iRet = LLDnodePtr2Next(self->iLineList);
iCount++;
}
return 1;
}
/*------------------------------------------------------------------------*/
extern char *StrReplace(char *str, char *old, char *pNew);
/* realised in Strrepl.c
*/
int BufferReplace(pRuenBuffer self, char *pattern, char *pReplace)
{
int iRet;
char *pPtr = NULL;
char pBueffel[1024];
char *pRet;
iRet = LLDnodePtr2First(self->iLineList);
while(iRet != 0)
{
pPtr = (char *)LLDnodePtr(self->iLineList);
strcpy(pBueffel,pPtr);
pRet = NULL;
pRet = StrReplace(pBueffel,pattern,pReplace);
if(pRet)
{
LLDstringDelete(self->iLineList);
iRet = LLDnodePtr2Next(self->iLineList);
LLDnodePtr2Prev(self->iLineList);
if(iRet)
{
LLDstringInsert(self->iLineList,pBueffel);
}
else
{
LLDstringAppend(self->iLineList,pBueffel);
}
}
iRet = LLDnodePtr2Next(self->iLineList);
}
return 1;
}
/*-----------------------------------------------------------------------*/
int BufferRun(pRuenBuffer self, SConnection *pCon, SicsInterp *pSics)
{
int iRet;
char *pPtr = NULL;
int iInt, iRes;
iRes = 1;
iRet = LLDnodePtr2First(self->iLineList);
while(iRet != 0)
{
pPtr = (char *)LLDnodePtr(self->iLineList);
iInt = InterpExecute(pSics,pCon,pPtr);
if(!iInt)
{
iRes = 0;
}
iRet = LLDnodePtr2Next(self->iLineList);
}
return iRes;
}
/*------------------------------------------------------------------------*/
int BufferSave(pRuenBuffer self, char *file)
{
int iRet;
char *pPtr = NULL;
FILE *fd = NULL;
fd = fopen(file,"w");
if(fd == NULL)
{
return 0;
}
iRet = LLDnodePtr2First(self->iLineList);
while(iRet != 0)
{
pPtr = (char *)LLDnodePtr(self->iLineList);
fprintf(fd,"%s\n",pPtr);
iRet = LLDnodePtr2Next(self->iLineList);
}
fclose(fd);
return 1;
}
/*------------------------------------------------------------------------*/
int BufferLoad(pRuenBuffer self, char *file)
{
int iRet;
char *pPtr = NULL;
FILE *fd = NULL;
char pBueffel[256];
fd = fopen(file,"r");
if(fd == NULL)
{
return 0;
}
pPtr = fgets(pBueffel,255,fd);
while(pPtr != NULL)
{
LLDstringAppend(self->iLineList,pBueffel);
pPtr = fgets(pBueffel,255,fd);
}
fclose(fd);
return 1;
}
/*------------------------------------------------------------------------*/
pRuenBuffer FindRuenBuffer(SicsInterp *pSics, char *name)
{
pRuenBuffer pBuf = NULL;
CommandList *pCom = NULL;
pCom = FindCommand(pSics,name);
if(!pCom)
{
return NULL;
}
pBuf = (pRuenBuffer)pCom->pData;
if(!pBuf)
{
return NULL;
}
if(!pBuf->pDes)
{
return NULL;
}
if(strcmp(pBuf->pDes->name,"SicsRuenBuffer") != 0)
{
return NULL;
}
return pBuf;
}
/*-------------------------------------------------------------------------*/
int InitBufferSys(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
pRuenStack pStack = NULL;
pCBQueue q = NULL;
pStack = CreateRuenStack();
if(!pStack)
{
SCWrite(pCon,"ERROR: No memory to create Ruen-Stack",eError);
return 0;
}
q = CreateCBQueue();
if(!q)
{
SCWrite(pCon,"ERROR: No memory to create Queue",eError);
return 0;
}
AddCommand(pSics,"Buf",BufferCommand,NULL,NULL);
AddCommand(pSics,"Stack",RuenStackAction,DeleteRuenStack,pStack);
AddCommand(pSics,"queue",QueueAction,NULL,q);
return 1;
}
/*------------------------------------------------------------------------*/
int BufferCommand(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
int iRet, iRet2;
char pBueffel[512];
char **argx;
FuPaResult PaRes;
pRuenBuffer pBuf = NULL;
FuncTemplate BufferTemplate[] = {
{"new",1,{FUPATEXT} },
{"del",1,{FUPATEXT} },
{"copy",2,{FUPATEXT, FUPATEXT}},
};
assert(pCon);
assert(pSics);
/* minimum user to use this */
if(!SCMatchRights(pCon,usUser))
{
return 0;
}
/* parse function args */
argtolower(argc,argv);
argx = &argv[1];
iRet = EvaluateFuPa((pFuncTemplate)&BufferTemplate,3,argc-1,argx,&PaRes);
if(iRet < 0)
{
sprintf(pBueffel,"%s",PaRes.pError);
SCWrite(pCon,pBueffel,eError);
return 0;
}
switch(iRet)
{
case 0: /* new */
pBuf = CreateRuenBuffer(PaRes.Arg[0].text);
if(!pBuf)
{
SCWrite(pCon, "ERROR: Out of memory allocating buffer",eError);
return 0;
}
iRet2 = AddCommand(pSics,pBuf->name,BufferAction,DeleteRuenBuffer,
(void *)pBuf);
if(!iRet2)
{
sprintf(pBueffel,"ERROR: duplicate command %s not created",pBuf->name);
SCWrite(pCon,pBueffel,eError);
DeleteRuenBuffer((void *)pBuf);
return 0;
}
return 1;
break;
case 1: /* del */
return RemoveCommand(pSics,PaRes.Arg[0].text);
break;
case 2: /* copy */
pBuf = FindRuenBuffer(pSics,PaRes.Arg[0].text);
if(!pBuf)
{
sprintf(pBueffel,"ERROR: Buffer %s not found",
PaRes.Arg[0].text);
SCWrite(pCon,pBueffel,eError);
return 0;
}
pBuf = CopyRuenBuffer(pBuf,PaRes.Arg[1].text);
if(!pBuf)
{
sprintf(pBueffel,"ERROR: creating buffer %s ",
PaRes.Arg[1].text);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet2 = AddCommand(pSics,pBuf->name,BufferAction,DeleteRuenBuffer,
(void *)pBuf);
if(!iRet2)
{
sprintf(pBueffel,"ERROR: duplicate command %s not created",pBuf->name);
SCWrite(pCon,pBueffel,eError);
DeleteRuenBuffer((void *)pBuf);
return 0;
}
return 1;
break;
default:
assert(0);
break;
}
assert(0);
}
/*-------------------------------------------------------------------------*/
int BufferAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
int iRet, iRet2;
char pBueffel[512];
char **argx;
FuPaResult PaRes;
pRuenBuffer pBuf = NULL;
FuncTemplate BufferTemplate[] = {
{"append",0,{FUPATEXT} },
{"del",1,{FUPAINT} },
{"ins",1,{FUPAINT}},
{"save",1,{FUPATEXT}},
{"load",1,{FUPATEXT}},
{"subst",2,{FUPATEXT,FUPATEXT}},
{"print",0,{0,0}},
{"run",0,{0,0}},
NULL
};
assert(pCon);
assert(pSics);
pBuf = (pRuenBuffer)pData;
assert(pBuf);
/* You need to be user in order to do this */
if(!SCMatchRights(pCon,usUser))
{
return 0;
}
/* parse function args */
argx = &argv[1];
strtolower(argx[0]);
iRet = EvaluateFuPa((pFuncTemplate)&BufferTemplate,8,argc-1,argx,&PaRes);
if(iRet < 0)
{
sprintf(pBueffel,"%s",PaRes.pError);
SCWrite(pCon,pBueffel,eError);
return 0;
}
switch(iRet)
{
case 0: /* append */
argx = &argv[2];
Arg2Text(argc-2,argx,pBueffel,511);
BufferAppendLine(pBuf,pBueffel);
SCSendOK(pCon);
return 1;
break;
case 1: /* del */
iRet2 = BufferDel(pBuf,PaRes.Arg[0].iVal);
if(iRet2)
SCSendOK(pCon);
break;
case 2: /* ins */
argx = &argv[3];
Arg2Text(argc-3,argx,pBueffel,511);
iRet2 = BufferInsertAfter(pBuf,PaRes.Arg[0].iVal,pBueffel);
if(iRet2)
SCSendOK(pCon);
return iRet2;
break;
case 3: /* save */
iRet2 = BufferSave(pBuf,PaRes.Arg[0].text);
if(!iRet2)
{
sprintf(pBueffel,"ERROR: cannot open %s for writing",
PaRes.Arg[0].text);
SCWrite(pCon,pBueffel,eError);
return 0;
}
else
{
SCSendOK(pCon);
return 1;
}
break;
case 4: /* load */
iRet2 = BufferLoad(pBuf,PaRes.Arg[0].text);
if(!iRet2)
{
sprintf(pBueffel,"ERROR: cannot open %s for reading ",
PaRes.Arg[0].text);
SCWrite(pCon,pBueffel,eError);
return 0;
}
else
{
SCSendOK(pCon);
return 1;
}
break;
case 5: /* subst */
iRet2 = BufferReplace(pBuf,PaRes.Arg[0].text,PaRes.Arg[1].text);
if(iRet2)
SCSendOK(pCon);
break;
case 6: /* print */
return BufferPrint(pBuf,pCon);
break;
case 7: /* run */
return BufferRun(pBuf,pCon,pSics);
default:
assert(0);
}
return 1;
}

94
buffer.h Normal file
View File

@ -0,0 +1,94 @@
/*---------------------------------------------------------------------------
T H E L N S R \" U N B U F F E R
The LNS has devised a special scheme to operate an instrument
via R\"un sequeneces and buffers. A R\"unbuffer is a series of
commands which are collected in a buffer. This buffer is
implemented here. A buffer can be added to, printed loaded from
a file etc. and can be executed.
The next schem is the R\"unlist which is a stack of R\"unbuffers.
That list can be exeuted as well. It gets a buffer from the
bottom of the stack and executes it and does so until the stack
is empty. While this is happening you are able to add other
buffers to the top of the stack. This schem is implemented in module
ruli.
So, here is all necessary to deal with an individual buffer.
For Lists A. Reitsma's lld package will be used. This package
identifies a list by an integer handle.
Mark Koennecke, January 1996
copyright: see implementation file
----------------------------------------------------------------------------*/
#ifndef RUENBUFFER
#define RUENBUFFER
typedef struct {
pObjectDescriptor pDes; /* needed */
char *name; /* BufferName */
int iLineList; /* Handle to the Line List */
} RuenBuffer, *pRuenBuffer;
/*--------------------- live & death ----------------------------------- */
pRuenBuffer CreateRuenBuffer(char *name);
void DeleteRuenBuffer(void *pSelf);
pRuenBuffer CopyRuenBuffer(pRuenBuffer pOld, char *NewName);
/*--------------------- operations --------------------------------------*/
int BufferAppendLine(pRuenBuffer self, char *line);
int BufferDel(pRuenBuffer self, int iLine);
/*
deletes line iLine from the RuenBuffer self
-------------------------------------------------------------------------*/
int BufferInsertAfter(pRuenBuffer self, int iLine, char *line);
/*
inserts line line AFTER line number iLine in the RuenBuffer self
------------------------------------------------------------------------- */
int BufferPrint(pRuenBuffer self, SConnection *pCon);
/*
lists the contents of the RuenBuffer on the Connection pCon
------------------------------------------------------------------------ */
int BufferReplace(pRuenBuffer self, char *pattern, char *pReplace);
/*
replaces all occurences of the string pattern in the whole RuenBuffer
by the replacement string pReplace.
------------------------------------------------------------------------- */
int BufferRun(pRuenBuffer self, SConnection *pCon, SicsInterp *pSics);
/*
executes the lines of the Ruenbuffer one by one.
Returns 1 on success, 0 on error.
------------------------------------------------------------------------- */
int BufferSave(pRuenBuffer self, char *file);
/*
writes the contents of Ruenbuffer self to the file specified by
file.
Returns 1 on success, 0 on error.
--------------------------------------------------------------------------*/
int BufferLoad(pRuenBuffer self, char *file);
/*
reads the contents of file into the RuenBuffer self.
Returns 1 on success, 0 on error.
*/
/* ------------------------ object functions ----------------------------*/
int InitBufferSys(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int BufferCommand(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int BufferAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
/* ----------------------- utility --------------------------------------*/
pRuenBuffer FindRuenBuffer(SicsInterp *pSics, char *name);
/*
similar to FindCommand in SCinter.h. But checks the object found if
it is a RuenBuffer.
Returns NULL if no RuenBuffer with this name could be found.
Returns a pointer to the RuenBuffer, when a RuenBuffer of this
name could be found in the interpreter pSics
----------------------------------------------------------------------------*/
#endif

228
callback.c Normal file
View File

@ -0,0 +1,228 @@
/*--------------------------------------------------------------------------
S I C S C A L L B A C K
Functions needed to deal with the SICSCallback interface. Description is
in file interface.h, interface.w and interface.w.
Mark Koennecke, Juli 1997
Copyright:
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5423 Villigen-PSI
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
----------------------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "fortify.h"
#include "lld.h"
#include "conman.h"
#include "interface.h"
#define CALLBACK 17777
/*--------------------- The interface datastructure ---------------------*/
typedef struct __ICallBack {
int iID;
int iList;
} ICallBack;
/*-------------- The data stored for a single callback ------------------*/
typedef struct {
long iID;
SICSCallBack pFunc;
void *pUserData;
KillFuncIT pKill;
int iEvent;
} CallBackItem, *pCallBackItem;
/*------------------------------------------------------------------------*/
static int CheckPointer(pICallBack self)
{
if(self == NULL) return 0;
if(self->iID != CALLBACK)
{
return 0;
}
return 1;
}
/*-------------------------------------------------------------------------*/
pICallBack CreateCallBackInterface(void)
{
pICallBack pNew = NULL;
pNew = (pICallBack)malloc(sizeof(ICallBack));
if(!pNew)
{
return 0;
}
pNew->iID = CALLBACK;
pNew->iList = LLDcreate(sizeof(CallBackItem));
if(pNew->iList < 0)
{
free(pNew);
return NULL;
}
return pNew;
}
/*--------------------------------------------------------------------------*/
void DeleteCallBackInterface(pICallBack self)
{
int iRet;
CallBackItem sItem;
if(!CheckPointer(self))
{
return;
}
/* kill all userdata associated with callbacks */
iRet = LLDnodePtr2First(self->iList);
while(iRet != 0)
{
LLDnodeDataTo(self->iList,&sItem);
if(sItem.pKill != NULL)
{
sItem.pKill(sItem.pUserData);
}
iRet = LLDnodePtr2Next(self->iList);
}
LLDdelete(self->iList);
free(self);
}
/*--------------------------------------------------------------------------*/
int InvokeCallBack(pICallBack self, int iEvent, void *pEventData)
{
CallBackItem sItem;
int iCurrent, iRet;
int iResult = 1;
if(!CheckPointer(self))
{
return 0;
}
iCurrent = LLDnodePtr2First(self->iList);
while(iCurrent != 0)
{
LLDnodeDataTo(self->iList,&sItem);
if(sItem.iEvent == iEvent)
{
iRet = sItem.pFunc(iEvent, pEventData,sItem.pUserData);
if(!iRet)
{
iResult = 0;
}
}
iCurrent = LLDnodePtr2Next(self->iList);
}
return iResult;
}
/*--------------------------------------------------------------------------*/
static long lCount = 1L;
long RegisterCallback(pICallBack self, int iEvent,
SICSCallBack pFunc,
void *pUserData, KillFunc pKFunc)
{
CallBackItem sItem;
if(!CheckPointer(self))
{
return 0;
}
sItem.iID = lCount++;
assert(pFunc);
sItem.pFunc = pFunc;
sItem.iEvent = iEvent;
sItem.pUserData = pUserData;
sItem.pKill = pKFunc;
LLDnodeAppendFrom(self->iList,&sItem);
return sItem.iID;
}
/*-------------------------------------------------------------------------*/
int RemoveCallback(pICallBack self, long lID)
{
CallBackItem sItem;
int iCurrent;
if(!CheckPointer(self))
{
return 0;
}
iCurrent = LLDnodePtr2First(self->iList);
while(iCurrent != 0)
{
LLDnodeDataTo(self->iList,&sItem);
if(sItem.iID == lID)
{
if(sItem.pKill != NULL)
{
sItem.pKill(sItem.pUserData);
}
LLDnodeDelete(self->iList);
return 1;
}
iCurrent = LLDnodePtr2Next(self->iList);
}
return 0;
}
/*--------------------------------------------------------------------------*/
int RemoveCallback2(pICallBack self, void *pUserData)
{
CallBackItem sItem;
int iCurrent;
if(!CheckPointer(self))
{
return 0;
}
iCurrent = LLDnodePtr2First(self->iList);
while(iCurrent != 0)
{
LLDnodeDataTo(self->iList,&sItem);
if(sItem.pUserData == pUserData)
{
if(sItem.pKill != NULL)
{
sItem.pKill(sItem.pUserData);
}
LLDnodeDelete(self->iList);
}
iCurrent = LLDnodePtr2Next(self->iList);
}
return 1;
}

79
center.tex Normal file
View File

@ -0,0 +1,79 @@
\subsection{Fit and Center}
This is a fit routine for SICS. It takes a scan and tries to find a peak and
its position. Trials showed that fitting a gauss function is not robust
enough for this facility which has to cope with bizarre peak shapes, half
finished measurements and the like. The algorithm choosen tries to find the
center of gravity of the peak. It does this by searching for the maximum
point in the diagram first. Then the points where the peak is below
half maximum are searched for either side of the peak. Within these
limits the COG is calculated. When this is done fit will print some
info about the peak.
Center will the drive the scan variable to the COG of the peak.
The interface to this simple facility is simple:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$fitinter {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __FitCenter *pFit;@\\
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------*/@\\
\mbox{}\verb@ pFit CreateFitCenter(pScanData pScan);@\\
\mbox{}\verb@ void DeleteFitCenter(void *pData);@\\
\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
\mbox{}\verb@ int CalculateFit(pFit self);@\\
\mbox{}\verb@ /* @\\
\mbox{}\verb@ CalcluateFit returns: -1 when left FWHM could not be found@\\
\mbox{}\verb@ -2 when right FWHM could not be found@\\
\mbox{}\verb@ 1 on success@\\
\mbox{}\verb@ */@\\
\mbox{}\verb@ int CalculateFitFromData(pFit self, float fAxis[], long lSum[], @\\
\mbox{}\verb@ int iLen);@\\
\mbox{}\verb@ void GetFitResults(pFit self, float *fNewCenter, float *fStdDev,@\\
\mbox{}\verb@ float *FWHM, float *fMax);@\\
\mbox{}\verb@ int DriveCenter(pFit self, SConnection *pCon, SicsInterp *pSics);@\\
\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
\mbox{}\verb@ int FitFactory(SConnection *pCon,SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ int FitWrapper(SConnection *pCon,SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ int CenterWrapper(SConnection *pCon,SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
\verb@"fitcenter.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*---------------------------------------------------------------------------@\\
\mbox{}\verb@ F I T C E N T E R@\\
\mbox{}\verb@@\\
\mbox{}\verb@ A simple peak finding and center of gravity determination facility for@\\
\mbox{}\verb@ SICS.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see copyright.h@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, October 1997@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSFITCENTER@\\
\mbox{}\verb@#define SICSFITCENTER@\\
\mbox{}\verb@@$\langle$fitinter {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

58
center.w Normal file
View File

@ -0,0 +1,58 @@
\subsection{Fit and Center}
This is a fit routine for SICS. It takes a scan and tries to find a peak and
its position. Trials showed that fitting a gauss function is not robust
enough for this facility which has to cope with bizarre peak shapes, half
finished measurements and the like. The algorithm choosen tries to find the
center of gravity of the peak. It does this by searching for the maximum
point in the diagram first. Then the points where the peak is below
half maximum are searched for either side of the peak. Within these
limits the COG is calculated. When this is done fit will print some
info about the peak.
Center will the drive the scan variable to the COG of the peak.
The interface to this simple facility is simple:
@d fitinter @{
typedef struct __FitCenter *pFit;
/*--------------------------------------------------------------------------*/
pFit CreateFitCenter(pScanData pScan);
void DeleteFitCenter(void *pData);
/*-------------------------------------------------------------------------*/
int CalculateFit(pFit self);
/*
CalcluateFit returns: -1 when left FWHM could not be found
-2 when right FWHM could not be found
1 on success
*/
int CalculateFitFromData(pFit self, float fAxis[], long lSum[],
int iLen);
void GetFitResults(pFit self, float *fNewCenter, float *fStdDev,
float *FWHM, float *fMax);
int DriveCenter(pFit self, SConnection *pCon, SicsInterp *pSics);
/*-------------------------------------------------------------------------*/
int FitFactory(SConnection *pCon,SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int FitWrapper(SConnection *pCon,SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int CenterWrapper(SConnection *pCon,SicsInterp *pSics, void *pData,
int argc, char *argv[]);
@}
@o fitcenter.h @{
/*---------------------------------------------------------------------------
F I T C E N T E R
A simple peak finding and center of gravity determination facility for
SICS.
copyright: see copyright.h
Mark Koennecke, October 1997
----------------------------------------------------------------------------*/
#ifndef SICSFITCENTER
#define SICSFITCENTER
@<fitinter@>
#endif
@}

322
chadapter.c Normal file
View File

@ -0,0 +1,322 @@
/*-------------------------------------------------------------------------
C h o c o A d a p t e r
This is a drivable adapter for the ChopperController object (or also generic
controller object). It allows to modify one of the variables supported by
the controller through the normal SICS drive command. For more information
see file choco.w or choco.tex.
Mark Koennecke, January 1998
---------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <tcl.h>
#include "fortify.h"
#include "sics.h"
#include "choco.h"
#define CHADAINTERNAL
#include "chadapter.h"
/*-------------------------------------------------------------------------*/
static void *AdapterGetInterface(void *pData, int iID)
{
pCHAdapter self = NULL;
self = (pCHAdapter)pData;
assert(self);
if(iID == DRIVEID)
{
return self->pInt;
}
return NULL;
}
/*-------------------------------------------------------------------------*/
static int CHHalt(void *pData)
{
pCHAdapter self = NULL;
self = (pCHAdapter)pData;
assert(self);
self->pDriv->Halt(self->pDriv);
return 1;
}
/*-------------------------------------------------------------------------*/
static int CHLimits(void *pData, float fVal, char *error, int iErrlen)
{
pCHAdapter self = NULL;
self = (pCHAdapter)pData;
assert(self);
if(fVal < self->fLower)
{
strncpy(error,"Lower limit violated",iErrlen);
return 0;
}
if(fVal > self->fUpper)
{
strncpy(error,"Upper limit violated",iErrlen);
return 0;
}
return 1;
}
/*------------------------------------------------------------------------*/
static float CHGetValue(void *pData, SConnection *pCon)
{
pCHAdapter self = NULL;
float fVal;
int iRet;
char pBueffel[80];
self = (pCHAdapter)pData;
assert(self);
iRet = self->pDriv->GetPar(self->pDriv,self->pParName,pBueffel,79);
if(!iRet)
{
fVal = -9999999.99;
self->pDriv->GetError(self->pDriv,&iRet,pBueffel,79);
SCWrite(pCon,pBueffel,eError);
return fVal;
}
sscanf(pBueffel,"%f",&fVal);
return fVal;
}
/*-----------------------------------------------------------------------*/
static int CHStatus(void *pData, SConnection *pCon)
{
pCHAdapter self = NULL;
int iRet, iCode;
static int iRetry = 0;
char pBueffel[80], pError[132];
self = (pCHAdapter)pData;
assert(self);
iRet = self->pDriv->CheckPar(self->pDriv,self->pParName);
switch(iRet)
{
case OKOK:
case HWIdle:
iRetry = 0;
return HWIdle;
case HWFault:
self->pDriv->GetError(self->pDriv,&iCode,pBueffel,79);
iRet = self->pDriv->TryFixIt(self->pDriv,iCode);
sprintf(pError,"ERROR: %s",pBueffel);
SCWrite(pCon,pError,eError);
if(iRet == CHFAIL || iRetry >= 3)
{
iRetry = 0;
return HWFault;
}
else
{
iRetry++;
self->pDriv->SetPar(self->pDriv,self->pParName,
self->fTarget);
return HWBusy;
}
break;
case HWBusy:
return HWBusy;
}
return HWFault;
}
/*-------------------------------------------------------------------------*/
static long CHSetValue(void *pData, SConnection *pCon, float fValue)
{
pCHAdapter self = NULL;
char pBueffel[80], pError[132];
int iRet, iCode, i;
self = (pCHAdapter)pData;
assert(self);
/* check privilege */
if(!SCMatchRights(pCon,usUser))
{
SCWrite(pCon,"ERROR: Insufficient privilege for driving",eError);
return 0;
}
for(i = 0; i < 3; i++)
{
iRet = self->pDriv->SetPar(self->pDriv,self->pParName,fValue);
if(iRet)
{
self->fTarget = fValue;
return 1;
}
self->pDriv->GetError(self->pDriv,&iCode,pBueffel,79);
sprintf(pError,"ERROR: %s",pBueffel);
SCWrite(pCon,pError,eError);
iRet = self->pDriv->TryFixIt(self->pDriv,iCode);
if(iRet == CHFAIL)
return 0;
}
return 0;
}
/*------------------------------------------------------------------------*/
static void KillAdapter(void *pData)
{
pCHAdapter self = NULL;
self = (pCHAdapter)pData;
if(!self)
return;
if(self->pDes)
DeleteDescriptor(self->pDes);
if(self->pInt)
free(self->pInt);
if(self->pParName);
free(self->pParName);
free(self);
}
/*-----------------------------------------------------------------------
Syntax: ChopperAdapter name choppercontroller parname upper lower
*/
int CHAdapterFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
char pBueffel[256];
pCHAdapter pNew = NULL;
pChoco pChopper = NULL;
CommandList *pCom = NULL;
pDummy pDum = NULL;
double dUpper, dLower;
int iRet;
/* do we have enough arguments? */
if(argc < 6)
{
SCWrite(pCon,
"ERROR: Insufficient number of arguments to ChopperAdapter",
eError);
return 0;
}
/* find the chopper first */
pCom = FindCommand(pSics,argv[2]);
if(pCom)
{
pDum = (pDummy)pCom->pData;
if(pDum)
{
if(strcmp(pDum->pDescriptor->name,"Chopper") == 0)
{
pChopper = (pChoco)pCom->pData;
}
}
}
if(!pChopper)
{
sprintf(pBueffel,"ERROR: %s is NO chopper controller",
argv[3]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/* interpret limits */
iRet = Tcl_GetDouble(pSics->pTcl,argv[5],&dUpper);
if(iRet != TCL_OK)
{
sprintf(pBueffel,
"ERROR: expected numeric argument for upper limit, got %s",
argv[4]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = Tcl_GetDouble(pSics->pTcl,argv[4],&dLower);
if(iRet != TCL_OK)
{
sprintf(pBueffel,
"ERROR: expected numeric argument for lower limit, got %s",
argv[5]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/* allocate new adapter data structure */
pNew = (pCHAdapter)malloc(sizeof(CHAdapter));
if(!pNew)
{
SCWrite(pCon,"ERROR: out of memory in ChopperAdapter",eError);
return 0;
}
memset(pNew,0,sizeof(CHAdapter));
pNew->pDes = CreateDescriptor("ChopperAdapter");
pNew->pDriv = CHGetDriver(pChopper);
pNew->pInt = CreateDrivableInterface();
pNew->pParName = strdup(argv[3]);
if( !pNew->pDes || !pNew->pDriv || !pNew->pInt || !pNew->pParName)
{
SCWrite(pCon,"ERROR: out of memory in ChopperAdapter",eError);
return 0;
}
/* initialize other fields */
pNew->fTarget = 0.;
pNew->fLower = (float)dLower;
pNew->fUpper = (float)dUpper;
pNew->pDes->GetInterface = AdapterGetInterface;
pNew->pInt->Halt = CHHalt;
pNew->pInt->CheckLimits = CHLimits;
pNew->pInt->SetValue = CHSetValue;
pNew->pInt->CheckStatus = CHStatus;
pNew->pInt->GetValue = CHGetValue;
/* install command */
iRet = AddCommand(pSics, argv[1],CHAdapterAction,KillAdapter,pNew);
if(!iRet)
{
sprintf(pBueffel,
"ERROR: duplicate ChopperAdapter command %s NOT created",
argv[1]);
SCWrite(pCon,pBueffel,eError);
KillAdapter(pNew);
return 0;
}
return 1;
}
/*------------------------------------------------------------------------*/
int CHAdapterAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
pCHAdapter self = NULL;
int iRet;
char pBueffel[132];
float fValue;
self = (pCHAdapter)pData;
assert(self);
/* only action: get value */
fValue = CHGetValue(self,pCon);
if(fValue < -99000)
{
return 0;
}
else
{
sprintf(pBueffel,"%s = %f",argv[0],fValue);
SCWrite(pCon,pBueffel,eValue);
}
return 1;
}

38
chadapter.h Normal file
View File

@ -0,0 +1,38 @@
/*------------------------------------------------------------------------
C H a d a p t e r
This is the header file for a drive adapter for collaboration with a
general device controller as implemented in choco.*
Mark Koennecke, January 1998
--------------------------------------------------------------------------*/
#ifndef SICSCHADA
#define SICSCHADA
#include "codri.h"
typedef struct __CHADAPTER *pCHAdapter;
/*-----------------------------------------------------------------------*/
int CHAdapterFactory(SConnection *pCon, SicsInterp *pSics,
void *pData,
int argc, char *argv[]);
int CHAdapterAction(SConnection *pCon, SicsInterp *pSics,
void *pData,
int argc, char *argv[]);
#ifdef CHADAINTERNAL
typedef struct __CHADAPTER {
pObjectDescriptor pDes;
pCodri pDriv;
pIDrivable pInt;
float fUpper;
float fLower;
float fTarget;
char *pParName;
}CHAdapter;
#endif
#endif

247
choco.c Normal file
View File

@ -0,0 +1,247 @@
/*------------------------------------------------------------------------
C h o p p e r C o n t r o l l e r
Implementation file for the SICS chopper controller and general controller
device. For details about this object and its relation with the SICS system
see choco.w or choco.tex.
Mark Koennecke, January 1998
-------------------------------------------------------------------------*/
#include <stdlib.h>
#include <tcl.h>
#include <assert.h>
#include "fortify.h"
#include "sics.h"
#define CHOCOINTERNAL
#include "choco.h"
/*------------------------------------------------------------------------*/
int CHGetParameter(pChoco self, char *parname, char *pParValue,
int iBuflen)
{
int iRet, iCode;
assert(self);
iRet = self->pDriv->GetPar(self->pDriv, parname, pParValue,
iBuflen);
if(!iRet)
{
iRet = 0;
self->pDriv->GetError(self->pDriv,&iCode,pParValue, iBuflen);
}
return iRet;
}
/*------------------------------------------------------------------------*/
pCodri CHGetDriver(pChoco self)
{
assert(self);
return self->pDriv;
}
/*------------------------------------------------------------------------*/
int CHList(pChoco self, SConnection *pCon, char *name)
{
char *pPar, *pCopy = NULL;
char pValue[80];
char pMessage[256];
int iRet, iLen;
Tcl_DString tlist;
assert(self);
/* copy pParList as it will be destroyed by strtok */
iLen = strlen(self->pDriv->pParList);
pCopy = (char *)malloc((iLen+10)*sizeof(char));
if(!pCopy)
{
SCWrite(pCon,"ERROR: out of memory in CHList",eError);
return 0;
}
memset(pCopy,0,iLen+10);
strcpy(pCopy,self->pDriv->pParList);
Tcl_DStringInit(&tlist);
pPar = strtok(pCopy,",");
while(pPar != NULL)
{
iRet = CHGetParameter(self,pPar,pValue,79);
if(iRet)
{
sprintf(pMessage,"%s.%s = %s \n",name,pPar,pValue);
}
else
{
sprintf(pMessage,"ERROR: %s : while reading parameter %s \n",
pValue,pPar);
}
Tcl_DStringAppend(&tlist, pMessage,-1);
pPar = strtok(NULL,",");
}
SCWrite(pCon,Tcl_DStringValue(&tlist),eValue);
Tcl_DStringFree(&tlist);
free(pCopy);
return 1;
}
/*-----------------------------------------------------------------------*/
int ChocoAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
pChoco self = NULL;
char pValue[80], pMessage[256];
int iRet;
self = (pChoco)pData;
assert(self);
if(argc < 2)
{
sprintf(pMessage, "ERROR: Ragument required for %s",argv[0]);
SCWrite(pCon,pMessage,eError);
return 0;
}
/* argument can either be list or parameter name */
strtolower(argv[1]);
if(strcmp(argv[1],"list") == 0)
{
return CHList(self,pCon,argv[0]);
}
else
{
iRet = CHGetParameter(self,argv[1],pValue,79);
if(iRet)
{
sprintf(pMessage,"%s.%s = %s",argv[0],argv[1],pValue);
}
else
{
sprintf(pMessage,"ERROR: %s : while reading parameter %s",
pValue,argv[1]);
}
SCWrite(pCon,pMessage,eValue);
return iRet;
}
return 0;
}
/*----------------------------------------------------------------------*/
static void KillChoco(void *pData)
{
pChoco self = NULL;
self = (pChoco)pData;
if(!self)
return;
if(self->pDriv)
{
self->pDriv->Close(self->pDriv);
self->pDriv->Delete(self->pDriv);
if(self->pDriv->pParList)
free(self->pDriv->pParList);
free(self->pDriv);
}
if(self->pDes)
DeleteDescriptor(self->pDes);
free(self);
}
/*-----------------------------------------------------------------------
DRIVERS
*/
extern pCodri MakeSimChopper(void);
extern pCodri MakeDoChoDriver(char *pHost, int iPort, int iChannel);
/*-----------------------------------------------------------------------*/
int ChocoFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
pChoco pNew = NULL;
pCodri pDriv = NULL;
pObjectDescriptor pDes = NULL;
char pBueffel[132];
int iRet, iPort, iChannel;
if(argc < 3)
{
SCWrite(pCon,"ERROR: Insufficient number of arguments to MakeChopper",
eError);
return 0;
}
/* first try to get everything done */
pNew = (pChoco)malloc(sizeof(Choco));
pDes = CreateDescriptor("Chopper");
/* do driver */
strtolower(argv[2]);
if(strcmp(argv[2],"sim") == 0)
{
pDriv = MakeSimChopper();
}
else if(strcmp(argv[2],"docho") == 0)
{
if(argc < 6)
{
SCWrite(pCon,
"ERROR: Insufficient number of arguments to install Dornier Chopper driver",
eError);
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl,argv[4],&iPort);
if(iRet != TCL_OK)
{
sprintf(pBueffel,"ERROR: expected integer as port number, got %s",
argv[4]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl,argv[5],&iChannel);
if(iRet != TCL_OK)
{
sprintf(pBueffel,"ERROR: expected integer as channel number, got %s",
argv[4]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
pDriv = MakeDoChoDriver(argv[3],iPort,iChannel);
}
else
{
sprintf(pBueffel,"ERROR: Driver %s NOT supported for MakeChopper",
argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
if( (pNew == NULL) || (pDes == NULL) || (pDriv == NULL) )
{
SCWrite(pCon,"ERROR: No memory left to create chopper",eError);
return 0;
}
pNew->pDes = pDes;
pNew->pDriv = pDriv;
/* initialize driver */
iRet = pDriv->Init(pDriv);
if(!iRet)
{
SCWrite(pCon,"ERROR: Failed to initialize driver",eError);
KillChoco(pNew);
return 0;
}
/* install as command */
iRet = AddCommand(pSics, argv[1],ChocoAction,KillChoco,pNew);
if(!iRet)
{
sprintf(pBueffel,"ERROR: duplicate SPS command %s NOT created",
argv[1]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
return 1;
}

36
choco.h Normal file
View File

@ -0,0 +1,36 @@
/*-----------------------------------------------------------------------
C h o p p e r C o n t r o l l e r
This is both the header file for a general controller and a SICS
chopper controller.
Mark Koennecke, January 1998
--------------------------------------------------------------------------*/
#ifndef CHOCOSICS
#define CHOCOSICS
#include "codri.h"
typedef struct __CHOCO *pChoco;
/*------------------------------------------------------------------------*/
int CHGetParameter(pChoco self, char *pParName,
char *pParValue, int iBuflen);
pCodri CHGetDriver(pChoco self);
int CHList(pChoco self, SConnection *pCon, char *name);
/*------------------------------------------------------------------------*/
int ChocoAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int ChocoFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
#ifdef CHOCOINTERNAL
typedef struct __CHOCO {
pObjectDescriptor pDes;
pCodri pDriv;
} Choco;
#endif
#endif

351
choco.tex Normal file
View File

@ -0,0 +1,351 @@
\subsection{Chopper Controller}
Yet another way to deal with a controller has beenn devised for
SICS. This uses the concept of a general controller which can have
parameters enquired and set. Furthermore it may have parameters which
may be driven like a motor through a special adapter. This scheme is
used for the chopper controller for FOCUS.
\begin{itemize}
\item A driver for a particular controller which allows to set and get
parameters.
\item The general controller object which holds things together.
\item An adapter object which allows to drive special parameters in a general
controller. Such adapter objects can be configured for each drivable parameter
in a controller.
\end{itemize}
The test case for this way of doing things is a controller for running
choppers. This is why it gets the name.
The chopper system in question is the FOCUS chopper system. There are two
choppers, a fermi chopper and a disk chopper. This system can be run in two
different modes: In synchronous mode both choppers run at a
predefined ratio of speeds. For instance the fermi chopper is two
times faster then the disk chopper. This means, that setting a new
value for one chopper also changes the speed of the other chopper. In
asynchronous mode both choppers operate independently. Also the ration
to use for synchronous mode can be changed. Another parameter which
frequently changes is the phase of the two choppers. In order to
compensate for the fligh path between the two choppers there is a
small angular displacement of the choppers against each other which
varies with wavelength.
\subsubsection{The Controller Driver}
The controller driver is represented by the following data structure:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$codri {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __CODRI *pCodri;@\\
\mbox{}\verb@ typedef struct __CODRI {@\\
\mbox{}\verb@ int (*Init)(pCodri self);@\\
\mbox{}\verb@ int (*Close)(pCodri self);@\\
\mbox{}\verb@ int (*Delete)(pCodri self);@\\
\mbox{}\verb@ int (*SetPar)(pCodri self, @\\
\mbox{}\verb@ char *parname,@\\
\mbox{}\verb@ float fValue);@\\
\mbox{}\verb@ int (*SetPar2)(pCodri self, @\\
\mbox{}\verb@ char *parname,@\\
\mbox{}\verb@ char *value);@\\
\mbox{}\verb@ int (*GetPar)(pCodri self,@\\
\mbox{}\verb@ char *parname,@\\
\mbox{}\verb@ char *pBuffer,@\\
\mbox{}\verb@ int iBufLen);@\\
\mbox{}\verb@ int (*CheckPar)(pCodri self, @\\
\mbox{}\verb@ char *parname);@\\
\mbox{}\verb@ int (*GetError)(pCodri self, int *iCode,@\\
\mbox{}\verb@ char *pError, @\\
\mbox{}\verb@ int iErrLen);@\\
\mbox{}\verb@ int (*TryFixIt)(pCodri self, int iCode);@\\
\mbox{}\verb@ int (*Halt)(pCodri self);@\\
\mbox{}\verb@ char *pParList;@\\
\mbox{}\verb@ void *pPrivate;@\\
\mbox{}\verb@ }Codri;@\\
\mbox{}\verb@ @\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
All functions take a pointer to the controller driver itself as a
parameter. All functions except TryFixIt and CheckPar
return 0 on failure and 1 for success.
\begin{description}
\item[Init] initializes the controller driver. The parameters argc,
argv are main() style parameters for the initialization of the
controller driver.
\item[Close] closes the connection to the controller but does not delete a thing.
\item[Delete] closes the connection to the controller and deletes private data structures. Called when deleting the controller.
\item[SetPar] tries to set the parameter parname to the value
fValue. The last is floating point which covers the frequent
occurence of numeric values.
\item[SetPar2] The same as SetPar but uses test string as input for
parameter setting.
\item[GetPar] retrieves the parameter parname formatted as test. The
value is put into the buffer pBuffer. iBufLen is the maximum number of
bytes permissable for pBuffer.
\item[CheckPar] When parameters are driven a means is needed to find
out about the progress of operations and errors during the
operation. This is done by CheckPar for the parameter parname. The
return value of this function must be one of the HWBusy, HWError,
HWDone family documented in the motor driver object description.
\item[GetError] retrieves the last error. An integer error code is
placed into iCode and a textual description of the problem is written
to pError. Maximum iErrLen bytes are copied to pError.
\item[TryFixIt] tries to fix the error condition specified by iCode in
software if this possible. TryFisIt returns HWRedo if the last command
needs to resent, HWFault if the problem could not be fixed and HWOK if
the error can be ignored or was fully resolved.
\item[pParList] is text string containing a comma separated list of
all parameters understood by this driver.
\item[pPrivate] Is a pointer to a driver specific specific data
structure. This data structure will not be messed with by upper level code.
\end{description}
\subsubsection{The Controller Object}
This is the general controller object visible from the SICS
interpreter. This object allows to list all possible
parameters. Internal functions are provided for setting
parameters. But this is meant to be operated through a drive adapter
object (see below) in SICS. Thus the interface to this object
includes:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$chocoint {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __CHOCO *pChoco;@\\
\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
\mbox{}\verb@ int CHGetParameter(pChoco self, char *pParName, @\\
\mbox{}\verb@ char *pParValue, int iBuflen); @\\
\mbox{}\verb@ @\\
\mbox{}\verb@ pCodri CHGetDriver(pChoco self);@\\
\mbox{}\verb@ int CHList(pChoco self, SConnection *pCon, char *name);@\\
\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
\mbox{}\verb@ int ChocoAction(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ int ChocoFactory(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ @\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{description}
\item[CHGetParameter] retrieves the value of the parameter ParName
converted to text. Maximum iBufLen of result or error text are copied into the
buffer pParvalue.
\item[CHGetDriver] returns a pointer to the controller driver. This
function will be used by the drive adapters for interfacing with the
driver directly.
\item[CHList] prints a listing of all parameters to the client
described by pCon. name is the name of the controller.
\item[ChocoAction] is the SICS interpreter interface function for the
controller.
\item[ChocoFactory] is the SICS interpreter interface function which
installs a controller into SICS.
\end{description}
Most of the actual work of the controller is left to the driver. Thus
the internal data structure for a controller object is very simple:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
$\langle$chocodata {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __CHOCO {@\\
\mbox{}\verb@ pObjectDescriptor pDes;@\\
\mbox{}\verb@ pCodri pDriv;@\\
\mbox{}\verb@ } Choco;@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
It consists just of the standard SICS object descriptor and a pointer
to the driver.
\subsubsection{The Drive Adapter}
Most of the work of the drive adaptor is hidden in the functions
implementing the drivable interface. Thus the interface to the
DriveAdapter is fairly simple:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap4}
$\langle$adapter {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __CHADAPTER *pCHAdapter;@\\
\mbox{}\verb@/*-----------------------------------------------------------------------*/@\\
\mbox{}\verb@ int CHAdapterFactory(SConnection *pCon, SicsInterp *pSics, @\\
\mbox{}\verb@ void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ int CHAdapterAction(SConnection *pCon, SicsInterp *pSics, @\\
\mbox{}\verb@ void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ @\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{description}
\item[CHAdapterFactory] is the SICS interpreter factory function for
creating a drive adapter.
\item[CHAdapterAction] is the SICS interpreter function for
representing the object in SICS. Just a single action is supported:
request the value of the parameter.
\end{description}
The data structure for the drive adapter is slightly more interesting:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap5}
$\langle$adadata {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __CHADAPTER {@\\
\mbox{}\verb@ pObjectDescriptor pDes;@\\
\mbox{}\verb@ pCodri pDriv;@\\
\mbox{}\verb@ pIDrivable pInt;@\\
\mbox{}\verb@ float fUpper;@\\
\mbox{}\verb@ float fLower;@\\
\mbox{}\verb@ float fTarget;@\\
\mbox{}\verb@ char *pParName;@\\
\mbox{}\verb@ }CHAdapter;@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{description}
\item[pDes] is the standard object descriptor.
\item[pDriv] is a pointer to the controller driver.
\item[pInt] is a pointer to the drivable interface implemented by the
adapter.
\item[fUpper] upper limit for the parameter.
\item[fLower] lower limit for the parameter.
\item[pParName] is the name of the parameter which is driven through
this adapter.
\end{description}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap6}
\verb@"codri.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-------------------------------------------------------------------------@\\
\mbox{}\verb@ C o n t r o l l e r D r i v e r@\\
\mbox{}\verb@@\\
\mbox{}\verb@ This file contains the description of the data structure for a@\\
\mbox{}\verb@ general controller driver.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, January 1998@\\
\mbox{}\verb@--------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef CODRIV@\\
\mbox{}\verb@#define CODRIV@\\
\mbox{}\verb@#define CHFAIL -1@\\
\mbox{}\verb@#define CHREDO -2@\\
\mbox{}\verb@#define CHOK -3@\\
\mbox{}\verb@@$\langle$codri {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap7}
\verb@"choco.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-----------------------------------------------------------------------@\\
\mbox{}\verb@ C h o p p e r C o n t r o l l e r@\\
\mbox{}\verb@@\\
\mbox{}\verb@ This is both the header file for a general controller and a SICS@\\
\mbox{}\verb@ chopper controller.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, January 1998@\\
\mbox{}\verb@--------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef CHOCOSICS@\\
\mbox{}\verb@#define CHOCOSICS@\\
\mbox{}\verb@#include "codri.h"@\\
\mbox{}\verb@@$\langle$chocoint {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#ifdef CHOCOINTERNAL@\\
\mbox{}\verb@@$\langle$chocodata {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@#endif @\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap8}
\verb@"chadapter.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*------------------------------------------------------------------------@\\
\mbox{}\verb@ C H a d a p t e r@\\
\mbox{}\verb@@\\
\mbox{}\verb@ This is the header file for a drive adapter for collaboration with a@\\
\mbox{}\verb@ general device controller as implemented in choco.*@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, January 1998@\\
\mbox{}\verb@--------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSCHADA@\\
\mbox{}\verb@#define SICSCHADA@\\
\mbox{}\verb@#include "codri.h"@\\
\mbox{}\verb@@$\langle$adapter {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#ifdef CHADAINTERNAL@\\
\mbox{}\verb@@$\langle$adadata {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{To Do}
This scheme seems to be quite promising for handling many SICS
objects. The following enhancements could be considered. Allow to set
certain primitive parameters without a drivable interface. And add an
adapter for an environment variable in the controller.

264
choco.w Normal file
View File

@ -0,0 +1,264 @@
\subsection{Chopper Controller}
Yet another way to deal with a controller has beenn devised for
SICS. This uses the concept of a general controller which can have
parameters enquired and set. Furthermore it may have parameters which
may be driven like a motor through a special adapter. This scheme is
used for the chopper controller for FOCUS.
\begin{itemize}
\item A driver for a particular controller which allows to set and get
parameters.
\item The general controller object which holds things together.
\item An adapter object which allows to drive special parameters in a general
controller. Such adapter objects can be configured for each drivable parameter
in a controller.
\end{itemize}
The test case for this way of doing things is a controller for running
choppers. This is why it gets the name.
The chopper system in question is the FOCUS chopper system. There are two
choppers, a fermi chopper and a disk chopper. This system can be run in two
different modes: In synchronous mode both choppers run at a
predefined ratio of speeds. For instance the fermi chopper is two
times faster then the disk chopper. This means, that setting a new
value for one chopper also changes the speed of the other chopper. In
asynchronous mode both choppers operate independently. Also the ration
to use for synchronous mode can be changed. Another parameter which
frequently changes is the phase of the two choppers. In order to
compensate for the fligh path between the two choppers there is a
small angular displacement of the choppers against each other which
varies with wavelength.
\subsubsection{The Controller Driver}
The controller driver is represented by the following data structure:
@d codri @{
typedef struct __CODRI *pCodri;
typedef struct __CODRI {
int (*Init)(pCodri self);
int (*Close)(pCodri self);
int (*Delete)(pCodri self);
int (*SetPar)(pCodri self,
char *parname,
float fValue);
int (*SetPar2)(pCodri self,
char *parname,
char *value);
int (*GetPar)(pCodri self,
char *parname,
char *pBuffer,
int iBufLen);
int (*CheckPar)(pCodri self,
char *parname);
int (*GetError)(pCodri self, int *iCode,
char *pError,
int iErrLen);
int (*TryFixIt)(pCodri self, int iCode);
int (*Halt)(pCodri self);
char *pParList;
void *pPrivate;
}Codri;
@}
All functions take a pointer to the controller driver itself as a
parameter. All functions except TryFixIt and CheckPar
return 0 on failure and 1 for success.
\begin{description}
\item[Init] initializes the controller driver. The parameters argc,
argv are main() style parameters for the initialization of the
controller driver.
\item[Close] closes the connection to the controller but does not delete a thing.
\item[Delete] closes the connection to the controller and deletes private data structures. Called when deleting the controller.
\item[SetPar] tries to set the parameter parname to the value
fValue. The last is floating point which covers the frequent
occurence of numeric values.
\item[SetPar2] The same as SetPar but uses test string as input for
parameter setting.
\item[GetPar] retrieves the parameter parname formatted as test. The
value is put into the buffer pBuffer. iBufLen is the maximum number of
bytes permissable for pBuffer.
\item[CheckPar] When parameters are driven a means is needed to find
out about the progress of operations and errors during the
operation. This is done by CheckPar for the parameter parname. The
return value of this function must be one of the HWBusy, HWError,
HWDone family documented in the motor driver object description.
\item[GetError] retrieves the last error. An integer error code is
placed into iCode and a textual description of the problem is written
to pError. Maximum iErrLen bytes are copied to pError.
\item[TryFixIt] tries to fix the error condition specified by iCode in
software if this possible. TryFisIt returns HWRedo if the last command
needs to resent, HWFault if the problem could not be fixed and HWOK if
the error can be ignored or was fully resolved.
\item[pParList] is text string containing a comma separated list of
all parameters understood by this driver.
\item[pPrivate] Is a pointer to a driver specific specific data
structure. This data structure will not be messed with by upper level code.
\end{description}
\subsubsection{The Controller Object}
This is the general controller object visible from the SICS
interpreter. This object allows to list all possible
parameters. Internal functions are provided for setting
parameters. But this is meant to be operated through a drive adapter
object (see below) in SICS. Thus the interface to this object
includes:
@d chocoint @{
typedef struct __CHOCO *pChoco;
/*------------------------------------------------------------------------*/
int CHGetParameter(pChoco self, char *pParName,
char *pParValue, int iBuflen);
pCodri CHGetDriver(pChoco self);
int CHList(pChoco self, SConnection *pCon, char *name);
/*------------------------------------------------------------------------*/
int ChocoAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int ChocoFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
@}
\begin{description}
\item[CHGetParameter] retrieves the value of the parameter ParName
converted to text. Maximum iBufLen of result or error text are copied into the
buffer pParvalue.
\item[CHGetDriver] returns a pointer to the controller driver. This
function will be used by the drive adapters for interfacing with the
driver directly.
\item[CHList] prints a listing of all parameters to the client
described by pCon. name is the name of the controller.
\item[ChocoAction] is the SICS interpreter interface function for the
controller.
\item[ChocoFactory] is the SICS interpreter interface function which
installs a controller into SICS.
\end{description}
Most of the actual work of the controller is left to the driver. Thus
the internal data structure for a controller object is very simple:
@d chocodata @{
typedef struct __CHOCO {
pObjectDescriptor pDes;
pCodri pDriv;
} Choco;
@}
It consists just of the standard SICS object descriptor and a pointer
to the driver.
\subsubsection{The Drive Adapter}
Most of the work of the drive adaptor is hidden in the functions
implementing the drivable interface. Thus the interface to the
DriveAdapter is fairly simple:
@d adapter @{
typedef struct __CHADAPTER *pCHAdapter;
/*-----------------------------------------------------------------------*/
int CHAdapterFactory(SConnection *pCon, SicsInterp *pSics,
void *pData,
int argc, char *argv[]);
int CHAdapterAction(SConnection *pCon, SicsInterp *pSics,
void *pData,
int argc, char *argv[]);
@}
\begin{description}
\item[CHAdapterFactory] is the SICS interpreter factory function for
creating a drive adapter.
\item[CHAdapterAction] is the SICS interpreter function for
representing the object in SICS. Just a single action is supported:
request the value of the parameter.
\end{description}
The data structure for the drive adapter is slightly more interesting:
@d adadata @{
typedef struct __CHADAPTER {
pObjectDescriptor pDes;
pCodri pDriv;
pIDrivable pInt;
float fUpper;
float fLower;
float fTarget;
char *pParName;
}CHAdapter;
@}
\begin{description}
\item[pDes] is the standard object descriptor.
\item[pDriv] is a pointer to the controller driver.
\item[pInt] is a pointer to the drivable interface implemented by the
adapter.
\item[fUpper] upper limit for the parameter.
\item[fLower] lower limit for the parameter.
\item[pParName] is the name of the parameter which is driven through
this adapter.
\end{description}
@o codri.h @{
/*-------------------------------------------------------------------------
C o n t r o l l e r D r i v e r
This file contains the description of the data structure for a
general controller driver.
Mark Koennecke, January 1998
--------------------------------------------------------------------------*/
#ifndef CODRIV
#define CODRIV
#define CHFAIL -1
#define CHREDO -2
#define CHOK -3
@<codri@>
#endif
@}
@o choco.h @{
/*-----------------------------------------------------------------------
C h o p p e r C o n t r o l l e r
This is both the header file for a general controller and a SICS
chopper controller.
Mark Koennecke, January 1998
--------------------------------------------------------------------------*/
#ifndef CHOCOSICS
#define CHOCOSICS
#include "codri.h"
@<chocoint@>
#ifdef CHOCOINTERNAL
@<chocodata@>
#endif
#endif
@}
@o chadapter.h @{
/*------------------------------------------------------------------------
C H a d a p t e r
This is the header file for a drive adapter for collaboration with a
general device controller as implemented in choco.*
Mark Koennecke, January 1998
--------------------------------------------------------------------------*/
#ifndef SICSCHADA
#define SICSCHADA
#include "codri.h"
@<adapter@>
#ifdef CHADAINTERNAL
@<adadata@>
#endif
#endif
@}
\subsubsection{To Do}
This scheme seems to be quite promising for handling many SICS
objects. The following enhancements could be considered. Allow to set
certain primitive parameters without a drivable interface. And add an
adapter for an environment variable in the controller.

122
circular.c Normal file
View File

@ -0,0 +1,122 @@
/*-----------------------------------------------------------------------
Implementation file for a circular buffer facility.
Mark Koennecke, October 1999
-------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include "fortify.h"
#include "circular.h"
/*========================================================================
Definitions of Structures
*/
typedef struct __CircularItem {
void *pData;
struct __CircularItem *next;
struct __CircularItem *previous;
}CircularItem, *pCircularItem;
typedef struct __CIRCULAR {
pCircularItem pPointer;
CirKillFunc killer;
}Circular;
/*=========================================================================
Functions for Birth and Death
*/
pCircular createCircular(int iSize, CirKillFunc kf)
{
pCircular pNew = NULL;
pCircularItem pItem = NULL, pFirst = NULL;
int i;
assert(iSize > 0);
/* create data structure */
pNew = (pCircular)malloc(sizeof(Circular));
if(!pNew)
return NULL;
memset(pNew,0,sizeof(Circular));
/* create all the members of the circular buffer */
pItem = (pCircularItem)malloc(sizeof(CircularItem));
if(!pItem)
return NULL;
memset(pItem,0,sizeof(CircularItem));
pNew->pPointer = pItem;
pFirst = pItem;
for(i = 1; i < iSize; i++)
{
pItem = (pCircularItem)malloc(sizeof(CircularItem));
if(!pItem)
return NULL;
memset(pItem,0,sizeof(CircularItem));
pItem->previous = pNew->pPointer;
pNew->pPointer->next = pItem;
pNew->pPointer = pItem;
}
pItem->next = pFirst;
pFirst->previous = pItem;
pNew->killer = kf;
return pNew;
}
/*---------------------------------------------------------------------*/
void deleteCircular(pCircular self)
{
pCircularItem pNext = NULL, pCurrent = NULL;
assert(self);
self->pPointer->previous->next = NULL;
pNext = self->pPointer;
while(pNext != NULL)
{
pCurrent = pNext;
pNext = pCurrent->next;
if(pCurrent->pData && self->killer)
{
self->killer(pCurrent->pData);
}
free(pCurrent);
}
free(self);
}
/*========================================================================
Data Manipulation functions
*/
void setCircular(pCircular self, void *pData)
{
assert(self);
/* delete if present */
if(self->pPointer->pData && self->killer)
{
self->killer(self->pPointer->pData);
}
self->pPointer->pData = pData;
}
/*----------------------------------------------------------------------*/
void *getCircular(pCircular self)
{
assert(self);
return self->pPointer->pData;
}
/*========================================================================
Pointer movement
*/
void nextCircular(pCircular self)
{
assert(self);
self->pPointer = self->pPointer->next;
}
/*---------------------------------------------------------------------*/
void previousCircular(pCircular self)
{
assert(self);
self->pPointer = self->pPointer->previous;
}

31
circular.h Normal file
View File

@ -0,0 +1,31 @@
/*--------------------------------------------------------------------------
C I R C U L A R
This is the implementation of a general purpose circular buffer facility.
Mark Koennecke, October 1999
--------------------------------------------------------------------------*/
#ifndef CIRCULAR
#define CIRCULAR
typedef struct __CIRCULAR *pCircular;
typedef void (*CirKillFunc)(void *pData);
/* ----------------- birth and death -----------------------------------*/
pCircular createCircular(int iSize,CirKillFunc kf);
/*
iSize is the size of the circular Buffer.
KillFunc is a function which can safely delete the data item held
as content of the circular buffer.
*/
void deleteCircular(pCircular self);
/*-------------- access and modify data item at current position ----------*/
void setCircular(pCircular self, void *pData);
void *getCircular(pCircular self);
/*---------------- pointer movement --------------------------------------*/
void nextCircular(pCircular self);
void previousCircular(pCircular self);
#endif

44
codri.h Normal file
View File

@ -0,0 +1,44 @@
/*-------------------------------------------------------------------------
C o n t r o l l e r D r i v e r
This file contains the description of the data structure for a
general controller driver.
Mark Koennecke, January 1998
--------------------------------------------------------------------------*/
#ifndef CODRIV
#define CODRIV
#define CHFAIL -1
#define CHREDO -2
#define CHOK -3
typedef struct __CODRI *pCodri;
typedef struct __CODRI {
int (*Init)(pCodri self);
int (*Close)(pCodri self);
int (*Delete)(pCodri self);
int (*SetPar)(pCodri self,
char *parname,
float fValue);
int (*SetPar2)(pCodri self,
char *parname,
char *value);
int (*GetPar)(pCodri self,
char *parname,
char *pBuffer,
int iBufLen);
int (*CheckPar)(pCodri self,
char *parname);
int (*GetError)(pCodri self, int *iCode,
char *pError,
int iErrLen);
int (*TryFixIt)(pCodri self, int iCode);
int (*Halt)(pCodri self);
char *pParList;
void *pPrivate;
}Codri;
#endif

229
coll.tcl Normal file
View File

@ -0,0 +1,229 @@
#----------------------------------------------------------------------------
# This file implements the collimator commands for SANS. It requires an
# SPS named sps2 within SICS.
#
# Mark Koennecke, March 1999
#----------------------------------------------------------------------------
proc coll args {
#-------- set case
if { [llength $args] > 0 ] } {
set length [lindex $args 0]
switch $length {
18 {
set command "sps2 push 200 0"
break
}
15 {
set command "sps2 push 200 1"
break
}
11 {
set command "sps2 push 200 2"
break
}
8 {
set command "sps2 push 200 3"
break
}
6 {
set command "sps2 push 200 4"
break
}
4.5 {
set command "sps2 push 200 5"
break
}
3 {
set command "sps2 push 200 6"
break
}
2 {
set command "sps2 push 200 7"
break
}
1.4 {
set command "sps2 push 201 0"
break
}
1 {
set command "sps2 push 201 1"
break
}
default {
append text \
[format "ERROR: collimation length %s invalid\n" $length]
append text "Possible length are: 18,15,11,8,6,4.5,3,2,1.4,1\n"
append text \
"Extraneous . or other characters will yield this error too\n"
append text "SPS programming courtesy Enzo Manfrin\n"
return $text
}
#------- command has been built, execute it!
set ret [catch {$command} msg]
if {$ret != 0} {
error $msg
}
setstatus Driving
#------- wait till finish, check for interrupts on the way
set exe 1
while {$exe} {
set ret [catch {sps2 colli} msg]
if {$ret != 0 } {
setstatus Eager
error $msg
}
set l [split $msg =]
set cval [lindex $l 1]
if { [expr $cval - $length] < 0.2 } {
set exe 0
}
set rupt [getint]
if {[string compare $rupt continue] != 0 } {
setstatus Eager
error "ERROR: driving collimator interrupted"
}
}
setstatus Eager
return OK
} else {
#-------- get case
set ret [catch {sps2 colli} msg]
if {$ret != 0} {
error $msg
}
return $msg
}
}
#--------------------------------------------------------------------------
# Another procedure for handling the attenuator.
#
# Mark Koennecke, March 1999
#--------------------------------------------------------------------------
proc findatt { } {
#----------- find the current attenuator
set ret [catch {sps2 stat2 9 5} msg]
if { $ret != 0 } {
error $msg
}
set l [split $msg =]
if { [lindex $l 1] == 1} {
return 0
}
set ret [catch {sps2 stat2 9 6} msg]
if { $ret != 0 } {
error $msg
}
set l [split $msg =]
if { [lindex $l 1] == 1} {
return 1
}
set ret [catch {sps2 stat2 9 7} msg]
if { $ret != 0 } {
error $msg
}
set l [split $msg =]
if { [lindex $l 1] == 1} {
return 2
}
set ret [catch {sps2 stat2 10 0} msg]
if { $ret != 0 } {
error $msg
}
set l [split $msg =]
if { [lindex $l 1] == 1} {
return 3
}
set ret [catch {sps2 stat2 10 1} msg]
if { $ret != 0 } {
error $msg
}
set l [split $msg =]
if { [lindex $l 1] == 1} {
return 4
}
set ret [catch {sps2 stat2 10 2} msg]
if { $ret != 0 } {
error $msg
}
set l [split $msg =]
if { [lindex $l 1] == 1} {
return 5
}
}
#--------------------------------------------------------------------------
proc att args {
if [ llength $args] > 0} {
#------- set case
set aat [lindex $args 0]
switch $aat {
0 {
set command "sps2 push 210 7"
break
}
1 {
set command "sps2 push 220 0"
break
}
2 {
set command "sps2 push 220 1"
break
}
3 {
set command "sps2 push 230 0"
break
}
4 {
set command "sps2 push 230 1"
break
}
5 {
set command "sps2 push 230 2"
break
}
default {
error [format "ERROR: attenuator %s unknown" $aat]
}
}
#-----send command
set ret [catch {$command} msg]
if {$ret != 0} {
error $msg
}
#------ wait till done
setstatus Driving
set exe 1
while {$exe} {
set ret [catch {findatt} msg]
if {$ret != 0 } {
setstatus Eager
error $msg
}
if { [expr $msg - $aat] < 0.2 } {
set exe 0
}
set rupt [getint]
if {[string compare $rupt continue] != 0 } {
setstatus Eager
error "ERROR: driving attenuator interrupted"
}
}
setstatus Eager
return OK
} else {
#----------- get case
set ret [catch {findatt} msg]
if {$ret != 0 } {
error $msg
} else {
return [format "att = %s" $msg]
}
}
}

54
comentry.h Normal file
View File

@ -0,0 +1,54 @@
/*---------------------------------------------------------------------------
C O M E N T R Y
some helper stuff for implementing MultiMotors. Functions in mumo.c
Mark Koennecke, February 1997
---------------------------------------------------------------------------*/
#ifndef COMENTRY
#define COMENTRY
#define MAXDEV 10
typedef struct {
void *pData;
char name[80];
pObjectDescriptor pDescriptor;
float fVal;
int iCount;
} DevEntry;
/* -------------------The Entry per registered command --------------------*/
typedef struct __ComEntry {
char name[10];
char *pCommand;
int iDevice;
DevEntry pDevice[MAXDEV];
struct __ComEntry *pNext;
struct __ComEntry *pPrevious;
}ComEntry, *pComEntry;
typedef struct __NAMPOS {
char *name; /* the name */
pComEntry pCom; /* the positions */
char *text; /* explanatory text */
struct __NAMPOS *pNext;
struct __NAMPOS *pPrevious;
} NamPos, *pNamPos;
typedef struct __NAMMAP {
char *alias;
char *motname;
pMotor pMot;
} NamMap, *pNamMap;
int CheckComEntryBounds(pComEntry self, SConnection *pCon);
int AddExeEntry(pExeList self, pComEntry pNew, SConnection *pCon);
pComEntry CreateComEntry(void);
pComEntry CopyComEntry(pComEntry pOld);
int AddDevEntry(pComEntry pCom, char *name, void *pData, pObjectDescriptor pDes,
float fVal);
pNamPos LinkNamPos(pNamPos pHead, pNamPos pNew);
pNamPos UnlinkNamPos(pNamPos pHead, pNamPos pOld);
#endif

422
commandlog.c Normal file
View File

@ -0,0 +1,422 @@
/*--------------------------------------------------------------------------
C O M M A N D L O G
A much requested facility for writing only user and manager level commands
in a transcript file. This is it.
Mark Koennecke, June 1998
Extended to support Heinz Heers autolog-file
Mark Koennecke, April-May 1999
Added a tail facility
Mark Koennecke, October 1999
--------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <time.h>
#include <tcl.h>
#include "sics.h"
#include "ifile.h"
#include "sicsvar.h"
#include "scaldate.h"
#include "network.h"
#include "circular.h"
/* in conman.c */
int TelnetWrite(mkChannel *pSock, char *pText);
/*-------------------- the command log file pointer ---------------------*/
static FILE *fd = NULL;
static FILE *fauto = NULL;
static char pFile[256];
/*-------------------- the tail buffer ---------------------------------*/
static pCircular pTail = NULL;
#define MAXTAIL 1000
/*----------------------------------------------------------------------*/
void WriteToCommandLog(char *prompt,char *pText)
{
int iNL = 0, iPos;
char *pPtr = NULL;
/* figure out if we have to do a newline with pText as well */
pPtr = strrchr(pText,'\n');
if(pPtr != NULL)
{
iPos = pPtr - pText;
if(iPos >= (strlen(pText) - 2) )
{
iNL = 1;
}
}
/* supress status messages */
if(strstr(pText,"status =") != NULL)
{
return;
}
/* create tail buffer as needed */
if(!pTail)
{
pTail = createCircular(MAXTAIL,free);
}
/* user file */
if(fd != NULL)
{
if(iNL)
{
fprintf(fd,"%s %s",prompt, pText);
}
else
{
fprintf(fd,"%s %s\n",prompt, pText);
}
}
/* automatic file */
if(fauto != NULL)
{
if(iNL)
{
fprintf(fauto,"%s %s",prompt, pText);
}
else
{
fprintf(fauto,"%s %s\n",prompt, pText);
}
}
/* tail buffer */
if(pTail != NULL)
{
if(iNL)
{
pPtr = strrchr(pText,'\n');
*pPtr = ' ';
}
setCircular(pTail,strdup(pText));
nextCircular(pTail);
}
}
/*------------------------------------------------------------------------*/
static void PrintTail(int iNum, SConnection *pCon)
{
char *pPtr = NULL;
int i;
if(pTail == NULL)
{
SCWrite(pCon,"Nothing to print",eError);
return;
}
/* step back */
for(i = 0; i < iNum; i++)
{
previousCircular(pTail);
}
/* now step ahead and print. I have to use a trick here: I do not
want the tail stuff to show up in log files. Thus I write it
directly to the connection socket.
*/
for(i = 0; i < iNum; i++)
{
pPtr = (char *)getCircular(pTail);
if(pCon->pSock)
{
TelnetWrite(pCon->pSock, pPtr);
}
nextCircular(pTail);
}
}
/*------------------------------------------------------------------------*/
void CLFormatTime(char *pBuffer, int iBufLen)
{
time_t iDate;
struct tm *psTime;
/* make time string */
iDate = time(NULL);
psTime = localtime(&iDate);
memset(pBuffer,0,iBufLen);
strftime(pBuffer,iBufLen,"%Y-%m-%d@%H-%M-%S",psTime);
}
/*----------------------------------------------------------------------
Build an automatically generated log file name and open it.
*/
static void AutoLog(void)
{
char pBueffel[1024];
char pTime[80];
pSicsVariable pInst = NULL;
char *pPtr = NULL;
if(fauto)
{
fclose(fauto);
fauto = NULL;
}
/* find path */
pPtr = IFindOption(pSICSOptions,"LogFileDir");
if(!pPtr)
{
pPtr = strdup("~/log");
printf("WARNING: Required SICS option LogFileDir not found");
}
/* get time */
CLFormatTime(pTime,79);
/* build file name */
sprintf(pBueffel,"%s/auto%s.log",pPtr,pTime);
/* open file */
fauto = fopen(pBueffel,"w");
if(!fauto)
{
ServerWriteGlobal("ERROR: failed to open autolog file",eError);
}
/* write the instrument name to it for identification */
pInst = FindVariable(pServ->pSics,"instrument");
if(pInst)
{
sprintf(pBueffel,"Logfile started at instument %s at %s",
pInst->text,pTime);
WriteToCommandLog("SYS>> ", pBueffel);
}
}
/*----------------------------------------------------------------------
AutoTask puts a time stamp into the auto log file any hour and
creates a new log file any 24 hours
*/
static time_t tLogfile = 0;
static time_t tStamp = 0;
static int iEnd = 1;
static int iAutoActive = 0;
static int iIntervall = 60;
static int AutoTask(void *pData)
{
time_t tNow;
char pTime[80];
struct tm *sTime;
long julian;
unsigned yr, mo, dd;
tNow = time(NULL);
if(tNow > tLogfile)
{
AutoLog();
sTime = localtime(&tNow);
/* find next day, do so by converting to julian Date, add one
and calculate back. The (stolen) julian calculations will
take care of all the leaps and month and year etc.
*/
julian = ymd_to_scalar(sTime->tm_year+1900, sTime->tm_mon+1,
sTime->tm_mday);
julian++;
scalar_to_ymd(julian, &yr, &mo, &dd);
sTime->tm_sec = 0;
sTime->tm_min = 1;
sTime->tm_hour = 0;
sTime->tm_mday = dd;
sTime->tm_mon = mo - 1;
sTime->tm_year = yr - 1900;
tLogfile = mktime(sTime);
if(tLogfile < 0)
tLogfile = tNow + 60*60*24;
}
if(tNow > tStamp)
{
CLFormatTime(pTime,79);
WriteToCommandLog("TIMESTAMP>> ",pTime);
sTime = localtime(&tNow);
sTime->tm_sec = 0;
sTime->tm_min += iIntervall;
if(sTime->tm_min >= 60)
{
sTime->tm_min = 0;
sTime->tm_hour++;
}
if(sTime->tm_hour >= 24)
sTime->tm_hour = 0;
tStamp = mktime(sTime);
if((tStamp < 0) || ( (tStamp-tNow) < 100) )
{
tStamp = tNow + iIntervall*60;
}
if(fauto)
fflush(fauto);
}
return iEnd;
}
/*----------- a command to configure the log --------------------------*/
int CommandLog(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
char *pPtr = NULL;
char pBueffel[1024];
int iVal, iRet;
if(argc == 1)
{
if(fd)
{
sprintf(pBueffel,"Command log ACTIVE at %s",pFile);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
else
{
SCWrite(pCon,"Command logging DISABLED",eValue);
return 1;
}
}
/* handle tail */
strtolower(argv[1]);
if(strcmp(argv[1],"tail") == 0)
{
/* check for optional number of lines argument */
iVal = 20;
if(argc >= 3)
{
iRet = Tcl_GetInt(pSics->pTcl,argv[2],&iVal);
if(iRet != TCL_OK)
iVal = 20;
}
PrintTail(iVal,pCon);
return 1;
}
/* check rights */
if(!SCMatchRights(pCon,usMugger))
{
SCWrite(pCon,"ERROR: only managers may configure the logfile",
eError);
SCWrite(pCon,"ERROR: Request refused",eError);
return 0;
}
/* check no of args */
if(argc < 2)
{
SCWrite(pCon,
"ERROR: Insufficient number or arguments to commandlog",
eError);
return 0;
}
if(strcmp(argv[1],"new") == 0) /* new command */
{
if(argc < 3)
{
SCWrite(pCon,
"ERROR: Insufficient number or arguments to commandlog new",
eError);
return 0;
}
if(fd)
{
fclose(fd);
fd = NULL;
}
/* make the filename */
pPtr = IFindOption(pSICSOptions,"LogFileDir");
if(!pPtr)
{
SCWrite(pCon,"WARNING: no log file directory specified",eWarning);
sprintf(pBueffel,"%s",argv[2]);
}
else
{
sprintf(pBueffel,"%s/%s",pPtr,argv[2]);
}
fd = fopen(pBueffel,"w");
if(!fd)
{
sprintf(pBueffel,"ERROR: cannot open %s/%s for writing",pPtr,
argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
strcpy(pFile,argv[2]);
SCSendOK(pCon);
return 1;
}
else if(strcmp(argv[1],"auto") == 0)
{
if(iAutoActive)
{
SCWrite(pCon,"ERROR: autologging is already active",eError);
return 0;
}
TaskRegister(pServ->pTasker,
AutoTask,
NULL,
NULL,
NULL,
1);
SCSendOK(pCon);
iAutoActive = 1;
return 1;
}
else if(strcmp(argv[1],"intervall") == 0)
{
if(argc > 2)
{
iRet = Tcl_GetInt(pSics->pTcl,argv[2],&iVal);
if(iRet != TCL_OK)
{
SCWrite(pCon,"ERROR: failed to convert new intervall to number",
eError);
return 0;
}
iIntervall = iVal;
SCSendOK(pCon);
return 1;
}
else
{
sprintf(pBueffel,"autolog.intervall = %d", iIntervall);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
}
else if(strcmp(argv[1],"close") == 0) /* close command */
{
fclose(fd);
fd = NULL;
SCSendOK(pCon);
return 1;
}
sprintf(pBueffel,"ERROR: subcommand %s to commandlog unknown",
argv[1]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/*-------------------------------------------------------------------------*/
void CommandLogClose(void *pData)
{
if(fd)
{
fclose(fd);
}
if(fauto)
fclose(fauto);
if(pData)
KillDummy(pData);
if(pTail)
deleteCircular(pTail);
}

19
commandlog.h Normal file
View File

@ -0,0 +1,19 @@
/*--------------------------------------------------------------------------
C O M M A N D L O G
A much requested facility for writing only user an manager level commands
in a transcript file. This is it.
Mark Koennecke, June 1998
--------------------------------------------------------------------------*/
#ifndef COMMANDLOG
#define COMMANDLOG
void WriteToCommandLog(char *prompt,char *pText);
int CommandLog(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
void CommandLogClose(void *pData);
#endif

26
configfu.h Normal file
View File

@ -0,0 +1,26 @@
/*--------------------------------------------------------------------------
` This is a common header for rarely used configuration
functions. Implementations are distributed across several
files. Therefor they are mentioned in a comment.
Mark Koennecke, December 1996
copyrights: see implementation files
--------------------------------------------------------------------------*/
#ifndef SICSCONFIG
#define SICSCONFIG
int AddHalt(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
/* configuration command: enters argv objects into Halt List of Interrupt.
This is the means how the server knows which hardware to halt in an
case of emergency. Implemented in intserv.c
*/
int ListObjects(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
/*
lists all avialable objects. Realised in Scinter.c
*/
#endif

1427
conman.c Normal file

File diff suppressed because it is too large Load Diff

115
conman.h Normal file
View File

@ -0,0 +1,115 @@
/*--------------------------------------------------------------------------
C O N N E C T I O N O B J E C T
This file defines the connection object data structure and the interface to
this data structure. This is one of the most important SICS components.
Substantially revised from a prior version.
Mark Koennecke, September 1997
copyright: see copyright.h
----------------------------------------------------------------------------*/
#ifndef SICSCONNECT
#define SICSCONNECT
#include <stdio.h>
#include "costa.h"
#include "SCinter.h"
#include "network.h"
#include "obdes.h"
#define MAXLOGFILES 10
typedef struct __SConnection {
/* object basics */
pObjectDescriptor pDes;
char *pName;
long lMagic;
/* I/O control */
mkChannel *pSock;
FILE *pFiles[MAXLOGFILES];
int iMacro;
int iTelnet;
int iOutput;
int iFiles;
int (*write)(struct __SConnection *pCon,
char *pMessage, int iCode);
mkChannel *pDataSock;
char *pDataComp;
int iDataPort;
/* execution context */
int eInterrupt;
int iUserRights;
int inUse;
int iDummy;
int iGrab;
int iErrCode;
SicsInterp *pSics;
/* a FIFO */
pCosta pStack;
/* callback registry */
int iList;
/* Tasking Stuff */
int iEnd;
}SConnection;
#include "nserver.h"
/*------------------------------ live & death ----------------------------*/
SConnection *SCreateConnection(SicsInterp *pSics, mkChannel *pSock,
int iUserRights);
SConnection *SCCreateDummyConnection(SicsInterp *pSics);
void SCDeleteConnection(void *pVictim);
/*------------------------------- tasking --------------------------------*/
int SCTaskFunction(void *pCon);
void SCSignalFunction(void *pCon, int iSignal, void *pSigData);
/* ***************************** I/O ************************************** */
int SCAddLogFile(SConnection *self, char *name);
int SCDelLogFile(SConnection *pCon, int iFile);
void SCSetOutputClass(SConnection *self, int iClass);
int SCWrite(SConnection *self, char *pBuffer, int iOut);
int SCRead(SConnection *self, char *pBuffer, int iBufLen);
int SCPrompt(SConnection *pCon, char *pPrompt, char *pResult, int iLen);
int SCSendOK(SConnection *self);
int SCnoSock(SConnection *pCon);
int SCWriteUUencoded(SConnection *pCon, char *pName, void *iData, int iLen);
/************************* CallBack *********************************** */
int SCRegister(SConnection *pCon, SicsInterp *pSics,
void *pInter, long lID);
int SCUnregister(SConnection *pCon, void *pInter);
/******************************* Error **************************************/
void SCSetInterrupt(SConnection *self, int eCode);
int SCGetInterrupt(SConnection *self);
void SCSetError(SConnection *pCon, int iCode);
int SCGetError(SConnection *pCon);
/****************************** Macro ***************************************/
int SCinMacro(SConnection *pCon);
int SCsetMacro(SConnection *pCon, int iMode);
/* *************************** Info *************************************** */
int SCGetRights(SConnection *self);
int SCSetRights(SConnection *pCon, int iNew);
int SCMatchRights(SConnection *pCon, int iCode);
int SCGetOutClass(SConnection *self);
int SCGetGrab(SConnection *pCon);
/* **************************** Invocation ******************************** */
int SCInvoke(SConnection *self,SicsInterp *pInter,char *pCommand);
/*************************** User Command **********************************/
int ConfigCon(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int ConSicsAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
#endif

31
copyright.h Normal file
View File

@ -0,0 +1,31 @@
/*----------------------------------------------------------------------------
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
Author: Mark Koennecke
Laboratory for Neutron Scattering
Paul Scherrer Institut
CH-5232 Villigen-PSI
Switzerland
Mark.Koennecke@psi.ch
-----------------------------------------------------------------------------*/

198
costa.c Normal file
View File

@ -0,0 +1,198 @@
/*----------------------------------------------------------------------------
C O S T A
Implementation of a command stack for use with connection objects in
SICS
Mark Koennecke, Septemeber 1997
Copyright:
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5423 Villigen-PSI
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
----------------------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <assert.h>
#include "fortify.h"
#include "lld.h"
#include "costa.h"
#include "costa.i"
/*-------------------------------------------------------------------------*/
pCosta CreateCommandStack(void)
{
pCosta pNew = NULL;
pNew = (pCosta)malloc(sizeof(Costa));
if(!pNew)
{
return NULL;
}
memset(pNew,0,sizeof(Costa));
pNew->iList = LLDcreate(sizeof(char *));
if(pNew->iList < 0)
{
free(pNew);
return NULL;
}
pNew->iCount = 0;
pNew->iMaxSize = INT_MAX;
return pNew;
}
/*-------------------------------------------------------------------------*/
void DeleteCommandStack(pCosta self)
{
int iRet;
char *pPtr;
assert(self);
iRet = LLDnodePtr2First(self->iList);
while(iRet != 0)
{
pPtr = NULL;
LLDnodeDataTo(self->iList,&pPtr);
if(pPtr)
{
free(pPtr);
}
iRet = LLDnodePtr2Next(self->iList);
}
LLDdelete(self->iList);
free(self);
}
/*--------------------------------------------------------------------------*/
int SetCommandStackMaxSize(pCosta self, int iNew)
{
assert(self);
if(iNew > 0)
{
self->iMaxSize = iNew;
return 1;
}
else
{
return 0;
}
}
/*--------------------------------------------------------------------------*/
int CostaTop(pCosta self, char *pCommand)
{
char *pPtr = NULL;
int iRet, iRes = 1;
assert(self);
/* check for lock */
if(self->iLock)
{
return 0;
}
/* check Size */
if(self->iCount >= self->iMaxSize)
{
return 0;
}
/* do not want 0 commands */
if(strlen(pCommand) < 1)
{
return 1;
}
pPtr = strdup(pCommand);
iRet = LLDnodeAppendFrom(self->iList,&pPtr);
if(iRet < 0)
{
iRes = 0;
}
self->iCount++;
return iRes;
}
/*--------------------------------------------------------------------------*/
int CostaBottom(pCosta self, char *pCommand)
{
char *pPtr = NULL;
int iRet, iRes = 1;
assert(self);
/* check for lock */
if(self->iLock)
{
return 0;
}
/* do not want 0 commands */
if(strlen(pCommand) < 1)
{
return 1;
}
pPtr = strdup(pCommand);
iRet = LLDnodePrependFrom(self->iList,&pPtr);
if(iRet < 0)
{
iRes = 0;
}
self->iCount++;
return iRes;
}
/*--------------------------------------------------------------------------*/
int CostaPop(pCosta self, char **pBuf)
{
char *pPtr = NULL;
int iRet;
assert(self);
iRet = LLDnodePtr2First(self->iList);
if(iRet != 0)
{
LLDnodeDataTo(self->iList,&pPtr);
*pBuf = pPtr;
LLDnodeDelete(self->iList);
self->iCount--;
return 1;
}
*pBuf = NULL;
return 0;
}
/*--------------------------------------------------------------------------*/
void CostaLock(pCosta self)
{
self->iLock = 1;
}
/*--------------------------------------------------------------------------*/
void CostaUnlock(pCosta self)
{
self->iLock = 0;
}

29
costa.h Normal file
View File

@ -0,0 +1,29 @@
/*-------------------------------------------------------------------------
C O S T A
A command stack implementation for SICS. To be used by each connection.
Mark Koennecke, September 1997
copyright: see implementation file.
----------------------------------------------------------------------------*/
#ifndef SICSCOSTA
#define SICSCOSTA
typedef struct __costa *pCosta;
/*----------------------------- live & death ----------------------------*/
pCosta CreateCommandStack(void);
void DeleteCommandStack(pCosta self);
int SetCommandStackMaxSize(pCosta self, int iNewSize);
/*----------------------------------------------------------------------*/
int CostaTop(pCosta self, char *pCommand);
int CostaBottom(pCosta self, char *pCommand);
int CostaPop(pCosta self,char **pPtr);
/*----------------------------------------------------------------------*/
void CostaLock(pCosta self);
void CostaUnlock(pCosta self);
#endif

15
costa.i Normal file
View File

@ -0,0 +1,15 @@
/*---------------------------------------------------------------------------
C O S T A
Internal data structures for the command stack.
--------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*/
typedef struct __costa {
int iLock;
int iList;
int iMaxSize;
int iCount;
} Costa;

108
costa.tex Normal file
View File

@ -0,0 +1,108 @@
\subsection{The Command Stack}
This is a helper class to the connection class.
Each connection to a client has a command stack associated with it. The
command stack is a stack of command strings as generated by the SICS
clients. Commands are added to the top of the command queue by the network
reader. Each time the task associated with a connection runs one command
is popped from the command stack and executed. During execution the command
stack must be locked in order to prevent commands being accepted by tasks
busy waiting for some other process to finish.
Correspondingly, the interface to the command stack looks like this:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$costaint {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __costa *pCosta;@\\
\mbox{}\verb@@\\
\mbox{}\verb@/*----------------------------- live & death ----------------------------*/@\\
\mbox{}\verb@ pCosta CreateCommandStack(void);@\\
\mbox{}\verb@ void DeleteCommandStack(pCosta self);@\\
\mbox{}\verb@ int SetCommandStackMaxSize(pCosta self, int iNewSize);@\\
\mbox{}\verb@/*----------------------------------------------------------------------*/@\\
\mbox{}\verb@ int CostaTop(pCosta self, char *pCommand);@\\
\mbox{}\verb@ int CostaBottom(pCosta self, char *pCommand);@\\
\mbox{}\verb@ int CostaPop(pCosta self,char **pPtr);@\\
\mbox{}\verb@/*----------------------------------------------------------------------*/@\\
\mbox{}\verb@ void CostaLock(pCosta self);@\\
\mbox{}\verb@ void CostaUnlock(pCosta self);@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
Internally, two data structure need to be defined, the first for the
list implementing the command stack, the second for the command stack
itself.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$costadat {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
\mbox{}\verb@ typedef struct __costa {@\\
\mbox{}\verb@ int iLock;@\\
\mbox{}\verb@ int iList;@\\
\mbox{}\verb@ int iMaxSize;@\\
\mbox{}\verb@ int iCount;@\\
\mbox{}\verb@ } Costa;@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
\verb@"costa.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-------------------------------------------------------------------------@\\
\mbox{}\verb@ C O S T A@\\
\mbox{}\verb@@\\
\mbox{}\verb@ A command stack implementation for SICS. To be used by each connection.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, September 1997@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see implementation file.@\\
\mbox{}\verb@@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSCOSTA@\\
\mbox{}\verb@#define SICSCOSTA@\\
\mbox{}\verb@@$\langle$costaint {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap4}
\verb@"costa.i"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*---------------------------------------------------------------------------@\\
\mbox{}\verb@ C O S T A@\\
\mbox{}\verb@ Internal data structures for the command stack.@\\
\mbox{}\verb@--------------------------------------------------------------------------*/@\\
\mbox{}\verb@@$\langle$costadat {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

68
costa.w Normal file
View File

@ -0,0 +1,68 @@
\subsection{The Command Stack}
This is a helper class to the connection class.
Each connection to a client has a command stack associated with it. The
command stack is a stack of command strings as generated by the SICS
clients. Commands are added to the top of the command queue by the network
reader. Each time the task associated with a connection runs one command
is popped from the command stack and executed. During execution the command
stack must be locked in order to prevent commands being accepted by tasks
busy waiting for some other process to finish.
Correspondingly, the interface to the command stack looks like this:
@d costaint @{
typedef struct __costa *pCosta;
/*----------------------------- live & death ----------------------------*/
pCosta CreateCommandStack(void);
void DeleteCommandStack(pCosta self);
int SetCommandStackMaxSize(pCosta self, int iNewSize);
/*----------------------------------------------------------------------*/
int CostaTop(pCosta self, char *pCommand);
int CostaBottom(pCosta self, char *pCommand);
int CostaPop(pCosta self,char **pPtr);
/*----------------------------------------------------------------------*/
void CostaLock(pCosta self);
void CostaUnlock(pCosta self);
@}
Internally, two data structure need to be defined, the first for the
list implementing the command stack, the second for the command stack
itself.
@d costadat @{
/*------------------------------------------------------------------------*/
typedef struct __costa {
int iLock;
int iList;
int iMaxSize;
int iCount;
} Costa;
@}
@o costa.h @{
/*-------------------------------------------------------------------------
C O S T A
A command stack implementation for SICS. To be used by each connection.
Mark Koennecke, September 1997
copyright: see implementation file.
----------------------------------------------------------------------------*/
#ifndef SICSCOSTA
#define SICSCOSTA
@<costaint@>
#endif
@}
@o costa.i @{
/*---------------------------------------------------------------------------
C O S T A
Internal data structures for the command stack.
--------------------------------------------------------------------------*/
@<costadat@>
@}

37
cotop.tcl Normal file
View File

@ -0,0 +1,37 @@
#--------------------------------------------------------------------------
# A MAD lookalike co command for TOPSI
# All arguments are optional. The current values will be used if not
# specified
# Dr. Mark Koennecke, November 1999
#--------------------------------------------------------------------------
proc SplitReply { text } {
set l [split $text =]
return [lindex $l 1]
}
#--------------------------------------------------------------------------
proc co { {mode NULL } { preset NULL } } {
starttime [sicstime]
#----- deal with mode
set mode2 [string toupper $mode]
set mode3 [string trim $mode2]
set mc [string index $mode2 0]
if { [string compare $mc T] == 0 } {
counter setMode Timer
} elseif { [string compare $mc M] == 0 } {
counter setMode Monitor
}
#------ deal with preset
if { [string compare $preset NULL] != 0 } {
set pre $preset
} else {
set pre [SplitReply [counter getpreset]]
}
#------ count
set ret [catch {counter count $pre} msg]
if { $ret != 0 } {
error [format "Counting ended with error: %s" $msg]
} else {
set cts [SplitReply [counter getcounts]]
}
return $cts
}

723
countdriv.c Normal file
View File

@ -0,0 +1,723 @@
/*------------------------------------------------------------------------
G E N C O U N T
Some general stuff for handling a CounterDriver.
Mark Koennecke, January 1997
Copyright:
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5423 Villigen-PSI
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
----------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include "fortify.h"
#include <string.h>
#include "Scommon.h"
#include "countdriv.h"
#include "hardsup/sinq_prototypes.h"
#include "hardsup/el737_def.h"
#include "hardsup/el737fix.h"
/*-------------------------------------------------------------------------*/
pCounterDriver CreateCounterDriver(char *name, char *type)
{
pCounterDriver pRes = NULL;
pRes = (pCounterDriver)malloc(sizeof(CounterDriver));
if(!pRes)
{
return NULL;
}
memset(pRes,0,sizeof(CounterDriver));
pRes->name = strdup(name);
pRes->type = strdup(type);
pRes->eMode = eTimer;
pRes->fPreset = 1000.;
pRes->fTime = 0.;
pRes->iNoOfMonitors = 0;
pRes->iPause = 0;
pRes->Start = NULL;
pRes->GetStatus = NULL;
pRes->ReadValues = NULL;
pRes->GetError = NULL;
pRes->TryAndFixIt = NULL;
pRes->Halt = NULL;
pRes->pData = NULL;
pRes->Pause = NULL;
pRes->Continue = NULL;
return pRes;
}
/*-------------------------------------------------------------------------*/
void DeleteCounterDriver(pCounterDriver self)
{
assert(self);
if(self->name)
{
free(self->name);
}
if(self->type)
{
free(self->type);
}
if(self->pData)
{
free(self->pData);
}
free(self);
}
/*----------------------------- EL737 ------------------------------------*/
typedef struct {
char *host;
int iPort;
int iChannel;
void *pData;
} EL737st;
/*------------------------------------------------------------------------*/
static int EL737GetStatus(struct __COUNTER *self, float *fControl)
{
int iRet;
int iC1, iC2, iC3,iC4,iRS;
float fTime;
EL737st *pEL737;
assert(self);
pEL737 = (EL737st *)self->pData;
assert(pEL737);
iRet = EL737_GetStatus(&pEL737->pData,&iC1,&iC2,&iC3,&iC4,&fTime,&iRS);
if(self->eMode == eTimer)
{
*fControl = fTime;
}
else
{
*fControl = iC1;
}
/* store time */
self->fTime = fTime;
if(iRet != 1)
{
return HWFault;
}
self->lCounts[0] = iC2;
self->lCounts[1] = iC1;
self->lCounts[2] = iC3;
self->lCounts[3] = iC4;
/* get extra counters for 8-fold counter boxes */
iRet = EL737_GetStatusExtra(&pEL737->pData,&iC1,&iC2,&iC3,&iC4);
self->lCounts[4] = iC1;
self->lCounts[5] = iC2;
self->lCounts[6] = iC3;
self->lCounts[7] = iC4;
if(iRS == 0)
{
return HWIdle;
}
else if((iRS == 1) || (iRS == 2))
{
return HWBusy;
}
else if( (iRS == 5) || (iRS == 6))
{
return HWNoBeam;
}
else
{
return HWPause;
}
}
/*-------------------------------------------------------------------------*/
static int EL737Start(struct __COUNTER *self)
{
int iRet, iRS;
EL737st *pEL737;
assert(self);
pEL737 = (EL737st *)self->pData;
assert(pEL737);
self->fTime = 0.;
if(self->eMode == ePreset)
{
iRet = EL737_StartCnt(&pEL737->pData,(int)nintf(self->fPreset),&iRS);
if(iRet == 1)
{
return OKOK;
}
else
{
return HWFault;
}
}
else if(self->eMode == eTimer)
{
iRet = EL737_StartTime(&pEL737->pData,self->fPreset,&iRS);
if(iRet == 1)
{
return OKOK;
}
else
{
return HWFault;
}
}
return 0;
}
/*-------------------------------------------------------------------------*/
static int EL737Pause(struct __COUNTER *self)
{
int iRet, iRS;
EL737st *pEL737;
assert(self);
pEL737 = (EL737st *)self->pData;
assert(pEL737);
iRet = EL737_Pause(&pEL737->pData,&iRS);
if(iRet == 1)
{
return OKOK;
}
else
{
return HWFault;
}
return 0;
}
/*-------------------------------------------------------------------------*/
static int EL737Continue(struct __COUNTER *self)
{
int iRet, iRS;
EL737st *pEL737;
assert(self);
pEL737 = (EL737st *)self->pData;
assert(pEL737);
iRet = EL737_Continue(&pEL737->pData,&iRS);
if(iRet == 1)
{
return OKOK;
}
else
{
return HWFault;
}
return 0;
}
/*--------------------------------------------------------------------------*/
static int EL737Halt(struct __COUNTER *self)
{
int iRet, iC1, iC2, iC3, iC4,iRS;
float fPreset;
EL737st *pEL737;
assert(self);
pEL737 = (EL737st *)self->pData;
assert(pEL737);
iRet = EL737_Stop(&pEL737->pData,&iC1, &iC2,&iC3,&iC4,&fPreset,&iRS);
if(iRet == 1)
{
self->lCounts[0] = iC2;
self->lCounts[1] = iC1;
self->lCounts[2] = iC3;
self->lCounts[3] = iC4;
return OKOK;
}
return HWFault;
}
/*--------------------------------------------------------------------------*/
static int EL737ReadValues(struct __COUNTER *self)
{
int iRet;
int iC1, iC2, iC3,iC4,iRS;
float fTime;
EL737st *pEL737;
assert(self);
pEL737 = (EL737st *)self->pData;
assert(pEL737);
iRet = EL737_GetStatus(&pEL737->pData,&iC1,&iC2,&iC3,&iC4,&fTime,&iRS);
if(iRet != 1)
{
return HWFault;
}
self->fTime = fTime;
self->lCounts[0] = iC2;
self->lCounts[1] = iC1;
self->lCounts[2] = iC3;
self->lCounts[3] = iC4;
/* get extra counters for 8-fold counter boxes */
iRet = EL737_GetStatusExtra(&pEL737->pData,&iC1,&iC2,&iC3,&iC4);
self->lCounts[4] = iC1;
self->lCounts[5] = iC2;
self->lCounts[6] = iC3;
self->lCounts[7] = iC4;
return OKOK;
}
/*---------------------------------------------------------------------------
EL737Error2Text converts between an EL734 error code to text
-----------------------------------------------------------------------------*/
static void EL737Error2Text(char *pBuffer, int iErr)
{
switch(iErr)
{
case EL737__BAD_ADR:
strcpy(pBuffer,"EL737__BAD_ADR");
break;
case EL737__BAD_OVFL:
strcpy(pBuffer,"EL737__BAD_OVFL");
break;
case EL737__BAD_BSY:
strcpy(pBuffer,"EL737__BAD_BSY");
break;
case EL737__BAD_SNTX:
strcpy(pBuffer,"EL737__BAD_SNTX");
break;
case EL737__BAD_CONNECT:
strcpy(pBuffer,"EL737__BAD_CONNECT");
break;
case EL737__BAD_FLUSH:
strcpy(pBuffer,"EL737__BAD_FLUSH");
break;
case EL737__BAD_DEV:
strcpy(pBuffer,"EL734__BAD_DEV");
break;
case EL737__BAD_ID:
strcpy(pBuffer,"EL737__BAD_ID");
break;
case EL737__BAD_ILLG:
strcpy(pBuffer,"EL737__BAD_ILLG");
break;
case EL737__BAD_LOC:
strcpy(pBuffer,"EL737__BAD_LOC");
break;
case EL737__BAD_MALLOC:
strcpy(pBuffer,"EL737__BAD_MALLOC");
break;
case EL737__BAD_NOT_BCD:
strcpy(pBuffer,"EL737__BAD_NOT_BCD");
break;
case EL737__BAD_OFL:
strcpy(pBuffer,"EL737__BAD_OFL");
break;
case EL737__BAD_PAR:
strcpy(pBuffer,"EL737__BAD_PAR");
break;
case EL737__BAD_RECV:
strcpy(pBuffer,"EL737__BAD_RECV");
break;
case EL737__BAD_RECV_NET:
strcpy(pBuffer,"EL737__BAD_RECV_NET");
break;
case EL737__BAD_RECV_PIPE:
strcpy(pBuffer,"EL737__BAD_RECV_PIPE");
break;
case EL737__BAD_RECV_UNKN:
strcpy(pBuffer,"EL737__BAD_RECV_UNKN");
break;
case EL737__BAD_RECVLEN:
strcpy(pBuffer,"EL737__BAD_RECVLEN");
break;
case EL737__BAD_RECV1:
strcpy(pBuffer,"EL737__BAD_RECV1");
break;
case EL737__BAD_RECV1_NET:
strcpy(pBuffer,"EL737__BAD_RECV1_NET");
break;
case EL737__BAD_RECV1_PIPE:
strcpy(pBuffer,"EL737__BAD_RECV1_PIPE");
break;
case EL737__BAD_RNG:
strcpy(pBuffer,"EL737__BAD_RNG");
break;
case EL737__BAD_SEND:
strcpy(pBuffer,"EL737__BAD_SEND");
break;
case EL737__BAD_SEND_PIPE:
strcpy(pBuffer,"EL737__BAD_SEND_PIPE");
break;
case EL737__BAD_SEND_NET:
strcpy(pBuffer,"EL737__BAD_SEND_NET");
break;
case EL737__BAD_SEND_UNKN:
strcpy(pBuffer,"EL737__BAD_SEND_UNKN");
break;
case EL737__BAD_SENDLEN:
strcpy(pBuffer,"EL737__BAD_SENDLEN");
break;
case EL737__BAD_SOCKET:
strcpy(pBuffer,"EL737__BAD_SOCKET");
break;
case EL737__BAD_TMO:
strcpy(pBuffer,"EL737__BAD_TMO");
break;
case EL737__FORCED_CLOSED:
strcpy(pBuffer,"EL737__FORCED_CLOSED");
break;
case EL737__BAD_ASYNSRV:
strcpy(pBuffer,"EL737__BAD_ASYNSRV");
break;
default:
sprintf(pBuffer,"Unknown EL737 error %d", iErr);
break;
}
}
/*--------------------------------------------------------------------------*/
static int EL737GetError(struct __COUNTER *self, int *iCode,
char *error, int iErrLen)
{
char *pErr = NULL;
int iC1, iC2, iC3;
char pBueffel[256];
if(self->iErrorCode == UNKNOWNPAR)
{
strncpy(error,"unknown internal parameter code",iErrLen);
*iCode = self->iErrorCode;
self->iErrorCode = 0;
return 1;
}
else if(self->iErrorCode == BADCOUNTER)
{
strncpy(error,"monitor cannot be selected",iErrLen);
*iCode = self->iErrorCode;
self->iErrorCode = 0;
return 1;
}
EL737_ErrInfo(&pErr,&iC1,&iC2, &iC3);
EL737Error2Text(pBueffel,iC1);
strncpy(error,pBueffel,iErrLen);
*iCode = iC1;
return 1;
}
/*--------------------------------------------------------------------------*/
static int EL737TryAndFixIt(struct __COUNTER *self, int iCode)
{
EL737st *pEL737;
int iRet;
char pCommand[50], pReply[50];
assert(self);
pEL737 = (EL737st *)self->pData;
assert(pEL737);
switch(iCode)
{
case EL737__BAD_ILLG:
case EL737__BAD_ADR:
case EL737__BAD_PAR:
case EL737__BAD_BSY:
case EL737__BAD_TMO:
case EL737__BAD_REPLY:
case EL737__BAD_SNTX:
return COREDO;
break;
case EL737__BAD_LOC:
strcpy(pCommand,"rmt 1\r");
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,49);
if(iRet < 0)
{
return COTERM;
}
strcpy(pCommand,"echo 2\r");
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,49);
if(iRet < 0)
{
return COTERM;
}
strcpy(pCommand,"ra\r");
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,49);
if(iRet < 0)
{
return COTERM;
}
return COREDO;
break;
case EL737__BAD_DEV:
case EL737__BAD_ID:
case EL737__BAD_NOT_BCD:
case UNKNOWNPAR:
case BADCOUNTER:
return COTERM;
break;
case EL737__FORCED_CLOSED:
iRet = EL737_Open(&pEL737->pData,pEL737->host, pEL737->iPort,
pEL737->iChannel);
if(iRet == 1)
{
return COREDO;
}
else
{
return COTERM;
}
break;
case EL737__BAD_OFL:
EL737_Close(&pEL737->pData,0);
iRet = EL737_Open(&pEL737->pData,pEL737->host, pEL737->iPort,
pEL737->iChannel);
if(iRet == 1)
{
return COREDO;
}
else
{
return COTERM;
}
break;
/* case EL737__BAD_ASYNSRV:
EL737_Close(&pEL737->pData,1);
return COREDO;
*/ default:
/* try to reopen connection */
EL737_Close(&pEL737->pData,1);
iRet = EL737_Open(&pEL737->pData,pEL737->host, pEL737->iPort,
pEL737->iChannel);
if(iRet == 1)
{
return COREDO;
}
else
{
return COTERM;
}
break;
}
return COTERM;
}
/*-------------------------------------------------------------------------*/
static int EL737Set(struct __COUNTER *self, int iCode, int iCter,
float fVal)
{
int iRet;
EL737st *pEL737;
char pCommand[80],pReply[80];
assert(self);
pEL737 = (EL737st *)self->pData;
assert(pEL737);
if(iCode == PARTHRESHOLD)
{
sprintf(pCommand,"DL %1.1d %f\r",iCter,fVal);
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,79);
if(iRet == 1)
{
if(pCommand[0] == '?')
{
self->iErrorCode = BADCOUNTER;
return HWFault;
}
}
else
{
return HWFault;
}
sprintf(pCommand,"DR %1.1d \r",iCter);
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,79);
if(iRet == 1)
{
if(pCommand[0] == '?')
{
self->iErrorCode = BADCOUNTER;
return HWFault;
}
return OKOK;
}
else
{
return HWFault;
}
}
else
{
self->iErrorCode = UNKNOWNPAR;
return HWFault;
}
}
/*-------------------------------------------------------------------------*/
static int EL737Get(struct __COUNTER *self, int iCode, int iCter,
float *fVal)
{
int iRet;
EL737st *pEL737;
char pCommand[80],pReply[80];
assert(self);
pEL737 = (EL737st *)self->pData;
assert(pEL737);
if(iCode == PARTHRESHOLD)
{
sprintf(pCommand,"DL %1.1d\r",iCter);
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,79);
if(iRet == 1)
{
if(pReply[0] == '?')
{
self->iErrorCode = BADCOUNTER;
return HWFault;
}
sscanf(pReply,"%f",fVal);
return OKOK;
}
else
{
return HWFault;
}
}
else
{
self->iErrorCode = UNKNOWNPAR;
return HWFault;
}
}
/*-------------------------------------------------------------------------*/
static int EL737Send(struct __COUNTER *self, char *pText, char *pReply,
int iReplyLen)
{
EL737st *pEL737;
char pBuffer[256];
assert(self);
pEL737 = (EL737st *)self->pData;
assert(pEL737);
/* ensure a \r at the end of the text */
if(strlen(pText) > 254)
{
strncpy(pReply,"Command to long",iReplyLen);
return 1;
}
strcpy(pBuffer,pText);
if(strchr(pBuffer,(int)'\r') == NULL)
{
strcat(pBuffer,"\r");
}
return EL737_SendCmnd(&pEL737->pData,pBuffer,pReply,iReplyLen);
}
/*--------------------------------------------------------------------------*/
pCounterDriver NewEL737Counter(char *name, char *host, int iPort, int iChannel)
{
pCounterDriver pRes = NULL;
EL737st *pData = NULL;
int iRet;
int iC1, iC2, iC3;
char *pErr;
char pBueffel[132];
pRes = CreateCounterDriver(name, "EL737");
if(!pRes)
{
return NULL;
}
/* open connection to counter */
pData = (EL737st *)malloc(sizeof(EL737st));
if(!pData)
{
DeleteCounterDriver(pRes);
return NULL;
}
pData->host = strdup(host);
pData->iPort = iPort;
pData->iChannel = iChannel;
pData->pData = NULL;
iRet = EL737_Open(&(pData->pData), host,iPort,iChannel);
if(iRet != 1)
{
EL737_ErrInfo(&pErr,&iC1,&iC2, &iC3);
DeleteCounterDriver(pRes);
if(pData->host)
{
free(pData->host);
}
return NULL;
}
pRes->pData = (void *)pData;
/* assign functions */
pRes->GetStatus = EL737GetStatus;
pRes->Start = EL737Start;
pRes->Halt = EL737Halt;
pRes->ReadValues = EL737ReadValues;
pRes->GetError = EL737GetError;
pRes->TryAndFixIt = EL737TryAndFixIt;
pRes->Pause = EL737Pause;
pRes->Continue = EL737Continue;
pRes->Set = EL737Set;
pRes->Get = EL737Get;
pRes->Send = EL737Send;
pRes->iNoOfMonitors = 7;
pRes->fTime = 0.;
return pRes;
}
/*--------------------------------------------------------------------------*/
void KillEL737Counter(pCounterDriver self)
{
EL737st *pEL737 = NULL;
assert(self);
pEL737 = (EL737st *)self->pData;
assert(pEL737);
EL737_Close(&pEL737->pData,0);
if(pEL737->host)
{
free(pEL737->host);
}
DeleteCounterDriver(self);
}

88
countdriv.h Normal file
View File

@ -0,0 +1,88 @@
/*---------------------------------------------------------------------------
C O U N T E R D R I V E R
This is the interface to a Sics-Counter driver. This means a
single counter managing possibly several monitors in one go.
A counter can run for a predefined time or until a predefined
monitor count has been reached.
Mark Koennecke, January 1996
General parameter setting added:
Mark Koennecke, April 1999
copyright: see implementation file.
---------------------------------------------------------------------------*/
#ifndef SICSCOUNTERDRIVER
#define SICSCOUNTERDRIVER
#define COTERM 0
#define COREDO 1
#define MAXCOUNT 9 /* No of monitors + actual counter */
typedef enum {
eTimer,
ePreset
}CounterMode;
/* Parameter codes for the Set/Get pair of routines */
/*-------- threshold */
#define PARTHRESHOLD 1
/* counter driver additional error codes*/
#define UNKNOWNPAR -5000
#define BADCOUNTER -5001
typedef struct __COUNTER {
/* variables */
char *name;
char *type;
CounterMode eMode;
float fPreset;
float fLastCurrent;
float fTime;
int iNoOfMonitors;
long lCounts[MAXCOUNT];
int iPause;
int iErrorCode;
/* functions */
int (*GetStatus)(struct __COUNTER *self, float *fControl);
int (*Start)(struct __COUNTER *self);
int (*Pause)(struct __COUNTER *self);
int (*Continue)(struct __COUNTER *self);
int (*Halt)(struct __COUNTER *self);
int (*ReadValues)(struct __COUNTER *self);
int (*GetError)(struct __COUNTER *self, int *iCode,
char *error, int iErrLen);
int (*TryAndFixIt)(struct __COUNTER *self, int iCode);
int (*Set)(struct __COUNTER *self,int iCode,
int iCter, float fVal);
int (*Get)(struct __COUNTER *self,int iCode,
int iCter, float *fVal);
int (*Send)(struct __COUNTER *self, char *pText,
char *pReply, int iReplyLen);
void *pData; /* counter specific data goes here, ONLY for
internal driver use!
*/
} CounterDriver, *pCounterDriver;
/*------------------------------------------------------------------------*/
/* countdriv.c */
pCounterDriver CreateCounterDriver(char *name, char *type);
void DeleteCounterDriver(pCounterDriver self);
/* PSI EL737 Counter */
pCounterDriver NewEL737Counter(char *name, char *host, int iPort,
int iChannel);
void KillEL737Counter(pCounterDriver self);
/* PSI Simulation counter, if you have no hardware */
/* simcter.c */
pCounterDriver NewSIMCounter(char *name);
void KillSIMCounter(pCounterDriver self);
#endif

1026
counter.c Normal file

File diff suppressed because it is too large Load Diff

56
counter.h Normal file
View File

@ -0,0 +1,56 @@
/*-------------------------------------------------------------------------
C O U N T E R
The SICS Interface to a single detector and his associated
monitors.
Mark Koennecke, January 1996
copyright: see implementation file.
----------------------------------------------------------------------------*/
#ifndef SICSCOUNTER
#define SICSCOUNTER
#include "countdriv.h"
typedef struct {
pObjectDescriptor pDes;
char *name;
int isUpToDate;
int iExponent;
pICountable pCountInt;
pCounterDriver pDriv;
pICallBack pCall;
unsigned long tStart;
} Counter, *pCounter;
/*----------------------------- birth & death -----------------------------*/
pCounter CreateCounter(char *name, pCounterDriver pDriv);
void DeleteCounter(void *self);
int MakeCounter(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
/*------------------------- set/get Parameters ----------------------------*/
int SetCounterMode(pCounter self, CounterMode eNew);
CounterMode GetCounterMode(pCounter self);
int SetCounterPreset(pCounter self, float fVal);
float GetCounterPreset(pCounter self);
long GetCounts(pCounter self, SConnection *pCon);
long GetMonitor(pCounter self, int iNum, SConnection *pCon);
int GetNMonitor(pCounter self);
float GetCountTime(pCounter self, SConnection *pCon);
int DoCount(pCounter self,float fPreset, SConnection *pCon,
int iBlock);
/*-------------------------------------------------------------------------
the real action: starting and checking is packaged with the
ObjectDescriptor.
*/
int CountAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
#endif

50
countf.tcl Normal file
View File

@ -0,0 +1,50 @@
#--------------------------------------------------------------------------
# A count command for FOCUS
# All arguments are optional. The current values will be used if not
# specified
# Dr. Mark Koennecke, Juli 1997
#--------------------------------------------------------------------------
proc SplitReply { text } {
set l [split $text =]
return [lindex $l 1]
}
#--------------------------------------------------------------------------
proc count { {mode NULL } { preset NULL } } {
starttime [sicstime]
#----- deal with mode
set mode2 [string toupper $mode]
set mode3 [string trim $mode2]
set mc [string index $mode2 0]
if { [string compare $mc T] == 0 } {
hm CountMode Timer
} elseif { [string compare $mc M] == 0 } {
hm CountMode Monitor
}
#------ deal with preset
if { [string compare $preset NULL] != 0 } {
hm preset $preset
}
#------ prepare a count message
set a [hm preset]
set aa [SplitReply $a]
set b [hm CountMode]
set bb [SplitReply $b]
ClientPut [format " Starting counting in %s mode with a preset of %s" \
$bb $aa]
#------- count
# hm InitVal 0
wait 1
set ret [catch {hm countblock} msg]
#------- StoreData
storefocus update
# wait 5
if { $ret != 0 } {
error [format "Counting ended with error: %s" $msg]
}
}
#---------------- Repeat -----------------------------------------------
proc repeat { num {mode NULL} {preset NULL} } {
for { set i 0 } { $i < $num } { incr i } {
count $mode $preset
}
}

16
cron.tex Normal file
View File

@ -0,0 +1,16 @@
\subsection{cron}
This module allows to install commands into SICS which will be repeated
periodically. The syntax is: sicscron intervall command. intervall is
the time intervall and command is the command to execute. A problem
is I/O becasue the original connection which installed the cron job
may be lost. Therefore cron commands are executed within the context
of special connection which does not do socket output. All I/O will be
logged into the command log though for control. As
this is a single system facility all data structure will be defined
in the implementation file. The public interface to this is just the
installation routine. This stuff is implemented in the files
sicscron.h and sicscron.c.
The installation routine installs another task into the SICS system
which will invoke the command to be executed at the predefined
intervalls.

16
cron.w Normal file
View File

@ -0,0 +1,16 @@
\subsection{cron}
This module allows to install commands into SICS which will be repeated
periodically. The syntax is: sicscron intervall command. intervall is
the time intervall and command is the command to execute. A problem
is I/O becasue the original connection which installed the cron job
may be lost. Therefore cron commands are executed within the context
of special connection which does not do socket output. All I/O will be
logged into the command log though for control. As
this is a single system facility all data structure will be defined
in the implementation file. The public interface to this is just the
installation routine. This stuff is implemented in the files
sicscron.h and sicscron.c.
The installation routine installs another task into the SICS system
which will invoke the command to be executed at the predefined
intervalls.

293
danu.c Normal file
View File

@ -0,0 +1,293 @@
/*-----------------------------------------------------------------------
D A T A N U M B E R
Implementation file for the data number module.
Mark Koennecke, Juli 1997
Copyright:
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5423 Villigen-PSI
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
----------------------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <assert.h>
#include "fortify.h"
#include "conman.h"
#include "obdes.h"
#include "danu.h"
/* ------------------ the data structure ----------------------------------*/
typedef struct __DataNumber {
pObjectDescriptor pDes;
char *pFileName;
} DataNumber;
/*-------------------------------------------------------------------------*/
pDataNumber CreateDataNumber(char *pFileName)
{
pDataNumber pNew = NULL;
FILE *fd = NULL;
pNew = (pDataNumber)malloc(sizeof(DataNumber));
if(!pNew)
{
return NULL;
}
memset(pNew,0,sizeof(DataNumber));
pNew->pDes = CreateDescriptor("DataNumber");
if(!pNew->pDes)
{
free(pNew);
return NULL;
}
/* check filename */
fd = fopen(pFileName,"r");
if(!fd)
{
printf("Serious error: cannot open file for Data Number!!!!\n");
printf("I continue, but you should not write data files!\n");
pNew->pFileName = strdup("default.num");
return pNew;
}
fclose(fd);
pNew->pFileName = strdup(pFileName);
return pNew;
}
/*--------------------------------------------------------------------------*/
void DeleteDataNumber(void *pData)
{
pDataNumber self = NULL;
self = (pDataNumber)pData;
assert(self);
if(self->pDes)
{
DeleteDescriptor(self->pDes);
}
if(self->pFileName)
{
free(self->pFileName);
}
free(self);
}
/*-------------------------------------------------------------------------*/
int IncrementDataNumber(pDataNumber self, int *iYear)
{
FILE *fd = NULL;
int iNum;
time_t iTime;
struct tm *psTime;
/* open file */
fd = fopen(self->pFileName,"r");
if(!fd)
{
return -1;
}
/* get and increment number */
fscanf(fd,"%d",&iNum);
iNum++;
fclose(fd);
/* reopen for rewriting */
fd = fopen(self->pFileName,"w");
if(fd == NULL)
{
return -1;
}
/* write file and leave */
fprintf(fd," %d \n",iNum);
fprintf(fd,"NEVER, EVER modify or delete this file\n");
fprintf(fd,"You'll risk eternal damnation and a reincarnation as a cockroach!|n");
fclose(fd);
/* get year */
iTime = time(NULL);
psTime = localtime(&iTime);
*iYear = psTime->tm_year + 1900;
return iNum;
}
/*-------------------------------------------------------------------------*/
int DecrementDataNumber(pDataNumber self)
{
FILE *fd = NULL;
int iNum;
/* open file */
fd = fopen(self->pFileName,"r");
if(!fd)
{
return -1;
}
/* get and decrement number */
fscanf(fd,"%d",&iNum);
iNum--;
if(iNum < 0)
iNum = 0;
fclose(fd);
/* reopen for rewriting */
fd = fopen(self->pFileName,"w");
/* write file and leave */
fprintf(fd," %d \n",iNum);
fprintf(fd,"NEVER, EVER modify or delete this file\n");
fprintf(fd,"You'll risk eternal damnation and a reincarnation as a cockroach!|n");
fclose(fd);
return iNum;
}
/*-------------------------------------------------------------------------*/
int DNWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
pDataNumber self = NULL;
FILE *fd = NULL;
int iNum, iYear;
char pBueffel[512];
self = (pDataNumber)pData;
assert(self);
assert(pCon);
argtolower(argc,argv);
if(argc < 2) /* value request */
{
fd = fopen(self->pFileName,"r");
if(!fd)
{
sprintf(pBueffel,"ERROR: cannot open file %s",self->pFileName);
SCWrite(pCon,pBueffel,eError);
return 0;
}
fscanf(fd,"%d",&iNum);
fclose(fd);
sprintf(pBueffel,"%s = %d",argv[0],iNum);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
if(strcmp(argv[1],"incr") == 0)
{
iNum = IncrementDataNumber(self,&iYear);
if(iNum > 0)
{
SCSendOK(pCon);
return 1;
}
else
{
sprintf(pBueffel,"ERROR: cannot increment %s",argv[0]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
}
sprintf(pBueffel,"ERROR: unknown command %s supplied to %s",
argv[1], argv[0]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/*------------------------------------------------------------------------*/
int DEWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
pDataNumber self = NULL;
int iNum;
char pBueffel[512];
self = (pDataNumber)pData;
assert(self);
assert(pCon);
if(SCMatchRights(pCon,usMugger))
{
DecrementDataNumber(self);
SCWrite(pCon,"Data file killed",eWarning);
return 1;
}
else
{
SCWrite(pCon,"ERROR: you are not authorized to kill data files",
eError);
return 0;
}
}
/*-------------------------------------------------------------------------*/
int DNFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
pDataNumber self = NULL;
char pBueffel[512];
int iRet;
if(argc < 3)
{
SCWrite(pCon,
"ERROR: not enough arguments provided to make DataNumber",eError);
return 0;
}
self = CreateDataNumber(argv[2]);
if(!self)
{
SCWrite(pCon,"ERROR: no memory to create data number",eError);
return 0;
}
iRet = AddCommand(pSics, argv[1],DNWrapper, DeleteDataNumber, self);
if(!iRet)
{
sprintf(pBueffel,"ERROR: duplicate command %s not created",argv[1]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = AddCommand(pSics,"killfile",DEWrapper,NULL, self);
if(!iRet)
{
sprintf(pBueffel,"ERROR: duplicate command %s not created",argv[1]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
return 1;
}

3
danu.dat Normal file
View File

@ -0,0 +1,3 @@
45
NEVER, EVER modify or delete this file
You'll risk eternal damnation and a reincarnation as a cockroach!|n

41
danu.h Normal file
View File

@ -0,0 +1,41 @@
#line 53 "danu.w"
/*-----------------------------------------------------------------------
D A T A N U M B E R
A module to provide a unique data number for data file writing.
Mark Koennecke, Juli 1997
copyright: see implementation file.
---------------------------------------------------------------------------*/
#ifndef SICSDATANUMBER
#define SICSDATANUMBER
#line 15 "danu.w"
typedef struct __DataNumber *pDataNumber;
pDataNumber CreateDataNumber(char *pFilename);
void DeleteDataNumber(void *pData);
int IncrementDataNumber(pDataNumber self, int *iYear);
int DecrementDataNumber(pDataNumber self);
int DNWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int DEWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int DNFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
#line 67 "danu.w"
#endif

92
danu.tex Normal file
View File

@ -0,0 +1,92 @@
\subsection{Data Number}
In some points of its life SICS has to write data files. The file names
usually consist of a header, a serial number and an indicator for the
year. The serial number must be unique and steadliy increasing. In order to
achieve this, the serial number are written into a file after any change.
Incrementing the serial number thus involves the following steps:
\begin{itemize}
\item Open file and read current number.
\item Increment number
\item Write File and close
\end{itemize}
This little task is implemented in this module.
The interface to this looks like:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$dni {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __DataNumber *pDataNumber;@\\
\mbox{}\verb@@\\
\mbox{}\verb@ pDataNumber CreateDataNumber(char *pFilename);@\\
\mbox{}\verb@ void DeleteDataNumber(void *pData);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int IncrementDataNumber(pDataNumber self, int *iYear);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int DecrementDataNumber(pDataNumber self);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int DNWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int DEWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int DNFactory(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{description}
\item [CreateDataNumber] creates a data number data structure. It checks if
the file requested as parameter exists and asserts if not. Returns a pointer
on success, NULL else.
\item [DeleteDataNumber] deletes a data number structure form memory.
\item [IncrementDataNumber] is the main working function of this module.
It performs the steps listed above. It returns a new id for the data number
in case of success, a negative value otherwise. iYear is filled with a value
for the year.
\item[DecrementDataNumber] decrements the data number and is used for
implementing the killdata function. Whis is the invalidation of a
data file by overwriting it.
\item[DNWrapper] is the wrapper function which makes DataNumber accessible
from within SICS.
\item[DEWrapper] is the wrapper for the killdata functionality.
\item [DNFactory] is the SICS factory function which creates a Data Number
object from the initialisation file. Only parameter is the filename.
\end{description}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
\verb@"danu.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-----------------------------------------------------------------------@\\
\mbox{}\verb@ D A T A N U M B E R@\\
\mbox{}\verb@@\\
\mbox{}\verb@ A module to provide a unique data number for data file writing.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, Juli 1997@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ copyright: see implementation file.@\\
\mbox{}\verb@@\\
\mbox{}\verb@---------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSDATANUMBER@\\
\mbox{}\verb@#define SICSDATANUMBER@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\langle$dni {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

77
danu.w Normal file
View File

@ -0,0 +1,77 @@
\subsection{Data Number}
In some points of its life SICS has to write data files. The file names
usually consist of a header, a serial number and an indicator for the
year. The serial number must be unique and steadliy increasing. In order to
achieve this, the serial number are written into a file after any change.
Incrementing the serial number thus involves the following steps:
\begin{itemize}
\item Open file and read current number.
\item Increment number
\item Write File and close
\end{itemize}
This little task is implemented in this module.
The interface to this looks like:
@d dni @{
typedef struct __DataNumber *pDataNumber;
pDataNumber CreateDataNumber(char *pFilename);
void DeleteDataNumber(void *pData);
int IncrementDataNumber(pDataNumber self, int *iYear);
int DecrementDataNumber(pDataNumber self);
int DNWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int DEWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int DNFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
@}
\begin{description}
\item [CreateDataNumber] creates a data number data structure. It checks if
the file requested as parameter exists and asserts if not. Returns a pointer
on success, NULL else.
\item [DeleteDataNumber] deletes a data number structure form memory.
\item [IncrementDataNumber] is the main working function of this module.
It performs the steps listed above. It returns a new id for the data number
in case of success, a negative value otherwise. iYear is filled with a value
for the year.
\item[DecrementDataNumber] decrements the data number and is used for
implementing the killdata function. Whis is the invalidation of a
data file by overwriting it.
\item[DNWrapper] is the wrapper function which makes DataNumber accessible
from within SICS.
\item[DEWrapper] is the wrapper for the killdata functionality.
\item [DNFactory] is the SICS factory function which creates a Data Number
object from the initialisation file. Only parameter is the filename.
\end{description}
@o danu.h -d @{
/*-----------------------------------------------------------------------
D A T A N U M B E R
A module to provide a unique data number for data file writing.
Mark Koennecke, Juli 1997
copyright: see implementation file.
---------------------------------------------------------------------------*/
#ifndef SICSDATANUMBER
#define SICSDATANUMBER
@<dni@>
#endif
@}

19
defines.h Normal file
View File

@ -0,0 +1,19 @@
/* ======================================================================
DEFINES.h Standard definitions etc.
For simplification or for debugging substitution.
v1.02 94-08-11 Stripped version.
_____ This version is Public Domain.
/_|__| A.Reitsma, Delft, Nederland.
/ | \ --------------------------------------------------------------- */
#include <stdlib.h> /* for malloc() prototype */
#include <string.h> /* for memcpy() prototype */
#include "fortify.h"
#define MALLOC(size,type) (type *) malloc( (size) * sizeof( type ))
#define FREE(mem) free( mem )
#define CALLOC(size,type) (type *) calloc( (size), sizeof( type))
/* === DEFINES.h end ================================================= */

922
devexec.c Normal file
View File

@ -0,0 +1,922 @@
/*-------------------------------------------------------------------------
D E V I C E E X E C U T E R
Mark Koennecke, December 1996
Substantial rewrite: Mark Koennecke, February 1997
revised: Mark Koennecke, June 1997
revised for use with tasker: Mark Koennecke, September 1997
Copyright:
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5423 Villigen-PSI
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
-----------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "fortify.h"
#include "conman.h"
#include "Scommon.h"
#include "interface.h"
#include "nserver.h"
#include "motor.h"
#include "countdriv.h"
#include "counter.h"
#include "task.h"
#include "devexec.h"
#include "status.h"
#include "lld.h"
#include "event.h"
/*
#define DEBUG 1
*/
typedef struct _DevEntry {
void *pData;
pObjectDescriptor pDescriptor;
float fVal;
char *name;
} DevEntry, *pDevEntry;
/*-------------------------------------------------------------------------*/
static pDevEntry CreateDevEntry(pObjectDescriptor pDes, void *pData,
float fVal, char *name)
{
pDevEntry pNew = NULL;
assert(pDes);
pNew = (pDevEntry)malloc(sizeof(DevEntry));
if(!pNew)
{
return NULL;
}
pNew->pDescriptor = pDes;
pNew->pData = pData;
pNew->name = strdup(name);
pNew->fVal = fVal;
return pNew;
}
/*-------------------------------------------------------------------------*/
static void DeleteDevEntry(pDevEntry self)
{
assert(self);
if(self->name)
{
free(self->name);
}
free(self);
}
/* ----------------- The Executor himself ---------------------------------*/
typedef struct __EXELIST{
pObjectDescriptor pDes;
SConnection *pOwner;
int iList;
int iRun;
int iStop;
int iStatus;
int iEnd;
long lTask;
pTaskMan pTask;
} ExeList;
static pExeList pExecutor = NULL;
/*--------------------------------------------------------------------------*/
pExeList CreateExeList(pTaskMan pTask)
{
pExeList pRes = NULL;
assert(pTask);
pRes = (pExeList)malloc(sizeof(ExeList));
if(!pRes)
{
return NULL;
}
pRes->pOwner = NULL;
pRes->pDes = CreateDescriptor("DeviceExecutor");
if(!pRes->pDes)
{
free(pRes);
return NULL;
}
pRes->iList = LLDcreate(sizeof(pDevEntry));
if(pRes->iList == -1)
{
free(pRes);
return NULL;
}
pRes->iRun = 0;
pRes->iStatus = DEVDONE;
pRes->pTask = pTask;
pRes->lTask = -1;
return pRes;
}
/*-------------------------------------------------------------------------*/
void DeleteExeList(void *pData)
{
pExeList self;
assert(pData);
self = (pExeList)pData;
if(self->pDes)
DeleteDescriptor(self->pDes);
ClearExecutor(self);
LLDdelete(self->iList);
free(self);
}
/*------------------------------------------------------------------------*/
int StartDevice(pExeList self, char *name, pObjectDescriptor pDes,
void *pData, SConnection *pCon, float fNew)
{
pDevEntry pNew = NULL;
int iRet;
char pBueffel[132];
pIDrivable pDrivInt = NULL;
pICountable pCountInt = NULL;
assert(self);
assert(pDes);
assert(pCon);
/* may we? */
if(self->pOwner != NULL)
{
if(pCon != self->pOwner)
{
SCWrite(pCon,
"ERROR: somebody else is still driving, Request rejected",eError);
return 0;
}
}
else
{
self->pOwner = pCon;
}
/* well create a new entry */
self->iStop = 0;
pNew = CreateDevEntry(pDes,pData,fNew,name);
if(!pNew)
{
SCWrite(pCon,"ERROR: memory exhausted in Device Executor ",eError);
SCSetError(pCon,NOMEMORY);
return 0;
}
/* start it */
pDrivInt = pDes->GetInterface(pData,DRIVEID);
pCountInt = pDes->GetInterface(pData,COUNTID);
if(pDrivInt)
{
iRet = pDrivInt->SetValue(pData,pCon,fNew);
}
else if(pCountInt)
{
iRet = pCountInt->StartCount(pData,pCon);
}
else
{ /* this is a programmers error */
SCWrite(pCon,"ERROR: Programmer error in StartDevice ",eError);
iRet = 0;
}
/* check return status */
if(iRet == OKOK)
{
LLDnodeAppendFrom(self->iList,&pNew);
self->iRun = 1;
self->iStatus = DEVDONE;
/* if no task: start it */
if(self->lTask < 0)
{
self->lTask = TaskRegister(self->pTask,
DevExecTask,
DevExecSignal,
NULL,
self,
1);
self->iEnd = 0;
}
return 1;
}
else
{
sprintf(pBueffel,"ERROR: cannot start device %s",name);
SCWrite(pCon,pBueffel,eError);
SCSetError(self->pOwner,iRet);
DeleteDevEntry(pNew);
if(LLDcheck(self->iList) >= LIST_EMPTY)
{
self->pOwner = NULL;
}
return 0;
}
return 0;
}
/*--------------------------------------------------------------------------*/
int StartMotor(pExeList self, SicsInterp *pSics, SConnection *pCon,
char *name, float fVal)
{
pMotor pMot = NULL;
CommandList *pCom = NULL;
char pBueffel[256];
assert(self);
assert(pSics);
assert(name);
pCom = FindCommand(pSics,name);
if(!pCom)
{
sprintf(pBueffel,"ERROR: cannot find motor %s",name);
SCWrite(pCon,pBueffel,eError);
return 0;
}
pMot = (pMotor)pCom->pData;
if(!pMot)
{
sprintf(pBueffel,"ERROR: %s is no motor ",name);
SCWrite(pCon,pBueffel,eError);
return 0;
}
if(!pMot->pDescriptor)
{
sprintf(pBueffel,"ERROR: cannot find motor %s",name);
SCWrite(pCon,pBueffel,eError);
return 0;
}
if(!pMot->pDescriptor->GetInterface(pMot,DRIVEID))
{
sprintf(pBueffel,"ERROR: %s is no motor",name);
SCWrite(pCon,pBueffel,eError);
return 0;
}
return StartDevice(self,name,pMot->pDescriptor,(void *)pMot,pCon,fVal);
}
/*---------------------------------------------------------------------------*/
int StartCounter(pExeList self, SicsInterp *pSics,SConnection *pCon,
char *name)
{
pCounter pCter = NULL;
CommandList *pCom = NULL;
char pBueffel[256];
assert(self);
assert(pSics);
assert(name);
pCom = FindCommand(pSics,name);
if(!pCom)
{
sprintf(pBueffel,"ERROR: cannot find counter %s",name);
SCWrite(pCon,pBueffel,eError);
return 0;
}
pCter = (pCounter)pCom->pData;
if(!pCter)
{
sprintf(pBueffel,"ERROR: %s is no counter ",name);
SCWrite(pCon,pBueffel,eError);
return 0;
}
if(!pCter->pDes)
{
sprintf(pBueffel,"ERROR: cannot find counter %s",name);
SCWrite(pCon,pBueffel,eError);
return 0;
}
if(!pCter->pDes->GetInterface(pCter,COUNTID))
{
sprintf(pBueffel,"ERROR: %s is no counter",name);
SCWrite(pCon,pBueffel,eError);
return 0;
}
return StartDevice(self,name,pCter->pDes,(void *)pCter,
pCon,pCter->pDriv->fPreset);
}
/*--------------------------------------------------------------------------*/
int CheckExeList(pExeList self)
{
int iRet;
pDevEntry pDev = NULL;
pICountable pCountInt = NULL;
pIDrivable pDrivInt = NULL;
int eCode;
assert(self);
/* Sometimes this gets called, though nothing is running. There are
cases where this is feasible for maintainance, but in some cases it
is pure rubbish, because nothing runs. This will ne checkd here.
*/
if((self->pOwner == NULL) || (LLDcheck(self->iList) == LIST_EMPTY))
{
self->iRun = 0;
self->iEnd = 1;
self->iStop = 0;
return 1;
}
iRet = LLDnodePtr2First(self->iList);
while(iRet != 0)
{
LLDnodeDataTo(self->iList,&pDev);
if(pDev)
{
pDrivInt = pDev->pDescriptor->GetInterface(pDev->pData,DRIVEID);
pCountInt = pDev->pDescriptor->GetInterface(pDev->pData,COUNTID);
if(pDrivInt)
{
eCode = pDrivInt->CheckStatus(pDev->pData,self->pOwner);
}
else if(pCountInt)
{
eCode = pCountInt->CheckCountStatus(pDev->pData,self->pOwner);
}
switch(eCode)
{
case HWIdle:
case OKOK:
if(pCountInt)
{
pCountInt->TransferData(pDev->pData,self->pOwner);
}
else if(pDrivInt)
{
pDrivInt->iErrorCount = 0;
}
DeleteDevEntry(pDev);
LLDnodeDelete(self->iList);
iRet = LLDnodePtr2Prev(self->iList);
self->iStatus = DEVDONE;
break;
case HWFault: /* real HW error: burning, no net etc.. */
SCSetError(self->pOwner,iRet);
DeleteDevEntry(pDev);
LLDnodeDelete(self->iList);
self->iStatus = DEVERROR;
if(pDrivInt)
{
pDrivInt->iErrorCount++;
}
if(SCGetInterrupt(self->pOwner) != eContinue)
{
self->iStatus = DEVINT;
StopExe(self,"all");
return -1;
}
break;
case HWNoBeam:
SetStatus(eOutOfBeam);
if(SCGetInterrupt(self->pOwner) != eContinue)
{
self->iStatus = DEVINT;
return -1;
}
break;
case HWPause:
SetStatus(ePaused);
if(SCGetInterrupt(self->pOwner) != eContinue)
{
self->iStatus = DEVINT;
return -1;
}
break;
case HWBusy:
if(pCountInt)
{
SetStatus(eCounting);
}
else if(pDrivInt)
{
SetStatus(eDriving);
}
self->iStatus = DEVBUSY;
break;
case HWPosFault: /* cannot get somewhere... */
SCSetError(self->pOwner,eCode);
DeleteDevEntry(pDev);
LLDnodeDelete(self->iList);
self->iStatus = DEVERROR;
if(pDrivInt)
{
pDrivInt->iErrorCount++;
}
if(SCGetInterrupt(self->pOwner) != eContinue)
{
self->iStatus = DEVINT;
StopExe(self,"all");
return -1;
}
break;
}
}
iRet = LLDnodePtr2Next(self->iList);
}
iRet = LLDnodePtr2First(self->iList);
if(LLDcheck(self->iList) == LIST_EMPTY)
{
self->pOwner = NULL;
self->iEnd = 1;
self->iRun = 0;
self->lTask = -1;
return 1;
}
else
{
return 0;
}
}
/*---------------------------------------------------------------------------*/
int Wait4Success(pExeList self)
{
int iRet;
assert(self);
self->iRun = 0;
/* do nothing if not running */
if(self->lTask < 0)
{
printf("Wait4Success finished very, very badly\n");
return self->iStatus;
}
/* wait for Devexec task to finish */
TaskWait(self->pTask,self->lTask);
#ifdef DEBUG
printf("Wait4Success finished\n");
#endif
return self->iStatus;
}
/*--------------------------------------------------------------------------*/
int ListPending(pExeList self, SConnection *pCon)
{
int iRet,i;
char pBueffel[512];
pDevEntry pDev = NULL;
assert(self);
assert(pCon);
/* first make sure that the list is fully updated */
iRet = CheckExeList(self);
if(iRet == 1) /* nothing to do! */
{
SCWrite(pCon,"Machine idle",eStatus);
return 1;
}
else if(iRet == -1)
{
SCWrite(pCon,"Handling Interrupt",eStatus);
return 0;
}
/* search the list for entries */
iRet = LLDnodePtr2First(self->iList);
while(iRet != 0)
{
LLDnodeDataTo(self->iList,&pDev);
if(pDev)
{
sprintf(pBueffel,"\t%s %f",pDev->name,pDev->fVal);
SCWrite(pCon,pBueffel,eStatus);
}
iRet = LLDnodePtr2Next(self->iList);
}
return 1;
}
/* -----------------------------------------------------------------------*/
long GetDevexecID(pExeList self)
{
assert(self);
return self->lTask;
}
/*--------------------------------------------------------------------------*/
int StopExe(pExeList self, char *name)
{
int i, iRet;
pDevEntry pDev = NULL;
pIDrivable pDrivInt = NULL;
pICountable pCountInt = NULL;
assert(self);
/* if not active, nothing to do */
if((self->pOwner == NULL) || (LLDcheck(self->iList) == LIST_EMPTY))
{
self->iRun = 0;
return 1;
}
/*
check for stop flag. This is to stop unnecessary calls to StopExe.
There may be way to many, but each call is reasonable under certain
circumstances.
*/
if(self->iStop == 1)
{
return;
}
else
{
self->iStop = 1;
}
/* first the ALL case */
if(strcmp(name,"all") == 0)
{
iRet = LLDnodePtr2First(self->iList);
while(iRet != 0)
{
pDev = (pDevEntry)LLDnodePtr(self->iList);
if(pDev)
{
pDrivInt = pDev->pDescriptor->GetInterface(pDev->pData,DRIVEID);
pCountInt = pDev->pDescriptor->GetInterface(pDev->pData,COUNTID);
if(pDrivInt)
{
pDrivInt->Halt(pDev->pData);
}
else if(pCountInt)
{
pCountInt->Halt(pDev->pData);
}
}
iRet = LLDnodePtr2Next(self->iList);
}
SCWrite(self->pOwner,"ERROR: Full Stop called!!",eError);
if(SCGetInterrupt(self->pOwner) > eContinue)
{
self->iStatus = DEVINT;
}
return 1;
}
/* now the special case: a well defined command */
iRet = LLDnodePtr2First(self->iList);
while(iRet != 0)
{
pDev = (pDevEntry)LLDnodePtr(self->iList);
if(pDev)
{
if(strcmp(pDev->name,name) == 0)
{
pDrivInt = pDev->pDescriptor->GetInterface(pDev->pData,DRIVEID);
pCountInt = pDev->pDescriptor->GetInterface(pDev->pData,COUNTID);
if(pDrivInt)
{
pDrivInt->Halt(pDev->pData);
}
else if(pCountInt)
{
pDrivInt->Halt(pDev->pData);
}
return 1;
}
}
iRet = LLDnodePtr2Next(self->iList);
}
return 0;
}
/*-------------------------------------------------------------------------*/
int StopExeWait(pExeList self)
{
StopExe(self,"all");
Wait4Success(self);
return 1;
}
/*--------------------------------------------------------------------------*/
int PauseExecution(pExeList self)
{
int i, iRet, iRes;
pDevEntry pDev = NULL;
pICountable pCountInt = NULL;
assert(self);
/* step through the list */
iRes = 0;
iRet = LLDnodePtr2First(self->iList);
while(iRet != 0)
{
pDev = (pDevEntry)LLDnodePtr(self->iList);
if(pDev)
{
pCountInt = pDev->pDescriptor->GetInterface(pDev->pData,COUNTID);
if(pCountInt)
{
iRet = pCountInt->Pause(pDev->pData,self->pOwner);
if(!iRet)
{
iRes = 0;
}
}
}
iRet = LLDnodePtr2Next(self->iList);
}
SetStatus(ePaused);
return iRes;
}
/*------------------------------------------------------------------------*/
int IsCounting(pExeList self)
{
int iRet;
pDevEntry pDev = NULL;
pICountable pCountInt = NULL;
assert(self);
/* step through the list */
iRet = LLDnodePtr2First(self->iList);
while(iRet != 0)
{
pDev = (pDevEntry)LLDnodePtr(self->iList);
if(pDev)
{
pCountInt = pDev->pDescriptor->GetInterface(pDev->pData,COUNTID);
if(pCountInt)
{
return 1;
}
}
iRet = LLDnodePtr2Next(self->iList);
}
return 0;
}
/*--------------------------------------------------------------------------*/
int ContinueExecution(pExeList self)
{
int i, iRet, iRes;
pDevEntry pDev = NULL;
pICountable pCountInt = NULL;
assert(self);
/* step through the list */
iRes = 0;
iRet = LLDnodePtr2First(self->iList);
while(iRet != 0)
{
pDev = (pDevEntry)LLDnodePtr(self->iList);
if(pDev)
{
pCountInt = pDev->pDescriptor->GetInterface(pDev->pData,COUNTID);
if(pCountInt)
{
iRet = pCountInt->Continue(pDev->pData,self->pOwner);
if(!iRet)
{
iRes = 0;
}
}
}
iRet = LLDnodePtr2Next(self->iList);
}
SetStatus(eCounting);
return iRes;
}
/*------------------------------------------------------------------------*/
void ClearExecutor(pExeList self)
{
int iRet;
pDevEntry pDev = NULL;
assert(self);
iRet = LLDnodePtr2First(self->iList);
while(iRet != 0)
{
pDev = (pDevEntry)LLDnodePtr(self->iList);
if(pDev)
{
DeleteDevEntry(pDev);
}
LLDnodeDelete(self->iList);
iRet = LLDnodePtr2Prev(self->iList);
iRet = LLDnodePtr2Next(self->iList);
}
if(self->pOwner)
{
if(SCGetInterrupt(self->pOwner) > eContinue)
{
self->iStatus = DEVINT;
}
}
self->pOwner = NULL;
self->iEnd = 1;
self->lTask = -1;
self->iRun = 0;
}
/*-------------------------------------------------------------------------*/
int StopCommand(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
pExeList self = NULL;
int iRet;
char pBueffel[132];
assert(pCon);
assert(pSics);
assert(pData);
/* check Privilege: Muggers may do it */
if(!SCMatchRights(pCon,usMugger))
{
SCWrite(pCon,"ERROR: NO Privilege to Stop operation ",eError);
return 0;
}
argtolower(argc,argv);
self = (pExeList)pData;
if(argc < 2)
{
ListPending(self,pCon);
return 1;
}
iRet = StopExe(self,argv[1]);
if(!iRet)
{
sprintf(pBueffel,"ERROR: %s not found, so could not halt", argv[1]);
SCWrite(pCon,pBueffel,eError);
}
return iRet;
}
/*--------------------------------------------------------------------------*/
int ListExe(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
return ListPending((pExeList)pData,pCon);
}
/*--------------------------------------------------------------------------
Usage:
Success
*/
int Success(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
int iRet;
Status eOld;
eOld = GetStatus();
SetStatus(eRunning);
iRet = Wait4Success((pExeList)pData);
if(iRet == DEVINT)
{
if(SCGetInterrupt(pCon) == eAbortOperation)
{
SCSetInterrupt(pCon,eContinue);
iRet = 0;
}
}
else if(iRet == DEVDONE)
{
SCWrite(pCon,"All done",eStatus);
iRet = 1;
}
else if(iRet = DEVERROR)
{
SCWrite(pCon,"Finished with Problems",eStatus);
iRet = 1;
}
SetStatus(eEager);
return iRet;
}
/*--------------------------------------------------------------------------*/
int isInRunMode(pExeList self)
{
assert(self);
return self->iRun;
}
/*--------------------------------------------------------------------------*/
SConnection *GetExeOwner(pExeList self)
{
if(self == NULL)
return NULL;
return self->pOwner;
}
/*--------------------------------------------------------------------------*/
int DevExecTask(void *pData)
{
pExeList self = NULL;
int iRet;
self = (pExeList)pData;
/* am I bound to end ? */
if(self->iEnd)
{
self->lTask = -1;
SetStatus(eEager);
return 0;
}
iRet = CheckExeList(self);
switch(iRet)
{
case -1: /* some problem */
if(SCGetInterrupt(self->pOwner) != eContinue)
{
SCWrite(self->pOwner,"ERROR: aborting operation due to HW problem",
eError);
StopExe(self,"all");
#ifdef DEBUG
printf("DevExecTask found an error\n");
#endif
return 1;
}
else
{
return 1;
}
break;
case 1: /* Success */
self->lTask = -1;
self->iEnd = 1;
SetStatus(eEager);
#ifdef DEBUG
printf("DevExecTask finishes on success\n");
#endif
return 0;
break;
default: /* continue, still busy */
return 1;
}
/* should not get here */
return 1;
}
/*---------------------------------------------------------------------------*/
void DevExecSignal(void *pEL, int iSignal, void *pSigData)
{
int *iInt;
pExeList self = NULL;
self = (pExeList)pEL;
assert(self);
if(iSignal == SICSINT)
{
iInt = (int *)pSigData;
if(*iInt != eContinue)
{
if(self->pOwner)
{
SCWrite(self->pOwner,"ERROR: Interrupting Current Hardware Operation",
eError);
SCSetInterrupt(self->pOwner,*iInt);
}
StopExe(self,"all");
}
}
}

146
devexec.h Normal file
View File

@ -0,0 +1,146 @@
#line 184 "devexec.w"
/*----------------------------------------------------------------------------
D E V I C E E X E C U T O R
Joachim Kohlbrecher wants to give several commands to the server
and than wait for them to happen before proceeding. Actually a useful
thing. A command will map to one or several positioning commands for a
device. This scheme is also useful for implementing objects which
drive several motors simulataneously, such as Monochromators. etc.
However, the whole thing is rather complicated.
It is forbidden, that several clients drive the instrument. In order
to ensure this the Executor remembers the connection which emitted the
first command. Subsequent AddExeEntries from different clients will
be rejected. The owner will be reset when the execution is found finished
in calls to CheckExe, Wait4Success or StopExe.
Mark Koennecke, December 1996
copyright: see implementation file
---------------------------------------------------------------------------*/
#ifndef SICSDEVEXEC
#define SICSDEVEXEC
#include "obdes.h"
#include "task.h"
typedef struct __EXELIST *pExeList;
/* Returncodes */
#define DEVDONE 1
#define DEVINT 0
#define DEVERROR 2
#define DEVBUSY 3
/*------------------------------------------------------------------------
B I R T H & D E A T H
*/
pExeList CreateExeList(pTaskMan pTask);
void DeleteExeList(void *self);
/* ================= Functions to talk to the above ====================== */
#line 43 "devexec.w"
int StartDevice(pExeList self, char *name, pObjectDescriptor pDes,
void *pData, SConnection *pCon, float fNew);
int StartMotor(pExeList self, SicsInterp *pSics, SConnection *pCon,
char *name, float fNew);
int StartCounter(pExeList self, SicsInterp *pSics, SConnection *pCon,
char *name);
#line 228 "devexec.w"
/*------------------------------------------------------------------------*/
#line 88 "devexec.w"
int CheckExeList(pExeList self);
/*
checks the entries for success and deletes entries which have finished
operation. If there are none left, the pOwner will be set to NULL.
*/
int Wait4Success(pExeList self);
long GetDevexecID(pExeList self);
int DevExecTask(void *pEL);
void DevExecSignal(void *pEL, int iSignal, void *pSigData);
#line 230 "devexec.w"
/*
Waits for execution to finish. returns 1 on Success, 0 if problems
ocurred. Than the Interrupt code shall be checked and acted upon
accordingly.
*/
/*-------------------------------------------------------------------------*/
SConnection *GetExeOwner(pExeList self);
/*-------------------------------------------------------------------------*/
int isInRunMode(pExeList self);
/*--------------------------------------------------------------------------*/
int ListPending(pExeList self, SConnection *pCon);
/*
lists the Operations still pending on pCon.
*/
/*-------------------------------------------------------------------------*/
#line 137 "devexec.w"
int StopExe(pExeList self, char *name);
int StopExeWait(pExeList self);
/*
will stop the entry name and its subentries from executing.
If ALL is specified as name, everything will be stopped and
the Executor cleared.
StopExeWait will stop all running things and wait for the stop
to complete.
*/
/*------------------------------------------------------------------------*/
void ClearExecutor(pExeList self);
/*
clears the executor without sending commands to the devices.
*/
/*-----------------------------------------------------------------------*/
int IsCounting(pExeList self);
int PauseExecution(pExeList self);
int ContinueExecution(pExeList self);
#line 248 "devexec.w"
/*-------------------------- Commands ------------------------------------*/
int StopCommand(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
/*
implements the stop command
*/
int ListExe(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
/*
lists all currently executing objects
*/
int Success(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
/*
waits until completion of all pending operations. Used in
connection with non blocking operation such as motors started
with run.
*/
/* -------------------------- Executor management -------------------------*/
pExeList GetExecutor(void);
void SetExecutor(pExeList pExe);
#endif

322
devexec.tex Normal file
View File

@ -0,0 +1,322 @@
\subsection{The Device Executor}
The Device Executor (devexec) is a core component of the system. It has to
fulfill three main tasks:
\begin{itemize}
\item Permit non--blocking hardware operations.
\item Ensure regular monitoring of running devices.
\item Ensure that only one client controls the hardware.
\end{itemize}
The devexec in its current form monitors driving and counting
operations only. The emonitor implements another monitor for
environment controllers.
Please note, that this module is quite crucial for the functioning of
SICS. Any changes here may have side effects throughout the whole
system. Be VERY careful with any changes. The current version does its job!
Some users want to continue typing commands while some hardware device is
still running. This is sensible, because some hardware devices require a
lot of time before they run to completion. Some people also require to count
while driving motors for quick overview measurements. This requirement was
the main reason for the invention of the devexec.
Of course, when devices are in operation it is needed to check on them
regularly in order to catch and report error conditions and in order to
find out when devices are finished with their job.
In a client server system many clients might issue commands to the hardware.
This could quickly lead into an undesirable form of chaos (There are
desirable forms of chaos, but not here!). In order to prevent this a means
is needed to ensure that at any given time only one client controls the
hardware. This function is also performed by the devexec.
The device executor also has to take care of special error conditions.
\subsubsection{Starting Devices}
These are the most important SICS operations. Environment controllers are
monitored by the environment monitor. Then here is a convention: {\bf Any
SICS object which
initiates driving or counting operations has to do so by registering this
operation with the devexec}. For this purpose the following interface
functions are provided.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$devreg {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ int StartDevice(pExeList self, char *name, pObjectDescriptor pDes,@\\
\mbox{}\verb@ void *pData, SConnection *pCon, float fNew);@\\
\mbox{}\verb@ int StartMotor(pExeList self, SicsInterp *pSics, SConnection *pCon,@\\
\mbox{}\verb@ char *name, float fNew);@\\
\mbox{}\verb@ int StartCounter(pExeList self, SicsInterp *pSics, SConnection *pCon,@\\
\mbox{}\verb@ char *name); @\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
The main interface function is {\bf StartDevice}. The parameters are:
\begin{itemize}
\item {\bf self}. A pointer to the device executor in which SICS operates.
\item {\bf name}. The name of the object which operates.
\item {\bf pDes}. A pointer to the ObjectDescriptor of the object to drive or count.
\item {\bf pData}. A pointer to the data structure coming with the object.
\item {\bf pCon}. A pointer to the client connection on whose request the
operation was initiated.
\item {\bf fNew}. A floating point value which sets the target value for
drivable devices.
\end{itemize}
{\bf StartMotor, StartCounter} are just convenience wrappers around
StartDevice which retrieve objects from the SICS interpreter and calls
StartDevice thereafter.
Once invoked StartDevice takes care of the following operations:
\begin{itemize}
\item It first checks on the connection object. If nobody else is running
hardware it enters the connection object specifed as owner of the devexec in
its data structure. If an owner was already specified by a prior drive or
count request StartDevice checks if the connection requesting the new
operation is the same. If this is not the case, an error message about this
situation will be issued. If it is the case, i. e. the client requesting the
new operation is the same as the one who has reserved the devexec, the
operation is performed. This scheme reserves the devexec to one client.
\item If the authorisation is OK, StartDevice then proceeds to start the
drive or counting operation.
\item StartDevice then enters all information regarding
the running device into an list for future monitoring.
\item If it not already running a DevExecTask is registered with the
task module in order to ensure the monitoring of the devices running.
\end{itemize}
\subsubsection{Monitoring devices}
From within the SICS main loops this special function is called:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$devcheck {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ int CheckExeList(pExeList self);@\\
\mbox{}\verb@ /*@\\
\mbox{}\verb@ checks the entries for success and deletes entries which have finished@\\
\mbox{}\verb@ operation. If there are none left, the pOwner will be set to NULL.@\\
\mbox{}\verb@ */ @\\
\mbox{}\verb@ int Wait4Success(pExeList self);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ long GetDevexecID(pExeList self);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int DevExecTask(void *pEL);@\\
\mbox{}\verb@ void DevExecSignal(void *pEL, int iSignal, void *pSigData);@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
CheckExeList then scan through its list of executing objects and request a
status from each of them. The next action depend on the status returned from
the device and any pending interrupts:
\begin{itemize}
\item If the device is still busy and no interrupts are pending, nothing
happens.
\item If there is a hardware error, this will be reported and apropriate
actions are intitiated depending on the type of problem and possible
interrupts being sets.
\item If a device is done, either naturally or due to an error or interrupt,
it is removed from devexec's list.
\item If the list is empty, the owner field of the devexec's datastructure
is reset to NULL. Then a new client is free to grab control over the
hardware.
\end{itemize}
{\bf DevExecTask} is the task function for the device executor. Calls
CheckExeList in the end. If all devices registered with the devexec
are finished running this function returns 0 and thus stops.
{\bf DevExecSignal} is the signal function for the device executor task.
{\bf Wait4Success} This function waits for the DevExecTask to
end. This is the case when the current devices running are finished.
There are occasions in the program where it is needed to wait for
an operation to complete before other tasks can be tackled. Wait4Success is
the function to call in such cases. Wait4Success returns DEVDONE for a
properly finished operation, DEVERROR for an operation which finished
with an error code and DEVINT for an aoperation which was interrupted
by the user.
\subsubsection{Influencing Execution}
In certain cases it is necessary to interact with running devices directly.
This is done via the following interface.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
$\langle$devstop {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ int StopExe(pExeList self, char *name);@\\
\mbox{}\verb@ int StopExeWait(pExeList self);@\\
\mbox{}\verb@ /*@\\
\mbox{}\verb@ will stop the entry name and its subentries from executing.@\\
\mbox{}\verb@ If ALL is specified as name, everything will be stopped and@\\
\mbox{}\verb@ the Executor cleared.@\\
\mbox{}\verb@ StopExeWait will stop all running things and wait for the stop@\\
\mbox{}\verb@ to complete.@\\
\mbox{}\verb@ */@\\
\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
\mbox{}\verb@ void ClearExecutor(pExeList self);@\\
\mbox{}\verb@ /*@\\
\mbox{}\verb@ clears the executor without sending commands to the devices.@\\
\mbox{}\verb@ */@\\
\mbox{}\verb@/*-----------------------------------------------------------------------*/@\\
\mbox{}\verb@ int IsCounting(pExeList self);@\\
\mbox{}\verb@ int PauseExecution(pExeList self);@\\
\mbox{}\verb@ int ContinueExecution(pExeList self);@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
{\bf StopExe} tackles the interrupting of pending operations. This may
happen on a users request. StopExe then invokes a halt on that device.
As parameters, the name of a device to stop can be specified. If ALL is
given as name to StopExe all executing devices are stopped. Please note, that
this stop does not automatically finish the operation. Motors need some time
to stop, too. This function is usally called as consequence of an
interrupt.
{\bf ClearExecutor} clears the executor without invoking commands on the
devices. Is probably only used internally to clean out the executor.
I some cases, for example if a environment controller gets out of range, an
error handling strategy may want to pause counting until the problem has
been rectified and continue afterwards. {\bf PauseExecution, ContinueExecution}
take care of invoking the apropriate commands on all registered counting
devices.
\subsubsection{The Rest}
The rest of the interface includes initialisation and deletion routines
and some access routines. With the devexec being such an important system
component a function {\bf GetExecutor} is provided which retrieves a pointer
to the global SICS device executor.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap4}
\verb@"devexec.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*----------------------------------------------------------------------------@\\
\mbox{}\verb@@\\
\mbox{}\verb@ D E V I C E E X E C U T O R@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Joachim Kohlbrecher wants to give several commands to the server@\\
\mbox{}\verb@ and than wait for them to happen before proceeding. Actually a useful@\\
\mbox{}\verb@ thing. A command will map to one or several positioning commands for a@\\
\mbox{}\verb@ device. This scheme is also useful for implementing objects which@\\
\mbox{}\verb@ drive several motors simulataneously, such as Monochromators. etc.@\\
\mbox{}\verb@ However, the whole thing is rather complicated.@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ It is forbidden, that several clients drive the instrument. In order@\\
\mbox{}\verb@ to ensure this the Executor remembers the connection which emitted the@\\
\mbox{}\verb@ first command. Subsequent AddExeEntries from different clients will@\\
\mbox{}\verb@ be rejected. The owner will be reset when the execution is found finished@\\
\mbox{}\verb@ in calls to CheckExe, Wait4Success or StopExe.@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ @\\
\mbox{}\verb@ Mark Koennecke, December 1996@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ copyright: see implementation file@\\
\mbox{}\verb@---------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSDEVEXEC@\\
\mbox{}\verb@#define SICSDEVEXEC@\\
\mbox{}\verb@#include "obdes.h"@\\
\mbox{}\verb@#include "task.h"@\\
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __EXELIST *pExeList;@\\
\mbox{}\verb@@\\
\mbox{}\verb@/* Returncodes */@\\
\mbox{}\verb@@\\
\mbox{}\verb@#define DEVDONE 1@\\
\mbox{}\verb@#define DEVINT 0@\\
\mbox{}\verb@#define DEVERROR 2@\\
\mbox{}\verb@#define DEVBUSY 3@\\
\mbox{}\verb@@\\
\mbox{}\verb@/*------------------------------------------------------------------------@\\
\mbox{}\verb@ B I R T H & D E A T H@\\
\mbox{}\verb@*/@\\
\mbox{}\verb@ pExeList CreateExeList(pTaskMan pTask);@\\
\mbox{}\verb@ void DeleteExeList(void *self);@\\
\mbox{}\verb@ @\\
\mbox{}\verb@/* ================= Functions to talk to the above ====================== */@\\
\mbox{}\verb@@$\langle$devreg {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
\mbox{}\verb@@$\langle$devcheck {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@ /*@\\
\mbox{}\verb@ Waits for execution to finish. returns 1 on Success, 0 if problems@\\
\mbox{}\verb@ ocurred. Than the Interrupt code shall be checked and acted upon@\\
\mbox{}\verb@ accordingly.@\\
\mbox{}\verb@ */@\\
\mbox{}\verb@@\\
\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
\mbox{}\verb@ SConnection *GetExeOwner(pExeList self);@\\
\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
\mbox{}\verb@ int isInRunMode(pExeList self);@\\
\mbox{}\verb@/*--------------------------------------------------------------------------*/@\\
\mbox{}\verb@ int ListPending(pExeList self, SConnection *pCon);@\\
\mbox{}\verb@ /*@\\
\mbox{}\verb@ lists the Operations still pending on pCon. @\\
\mbox{}\verb@ */@\\
\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
\mbox{}\verb@@$\langle$devstop {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@/*-------------------------- Commands ------------------------------------*/@\\
\mbox{}\verb@ int StopCommand(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ /*@\\
\mbox{}\verb@ implements the stop command@\\
\mbox{}\verb@ */@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ int ListExe(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ /*@\\
\mbox{}\verb@ lists all currently executing objects@\\
\mbox{}\verb@ */@\\
\mbox{}\verb@ int Success(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ /*@\\
\mbox{}\verb@ waits until completion of all pending operations. Used in@\\
\mbox{}\verb@ connection with non blocking operation such as motors started@\\
\mbox{}\verb@ with run.@\\
\mbox{}\verb@ */@\\
\mbox{}\verb@ @\\
\mbox{}\verb@/* -------------------------- Executor management -------------------------*/@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ pExeList GetExecutor(void);@\\
\mbox{}\verb@ void SetExecutor(pExeList pExe);@\\
\mbox{}\verb@ @\\
\mbox{}\verb@#endif @\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

282
devexec.w Normal file
View File

@ -0,0 +1,282 @@
\subsection{The Device Executor}
The Device Executor (devexec) is a core component of the system. It has to
fulfill three main tasks:
\begin{itemize}
\item Permit non--blocking hardware operations.
\item Ensure regular monitoring of running devices.
\item Ensure that only one client controls the hardware.
\end{itemize}
The devexec in its current form monitors driving and counting
operations only. The emonitor implements another monitor for
environment controllers.
Please note, that this module is quite crucial for the functioning of
SICS. Any changes here may have side effects throughout the whole
system. Be VERY careful with any changes. The current version does its job!
Some users want to continue typing commands while some hardware device is
still running. This is sensible, because some hardware devices require a
lot of time before they run to completion. Some people also require to count
while driving motors for quick overview measurements. This requirement was
the main reason for the invention of the devexec.
Of course, when devices are in operation it is needed to check on them
regularly in order to catch and report error conditions and in order to
find out when devices are finished with their job.
In a client server system many clients might issue commands to the hardware.
This could quickly lead into an undesirable form of chaos (There are
desirable forms of chaos, but not here!). In order to prevent this a means
is needed to ensure that at any given time only one client controls the
hardware. This function is also performed by the devexec.
The device executor also has to take care of special error conditions.
\subsubsection{Starting Devices}
These are the most important SICS operations. Environment controllers are
monitored by the environment monitor. Then here is a convention: {\bf Any
SICS object which
initiates driving or counting operations has to do so by registering this
operation with the devexec}. For this purpose the following interface
functions are provided.
@d devreg @{
int StartDevice(pExeList self, char *name, pObjectDescriptor pDes,
void *pData, SConnection *pCon, float fNew);
int StartMotor(pExeList self, SicsInterp *pSics, SConnection *pCon,
char *name, float fNew);
int StartCounter(pExeList self, SicsInterp *pSics, SConnection *pCon,
char *name);
@}
The main interface function is {\bf StartDevice}. The parameters are:
\begin{itemize}
\item {\bf self}. A pointer to the device executor in which SICS operates.
\item {\bf name}. The name of the object which operates.
\item {\bf pDes}. A pointer to the ObjectDescriptor of the object to drive or count.
\item {\bf pData}. A pointer to the data structure coming with the object.
\item {\bf pCon}. A pointer to the client connection on whose request the
operation was initiated.
\item {\bf fNew}. A floating point value which sets the target value for
drivable devices.
\end{itemize}
{\bf StartMotor, StartCounter} are just convenience wrappers around
StartDevice which retrieve objects from the SICS interpreter and calls
StartDevice thereafter.
Once invoked StartDevice takes care of the following operations:
\begin{itemize}
\item It first checks on the connection object. If nobody else is running
hardware it enters the connection object specifed as owner of the devexec in
its data structure. If an owner was already specified by a prior drive or
count request StartDevice checks if the connection requesting the new
operation is the same. If this is not the case, an error message about this
situation will be issued. If it is the case, i. e. the client requesting the
new operation is the same as the one who has reserved the devexec, the
operation is performed. This scheme reserves the devexec to one client.
\item If the authorisation is OK, StartDevice then proceeds to start the
drive or counting operation.
\item StartDevice then enters all information regarding
the running device into an list for future monitoring.
\item If it not already running a DevExecTask is registered with the
task module in order to ensure the monitoring of the devices running.
\end{itemize}
\subsubsection{Monitoring devices}
From within the SICS main loops this special function is called:
@d devcheck @{
int CheckExeList(pExeList self);
/*
checks the entries for success and deletes entries which have finished
operation. If there are none left, the pOwner will be set to NULL.
*/
int Wait4Success(pExeList self);
long GetDevexecID(pExeList self);
int DevExecTask(void *pEL);
void DevExecSignal(void *pEL, int iSignal, void *pSigData);
@}
CheckExeList then scan through its list of executing objects and request a
status from each of them. The next action depend on the status returned from
the device and any pending interrupts:
\begin{itemize}
\item If the device is still busy and no interrupts are pending, nothing
happens.
\item If there is a hardware error, this will be reported and apropriate
actions are intitiated depending on the type of problem and possible
interrupts being sets.
\item If a device is done, either naturally or due to an error or interrupt,
it is removed from devexec's list.
\item If the list is empty, the owner field of the devexec's datastructure
is reset to NULL. Then a new client is free to grab control over the
hardware.
\end{itemize}
{\bf DevExecTask} is the task function for the device executor. Calls
CheckExeList in the end. If all devices registered with the devexec
are finished running this function returns 0 and thus stops.
{\bf DevExecSignal} is the signal function for the device executor task.
{\bf Wait4Success} This function waits for the DevExecTask to
end. This is the case when the current devices running are finished.
There are occasions in the program where it is needed to wait for
an operation to complete before other tasks can be tackled. Wait4Success is
the function to call in such cases. Wait4Success returns DEVDONE for a
properly finished operation, DEVERROR for an operation which finished
with an error code and DEVINT for an aoperation which was interrupted
by the user.
\subsubsection{Influencing Execution}
In certain cases it is necessary to interact with running devices directly.
This is done via the following interface.
@d devstop @{
int StopExe(pExeList self, char *name);
int StopExeWait(pExeList self);
/*
will stop the entry name and its subentries from executing.
If ALL is specified as name, everything will be stopped and
the Executor cleared.
StopExeWait will stop all running things and wait for the stop
to complete.
*/
/*------------------------------------------------------------------------*/
void ClearExecutor(pExeList self);
/*
clears the executor without sending commands to the devices.
*/
/*-----------------------------------------------------------------------*/
int IsCounting(pExeList self);
int PauseExecution(pExeList self);
int ContinueExecution(pExeList self);
@}
{\bf StopExe} tackles the interrupting of pending operations. This may
happen on a users request. StopExe then invokes a halt on that device.
As parameters, the name of a device to stop can be specified. If ALL is
given as name to StopExe all executing devices are stopped. Please note, that
this stop does not automatically finish the operation. Motors need some time
to stop, too. This function is usally called as consequence of an
interrupt.
{\bf ClearExecutor} clears the executor without invoking commands on the
devices. Is probably only used internally to clean out the executor.
I some cases, for example if a environment controller gets out of range, an
error handling strategy may want to pause counting until the problem has
been rectified and continue afterwards. {\bf PauseExecution, ContinueExecution}
take care of invoking the apropriate commands on all registered counting
devices.
\subsubsection{The Rest}
The rest of the interface includes initialisation and deletion routines
and some access routines. With the devexec being such an important system
component a function {\bf GetExecutor} is provided which retrieves a pointer
to the global SICS device executor.
@o devexec.h -d @{
/*----------------------------------------------------------------------------
D E V I C E E X E C U T O R
Joachim Kohlbrecher wants to give several commands to the server
and than wait for them to happen before proceeding. Actually a useful
thing. A command will map to one or several positioning commands for a
device. This scheme is also useful for implementing objects which
drive several motors simulataneously, such as Monochromators. etc.
However, the whole thing is rather complicated.
It is forbidden, that several clients drive the instrument. In order
to ensure this the Executor remembers the connection which emitted the
first command. Subsequent AddExeEntries from different clients will
be rejected. The owner will be reset when the execution is found finished
in calls to CheckExe, Wait4Success or StopExe.
Mark Koennecke, December 1996
copyright: see implementation file
---------------------------------------------------------------------------*/
#ifndef SICSDEVEXEC
#define SICSDEVEXEC
#include "obdes.h"
#include "task.h"
typedef struct __EXELIST *pExeList;
/* Returncodes */
#define DEVDONE 1
#define DEVINT 0
#define DEVERROR 2
#define DEVBUSY 3
/*------------------------------------------------------------------------
B I R T H & D E A T H
*/
pExeList CreateExeList(pTaskMan pTask);
void DeleteExeList(void *self);
/* ================= Functions to talk to the above ====================== */
@<devreg@>
/*------------------------------------------------------------------------*/
@<devcheck@>
/*
Waits for execution to finish. returns 1 on Success, 0 if problems
ocurred. Than the Interrupt code shall be checked and acted upon
accordingly.
*/
/*-------------------------------------------------------------------------*/
SConnection *GetExeOwner(pExeList self);
/*-------------------------------------------------------------------------*/
int isInRunMode(pExeList self);
/*--------------------------------------------------------------------------*/
int ListPending(pExeList self, SConnection *pCon);
/*
lists the Operations still pending on pCon.
*/
/*-------------------------------------------------------------------------*/
@<devstop@>
/*-------------------------- Commands ------------------------------------*/
int StopCommand(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
/*
implements the stop command
*/
int ListExe(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
/*
lists all currently executing objects
*/
int Success(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
/*
waits until completion of all pending operations. Used in
connection with non blocking operation such as motors started
with run.
*/
/* -------------------------- Executor management -------------------------*/
pExeList GetExecutor(void);
void SetExecutor(pExeList pExe);
#endif
@}

81
dict.c Normal file
View File

@ -0,0 +1,81 @@
/*--------------------------------------------------------------------------
D I C T
This file exercises some of the NXDICT functionality for test purposes.
It can also serve as an example for the usage of the API.
Mark Koennecke, August 1997
Upgraded to support file idetification and text replacement
Mark Koennecke, April 1998
----------------------------------------------------------------------------*/
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <mfhdf.h>
#include "dynstring.h"
#include "napi.h"
#include "nxdict.h"
int main(int argc, char *argv[])
{
NXdict pDict = NULL;
NXhandle hfil;
void *pData = NULL;
float fTina[3] = { 0.123, 0.234, 0.456};
float fTest[3], fDelta;
float fTust[20*20];
char pBuffer[132];
int i;
/* test nxdict */
NXDinitfromfile("test.dict",&pDict);
NXopen("test.hdf",NXACC_CREATE,&hfil);
NXDadd(pDict,"Gundula",
"/entry1,NXentry/SphereOmeter,NXinstrument/SDS");
NXDupdate(pDict,"Bea","/entry1,NXentry/SDS");
NXDget(pDict,"Bea",pBuffer,131);
printf("Bea = %s\n",pBuffer);
NXDget(pDict,"Linda",pBuffer,131);
NXDopendef(hfil,pDict,pBuffer);
NXDputalias(hfil,pDict,"Tina",fTina);
NXDputalias(hfil,pDict,"Gina",fTina);
NXDgetalias(hfil,pDict,"Tina",fTest);
NXDgetalias(hfil,pDict,"Gina",fTest);
NXDputalias(hfil,pDict,"Linda",fTust);
NXDaliaslink(hfil,pDict,"Eva","Linda");
NXDclose(pDict,"close.dict");
NXclose(&hfil);
printf("NXDICT seemed to have worked \n");
/* test Utility functions */
printf(" Proceeding to test of utility functions \n");
NXopen("test2.hdf",NXACC_CREATE,&hfil);
NXUwriteglobals(hfil,
"test2.hdf",
"Willibald Wuergehals",
"Rue des Martyrs, 26505 Timbuktu, Legoland ",
"+41-56-3102512",
"Nobody@nowhere.edu",
" 755-898767",
"Dingsbums");
NXUentergroup(hfil, "TestGroup", "NXtest");
NXclosegroup(hfil);
NXUentergroup(hfil, "TestGroup", "NXtest");
i = 120;
NXUenterdata(hfil,"TestData",DFNT_INT8, 1,&i,"Testis");
NXclosedata(hfil);
NXUenterdata(hfil,"TestData",DFNT_INT8, 1,&i,"Testis");
NXUallocSDS(hfil,&pData);
NXUfreeSDS(&pData);
NXclose(&hfil);
printf("All tests seem to have worked OK, %s %s\n",
"but the test is pathetic\n",
"Do not rely, in any circumstances, on this test alone");
}

539
difrac.c Normal file
View File

@ -0,0 +1,539 @@
/*-------------------------------------------------------------------------
D I F R A C
A four-circle diffractometer requires sophicticated procedures for
searching peaks, orienting crystals and for performing data collection.
Rather then invent all of this again the DIFRAC-F77 program written by
Peter White and Eric Gabe has been incoporated into SICS. This module
provides the C-language side of the interface between DIFRAC and SICS.
DIFRAC can only be included once into SICS, it is not possible to have
more then one copy of this. This is why there is file static global data
here.
copyright: see copyright.h
Mark Koennecke, November 1999
--------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <ctype.h>
#include "fortify.h"
#include "sics.h"
#include "motor.h"
#include "counter.h"
#include "status.h"
#include "splitter.h"
#include "difrac.h"
/*--------------------------------------------------------------------------
In order to deal with multiple request to the DIFRAC subsystem we need to
keep the connection objects on a stack. This stack is defined here.
---------------------------------------------------------------------------*/
#define MAXSTACK 50
static SConnection *ConStack[MAXSTACK];
static int iConStackPtr = -1;
/*--------------------------------------------------------------------------
In order to do the four circle work we need to know the motors of the
eulerian cradle and access to the counter. Furthermore we need to know
about the omega2theta motor and the scanning routine.
These data structures are initialized by the installation routine.
---------------------------------------------------------------------------*/
static pMotor pTTH, pOM, pCHI, pPHI;
static pCounter counter;
/*---------------------------------------------------------------------------
The following routines will be called from F77. Their names take care of the
system dependent name mangling scheme for calling C from F77. This may
need adjustment when porting to another system
---------------------------------------------------------------------------*/
/*========= read angles */
void sicsanget_(float *fTH, float *fOM, float *fCHI, float *fPHI)
{
int iRet;
/* this is just security, may never happen */
if(iConStackPtr < 0)
{
return;
}
if(ConStack[iConStackPtr] == NULL)
{
return;
}
iRet = MotorGetSoftPosition(pTTH,ConStack[iConStackPtr],fTH);
if(iRet != 1)
{
SCWrite(ConStack[iConStackPtr],
"ERROR: failed to read two theta, DIFRAC may be confused now",
eError);
}
iRet = MotorGetSoftPosition(pOM,ConStack[iConStackPtr],fOM);
if(iRet != 1)
{
SCWrite(ConStack[iConStackPtr],
"ERROR: failed to read omega, DIFRAC may be confused now",
eError);
}
iRet = MotorGetSoftPosition(pCHI,ConStack[iConStackPtr],fCHI);
if(iRet != 1)
{
SCWrite(ConStack[iConStackPtr],
"ERROR: failed to read chi, DIFRAC may be confused now",
eError);
}
iRet = MotorGetSoftPosition(pPHI,ConStack[iConStackPtr],fPHI);
if(iRet != 1)
{
SCWrite(ConStack[iConStackPtr],
"ERROR: failed to read two theta, DIFRAC may be confused now",
eError);
}
}
#define ABS(x) (x < 0 ? -(x) : (x))
/*=========== check angles */
void sicsangcheck_(float *fTH, float *fOM, float *fCHI, float *fPHI,
int *iInvalid)
{
int iRet;
SConnection *pCon = NULL;
float fHard;
char pBueffel[256], pError[131];
/* this is just security, may never happen */
if(iConStackPtr < 0)
{
return;
}
if(ConStack[iConStackPtr] == NULL)
{
return;
}
pCon = ConStack[iConStackPtr];
*iInvalid = 0;
iRet = MotorCheckBoundary(pTTH,*fTH,&fHard,pError,131);
if(iRet != 1)
{
sprintf(pBueffel,
"ERROR: %6.2f %6.2f %6.2f %6.2f violates twotheta limits",
*fTH, *fOM, *fCHI, *fPHI);
SCWrite(pCon,pBueffel,eError);
*iInvalid = 4;
return;
}
iRet = MotorCheckBoundary(pOM,*fOM,&fHard,pError,131);
if(iRet != 1)
{
sprintf(pBueffel,
"ERROR: %6.2f %6.2f %6.2f %6.2f violates omega limits",
*fTH, *fOM, *fCHI, *fPHI);
SCWrite(pCon,pBueffel,eError);
*iInvalid = 4;
return;
}
iRet = MotorCheckBoundary(pCHI,*fCHI,&fHard,pError,131);
if(iRet != 1)
{
sprintf(pBueffel,
"ERROR: %6.2f %6.2f %6.2f %6.2f violates chi limits",
*fTH, *fOM, *fCHI, *fPHI);
SCWrite(pCon,pBueffel,eError);
*iInvalid = 4;
return;
}
iRet = MotorCheckBoundary(pPHI,*fPHI,&fHard,pError,131);
if(iRet != 1)
{
sprintf(pBueffel,
"ERROR: %6.2f %6.2f %6.2f %6.2f violates phi limits",
*fTH, *fOM, *fCHI, *fPHI);
SCWrite(pCon,pBueffel,eError);
*iInvalid = 4;
return;
}
}
/*======== set angles */
void sicsangset_(float *fTTH, float *fOM, float *fCHI, float *fPHI,
int *icol)
{
pDummy pDum;
int iRet;
SConnection *pCon = NULL;
float fT1, fT2, fT3, fT4;
*icol = 0;
/* this is just security, may never happen */
if(iConStackPtr < 0)
{
return;
}
if(ConStack[iConStackPtr] == NULL)
{
return;
}
pCon = ConStack[iConStackPtr];
/* check if this is possible, if not complain */
sicsangcheck_(fTTH, fOM,fCHI,fPHI, &iRet);
if(iRet >= 4)
{
*icol = 1;
return;
}
/* start */
pDum = (pDummy)pTTH;
iRet = StartDevice(pServ->pExecutor, "TTH",
pDum->pDescriptor, pDum,pCon, *fTTH);
if(!iRet)
{
SCWrite(pCon,"ERROR: cannot start two theta motor",eError);
StopExe(pServ->pExecutor,"all");
*icol = 10;
}
pDum = (pDummy)pOM;
iRet = StartDevice(pServ->pExecutor, "OM",
pDum->pDescriptor, pDum,pCon, *fOM);
if(!iRet)
{
SCWrite(pCon,"ERROR: cannot start omega motor",eError);
StopExe(pServ->pExecutor,"all");
*icol = 10;
}
pDum = (pDummy)pCHI;
iRet = StartDevice(pServ->pExecutor, "CHI",
pDum->pDescriptor, pDum,pCon, *fCHI);
if(!iRet)
{
SCWrite(pCon,"ERROR: cannot start chi motor",eError);
StopExe(pServ->pExecutor,"all");
*icol = 10;
}
pDum = (pDummy)pPHI;
iRet = StartDevice(pServ->pExecutor, "PHI",
pDum->pDescriptor, pDum,pCon, *fPHI);
if(!iRet)
{
SCWrite(pCon,"ERROR: cannot start two theta motor",eError);
StopExe(pServ->pExecutor,"all");
*icol = 10;
}
/* wait for end of it */
iRet = Wait4Success(pServ->pExecutor);
switch(iRet)
{
case DEVINT:
if(SCGetInterrupt(pCon) == eAbortOperation)
{
SCSetInterrupt(pCon,eContinue);
SCSetError(pCon,OKOK);
}
break;
case DEVDONE:
break;
default:
break;
}
/*
As TRICS has such a shitty cradle check angles and report error
if bad
*/
sicsanget_(&fT1, &fT2, &fT3, &fT4);
if(ABS(fT1 - *fTTH) > .2)
{
*icol = 10;
}
if(ABS(fT2 - *fOM) > .2)
{
*icol = 10;
}
if(ABS(fT3 - *fCHI) > .2)
{
*icol = 10;
}
if(ABS(fT4 - *fPHI) > .2)
{
*icol = 10;
}
}
/*=========== count */
void sicscount_(float *fPreset, float *fCounts)
{
pDummy pDum;
int iRet;
SConnection *pCon = NULL;
long lTask;
/* this is just security, may never happen */
if(iConStackPtr < 0)
{
return;
}
if(ConStack[iConStackPtr] == NULL)
{
return;
}
pCon = ConStack[iConStackPtr];
pDum = (pDummy)counter;
SetCounterPreset(counter,*fPreset);
iRet = StartDevice(pServ->pExecutor,
"DifracCount",
pDum->pDescriptor,
counter,
pCon,
*fPreset);
if(!iRet)
{
SCWrite(pCon,"ERROR: Failed to start counting ",eError);
return;
}
SetStatus(eCounting);
/* wait for finish */
lTask = GetDevexecID(pServ->pExecutor);
if(lTask > 0);
{
TaskWait(pServ->pTasker,lTask);
}
*fCounts = (float)GetCounts(counter,pCon);
}
/*========= sicswrite */
void sicswrite_(int *iText, int *iLen)
{
SConnection *pCon = NULL;
char pBueffel[256];
int i;
if(*iLen > 255)
return;
for(i = 0; i < *iLen; i++)
{
pBueffel[i] = (char)iText[i];
}
pBueffel[i] = '\0';
/* this is just security, may never happen */
if(iConStackPtr < 0)
{
puts(pBueffel);
return;
}
if(ConStack[iConStackPtr] == NULL)
{
puts(pBueffel);
return;
}
pCon = ConStack[iConStackPtr];
SCWrite(pCon,pBueffel,eValue);
}
/*========== sicsgetline */
void sicsgetline_(int *iText, int *iLen)
{
SConnection *pCon = NULL;
char pBueffel[256];
int i, iRet;
/* this is just security, may never happen */
if(iConStackPtr < 0)
{
return;
}
if(ConStack[iConStackPtr] == NULL)
{
return;
}
pCon = ConStack[iConStackPtr];
iRet = SCPrompt(pCon,"Enter data please >>" , pBueffel, 255);
/* difrac cannot handle an interrupted input operation */
if(iRet == 0)
{
SCSetInterrupt(pCon,eContinue);
}
for(i = 0; i < strlen(pBueffel); i++)
{
iText[i] = (int)pBueffel[i];
}
*iLen = strlen(pBueffel);
}
/*============= checkint */
void checkint_(int *iK)
{
SConnection *pCon = NULL;
char pBueffel[256];
int i;
/* this is just security, may never happen */
if(iConStackPtr < 0)
{
*iK = 0;
return;
}
if(ConStack[iConStackPtr] == NULL)
{
return;
}
pCon = ConStack[iConStackPtr];
if(SCGetInterrupt(pCon) >= eAbortScan)
{
*iK = 0;
}
else
{
*iK = 1;
}
}
/*--------------------------------------------------------------------------
DifracAction is the interface routine between the SICS interpreter and
the DIFRAC subsystem. What it basically does is: pop the connection onto
the stack. Concatenate all pending command line data to a string. Then
call DIFRAC with this string as an parameter. On return, remove the
connection from the stack again and return.
-------------------------------------------------------------------------*/
/* some protoypes for things defined in F77 */
extern void difini_(void);
extern void difint_(int *iText, int *iLen);
int DifracAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
char pInput[256];
int iInput[256];
int iLen, i;
if(argc < 2)
{
SCWrite(pCon,"ERROR: dif expects at least one argument",eError);
return 0;
}
/* user privilege required */
if(!SCMatchRights(pCon,usUser))
{
return 0;
}
/* steal: redirect the I/O to me */
strcpy(pInput,argv[1]);
strtolower(pInput);
if(strcmp(pInput,"steal") == 0)
{
if(iConStackPtr >= 0)
{
ConStack[iConStackPtr] = pCon;
}
SCSendOK(pCon);
return 1;
}
iConStackPtr++;
ConStack[iConStackPtr] = pCon;
Arg2Text(argc-1, &argv[1],pInput,255);
iLen = strlen(pInput);
for(i = 0; i < iLen; i++)
{
iInput[i] = toupper((int)pInput[i]);
}
/* do difrac */
difint_(iInput, &iLen);
SCWrite(pCon,"Difrac subsystem finished",eWarning);
iConStackPtr--;
if(SCGetInterrupt(pCon) != eContinue)
{
return 0;
}
else
{
return 1;
}
}
/*-------------------- The initialization routine ----------------------*/
int MakeDifrac(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
CommandList *pCom = NULL;
pICountable pCts = NULL;
int iRet;
if(argc < 6)
{
SCWrite(pCon,
"ERROR: Insufficient number of arguments to MakeDifrac",eError);
return 0;
}
/* find motors */
pTTH = FindMotor(pSics,argv[1]);
if(!pTTH)
{
SCWrite(pCon,"ERROR: cannot find two theta motor",eError);
return 0;
}
pOM = FindMotor(pSics,argv[2]);
if(!pOM)
{
SCWrite(pCon,"ERROR: cannot find omega motor",eError);
return 0;
}
pCHI = FindMotor(pSics,argv[3]);
if(!pTTH)
{
SCWrite(pCon,"ERROR: cannot find chi motor",eError);
return 0;
}
pPHI = FindMotor(pSics,argv[4]);
if(!pTTH)
{
SCWrite(pCon,"ERROR: cannot find phi motor",eError);
return 0;
}
/* locate counter */
pCom = FindCommand(pSics,argv[5]);
if(pCom == NULL)
{
SCWrite(pCon,"ERROR: counter not found in MakeDifrac",
eError);
return 0;
}
pCts = GetCountableInterface(pCom->pData);
if(!pCts)
{
SCWrite(pCon,"ERROR: argument to MakeDifrac is no counter",
eError);
return 0;
}
counter = (pCounter)pCom->pData;
/* initialize difrac */
difini_();
/* install command */
iRet = AddCommand(pSics,
"dif",
DifracAction,
NULL,
NULL);
if(!iRet)
{
SCWrite(pCon,"ERROR: duplicate command dif NOT created",
eError);
}
return iRet;
}

14
difrac.h Normal file
View File

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

728
difrac/CAD4COMM Normal file
View File

@ -0,0 +1,728 @@
*$noreference
!
! This is the common block for CAD4
! VAX/VMS to PDP11/02 transfer program.
!
! modified: 03-jan-1985 LCB adaption for SBC-21 target processor
!
! Logical assignments used in CAD4 system
!
! CAn_term device name of communication channel with lsi-11
! LB0 default device for [1,3n]GONCAn.DAT;1 data files
! cad4$nrcsys default directory specification for .EXE
! cad4$error default task error device
!
! Assumed process name CAD4?_CAn
!
!
! Filename of GONCAn.DAT file
!
character*22 def_gon_spec
parameter (def_gon_spec='LB0:[1,40]GONCAn.DAT;1')
character*18 gon_file_spec
!
! Filename of monitor task image
!
character*21 def_mon_spec
parameter (def_mon_spec='CAD4M.TSK')
character*22 mon_file_spec
!
! Default mother task image name
!
character*18 def_mother_spec
parameter (def_mother_spec='nrccad')
!
! Input filenames
!
character*63 mother_file_spec
character*63 daughter_file_spec
!
! Test send message definitions
!
character*120 message_text
integer*1 message_buffer
integer*4 message_descr
dimension message_buffer(128),message_descr(2)
equivalence (message_buffer(9),message_text)
!
parameter (l_unit=6 ) ! Logical unit number for log file
logical*1 l_unit_open ! True if file open
!
! Define QIO function codes and modifiers
!
external tt$v_eightbit,tt$v_noecho,tt$v_passall
external tt$v_nobrdcst,tt$v_escape,tt$v_hostsync
external tt$v_ttsync,tt$v_readsync,tt$v_halfdup
external io$_setmode,io$_ttyreadpall,io$_writelblk
external io$_ttyreadall,io$m_timed,io$m_noecho
external io$m_noformat,io$m_purge
!
! Define QIO status codes
!
integer*4 ss$_normal,ss$_badchksum,ss$_bufferovf
integer*4 ss$_abort,ss$_timeout,ss$_nodata
!
parameter (ss$_normal = #1) ! Normal return
parameter (ss$_timeout = #22c) ! Timeout
!
! Internal status codes returned in one byte
!
integer*2 result,e_suc,e_tos,e_tol,e_seq
integer*2 e_crc,e_typ,e_ovf,e_pnd
!
parameter (e_suc = #0) ! success
parameter (e_tos = #4) ! tmo + data
parameter (e_tol = #8) ! tmo , no data
parameter (e_seq = #c) ! Unexpected sequence number
parameter (e_crc = #10) ! CRC error
parameter (e_typ = #14) ! Unexpected function code
parameter (e_ovf = #18) ! Buffer overflow
parameter (e_pnd = #1c) ! Any system service fail.
!
integer*2 m_seq,m_efl,m_fun
!
parameter (m_seq = #3) ! Mask to get seq. bits
parameter (m_efl = #1c) ! Mask to get error flag
parameter (m_fun = #e0) ! Mask to get function bits
!
! Function codes for CAD4_IO routine
!
integer*2 io_func,f_init,f_xfr_asc,f_xfr_mem,f_tr_swr
integer*2 f_tr_gon,f_tr_asc,f_req_mem,f_req_asc
!
parameter (f_init = #0) ! Bootstrap 11/02
parameter (f_xfr_asc = #20) ! Xfr ASCII buffer to 11/02
parameter (f_xfr_mem = #40) ! Xfr code block to 11/02
parameter (f_tr_swr = #60) ! Trm. and rec. SWR
parameter (f_tr_gon = #ff80) ! Trm. and rec. goniometer data
parameter (f_tr_asc = #ffa0) ! Trm. and rec. ASCII buffer
parameter (f_req_mem = #ffc0) ! Request code block from 11/02
parameter (f_req_asc = #ffe0) ! Request ASCII buffer from 11/02
!
! Data used by CAD4_IO routine
!
integer*2 io_coswr ! Switch options register from vax to 11/02
integer*2 io_cobnr ! No. of calls to 11/02
integer*1 io_cohex ! Header from VAX to 11/02
! bit 0-1 : seq. no. of the calls to 11/02
! bit 2-4 : result code
! bit 5-7 : function
!
! Flags to define command string options
! 0 - no option
! -1 - negated option
! +1 - positive option
!
integer*1 mt_flag,ex_flag
!
! Flag for cad4_prompt routine
! 0 - no error message
! 1 - command input error
! -1 - daughter file cannot be opened
! -2 - " " " " read
!
integer*1 io_prompt_flag
!
! Define baud rate constants for CAD4 terminal
!
integer*2 baud_38400,baud_19200,baud_9600,baud_4800
integer*2 baud_2400,baud_1200,baud_600,baud_300
!
parameter (baud_38400 = 3)
parameter (baud_19200 = 2*baud_38400)
parameter (baud_9600 = 2*baud_19200)
parameter (baud_4800 = 2*baud_9600)
parameter (baud_2400 = 2*baud_4800)
parameter (baud_1200 = 2*baud_2400)
parameter (baud_600 = 2*baud_1200)
parameter (baud_300 = 2*baud_600)
!
! Default goniometer parameter (goncan.dat record 8)
! system constants as will be expected at bottom of LSI target computer
!
integer*2 lsi_bottom ! LSI memory size (bytes)
parameter (lsi_bottom=#8000)
integer*2 sbc_bottom ! SBC user memory bottom
parameter (sbc_bottom=#ec00)
integer*2 lsypar ! value of LSI syspar address
integer*2 sbcp_bottom ! SBC PLUS memory bottom
parameter (sbcp_bottom=#7F80)
!
integer*2 syspar_def_1,syspar_def_2,syspar_def_3
integer*2 syspar_def_4,syspar_def_5,syspar_def_6
integer*2 syspar_def_7,syspar_def_8,syspar_def_9
integer*2 syspar_def_10,syspar_def_11,syspar_def_12
integer*2 syspar_def_13,syspar_def_14,syspar_def_15
integer*2 syspar_def_16,syspar_def_17
!
parameter (syspar_def_1 = #ff-((640-255)/3) )
! Photomultiplier hv setting of 640 volts
parameter (syspar_def_2 = #ff-(120/5) )
! Lower level setting of 120
parameter (syspar_def_3 = #ff-(750/5) )
! Discrimination window setting
parameter (syspar_def_4 = 0)
parameter (syspar_def_5 = 0)
! Deadtime correction factor (default 0, I*4)
parameter (syspar_def_6 = baud_300.and.#ff)
! CAD4 terminal baudrate setting of ...
parameter (syspar_def_7 = baud_300/#100)
! 300 baud default
parameter (syspar_def_8 = 0)
parameter (syspar_def_9 = 18)
! System clock speed default = 400 cycles/sec.
parameter (syspar_def_10 = 2)
! Default positioning accuracy is 2 steps
!
!
! common for load syspar data
!
integer*2 slave_load_address !address to load syspar in lsi
integer*2 nr_load_byte !number of bytes to load
!
character*1 bvers_c
integer*1 bvers !bootstrap version character if not 0
equivalence (bvers,bvers_c(1:1))
!
!
! 5 Axes gain list
!
! output = calculated value*(32.-gain)/32.
!
parameter (syspar_def_11 = 24) ! Theta motorgain
parameter (syspar_def_12 = 28) ! Phi motorgain
parameter (syspar_def_13 = 24) ! Omega motorgain
parameter (syspar_def_14 = 24) ! Kappa motorgain
parameter (syspar_def_15 = 24) ! Dial motorgain
!
! System flag word
!
! 1 - High voltage sense
! 4 - Switch limit for phi: present = set
! 10 - Special collar: present = set
! 20 - Cryostat: present = set
!
parameter (syspar_def_16 = 0) ! System flag word
!
parameter (syspar_def_17 = (60-10)*3/10 )
! Maximum emission allowed of 60 mA
!
integer*2 syspar_def
dimension syspar_def(32)
!
! Define syspar values as read from goncan.dat file
!
integer*2 syspar_val
dimension syspar_val(32)
!
! Define code for $getdvi system service
!
integer*4 dvi$_devdepend,dvi$_devdepend2
integer*4 dvi$_devclass,dvi$_devtype
parameter (dvi$_devclass = #00000004)
parameter (dvi$_devdepend = #0000000A)
parameter (dvi$_devdepend2= #0000001C)
parameter (dvi$_devtype = #00000006)
!
! Define system services as integer*4 to allow function call
!
integer*4 io_status ! I/O status code
integer*4 exmess_status !i/o status code memory for exit
integer*4 cli$present,cli$get_value,sys$exit,sys$alloc
integer*4 sys$assign,sys$qiow,sys$getdvi,sys$dclexh,sys$sndopr
integer*4 sys$setprn,sys$getjpi,sys$creprc,sys$getmsg
!
! Cad4 buffer format
!
! 15 0
! +-----------------------+
! + header byte +
! +------------------------------------------------+
! + length(high byte) + length (low byte) +
! +------------------------------------------------+
! ! switch register word or load address +
! +------------------------------------------------+
! ! switch register word or load address +
! +------------------------------------------------+
! ! !
! ! ... !
!
! ! 256 words data (512. bytes) !
! +------------------------------------------------+
! + CRC (16. bit) +
! +------------------------------------------------+
!
!
! Define argumensts for cad4_readprompt routine
!
integer*1 prompt_buffer ! Buffer to save prompt
dimension prompt_buffer(521) ! send to pdp11/02
integer*1 output_buffer ! Same as Output buffer
dimension output_buffer(521) ! for cad4_writelogical
equivalence (prompt_buffer(1),output_buffer(1))
character*521 output_buffer_c ! Allow use of ICHAR function
equivalence (prompt_buffer(1),output_buffer_c)
!
integer*4 prompt_size ! Size of prompt (for QIO)
integer*4 output_size ! "
equivalence (prompt_size,output_size)
!
integer*1 input_buffer ! Input buffer to read record
dimension input_buffer(521)
integer*4 input_size ! Size of input buff for Qio
character*521 input_buffer_c ! Allow use of ICHAR function
equivalence (input_buffer(1),input_buffer_c)
!
! Buffer for input and output are the same
!
equivalence (input_buffer(1),output_buffer(1))
!
! Define structure of I/O blocks
!
integer*1 prompt_header ! Header byte of output block
integer*1 output_header ! "
equivalence (prompt_buffer(1),prompt_header)
equivalence (prompt_buffer(1),output_header)
!
integer*2 prompt_length ! Length send to pdp11/02
integer*2 output_length ! "
equivalence (prompt_buffer(2),prompt_length)
equivalence (prompt_buffer(2),output_length)
!
integer*1 prompt_data ! Data bytes send to pdp11/02!
integer*1 output_data ! "
integer*2 output_data_w !
character*518 output_data_c !
dimension prompt_data(512+2+2+2)
dimension output_data(512+2+2+2)
dimension output_data_w((512+2+2+2)/2)
equivalence (prompt_buffer(4),output_data_c)
equivalence (prompt_buffer(4),prompt_data(1))
equivalence (prompt_buffer(4),output_data(1))
equivalence (prompt_buffer(4),output_data_w(1))
!
integer*1 input_header ! Header byte received from 11
equivalence (input_buffer(1),input_header)
!
integer*2 input_length ! Length received from pdp11/02
equivalence (input_buffer(2),input_length)
!
integer*1 input_data ! Data read from pdp11/02
integer*2 input_data_w !
dimension input_data(512+2+2+2)
dimension input_data_w((512+2+2+2)/2)
equivalence (input_buffer(4),input_data(1))
character*518 input_data_c !
equivalence (input_buffer(4),input_data_c)
equivalence (input_buffer(4),input_data_w)
!
! Define word to compute CRC
!
integer*4 iconst !crc-constant
parameter (iconst=#a001) ! value of constant
integer*4 crchar !crc-character
integer*4 isum !to remember received crc
integer*4 isum_w ! 16 bit CRC
integer*1 isum_b ! 8 bit (low&high 16 bit CRC)
dimension isum_b(2)
equivalence (isum_w,isum_b)
!
! Define item list for $getdvi system service
!
integer*4 item_list_i4 ! Item list for $getdvi
integer*2 item_list_i2 ! information
integer*1 item_list_i1
dimension item_list_i4(13) ! 4* 3 + 1 longword
dimension item_list_i2(13*2)
dimension item_list_i1(13*4)
equivalence (item_list_i4,item_list_i2)
equivalence (item_list_i4,item_list_i1)
!
! Define item list for $getjpi system service
!
integer*4 getjpi_list_l
integer*2 getjpi_list_w
dimension getjpi_list_l(13)
dimension getjpi_list_w(2*13)
equivalence (getjpi_list_l,getjpi_list_w)
!
! Define info var from $getjpi
!
character*15 process_name_c
integer*1 process_name_b
dimension process_name_b(15)
equivalence (process_name_c(1:1),process_name_b(1))
integer*2 process_name_len
!
integer*4 process_uic_l
integer*2 process_uic_w
dimension process_uic_w(2)
equivalence (process_uic_l,process_uic_w)
integer*2 process_uic_len
!
character*63 process_image_c
integer*1 process_image_b
dimension process_image_b(63)
equivalence (process_image_c(1:1),process_image_b(1))
integer*2 process_image_len
!
integer*4 process_prio_l
integer*2 process_prio_len
!
! Define buffer for io$_setmode QIO
!
integer*4 char_buff_i4 ! Item list for $getdvi
integer*2 char_buff_i2 ! information
integer*1 char_buff_i1
dimension char_buff_i4(3) ! Three longwords
dimension char_buff_i2(3*2)
dimension char_buff_i1(3*4)
equivalence (char_buff_i4,char_buff_i2)
equivalence (char_buff_i4,char_buff_i1)
!
! Define characteristics returned by $getdvi and used for
! $qiow (io$_setmode).
!
integer*4 cad4_devclass ! Device class
integer*4 cad4_devtype ! Device type
integer*4 cad4_devdepend ! Device characteristics
integer*4 cad4_devdepend2 !
integer*2 cad4_pagewidth ! Width of a page
integer*1 cad4_pagelength ! Length of a page
equivalence (char_buff_i1(1),cad4_devclass)
equivalence (char_buff_i1(2),cad4_devtype)
equivalence (char_buff_i2(2),cad4_pagewidth)
equivalence (char_buff_i4(2),cad4_devdepend)
equivalence (char_buff_i4(3),cad4_devdepend2)
equivalence (char_buff_i1(8),cad4_pagelength)
!
integer*4 cad4_devdepend_old ! Save old characteristics here
!
!
! Define arguments for QIOW system service to cad4
!
integer*4 qio_status ! Qio status code
integer*2 cad4_chan ! Channel number
integer*4 cad4_event_flag ! Event flag number
parameter (cad4_event_flag=8) !
integer*4 cad4_iosb ! I/O status
integer*2 cad4_iosb_i2 ! words
dimension cad4_iosb(2) ! quadword
dimension cad4_iosb_i2(4)
equivalence (cad4_iosb,cad4_iosb_i2)
integer*4 cad4_l_timo ! Long time out count
parameter (cad4_l_timo=25) ! 25 seconds
integer*4 cad4_timeout ! Short timeout count
parameter (cad4_timeout=2) ! Two seconds
integer*4 cad4_terminator ! Line terminator bit mask
dimension cad4_terminator(2) ! quadword (short form)
!
! Define argument block for declare exit handler directive
!
integer*4 exit_block ! Exit handler control block
dimension exit_block(4)
integer*4 exit_status
!
! Define parameters for $assign system service
!
character*10 cad4_term_name ! Physical name of transfer
! terminal
integer*4 cad4_term_len ! Length of physical
! name string
!
! Variable to save instrument name
!
! ibycan_b 1. byte : integer CA?: unit number
! 2.-4. byte : ASCII device name ('CAn')
!
integer*1 ibycan_b
dimension ibycan_b(4)
integer*2 ibycan
dimension ibycan(2)
character*4 ibycan_c
equivalence (ibycan_b(1),ibycan_c(1:1))
equivalence (ibycan_b(1),ibycan(1))
integer*2 ir5can !radix-50 name of channel for RSX
!
! Variable to save current process name name and uic
!
! Common block for all I/O routines
!
integer*4 img_io_record ! Record no. of task image
integer*4 img_io_status ! FORTRAN I/O status code
!
! Define file I/O buffer
!
integer*4 img_io_buffer_l
integer*2 img_io_buffer_w
integer*1 img_io_buffer_b
dimension img_io_buffer_l(128),img_io_buffer_w(256)
equivalence (img_io_buffer_l,img_io_buffer_w)
equivalence (img_io_buffer_l,img_io_buffer_b)
!
! Define read bookkeeping
!
integer*2 img_io_bsa ! Base address (bytes)
integer*2 img_io_ldz ! Load size (32. word blocks)
integer*2 img_io_xfr ! Transfer address
integer*4 img_io_pointer ! Pointer
!
!
! common declaration for blank common block
integer*2 nswreg !slave switch register
integer*2 iroutf !routine flag
integer*2 incr1 !master increment
integer*2 incr2 !slave increment
integer*2 npi1 !inverse of scanspeed for master
integer*2 npi2 !relative scanspeed for slave
integer*2 iscanw !scanwidth tensor
integer*2 motw !motor selection word
integer*2 ishutf !shutter flag
integer*2 ibalf !balance filter flag
integer*2 iattf !attenuator filter flag
integer*2 iresf !reserve flag
integer*2 ierrf !result error flag
integer*2 intfl !intensity result flag
real*4 xrayt !x-ray time
real*4 tthp !limit value for detector
real*4 tthn !limit value for neg side
real*4 aptw !wanted encoder value for aperture
real*4 want !wanted values for gonio-angles
real*4 spare !spare locs
real*4 aptm !measured encoder value of aperture
real*4 cmeas !measured gonio angles
real*4 dump !intensity dumps
!
! cad4-handler offsets
!
integer*2 c4h_swreg
integer*2 c4h_routfl
integer*2 c4h_errfl
integer*2 c4h_intfl
integer*2 c4h_tthmxh
integer*2 c4h_tthmnh
integer*2 c4h_sasysc
integer*2 c4h_xrtim
integer*2 c4h_mselw
integer*2 c4h_nrd
integer*2 c4h_nid
integer*2 c4h_incr
integer*2 c4h_inci
integer*2 c4h_dincr
integer*2 c4h_nrinc
integer*2 c4h_thwh
integer*2 c4h_phwh
integer*2 c4h_omwh
integer*2 c4h_kawh
integer*2 c4h_apwh
integer*2 c4h_apwl
integer*2 c4h_thmh
integer*2 c4h_phmh
integer*2 c4h_ommh
integer*2 c4h_kamh
integer*2 c4h_apmh
integer*2 c4h_dump0
!
parameter (c4h_swreg =1)
parameter (c4h_routfl =2)
parameter (c4h_errfl =3)
parameter (c4h_intfl =4)
parameter (c4h_tthmxh =5)
parameter (c4h_tthmnh =7)
parameter (c4h_sasysc =9)
parameter (c4h_xrtim =10)
parameter (c4h_mselw =12)
parameter (c4h_nrd =13)
parameter (c4h_nid =14)
parameter (c4h_incr =12)
parameter (c4h_inci =0)
parameter (c4h_dincr =1)
parameter (c4h_nrinc =2)
parameter (c4h_thwh =30)
parameter (c4h_phwh =32)
parameter (c4h_omwh =34)
parameter (c4h_kawh =36)
parameter (c4h_apwh =38)
parameter (c4h_apwl =39)
parameter (c4h_thmh =40)
parameter (c4h_phmh =42)
parameter (c4h_ommh =44)
parameter (c4h_kamh =46)
parameter (c4h_apmh =48)
parameter (c4h_dump0 =50)
!
! c4h_routfl function table
!
integer*2 rf_swi
integer*2 rf_mea
integer*2 rf_col
integer*2 rf_poc
integer*2 rf_pos
integer*2 rf_pof
integer*2 rf_sap
integer*2 rf_sca
integer*2 rf_scd
integer*2 rf_res
integer*2 routbl(16)
!
parameter (rf_swi =#0)
parameter (rf_mea =#4)
parameter (rf_col =#8)
parameter (rf_poc =#10)
parameter (rf_pos =#20)
parameter (rf_pof =#40)
parameter (rf_sap =#80)
parameter (rf_sca =#100)
parameter (rf_scd =#200)
parameter (rf_res =#8000)
!
integer*2 rout0,rout1,rout2,rout3,rout4,rout5
integer*2 rout6,rout7,rout8,rout9,rout10,rout11
integer*2 rout12,rout13,rout14,rout15
!
parameter (rout0 = rf_swi+rf_res)
parameter (rout1 = rf_swi+rf_mea+rf_res)
parameter (rout2 = rf_swi+rf_col+rf_res)
parameter (rout3 = rf_swi+rf_pos+rf_res)
parameter (rout4 = rf_swi+rf_pof+rf_res)
parameter (rout5 = rf_swi+rf_poc+rf_pof+rf_res)
parameter (rout6 = rf_swi+rf_sca+rf_res)
parameter (rout7 = rf_swi+rf_sap+rf_sca+rf_res)
parameter (rout8 = rf_swi+rf_poc+rf_pof+rf_sap+rf_sca+rf_res)
parameter (rout9 = rf_swi+rf_scd+rf_res)
parameter (rout10= rf_swi+rf_sap+rf_scd+rf_res)
parameter (rout11= rf_swi+rf_poc+rf_pof+rf_sap+rf_scd+rf_res)
parameter (rout12= rf_swi+rf_poc+rf_res)
parameter (rout13= rf_swi+rf_sap+rf_res)
parameter (rout14= rf_swi+rf_res) !free
parameter (rout15= rf_swi+rf_res) !free
!
! cad4_handler error table
!
integer*2 errtbl(15)
!
! cad4_handler intensity error table
!
integer*2 inttbl(15)
!
!
! cad4-handler sasysc table
!
integer*2 sa_att
integer*2 sa_shu
!
parameter (sa_att = #4000)
parameter (sa_shu = #8000)
!
integer*2 satbl(4),sas0,sas1,sas2,sas3
!
parameter (sas0 = #0)
parameter (sas1 = sa_att)
parameter (sas2 = sa_shu)
parameter (sas3 = sa_att+sa_shu)
!
! fortran blank common array for angles
!
integer*2 for_ph
integer*2 for_om
integer*2 for_ka
integer*2 for_th
!
parameter (for_ph = 1)
parameter (for_om = 2)
parameter (for_ka = 3)
parameter (for_th = 4)
!
! number of dumps used
!
integer ndumps
!
common /cad4_main/nswreg ,iroutf ,incr1 ,incr2 ,npi1 ,
1 npi2 ,iscanw ,motw ,ishutf ,ibalf ,iattf ,
2 iresf ,ierrf ,intfl ,xrayt ,tthp ,tthn ,
3 aptw ,want(4) ,spare(6) ,aptm ,
4 cmeas(4),ndumps, dump(512)
!
!
! Common for cad4 ascii buffer in cad4b
!
integer*2 nr_ascii_byte !number of ascii in BUFA
character*1 bufa !ascii buffer
dimension bufa(134)
!
!
common /mesg/bufa !ascii buffer for cad4b
!
!
! Common blocks for integer and logical variables
!
common /cad4_integer/ io_status,cad4_term_len,
1 item_list_i4,char_buff_i4,cad4_devdepend_old,
2 exit_block,cad4_chan,cad4_iosb,qio_status,
3 cad4_terminator,isum_w,l_unit_open,
4 message_buffer,message_descr,
5 img_io_buffer_l,img_io_bsa,img_io_ldz,img_io_xfr,
6 img_io_record,img_io_pointer,img_io_status,
7 getjpi_list_l,process_name_b,process_uic_l,
8 process_image_b,process_name_len,process_uic_len,
9 process_image_len,process_prio_l,process_prio_len,
1 mt_flag,ex_flag,io_prompt_flag,syspar_def,
2 slave_load_address,nr_load_byte,nr_ascii_byte,
3 bvers
!
!
! Common block for transfer buffer
!
common /tbuf/output_size,output_buffer,input_size
!
!
! Common block for communication channel name and communication values
!
common /cacomm/ibycan,ir5can,lsypar,io_coswr,io_cobnr,
1 io_cohex
!
!
! Common block for syspar values (shadow of 11/02 lsi_bottom)
!
common /syspar/syspar_val
!
!
! Common block for character variables
!
common /cad4_character/ cad4_term_name,
1 mother_file_spec,daughter_file_spec,
2 gon_file_spec
!
common /cad4_sysval/ freq, ragmxt
!
! cad4-handler motor table
!
integer*2 mottbl(8) !no,ap,ph,om,ka,th,no,no
! !converted to
data mottbl /0,5,2,3,4,1,0,0/ !no,th,ph,om,ka,ap,no,no
!
data syspar_def /syspar_def_1,syspar_def_2,syspar_def_3,
1 syspar_def_4,syspar_def_5,syspar_def_6,
2 syspar_def_7,syspar_def_8,syspar_def_9,
3 syspar_def_10,syspar_def_11,syspar_def_12,
4 syspar_def_13,syspar_def_14,syspar_def_15,
5 syspar_def_16,syspar_def_17,15*0/
!
data routbl /rout0,rout1,rout2,rout3,
1 rout4,rout5,rout6,rout7,rout8,
2 rout9,rout10,rout11,rout12,rout13,
3 rout14,rout15/
!
data errtbl /1,2,3,4,5,5,5,0,0,0,0,0,0,0,0/
!
data inttbl /-1,1,0,0,0,0,0,0,0,0,0,0,0,0,0/
!
data satbl/sas0,sas1,sas2,sas3/
!
data ndumps /512/
!
!
!
*$reference

54
difrac/COMDIF Normal file
View File

@ -0,0 +1,54 @@
PARAMETER (NSIZE=200)
COMMON /DFMACH/ ISCDEF,ICDDEF,IDTDEF,IDODEF,IDCDEF,IFRDEF,NRC,
$ NATTEN,STEPDG,ICADSL,ICADSW
CHARACTER DFTYPE*5,DFMODL*5
COMMON /DFMACC/ DFTYPE,DFMODL
COMMON /ANGLE/ THETA,PHI,CHI,OMEGA,RTHETA,ROMEGA,RPHI,RCHI,
$ DTHETA,DOMEGA,DCHI,THEMAX,THEMIN,PSI,DPSI,PSIMAX,
$ PSIMIN,R(3,3),ROLD(3,3),IVALID,WAVE,IROT,DEG,DPHI
COMMON /REFLEC/ IH,IK,IL,IH0,IK0,IL0,IHMAX,IKMAX,ILMAX,NREF,
$ IOH(NSIZE),IOK(NSIZE),IOL(NSIZE),ITRUE
COMMON /SYMTRY/ NSYM,ICENT,LATCEN,LAUENO,NAXIS,
$ SGSYMB(10),JHKL(3,24),JRT(3,4,24)
COMMON /INTENS/ IHK(10),ILA(10),BCOUNT(10),BBGR1(10),BBGR2(10),
$ BTIME(10),BPSI(10),NREFB(10),PRESET,COUNT,BGRD1,
$ BGRD2,NATT,AS,BS,CS,PA,PM,QTIME,TMAX,AFRAC,
$ ATTEN(6)
COMMON /PROFL/ ACOUNT(10*NSIZE),D12,ILOW,IHIGH,IDEL,IWARN,SUM,
$ FRAC1,IPRFLG,IAUTO,STEPOF,FRAC,PJUNK(9)
COMMON /CUTOFF/ ISYS,SINABS(6),ILN,DELAY,STEP,IUPDWN,ISTOP,
$ CJUNK(8)
COMMON /CELL/ SR(3,3),SSG(3,3),GI(3,3),AP(3),APS(3),SANGS(3),
$ CANGS(3),SANG(3),CANG(3)
COMMON /SEGS/ IFSHKL(3,3),NDH(3,3),IHO(8),IKO(8),ILO(8),
$ IDH(8,3,3),ISEG,NCOND,ICOND(5),IHS(5),IKS(5),
$ ILS(5),IR(5),IS(5),NSEG,NMSEG,IND(3),NUMDH,NSET
COMMON /IODEVS/ ITP,ITR,LPT,LPTX,NB,NBLOCK,ISD,IID,
$ IBYLEN,IPR,NPR,IIP
COMMON /IOUASS/ IOUNIT(10)
CHARACTER*132 COUT(20)
COMMON /IOUASC/ COUT
COMMON /STAN/ NSTAN,NMSTAN,ISTAN,NN,IHSTAN(6),IKSTAN(6),
$ ILSTAN(6),NINTRR,NINTOR,IORNT,REOTOL,NREFOR
COMMON /FLAGS/ ITYPE,KQFLAG,KQFLG2,IBSECT,ISCAN,IPRVAL,IUMPTY
COMMON /TRANS/ BLINDR(3,3),TMATS(3,3,20),IFSYS(20),IFMODE(20),
$ NTMATS
COMMON /JUNKS/ JA(8),JB(8),JC(8),JMIN(8),JMAX(8)
COMMON /INFREE/ IFREE(20),RFREE(20),ICFLAG
CHARACTER OCHAR*100,KI*2,ANS*1
COMMON /FREECH/ OCHAR
COMMON /POINTR/ KI,ANS
CHARACTER IDNAME*40,DSNAME*40,DDNAME*40,STATUS*2,PRNAME*40
COMMON /FNAMES/ IDNAME,DSNAME,DDNAME,STATUS,PRNAME
COMMON /REGIST/ ISREG(10)
COMMON /SCRTCH/ SIGMA(7),SIGSQ(7),LAUE,NUMD,IAXIS
CHARACTER WIN1BF*80
COMMON /CWIND1/ WIN1BF(3)
COMMON /FWIND1/ IWNCUR
DIMENSION PROF(520),CUT(20)
EQUIVALENCE (ACOUNT(1),PROF(1)),(CUT(1),ISYS)
INTEGER XOPEN,XCLOSE,XMOVE,XDRAW,XCLEAR,XTEXT,XSCROL,XWIN,
$ XTDEL
PARAMETER (XOPEN = 1, XCLOSE = 2, XMOVE = 3, XDRAW = 4,
$ XCLEAR = 5, XTEXT = 6, XSCROL = 7, XWIN = 8,
$ XTDEL = 9)

5
difrac/IATSIZ Normal file
View File

@ -0,0 +1,5 @@
C-----------------------------------------------------------------------
C Parameters for LSTSQ, FOURR & COFOUR, DATRD2, TABLES and SOLVER
C-----------------------------------------------------------------------
CHARACTER MNCODE*6
PARAMETER (MNCODE = 'PCMSDS')

43
difrac/Makefile Normal file
View File

@ -0,0 +1,43 @@
#---------------------------------------------------------------------------
# Makefile for the DIFRAC library for SICS.
#
# Mark Koennecke, November 1999
#----------------------------------------------------------------------------
CFLAGS = -g -c
FL = f77 $(CFLAGS)
ROOT = ..
LIBS = $(ROOT)\libs
OBJECTS=difini.o \
ang180.o angval.o begin.o \
cent8.o cfind.o demo1e.o align.o \
centre.o mod360.o profil.o range.o sinmat.o cellls.o \
wxw2t.o angcal.o basinp.o comptn.o orcel2.o inchkl.o \
linprf.o lsormt.o mesint.o goloop.o ormat3.o blind.o \
params.o pltprf.o pcount.o prtang.o prnbas.o prnint.o \
grid.o sammes.o cellsd.o stdmes.o cntref.o indmes.o \
wrbas.o reindx.o rcpcor.o lotem.o nexseg.o lister.o \
oscil.o pfind.o pscan.o peaksr.o sgprnh.o \
difint.o tcentr.o tfind.o fndsys.o \
dhgen.o setrow.o creduc.o cinput.o \
burger.o angrw.o bigchi.o \
eulkap.o trics.o swrite.o
GENS = yesno.o freefm.o alfnum.o matrix.o \
sgroup.o latmod.o sgrmat.o \
sglatc.o sglpak.o sgerrs.o sgmtml.o \
sgtrcf.o \
setiou.o ibmfil.o
all: lib
clean:
rm *.o
lib: $(OBJECTS) $(GENS)
- rm libdif.a
ar cr libdif.a $(OBJECTS) $(GENS)
ranlib libdif.a
.f.o:
$(FL) $*.f

51
difrac/alfnum.f Normal file
View File

@ -0,0 +1,51 @@
C-----------------------------------------------------------------------
C Get an alphanumeric input string.
C In general all alphabetic characters are converted to upper-case,
C but if STRING contains "DONT DO IT" on input no conversion is done.
C This is useful to allow the input of file names in case sensitive
C operating systems like UNIX.
C All null characters are converted to blanks
C The code should be general for ASCII and EBCDIC.
C If the first character is a question mark (?) the routine exits to
C the system monitor.
C-----------------------------------------------------------------------
SUBROUTINE ALFNUM (STRING)
COMMON /IOUASS/ IOUNIT(12)
CHARACTER STRING*(*),NULL*1
NULL = CHAR(0)
ITR = IOUNIT(5)
ITP = IOUNIT(6)
IDONT = 0
IF (LEN(STRING) .GE. 10 .AND. STRING(1:10) .EQ. 'DONT DO IT')
$ IDONT = 1
C-----------------------------------------------------------------------
C Write the prompt - if any - and get the answer
C-----------------------------------------------------------------------
CALL GWRITE (ITP,'$')
STRING = ' '
ILEN = LEN(STRING)
IF (ILEN .GT. 80) ILEN = 80
CALL GETLIN (STRING)
IF (STRING(1:1) .EQ. '?') STOP
ILEN = LEN(STRING)
DO 120 I = 1,ILEN
IF (STRING(I:I) .EQ. NULL) STRING(I:I) = ' '
120 CONTINUE
IF (IDONT .EQ. 0) THEN
LITTLA = ICHAR('a')
LARGEA = ICHAR('A')
LITTLZ = ICHAR('z')
IDIFF = LITTLA - LARGEA
ILEN = LEN(STRING)
DO 130 I = 1,ILEN
ITHIS = ICHAR(STRING(I:I))
IF (ITHIS .GE. LITTLA .AND. ITHIS .LE. LITTLZ) THEN
ITHIS = ITHIS - IDIFF
STRING(I:I) = CHAR(ITHIS)
ENDIF
130 CONTINUE
ENDIF
RETURN
10000 FORMAT (A)
END


Some files were not shown because too many files have changed in this diff Show More