Initial revision
This commit is contained in:
27
.rfl
Normal file
27
.rfl
Normal 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
161
Components.txt
Normal 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
|
46
Dbg.h
Normal file
46
Dbg.h
Normal 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
64
Dbg_cmd.c
Normal 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
93
HistDriv.i
Normal 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
94
HistMem.h
Normal 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
35
HistMem.i
Normal 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
78
Makefile
Normal 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
528
SCinter.c
Normal 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
133
SCinter.h
Normal 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
87
SICSmain.c
Normal 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
81
Scommon.h
Normal 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
16
access.c
Normal 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
214
alias.c
Normal 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
20
alias.h
Normal 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
210
amor.dic
Normal 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
634
amor2t.c
Normal 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
22
amor2t.h
Normal 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
27
amor2t.i
Normal 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
176
amor2t.tex
Normal 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
122
amor2t.w
Normal 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
23
amorpar.tcl
Normal 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
140
amorscan.c
Normal 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
15
amorscan.h
Normal 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
71
amorscan.tex
Normal 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
57
amorscan.w
Normal 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
772
amorstat.c
Normal 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
21
amorstat.h
Normal 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
29
amorstat.i
Normal 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
138
amorstat.tex
Normal 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
102
amorstat.w
Normal 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
268
amortest.tcl
Normal 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
7
ati.tcl
Normal 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
46
author.txt
Normal 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
211
autofile.tcl
Normal 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
137
backup.tcl
Normal 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
47
bare.tcl
Normal 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
791
base.tcl
Normal 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
20
beam.tcl
Normal 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
20
beamdt.tcl
Normal 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
17
bit.h
Normal 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
999
bruker.c
Normal 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
25
bruker.h
Normal 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
64
bruker.tex
Normal 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
64
bruker.w
Normal 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
593
buffer.c
Normal 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
94
buffer.h
Normal 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
228
callback.c
Normal 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
79
center.tex
Normal 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
58
center.w
Normal 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
322
chadapter.c
Normal 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
38
chadapter.h
Normal 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
247
choco.c
Normal 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
36
choco.h
Normal 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
351
choco.tex
Normal 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
264
choco.w
Normal 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
122
circular.c
Normal 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
31
circular.h
Normal 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
44
codri.h
Normal 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
229
coll.tcl
Normal 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
54
comentry.h
Normal 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
422
commandlog.c
Normal 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
19
commandlog.h
Normal 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
26
configfu.h
Normal 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
|
115
conman.h
Normal file
115
conman.h
Normal 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
31
copyright.h
Normal 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
198
costa.c
Normal 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
29
costa.h
Normal 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
15
costa.i
Normal 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
108
costa.tex
Normal 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
68
costa.w
Normal 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
37
cotop.tcl
Normal 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
723
countdriv.c
Normal 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
88
countdriv.h
Normal 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
|
56
counter.h
Normal file
56
counter.h
Normal 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
50
countf.tcl
Normal 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
16
cron.tex
Normal 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
16
cron.w
Normal 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
293
danu.c
Normal 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
3
danu.dat
Normal 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
41
danu.h
Normal 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
92
danu.tex
Normal 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
77
danu.w
Normal 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
19
defines.h
Normal 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
922
devexec.c
Normal 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
146
devexec.h
Normal 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
322
devexec.tex
Normal 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
282
devexec.w
Normal 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
81
dict.c
Normal 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
539
difrac.c
Normal 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
14
difrac.h
Normal 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
728
difrac/CAD4COMM
Normal 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
54
difrac/COMDIF
Normal 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
5
difrac/IATSIZ
Normal 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
43
difrac/Makefile
Normal 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
51
difrac/alfnum.f
Normal 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
Reference in New Issue
Block a user