PSI sics-cvs-psi_pre-ansto

This commit is contained in:
2003-06-13 00:00:00 +00:00
committed by Douglas Clowes
parent 2e3ddfb6c6
commit 3ffd0d8af4
1099 changed files with 318432 additions and 0 deletions

5
doc/programmer/README Normal file
View File

@@ -0,0 +1,5 @@
The entry points in this file are:
pub.tex for a SICS publication
programmer.tex for a SICS programming guide
reference.tex for the SICS reference manual

140
doc/programmer/SCinter.tex Normal file
View File

@@ -0,0 +1,140 @@
\subsection{The SICS Interpreter} \label{scinter}
The SICS interpreter does the first step of command interpretation. Each
SICS command is a name followed by parameters. The interpreter holds for
each command a function (the object function) and a data structure. When a
command is invoked the list will be searched for a fitting command and then
its object function will be invoked for further processing.
The object
function is the object wrapper function as discussed in much detail in the
Guide to Object Writers. It looks like this:
\begin{verbatim}
typedef int (*ObjectFunc)(pSConnection pCon, pSicsInterp pInter, void
*pData, int argc, char *argv[]);
\end{verbatim}
{\bf pCon} is a pointer to the the connection for which the command
was invoked. {\bf pInter} is the SICS interpreter in which the command
was invoked. {argc, argv[]} are the command arguments similar to the
classic C main() function arguments. This is an objects interface to
the SICS interpreter.
{\bf pData} is a pointer to a command own data structure. This data structure
is deleted by the interpreter when the command is removed by calling
a special removal function with the pointer as parameter. This
function looks like this:
\begin{verbatim}
typedef void (*KillFunc)(void *pData);
\end{verbatim}
In order to do ist job the SICS interpreter has for each command a data
structure defined below:
\begin{verbatim}
typedef struct __Clist {
char *pName;
ObjectFunc OFunc;
KillFunc KFunc;
void *pData;
struct __Clist *pNext;
struct __Clist *pPrevious;
} CommandList;
\end{verbatim}
The fields are: \begin{description}
\item[name] The command name.
\item[OFunc] The object wrapper function.
\item[KFunc] The object data structure removal function.
\item[pData] The objects data structure.
\item[pNext, pPrevious] pointers necessary to maintain the doubly linked
list of commands.
\end{description}
The interpreter itself is described by the following data structure:
\begin{verbatim}
typedef struct __SINTER
{
CommandList *pCList;
OutCode eOut;
void *pTcl;
char **argv;
int iDeleting;
}SicsInterp;
\end{verbatim}
The fields are: \begin{description}
\item[pCList] A pointer to the command list.
\item[eOut] an out code.
\item[pTcl] a pointer to the Tcl macro interpreter.
\item[argv] An argv[] array with command arguments.
\item[iDeleting] a flag which is set when the interpreter is in the
process of being removed.
\end{description}
Please note, that currently commands are searched for by linear scanning of
the command list, doing a strcmp at each stop. This is inherently
inefficient. If in some stage interpreter inefficiency is a problem this
scheme should be chnaged to a hash table system or a randomized binary tree.
The interpreter can be controlled with the following functions:
\begin{description}
\item[SicsInterp *InitInterp(void)]
Makes a new interpreter. Returns him on success, else NULL
\item[int AddCommand(SicsInterp *pInterp, char *pName, ObjectFunc pFunc,
KillFunc pKFunc, void *pData)]
Adds a new command, Returns True or False, depending on success
Parameters:
\begin{itemize}
\item pInterp : the interpreter to add the command to.
\item pName : the commands name
\item pFunc : the object function to call when this command is
invoked. Definition of type: see above
\item pKFunc : function to call in order to delete command data.
type definition: above
\item pData : pointer to the command's own datastructure. Will be
passed as pData with each call to Ofunc.
\end{itemize}
It is possible to install commands without an associated data structure.
Then pData must be NULL. In such cases AddCommand provides a default data
structure with a default object descriptor.
\item[int RemoveCommand(SicsInterp *pInterp, char *pName)]
Kills the command name from the interpreter pInterp
\item[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: \begin{itemize}
\item self : interpreter to invoke command in.
\item The connection pCon will be used for I/O and status reporting.
\item The command to invoke is the string pCommand.
\end{itemize}
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.
\item[CommandList *FindCommand(SicsInterp *pInterp, char *name)]
Searches the Interpreters pInterp command list for a command
with name. Returns its data structure if found, NULL else
\item[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: \begin{itemize}
\item pSics : the interpreter to use.
\item file : the file to write the information to.
\end{itemize}
Returns: 1 on success, 0 on failure.
\item[int InterpWrite(SicsInterp *pSics, char *buffer)]
Writes result to Tcl, used for Macro mechanism.
This is an internal function and should not be used.
\item[void DeleteInterp(SicsInterp *self)]
Deletes the interpreter self aand clears all asoociated datastructures.
self will no longer be vaild after this.
\item[FindAlias] find the alias for a given data structure. This is a
special function required internally.
\item[FindCommandData] is a convenience wrapper around FindCommand
which returns the commands data structure instead the CommandList
entry fo a given command name. Returns NULL, if the command was not
found.
\end{description}

37
doc/programmer/alias.tex Normal file
View File

@@ -0,0 +1,37 @@
\subsection{The Alias Facility}
Aliases make commands available under a different name. SICS currently supports two types of aliases:
\begin{itemize}
\item Object aliases. This is a facility for renaming first class SICS
objects such as commands and hardware objects. This is installed into
SICS by creating a new name in the interpreter but with the data
structures of the original object. Thus all interface operations such
as driving etc will work. Object aliases are installed from the
initialization script through the SicsAlias command.
\item Command aliases. This is just plain text replacement. For
instance one may define ``sttll'' instead of ``a4 softlowerlim''. Such
an alias can be installed with the ``alias'' command at any
time. However, renaming a motor with this scheme will not work
properly as this alias facility has no way to forward interfaces
properly.
\end{itemize}
There is no
data structure associated with object aliases. The trick is done by
just putting in
the same command as a new name into the interpreter.
Corrspondingly there is only one function to it:
\begin{verbatim}
int SicsAlias(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
\end{verbatim}
SicsAlias is the object wrapper function which implements the alias command.
Command aliases are implemented through:
\begin{verbatim}
int MakeAlias(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
\end{verbatim}
There is a little trivial data structure associated with command
aliases which is defined in alias.c.

176
doc/programmer/amor2t.tex Normal file
View File

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

View File

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

138
doc/programmer/amorstat.tex Normal file
View File

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

64
doc/programmer/bruker.tex Normal file
View File

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

81
doc/programmer/buffer.tex Normal file
View File

@@ -0,0 +1,81 @@
\subsection{The LNS R\"unbuffer}
R\"unbuffers are a special LNS feature for handling instruments. Essentially
a R\"unbuffer is a list of commands which can be executed as a block. On
line editing of such a R\"unbuffer is supported as well. R\"unbuffers can
also be saved to or read from disk files. R\"unbuffers are related to the
batch file processing facility FileEval. However, there are subtle
differences. The first is I/O: When evaluating a batch file with FileEval
all messages except errors and warnings are suppressed. This is a nice
feature if the file evaluated contains a macro, where a user might be
confused when confronted with all internal messages. With R\"unbuffers all
output is written to the user. R\"unbuffers support only SICS commands, with
FileEval Tcl commands can be given as well.
It turned out that the R\"unbuffer system together with the R\"unlist
facility documented in the next section is rarely
used. Experimentators prefer the batch file facility ``fileeval''
instead. Consequently, this may be retracted and cleaned out in some
stage.
A R\"unbuffer is characterized by a an own data structure:
\begin{verbatim}
typedef struct {
pObjectDescriptor pDes; /* needed */
char *name; /* BufferName */
int iLineList; /* Handle to the Line List */
} RuenBuffer, *pRuenBuffer;
\end{verbatim}
The fields:
\begin{description}
\item[pDes] A pointer to the usual SICS object descriptor.
\item[name] The name of the R\"unbuffer.
\item[iLineList] The handle of the lldlist holding the lines of the
R\"unbuffer.
\end{description}
Interaction with R\"unbuffers happesn through the functions listed below.
All functions return 0 on failure or 1 on success, if not stated otherwise.
Most functions take as first parameter a pointer to the R\"unbuffer to act
upon.
\begin{description}
\item[pRuenBuffer CreateRuenBuffer(char *name)] creates a R\"unbuffer.
Returns the pointer to the new r\"unbuffer on success, or NULL on failure.
\item[void DeleteRuenBuffer(void *pSelf)] Deletes a R\"unbuffer.
\item[pRuenBuffer CopyRuenBuffer(pRuenBuffer pOld, char *NewName)] copies a
R\"unbuffer including all data lines. Returns NULL on failure, a pointer to
a new R\"unbuffer structure otherwise.
\item[int BufferAppendLine(pRuenBuffer self, char *line)] appends line to
r\"unbuffer self.
\item[int BufferDel(pRuenBuffer self, int iLine)] deletes line iLine from
r\"unbuffer self.
\item[int BufferInsertAfter(pRuenBuffer self, int iLine, char *line)]
inserts line line AFTER line number iLine in the RuenBuffer self.
\item[int BufferPrint(pRuenBuffer self, SConnection *pCon)]
lists the contents of the RuenBuffer on the Connection pCon.
\item[int BufferReplace(pRuenBuffer self, char *pattern, char *pReplace)]
replaces all occurences of the string pattern in the whole RuenBuffer
by the replacement string pReplace.
\item[int BufferRun(pRuenBuffer self, SConnection *pCon, SicsInterp *pSics)]
executes the lines of the Ruenbuffer one by one.
Returns 1 on success, 0 on error.
\item[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.
\item[int BufferLoad(pRuenBuffer self, char *file)]
reads the contents of file into the RuenBuffer self.
Returns 1 on success, 0 on error.
\item[int InitBufferSys(SConnection *pCon, SicsInterp *pSics, void *pData,\\
int argc, char *argv[])] The factory function for the
R\"unbuffer system. Initialises the Buf command and the ruli command.
\item[int BufferCommand(SConnection *pCon, SicsInterp *pSics, void *pData,\\
int argc, char *argv[])] The object wrapper function
which implements the Buf command.
\item[int BufferAction(SConnection *pCon, SicsInterp *pSics, void *pData,\\
int argc, char *argv[])] The object wrapper function for
the R\"unbuffer itself.
\item[pRuenBuffer FindRuenBuffer(SicsInterp *pSics, char *name)] finds
r\"unbuffer name in the interpreter pSics. Returns a pointer to the
r\"unbuffers data structure if it exists, NULL otherwise.
\end{description}

79
doc/programmer/center.tex Normal file
View File

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

380
doc/programmer/choco.tex Normal file
View File

@@ -0,0 +1,380 @@
\subsection{Chopper Controller}
Yet another way to deal with a controller has been 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 or environment controller through special
adapters . 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.
\item An adapter to an environment controller driver.
\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 text. 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 And Environment Adapters}
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@ pEVDriver MakeControllerEnvironmentDriver(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.
\item[MakeControllerEnvironmentDriver] creates an environment control
driver for a parameter in a general controller object.
\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}
This is the data structure for the private part of the environment
controller driver:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap6}
$\langle$evada {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __CHEV {@\\
\mbox{}\verb@ char *pParName;@\\
\mbox{}\verb@ pCodri pDriv;@\\
\mbox{}\verb@ int iLastError;@\\
\mbox{}\verb@ }CHev, *pCHev;@\\
\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{scrap7}
\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{scrap8}
\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{scrap9}
\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@@$\langle$evada {\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.

108
doc/programmer/costa.tex Normal file
View File

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

180
doc/programmer/counter.tex Normal file
View File

@@ -0,0 +1,180 @@
\subsection{The Counter}
This is the SICS object responsible for handling single counters and
monitors. As usual for SICS hardware objects the
counter is subdivided in a driver and a logical object. The driver will be
discussed first. The same concept with overlaying structures is used
for counters as for motors in order to allow for different drivers.
\subsubsection{The Counter Driver}
Counter drivers are polymorphic. This means that different drivers look the
same to the logical counter objects. This is achieved by having pointers to
functions in the driver. These pointers must be initialised by an actual driver
with functions which implement the required behaviour.
The counter driver is a large data structure defined below:
\begin{verbatim}
typedef struct __COUNTER {
/* variables */
char *name;
char *type;
CounterMode eMode;
float fPreset;
int iNoOfMonitors;
long lCounts[MAXCOUNT];
int iPause;
/* 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);
void *pData; /* counter specific data goes here, ONLY for
internal driver use!
*/
} CounterDriver, *pCounterDriver;
\end{verbatim}
All functions take a pointer to a counter structure as first parameter. If
not described otherwise all functions return 0 on failure and 1 on success.
The fields have the following meanings:
\begin{description}
\item[name] The counter name in the system.
\item[type] A string describing the counter type.
\item[eMode] The counting mode of the counter. Can be eTimer for counting
till a preset time has passed or ePreset for counting until one of the
monitors has reached a certain count rate.
\item[fPreset] Depending on the count mode either the time to count or the
monitor rate to wait for for.
\item[iNoOfMonitors] The number of monitors handled by this counter.
\item[lCounts] An array which stores the counts in the array position 0, and
the monitor counts in the other fields of the array.
\item[iPause] A logical which is set when the counter is paused.
\item[GetStatus] GetStatus is the first of the functions a driver has to
define. GetStatus reads the counter status. Possible return values are:
\begin{description}
\item[HWIdle, OKOK] The counter is finished or idle.
\item[HWFault] A fault has been found at the counter instead of an
reasonable answer.
\item[HWNoBeam] There is currently no incident beam. This is usually
detected through a monitor which does not increase over time.
\item[HWPause] Counting has been paused.
\item[HWBusy] The counter is busy counting.
\end{description}
The parameter fControl is set to the current value of the counting control
variable. This can either be the counting time already passed or the count
rate of the control monitor in ePreset mode.
\item[Start] Starts counting with the current mode and preset parameters.
\item[Pause] pauses a counting operation.
\item[Continue] continues a paused counting operation.
\item[Halt] cancels a counting operation. This a emergency stop used when
interrupting an operation.
\item[ReadValues] reads the counter and the monitors in the lCounts array.
This gets automatically called through the TransferData routine of the
countable interface after a counting operations finishes. The point is that
data is transfered from the counter once and further requests operate on the
contents of the local array instead of bothering the hardware again.
\item[GetError] This gets called when an error has been detected during one
of the previous operations. The function has to return more information
about the error: iCode an driver dependent integer error code and maximum
iErrLen characters of problem description in error.
\item[TryAndFixIt] takes the integer error code returned in iCode from
GetError and tries to solve the problem with the hardware. This function can
either return COREDO which means the problem has been fixed and the
operation needs to redone or COTERM which means that it is not possible to
resolve the problem in software.
\item[pData] A pointer to a driver dependent data structure. Whereas the
fields above are required and expected by the counter module for a driver,
this is an area private to the actual driver.
\end{description}
As most of the action of the counter driver is done in the functions given
in its data structure only few functions are available in order to interact
with it:
\begin{description}
\item[pCounterDriver CreateCounterDriver(char *name, char *type)] creates a
general default counter driver structure.
\item[void DeleteCounterDriver(pCounterDriver self)] deletes a counter
driver.
\item[pCounterDriver NewEL737Counter(char *name, char *host, int iPort,
int iChannel)] creates a PSI--EL737 counter
driver. The counter box is meant to be reachable at the terminal server
host, listening at iPort and connected to channel iChannel at the macintosh.
\item[void KillEL737Counter(pCounterDriver self)] deletes an EL737 counter
driver.
\item[pCounterDriver NewSIMCounter(char *name)] creates a simulated counter
driver. Needed for software testing and instrument simulation.
\item[void KillSIMCounter(pCounterDriver self)] deletes a simulated counter
driver.
\end{description}
\subsubsection{The Logical Counter Object}
This is the object which represents the counter to the system. For all
actual hardware action the driver is called. The counter objects data
structure:
\begin{verbatim}
typedef struct {
pObjectDescriptor pDes;
char *name;
int isUpToDate;
int iExponent;
pICountable pCountInt;
pCounterDriver pDriv;
pICallBack pCall;
unsigned long tStart;
} Counter, *pCounter;
\end{verbatim}
The fields:\begin{description}
\item[pDes] The required object descriptor for any SICS object.
\item[name] The counters name in the system.
\item[isUpToDate] a logical which is true when counting is finished and the
data in the drivers lCount array represent the correct values.
\item[iExponent] The exponent to apply on preset values in monitor mode. At
SINQ monitor count rates in millions are usual. The exponent saves typing
all those 0's. Each monitor preset value given is multiplied by this value.
\item[pCountInt] A pointer to the countable interface.
\item[pDriv] A pointer to a counter driver for this counter.
\item[pCall] A pointer to the callback interface implemented by this
counter.
\item[tStart] The start time of the last counting operation.
\end{description}
Unlike the counter driver, there exist many functions for interaction with
the counter. Mosts functions take a pointer to a counter structure as first
parameter. In order to communicate error messages, functions which interact
with hardware take a pointer to a connection object as parameter.
\begin{description}
\item[pCounter CreateCounter(char *name, pCounterDriver pDriv)] Creates a
new counter object with name name and counter driver pDriv.
\item[void DeleteCounter(void *self)] deletes a counter object.
\item[int MakeCounter(SConnection *pCon, SicsInterp *pSics, void *pData,\\
int argc, char *argv[])] The counter object factory
function. The function to be hacked (plus DeleteCounter) when a new driver
needs to be introduced into the system.
\item[int SetCounterMode(pCounter self, CounterMode eNew)] sets a new
counter mode.
\item[CounterMode GetCounterMode(pCounter self)] requests the current
counter mode.
\item[int SetCounterPreset(pCounter self, float fVal)] sets a new preset
time or monitor.
\item[float GetCounterPreset(pCounter self)] returns the current preset time
or monitor.
\item[long GetCounts(pCounter self, SConnection *pCon)] returns the detector
counts.
\item[long GetMonitor(pCounter self, int iNum, SConnection *pCon)] returns
the monitor counts in monitor iNum. This function returns -1 when the
requetsed monitor does not exist.
\item[ GetNMonitor(pCounter self)] returns the number of monitors
available.
\item[int DoCount(pCounter self,float fPreset, SConnection *pCon, SicsInterp
*pSics)] does a count operation with fPreset as preset value.
\item[int CountAction(SConnection *pCon, SicsInterp *pSics, void *pData,\\
int argc, char *argv[])] The counter objects wrapper
function. This function defines the user interface to the counter object.
\end{description}

16
doc/programmer/cron.tex Normal file
View File

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

92
doc/programmer/danu.tex Normal file
View File

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

322
doc/programmer/devexec.tex Normal file
View File

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

52
doc/programmer/difrac.tex Normal file
View File

@@ -0,0 +1,52 @@
\subsection{The Difrac Subsystem}
Difrac is a F77 package for controlling a four circle diffractometer
developed by P. Gabe and White for PC's. This package became only
available very late. This package has been included into SICS for four
circle diffraction. All the code for the difrac package resides in the
difrac subdirectory to sics. For more information about the difrac
system see the documentation coming with difrac. In order to
integrate difrac into SICS the following steps had to be taken:
\begin{itemize}
\item Define an interface from SICS to DIFRAC.
\item Modify the DIFRAC hardware control to run the hardware through
SICS.
\item Adapt I/O
\item Modify DIFRAC to be a subsystem instead of a program of its own.
\item Adapt measurement procedures to the special needs of TRICS.
\end{itemize}
\subsubsection{The Interface SICS to DIFRAC}
This is implemented in difrac.c. It it is just a interface wrapper
function which takes the command given and forwards it to the DIFRAC
interpreter. A tricky bit about this ist, that this module has to keep
track of which cconnection issued the command. This is done through a
connection stack.
\subsubsection{DIFRAC HW control}
DIFRAC controls the hardware through a couple of function originally
defined in the file ralf.f. This file has been replaced by a file
trics.f which in turn calls C-functions implemented in difrac.c which
do the actual job.
\subsubsection{DIFRAC I/O}
In contrast to many F77 prograsm DIFRAC has a very intelligent I/O
system. All input is channelled through the function GETLIN in
gwrite.f. This function has been modified to call a C-function which
gets a line of input from SICS. This adpater is again in difrac.c. All
output is printed first into a internal string buffer, COUT, and then
printed using the function GWRITE. This function has been modified to
call a C-function which writes the output to a SICS connection. The
integration of DIFRAC into SICS was only possible because of the
existence of this I/O system.
\subsubsection{Changes in DIFRAC}
The DIFRAC main program was taken apart into a initialisation routine
(difini.f) and a callable interpreter function (difint.f). Further
changes were required because TRICS does not do continous scans in the
way a X-ray four circle diffractometer does. DIFRAC's concept of a
scan drives a motor slowly and collects data. This has been modified
to do step scans for TRICS. Some commands which do not make sense
within SICS have been disabled. Some little changes to measurement
routines were necessary.

48
doc/programmer/dmc.tex Normal file
View File

@@ -0,0 +1,48 @@
\subsection{DMC module}
This module initialises all DMC specific commands. Currently there is only
one: StoreData. This does not do much, it is just here as a container for
things to come.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$Protos {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ int InitDmc(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@"dmc.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-------------------------------------------------------------------------@\\
\mbox{}\verb@ D M C @\\
\mbox{}\verb@@\\
\mbox{}\verb@ this modules purpose is solely to initialise the commands specific to@\\
\mbox{}\verb@ the powder diffractometer DMC.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koenencke, March 1997@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ copyright: see implementation file.@\\
\mbox{}\verb@@\\
\mbox{}\verb@--------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSDMC@\\
\mbox{}\verb@#define SICSDMC@\\
\mbox{}\verb@@$\langle$Protos {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

30254
doc/programmer/dmccom.eps Normal file

File diff suppressed because it is too large Load Diff

BIN
doc/programmer/dmccom.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

22
doc/programmer/drive.tex Normal file
View File

@@ -0,0 +1,22 @@
\subsection{The Drive and Run Command}
This command implements driving of real motors or virtual motors (variables
which control multiple motors). The drive command has no associated data
structure going with it. There are just a few function:
\begin{description}
\item[int Drive(SConnection *pCon,SicsInterp *pSics, char *name, float
fNew)] drives motor name to fNew and waits for the motor to finish. Possible
errors will be written to the connection object pCon.
\item[int Start2Run(SConnection *pCon, SicsInterp *pSics, char *name, float
fNew)] starts the motor name to run to fNew. This
function will NOT wait for the motor to get there. In spite of this,
possible errors will be printed to the connection object pCon.
\item[int DriveWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])] the object wrapper
function for the drive command.
\item[int RunWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])] the object wrapper
function for the run command.
\item[int MakeDrive(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])]
The factory command which installs the drive and run commands into SICS.
\end{description}

140
doc/programmer/dynar.tex Normal file
View File

@@ -0,0 +1,140 @@
\subsection{Dynamic Array}
This section describes a dynamic array of arbitrary pointers. Dynamic means,
that the array gets enlarged automatically when an index outside of the
current bounds has been requested. Negative values are supported as well.
The interface to this module looks like this:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$dynarint {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __SDynar *pDynar;@\\
\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
\mbox{}\verb@ pDynar CreateDynar(int iStart, int iEnd, int iGrain, @\\
\mbox{}\verb@ void (*DataFree)(void *pData));@\\
\mbox{}\verb@ void DeleteDynar(pDynar self);@\\
\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
\mbox{}\verb@ int DynarPut(pDynar self, int iIndex, void *pData);@\\
\mbox{}\verb@ int DynarPutCopy(pDynar self, int iIndex, void *pData, int iDataLen);@\\
\mbox{}\verb@ int DynarReplace(pDynar self, int iIndex, void *pData, int iDatLen);@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ int DynarGet(pDynar self, int iIndex, void **pData);@\\
\mbox{}\verb@ int DynarGetCopy(pDynar self, int iIndex, void *pData, int iDataLen);@\\
\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}
If not stated otherwise, all functions return 1 on success and 0 on failure.
\begin{description}
\item[CreateDynar] creates a new dynamic array. On success a pointer to a
new dynamic array is returned, else NULL. The parameters are: iStart, the
initial start index of the array, iEnd, the initial end index of the array,
iGrain, the packet of new space to allocate when the array is enlarged
dynamically, DataFree, a function which takes a pointer to one of the data
items stored in the dynamic array and the free's all the memory associated
with the data item. DataFree will be used automatically by Dynar for
releasing memory when data items are replaced or the whole array is deleted.
\item[DeleteDynar] removes the dynamic arary from memory. The pointer to
self will point to rubbish afterwards and shall not be used.
\item[DynarPut] puts the pointer pData at position iIndex in the dynamic
array. pData needs to be allocated from dynamic memory, otherwise you'll
experience core dumps. A data item which was previously at the position
denoted by iIndex will be freed.
\item[DynarPutCopy] does the same as DynarPut, but copies the data item.
iDataLen bytes of new memory will be allocated and the data from pData be
put into it. Then this will be entered into the dynamic array at position
iIndex.
\item[DynarReplace] replaces the data at iIndex by the data pointed to by
pData by a memcpy. If there was no data defined previously, this call has
the same effect as DynarPutCopy.
\item[DynarGet] retrieves the pointer pData at position iIndex from the dynamic
array.
\item[DynarGetCopy] copies iDataLen bytes from the data at position iIndex
into the buffer pData. pData must be large enough to hold iDataLen bytes.
\end{description}
Nowe, here is the definition of the internal datastructure for the
dynamic array class.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$dynardat {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __SDynar {@\\
\mbox{}\verb@ int iStart;@\\
\mbox{}\verb@ int iEnd;@\\
\mbox{}\verb@ int iGrain;@\\
\mbox{}\verb@ void **pArray;@\\
\mbox{}\verb@ void (*DataFree)(void *pData);@\\
\mbox{}\verb@ } Dynar;@\\
\mbox{}\verb@ @\\
\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{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
\verb@"sdynar.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*---------------------------------------------------------------------------@\\
\mbox{}\verb@ D Y N A M I C A R R A Y@\\
\mbox{}\verb@@\\
\mbox{}\verb@ This file describes the interface to a dynamic array module for pointers.@\\
\mbox{}\verb@ This sort of array resizes dynamically.@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ Mark Koennecke, September 1997@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see copyright.h@\\
\mbox{}\verb@@\\
\mbox{}\verb@-----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSDYNAR@\\
\mbox{}\verb@#define SICSDYNAR@\\
\mbox{}\verb@@$\langle$dynarint {\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{scrap4}
\verb@"sdynar.i"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*----------------------------------------------------------------------------@\\
\mbox{}\verb@ D Y N A M I C A R R A Y@\\
\mbox{}\verb@@\\
\mbox{}\verb@ This file defines the internal data structure used by the dynamic@\\
\mbox{}\verb@ array module.@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ More info: see sdynar.h@\\
\mbox{}\verb@-----------------------------------------------------------------------------*/@\\
\mbox{}\verb@@$\langle$dynardat {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

218
doc/programmer/emonitor.tex Normal file
View File

@@ -0,0 +1,218 @@
\subsection{SICS Sample Environment Handling}
In addition to driving motors and counting SICS has to take care of sample
environment devices as well. These can be temperature controllers, current
controllers etc. It can be assumed, that SICS has to take care of
intelligent sample environment devices only, i. e. devices which do their
own realtime processing. SICS, however, has to implement the logic to drive
an environment controller to a new value. Furthermore SICS has to do the
error handling when an environment controller fails. In order to do this the
following software components will be needed:
\begin{itemize}
\item An environment monitor. This component will register any active
environment control device. A test function will be called from the main
loop which checks for controller out of range and initiates error handling.
\item A new interface, the environment interface (see \ref{interface}).
\item Controller objects. One for each environment controller. Again, the
SICS distinction between logical objects and hardware drivers will be
maintained.
\end{itemize}
Controller objects will be able to share some code among them. Each
environemnt controller will hold a target value, a permissable tolerance,
a selctor variable which defines the type of error handling to perform and
an interrupt code to issue when that form of error handling is choosen.
Furthermore each environment controller needs to implement the drivable
interface (for driving to new values) and the environment interface (for
monitoring the controller). Controller object will also share the error
handling during the monitor phase between them. The scheme is that each controller will have a
variable which selects the error handling mechanism. Depending on this
variable an error managment routine will be invoked. Current two schemes for
handling errors are supported:
\begin{itemize}
\item Print a warning but do nothing else.
\item Interrupt: an interrupt will be issued.
\item Pause: the measurement will be paused.
\item Try to drive to a safe value. This may be used to rescue a oven
gone haywire by setting a low setpoint where the device is safe.
\end{itemize}
This scheme allows for adding more error handling strategies when necessary
and to implement them in one place for all environment controllers.
Consequently, there will be some some general controller code in files
evcontrol.*. In the object oriented paradigm environment controller would
inherit from this general controller. This is implemented by delegation in
SICS.
Please note, that any environment device has three modes of
operation. The first, trivial one, is idle. The second one is the driving
phase. This phase is entered when a drive or run command tries to set the
controller to a new value. Once this target has been reached a environment
controller will be registered in the environment monitor which will take
care of monitoring the controller during its operation. This is the
third stage: inMonitor.
\subsection{The Environment Monitor}
The environment monitors (emon) task is to register all active environment
controllers. It will be called from the main loop to check if each
registered environment controller is still within tolerances. If not, emon
has to enforce error processing. Else it does nothing.
The environment monitor uses the following datastructures:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$emondat {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __EnvMon {@\\
\mbox{}\verb@ pObjectDescriptor pDes;@\\
\mbox{}\verb@ int iList;@\\
\mbox{}\verb@ int iEnd;@\\
\mbox{}\verb@ } EnvMon;@\\
\mbox{}\verb@/*---------------------------------------------------------------------------*/@\\
\mbox{}\verb@ typedef struct {@\\
\mbox{}\verb@ pDummy pDum;@\\
\mbox{}\verb@ char *pName;@\\
\mbox{}\verb@ pEVInterface pInter;@\\
\mbox{}\verb@ } EVEntry, *pEVEntry; @\\
\mbox{}\verb@@\\
\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}
As it it will be accessible as SICS object emon needs an object descriptor.
The other data member is a list of active controllers.
The EVEntry structure contains the data held in the list for each active
controller. It is, disguised as pDum, a pointer to the controllers
datastructure, the name of the controller, and the environment interface of
the controller.
The following interface is implemented by the environment monitor:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$emonint {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@ pEnvMon CreateEnvMon(void);@\\
\mbox{}\verb@ void DeleteEnvMon(void *pData);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int EVRegisterController(pEnvMon self, char *pName, void *pData,@\\
\mbox{}\verb@ SConnection *pCon);@\\
\mbox{}\verb@ int EVUnregister(pEnvMon self, char *name);@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ int EVMonitorControllers(pEnvMon self);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int EVList(pEnvMon self, SConnection *pCon);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int EVWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ pEnvMon FindEMON(SicsInterp *pSics);@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ int EnvMonTask(void *pEv);@\\
\mbox{}\verb@ void EnvMonSignal(void *pEndv, int iSignal, void *pSigData);@\\
\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 CreateEnvMon} initialises a emon data structure. As usual it returns
NULL on error, a pointer to a new structure on success.
{\bf DeleteEnvMon} deletes and emon data structure and frees all memory
associated with it.
{\bf EVRegisterController} registers a controller for monitoring. The
parameters are:
\begin{itemize}
\item {\bf self}. A pointer to the environment monitor where to register the
controller.
\item {\bf pName}. The name of the controller object.
\item {\bf pData}. A pointer to the data structure belonging to the
controller object.
\item {\bf pCon}. A pointer to the client connection to which erros shall be
reported.
\end{itemize}
{\bf EVUnregister} Removes the controller name from the monitoring list.
{\bf EVMonitorControllers} is the function which will be called from the
main loop and which is responsible for monitoring the registered
controllers.
{\bf EVList} prints a status report about the emon to the Connection object
specified.
{\bf EVWrapper} is the wrapper function necessary to make the emon
available from SICS. The user may interact with the emon through SICS. The
user will be enabled to list the currently registered environment
controllers and their current state and to register and unnregister
controllers.
{\bf EnvMonTask} is the task function associated with the environment
monitor. This is called by the task handling object and eventually
invokes EVMonitorControllers for checking on the environment
controllers configured into SICS.
{\bf EnvMonSignal} is the signale handler for the environment monitor task.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
\verb@"emon.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------@\\
\mbox{}\verb@ E N V I R O N M E N T M O N I T O R@\\
\mbox{}\verb@@\\
\mbox{}\verb@ The environment monitor is responsible for monitoring active environment@\\
\mbox{}\verb@ devices. @\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, Juli 1997@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see implementation file.@\\
\mbox{}\verb@ doc: programmers reference.@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSEMON@\\
\mbox{}\verb@#define SICSEMON@\\
\mbox{}\verb@ typedef struct __EnvMon *pEnvMon;@\\
\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
\mbox{}\verb@@$\langle$emonint {\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@"emon.i"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------@\\
\mbox{}\verb@ Internal header file defining the datastructure for the environment@\\
\mbox{}\verb@ controller.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, Juli 1997@\\
\mbox{}\verb@---------------------------------------------------------------------------*/@\\
\mbox{}\verb@@$\langle$emondat {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

View File

@@ -0,0 +1,321 @@
\subsection{Environment Controller}
An environemnet controller controls a piece of sample environemnet
equipment. Thereby it does not really matter if the device in question
is a temperature controller or a magnet or whatever. All devices need
to be driven to a new value and there must be some scheme for
monitoring the device during a measurement. This monitoring is done by the
environment monitor described in the kernel section of this book.
Then there must be some type of logging facility. SICS defers logging to
a separate module, the varlogger.
The Environment Controller (EVControl) is a kind of base class for all
environment devices. This poses the question how SICS implements
inheritance. The scheme is simple:
\begin{itemize}
\item The base class (in this case EVControl) will hold a void pointer.
Derived classes are meant to add their datastructures at that level.
Furthermore derived classes are required to provide a function, which
deletes its private data.
\item When overloading functions of the base class, the derived class
should call the overloaded function of the base class whenever apropriate.
\end{itemize}
\subsubsection{Environment Controller Datastructures}
To enhance understanding of this, see the definition of the datastructure
used by EVControl:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$evdata {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __EVControl {@\\
\mbox{}\verb@ pObjectDescriptor pDes;@\\
\mbox{}\verb@ pIDrivable pDrivInt;@\\
\mbox{}\verb@ pEVInterface pEnvir;@\\
\mbox{}\verb@ pEVDriver pDriv;@\\
\mbox{}\verb@ EVMode eMode;@\\
\mbox{}\verb@ float fTarget;@\\
\mbox{}\verb@ char *pName;@\\
\mbox{}\verb@ ObPar *pParam;@\\
\mbox{}\verb@ int iLog;@\\
\mbox{}\verb@ pVarLog pLog;@\\
\mbox{}\verb@ int iWarned;@\\
\mbox{}\verb@ int iTcl;@\\
\mbox{}\verb@ int iStop;@\\
\mbox{}\verb@ void *pPrivate;@\\
\mbox{}\verb@ void (*KillPrivate)(void *pData);@\\
\mbox{}\verb@ } EVControl;@\\
\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 first field is a pointer to the usual object descriptor,
the second field a pointer to an Drivable interface. Each environment
controller needs to implement that in order to allow SICS drive the device
to a new value. The third field is a pointer to an environment interface.
This is needed in order to enable monitoring of the device when it has
reached its target value. The fourth field is a pointer to the driver for
the actual hardware. Next is the mode the device is in. Of course there
must be floating point value which defines the current target value for the
device. pName is a pointer to a string representing the name of the
controller. Then there is a
parameter array. iLog is a boolean which says if data should be logged
for this controller or not. pLog is the a pointer to a Varlog structure
holding the logging information. Then there is a switch, iWarned, which is
used to prevent execessive output on environment controller error handling.
iTcl is a boolean stating if the driver used is a proper C language driver
or a Tcl driver.
This is followed by the void pointer for use by a derived
class. KillPrivate is a pointer to a function capable of deleting pPrivate
properly.
For the hardware drivers for environment controllers a similar scheme is
used:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$evdriv {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __EVDriver {@\\
\mbox{}\verb@ int (*SetValue)(pEVDriver self, float fNew);@\\
\mbox{}\verb@ int (*GetValue)(pEVDriver self, float *fPos);@\\
\mbox{}\verb@ int (*Send)(pEVDriver self, char *pCommand,@\\
\mbox{}\verb@ char *pReplyBuffer, int iReplBufLen); @\\
\mbox{}\verb@ int (*GetError)(pEVDriver self, int *iCode,@\\
\mbox{}\verb@ char *pError, int iErrLen);@\\
\mbox{}\verb@ int (*TryFixIt)(pEVDriver self, int iCode);@\\
\mbox{}\verb@ int (*Init)(pEVDriver self);@\\
\mbox{}\verb@ int (*Close)(pEVDriver self);@\\
\mbox{}\verb@ void *pPrivate;@\\
\mbox{}\verb@ void (*KillPrivate)(void *pData);@\\
\mbox{}\verb@ } EVDriver;@\\
\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}
If not stated otherwise, member functions return 0 on failure and 1 on
success.
This datastructure in detail: \begin{description}
\item [SetValue] Sends a command to the environment device which drives it
to a new value specified as second parameter. Translation to device specific
values is done here. If an error occurs, SetValue returns 0, else 1.
\item [GetValue] Asks the device its current measured value.
If an error occurs, GetValue returns 0, 1 on success and -1 when there is
data pending. GetValue will be used for enquiring status. Some devices have
such a slow response that the first call will issue the command and the next
ones will check for data availability and read eventually.
\item [Send] Sends the command in pCommand to the environment device. For
replies, a pointer to a ReplyBuffer is provided. iReplBufLen is the maximum
length permissable for the ReplyBuffer. Send copies maximum iReplBufLen
bytes into pReplyBuffer in order to prevent memory overwrite. The idea of
send is to provide a means to load calibration data and parameters to the
environment device.
\item [GetError] GetError will be called when an error occurs. It is meant
to set iCode to an internal error code and fill pError with an textual
description of the error observed. Maximum iErrLen bytes of information
will be copied to pError.
\item [TryFixIt] TryFixIt will be called with the internal error code
retuned by GetError in iCode as second parameter. TryAndFixIt then analyses
the error code and figures out if something can be done in software to fix
the problem. If so, the apropriate actions are performed. TryFixIt returns
either DEVOK, if the device is OK, DEVFAULT, if TryFixIt cannot fix the
problem and DEVREDO if TryFixIt manged to fix the problem but requires the
last command to be resent.
\item [Init] Init is meant to initialise or reinitialise the driver.
\item [Close] Close is meant to close the driver and bring the device into a
safe state.
\item [pPrivate] is a pointer to a driver specific datastructure.
\item [KillPrivate] is a pointer to a function which is capable of removing
a drivers specific datastructure properly.
\end{description}
\subsubsection{Environment Controller Funtions}
All of the functions below return 1 on success, 0 on failure if not sated
otherwise. Most functions take a pointer to an environment controller
data structure as first parameter.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
$\langle$dvfunc {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------- live & death --------------------------------*/ @\\
\mbox{}\verb@ typedef struct __EVControl *pEVControl;@\\
\mbox{}\verb@ typedef struct __EVDriver *pEVDriver;@\\
\mbox{}\verb@@\\
\mbox{}\verb@ pEVControl CreateEVController(pEVDriver pDriv, char *pName, int *iErr);@\\
\mbox{}\verb@ void DeleteEVController(void *pData);@\\
\mbox{}\verb@@\\
\mbox{}\verb@/*-------------------------- driving ---------------------------------*/@\\
\mbox{}\verb@ int EVCDrive(pEVControl self,SConnection *pCon, float fNew);@\\
\mbox{}\verb@ int EVCGetPos(pEVControl self, SConnection *pCon,float *fVal);@\\
\mbox{}\verb@@\\
\mbox{}\verb@/*------------------------ parameters ----------------------------------*/@\\
\mbox{}\verb@ EVMode EVCGetMode(pEVControl self);@\\
\mbox{}\verb@ int EVCSetMode(pEVControl self, EVMode eNew);@\\
\mbox{}\verb@ int EVCSetPar(pEVControl self, char *name, float fNew, SConnection *pCon);@\\
\mbox{}\verb@ int EVCGetPar(pEVControl self, char *name, float *fVal);@\\
\mbox{}\verb@ int EVCList(pEVControl self, SConnection *pCon);@\\
\mbox{}\verb@/*------------------------- logging -----------------------------------*/@\\
\mbox{}\verb@ pVarLog EVCGetVarLog(pEVControl self);@\\
\mbox{}\verb@/*----------------- Interface to SICS interpreter -----------------------*/@\\
\mbox{}\verb@ int EVControlWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ int EVControlFactory(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ @\\
\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 functions in more detail:
\begin{description}
\item [CreateEVController] CreateEVController creates and initialises a
EVController. All interface functions are initialised with default
functions. The first parameter is a pointer to the driver to use, the second
the name of the thing.
\item [DeleteEVController] cleans a EVController from memory. A
KillFunction type for the SICS interpreter.
\item [EVCDrive] drives an EVcontroller to the new value fNew.
\item [EVCGetPos] retrieves the actual value of the environment value from
the device. It is put into fVal.
\item [EVCSetPar] sets a parameter in the EVControllers internal database.
name is the name of the parameter, fNew the value it should get. A
connection object is passed in this call, which will be used for error
reporting and in order to check if the client is permitted to change the
parameter.Parameters recognized are:
\begin{description}
\item [Tolerance] The permissable deviation from the target value before an
error is raised.
\item [Access] which user id has permission to access this controller.
Permited values are: 0 == internal, 1 == Manager, 2 == User, 3 == Spy.
\item [ErrorHandler] determines which error handling strategy will be used
if the EVcontroller gets out of range. Recognized values are:
0 == do nothing, 1 == pause measurement till back in tolerance, 2 ==
interrupt, 3 == drive controller to a value considered safe.
\item [SaveValue] Value to be used as safe value if ErrorHandler 3 is
requested.
\item [Interrupt] The interrupt to issue, when interrupt error handling had
been requested. Will also be used as interrupt if a hardware failure is
detected while driving. Valid values are: 0 == Continue, 1 == Abort
Operation (Count), 2 == Abort Scan, 3 == Abort Batch processing, 4 == Halt
system, 6 == end SICS server.
\item [UpperLimit] The upper limit of values possible for the environment
device.
\item [LowerLimit] The lower limit of values possible for the environment
device.
\end{description}
\item [EVCGetPar] retrieves the value of a parameter. Name must be one of
the recognized names.
\item [EVCGetMode] retrieves the mode the EVController is in.
\item [EVCList] lists all the parameters to pCon.
\item[EVCGetVarLog] returns a pointer to the variable logger for this
controller.
\item [EVControlWrapper] is the interpreter interface to the EVController.
See the documentation for commands understood.
\item [EVControlFactory] is the SICS function needed for creation and
deletion of environment controllers.
\end{description}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap4}
\verb@"evcontroller.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------@\\
\mbox{}\verb@ E N V I R O N M E N T C O N T R O L L E R@\\
\mbox{}\verb@@\\
\mbox{}\verb@ This is the base class for all environment controllers. @\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, Juli 1997@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see implementation file@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSEVCONTROL@\\
\mbox{}\verb@#define SICSEVCONTROL@\\
\mbox{}\verb@#include "varlog.h"@\\
\mbox{}\verb@@$\langle$dvfunc {\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{scrap5}
\verb@"evcontroller.i"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-------------------------------------------------------------------------@\\
\mbox{}\verb@ Environment controller datastructure@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ Mark Koennecke, Juli 1997@\\
\mbox{}\verb@@\\
\mbox{}\verb@---------------------------------------------------------------------------*/@\\
\mbox{}\verb@/*-------- Parameter defines */@\\
\mbox{}\verb@#define TOLERANCE 0@\\
\mbox{}\verb@#define ACCESS 1@\\
\mbox{}\verb@#define ERRORHANDLER 2@\\
\mbox{}\verb@#define INTERRUPT 3@\\
\mbox{}\verb@#define UPLIMIT 4@\\
\mbox{}\verb@#define LOWLIMIT 5@\\
\mbox{}\verb@#define SAFEVALUE 6@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\langle$evdata {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap6}
\verb@"evdriver.i"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-------------------------------------------------------------------------@\\
\mbox{}\verb@ Environment device driver datastructure@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ Mark Koennecke, Juli 1997@\\
\mbox{}\verb@@\\
\mbox{}\verb@---------------------------------------------------------------------------*/@\\
\mbox{}\verb@#define DEVOK 1@\\
\mbox{}\verb@#define DEVFAULT 0@\\
\mbox{}\verb@#define DEVREDO 2@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\langle$evdriv {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@/*-------------------- life & death of a driver --------------------------*/@\\
\mbox{}\verb@ pEVDriver CreateEVDriver(int argc, char *argv[]);@\\
\mbox{}\verb@ void DeleteEVDriver(pEVDriver pDriv);@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

View File

@@ -0,0 +1,110 @@
\subsubsection{LTC-11 Driver}
This is a driver for the Kyocera LTC-11 temperature controller which
is used with the Kryo furnace at SINQ (funny idea, a kryo
furnace). As with the ITC-4 this device has a few special functions
and requires an additional interpreter function which delegates to the
standard one for the general stuff. This is mainly the switching of
the operation mode of the LTC-11. It has two modes: analog mode and
heater mode. For more details about this see the controller
manual. The driver is implemented in the
file ltc11.h and ltc11.c. The following functions, besides those
required for the standard driver, are defined:
\begin{verbatim}
pEVDriver CreateLTC11Driver(int argc, char *argv[]);
int LTC11GetMode(pEVDriver self, int *iMode);
int LTC11SetMode(pEVDriver self, int iMode);
int LTC11Action(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
\end{verbatim}
These are:
\begin{description}
\item[CreateLTC11Driver] creates a driver for a LTC-11. Returns a
pointer to a newly allocated LTC-11 driver or NULL in case of failure.
\item[LTC11GetMode] retrieves the current operation mode of the
LTC-11.
\item[LTC11SetMode] sets the operation mode for the LTC-11.
\item[LTC11Action] The interpreter interface function for the
LTC-11. Implements the special commands for the LTC-11 and calls
EVControlWrapper for anything else.
\end{description}
\subsubsection{The Dillution Cryostat}
This is the old monster cryostat inherited from Saphir. Its driver is
implemented in dilludriv.h and dilludriv.c. There is additional code
for this device in the hardsup subdirectory in the file dillutil.h and
dillutil.c. This device has a fairly involved command protocoll. A
change of the set point requires heater output and and various
parameters for the resistance bridge used for temperature measurement
to be set. Then the set value has to be formatted in a range specific
way in a hexidecimal format. Most of this code is a C adaption of an
earlier F77 code from Elsenhans. Additionally this controller does not
provide a temperature but a resistance value. This resistance value
has to be converted to temperature through a calibration table. Thus
there is an additional file, dilu.tem, which holds this conversion
table.
\subsubsection{Eurotherm Temperature Controller}
SANS is Eurotherm temperature controller somewhere. These controllers
are quite common and the problem may come up again. The Eurotherm
supports not one but several command protocolls, each weirder then the
other. The implementation here serves the EI-Bisynch protocoll. The
thing ahs to be configured manually to run this protocoll. This
protocoll uses specific message formats for communication, the command
protocoll is not plain ASCII. For more details about the protocoll see
the documentation coming with the gadget. Due to this protocoll
restriction the usual Send function of the driver just returns an
error. The driver is impelemwnted
in file eurodriv.h and eurodriv.c. The following functions are
provided:
\begin{verbatim}
pEVDriver CreateEURODriv(int argc, char *argv[]);
/*
these are hooks to implement further functionality which,
I'am sure, Joachim Kohlbrecher will request.
*/
int EuroGetParameter(void **pData, char *pPar, int iLen, float *fVal);
int EuroSetParameter(void **pData, char *pPar, int iLen,
char *pFormat, float fVal);
\end{verbatim}
These are:
\begin{description}
\item[CreateEuroDriver] creates a driver for a Eurotherm controller. Returns a
pointer to a newly allocated Eurotherm driver or NULL in case of failure.
\item[EuroGetParameter] gets one out of many parameters possible with
the Eurotherm. This is a hook to implement further functionality. For
possible values for parameter names pPar see the Eurotherm
documentation. iLen is the length of pPar.
\item[LTC11SetParameter] retrieves the value of a parameter from the
Eurotherm. Again a hook for further expansion. pFormat is the format
how to print the parameter into the command string.
\end{description}
\subsubsection{EL755 Magnet Controller}
This is a driver for the PSI manufactured EL755 magnet
controller. There is additional code for this in the hardsup directory
with files el755\_utility.*. The functions there are documented in that
file. For SICS there is only an adapter to this implemented in
el755driv.h and el755driv.c. The only external function is a driver
creation function with the usual parameters and return values.

144
doc/programmer/event.tex Normal file
View File

@@ -0,0 +1,144 @@
\subsection{SICS Events}
This section lists the callback events known to Sics, their purpose, and
their associated event datastructures when applicable. See the
\ref{inter} section about callbacks for more information about
callbacks. This only defines the integer codes possible. Please be
aware that the implementation of the callbacks is a duty of the SICS
objects generating it. The mentioning of an event code here means it
is used somewhere in SICS but does not mean that it is implemented by
all objects which might implement the event.
This module defines several event related functions as well.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$eFunc {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ int Text2Event(char *pText);@\\
\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 Text2Event } converts a text value into an event code. It returns -1
if the event code is not known, else the apropriate event code.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$VE {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@#define VALUECHANGE 0@\\
\mbox{}\verb@#define MOTDRIVE 1@\\
\mbox{}\verb@#define MONITOR 2 @\\
\mbox{}\verb@#define ROTSTART 3@\\
\mbox{}\verb@#define ROTMOVE 4@\\
\mbox{}\verb@#define SCANEND 5@\\
\mbox{}\verb@#define SCANSTART 6@\\
\mbox{}\verb@#define SCANPOINT 7@\\
\mbox{}\verb@#define WLCHANGE 8@\\
\mbox{}\verb@#define REFLECTIONDONE 9@\\
\mbox{}\verb@#define COUNTSTART 10@\\
\mbox{}\verb@#define COUNTEND 11@\\
\mbox{}\verb@#define FILELOADED 12@\\
\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[VALUECHANGE] This is a variable changing its value. As event data a pointer to the
SicsVariable is passed along. This is defined in sicsvar.h.
\item[MOTDRIVE] a motor is moving. The event data is the current position.
\item[MONITOR] The control value for a counting operation has changed.
The event data is the new value.
\item[ROTSTART] A velocity selector is starting up.
\item[ROTMOVE] A velocity selector changes its rotation speed.
\item[SCANEND] A scan has ended.
\item[SCANSTART] A new scan has been started.
\item[SCANPOINT] A scan point has finished and there is new data.
\item[WLCHANGE] is incoked when the wavelength of a crystal monochromator
changes. The event parameter is a pointer to the wave length or energy
variable being driven. Client code can then get what it needs to know.
\item[REFLECTIONDONE] is issued when a single reflection of a four circle
fiffractometer has been measured.
\item[COUNTSTART] is an event which signals the start of a counting
operation.
\item[COUNTEND] is an event signalling the end of a counting operation.
\end{description}
Furthermore event contains system wide signal codes which are interpreted in
the signal functions provided by each SICS task. These code are
evaluated by the TaskSignalFunction which may be configured for each
SICS task. See the task section for more information. Here, only
possible codes are defined.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
$\langle$VSIG {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@#define SICSINT 300@\\
\mbox{}\verb@#define SICSBROADCAST 301@\\
\mbox{}\verb@#define TOKENGRAB 302@\\
\mbox{}\verb@#define TOKENRELEASE 303@\\
\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[SICSINT] An interrupt has ocurred. The signal data is the interrupt
number which ocurred.
\item[SICSBROADCAST] A message shall be sent to each SICS client. The signal
data is the string to send.
\item[TOKENGRAB] A connection has successfully grabbed the control token.
\item[TOKENRELEASE] A connection has released the control token.
\end{description}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap4}
\verb@"event.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*----------------------------------------------------------------------------@\\
\mbox{}\verb@ E V E N T@\\
\mbox{}\verb@@\\
\mbox{}\verb@ This header file lists the event codes known to SICS. These event code@\\
\mbox{}\verb@ are used in callback functions. Where apropriate, the event data@\\
\mbox{}\verb@ structures are also defined in this file.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, 1997@\\
\mbox{}\verb@@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSEVENT@\\
\mbox{}\verb@#define SICSEVENT@\\
\mbox{}\verb@@$\langle$eFunc {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\langle$VE {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------- Signals for the Signalfunction of each task ------------*/@\\
\mbox{}\verb@@$\langle$VSIG {\footnotesize ?}$\rangle$\verb@ @\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

View File

@@ -0,0 +1,70 @@
\subsection{The FOCUS Averager}
This is a special object for the instrument FOCUS and its Status display
client. In the FOCUS status display the averaged data from a number of
detectors is displayed. Thus there is already a reduced form of data. The
actual raw data would be 150*1024*4 bytes of data and possibly more. Rather
then transporting all this data to the status display client at regular
intervalls it was choosen to implement this averaging process at the server
and only send the reduced form to the status display client. Which is two
arrays of floating point data 1024 items long. This little object implements this
averager.
As all SICS objects this object has a little data structure:
\begin{verbatim}
typedef struct __FocusAverager {
pObjectDescriptor pDes;
pHistMem pHist;
} FocusAverager;
\end{verbatim}
The two fields are the standard object descriptor and a pointer to the
histogram memory object holding the data.
The interface is minimal: it consists just of the factory function for
installing this object into SICS and the actual function doing the
averaging in the interpreter.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$faint {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ int MakeFA(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int FocusAverageDo(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{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
\verb@"faverage.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-----------------------------------------------------------------------@\\
\mbox{}\verb@ F o c u s A v e r a g e@\\
\mbox{}\verb@@\\
\mbox{}\verb@ An averager for FOCUS data. See faverage.tex for more details.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, October 1998@\\
\mbox{}\verb@@\\
\mbox{}\verb@--------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef FOCUSAVERAGE@\\
\mbox{}\verb@#define FOCUSAVERAGE@\\
\mbox{}\verb@@$\langle$faint {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

View File

@@ -0,0 +1,22 @@
\subsection{FOCUS Data File Writing}
FOCUS writes NeXus files. This file writing is impleneted in the files
fowrite.h and fowrite.c. So these files contain the code for writing
FOCUS NeXus files. But there is more to it: FOCUS has a scheme where
the data file is updated any 20 minutes during the course of an
measurement. This scheme is implemented with the following bits and
pieces:
\begin{itemize}
\item Data file updating is triggered by a special task function,
FoTask, which is installed into the SICS tasker when counting starts.
\item The module registers callbacks with the histogram memory which
are invoked when counting starts or ends. These callback functions
take care of craeting a new file and updating it.
\item There is a special command which allows to start and update the
data file manually.
\end{itemize}
As is it not likely that more then one FOCUS writing object is ever
needed, all the data structures are file statics in fowrite.c. The
external interface of this module is just a interpreter initialisation
function and a interpreter interface function for interacting with the
data file writing object.

83
doc/programmer/fupa.tex Normal file
View File

@@ -0,0 +1,83 @@
\subsection{Function Parser}
A utility module to take some of the pain from parsing input while
writing text wrapper function for SICS.
The idea is that you specify an array of function templates.
These function templates will contain function names and argument
information. This module will than parse the input against this
template. It will return -1 if an error occurs and provide error
information.
On success the index of the function found will be returned.
Arguments will have been updated with their proper values.
Invoking functions ist still your job, probably in a switch statement
following the call to the evaluation function.
The function parser supports these different argument types:
\begin{verbatim}
#define FUPATEXT 0 /* text*/
#define FUPAINT 1 /* integer */
#define FUPAFLOAT 2 /* a float */
#define FUPAOPT 3 /* optional argument, in this case text contains it
and iVal indicates its presence
*/
\end{verbatim}
Each template for a function has these fields:
\begin{verbatim}
typedef struct {
char *name;
int iArgs;
int pArgs[MAXARG];
} FuncTemplate, *pFuncTemplate;
\end{verbatim}
\begin{description}
\item[name] the name of the function.
\item[iArgs] The number of arguments to the function.
\item[pArgs] An array with iArgs entries of the integer argument description
types stated above.
\end{description}
On return the actual values of the arguments will be returned as a field in
this structure, according to type.
\begin{verbatim}
typedef struct {
char text[80];
int iVal;
float fVal;
} FuPaArg;
\end{verbatim}
The whole result is returned in the structure defined below:
\begin{verbatim}
typedef struct {
char pError[132];
int iArgs;
FuPaArg Arg[MAXARG];
} FuPaResult;
\end{verbatim}
The fields are: \begin{description}
\item[pError] An error description in case of an error.
\item[iArgs] the number of arguments actually read.
\item[Arg] An array of argumnet result structures as defined above.
\end{description}
Function parsing is done with this function:
\begin{verbatim}
int EvaluateFuPa(pFuncTemplate pTemplate,int iFunc, int argc, char *argv[],
FuPaResult *pRes);
\end{verbatim}
The parameters are:
\begin{description}
\item[pTemplate] a parsing template.
\item[iFunc] The number of functions in the template array.
\item[argc,argv] The text to parse.
\item[pRes] A pointer to a retuned result array.
\end{description}
The return value is -1 on error, or the number of the template identified on
success.
For more information, look on a usage example in counter.c.

463
doc/programmer/hart.eps Normal file
View File

@@ -0,0 +1,463 @@
%!
%%BoundingBox: 24 540 514 775
%%Title: hart
%%CreationDate: Fri May 30 10:02:56 1997
%%Creator: Tgif-3.0-p7 by William Chia-Wei Cheng (william@cs.UCLA.edu)
/tgifdict 4 dict def
tgifdict begin
/tgifellipsedict 6 dict def
tgifellipsedict /mtrx matrix put
/tgifellipse
{ tgifellipsedict begin
/yrad exch def
/xrad exch def
/y exch def
/x exch def
/savematrix mtrx currentmatrix def
x y translate
xrad yrad scale
0 0 1 0 360 arc
savematrix setmatrix
end
} def
end
%%PageBoundingBox: 24 540 514 775
tgifdict begin
/tgifsavedpage save def
1 setmiterlimit
1 setlinewidth
0 setgray
72 0 mul 72 11.00 mul translate
72 128 div 100.000 mul 100 div dup neg scale
gsave
/tgiforigctm matrix currentmatrix def
% BOX
0 setgray
gsave
10 setmiterlimit
gsave
newpath
112 163 moveto 227 163 lineto 227 189 lineto 112 189 lineto
closepath
stroke
grestore
grestore
% BOX
0 setgray
gsave
10 setmiterlimit
gsave
newpath
125 99 moveto 214 99 lineto 214 150 lineto 125 150 lineto
closepath
stroke
grestore
grestore
% RCBOX
0 setgray
gsave
gsave
newpath
202 112 moveto 202 138 lineto 138 138 lineto 138 112 lineto
closepath
stroke
grestore
grestore
% BOX
0 setgray
gsave
10 setmiterlimit
gsave
newpath
368 99 moveto 509 99 lineto 509 176 lineto 368 176 lineto
closepath
stroke
grestore
grestore
% TEXT
0 setgray
/Courier findfont [17 0 0 -17 0 0] makefont setfont
gsave
573 75 moveto (Motor Controller) show
grestore
% TEXT
0 setgray
/Courier findfont [17 0 0 -17 0 0] makefont setfont
gsave
573 139 moveto (Motor Controller) show
grestore
% TEXT
0 setgray
/Courier findfont [17 0 0 -17 0 0] makefont setfont
gsave
573 228 moveto (Counter Box) show
grestore
% TEXT
0 setgray
/Courier findfont [17 0 0 -17 0 0] makefont setfont
gsave
573 305 moveto (Counter) show
grestore
% TEXT
0 setgray
/Courier findfont [17 0 0 -17 0 0] makefont setfont
gsave
368 382 moveto (Histogram) show
368 399 moveto (Memory) show
grestore
% BOX
0 setgray
gsave
10 setmiterlimit
gsave
newpath
560 202 moveto 726 202 lineto 726 240 lineto 560 240 lineto
closepath
stroke
grestore
grestore
% BOX
0 setgray
gsave
10 setmiterlimit
gsave
newpath
330 355 moveto 483 355 lineto 483 445 lineto 330 445 lineto
closepath
stroke
grestore
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
48 266 moveto
483 266 lineto
tgiforigctm setmatrix
5 setlinewidth
stroke
1 setlinewidth
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
432 176 moveto
432 266 lineto
tgiforigctm setmatrix
5 setlinewidth
stroke
1 setlinewidth
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
150 189 moveto
150 266 lineto
tgiforigctm setmatrix
5 setlinewidth
stroke
1 setlinewidth
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
381 266 moveto
381 355 lineto
tgiforigctm setmatrix
5 setlinewidth
stroke
1 setlinewidth
grestore
% TEXT
0 setgray
/Courier findfont [17 0 0 -17 0 0] makefont setfont
gsave
176 292 moveto (TCP/IP) show
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
509 112 moveto
560 74 lineto
tgiforigctm setmatrix
2 setlinewidth
stroke
1 setlinewidth
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
509 138 moveto
560 138 lineto
tgiforigctm setmatrix
2 setlinewidth
stroke
1 setlinewidth
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
509 163 moveto
560 214 lineto
tgiforigctm setmatrix
2 setlinewidth
stroke
1 setlinewidth
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
611 240 moveto
611 291 lineto
tgiforigctm setmatrix
2 setlinewidth
stroke
1 setlinewidth
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
624 240 moveto
624 291 lineto
tgiforigctm setmatrix
2 setlinewidth
stroke
1 setlinewidth
grestore
% TEXT
0 setgray
/Courier findfont [17 0 0 -17 0 0] makefont setfont
gsave
483 75 moveto (RS-232) show
grestore
% BOX
0 setgray
gsave
10 setmiterlimit
gsave
newpath
560 48 moveto 752 48 lineto 752 96 lineto 560 96 lineto
closepath
stroke
grestore
grestore
% BOX
0 setgray
gsave
10 setmiterlimit
gsave
newpath
560 112 moveto 752 112 lineto 752 160 lineto 560 160 lineto
closepath
stroke
grestore
grestore
% BOX
0 setgray
gsave
10 setmiterlimit
gsave
newpath
560 288 moveto 672 288 lineto 672 320 lineto 560 320 lineto
closepath
stroke
grestore
grestore
% TEXT
0 setgray
/Courier findfont [17 0 0 -17 0 0] makefont setfont
gsave
384 126 moveto (Terminal) show
384 143 moveto (Server) show
grestore
% TEXT
0 setgray
/Courier findfont [17 0 0 -17 0 0] makefont setfont
gsave
864 62 moveto (M1) show
grestore
% TEXT
0 setgray
/Courier findfont [17 0 0 -17 0 0] makefont setfont
gsave
864 126 moveto (M2) show
grestore
% TEXT
0 setgray
/Courier findfont [17 0 0 -17 0 0] makefont setfont
gsave
864 190 moveto (M3) show
grestore
% TEXT
0 setgray
/Courier findfont [17 0 0 -17 0 0] makefont setfont
gsave
864 254 moveto (M4) show
grestore
% TEXT
0 setgray
/Courier findfont [17 0 0 -17 0 0] makefont setfont
gsave
864 334 moveto (M5) show
grestore
% OVAL
0 setgray
gsave
gsave
newpath 864 56 32 24 tgifellipse
stroke
grestore
grestore
% OVAL
0 setgray
gsave
gsave
newpath 880 120 32 24 tgifellipse
stroke
grestore
grestore
% OVAL
0 setgray
gsave
gsave
newpath 880 184 32 24 tgifellipse
stroke
grestore
grestore
% OVAL
0 setgray
gsave
gsave
newpath 880 248 32 24 tgifellipse
stroke
grestore
grestore
% OVAL
0 setgray
gsave
gsave
newpath 880 328 32 24 tgifellipse
stroke
grestore
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
752 64 moveto
832 48 lineto
tgiforigctm setmatrix
1 setlinewidth
stroke
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
752 80 moveto
848 112 lineto
tgiforigctm setmatrix
1 setlinewidth
stroke
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
752 144 moveto
848 176 lineto
tgiforigctm setmatrix
1 setlinewidth
stroke
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
752 144 moveto
848 240 lineto
tgiforigctm setmatrix
1 setlinewidth
stroke
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
752 144 moveto
848 320 lineto
tgiforigctm setmatrix
1 setlinewidth
stroke
grestore
% TEXT
0 setgray
/Courier findfont [17 0 0 -17 0 0] makefont setfont
gsave
96 238 moveto (Data Aquisition Computer) show
grestore
grestore
tgifsavedpage restore
end
%MatchingCreationDate: Fri May 30 10:02:56 1997

BIN
doc/programmer/hart.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@@ -0,0 +1,656 @@
\subsection{Histogram memory}
A histogram memory is the interface to a large multidetector. This is quite
a complex piece of equipment. It does not only provide lots of data but also
has a lot of configuration options. Things which need configuration are:
histogram mode, overflow mode, measurement mode and the layout of the
histograms. Let's discuss these different modes first.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$Modes {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef enum {@\\
\mbox{}\verb@ eHTransparent,@\\
\mbox{}\verb@ eHNormal,@\\
\mbox{}\verb@ eHTOF,@\\
\mbox{}\verb@ eHStrobo,@\\
\mbox{}\verb@ eHRPT@\\
\mbox{}\verb@ } HistMode;@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro defined by scraps ?, ?.
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
A histogram memory can be operated in transparent mode. It has not yet been
defined what this means but it is sort of storing raw data from the detector
without any summing or processing. Normal mode is better defined, this is
sorting and summing data from the detector into apropriate bins for each
detector. Time is not resolved. TOF mode means time of flight mode. In this
mode incoming is not only sorted and summed into the correct detector bins
but also resolved in time (which means energy for neutrons). This means for
each detector there is a histogram counts versus time. Similar is
stroboscopic mode (eHStrobo). In stroboscopic mode there is a histogram
counts versus pulses for each physical detector. The bin switching is done
via a secondary hardware signal or from software. This is useful for
measuring diffraction data versus oscillating environment conditions. eHRPT
is a special mode for the HRPT Cerca detector. It requires special handling,
this is why there is a special flag.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$Modes {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef enum {@\\
\mbox{}\verb@ eOIgnore,@\\
\mbox{}\verb@ eOCeil,@\\
\mbox{}\verb@ eOCount,@\\
\mbox{}\verb@ eReflect@\\
\mbox{}\verb@ } OverFlowMode;@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro defined by scraps ?, ?.
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
Histogram memories may support different schemes for handling overflow
conditions. In this condition there are more counts than fit into the
configured
binwidth. The simplest thing to do is to ignore the condition and simply
wrap over to zero (eOIgnore). The other mode is to keep the bin at the
highest count possible (eOCeil). More sophisticated histogram memories
maintain a separate list where all those overflowed bins are registered.
This is eOCount. eReflect has nothing to do with overflows. It says that the
histogram should be reflected. This means counter 1 becomes counter max etc.
This is special for HRPT. It happens to live in the OverFlowMode enum because
this is really a sub mode descriptor.
The measurement mode is the simple counter operation mode: wait for a timer
or wait for a monitor to run full.
The layout of the histogram memory (HM) is defined by the rank (i.e. the number
of dimensions of the HM, the number of points in each dimension and by the
binwidth in bits for each bin. For TOF and stroboscopic modes information
about the binning in time or pulses is needed as well. Needless to say that
these values have to match the geometry of the detector.
Histograms usually have a number type associated with them. In order to
minimise conversion overhead in the logical object, the data size will
defined by a typedef, HistInt.
There is a scheme for handling all this configuration information
which may even be more for a Histogram memory with a specific
driver. There is a dictionary of configuration options in the logical
histogram memory object. These options can be set with a special
command. Then on initialisation first the logical histogram memory
evaluates the general options and then the driver in its Config
function evaluates the driver specific options.
\subsubsection{The Histogram memory driver}
Adhering to the Sics paradigm of dividing any device into a logical device
and a hardware driver, the Sics histogram memory needs drivers as well. This
section describes this driver interface. For an overview, see the structure
definition:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
$\langle$HistType {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __HistDriver {@\\
\mbox{}\verb@ /* configuration data */@\\
\mbox{}\verb@ HistMode eHistMode;@\\
\mbox{}\verb@ OverFlowMode eFlow;@\\
\mbox{}\verb@ int iRank;@\\
\mbox{}\verb@ int iDims[MAXDIM];@\\
\mbox{}\verb@ int nDim;@\\
\mbox{}\verb@ int iLength;@\\
\mbox{}\verb@ int iBinWidth;@\\
\mbox{}\verb@ float fTime[MAXCHAN];@\\
\mbox{}\verb@ int iTimeChan;@\\
\mbox{}\verb@ /* counting operations data */@\\
\mbox{}\verb@ CounterMode eCount;@\\
\mbox{}\verb@ float fCountPreset;@\\
\mbox{}\verb@ /* status flags */@\\
\mbox{}\verb@ int iReconfig;@\\
\mbox{}\verb@ int iUpdate;@\\
\mbox{}\verb@ /* interface functions */@\\
\mbox{}\verb@ int (*Configure)(pHistDriver self,@\\
\mbox{}\verb@ SConnection *pCon,@\\
\mbox{}\verb@ pStringDict pOpt,@\\
\mbox{}\verb@ SicsInterp *pSics);@\\
\mbox{}\verb@ int (*Start)(pHistDriver self, @\\
\mbox{}\verb@ SConnection *pCon);@\\
\mbox{}\verb@ int (*Halt)(pHistDriver self);@\\
\mbox{}\verb@ int (*GetCountStatus)(pHistDriver self,@\\
\mbox{}\verb@ SConnection *pCon);@\\
\mbox{}\verb@ int (*GetError)(pHistDriver self, @\\
\mbox{}\verb@ int *iCode,@\\
\mbox{}\verb@ char *perror,@\\
\mbox{}\verb@ int iErrlen);@\\
\mbox{}\verb@ int (*TryAndFixIt)(pHistDriver self,@\\
\mbox{}\verb@ int iCode);@\\
\mbox{}\verb@ int (*GetData)(pHistDriver self,@\\
\mbox{}\verb@ SConnection *pCon);@\\
\mbox{}\verb@ int (*GetHistogram)(pHistDriver self,@\\
\mbox{}\verb@ SConnection *pCon,@\\
\mbox{}\verb@ int i,@\\
\mbox{}\verb@ int iStart, int iEnd,@\\
\mbox{}\verb@ HistInt *pData);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int (*SetHistogram)(pHistDriver self,@\\
\mbox{}\verb@ SConnection *pCon,@\\
\mbox{}\verb@ int i,@\\
\mbox{}\verb@ int iStart, int iEnd,@\\
\mbox{}\verb@ HistInt *pData);@\\
\mbox{}\verb@ long (*GetMonitor)(pHistDriver self, @\\
\mbox{}\verb@ int i,@\\
\mbox{}\verb@ SConnection *pCon);@\\
\mbox{}\verb@ float (*GetTime)(pHistDriver self,@\\
\mbox{}\verb@ SConnection *pCon);@\\
\mbox{}\verb@ int (*Preset)(pHistDriver self,@\\
\mbox{}\verb@ SConnection *pCon,@\\
\mbox{}\verb@ HistInt iVal);@\\
\mbox{}\verb@ int (*Pause)(pHistDriver self,@\\
\mbox{}\verb@ SConnection *pCon);@\\
\mbox{}\verb@ int (*Continue)(pHistDriver self,@\\
\mbox{}\verb@ SConnection *pCon);@\\
\mbox{}\verb@ int (*FreePrivate)(pHistDriver self);@\\
\mbox{}\verb@ void *pPriv;@\\
\mbox{}\verb@ } HistDriver;@\\
\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}
Quite a lot, but a histogram memory is quite a complex piece of equipment.
The configuration information is in the elements EhistMode, eOverFlowMode,
iRank, iDims and iBinWidth fields. iDim and nDim desribe the logical
dimensions of the histogram memory. These may be different from the
dimensions used for data transfer. For instance the SANS detector is
handled internally as 1600+ numbers where it really is a filed o
128*128.
Additionally there is an array of
floating point values which denote the time binning for time-o-flight
operation or the stroboscopic binning axis in stroboscopic mode.
The fields fPreset and CounterMode hold the counting parameter data.
Than there are two status fields. The first is iReconfig. This will be set
to true, whenever any changes to the configuration to the HM are made. This
will be tested against when starting a measurement and will force a
configuration call to be issued. A call to the interface function Configure
clears this flag. The other flag is iUpdate. This is only useful when an in
memory copy of the histogrammed data is maintained on the host computer.
This flag is set when a count gets started and gets cleared when counting is
finished and all data has been transferred.
The next part defines the hardware interface functions to the histogram
memory. Each of these functions must be defined by any complete
implementation of a HM driver. If not stated otherwise these functions
return 1 on success and 0 on failure. All functions take a pointer to their
HistDriver structure as first parameter. Many functions have a pointer to an
SConnection as parameter. This connection will be used for error reporting.
\begin{itemize}
\item {\bf Configure} configures the histogram memory to the specifications
given in the fields of the HMdriver structure. Further driver specific
information can be read from the options dictionary passed in.
\item {\bf Start} starts a counting operation according to the current
settings of the counter mode parameters.
\item {\bf Halt} implements an emergency stop of a counting operation.
\item {\bf GetCountStatus} serves to monitor the status of the counting
operation. Possible return values to this call are:
\begin{itemize}
\item HWBUSY when still counting.
\item HWNoBeam when the monitor is to low.
\item HWIDLE or OKOK when nothing is going on.
\item HWFault when there is an error on the device.
\end{itemize}
\item {\bf GetError} will be called whenever an error has been detected on
the device. The task is to put an internal error code into the iCode
parameter. The string parameter error will be filled with a text description
of the error. But maximum iLen characters will be transferred to the error
string in order to protect against memory corruption. Therefore iLen must be
the maximum field length of error.
\item {\bf TryAndFixIt} is the next function called in case of an error on
the device. Its second parameter is the internal code obtained in the ICode
parameter of the call to GetError. The task of this function is to examine
the error code and do whatever is possible in software to fix the problem.
TryAndFixIt returns one of the following values:
\begin{itemize}
\item MOTREDO when the error could be fixed, but the upper level code will
need to rerun the command which failed.
\item MOTFAIL when the software is unable to fix the problem and a real
mechanic with a hammer is needed (or somebody able to reboot!).
\item MOTOK when the error was fixed and nor further action is necessary.
\end{itemize}
\item {\bf GetData} transfers all the data collected in the HM into the
host computers memory.
\item {\bf GetHistogram} copies the histogram number i into the data space
given by the pointer to a long array. A conversion from different binwidth
to long is performed as well.
\item {\bf SetHistogram} presets the histogram number i with the data
given in lData. A conversion from different binwidth
to long is performed as well. iStart and iStop define the start and end of
the stretch of histogram to replace.
\item {\bf GetMonitor} returns the counts in the monitor i. Returns a
negative value on error. The error will have been printed to pCon.
\item {\bf GetTime} returns the actual counting time.
\item {\bf Preset} initializes the histogram memory to the value given by
iVal.
\item {\bf Pause} pauses data collection.
\item {\bf Continue} continues a paused data collection.
\item {\bf FreePrivate} will be called automatically by DeleteHistDriver and
has the task to remove the private data installed by implementations of an
actual histogram memory driver.
\end{itemize}
The last entry in the HistDriver structure is a pointer to void. Rather then use the overlay structure as with motor drivers, histogram
memory stores driver specific information in a driver specific sub
data structure. This is the pointer to pPrivate. KillPrivate is a
function which is able to delete the driver specific data structure
properly.
As all the burden is up to the implementation of the histogram memory driver
only these few functions operate on histogram memory drivers in general:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap4}
$\langle$HistDrivProt {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ pHistDriver CreateHistDriver(pStringDict pDict);@\\
\mbox{}\verb@ void DeleteHistDriver(pHistDriver self);@\\
\mbox{}\verb@ int HistDriverConfig(pHistDriver self, pStringDict pOpt,@\\
\mbox{}\verb@ SConnection *pCon);@\\
\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}
CreateHistDriver creates a new HistDriver data structure and returns it. Or
NULL when the memory is exhausted. It also initialises the options database
in pDict to the apropriate values.
DeleteHistDriver removes a histogram memory driver from memory. It will
automatically try and call Freeprivate in order to remove driver specific
data. Than an the rest is removed. After this call self will point to
rubbish.
\subsubsection{The histogram memory object}
Most of the HM data will be held with the driver as it is needed there for
performing operations. Accordingly the datastructure associated with the
histogram memory object is fairly simple:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap5}
$\langle$HistST {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __HistMem {@\\
\mbox{}\verb@ pObjectDescriptor pDes;@\\
\mbox{}\verb@ int iAccess;@\\
\mbox{}\verb@ int iExponent;@\\
\mbox{}\verb@ pHistDriver pDriv;@\\
\mbox{}\verb@ int iInit;@\\
\mbox{}\verb@ pICountable pCountInt;@\\
\mbox{}\verb@ pICallBack pCall;@\\
\mbox{}\verb@ pStringDict pOption;@\\
\mbox{}\verb@ HistInt *iLocalData;@\\
\mbox{}\verb@ int iLocalLength;@\\
\mbox{}\verb@ int iLocalUpdate;@\\
\mbox{}\verb@ time_t tLocal;@\\
\mbox{}\verb@ int iUpdateIntervall;@\\
\mbox{}\verb@ } HistMem;@\\
\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}
According to the general Sics object interface the first field is the object
descriptor. Note, that the histogram memory has to adhere to the countable
objects interface. iAccess is the access code used to control user
interaction with the HM. iExponent is the force of 10 used for calculating
the actual preset value for counting in monitor mode.
However, note, that all configuration commands will
require Manager privilege at least. Then there is a pointer to the
driver followed by pointers to the interfaces implemented by the histogram
memory. pOption is a string dictionary of configuration options for the
histogram memory.
In order to save network bandwidth and for efficiency the histogram memory
object buffers the histogram memory in memory. The histogram itself resides
in iLocalData. iLocalLength is the length of iLocalData. iLocalUpdate is a
flag which will be set when counting operations (histogram changes ) are
going on and cleared when the histogram has been completely read.
When counting the local data will be updated only at certain intervalls.
This is a configuration option. iUpdateIntervall is that intervall in
seconds, tLocal is the time for the next scheduled update.
The interaction with the histogram memory can be classified into four
groups: basic initialisation and destruction, configuration, counting and
data retrieval. The first group to look at are the basics:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap6}
$\langle$Protos {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ pHistMem CreateHistMemory(char *drivername);@\\
\mbox{}\verb@ void DeleteHistMemory(void *self);@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro defined by scraps ?, ?, ?, ?, ?.
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
CreateHistMem creates a new histogram memory.
On error this
call returns NULL. On success a pointer to the new histogram memory object.
CreateHistMem does NOT configure anything! A driver gets selected according
to the driver name.
DeleteHistMemory removes a histogram memory from computer memory.
Any references to self afterwards will
point to rubbish.
The next group of functions refer to configuration.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap7}
$\langle$Protos {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ int HistGetOption(pHistMem self, char *name, char *result, int iResultLen);@\\
\mbox{}\verb@ int HistSetOption(pHistMem self, char *name, char *value);@\\
\mbox{}\verb@ int HistConfigure(pHistMem self, SConnection *pCon, SicsInterp *pSics);@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro defined by scraps ?, ?, ?, ?, ?.
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
HistGetOption caters for the retrieval of the current option given in name.
Maximum iResultLen characters of result will be copied into result, or an
error message if things go wrong.
HistSetOption sets the option name to value specified in value. No error
checking except availability of the option and permission is done here.
HistConfigure updates the internal datastructures from the dictionary and
does the actual configuration of the HM. Tons of error messages will be
printed to pCon.
Valid names for the options in the dictionary are all the names in the
histogram datastructure. Please note, that counting options are handled
separately (see below). Additionally there may be driver specific options
available. For iDim iRank numbers are expected which represent the
dimensions of the HM.
The functions for counting and manipulation of counting parameters have been
separated from the rest of the configuration. The reason is that the main
configuration will only be performed by highly privileged users, whereas
the counting operations will be accessible by normal users. Counting is
controlled by the following functions:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap8}
$\langle$Protos {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ float GetHistPreset(pHistMem self);@\\
\mbox{}\verb@ int SetHistPreset(pHistMem self, float fVal);@\\
\mbox{}\verb@ CounterMode GetHistCountMode(pHistMem self);@\\
\mbox{}\verb@ int SetHistCountMode(pHistMem self, CounterMode eNew);@\\
\mbox{}\verb@ long GetHistMonitor(pHistMem self, int i, SConnection *pCon);@\\
\mbox{}\verb@ const float *GetHistTimeBin(pHistMem self, int *iLength);@\\
\mbox{}\verb@ int GetHistLength(pHistMem self);@\\
\mbox{}\verb@ int GetHistDim(pHistMem self, int iDim[MAXDIM], int *nDim);@\\
\mbox{}\verb@ float GetHistCountTime(pHistMem self,SConnection *pCon);@\\
\mbox{}\verb@ int HistDoCount(pHistMem self, SConnection *pCon);@\\
\mbox{}\verb@ int HistBlockCount(pHistMem self, SConnection *pCon);@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro defined by scraps ?, ?, ?, ?, ?.
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
The first four functions are simple parameter enquiry and manipulation
functions. GetHistMonitor returns the count on monitor number i for the
histogram memory. This function returns a negative value when the value
specified for i is invalid.
HistDoCount actually starts a counting operation. It will not
block and wait for counting to finish. Please note, that many counting
manipulation functions are hidden in the functions of the countable
interface, which the HM has to implement.
HistBlockCount also starts counting. But will block until counting has
finished.
Another set of functions is needed for manipulation of the data in the
histogram memory:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap9}
$\langle$Protos {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ int SetHistogram(pHistMem self, SConnection *pCon,@\\
\mbox{}\verb@ int i,int iStart, int iEnd, HistInt *lData);@\\
\mbox{}\verb@ int GetHistogram(pHistMem self, SConnection *pCon,@\\
\mbox{}\verb@ int i,int iStart, int iEnd, HistInt *lData, int iDataLen);@\\
\mbox{}\verb@ HistInt *GetHistogramPointer(pHistMem self,SConnection *pCon);@\\
\mbox{}\verb@ int PresetHistogram(pHistMem self, SConnection *pCon, HistInt lVal);@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro defined by scraps ?, ?, ?, ?, ?.
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
For histogram I/O the following aproach has been taken: Histograms are kept
as linear arrays of data regardless of the layout of the detector. It is the
task of upper level code to map the right histogram to the right position.
This aproach was choosen for two reasons: 1.) simplification of interface,
2.) easier to retrieve smaller chunks of data at a time.
With both SetHistogram and GetHistogram the parameter i denotes the
histogram to retrieve. A value of -1 retrieves the whole lot. iStart and
iEnd allow for extraction of a subset of a histogram. These values get
ignored when trying to retrieve a whole HM content. These routines
perform conversion to and from long to the binwidth of the HM. SetHistogram
initialises the HM from the lData provided. GetHistogram reads an histogram
into lData but maximum iDataLen items. PresetHistogram presets the HM to the
value lVal. Can be used to clear the HM.
The histogram memory object buffers the histograms for a adjustable
period of time. GetHistogramPointer retrieves a pointer to the local
histogram buffer. It also makes sure, that the histogram has been
updated if appropriate. This is provided for efficiency and saves some
memory copying and duplication of data during operations. Thus memory
consumption can be reduced. However, the drawback is that you mess
directly with the histogram memory content which is potentially
dangerous. Use this method with great care!
A last group of functions are those needed to interface to the Sics
interpreter:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap10}
$\langle$Protos {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ int MakeHistMemory(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int HistAction(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 defined by scraps ?, ?, ?, ?, ?.
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
MakeHistMem is supposed to be called with two parameters: name and driver
which denote the name of the HM object and the type of driver to use. If all
is well, this call will create a command named name. Remember, that
the HM is
not yet configured!
HistAction is supposed to be where the action goes. HistAction understands
the commands:\begin{itemize}
\item {\bf name config option value} sets a configuration option.
\item {\bf name init} configures the HM.
\item {\bf name Preset val} returns the preset value if val is missing, else
it sets it.
\item {\bf name Mode val} returns the counting mode if val is missing, else
it sets it.
\item {\bf name count} starts a counting operation.
\item {\bf name get number} gets histogram number. -1 as histogram number
gets all.
\item {\bf name set number val........} sets histogram number to the values
following.
\item {\bf name clear val} sets all the HM to val.
\end{itemize}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap11}
\verb@"HistMem.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------@\\
\mbox{}\verb@ H I S T M E M @\\
\mbox{}\verb@@\\
\mbox{}\verb@ header for the histogram memory object for SICS.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see implementation file.@\\
\mbox{}\verb@ Mark Koennecke, April 1997@\\
\mbox{}\verb@-----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSHISTMEM@\\
\mbox{}\verb@#define SICSHISTMEM@\\
\mbox{}\verb@#define MAXDIM 3@\\
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __HistDriver *pHistDriver;@\\
\mbox{}\verb@ typedef struct __HistMem *pHistMem;@\\
\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
\mbox{}\verb@ typedef int HistInt;@\\
\mbox{}\verb@/*@\\
\mbox{}\verb@ 32 bit integer on a DigitalUnix@\\
\mbox{}\verb@*/@\\
\mbox{}\verb@@$\langle$Modes {\footnotesize ?, \ldots\ }$\rangle$\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------*/@\\
\mbox{}\verb@@$\langle$Protos {\footnotesize ?, \ldots\ }$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap12}
\verb@"HistDriv.i"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*---------------------------------------------------------------------------@\\
\mbox{}\verb@ H I S T D R I V@\\
\mbox{}\verb@ internal header file which includes the definition of the Histogram memory@\\
\mbox{}\verb@ driver structure.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, April 1997@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSHISTDRIV@\\
\mbox{}\verb@#define SICSHISTDRIV@\\
\mbox{}\verb@#define MAXCHAN 4096@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\langle$HistType {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@$\langle$HistDrivProt {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap13}
\verb@"HistMem.i"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*---------------------------------------------------------------------------@\\
\mbox{}\verb@ H I S T M E M -- Internal@\\
\mbox{}\verb@ internal header file which includes the definition of the Histogram memory@\\
\mbox{}\verb@ data structure.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, April 1997@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSHISTMEMINT@\\
\mbox{}\verb@#define SICSHISTMEMINT@\\
\mbox{}\verb@@$\langle$HistST {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

View File

@@ -0,0 +1,50 @@
\subsubsection{Simulated histogram memory driver}
This is a driver for a simulated histogram memory needed for software
testing.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$Protos {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ pHistDriver CreateSIMHM(pStringDict pOpt);@\\
\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 only visible function defined is a creation function. Please note that
all the interface functions need to be defined as well. For implementation
of the countable interface this thing will use the simulated counter. All
data retrieval members will return random numbers in the required amount.
The call to configure will actually do nothing.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
\verb@"histsim.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------@\\
\mbox{}\verb@ H I S T S I M@\\
\mbox{}\verb@@\\
\mbox{}\verb@ A simulated histogram memory for software testing.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, April 1997@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see implementation file.@\\
\mbox{}\verb@---------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSHISTSIM@\\
\mbox{}\verb@#define SICSHISTSIM@\\
\mbox{}\verb@@$\langle$Protos {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

216
doc/programmer/hkl.tex Normal file
View File

@@ -0,0 +1,216 @@
\subsection{Crystallographic Computations}
The HKL object performs standard four circle calculations. I.e., given a UB
matrix it calculates the four circle diffractometer setting angles required
for a reflection with index hkl. The UB must be determined from a set of
reflections found manually or automatically. This is done in an offline
program. The code in this module is a direct reimplementation of fortran code
provided by Jean Allibon, ILL with the MAD four circle diffractometer
control program in ANSI-C. For theory, see the contribution by
W.C. Hamilton in the International Tables for Crystallography, 1974 edition.
The object uses the following object data structure:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$hkldat {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __HKL {@\\
\mbox{}\verb@ pObjectDescriptor pDes;@\\
\mbox{}\verb@ double fUB[9];@\\
\mbox{}\verb@ MATRIX UBinv;@\\
\mbox{}\verb@ double fLambda;@\\
\mbox{}\verb@ int iManual;@\\
\mbox{}\verb@ double fLastHKL[5];@\\
\mbox{}\verb@ int iNOR;@\\
\mbox{}\verb@ int iQuad;@\\
\mbox{}\verb@ pMotor pTheta;@\\
\mbox{}\verb@ pMotor pOmega;@\\
\mbox{}\verb@ pMotor pChi;@\\
\mbox{}\verb@ pMotor pPhi;@\\
\mbox{}\verb@ pMotor pNu;@\\
\mbox{}\verb@ pSelVar pMono;@\\
\mbox{}\verb@ long lID;@\\
\mbox{}\verb@ } HKL;@\\
\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 fields are more or less self explaining:
\begin{description}
\item[pDes] The standard object descriptor.
\item[fUB] The UB matrix.
\item[iUB] is a flag which spcifies if a UB is specified.
\item[fLambda] The wavelength of the neutrons.
\item[iManual] A flag which defines if the wavelength has been set manually
or is updated automatically from a wavelength variable.
\item[fLastHKL] the HKL of the last reflection calculated.
\item[iNor] a flag for normal beam calculation mode.
\item[pTheta] The two theta motor. All motor are needed for boundary
checking.
\item[pOmega] The omega axis motor.
\item[pChi] The chi axis motor.
\item[pPhi] the phi axis motor.
\item[pNu] the nu axis motor for normal beam geometry.
This is detector tilt.
\item[pMono] The selector variable doing the wavelength.
\end{description}
The wavelength is a bit tricky. As it would be to time consuming to read two
motors each time a calculation is performed, the lambda variable is updated
by registering a callback with the selector variable handling the
monochromator wavelength. As TriCS will be run with two monochromators on a
lift a means has to be provided to change the selector variable online. An
additonal feature is that the wavelength can be manipulated manually. This
adresses the issue that automatic wavelength may be inaccurate due to
lazy instrument scientists not adjusting their instruments.
In terms of an interface the following functions will be provided by this
module:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$hklint {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __HKL *pHKL;@\\
\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
\mbox{}\verb@ pHKL CreateHKL(pMotor pTheta, pMotor pOmega, @\\
\mbox{}\verb@ pMotor pChi, pMotor pPhi, pMotor pNu);@\\
\mbox{}\verb@ void DeleteHKL(void *pData);@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ int HKLFactory(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
\mbox{}\verb@ int SetWavelengthVariable(SConnection *pCon, pHKL self, pSelVar pVar);@\\
\mbox{}\verb@ int SetWavelengthManual(pHKL self, float fVal);@\\
\mbox{}\verb@ int SetUB(pHKL self, float fUB[9]);@\\
\mbox{}\verb@ int GetUB(pHKL self, float fUB[9]);@\\
\mbox{}\verb@ int SetNOR(pHKL self, int iNOB);@\\
\mbox{}\verb@ int GetLambda(pHKL self, float *fVal);@\\
\mbox{}\verb@ int GetCurrentHKL(pHKL self, float fVal[3]);@\\
\mbox{}\verb@ int GetCurrentPosition(pHKL self, SConnection *pCon, float fPosition[4]);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int CalculateSettings(pHKL self, float fHKL[3], float fPsi, int iHamil,@\\
\mbox{}\verb@ float fSet[4],SConnection *pCon);@\\
\mbox{}\verb@ int RunHKL(pHKL self, float fHKL[3], float fPsi, int iHamil, SConnection@\\
\mbox{}\verb@ *pCon);@\\
\mbox{}\verb@ int DriveHKL(pHKL self, float fHKL[3], float fPsi, int iHamil,@\\
\mbox{}\verb@ SConnection *pCon);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int DriveSettings(pHKL self, float fSet[4],SConnection *pCon);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int HKLAction(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}
All functions return 0 on failure, 1 on success if not stated otherwise.
Most functions take a pointer to a HKL data structure as first parameter.
The function in more detail:
\begin{description}
\item[CreateHKL] creates a HKL object. The parameters are pointers to the
four four circle motors. Returns NULL on failure, a pointer to the new
object on success.
\item[DeleteHKL] properly removes an HKL object from the system.
\item[HKLFactory] The factory function which initialises an HKL object from
the initialisation script.
\item[SetWavelengthVariable] sets a new wavelength variable. Installs all
necesarry callbacks for automatic update.
\item[SetWaveLengthManual] deinstall all callbacks and forces the wavelength
to the value specified a second parameter.
\item[SetUB] sets the UB matrix.
\item[SetNOR] sets the normal beam calculation flag to iNOR.
\item[CalculateSettings] is the heart of this all. As the name suggests
calculates the settings for a four circle diffractometer. The parameters
are:
\begin{description}
\item[self] A pointer to a HKL data structure.
\item[fHKL] The reflection indices to calculate the settings for.
\item[fPsi] The psi value for the reflection. For psi scans. Set to 0 if not
used.
\item[iHamil] The index of the hamilton position to calculate. Can be an
integer between 0 to 8. 0 denotes the normal case.
\item[fSet] contains the required settings if the function returns with
success. 0 = two theta, 1 = omega, 2 = chi, 3 = phi.
\end{description}
The function returns 1 on success, a negative value on failure. Possible
error returns are:
\begin{description}
\item[HKLIMPOSSIBLE] the calculation was impossible.
\item[HKLTHETALIMIT] a setting could be calculated but can not be accessed
due to a limit on two theta.
\end{description}
\item[DriveHKL] calculates a setting and drives to the position. The
parameters are the same as with CalculateSettings. With the addition of a
pointer to the connection object doing the command for error messages and
everything. The error returns are the same as with CalculateSettings
well. With the addition of HKJMOTFAIL, which means that a motor failed to
drive properly.
\item[DriveSettings] drives to the the settings given in fSet.
\item[HKLAction] is the interpreter wrapper function for the HKL object.
\end{description}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
\verb@"hkl.i"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-------------------------------------------------------------------------@\\
\mbox{}\verb@ H K L@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Internal data structure description. See hkl.h, c,w for more details.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, February 1998@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@@$\langle$hkldat {\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@"hkl.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*---------------------------------------------------------------------------@\\
\mbox{}\verb@ H K L@\\
\mbox{}\verb@ This SICS object performs angle setting calculations for a four circle @\\
\mbox{}\verb@ diffractometer. The heart of this code is a C transcriptions of routines@\\
\mbox{}\verb@ written by Jean Allibon at ILL for the MAD program. Theory is explained in@\\
\mbox{}\verb@ the article by W. C. Hamilton in International Tables for Crystallography,@\\
\mbox{}\verb@ 1974 edition.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see copyright.h@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, February 1998@\\
\mbox{}\verb@@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSHKL@\\
\mbox{}\verb@#define SICSHKL@\\
\mbox{}\verb@#include "selector.h"@\\
\mbox{}\verb@#include "selvar.h"@\\
\mbox{}\verb@@$\langle$hklint {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif @\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

111
doc/programmer/hklscan.tex Normal file
View File

@@ -0,0 +1,111 @@
\subsection{hklscan}
hklscan is an object which implements scanning in reciprocal space. It belongs
to the four circle diffraction line of commands. It requires the hkl object
for doing four circle calculations and a scan object for doing the scanning.
The scan object is configured by overloading its WriteScanPoints and
ScanDrive functions to do the right thing for this. Thus most of the work
is done in scan and hkl.
hklscan has its own data structure looking like this:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$hklscandat {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __HKLSCAN {@\\
\mbox{}\verb@ pObjectDescriptor pDes;@\\
\mbox{}\verb@ pScanData pScan;@\\
\mbox{}\verb@ pHKL pCalc; @\\
\mbox{}\verb@ float fStart[3];@\\
\mbox{}\verb@ float fStep[3];@\\
\mbox{}\verb@ float fPos[3];@\\
\mbox{}\verb@ } sHklscan;@\\
\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 object descriptor.
\item[pScan] The scan object used for scanning.
\item[pCalc] The hkl object used for crystallographic computations.
\item[fStart] The start values in H, K, L for scanning.
\item[fStep] The step width in H, K, L.
\item[fPos] The last position in H, K, L.
\end{description}
The hklscan object defines the following external interface:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$hklscanfunc {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __HKLSCAN *pHklscan;@\\
\mbox{}\verb@/*--------------------------------------------------------------------------*/@\\
\mbox{}\verb@ int HklScan(pHklscan self, SConnection *pCon, int iNP, int iMode,@\\
\mbox{}\verb@ float fPreset);@\\
\mbox{}\verb@/*---------------- interpreter functions -----------------------------------*/@\\
\mbox{}\verb@ int HklscanFactory(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ int HklscanAction(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{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
\verb@"hklscan.i"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-------------------------------------------------------------------------@\\
\mbox{}\verb@ Internal data structure for the hklscan object. DO NOT MODIFY. @\\
\mbox{}\verb@ Modifications only in hklscan.i@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ Mark Koennecke, June 1999@\\
\mbox{}\verb@--------------------------------------------------------------------------*/@\\
\mbox{}\verb@@$\langle$hklscandat {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap4}
\verb@"hklscan.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------@\\
\mbox{}\verb@ H K L S C A N@\\
\mbox{}\verb@@\\
\mbox{}\verb@ A class for doing scans in reciprocal space. This makes only sense at an@\\
\mbox{}\verb@ four circle diffractometer. Most of the work is done in the HKL and scan@\\
\mbox{}\verb@ objects. This class just adapts and used both objects to do the right thing.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, June 1999@\\
\mbox{}\verb@---------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef HKLSCAN@\\
\mbox{}\verb@#define HKLSCAN@\\
\mbox{}\verb@@$\langle$hklscanfunc {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

32
doc/programmer/ini.tex Normal file
View File

@@ -0,0 +1,32 @@
\subsection{Initialisation file management}
This module supports initialisation files with a simple structure.
This is used to hold the internal SICS server options which are
installed with the SicsOption initialisation commands. All the file
handling stuff is dead code not used by SICS as of current. Any line
is intended to
contain one name value pair separated by an equlity sign. Lines beginning
with a \verb+#+ are treated as comments, other lines not conforming to the name =
value scheme are ignored. Another option (and the currently preferred one)
to get values into the initialisation database is to use a special command
SicsOption from the SICS initialisation file.
These initialisation files are manipulated through
the ifile module, implemented in ifile.h and ifile.c. The class in more
detail:
After reading the configuration options are stored in memory as a linked list with entries if the type shown below. \begin{verbatim}
typedef struct __IFileE
{
char *name;
char *value;
struct __IFileE *pNext;
} IPair;
\end{verbatim}
This datastructure is manipulated using the following functions:\begin{itemize}
\item {\bf IPair *IFReadConfigFile(FILE *fp) }, expects as input a pointer to the configuration file. Than the function will read the file and initialise the configuration linked list from the data found in the file. On success a pointer to the head of the linked list is returned which is to be used in further calls to the configuration management functions. On failure NULL is returned.
\item {\bf char *IFindOption(IPair *pList,char *name) }. Input is a pointer to a configuration list as returned by IFReadConfigFile and the name of the option requested (case sensitive). If this option exists a pointer to its value will be returned, else NULL. Never, ever, free the returned pointer as it belongs to this module.
\item {\bf IPair *IFAddOption(IPair *pList,char *name, char *value) } Adds a name value pair to the list specified as first parameter. Returns a pointer to the new list including the new name value pair on succes, else the old pointer specified as input.
\item {\bf int IFSaveOptions(IPair *pList,FILE *fp) }. Saves the options in the list to the file fp.
\item {\bf void IFDeleteOptions(IPair *pList) }. Use this to delete the list after use. The list pList is no longer valid after this call. Omission of this call will result in wasted memory.
\end{itemize}

View File

@@ -0,0 +1,52 @@
\subsection{Integrate}
For four circle diffractometers it is usefull to be able to integrate the
intensity of the peak from a collected counting profile. This module does
just this. It uses the method as described by Grant \& Gabe in J. Appl. Cryst
(1987), 11, 114-120. This method uses a moving window technique for finding
the limits of the peak. This method was choosen for reason of its
simplicity. The authors state, that the results are comparable to the
Lehmann Larsen method used elsewhere. This is a utility module. Just a
single function is implemented:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
\verb@"integrate.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------@\\
\mbox{}\verb@@\\
\mbox{}\verb@ I N T E G R A T E@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Peak integration follwing the method described by Grant & Gabe in@\\
\mbox{}\verb@ J. Appl. Cryst (1978), 11, 114-120.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, March 1998@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef GABEINTEGRATE@\\
\mbox{}\verb@#define GABEINTEGRATE@\\
\mbox{}\verb@@\\
\mbox{}\verb@#define INTEGLEFT -1@\\
\mbox{}\verb@#define INTEGRIGHT -2@\\
\mbox{}\verb@#define INTEGNOPEAK -3@\\
\mbox{}\verb@#define INTEGFUNNYBACK -4@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int GabePeakIntegrate(int m, int iCounts, long lCounts[], @\\
\mbox{}\verb@ float *fIntens, float *fVariance);@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
Input to this routine is the number of counts and the counts themselves.
Then m, the number of lookahead points to use. As a result fIntens will
contain the summed Intensity and fVariance the sigma of the summed
intensity. The function retusn 1 for success or a negative error code in
case of trouble. These error codes are:
\begin{description}
\item[INTEGLEFT] no left side background found.
\item[INTEGRIGHT] nor right side background found.
\item[INTEGNOPEAK] The data does not contain a peak.
\item[INTEGFUNNYBACK] the data has a strange background.
\end{description}

69
doc/programmer/inter.tex Normal file
View File

@@ -0,0 +1,69 @@
\subsection{The SICS Interpreter}
The SicsInterpreter implements a Tcl-look alike command list with each
object having a similar wrapper function to those used in Tcl. But
augmented with a pointer to a Connection structure in order to enable
authorisation checking and providing the I/O context. The object wrapper
function has a prototype looking like this:
{\bf int ObjectWrapper(SConnection *pCon, SicsInterp *pInter, void *pData,
int argc, char *argv); }
pCon is the connection responsible for this call and holds necessary
information for authorisation checking. pInter is the Sics interpreter.
pData is a pointer to an object specific datastructure (the struct holding
the motor data for instance). Argc and argv hold the arguments as in a C
main program. The object wrapper is meant to evaluate the arguments, do the
right thing to the object with them and than pass results back. There are
two ways to do that. The prefered one is to copy results or error messages
into the interpreters result space and associate an output code with the
result space. After returning the interpreter will than copy these results
to the client. However, a scan routine might want to print status
information to the client during a lengthy operation. In this case the
object can write directly to the connnection usinfg the provided connection
pointer. The object wrapper function returns true or false depending on the
success of the operation.
The command list is a doubly linked list holding for each command a record
containing: the commands name, a pointer to the objects object function, a
pointer to the objects data structure (passed as pData) on invocations and a
pointer to a function which is capable to delete the objects data structure.
This function will be called when the object/command is removed. In the end
the SicsInterpreter implements the following datastrucures an
interfaces:\begin{verbatim} typedef struct __Clist {
char *pName;
ObjectFunc OFunc;
KillFunc KFunc;
void *pData;
struct __Clist *pNext;
struct __Clist *pPrevious;
} CommandList;
\end{verbatim}
The structure held in a doubly linked list for each command.\begin{verbatim}
typedef struct __SINTER
{
CommandList *pCList;
char *pErrors;
int iSpace;
OutCode eOut;
}SicsInterp;
\end{verbatim}
The interpreter data structure. Access only through the interface functions given below:\begin{itemize}
\item {\bf SicsInterp *InitInterp(void) } creates a new interpreter. Returns a pointer on success, NULL on failure.
\item {\bf int AddCommand(SicsInterp *pInterp, char *pName, ObjectFunc pFunc, KillFunc pKFunc, void *pData); } adds a new command to the commandlist of the specified interpreter. Returns True or false depending on success.
\item {\bf int RemoveCommand(SicsInterp *pInterp, char *pName) } finds command name and removes it from the list. Returns True on success (command found) and False if it fails.
\item {\bf int InterpExecute(SicsInterp *self,pSConnection pCon, char *pCommand) } executes pcommand in the SICS interpreter. Returns -1 if the command did not exist. If ist exists True or False is returned depending on the success of the command.
\item {\bf int InterpWriteResult(SicsInterp *self,char *text) } used within object wrapper functions to append result text to the interpreter. Allocating sufficient memory is taken care of by this function.
\item {\bf void InterpSetOutCode(SicsInterp *self, OutCode eCode) } does what it says.
\item {\bf OutCode InterpGetOutCode(SicsInterp *self) } return the current output code for the interpreters result.
\item {\bf CommandList *FindCommand(SicsInterp *pInterp, char *name) } return a pointer to a commandlist structure if the object specified by name exists, NULL else. Used in the definition of interpreter and macro functionality.
\item {\bf const char *InterpGetResult(SicsInterp *self) } returns a pointer to the interpreter result space. This space is managed by the interpreter, never ever delete it in client code.
\item {\bf void DeleteInterp(SicsInterp *self) } removes the interpreter, his command list etc. Frees all allocated memory for this interpreter.
\item {\bf WriteSicsStatus(SicsInterp *pSics, char *file)} opens the file
for writing and writes the current status of SICS objects int the file. In
order to do so, the SaveStatus function of each object registered in the
interpreter is called.
\end{itemize}

View File

@@ -0,0 +1,497 @@
\subsection{Object interfaces}\label{inter}
In order to present themselves to the system SICS objects need to adhere to
certyain interfaces. These interfaces are described in this
section. Thus this section is one of the most important sections of
theis document, read carefully!
A first
requirement was that it must be possible to inquire the capabilities of an
object at run time. A second one was that the system should be extendable.
This means it should be possible to add new interfaces or modify them as the
need arises. In order to achieve this the idea of the interface
datastructure (INDS) was conceived. An INDS contains all the variables and
functions which make up an interface. Then it is possible to create such a
datastructure and pass it around. Each object can now be requested to pass
an INDS of a certain type on demand. What is still needed is a standard way
of asking a SICS object for such a datastructure. This is achieved by the
means of the object descriptor. This is a datastructure which contains
everything necessary to identify an object to SICS. This requires a
convention which is that {\em each SICS objects has to have a pointer to an
object descriptor as first element of its own datastructure.} All this
probably gets clearer once the actual datastructures have been discussed.
As usual, functions return 1 on success and 0 on failure.
\subsubsection{The object descriptor}
Let's start with the objectdescriptor:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$obdes {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------@\\
\mbox{}\verb@ In SICS there is the to find out what an@\\
\mbox{}\verb@ object is capable of at runtime. If this has been done a general@\\
\mbox{}\verb@ way to access those capabilities is needed. In order to do all@\\
\mbox{}\verb@ this each SICS-object is required to carry an object descriptor@\\
\mbox{}\verb@ struct as first parameter in its class/object struct. Additionslly@\\
\mbox{}\verb@ it is required to initialize this struct to something sensible.@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ This file defines this struct. Additionally a few functions of@\\
\mbox{}\verb@ general use are prototyped.@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ Mark Koennecke, June, 1997@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ copyrigth: see implementation file @\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSDESCRIPTOR@\\
\mbox{}\verb@#define SICSDESCRIPTOR@\\
\mbox{}\verb@#include <stdio.h>@\\
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct {@\\
\mbox{}\verb@ char *name;@\\
\mbox{}\verb@ int (*SaveStatus)(void *self, char *name,FILE *fd);@\\
\mbox{}\verb@ void *(*GetInterface)(void *self, int iInterfaceID);@\\
\mbox{}\verb@ } ObjectDescriptor, *pObjectDescriptor;@\\
\mbox{}\verb@@\\
\mbox{}\verb@ /*---------------------------------------------------------------------------*/@\\
\mbox{}\verb@ pObjectDescriptor CreateDescriptor(char *name);@\\
\mbox{}\verb@ void DeleteDescriptor(pObjectDescriptor self);@\\
\mbox{}\verb@ @\\
\mbox{}\verb@/*============================================================================@\\
\mbox{}\verb@ Objects which do not carry data need a dummy descriptor. Otherwise@\\
\mbox{}\verb@ drive or scan will protection fault when trying to drive something@\\
\mbox{}\verb@ which should not be driven. This is defined below.@\\
\mbox{}\verb@*/@\\
\mbox{}\verb@@\\
\mbox{}\verb@typedef struct {@\\
\mbox{}\verb@ pObjectDescriptor pDescriptor;@\\
\mbox{}\verb@ }Dummy, *pDummy;@\\
\mbox{}\verb@ @\\
\mbox{}\verb@@\\
\mbox{}\verb@ pDummy CreateDummy(char *name);@\\
\mbox{}\verb@ void KillDummy(void *pData); @\\
\mbox{}\verb@@\\
\mbox{}\verb@ int iHasType(void *pData, char *Type);@\\
\mbox{}\verb@ @\\
\mbox{}\verb@#endif @\\
\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 first element of the object descriptor is a {\bf name} which is better
described as a type identifier. This specifies the type of the object.
The function {\bf SaveStatus} will be called automatically by SICS when the
server is closing down or a status backup is requested. Each object is meant
to print the commands necessary to configure it back into its current state
into the file passed as a parameter. The idea is that by executing the file
thus created the system gets back into the state before closedown.
The heart of the interface system is the {\bf GetInterface}
function. It takes as arguments a pointer to the datastructure on which it
is called and an integer ID
for the interface. These ID's are defined in the file interface.h. This
function is meant to return a pointer to the apropriate interface
datastructure after this call. If the object does not implement the interface
requested, this function should return NULL. New interfaces can be added
into the scheme by defining new ID's, interfaces and objects which implement
them.
It is {\bf important} to note, that the objects themselves are responsible
for allocating and freeing memory for the interface structures. Client never
should need to worry how to dispose of these structures. Moreover this
scheme ensures that changes to the interface due to some command given to
the object are immediatetly visible through the whole system.
Additionally this header file defines a few relatively uninteresting
functions for object descriptor maintainance. Slightly more interesting is
the Dummy structure, which will be used to find the object descriptor in a
given objects data structure.
\subsubsection{The drivable interface}
As first example of an interface the drivable interface will be given. This
interface is implemented by all devices or varaibles which can be driven to
a value. Most notable example are motors, but composite variables and
environment controllers fit this bill as well.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$driv {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct {@\\
\mbox{}\verb@ int ID;@\\
\mbox{}\verb@ int (*Halt)(void *self);@\\
\mbox{}\verb@ int (*CheckLimits)(void *self, float fVal, @\\
\mbox{}\verb@ char *error, int iErrLen);@\\
\mbox{}\verb@ long (*SetValue)(void *self, SConnection *pCon,@\\
\mbox{}\verb@ float fVal);@\\
\mbox{}\verb@ int (*CheckStatus)(void *self, SConnection *pCon);@\\
\mbox{}\verb@ float (*GetValue)(void *self, SConnection *pCon); @\\
\mbox{}\verb@ int iErrorCount;@\\
\mbox{}\verb@ } IDrivable, *pIDrivable;@\\
\mbox{}\verb@@\\
\mbox{}\verb@ pIDrivable GetDrivableInterface(void *pObject); @\\
\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 first member of this structure is an ID which can be used in order to
check if the right datastructure has been obtained.
The second field is a pointer to a {\bf Halt} function. This function will be
called in an emergency and is meant to send a stop command to the device.
The third field is a pointer to the {\bf CheckLimits} function. This function is
given a float value as second parameter. This is the new value the device
should go to. CheckLimits checks if this position is permitted. If so it
returns 1 else 0.
The {\bf SetValue} member is a pointer to a function which actually makes the
object start to move to its new position.
The {\bf CheckStatus} function will be called in order to check for the current
status of the device during operation. Possible return values are:
\begin{itemize}
\item OKOK if everything is OK.
\item HWIdle if the device is idle i. e. doing nothing.
\item HWFault if the device is in trouble.
\item HWBusy if the device is still running.
\item HWPosFault when the device is principally OK but has not reached the
position specified, for instance because somebody has put a slab of concrete
into the instruments way.
\end{itemize}
The last function which makes up this interface is {\bf GetValue} which is meant
to return the current position of the device.
{\bf iErrorCount} is the number of number of failed driving commands on this drivable
item. This can be used by motors to check and abort the experiment if there
are to many errors. This is to stop a scan command hammer at a blocked motor
a hundred times.
{\bf GetDrivableInterface} is a convenience function which checks object pData for
the existence of a drivable interface. If it exists a pointer to it will be
returned. NEVER free this pointer. If no drivable interface exists, NULL
will be returned.
\subsubsection{The Countable Interface}
This is an interface for interacting with anything which counts.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
$\langle$count {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct {@\\
\mbox{}\verb@ int ID;@\\
\mbox{}\verb@ int (*Halt)(void *self);@\\
\mbox{}\verb@ int (*StartCount)(void *self, SConnection *pCon);@\\
\mbox{}\verb@ int (*CheckCountStatus)(void *self, SConnection *pCon);@\\
\mbox{}\verb@ int (*Pause)(void *self, SConnection *pCon);@\\
\mbox{}\verb@ int (*Continue)(void *self, SConnection *pCon);@\\
\mbox{}\verb@ int (*TransferData)(void *self, SConnection *pCon);@\\
\mbox{}\verb@ } ICountable, *pICountable;@\\
\mbox{}\verb@@\\
\mbox{}\verb@ pICountable GetCountableInterface(void *pObject); @\\
\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 Halt and StartCount} are self explaining, they just do what they say. Please
note, that counting configuration must have happened before usage of this
interface.
{\bf Pause} pauses a data aquisition. It does NOT abort it. {\bf Continue}
continues a paused data aquisition.
{\bf CheckCountStatus} works much like CheckStatus in the IDrivable interface
described above. However, there is an additional return code: HWNoBeam. This
is retuned if a monitor is below a certain threshold, i. e. the beam is off.
{\bf TransferData} will be called at the end of each counting operation and is
meant to update the internal datastructures of the counter. Some counters
choose to keep the last count in their own datastructure, some such as
histogram memories might choose to leave them in the hardware. This function
has been conceived in order to ensure that the first type of counters is
supported.
{\bf GetCountableInterface} is a convenience function which checks object pData for
the existence of a countable interface. If it exists a pointer to it will be
returned. NEVER free this pointer. If no countable interface exists, NULL
will be returned.
\subsubsection{The Callback Interface}
The Callback Interface is SICS suport for component behaviour for objects.
Consider objects A and B. A now is able to generate certain events when it's
state changes. For instance if A is a variable that its value is changed.
B may then choose to register a function with A which gets automatically
called whenever A generates the apropriate event. B is thus automatically
notified about A's status change and can act accordingly to it. In contrast
to the interfaces defined above, this interface is defined in terms of a set
of functions which manipulate the interface and not as a data structure of
overloadable functions.
The first thing to define for such an interface is the type of the callback
function:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap4}
$\langle$callfunc {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef void (*KillFuncIT)(void *pData);@\\
\mbox{}\verb@ typedef int (*SICSCallBack)(int iEvent, void *pEventData, @\\
\mbox{}\verb@ void *pUserData);@\\
\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 callback function is meant to return 0 for failure or 1 for success.
This infomation may be needed by an event invoking object if to continue an
operation or not. The first parameter passed to {\bf SICSCallBack} is the id of
the generated event. Clearly the communicating objects need to agree on
these event. In SICS events types will be held in an header file event.h.
The next parameter to SICSCallBack is a pointer to void. The event
generating object may choose to pass additional data along with the event.
Suitable event datastructures are also defined in event.h. The last
parameter to SICSCallBack is a pointer to a datastructure defined by the
owner of the callback routine when registering the callback. {\bf pKill} is a
function which will be called automatically when the callback is deleted and
whose sole task is to delete pUserData properly.
Then there are the functions needed to interface with the callback
interface:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap5}
$\langle$cifunc {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __ICallBack *pICallBack;@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ /* event source side */@\\
\mbox{}\verb@ pICallBack CreateCallBackInterface(void);@\\
\mbox{}\verb@ void DeleteCallBackInterface(pICallBack self);@\\
\mbox{}\verb@ int InvokeCallBack(pICallBack pInterface, int iEvent, void *pEventData); @\\
\mbox{}\verb@@\\
\mbox{}\verb@ /* callback client side */@\\
\mbox{}\verb@ long RegisterCallback(pICallBack pInterface, int iEvent, SICSCallBack pFunc,@\\
\mbox{}\verb@ void *pUserData, KillFuncIT pKill);@\\
\mbox{}\verb@ int RemoveCallback(pICallBack pInterface, long iID);@\\
\mbox{}\verb@ int RemoveCallback2(pICallBack pInterface, void *pUserData);@\\
\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 callback interface has two parts: A part the event generating object has
to deal with and a part the interested object has to use. There is no way of
enforcing this convention. However, SICS programmers should stick to it,
otherwise weird things may happen.
The first two functions just deal with creating and deleting the callback
interface data structure. {\bf CreateCallBackInterface} returns NULL if the
request fails, or a pointer on success.
{\bf InvokeCallBack} is responsible for invoking the registered callback functions
and will be called only by the source object for the event. This function
will scan the list of registered callback function for callback function
which are registered for the event ID specified as second parameter. Each of
them will be invoked with the event data given as third parameter. If any of
the callback functions returns Failure this function will do so as well.
Else 1 is returned. The event data structure belongs to the object invoking
the callback. It should never be deleted in callback functions.
The next functions deal with the client side of the callback interface.
{\bf RegisterCallBack} registers a callback function with the interface. The first
parameter is the interface to register the callback with. The second
parameter is the event ID for which this callback is defined. pFunc is the
pointer to the actual callback function. Finally pUserData is a pointer to
some user defined data structure which shall be passed as pUserData when the
callback is called. RegisterCallback retuns a long value which server as an
identifier for the callback registration. If the registration fails, this
function returns 0.
{\bf RemoveCallBack} is used to delete a registered callback. The first parameter
is the interface to act upon, the second is the callback ID as returned by
RegisterCallBack.
{\bf RemoveCallback2} is another variant for removing callbacks. This time the
search key for deletion is the pointer to user data. All callbacks related
to this user data in the interface specified will be removed.
All these functions are implemented in the file callback.c.
\subsubsection{The Environment Interface}
This interface is used by the environment monitor in order to monitor
the status of a environment controller. The interface looks like this:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap6}
$\langle$envir {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef enum { EVIdle, EVDrive, EVMonitor, EVError } EVMode;@\\
\mbox{}\verb@ typedef struct {@\\
\mbox{}\verb@ int iID;@\\
\mbox{}\verb@ EVMode (*GetMode)(void *self);@\\
\mbox{}\verb@ int (*IsInTolerance)(void *self);@\\
\mbox{}\verb@ int (*HandleError)(void *self);@\\
\mbox{}\verb@ } EVInterface, *pEVInterface;@\\
\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 enum {\bf EVMode} describes the mode a environment controller can be in. The
default is Idle, no action necessary. EVDrive means that the controller is
currently being driven to a new value and the device executor has control.
EVMonitor means that the environment monitor has to take care of the
controller. EVError is set if the controller is out of tolerances.
{\bf GetMode} retrieves the current operation mode of the controller.
{\bf IsInTolerance} returns 1 if the controller is still within tolerances,
0 otherwise.
{\bf HandleError} will be automatically called when IsInTolerance returns 0.
Its purpose is to implemnt the error handling startegy for the controller
in question.
The environment interface has just one function associated with it:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap7}
$\langle$envfunc {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ pEVInterface CreateEVInterface(void);@\\
\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 CreateEVInterface} just creates an environment interface.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap8}
\verb@"obdes.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@@$\langle$obdes {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap9}
\verb@"interface.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*---------------------------------------------------------------------------@\\
\mbox{}\verb@ I N T E R F A C E S@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Any object in SICS has to adhere to the object descriptor interface (see@\\
\mbox{}\verb@ file obdes.h). Furthermore SICS objects may choose to support other@\\
\mbox{}\verb@ interfaces as well. These interfaces are defined.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, June 1997@\\
\mbox{}\verb@@\\
\mbox{}\verb@ For more documentation see interface.w, interface.tex@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see SICS impelementation files@\\
\mbox{}\verb@---------------------------------------------------------------------------*/@\\
\mbox{}\verb@@\\
\mbox{}\verb@#ifndef SICSINTERFACES@\\
\mbox{}\verb@#define SICSINTERFACES@\\
\mbox{}\verb@@\\
\mbox{}\verb@/* interface ID's used to recognize an interface */@\\
\mbox{}\verb@#define DRIVEID 513@\\
\mbox{}\verb@#define COUNTID 713@\\
\mbox{}\verb@#define CALLBACKINTERFACE 947@\\
\mbox{}\verb@#define ENVIRINTERFACE 949@\\
\mbox{}\verb@@\\
\mbox{}\verb@/* ----------------------- The drivable interface -----------------------*/@\\
\mbox{}\verb@@$\langle$driv {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@ pIDrivable CreateDrivableInterface(void);@\\
\mbox{}\verb@@\\
\mbox{}\verb@/* ------------------------ The countable interface ---------------------*/@\\
\mbox{}\verb@@$\langle$count {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@ pICountable CreateCountableInterface(void);@\\
\mbox{}\verb@@\\
\mbox{}\verb@/* ------------------------- The CallBack Interface --------------------*/@\\
\mbox{}\verb@@$\langle$callfunc {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@$\langle$cifunc {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@/*---------------------- The Environment Interface --------------------*/@\\
\mbox{}\verb@@$\langle$envir {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@$\langle$envfunc {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsection{More interfaces}
For completeness it should be mentioned that besides these interfaces
there exist further important interfaces in SICS. This includes the
interface to the SICS interpreter defined in
\ref{scinter}. Furthermore the data structures defined for the various
types of drivers within SICS may be considered interfaces as
well. Then there is the interface to the client as defined by the
functions of the connection interface.

View File

@@ -0,0 +1,53 @@
\subsection{Interrupt Handling}
SICS needs a way to interrupt server processsing. This is done
with this module.
Interrupts may come in through two ways: They may be created
internally or they may be user requested. For the last ones
the main loop will poll an additional special interrupt
port.
In order to do interrupting a set of interrupt codes are defined:
\begin{verbatim}
#define eContinue 0
#define eAbortOperation 1
#define eAbortScan 2
#define eAbortBatch 3
#define eHaltSystem 4
#define eFreeSystem 5
#define eEndServer 6
\end{verbatim}
Their meanings:
\begin{description}
\item[eContinue] Go on, interrupt nothing.
\item[eAbortOperation] stop current hardware operation but no scans or
batchfiles.
\item[eAbortScan] stop current scan or operation but continue processing of
batch files with next command.
\item[eAbortBatch] Stop all processing, even batch files.
\item[eHaltSystem, eFreeSystem] are currently unused.
\item[eEndServer] is used internally by the SicsExitus command to run down
the server.
\end{description}
The interrupt module supports the following interface:
\begin{description}
\item[void ServerStopInterrupt(void)] stops interrupt processing.
\item[void SetInterrupt(int iCode)]
Send an interrupt to all connections. Use with care! More often an
interrupt need to be set on a special connection. This can be done with
SCSetInterrupt defined in conman.h.
\item[int Interrupt2Text(int iInterrupt, char *text, int iTextLen)] converts
iInterrupt to a text. Maximum iTextLen characters will be copied to text.
\item[int Text2Interrupt(char *text)] Converts text, when applicable to an
interrupt code which is returned. If the text is invalid -1 is returned.
\item[int ClientSetupInterrupt(char *host, int iPort)] Creates a client side
interrupt UDP port.
\item[void ClientStopInterrupt(void)] removes an client side interrupt port
created by ClientSetupInterrupt.
\item[void SendInterrupt( int iCode)] sends an interrupt through the UDP
port.
\end{description}
Please note, that the interrupt implementation is distributed into two
files: intserv.c for the server side stuff and intcli.c for the client side
part. UDP interrupting is not fully tested.

107
doc/programmer/itc4.tex Normal file
View File

@@ -0,0 +1,107 @@
\subsubsection{Oxford Instruments ITC4 Temperature Controllers}
SINQ makes heavy use of Oxford Instruments ITC4 temperature controllers. In
order to support them the following software components had to be defined in
addition to the basic environmet controller interfaces:
\begin{itemize}
\item ITC4driver, naturally.
\item A ITC4-controller object as derivation of environment controller. ITC4
's allow you to select a sensor which you read as your standard sensor and a
sensor which is used for automatic control. The ITC4 controller object adds
just that additional functionality to the statndard environment controller.
\end{itemize}
The additional data, the selection of sensors, will be kept in the driver.
This serves also an example for implementing inheritance without C++.
The driver interface:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$itcd {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ pEVDriver CreateITC4Driver(int argc, char *argv[]);@\\
\mbox{}\verb@ int ConfigITC4(pEVDriver self);@\\
\mbox{}\verb@ int SetSensorITC4(pEVDriver self, int iSensor);@\\
\mbox{}\verb@ int SetControlITC4(pEVDriver self, int iSensor);@\\
\mbox{}\verb@ int GetSensorITC4(pEVDriver self);@\\
\mbox{}\verb@ int GetControlITC4(pEVDriver self);@\\
\mbox{}\verb@ int SetDivisorITC4(pEVDriver self, float iSensor);@\\
\mbox{}\verb@ float GetDivisorITC4(pEVDriver self);@\\
\mbox{}\verb@ int SetMultITC4(pEVDriver self, float iSensor);@\\
\mbox{}\verb@ float GetMultITC4(pEVDriver self);@\\
\mbox{}\verb@ int SetTMOITC4(pEVDriver self, int iSensor);@\\
\mbox{}\verb@ int GetTMOITC4(pEVDriver 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}
The ConfigITC4 is special. It has to be called to commit changes to the
driver read and control parameters.
The ITC4 object interface:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$itco {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ int ITC4Wrapper(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ int ITC4SetPar(pEVControl self, char *name, float fNew, @\\
\mbox{}\verb@ SConnection *pCon);@\\
\mbox{}\verb@ int ITC4GetPar(pEVControl self, char *name, float *fVal);@\\
\mbox{}\verb@ int ITCList(pEVControl self, SConnection *pCon);@\\
\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 functions defined are: new parameter handling functions, with just
support for the two extra parameters added and a new Wrapper function for
SICS. The meaning of all these functions, their parameters and return values
are identical to those defined for an environment controller. Additionally,
the standard environment controller functions will work as described. The
functions described above are just needed to implement the extra parameters.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
\verb@"itc4.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-------------------------------------------------------------------------@\\
\mbox{}\verb@ ITC 4@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ Support for Oxford Instruments ITC4 Temperature controllers for SICS.@\\
\mbox{}\verb@ The meaning and working of the functions defined is as desribed for a@\\
\mbox{}\verb@ general environment controller.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, Juli 1997@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see implementation file.@\\
\mbox{}\verb@@\\
\mbox{}\verb@-----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSITC4@\\
\mbox{}\verb@#define SICSITC4@\\
\mbox{}\verb@/*------------------------- The Driver ------------------------------------*/@\\
\mbox{}\verb@@$\langle$itcd {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@/*------------------------- The ITC4 object ------------------------------*/@\\
\mbox{}\verb@@$\langle$itco {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@#endif @\\
\mbox{}\verb@ @\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

View File

@@ -0,0 +1,355 @@
\chapter{Guide To SICS Kernel Facilities}
In this chapter the facilities of the SICS servers kernel will be examined
more closely. All the kernel modules and their function will be listed,
together with some explanatory information and an overview about the
application programmers interfaces (API) provided. This section should
answer the questions: WHat is available?, Where to find what?,
Why did they do that? Details of
the API's mentioned are given in the reference section.
The SICS servers kernel consists of the following objects and modules:
\begin{itemize}
\item The task manager , Files tasker.*.
\item The network reader, Files nread.*.
\item The network module, Files network.*.
\item The connection object, Files conman.*.
\item The SICS interpreter, Files SCinter.*.
\item The SICS macro facility, Files macro.*, script.*.
\item The device executor, Files devexec.*.
\item The environment monitor, Files emon.c.
\item The server himself, Files nserver.*
\item The serverlog, Files servlog.*.
\item A performance monitor, Files perfmon.*.
\item The object factory, Files ofac.*.
\item The options database, Files ifile.*.
\item The password database, Files passwd.*.
\item The main program, File SICSmain.c.
\end{itemize}
\section{The Task Manager}
The task manager implements cooperative multitasking in SICS. A task in the
SICS sense is defined by a function, the task function. It is of the type:
\begin{verbatim}
int TaskFunction(void *pData);
\end{verbatim}
When it is time for the task to execute this function is called, with a
parameter to a the tasks own data structure. This data structure must have
been defined by the user of this module. The task function returns 1, if it
shall continue to live, or 0 if it should be deleted from the task list.
These task functions are kept in a list. The elements of this list are
visited cyclically, when the scheduler runs.
The API to this object consists of functions for creating a task manager,
adding tasks to the task list and to run the task list. Other functions
allow to put a task into a wait state. This means that the task will not
execute until another task has died (returned 0). Then the waiting task will
continue execution at the point where it has called the wait function.
For example, consider a task which wants to wait for say 10 seconds. This
tasks name shall be BedTask. It does so by starting a second task, called
ClockTask which checks if 10 seconds have passed and dies after this.
BedTask then waits for this task. This makes BedTask look like this:
\begin{verbatim}
int BedTask(void *pData)
{
/* Code block 1.
Fill in horrendously complex operations here.
*/
lID = TaskRegister(pTasker, ClockTask,....)
TaskWait(pTasker, lID, ....);
/* Code block 2.
More horrendous computations.
Will be executed after ClockTask died.
*/
/* Beds never die!!! */
return 1;
}
\end{verbatim}
and ClockTask:
\begin{verbatim}
int ClockTask(void *pData)
{
if(10 seconds are gone)
{
/* death is lurking */
return 0;
}
else
{
/* continue running */
return 1;
}
}
\end{verbatim}
The task manager supports a primitive means of inter task communication as
well. Each registered task may not only have a task function associated with
it, but also a SignalFunction. When a task feels like it, it may advise the
task manager to send a signal and some data to all the other tasks. Signals
are identified by integer numbers. The SignalFunction of each task will then
be called. It has to check the signal and if it is of meaning to the task,
do something appropriate with it. SICS uses this facility to distribute
interrupts and broadcast messages to all tasks. Currently defined signal
IDs are defined in file event.h.
\section{The Network Reader and the Network Module}
The network module implements the mechanics of network connection. This
module is the one which needs heavy reworking if the network protocol for
SICS should be changed. For instance to Token--Ring or AppleTalk or
whatever.
The network reader implements the polling for network message in the SICS
server. It is organized as one of the SICS system tasks. Polling in a POSIX
environment is all about the select system call. The select system call
allows to enquire if an open TCP/IP socket has data pending to be read, can
be written to etc. For more details see the unix man pages for the select
system call. An earlier version of the SICS server had a list of connection
objects and each of them were checked for pending commands with a call to
select. This proved to be inefficient with the system spending two thirds
of its time in select. Then it was decided to make use of the fact that
select can check more then one socket in one call. This gave birth to the
network reader. Each network user in the SICS server can register his socket
with the network reader. When the network reader tasks executes, it checks
all registered sockets for pending data with one central select system call.
This scheme improved system performance by a factor of 900.
What happens when data is pending on a socket depends on the type of the
socket.
The network reader currently supports four types of sockets:
\begin{itemize}
\item Accept type sockets.
\item Normal client sockets.
\item UDP sockets.
\item User sockets.
\end{itemize}
The accept type of socket is the main server port where clients try to
connect to. The network reader accepts the connection and tries to read a
username/password pair for a specified amount of time.
If the username/password is valid, the connection will be accepted,
else it will be broken again. The username/password pair will be verified
against the data in the password database. If a connection is accepted, a
new connection object is created, a new connection task is registered into
the system and the network reader registers a new client command port.
The normal client command ports are accepted connections from a client. The
SICS server expects commands to be sent from the clients. Thus any data
pending on such a socket will be read, split into single commands at the \\n
and put into the connections command stack for execution. At this place
there is also the check for the special interrupt string on command
connections (see \ref{prot1}).
The SICS server accepts only interrupts on its UDP port. This will be checked
for when handling data pending on the servers UDP port.
User type sockets are a feature for dealing with extremely slow hardware
connections. Some hardware devices require a long time to answer requests.
For example the Dornier velocity selector. This would block the SICS server
or diminish its performance to unbearable levels. If situations like that
occur somewhere in SICS object code, the object may call a special wait
function which returns when data is pending on the socket. Thereby, other
clients requests would be served, as the task switcher would run.
This special wait facility is implemented in the network reader.
\section{The Connection Object}
The connection object holds the execution context of the current client
connection. Its data structure holds information about the network channel to
the client connection, the command stack which the network reader fills with
commands, a list of files where all I/O to and from this connection will be
logged, the user rights associated with this client connection, interrupts,
and flags which determine if the connection is currently executing in a
macro or is busy. Functions exist which allow to interact with this object.
Most of them will be discussed in section \ref{gow}. Associated with each
connection is a task and a task function. Whenever this task executes, it
will pop a command from the command stack and execute it in the
interpreter. More details about the usage of the connection object can be
found in the next chapter \ref{gow}.
\section{The SICS Interpreter and Macro Language}
In order to understand this section a knowledge of some aspects of the C
language interface to the Tcl interpreter helps. Interesting chapters include
the sections about defining new commands in Tcl and the Tcl unknown
mechanism. For more details see John Ousterhout's book.
In an earlier stage it was considered to use the Tcl interpreter as the SICS
interpreter. This idea was discarded for some reasons: One was the
difficulty of transporting the client execution context (i.e. the connection
object) through the Tcl interpreter. There is no standard Tcl mechanism for
doing that. The second was security: the Tcl
interpreter is very powerful and can be abused. It was felt that the system
had to be protected against such problems. The third reasons was that the
set of user commands should not be cluttered with Tcl commands in order to
prevent confusion. Programming macros is anyway something which is done by
SICS managers or programmers. However, the SICS interpreter is still modeled
very much like the Tcl-interpreter. A Tcl interpreter is still included in
order to provide a full featured macro language. The SICS interpreter and the
Tcl macro interpreter are still tightly coupled.
The SICS interpreter must forward commands to the SICS objects. For this the
interpreter needs some help from the objects themselves. Each SICS object
has to provide a wrapper function of the type:
\begin{verbatim}
int ObjectWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
\end{verbatim}
in order to be visible from the interpreter. The parameters to this function
are: a pointer to the client connection executing the command,
the interpreter in which the command
executes, a pointer to the objects data structure and an argc,
\verb+argv[]+ pair
like for an C language main program. This argc, \verb+argv[]+ pair contains the
arguments to the wrapper function. The wrapper function is responsible for
evaluating the arguments and do whatever is appropriate. It returns 0 on
failure and 1 on success. The SICS interpreter holds a list of such wrapper
functions. For each object the list holds:
\begin{itemize}
\item The name of the SICS object.
\item The address of the objects wrapper function.
\item The address of the objects data structure.
\item The address of a function which can remove the objects data structure
from memory cleanly. This is used when deleting an object/command from the
interpreter to clean up memory.
\end{itemize}
Command interpretation then involves the following steps:
\begin{enumerate}
\item The command is parsed into an argc, \verb+argv[]+ pair.
\item Using the first word of the command as a key, the list of objects is
searched for a match.
\item If a match is found, the objects wrapper function is invoked with the
appropriate parameters.
\item All the rest of command interpretation is done by the wrapper
function.
\end{enumerate}
The SICS interpreter interface offers functions which allow to add or remove
entries to and from the interpreters list of objects. Other functions allow
to find objects (and their data structures) in this list. And of course,
there is a function which executes a command in this interpreter.
The Tcl macro interpreter is invoked either through the FileEval command or
through commands made available through the Publish mechanism. Publish
is a SICS manager command which makes a Tcl command or procedure
visible in the SICS interpreter. Publish provides a special wrapper for a
Tcl command, which first checks the user rights of the client connection which
wants to execute the Tcl command. If the user rights are appropriate the
command is invoked in the Tcl--interpreter. The Tcl interpreter has access
to all normal SICS commands. This is implemented by using the Tcl
unknown mechanism. If Tcl cannot find a command it invokes a command named
unknown with the missing commands name as a parameter. Unknown is usually
implemented as a Tcl script, loaded at Tcl startup time. The unknown function
is then responsible for finding the missing command and execute it. The
usual Tcl mechanism tries to find the missing command in Tcl libraries and
as operating system commands. This mechanism has been modified for SICS such
that unknown tries to find missing commands in Tcl libraries or in the SICS
interpreter. This last bit is implemented as a special Tcl command
SISCUnknown defined in macro.c. In order to invoke SICS command a connection
object is needed. A suitable connection object is provided through a stack.
Before invoking the Tcl-interpreter, the connection object from which the
request has come is put at the bottom of a stack. The SICSUnknown routine
then uses the last element of the stack as the connection object for
invoking SICS. When control returns from the Tcl-interpreter, the connection
is popped from the stack.
%% Idea: simplify: use Tcl as interpreter, have a wrapper around SICS
%% objects which provide the SICS wrapper contexts. Add SICS commands to Tcl
%% in a special data structure:
%% struct TclSICS {
%% (*ObjectWrapper);
%% void *ObjectData;
%% (*KillObject)
%% };
%% The Tcl wrapper function gets the connection object from the stack and
%% invokes the SICS object function.
%% This does not solve the Tcl security issue, though.
%%
\section{The Device Executor}
The device executor is responsible for executing and monitoring requests to
the actual instrument hardware. In its current form the device executor can
do this for any variable which can be driven (motors, temperature, composite
variables) and counters (single counters, histogram memory). How this is
done is explained in some detail in the section about SICS interfaces (see
\ref{inter}) in the object writers guide. The interface to the device
executor includes functions for starting, pausing, continuing devices and
monitoring their status. Additionally there are some functions and SICS
commands which allow to enquire about the status of the executor. If
hardware is active, the device executor has a SICS system task running
which initiates monitoring of devices. The device executor is built around a
list of currently active hardware devices.
\section{The Environment Monitor}
For the SICS concept for handling sample environment devices see
\ref{evdev}.
\section{The Server}
The server module defines a server data structure. A pointer to this
data structure is the sole global variable in the SICS system. Its name is
{\bf {\huge pServ}}. This data structure contains pointers to the most
important SICS components: the interpreter, the task switcher, the device
executor, the environment monitor and the network reader. This module also
contains the code for initializing, running and stopping the server.
\section{The ServerLog}
As part of the SICS kernel there exists a global server log file. This file
contains:
\begin{itemize}
\item All traffic on all client connections. Even messages suppressed by the
clients.
\item All internal error messages.
\item Notifications about important internal status changes.
\end{itemize}
This server log is meant as an aid in debugging the server. As the SICS
server may run for days, weeks and months uninterrupted this log file may
become very large. However, only the last thousand or so messages are really
of interest when tracking a problem. Therefore a scheme is implemented to
limit the disk space used by the server log. The server log writes
cyclically into a number of files. A count of the lines is kept which were
written to each file. Above a predefined count, a new file is started.
As an interface the server log provides a function which allows to write
a message to it. This can be used by any object in the system for
interesting messages. The number of files to cycle through and the length of
each file can be configured by defines at the top of servlog.c.
\section{The Performance Monitor}
This facility provides the data for the Performance (see user documentation)
command. The Performance Monitor is a task which increments a counter each
time it is executed. After a predefined integration time (20 seconds) a new
value cycles/per second is calculated. This is the data retrievable by the
Performance command. This facility is not particularly necessary but proved
useful for judging the impact of various system conditions on server
performance. If at some stage performance needs to be boosted to the utmost
and it is no longer the hardware which makes things slow, the performance
monitor may well be removed from the system without harm.
\section{The Object Factory}
During SICS initialization the SICS interpreters command list needs to be
initialized. This is the task of the object factory. Its function
IniIniCommand initializes all fixed, general SICS commands and all object
creation commands. Then the server initialization file is processed from the
server initialization code. After this is done, the server initialization
code calls KillIniCommands which removes the now surplus object creation
commands from the SICS interpreter. If new commands get added to SICS the
object creation command or (for a permanent command) the object wrapper have
to be registered with these two functions.
\section{SICS Options}
Any system needs a way to configure itself. SICS uses options for internal
parameters which should or need not be visible from the SICS interpreter. An
option is a name value pair. For a definition of currently valid SICS
options and how to create them see the SICS manager documentation. In terms
of an interface this module allows to retrieve an option from the options
database.
\section{The Password Database}
The password database holds a triplet of username password and rights code
for each user. This information is currently initialized from the server
initialization file. This scheme is not very secure, as anybody with an
account on the DAQ computer may view the file and thus the list of valid
users. If this becomes a serious concern, this module has to be rewritten.
\section{The Server Main Function}
This does not do much, just initialize the server, run it, and stop it.

View File

@@ -0,0 +1,239 @@
TAS_SRC:[PSI.NOTES]LANTRONIX_SETUP.TXT
======================================
15-Nov-2000
===========
The Following setup was made for the
Lantronix ETS16PR Terminal Server psts240 (129.129.120.240) for POLDI
define server name "psts240"
define server incoming telnet
define server incoming nopassword
define server domain "psi.ch"
define server subnet mask 255.255.0.0
define protocol ip enable
define protocol ip ipaddress 129.129.120.240
define protocol ip gateway 129.129.100.2
define protocol ip nameserver 129.129.100.1
define protocol ip secondary nameserver 129.129.110.10
define protocol ip timeserver enable
define server dhcp disabled
define server bootp disabled
define server rarp disabled
define server serial delay 10 # (was 30 msec)
define server buffer 256 # (was 2048)
define server ident "POLDI Terminal Server"
define port 2-16 access remote
define port 2-16 autobaud disable
define port 2-16 break disable
define port 2-16 broadcast disable
define port 2-16 flow control none
define port 2-16 loss notif disable
define port 2-16 modem disable
define port 2-16 passflow enable
define port 2-16 telnet pad disable
define port 2-16 verific disable
init delay 0
-------------------------------------------------------------------------------
08-Nov-2000
===========
The following commands:
define server dhcp disabled
define server bootp disabled
define server rarp disabled
were executed on
psts213 -- Test device in WHGA/247
psts216 -- Druechal
psts217 -- TASP
psts222 -- Loan device for P.Rasmussen
psts223 -- SANS
psts224 -- AMOR
psts225 -- DMC
psts227 -- FOCUS
psts228 -- TriCS
psts229 -- HRPT
psts230 -- POLDI (on loan from LNS)
on the recommendation of Lantronix (Brian Tutor)
-------------------------------------------------------------------------------
28-Apr-2000
===========
The Following setup was made for the
Lantronix ETS16PR Terminal Server psts225 (129.129.120.225) for DMC
and
Lantronix ETS16PR Terminal Server psts227 (129.129.120.227) for FOCUS
Local_18>> define server serial delay 10 (was 30 msec)
Local_18>> define server buffer 256 (was 2048)
Local_18>> define server ident "DMC/FOCUS Terminal Server"
Local_18>> define server dhcp disabled \
Local_18>> define server bootp disabled > Done on 8-Nov-2000 (see above)
Local_18>> define server rarp disabled /
Local_18>> define port 2-16 access remote
Local_18>> define port 2-16 autobaud disable
Local_18>> define port 2-16 break disable
Local_18>> define port 2-16 broadcast disable
Local_18>> define port 2-16 flow control none
Local_18>> define port 2-16 loss notif disable
Local_18>> define port 2-16 modem disable
Local_18>> define port 2-16 passflow enable
Local_18>> define port 2-16 telnet pad disable
Local_18>> define port 2-16 verific disable
Local_18>> init delay 0
Local_18>> show server char
ETS16PR Version V3.5/7(981112) Uptime: 0:01:57
Hardware Addr: 00-80-a3-23-8e-1d Name/Nodenum: ETS_238E1D/ 0
Ident String: DMC/FOCUS Terminal Server
LAT Circuit Timer (msec): 80 Password Limit: 3
Inactive Timer (min): 30 Console Port: 1
Queue Limit: 32 Retrans Limit: 50
Keepalive Timer (sec): 20 Session Limit: 4
Multicast Timer (sec): 30 Node/Host Limits: 50/20
TCP/IP Address: 129.129.120.225 Subnet Mask: 255.255.0.0
Nameserver: (undefined) Backup Nameserver: (undefined)
TCP/IP Gateway: 129.129.40.151 Backup Gateway: 129.129.100.2
Domain Name: (undefined) Daytime Queries: Enabled
TCP Keepalives: Enabled
DHCP Server: None Lease Time: 0:00
Serial Delay (msec): 10 Network Buffering: 256
Prompt: Local_%n%P>
Groups: 0
Characteristics: Announce Broadcast Lock
Incoming Logins: Telnet (No Passwords Required)
-------------------------------------------------------------------------------
6-Mar-2000
==========
The Following setup was made for the
Lantronix ETS16PR Terminal Server psts223 (129.129.120.223) for SANS
Local_18>> define server serial delay 10 (was 30 msec)
Local_18>> define server buffer 256 (was 2048)
Local_18>> define server ident "SANS Terminal Server"
Local_18>> define server dhcp disabled \
Local_18>> define server bootp disabled > Done on 8-Nov-2000 (see above)
Local_18>> define server rarp disabled /
Local_18>> define port 2-16 access remote
Local_18>> define port 2-16 autobaud disable
Local_18>> define port 2-16 break disable
Local_18>> define port 2-16 broadcast disable
Local_18>> define port 2-16 flow control none
Local_18>> define port 2-16 loss notif disable
Local_18>> define port 2-16 modem disable
Local_18>> define port 2-16 passflow enable
Local_18>> define port 2-16 telnet pad disable
Local_18>> define port 2-16 verific disable
Local_18>> define port 16 speed 4800
Local_18>> init delay 0
Local_18>> show server char
ETS16PR Version V3.5/7(981112) Uptime: 22 Days 20:09
Hardware Addr: 00-80-a3-23-8e-4f Name/Nodenum: ETS_238E4F/ 0
Ident String: SANS Terminal Server Daytime: 11:31:15
LAT Circuit Timer (msec): 80 Password Limit: 3
Inactive Timer (min): 30 Console Port: 1
Queue Limit: 32 Retrans Limit: 50
Keepalive Timer (sec): 20 Session Limit: 4
Multicast Timer (sec): 30 Node/Host Limits: 50/20
TCP/IP Address: 129.129.120.223 Subnet Mask: 255.255.0.0
Nameserver: (undefined) Backup Nameserver: (undefined)
TCP/IP Gateway: 129.129.80.1 Backup Gateway: 129.129.100.2
Domain Name: (undefined) Daytime Queries: Enabled
TCP Keepalives: Enabled
DHCP Server: None Lease Time: 0:00
Serial Delay (msec): 10 Network Buffering: 256
Prompt: Local_%n%P>
Groups: 0
Characteristics: Announce Broadcast Lock
Incoming Logins: Telnet (No Passwords Required)
-------------------------------------------------------------------------------
19-May-1999
===========
The Following setup was made for the
Lantronix ETS8P Terminal Server psts217 (129.129.120.217) for TASP
and Lantronix ETS8P Terminal Server psts216 (129.129.120.216) for DRUECHAL
Local_10>> define server serial delay 10 (was 30 msec)
Local_10>> define server buffer 256 (was 2048)
Local_10>> define server ident "TASP Terminal Server"
Local_10>> define server dhcp disabled \
Local_10>> define server bootp disabled > Done on 8-Nov-2000 (see above)
Local_10>> define server rarp disabled /
Local_10>> define port 2-8 access remote
Local_10>> define port 2-8 autobaud disable
Local_10>> define port 2-8 break disable
Local_10>> define port 2-8 broadcast disable
Local_10>> define port 2-8 flow control none
Local_10>> define port 2-8 loss notif disable
Local_10>> define port 2-8 modem disable
Local_10>> define port 2-8 passflow enable
Local_10>> define port 2-8 telnet pad disable
Local_10>> define port 2-8 verific disable
Local_10>> define port 7 stop 2
Local_10>> init delay 0
Local_10>> show server char
ETS8P Version V3.5/5(980529) Uptime: 0:08:00
Hardware Addr: 00-80-a3-17-09-7f Name/Nodenum: ETS_17097F/ 0
Ident String: TASP Terminal Server
LAT Circuit Timer (msec): 80 Password Limit: 3
Inactive Timer (min): 30 Console Port: 1
Queue Limit: 32 Retrans Limit: 50
Keepalive Timer (sec): 20 Session Limit: 4
Multicast Timer (sec): 30 Node/Host Limits: 50/20
TCP/IP Address: 129.129.120.202 Subnet Mask: 255.255.0.0
Nameserver: 129.129.110.10 Backup Nameserver: (undefined)
TCP/IP Gateway: 129.129.100.2 Backup Gateway: 129.129.30.4
Domain Name: psi.ch Daytime Queries: Enabled
TCP Keepalives: Enabled
DHCP Server: None Lease Time: 0:00
Serial Delay (msec): 10 Network Buffering: 256
Prompt: Local_%n%P>
Groups: 0
Characteristics: Announce Broadcast Lock
Incoming Logins: Telnet (No Passwords Required)
-------------------------------------------------------------------------------

49
doc/programmer/macro.tex Normal file
View File

@@ -0,0 +1,49 @@
\subsection{The Macro Interpreter}
This module is responsible for splicing the Tcl macro interpreter into
the SICS framework. In order to achieve this several problems have to be
adressed:
\begin{itemize}
\item How to make Tcl commands available from within SICS.
\item How to call SICS with the correct execution context from Tcl macros.
\end{itemize}
The first problem is solved by overloading Tcl's unknown mechanism. The Tcl
interpreter automatically invokes a procedure {\bf unknown} when it cannot
find a command. The usual procedure in this case searches for Tcl procedures
in libraries and then tries to invoke the command as a shell command. For
SICS the last part has been cut off and replaced by a call to SICSUnknown
which tries to find an appropriate SICS command.
The second problem is solved by maintaing a stack of connection objects.
Before a Tcl command is invoked from SICS the current connection object is
pushed on the stack. If in due course SICSUnknown needs to find a connection
object in order to invoke a SICS object the last object from the stack will
be used. If Tcl finishes, the connection object is popped from the stack.
This is nicely shown in the TclAction code.
All this is implemented in macro.c.
The macro module presents the following interface to the outside world:\begin{itemize}
\item {\bf Tcl\_Interp *MacroInit(SicsInterp *pInter,SConnection *pCon) } initialises a Tcl interpreter with a SICS unknown mechanism. Furthermore deletes some Tcl standard commands which can be harmful in SICS. Returns a pointer to an interpreter on success, NULL else.
\item {\bf void MacroDelete(Tcl\_Interp *pInter) } deletes an interpreter.
\item {\bf int MacroFileEval(SConnection *pCon, SicsInterp *pInter, void *pData, int argc, char *argv) }, the SICS object wrapper function for script processing.
\item {\bf int InternalFileEval(SConnection *pCon, SicsInterp *pInter,
void *pData, int argc, char *argv) }, the SICS object wrapper
function for script processing. This version suppresses output to the
client however. All output goes into the command log only.
\item {\bf int ClientPut(SConnection *pCon, SicsInterp *pInter, void *pData, int argc, char *argv) },
the SICS object wrapper function for writing datato a client from
within a Tcl--script.
\item {\bf int MacroWhere(SConnection *pCon, SicsInterp *pInter,
void *pData, int argc, char *argv) }, the SICS object wrapper
function implementing the filewhere command.
\item {\bf int TclPublish(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])} is the implmentation of the Publish command for the
interpreter which installs a Tcl command into the system.
\item {\bf int TransactAction (SConnection *pCon, SicsInterp *pInter,
void *pData, int argc, char *argv) } This Function implements the
transact command which executes an command and sends a string
``TRANSACTIONFINISHED'' when the command finished executing.
\item {\bf MacroPush} pushes a connection onto the Tcl connection
stack.
\item {\bf MacroPop} removes a connection for the Tcl connection
stack.
\end{itemize}

126
doc/programmer/mesure.tex Normal file
View File

@@ -0,0 +1,126 @@
\subsection{Four Circle Single Counter Measurement Object}
This object implements a basic single counter reflection measurement routine
for four circle diffractometers. This object is able to read a reflection
listing, drive to each reflection in the list, do a scan on it, integrate
the scan results and write the results to ASCII files. Nothing sophisticated
such as optimised measurement procedures and special background measurement
programs. Three files will be created as output: one file with the ending
.rfl which contains the reflection profiles for each reflection, a file .asc
which contains a summary in form of HKL, I, sigma(I) for each reflection
and a file ending .err which contains all the error messages obtained during
the run.
The interface to this object consists of these functions:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$mesureint {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __Mesure *pMesure;@\\
\mbox{}\verb@/*--------------------- live & death --------------------------------------*/@\\
\mbox{}\verb@ pMesure CreateMesure(pHKL pCryst, pScanData pScanner, @\\
\mbox{}\verb@ pMotor pOmega, char *pom, char *po2t,@\\
\mbox{}\verb@ char *pFileRoot,pDataNumber pDanu);@\\
\mbox{}\verb@ void DeleteMesure(void *pData);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int MesureFactory(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@/*------------------- object functions -----------------------------------*/@\\
\mbox{}\verb@ int MesureReflection(pMesure self, float fHKL[3], SConnection *pCon);@\\
\mbox{}\verb@ int MesureGenReflection(pMesure self, float fHKL[3],float fSet[4], SConnection *pCon);@\\
\mbox{}\verb@ int MesureStart(pMesure self, SConnection *pCon);@\\
\mbox{}\verb@ int MesureReopen(pMesure self, char *filename, SConnection *pCon);@\\
\mbox{}\verb@ int MesureClose(pMesure self);@\\
\mbox{}\verb@ int MesureFile(pMesure self, char *pFile, int iSkip, SConnection *pCon);@\\
\mbox{}\verb@ int MesureGenFile(pMesure self, char *pFile, int iSkip, SConnection *pCon);@\\
\mbox{}\verb@ int MesureSetPar(pMesure self, char *name, float fVal);@\\
\mbox{}\verb@ int MesureGetPar(pMesure self, char *name, float *fVal);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int MesureAction(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}
All functions return 1 on success, 0 on failure.
\begin{description}
\item[CreateMesure] creates a new pMesure object. Parameters are the HKL
object to use for cystallographic conversions and the scan object to use for
doing the scans. This is followd by the motor for running omega, its name
and the name of the motor for driving omega 2 theta. Finnaly the path to the
data directory and the data number object for automatic filename creation is
specified.
\item[DeleteMesure] wipes the mesure object pData from memory.
\item[MesureFactory] is the factory function for mesure which will be used
by the interpreter to install mesure into the system.
\item[MesureReflection] measures the single reflection fHKL. It drives
there, calculates scan borders and performs the scan.
\item[MesureGenReflection] measures the single reflection fHKL. It drives
there, calculates scan borders and performs the scan. This version uses
supplied values for the instrument settings.
\item[MesureStart] sets everything up for a new measurement with new file
names.
\item[MesureReopen] reopens the files belonging to the file name given as
base for appending. This is a recovery feature.
\item[MesureFile] opens the file specified as second parameter and reads
each line. Expected is a reflection to measure. Each reflection is then
measured and output written. The last parameter iSkip allows to skip iSkip
lines of the reflection file. This facility exists in order to restart work
on an reflection file which had been interrupted for some reason.
\item[MesureGenFile] opens the file specified as second parameter and reads
each line. Expected is a reflection to measure. Each reflection is then
measured and output written. The last parameter iSkip allows to skip iSkip
lines of the reflection file. This facility exists in order to restart work
on an reflection file which had been interrupted for some reason. This
version acts upon files created by the program HKLGEN.
\item[MesureSetPar] sets the parameter name of Mesure to fVal. A listing of
possible parameters is given below.
\item[MesureGetPar] returns the value of the parameter name in fVal.
\item[MesureAction] implements the interpreter interface to the mesure
object.
\end{description}
Mesure supports the following parameters:
\begin{description}
\item[np] the number of points per scan.
\item[preset] The preset value for counting.
\item[countmode] the counting mode, can be 0 for timer or 1 for monitor
mode.
\item[mode] can be 0 for omega 2theta scans or 1 for omega scans.
\item[step] the scan step widths. This is allways in omega, in omega 2theta
mode 2theta is always the double of this.
\end{description}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
\verb@"mesure.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*----------------------------------------------------------------------------@\\
\mbox{}\verb@ M E S U R E@\\
\mbox{}\verb@@\\
\mbox{}\verb@ A SICS object for doing simple four circle measurements with a single@\\
\mbox{}\verb@ counter. @\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see copyright.h@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koenencke, April 1998@\\
\mbox{}\verb@---------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSMESURE@\\
\mbox{}\verb@#define SICSMESURE@\\
\mbox{}\verb@@$\langle$mesureint {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

209
doc/programmer/motor.tex Normal file
View File

@@ -0,0 +1,209 @@
\subsection{Motors}
Most neutron scattering instruments have lots of motors to drive
monochromators, samples and detectors through space.This module implements
support for them. As usual for hardware objects in SICS motors are
subdivided into a driver and the logical object.
\subsubsection{The Motor Driver}
There is a problem here. There are some data fields and functions
which must be present for any motor driver. Then there are fields
which are specific just to a special implementation of a mot
driver. There are several ways to deal with this. The way choosen for
the motor driver is a kind of overlay. The first few fields of a valid
motor driver structure MUST be specified in the same order as given
below. A special motor driver can add additional fields at the end of
the standard list. As an example for this scheme compare the
AbstractMoDriv structure with the one for the EL734 motor driver.
\begin{verbatim}
typedef struct __AbstractMoDriv {
/* general motor driver interface
fields. REQUIRED!
*/
float fUpper; /* upper limit */
float fLower; /* lower limit */
char *name;
int (*GetPosition)(void *self, float *fPos);
int (*RunTo)(void *self,float fNewVal);
int (*GetStatus)(void *self);
void (*GetError)(void *self, int *iCode, char *buffer, int iBufLen);
int (*TryAndFixIt)(void *self, int iError,float fNew);
int (*ContinueAfterWarn)(void *self);
int (*Halt)(void *self);
}
MotorDriver;
\end{verbatim}
All functions return 0 on failure or 1 on success, if not stated otherwise.
The first parameter is always a pointer to the motor driver structure.
The fields and their meanings: \begin{description}
\item[fUpper,fLower] The hardware upper and lower limits for the motor.
These are the real hardware limits as implemented by limit switches bolted
to the instrument.
\item[name] The real motor name.
\item[GetPosition] retrieves the current hardware position of the motor into
fPos.
\item[RunTo] starts the motor to run to fNewVal. This sends a command to the
motor and returns immediately.
\item[GetStatus] requests the status from the motor. Possible answers are:
\begin{description}
\item[HWIdle, OKOK] The motor has finished or is idle.
\item[HWFault] A fault has been found at the motor.
\item[HWBusy] The motor is busy moving.
\item[HWWarn] The motor hardware complained but managed to reach the
requested position.
\item[HWPosFault] The motor could not go where it should go for some reason.
However, the motor is intact and ready to move somewhere else. This can
happen when there is a concrete block in the instruments way which is not
accounted for by a limit switch. This can also happen when the motor hits a
limit switch. However, the general idea of SICS is that the limits will be
checked for before even starting to run the motor. In order for this to
work, the limits SICS knows about must macth those actually implemented.
\end{description}
\item[GetError] This gets called when an error has been detected during one
of the previous operations. The function has to return more information
about the error: iCode an driver dependent integer error code and maximum
iErrLen characters of problem description in error.
\item[TryAndFixIt] takes the integer error code returned in iCode from
GetError and tries to solve the problem with the hardware. This function can
either return MOTREDO which means the problem has been fixed and the
operation needs to be redone, MOTOK when the problem has been fixed and no
resending of a command is necessary or MOTFAIL which means that it is not
possible to resolve the problem in software.
\item[ContinueAfterWarn] will be called after a warning from the motor. This
function is supposed to do whatever is needed to clear the warning from the
motor and keep him going.
\item[Halt] emergency stop the motor, NOW.
\end{description}
As an example for a derived motor driver the SINQ EL734 motor driver is
shown below. It add to the general fields the special things for that motor:
host, port and channel number of the motor controller and a pointer to the
driver communications structure.
\begin{verbatim}
typedef struct __MoDriv {
/* general motor driver interface
fields. REQUIRED!
*/
float fUpper; /* upper limit */
float fLower; /* lower limit */
char *name;
int (*GetPosition)(void *self,float *fPos);
int (*RunTo)(void *self, float fNewVal);
int (*GetStatus)(void *self);
void (*GetError)(void *self, int *iCode, char *buffer, int iBufLen);
int (*TryAndFixIt)(void *self,int iError, float fNew);
int (*ContinueAfterWarn)(void *self);
int (*Halt)(void *self);
/* EL-734 specific fields */
int iPort;
char *hostname;
int iChannel;
int iMotor;
void *EL734struct;
int iMSR;
} EL734Driv;
\end{verbatim}
Most of the interaction with the motor driver happens through the functions
defined in its data structure. The rest is creation and deletion:
\begin{description}
\item[MotorDriver *CreateEL734(SConnection *pCon, int argc, char
*argv[])]
creates a EL734 motor driver. The argc, \verb+argv[]+ pair contains the
necessary drive parameters.
\item[MotorDriver *CreateEL734DC(SConnection *pCon, int argc, char
*argv[])]
created an EL734 DC motor driver.
\item[void KillEL734(void *pData)] deletes a EL734 motor driver.
\item[MotorDriver *CreateSIM(SConnection *pCon, int argc, char *argv[])]
creates a simulation motor driver.
\item[void KillSIM(void *pData)] deletes a simulated motor driver.
\end{description}
\subsubsection{The Motor Logical Object}
The motor object represents the motor to SICS. One of its responsabilities
is to drive motor operations and error checking. The scheme
implemented is that the motor object tries to bring the motor to its
position at least three times before a failure is recorded. Also the
motor object keeps track of a count of failed operations. If this
count gets to high an interrupt is issued to stop the instrument. This
was put in after Druechal tried to drive over a slab of concrete for a
whole night and subsequently broke a clutch.
Motors are represented by the
following data structure:
\begin{verbatim}
typedef struct __Motor {
pObjectDescriptor pDescriptor;
ObPar *ParArray;
pIDrivable pDrivInt;
pICallBack pCall;
char *drivername;
char *name;
MotorDriver *pDriver;
float fTarget;
float fPosition;
} Motor;
typedef Motor *pMotor;
\end{verbatim}
The fields: \begin{description}
\item[pDescriptor] The usual SICS object descriptor.
\item[ParArray] A dictionary of parameter names and float values. This array
holds all the different parameters used to operate the motor.
\item[pDrivInt] A pointer to the drivable interface implemented by the motor
object.
\item[pCall] A pointer to the callback interface implemented by the motor
object.
\item[drivername] The name of the motor driver.
\item[name] The name of the motor.
\item[pDriver] A pointer to the motor driver to use.
\item[fTarget] The target position for the motor.
\item[fPosition] The last known position of the motor.
\end{description}
Much of the action of the motor is hidden in the implementation of the
drivable interface to the motor. Additionally the functions as given below
are defined. All functions take a pointer to the motor object data structure
as a parameter. They retun 0 on success or 1 on failure while not stated
otherwise.
\begin{description}
\item[int MotorGetPar(pMotor self, char *name, float *fVal)] retrieves the
value of the parameter name in fVal.
\item[int MotorSetPar(pMotor self, SConnection *pCon, char *name, float
fVal)] tries to write fVal to the parameter name. Errors are written to
the connection pCon.
\item[long MotorRun(void *self, SConnection *pCon, float fNew)] starts a
motor running to fNew. Does not wait for the motor to finish.
\item[int MotorCheckBoundary(pMotor self, float fVal, float *fHard,
char *error, int iErrLen)] checks if the position
fVal violates any of the motors software or hardware limits. In case of
success a new hardware position is returned in fHard. fHard is then
corrected for possible software zero points. In case of a limit violation
maximum iErrLen characters of error information are returned in error.
\item[int MotorCheckPosition(void *self, SConnection *pCon)] returns 1 if
the motor is at the target position, 0 else, or -1 if the motor could not be
read.
\item[int MotorGetSoftPosition(pMotor self,SConnection *pCon, float *fVal)]
reads the current motor position into fVal. This position is corrected for
software zero points.
\item[int MotorGetHardPosition(pMotor self,SConnection *pCon, float *fVal)]
reads the current position of the motor as returned from the hardware.
\item[int MakeMotor(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])] the motor factory function. To
be hacked when a new driver needs to be included.
\item[pMotor MotorInit(char *drivername,char *name, MotorDriver *pDriv)]
creates a new motor object with driver pDriv. Returns NULL on failure.
\item[void MotorKill(void *self)] deletes a motor object. Needs to be
modified for a new driver in order to clean out the new driver properly.
\item[int MotorAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])] the object wrapper function for
the motor. Implements the user interface.
\item[pMotor FindMotor(SicsInterp *pSics, char *name)] finds a motor name in
the interpreter pSics. This is a convenience function. Returns NULL if no
motor could be found, else a pointer to its data structure.
\end{description}

49
doc/programmer/mumo.tex Normal file
View File

@@ -0,0 +1,49 @@
\subsection{Multiple Motors}
Multiple Motors is a module which implements a special syntax for SANS.
Motors are collected into a group. For example beamstop and manipulated
through them. Furthermore multiple motors support named positions and a
special position {\bf back} which is the position before the last movement.
Multiple Motors works, but it if larger changes become necessary it might be
sensible to drop it and replace it by a work alike in the macro language.
Please note, that multiple motors starts motors to run, but does not wait
for them to finish.
Multiple motors are characterized through the following data structure:
\begin{verbatim}
typedef struct __MULMOT {
pObjectDescriptor pDes;
char *name;
pStringDict pAlias;
pStringDict pNamPos;
ObPar *pParam;
} MulMot;
\end{verbatim}
The fields are:
\begin{description}
\item[pDes] A pointer to the usual SICS object descriptor.
\item[name] The name of the multi motor.
\item[pAlias] A string dictionary which maps group internal motor names to
real SICS motor names.
\item[pNamPos] A string dictionary which maps named positions to the SICS
command necessary to run to that position.
\end{description}
Multiple motors are interfaced to with the following functions:
\begin{description}
\item[pMulMot MakeMultiMotor(void)] creates multi motors device. Returns a
pointer to a new data structure on success, NULL in case of failure.
\item[void KillMultiMotor(void *pData)] deletes a multi motor device.
\item[int MultiWrapper(SConnection *pCon, SicsInterp *pSics, void *pData, \\
int argc, char *argv[])] The object wrapper function for
multiple motors.
\item[int MakeMulti(SConnection *pCon, SicsInterp *pSics, void *pData,\\
int argc, char *argv[])] The object factory function for
multiple motors.
\item[int ConfigMulti(SConnection *pCon, SicsInterp *pSics, void *pData,\\
int argc, char *argv[])] The configuration function for
multiple motors.
\end{description}
The implementation of multiple motors can be found in files mumo.c,
mumoconf.c, mumo.h and mumo.i.

1850
doc/programmer/napi.tex Normal file

File diff suppressed because it is too large Load Diff

389
doc/programmer/nconman.tex Normal file
View File

@@ -0,0 +1,389 @@
\subsection{The Connection Object}
The connection object is a major player in the SICS world. The connection
object represents an active connection between the SICS server and a client.
There will be one connection object for each client connection. A lot of
stuff is associated with a client connection:
\begin{itemize}
\item A task. This task will read one command from the command fifo and
execute it.
\item A command fifo which will be filled by the network reader.
\item An execution context consisting of user rights for this connection
and interrupt status.
\item A communication channel to the client.
\item A list of log files to which all traffic on the connection will be
logged.
\item An interface to the SICS interpreter which allows to configure
certain aspects of the connection and makes the connection available as
a command.
\item A list of callbacks registered for the connection. A connection can
be automatically notified about changes in system state. These callbacks
have to be removed when the client server connection terminates. Otherwise
callback code would write to a dead connection causing the program to
crash.
\end{itemize}
\subsubsection{Connection I/O}
Due to user requirements for features not considered in the design the
I/O facilities of connection have become quite involved.
Incoming commands are printed into client log files if configured, and
into the commandlog if the connection has a privilege $\ge$ user
privilege. This is implemented in SCInvoke. Also each command is
printed to the server log.
Output is more sophisticated. First of all there are different output
codes given as last parameter to SCWrite. The most important of these
are:
\begin{description}
\item[eError] Error messages.
\item[Warning] warnings.
\item[Value] values requested by the client.
\item[Status] status messages.
\end{description}
Clients can choose to suppress certain types of messages in order to
reduce I/O.
The logic is mostly implemented in the
file static function SCNormalWrite. The follwoing conditions are
implemented:
\begin{itemize}
\item Any output is logged to the
server log.
\item If the privilege of the connection is $\ge$ user the
output is printed to the commandlog as well.
\item If the command is executing as part of a Tcl--macro script
output to the socket is suppressed. The output is copied into the
interpreter for further evaluation instead. This is done in order to
prevent excessive output during macro evaluation and in order to make
SICS results available in the Tcl interpreter. However, messages of
type error or warning are printed to the socket even during macro
evaluation.
\item In the normal case the output is printed to the socket and all
log files configured for the connection.
\item As of recent the output function can be modified by setting a
new function. One sich function exists which supresses all output to
the socket. This is done in order to help when the connection gets
lost. For instance with the cron command.
\end{itemize}
This aspect of the connection object could do with a cleanup. A
possible cleanup path is the implementation of the different output
strategies in different functions and devise a SCsetOutMode function which
switches between the various possibilities. Also, it can be argued if
the client specific log files are still needed. Then this part of the
code can be cleaned out as well.
\subsubsection{Command Execution Path}
In the course of the SICS development the path of a command through
the system has become more complex as well. This section describes how
it works. The incoming command is collected at the socket by the
NetReaderTask. This does a little processing and checks for interrupts
issued on the connection and invokes them. But any normal command is
put into the connections Command-FIFO. Thus ends the business of the
NetReaderTask. The connections task function SCTaskFunction is
invoked by the task manager in due time and checks for pending
commands on the command stack. If a command is pending it is taken
from the stack and executed through SCInvoke.
\subsubsection{Execution context}
Each connection has a user right code associated with it. The there is
a second protection scheme in SICS with the token system. This system
reserves command input to a certain connection. In the connection
object this scheme requires the iGrab field which defines if this
connection may execute commands or not. This field is modified through
the tasks signal handling function. Code implementing a command may
call SCMatchRights in order to check for permission. SCMatchRights
will also send appropriate error messages.
Errors are usually signalled by setting an interrupt code on the
connection. An additional field, iError allows to give a more detailed
error description if required.
\subsubsection{Callbacks}
SICS can be configured to forward notifications about certain state
changes to a connection automatically. This is implemented through the
callback system. For more details see \ref{inter}. However, it is
important that any callback acting on a connection is registered with
the connection object. This allows the removal of the callback when
the connection is closed. Otherwsie the system gets filled up with
dead callbacks which usuallly cause core dumps when it is tried to
send a message to a dead connection.
\subsubsection{The Connection Data Structure}
Given the plethora of things to take care of, each connection is
represented by a rather large data structure.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$condat {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __SConnection {@\\
\mbox{}\verb@ /* object basics */@\\
\mbox{}\verb@ pObjectDescriptor pDes;@\\
\mbox{}\verb@ char *pName;@\\
\mbox{}\verb@ long lMagic;@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ /* I/O control */@\\
\mbox{}\verb@ mkChannel *pSock;@\\
\mbox{}\verb@ FILE *pFiles[MAXLOGFILES];@\\
\mbox{}\verb@ int iMacro;@\\
\mbox{}\verb@ int iTelnet;@\\
\mbox{}\verb@ int iOutput; @\\
\mbox{}\verb@ int iFiles;@\\
\mbox{}\verb@ int (*write)(struct __SConnection *pCon,@\\
\mbox{}\verb@ char *pMessage, int iCode);@\\
\mbox{}\verb@ mkChannel *pDataSock;@\\
\mbox{}\verb@ char *pDataComp;@\\
\mbox{}\verb@ int iDataPort;@\\
\mbox{}\verb@@\\
\mbox{}\verb@ /* execution context */@\\
\mbox{}\verb@ int eInterrupt;@\\
\mbox{}\verb@ int iUserRights;@\\
\mbox{}\verb@ int inUse;@\\
\mbox{}\verb@ int iDummy;@\\
\mbox{}\verb@ int iGrab;@\\
\mbox{}\verb@ int iErrCode;@\\
\mbox{}\verb@ SicsInterp *pSics;@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ /* a FIFO */@\\
\mbox{}\verb@ pCosta pStack;@\\
\mbox{}\verb@@\\
\mbox{}\verb@ /* callback registry */@\\
\mbox{}\verb@ int iList;@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ /* Tasking Stuff */@\\
\mbox{}\verb@ int iEnd;@\\
\mbox{}\verb@ }SConnection;@\\
\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 fields are:
\begin{description}
\item[pDes] The usual object descriptor belonging to any object within the
SICS interpreter. See \ref{inter} for details.
\item[pName] The automatically generated name of the connection object in the
interpreter.
\item[lMagic] is a magic number used internally in order to check if
the connection object given as a parameter is valid.
\item[pChannel] A pointer to a network channel structure. This channel
will be used for I/O to the client. If thispointer is NULL I/O is done onto
stdin/stdout instead.
\item[pFiles] An array of file to which all I/O on this connection will be
logged.
\item[iOutPut] The currently valid output mask. SICS messages are classified
into several output classes. If a message is going to be printed it must
have a output class above the one configured as the mask. This was made in
order to allow clients to suppress certain messages which are not of
interest.
\item[iFiles] The number of configured log files.
\item[write] a pointer to a function which does the actual writing of
a message to the connection.
\item[iTelnet] is true when I/O is through a telnet connection.
\item[iMacro] This flag is set when the connection is executing a Tcl
script. In this mode mode all output is written into the Tcl interpreter and
not written to the client. Thus a script can execute silently. As always,
there is an exception: errors and warning will still be written to the
client.
\item[iGrab] This is 0 when the connection may execute commands. It is 1 if
another connection has grabbed the control token and commands may not be
executed. For details about the token system, see the token reference.
\item[eInterrupt] This is the current interrupt status of the connection.
\item[iUserRights] This integer denotes the user rights associated with the
connection. This value is initially deducted from the username password pair
given at login to SICS. The value can be configured otherwise afterwards.
iUserRights will be used to check at object level if a client may perform
the requested operation or not.
\item[iErrCode] is the last error code. I think this field is no longer
used.
\item[pSics] is a pointer to an SICS interpreter where to invoke commands.
\item[pStack] Is the command FIFO.
\item[iList] This is the identifier of a lld list which holds the callbacks
registered on this connection object.
\item[iEnd] iEnd is a flag which is usually 0. It is set by certain
interrupts or if the connection is broken and causes the connection task to
end and the connection data structure to be removed from the system.
\end{description}
Quite a few places in SICS refer to this data structure directly,
without a function interface. The reason for this is performance. Therefore
this data structure is made public in the conman.h file.
\subsubsection{Connection Functions}
The interface to this data structure is defined by the following functions:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$conint {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*------------------------------ live & death ----------------------------*/@\\
\mbox{}\verb@ SConnection *SCreateConnection(SicsInterp *pSics, mkChannel *pSock,@\\
\mbox{}\verb@ int iUserRights);@\\
\mbox{}\verb@ SConnection *SCCreateDummyConnection(SicsInterp *pSics);@\\
\mbox{}\verb@ void SCDeleteConnection(void *pVictim);@\\
\mbox{}\verb@ @\\
\mbox{}\verb@/*------------------------------- tasking --------------------------------*/@\\
\mbox{}\verb@ int SCTaskFunction(void *pCon);@\\
\mbox{}\verb@ void SCSignalFunction(void *pCon, int iSignal, void *pSigData);@\\
\mbox{}\verb@/* ***************************** I/O ************************************** */@\\
\mbox{}\verb@ int SCAddLogFile(SConnection *self, char *name);@\\
\mbox{}\verb@ int SCDelLogFile(SConnection *pCon, int iFile);@\\
\mbox{}\verb@ void SCSetOutputClass(SConnection *self, int iClass);@\\
\mbox{}\verb@ int SCWrite(SConnection *self, char *pBuffer, int iOut);@\\
\mbox{}\verb@ int SCRead(SConnection *self, char *pBuffer, int iBufLen); @\\
\mbox{}\verb@ int SCPrompt(SConnection *pCon, char *pPrompt, char *pResult, int iLen);@\\
\mbox{}\verb@ int SCSendOK(SConnection *self);@\\
\mbox{}\verb@ int SCnoSock(SConnection *pCon);@\\
\mbox{}\verb@ int SCWriteUUencoded(SConnection *pCon, char *pName, void *iData, int iLen);@\\
\mbox{}\verb@/************************* CallBack *********************************** */@\\
\mbox{}\verb@ int SCRegister(SConnection *pCon, SicsInterp *pSics,@\\
\mbox{}\verb@ void *pInter, long lID);@\\
\mbox{}\verb@ int SCUnregister(SConnection *pCon, void *pInter);@\\
\mbox{}\verb@/******************************* Error **************************************/@\\
\mbox{}\verb@ void SCSetInterrupt(SConnection *self, int eCode);@\\
\mbox{}\verb@ int SCGetInterrupt(SConnection *self); @\\
\mbox{}\verb@ void SCSetError(SConnection *pCon, int iCode);@\\
\mbox{}\verb@ int SCGetError(SConnection *pCon); @\\
\mbox{}\verb@/****************************** Macro ***************************************/@\\
\mbox{}\verb@ int SCinMacro(SConnection *pCon);@\\
\mbox{}\verb@ int SCsetMacro(SConnection *pCon, int iMode); @\\
\mbox{}\verb@@\\
\mbox{}\verb@/* *************************** Info *************************************** */@\\
\mbox{}\verb@ int SCGetRights(SConnection *self);@\\
\mbox{}\verb@ int SCSetRights(SConnection *pCon, int iNew);@\\
\mbox{}\verb@ int SCMatchRights(SConnection *pCon, int iCode);@\\
\mbox{}\verb@ int SCGetOutClass(SConnection *self);@\\
\mbox{}\verb@ int SCGetGrab(SConnection *pCon);@\\
\mbox{}\verb@@\\
\mbox{}\verb@/* **************************** Invocation ******************************** */@\\
\mbox{}\verb@ int SCInvoke(SConnection *self,SicsInterp *pInter,char *pCommand);@\\
\mbox{}\verb@ @\\
\mbox{}\verb@/*************************** User Command **********************************/@\\
\mbox{}\verb@ int ConfigCon(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]); @\\
\mbox{}\verb@ int ConSicsAction(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}
The functions in more detail:
\begin{description}
\item[SCreateConnection] creates a new connection object. Parameters to this
call are a pointer to a server data structure, a pointer to a network
connection object and the user rights to use in this connection. This
also adds a new task function for this connection to the task object.
\item[SCCreateDummyConnection] creates a dummy connection for use during
system initialisation. Printing to a socket will be suppressed for such a connection. But the output is printed to stdout.
\item[SCTaskFunction] is the task function which will be registered with the
Tasker. This function reads a new command from the command stack (if
available) and executes it in the interpreter.
\item[SCSignalFunction] is the signal function for the connection
object. This function handles interrupts and the token security
system.
\item[SCDeleteConnection] deletes a connection object and all its data
structures. This function will be automatically called by the tasker when
the task function returns with a 0.
\item[SCAddLogFile] configures the log file name into the connection object.
If this suceeds all I/O to the connection will be logged to this file as
well.
\item[SCSetOutputClass] sets the output class for the connection.
\item[SCGetOutClass] returns the output class of the connection.
\item[SCWrite] is the most important function of SConnection. Writes the
buffer pBuffer with output code iOut to the client. {\em All output to the
client has to be channelled through this function!}
\item[SCRead] reads data from the client connection into the buffer pBuffer,
but maximum iBufLen bytes.
\item[SCPrompt] prompts the client for a reply. But waits only for certain
timeout period. pPrompt is the prompt for the client, pResult is the buffer
with the client reply. Maximum iLen bytes will be copied to
pResult. Returns true (1) on a successfull read, else 0 (false).
\item[SCSendOK] A short cut which sends OK to the client.
\item[SCRegister] registers a callback with the connection. Parameters are:
The interpreter to use, the interface with which the callback was
registered and the ID of the callback. All automatic notifications to a
client MUST be registered with this call. When the connection is deleted all
these callbacks will be removed as well. Otherwise a core dump is bound to
happen.
\item[SCUnregister] will remove all callbacks on interface pInter for this
connection.
\item[SCSetInterrupt] sets an interrupt on the connection.
\item[SCGetInterrupt] retrives the current interrupt status of the
connection.
\item[SCSetError] sets an error code in the connection.
\item[SCGetError] retreives the current error code on the connection.
\item[SCinMacro] returns true if the connection is executing a tcl script,
returns false otherwise.
\item[SCsetMacro] sets the iMacro flag.
\item[SCGetRights] returns the current user rights associated with the
connection.
\item[SCGetGrab] gets the status of the control token for this connection.
This calls returns 0 if the connection may execute commands and 1 if another
connection has the control token.
\item[SCSetRights] sets the user rights for the connection to a new value.
\item[SCMatchRights] return true (1) if the iCode matches with the user
rights of the connection, 0 (false) otherwise. SCMatchRights also checks for
the status of the control token. Suitable error messages are written to pCon
if the user rights do not match.
\item[SCInvoke] invokes pCommand in the SICS interpreter pSics for the
connection pCon. This function also prints the executed command into
logfiles and into the commandlog.
\end{description}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
\verb@"conman.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------@\\
\mbox{}\verb@ C O N N E C T I O N O B J E C T@\\
\mbox{}\verb@@\\
\mbox{}\verb@ This file defines the connection object data structure and the interface to@\\
\mbox{}\verb@ this data structure. This is one of the most important SICS components.@\\
\mbox{}\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Substantially revised from a prior version.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, September 1997@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see copyright.h@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSCONNECT@\\
\mbox{}\verb@#define SICSCONNECT@\\
\mbox{}\verb@#include <stdio.h>@\\
\mbox{}\verb@#include "costa.h"@\\
\mbox{}\verb@#include "SCinter.h"@\\
\mbox{}\verb@#include "network.h"@\\
\mbox{}\verb@#include "obdes.h"@\\
\mbox{}\verb@@\\
\mbox{}\verb@#define MAXLOGFILES 10@\\
\mbox{}\verb@@$\langle$condat {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#include "nserver.h"@\\
\mbox{}\verb@@$\langle$conint {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@#endif @\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

View File

@@ -0,0 +1,38 @@
\subsection{The network module}
The network class encapsulates the network protocoll used for client server communications in SICS. This is the place to hack if SICS needs porting to other protocols. This class implements:\begin{verbatim}
typedef struct {
int sockid;
int iType;
struct sockaddr_in adresse;
} mkChannel;
\end{verbatim}
This is the datastructure maintained for each socket. Never deal with it
directly but through the functions given below. Wherever a timeout is
specified as a parameter below the following rule applies: If timout is
greater 0, then timeout means a time in milliseconds to wait with a select
system call for data to arrive. If timeout is less or equal then 0 the
socket will block on input.
\begin{itemize}
\item {\bf mkChannel *NETOpenPort(int iPort) }, opens a server port on port number iPort for listening. If successful returns a pointer to a fresh mkChannel datastructure , else NULL.
\item {\bf mkChannel *NETAccept(mkChannel *self, int timeout) }, waits timeout microseconds for a client requesting a connection to the server This is done with thke select system call. If a request comes in a new mkChannel structure is created and returned. If not NULL will be returned.
\item {\bf mkChannel *NETConnect(char *name, int port) } tries to connect to a server specified by the hostname name and the port number port. Returns a pointer to a new mkChannel structure on success, NULL else.
\item {\bf int NETWrite(mkChannel *self, char *buffer, long lLen) } writes lLen bytes from buffer to the socket specified by self. Returns True on succees, else False.
\item {\bf long NETRead(mkChannel *self, char *buffer, long lLen, int timeout) } waits timeout microseconds for data to arrive at the socket specified by self. If data is available it will be copied into the buffer, but to a maximum length of lLen. Returns the length of data read, 0 if there is no data and -1 if an EOF occured on the socket (i.e the partner closed the connection).
\item {\bf int NETClosePort(mkChannel *self) } If you are done with talking you can use this to close the connection. The socket specified by self can no longer be used after this. You still have to free the mkChannel though, if you want to do it properly. The function returns True on success, False (0) if the call failed.
\item {\bf mkChannel *UDPOpen(int iPort) } opens a port for connectionless UDP-connection.
\item {\bf mkChannel UDPConnect(int iPort) } connects a client to a UDP port for Data transfer.
\item {\bf long UDPRead(mkChannel self, char *buffer, long lLen, int timeout) } reads data from a UDP port inot buffer, but maximum lLen bytes. Waits maximum timeout microseconds for data. Returns the number of bytes read or -1 for end of file.
\item {\bf int UDPWrite(mkChannel *self, char *buffer, long lLen); } writes lLen bytes from buffer into an UDP channel.
\end{itemize}
SICS needs I/O multiplexing, that is it needs to be able to handle request
from many clients. Instead of spawning more processes or using threads with
all the synchronisation problems associated with both of the above, I/O
multiplexing is done with the select() system call here. Select uses a
funny mask as input which specifies the id of the stream it is interested
in. It requires the (stream-number (number, not FILE *) + 1 ) bit of the
mask to be set for interest in stream number. This mask is set using macros
defined in the apropriate header files.

660
doc/programmer/newsics.eps Normal file
View File

@@ -0,0 +1,660 @@
%!
%%BoundingBox: 2 358 358 785
%%Title: newsics
%%CreationDate: Thu Nov 20 13:43:31 1997
%%Creator: Tgif-3.0-p7 by William Chia-Wei Cheng (william@cs.UCLA.edu)
/tgifdict 4 dict def
tgifdict begin
/tgifarrowtipdict 8 dict def
tgifarrowtipdict /mtrx matrix put
/tgifarrowtip
{ tgifarrowtipdict begin
/dy exch def
/dx exch def
/h exch def
/w exch def
/y exch def
/x exch def
/savematrix mtrx currentmatrix def
x y translate
dy dx atan rotate
0 0 moveto
w neg h lineto
w neg h neg lineto
savematrix setmatrix
end
} def
end
%%PageBoundingBox: 2 358 358 785
tgifdict begin
/tgifsavedpage save def
1 setmiterlimit
1 setlinewidth
0 setgray
72 0 mul 72 11.00 mul translate
72 128 div 100.000 mul 100 div dup neg scale
gsave
/tgiforigctm matrix currentmatrix def
% TEXT
0 setgray
/Courier-Bold findfont [24 0 0 -24 0 0] makefont setfont
gsave
192 36 moveto (The Taskloop) show
grestore
% TEXT
0 setgray
/Courier findfont [17 0 0 -17 0 0] makefont setfont
gsave
192 94 moveto (Device) show
192 111 moveto (Executor) show
grestore
% TEXT
0 setgray
/Courier findfont [17 0 0 -17 0 0] makefont setfont
gsave
112 190 moveto (Network) show
112 207 moveto (Reader) show
grestore
% TEXT
0 setgray
/Courier findfont [17 0 0 -17 0 0] makefont setfont
gsave
224 270 moveto (Client1 ) show
grestore
% TEXT
0 setgray
/Courier findfont [17 0 0 -17 0 0] makefont setfont
gsave
352 270 moveto (Client2) show
grestore
% TEXT
0 setgray
/Courier findfont [17 0 0 -17 0 0] makefont setfont
gsave
448 222 moveto (Client3) show
grestore
% TEXT
0 setgray
/Courier findfont [17 0 0 -17 0 0] makefont setfont
gsave
384 142 moveto (Emon) show
grestore
% RCBOX
0 setgray
gsave
gsave
newpath
272 80 moveto
288 80 288 128 16 arcto 4 {pop} repeat
288 112 lineto
288 128 176 128 16 arcto 4 {pop} repeat
192 128 lineto
176 128 176 80 16 arcto 4 {pop} repeat
176 96 lineto
176 80 288 80 16 arcto 4 {pop} repeat
closepath
stroke
grestore
grestore
% RCBOX
0 setgray
gsave
gsave
newpath
192 176 moveto
208 176 208 224 16 arcto 4 {pop} repeat
208 208 lineto
208 224 96 224 16 arcto 4 {pop} repeat
112 224 lineto
96 224 96 176 16 arcto 4 {pop} repeat
96 192 lineto
96 176 208 176 16 arcto 4 {pop} repeat
closepath
stroke
grestore
grestore
% RCBOX
0 setgray
gsave
gsave
newpath
432 128 moveto
448 128 448 160 16 arcto 4 {pop} repeat
448 144 lineto
448 160 368 160 16 arcto 4 {pop} repeat
384 160 lineto
368 160 368 128 16 arcto 4 {pop} repeat
368 144 lineto
368 128 448 128 16 arcto 4 {pop} repeat
closepath
stroke
grestore
grestore
% RCBOX
0 setgray
gsave
gsave
newpath
288 240 moveto
304 240 304 288 16 arcto 4 {pop} repeat
304 272 lineto
304 288 208 288 16 arcto 4 {pop} repeat
224 288 lineto
208 288 208 240 16 arcto 4 {pop} repeat
208 256 lineto
208 240 304 240 16 arcto 4 {pop} repeat
closepath
stroke
grestore
grestore
% RCBOX
0 setgray
gsave
gsave
newpath
416 240 moveto
432 240 432 288 16 arcto 4 {pop} repeat
432 272 lineto
432 288 336 288 16 arcto 4 {pop} repeat
352 288 lineto
336 288 336 240 16 arcto 4 {pop} repeat
336 256 lineto
336 240 432 240 16 arcto 4 {pop} repeat
closepath
stroke
grestore
grestore
% RCBOX
0 setgray
gsave
gsave
newpath
512 192 moveto
528 192 528 240 16 arcto 4 {pop} repeat
528 224 lineto
528 240 448 240 16 arcto 4 {pop} repeat
464 240 lineto
448 240 448 192 16 arcto 4 {pop} repeat
448 208 lineto
448 192 528 192 16 arcto 4 {pop} repeat
closepath
stroke
grestore
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
152 224 moveto
32 48 atan dup cos 12.000 mul 200 exch sub
exch sin 12.000 mul 256 exch sub lineto
tgiforigctm setmatrix
3 setlinewidth
stroke
1 setlinewidth
grestore
gsave
tgiforigctm setmatrix
newpath
200 256 12.000 5.000 48 32 tgifarrowtip
1 setgray closepath fill
0 setgray
newpath
200 256 12.000 5.000 48 32 tgifarrowtip
closepath fill
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
304 264 moveto
0 24 atan dup cos 12.000 mul 328 exch sub
exch sin 12.000 mul 264 exch sub lineto
tgiforigctm setmatrix
3 setlinewidth
stroke
1 setlinewidth
grestore
gsave
tgiforigctm setmatrix
newpath
328 264 12.000 5.000 24 0 tgifarrowtip
1 setgray closepath fill
0 setgray
newpath
328 264 12.000 5.000 24 0 tgifarrowtip
closepath fill
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
432 272 moveto
-24 32 atan dup cos 12.000 mul 464 exch sub
exch sin 12.000 mul 248 exch sub lineto
tgiforigctm setmatrix
3 setlinewidth
stroke
1 setlinewidth
grestore
gsave
tgiforigctm setmatrix
newpath
464 248 12.000 5.000 32 -24 tgifarrowtip
1 setgray closepath fill
0 setgray
newpath
464 248 12.000 5.000 32 -24 tgifarrowtip
closepath fill
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
504 192 moveto
-40 -48 atan dup cos 12.000 mul 456 exch sub
exch sin 12.000 mul 152 exch sub lineto
tgiforigctm setmatrix
3 setlinewidth
stroke
1 setlinewidth
grestore
gsave
tgiforigctm setmatrix
newpath
456 152 12.000 5.000 -48 -40 tgifarrowtip
1 setgray closepath fill
0 setgray
newpath
456 152 12.000 5.000 -48 -40 tgifarrowtip
closepath fill
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
368 144 moveto
32 -152 atan dup cos 12.000 mul 216 exch sub
exch sin 12.000 mul 176 exch sub lineto
tgiforigctm setmatrix
3 setlinewidth
stroke
1 setlinewidth
grestore
gsave
tgiforigctm setmatrix
newpath
216 176 12.000 5.000 -152 32 tgifarrowtip
1 setgray closepath fill
0 setgray
newpath
216 176 12.000 5.000 -152 32 tgifarrowtip
closepath fill
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
[4 12] 0 setdash
newpath
368 136 moveto
-32 -64 atan dup cos 10.000 mul 304 exch sub
exch sin 10.000 mul 104 exch sub lineto
tgiforigctm setmatrix
2 setlinewidth
stroke
[] 0 setdash
1 setlinewidth
grestore
gsave
tgiforigctm setmatrix
newpath
304 104 10.000 4.000 -64 -32 tgifarrowtip
1 setgray closepath fill
0 setgray
newpath
304 104 10.000 4.000 -64 -32 tgifarrowtip
closepath fill
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
[4 12] 0 setdash
newpath
176 104 moveto
64 -32 atan dup cos 10.000 mul 144 exch sub
exch sin 10.000 mul 168 exch sub lineto
tgiforigctm setmatrix
2 setlinewidth
stroke
[] 0 setdash
1 setlinewidth
grestore
gsave
tgiforigctm setmatrix
newpath
144 168 10.000 4.000 -32 64 tgifarrowtip
1 setgray closepath fill
0 setgray
newpath
144 168 10.000 4.000 -32 64 tgifarrowtip
closepath fill
grestore
% TEXT
0 setgray
/Courier-Bold findfont [20 0 0 -20 0 0] makefont setfont
gsave
128 407 moveto (SICS Interpreter and Macro Language) show
grestore
% TEXT
0 setgray
/Courier-Bold findfont [25 0 0 -25 0 0] makefont setfont
gsave
136 508 moveto (SICS Object Database) show
grestore
% BOX
0 setgray
gsave
10 setmiterlimit
gsave
newpath
104 472 moveto 536 472 lineto 536 536 lineto 104 536 lineto
closepath
2 setlinewidth
stroke
grestore
grestore
% TEXT
0 setgray
/Courier-Bold findfont [25 0 0 -25 0 0] makefont setfont
gsave
128 700 moveto (Hardware ) show
grestore
% BOX
0 setgray
gsave
10 setmiterlimit
gsave
newpath
112 664 moveto 576 664 lineto 576 768 lineto 112 768 lineto
closepath
2 setlinewidth
stroke
grestore
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
280 432 moveto
40 0 atan dup cos 14.000 mul 280 exch sub
exch sin 14.000 mul 472 exch sub lineto
tgiforigctm setmatrix
4 setlinewidth
stroke
1 setlinewidth
grestore
gsave
tgiforigctm setmatrix
newpath
280 472 14.000 6.000 0 40 tgifarrowtip
1 setgray closepath fill
0 setgray
newpath
280 472 14.000 6.000 0 40 tgifarrowtip
closepath fill
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
176 536 moveto
120 0 atan dup cos 14.000 mul 176 exch sub
exch sin 14.000 mul 656 exch sub lineto
tgiforigctm setmatrix
4 setlinewidth
stroke
1 setlinewidth
grestore
gsave
tgiforigctm setmatrix
newpath
176 656 14.000 6.000 0 120 tgifarrowtip
1 setgray closepath fill
0 setgray
newpath
176 656 14.000 6.000 0 120 tgifarrowtip
closepath fill
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
320 536 moveto
120 -104 atan dup cos 14.000 mul 216 exch sub
exch sin 14.000 mul 656 exch sub lineto
tgiforigctm setmatrix
4 setlinewidth
stroke
1 setlinewidth
grestore
gsave
tgiforigctm setmatrix
newpath
216 656 14.000 6.000 -104 120 tgifarrowtip
1 setgray closepath fill
0 setgray
newpath
216 656 14.000 6.000 -104 120 tgifarrowtip
closepath fill
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
408 536 moveto
120 80 atan dup cos 14.000 mul 488 exch sub
exch sin 14.000 mul 656 exch sub lineto
tgiforigctm setmatrix
4 setlinewidth
stroke
1 setlinewidth
grestore
gsave
tgiforigctm setmatrix
newpath
488 656 14.000 6.000 80 120 tgifarrowtip
1 setgray closepath fill
0 setgray
newpath
488 656 14.000 6.000 80 120 tgifarrowtip
closepath fill
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
[12 4] 0 setdash
newpath
248 288 moveto
80 0 atan dup cos 8.000 mul 248 exch sub
exch sin 8.000 mul 368 exch sub lineto
tgiforigctm setmatrix
1 setlinewidth
stroke
[] 0 setdash
grestore
gsave
tgiforigctm setmatrix
newpath
248 368 8.000 3.000 0 80 tgifarrowtip
1 setgray closepath fill
0 setgray
newpath
248 368 8.000 3.000 0 80 tgifarrowtip
closepath fill
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
[12 4] 0 setdash
newpath
376 288 moveto
80 -120 atan dup cos 8.000 mul 256 exch sub
exch sin 8.000 mul 368 exch sub lineto
tgiforigctm setmatrix
1 setlinewidth
stroke
[] 0 setdash
grestore
gsave
tgiforigctm setmatrix
newpath
256 368 8.000 3.000 -120 80 tgifarrowtip
1 setgray closepath fill
0 setgray
newpath
256 368 8.000 3.000 -120 80 tgifarrowtip
closepath fill
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
[12 4] 0 setdash
newpath
504 240 moveto
496 312 lineto
56 -224 atan dup cos 8.000 mul 272 exch sub
exch sin 8.000 mul 368 exch sub lineto
tgiforigctm setmatrix
1 setlinewidth
stroke
[] 0 setdash
grestore
gsave
tgiforigctm setmatrix
newpath
272 368 8.000 3.000 -224 56 tgifarrowtip
1 setgray closepath fill
0 setgray
newpath
272 368 8.000 3.000 -224 56 tgifarrowtip
closepath fill
grestore
% TEXT
0 setgray
/Courier findfont [17 0 0 -17 0 0] makefont setfont
gsave
504 310 moveto (send commands) show
grestore
% TEXT
0 setgray
/Courier findfont [17 0 0 -17 0 0] makefont setfont
gsave
488 166 moveto (pass execution) show
grestore
% BOX
0 setgray
gsave
10 setmiterlimit
gsave
newpath
96 368 moveto 624 368 lineto 624 432 lineto 96 432 lineto
closepath
2 setlinewidth
stroke
grestore
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
8 16 moveto
56 120 lineto
64 72 lineto
104 168 lineto
tgiforigctm setmatrix
4 setlinewidth
stroke
1 setlinewidth
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
104 168 moveto
80 152 lineto
tgiforigctm setmatrix
4 setlinewidth
stroke
1 setlinewidth
grestore
% POLY/OPEN-SPLINE
0 setgray
gsave
newpath
104 168 moveto
112 144 lineto
tgiforigctm setmatrix
4 setlinewidth
stroke
1 setlinewidth
grestore
% TEXT
0 setgray
/Courier findfont [17 0 0 -17 0 0] makefont setfont
gsave
40 62 moveto (TCP/IP) show
grestore
grestore
tgifsavedpage restore
end
%MatchingCreationDate: Thu Nov 20 13:43:31 1997

BIN
doc/programmer/newsics.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

160
doc/programmer/nread.tex Normal file
View File

@@ -0,0 +1,160 @@
\subsection{The Network Reader}
The network readers task is to read incoming messages for the SICS server.
These may come in four main forms.
\begin{itemize}
\item connection requests
\item commands
\item interrupts
through a command channel
\item interrupt messages on the UDP port.
\end{itemize}
A prior
version of SICS had a select system call for each of these cases. It was
found, that the code spent most of its time in the select system call
thus intrdoducing a major performance problem.
The select system call can handle more then one file descriptor in one call.
This is exactly what this module handles. It does a global select on
all open sockets and forwards any pending data to approriate handlers.
This scheme brought a drastic
performance improvement.
Each of the messages to SICS is handled
differently:
A connection request will be validated, a new connection object will be
created and a new task for this connection object will be started.
A command will be placed in the apropriate command stack for the task
belonging to this connection to work on in a later stage. The netreader will
also take care that all commands are complete, this is the terminator
\verb+\n+ or \verb+\r+ has been sent.
Both forms of interrupt will be interpreted and a suitable signal
will be sent to all runing tasks if the interrupt request is valid.
In order to perform his tasks the network reader needs to maintain a list of
all open sockets and their types. Additionally it needs to know about the
SICS tasker.
The early version of SICS only supported connections on a plain
socket. This feauture is not used any more in favour of the Telnet
option described below. However, as this may be used to transport
binary data, the obsolete code has not been removed.
Support for the internet TCP/IP standard telnet protocoll has been added in
January 1998. Telnet things need to be handled differently, therefore two
more socket types have been defined: A telnet listen socket on which
requests for telnet connections are listened for, and a telnet command
socket which actually process the telnet messages.
Support for user sockets was added in February 1998. User sockets provides a
primitive interface to the network readers monitoring functions. This is
part of a solution to one problem which can occur in SICS: The whole server
is blocked if one of the serial devices is slow in responding. User sockets
now provide a method for client code to register a socket for monitoring
with the network reader and find out if data is pending at it. This support
is provided by the functions: NetReadRegisterUserSocket,
NetReadRemoveUserSocket, NetReadReadable and NetReadResetUser described
below. NetReadWait4Data is a special wait function which waits for data to
come in on a user socket. This function is problematic with dynamically
creates and deleted objects such as environment device objects. Its use is
therefore no longer recommended.
Thus the interface looks like this:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$nrint {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------*/@\\
\mbox{}\verb@ typedef struct __netreader *pNetRead;@\\
\mbox{}\verb@ typedef enum {naccept, command, udp, user, taccept, tcommand} eNRType;@\\
\mbox{}\verb@/*--------------------------------------------------------------------------*/@\\
\mbox{}\verb@ pNetRead CreateNetReader(pServer pServ, int iPasswdTimeout,@\\
\mbox{}\verb@ int iReadTimeout);@\\
\mbox{}\verb@ void DeleteNetReader(void *pData);@\\
\mbox{}\verb@/*--------------------------------------------------------------------------*/@\\
\mbox{}\verb@ int NetReadRegister(pNetRead self, mkChannel *pSock, eNRType eType,@\\
\mbox{}\verb@ SConnection *pCon);@\\
\mbox{}\verb@ int NetReadRegisterUserSocket(pNetRead self, int iSocket);@\\
\mbox{}\verb@ int NetReadRemove(pNetRead self, mkChannel *pSock);@\\
\mbox{}\verb@ int NetReadRemoveUserSocket(pNetRead self, int iSocket);@\\
\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
\mbox{}\verb@ int NetReaderTask(void *pReader); @\\
\mbox{}\verb@ void NetReaderSignal(void *pUser, int iSignal, void *pSigData);@\\
\mbox{}\verb@ int NetReadWait4Data(pNetRead self, int iSocket);@\\
\mbox{}\verb@ int NetReadReadable(pNetRead self, int iSocket);@\\
\mbox{}\verb@ int NetReadResetUser(pNetRead self, int iSocket);@\\
\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}
This starts off with the definition of a data type for the net reader and an
enum which denotes the possible types of connections.
\begin{description}
\item[CreateNetReader] sets a new net reader up. Only parameter is a pointer
to the task manager to use while creating new connections. iPasswdTimeout
is the period in which a client is expected to send his userid/password
pair. iReadTimeout is the time to wait on the select statement for a
channel to become readable. Both time values are specified in milliseconds.
\item[DeleteNetReader] deletes the net reader and all its data structures.
Must be called in order to free all memory.
\item[NetReadRegister] register the channel pSock of type eType with the net
reader self. The parameter pData will only be interpreted for connections
of type command. It must point to the command stack belonging to the
connection which registers this socket.
\item[NetReadRegisterUserSocket] registers a socket from within SICS foth
the network reader. The client code to this module may then find out with a
call to NetReadReadable if data is pending on this socket. This a
convenience wrapper to NetReadRegister.
\item[NetReadRemove] removes the socket pSock from the net reader. This must
be done when closing the socket, otherwise the net reader will continue
checking for pending data on this socket.
\item[NetReadRemoveUserSocket] removes a user socket from
monitoring. Again, this is a vonvenience wrapper around NetReadRemove.
\item[NetReaderTask] is the net reader task function which will be
registered with the task manager. This function builds the select
mask, does the select and forwards incoming data to the appropriate
handler functions. These are not documented here, as they are file
static function in nread.c.
\item[NetReaderSignal] is the signal handler for the net reader. It
just stops the NetReaderTask when the SICS server is run down.
\item[NetReadReadable] returns 1 if data is pending at the user socket or 0
if not.
\item[NetReadResetUser] resets a user socket to not readable.
\end{description}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
\verb@"nread.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*------------------------------------------------------------------------@\\
\mbox{}\verb@ N E T R E A D E R@\\
\mbox{}\verb@@\\
\mbox{}\verb@ This module will check for pending requests to the SICS server and@\\
\mbox{}\verb@ initiate apropriate actions.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koenencke, September 1997@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see copyright.h@\\
\mbox{}\verb@@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSNETREADER@\\
\mbox{}\verb@#define SICSNETREADER@\\
\mbox{}\verb@@$\langle$nrint {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

123
doc/programmer/nserver.tex Normal file
View File

@@ -0,0 +1,123 @@
\subsection{The SICS Server Object}
This objects responsability is the proper initialisation and shutdown
of the SICS server and the provision of some utility functions.
The Server's data structure holds pointers to the most important parts of
the system:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$servdat {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __SicsServer {@\\
\mbox{}\verb@ SicsInterp *pSics;@\\
\mbox{}\verb@ pTaskMan pTasker;@\\
\mbox{}\verb@ pExeList pExecutor;@\\
\mbox{}\verb@ pEnvMon pMonitor;@\\
\mbox{}\verb@ mkChannel *pServerPort;@\\
\mbox{}\verb@ pNetRead pReader;@\\
\mbox{}\verb@ } SicsServer;@\\
\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 fields are:
\begin{description}
\item[pSics] is a pointer to the SICS interpreter.
\item[pTasker] is a pointer to the task scheduler.
\item[pExecutor] is a pointer to the device executor. This module monitors
variables during counting and driving operations.
\item[pMonitor] is a pointer to an environment device controller monitor.
This module monitors sample environment controllers.
\item[pServerPort] points to a data structure describing the port at which
the SICS server is listening for connections.
\item[pReader] points to a data structure which defines the network
communication object.
\end{description}
In terms of a function interface the server module supplies.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$servint {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*----------------------------------------------------------------------*/@\\
\mbox{}\verb@ int InitServer(char *file, pServer *pServ);@\\
\mbox{}\verb@ void RunServer(pServer self);@\\
\mbox{}\verb@ void StopServer(pServer self);@\\
\mbox{}\verb@/*----------------------------------------------------------------------*/@\\
\mbox{}\verb@ SicsInterp *GetInterpreter(void);@\\
\mbox{}\verb@ pExeList GetExecutor(void);@\\
\mbox{}\verb@ pTaskMan GetTasker(void);@\\
\mbox{}\verb@ void ServerWriteGlobal(char *pMessage, int iCode);@\\
\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}
For most functions the name already says what it does. {\bf
InitServer} initializes the SICS servers data structures. {\bf
RunServer} implements the main loop and essentially calls the task
modules ScheduleTask function for running all the SICS tasks which
will handle the rest of the job. {\bf Stopserver} is responisble for
closing the SICS server down in a sensible manner and in a well
defined sequence of events.
{\bf ServerWriteGlobal}
is special. This function sends the message pMessage to all clients
currently connected to the SICS server with the output code iCode. iCode has
the same meaning as in the connection object.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
\verb@"nserver.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------@\\
\mbox{}\verb@ N S E R V E R@\\
\mbox{}\verb@@\\
\mbox{}\verb@ The SICS server main data structure and functions.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Restructured: September 1997@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke.@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ copyright: see copyright.h@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSNSERVER@\\
\mbox{}\verb@#define SICSNSERVER@\\
\mbox{}\verb@#include "conman.h"@\\
\mbox{}\verb@#include "SCinter.h"@\\
\mbox{}\verb@#include "emon.h"@\\
\mbox{}\verb@#include "devexec.h"@\\
\mbox{}\verb@#include "task.h"@\\
\mbox{}\verb@#include "network.h"@\\
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __SicsServer *pServer;@\\
\mbox{}\verb@@\\
\mbox{}\verb@#include "nread.h"@\\
\mbox{}\verb@@$\langle$servdat {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@$\langle$servint {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@ int UserWait(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int SicsWait(long lTime);@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

69
doc/programmer/nxamor.tex Normal file
View File

@@ -0,0 +1,69 @@
\subsection{AMOR NeXus Routines}
This module implements a few functions for writing NeXus data files
for the reflectoemter AMOR at SINQ, PSI. Nothing very exciting here:
this is mostly boring repetetive code. Three functions are defined:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$namor {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ int WriteAmorHeader(char *file, SConnection *pCon);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int WriteAmorScan(char *file, SConnection *pCon, pScanData pScan);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int WriteAmorTOF(char *file, SConnection *pCon, pHistMem pHM);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int AmorStore(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ int AmorStoreMake(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[WriteAmorHeader] writes all the AMOR header information and the
zillions of motors.
\item[WriteAmorScan] writes data when AMOR was operated in scanning
mode.
\item[WriteAmorTOF] writes AMOR data when used with the PSD in
time-of-flight mode.
\item[AmorStore] the command function implementing the storeamor
command.
\item[AmorStoreMake] the initialization function which creates the
storeamor command.
\end{description}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
\verb@"nxamor.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*------------------------------------------------------------------------@\\
\mbox{}\verb@ N X A M O R@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Some routines for writing NeXus files for the reflectometer AMOR at@\\
\mbox{}\verb@ SINQ.@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ copyright: see copyright.h@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, September 1999@\\
\mbox{}\verb@----------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef NXAMOR@\\
\mbox{}\verb@#define NXAMOR@\\
\mbox{}\verb@@$\langle$namor {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

192
doc/programmer/nxdata.tex Normal file
View File

@@ -0,0 +1,192 @@
\subsection{NXdata}
NXdata is a module for writing Powder Diffraction Data files. The
routines here are somewhat obsolete as they refer to NeXus writing
using the standard Napi routines which is quite involved. Usually,
NeXus files are written from SICS through the NXDICT aware utility
routines in NXUTIL.
If not stated
otherwise, all routines return 1 on successful completion and 0 when an
error is detected. Please note, that many of these routines expect to find
certain data items in the Sics Interpreter. This implies, that any naming
changes in the initialisation file might force changes in here as well.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$Protos {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ char *SNXMakeFileName(SicsInterp *pSics, SConnection *pCon);@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro defined by scraps ?, ?, ?, ?, ?, ?, ?.
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
SNXMakeFileName creates a new filename from the SICS variables SicsDataPath,
SicsDataPresript, SicsDataNumber and SicsDataEnding. SicsDataNumber will be
incremented as well. The function returns a newly allocate buffer with the
assembled filename or NULL on error. Note, that the caller is responsible
for freeing the memory associated with the filename afterwards.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$Protos {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ NXhandle SNXStartFile(SConnection *pCon, SicsInterp *pSics); @\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro defined by scraps ?, ?, ?, ?, ?, ?, ?.
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
First calls SNXMakeFileName in order to get a new Filename.
Then a new Nexus file is
created and all the standard headings are filled in: Filename, User,
instrument, date etc. This routine also installs an error handler which
prints errors to pCon.
If successful, the SicsDataNumber is incremented and
an NXhandle into the new file is returned. If there is a problem, NULL
will be returned. The file returned will be positioned at root level.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
$\langle$Protos {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ int SNXStartEntry(NXhandle Nfil, int iNew, SicsInterp *pSics);@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro defined by scraps ?, ?, ?, ?, ?, ?, ?.
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap4}
$\langle$Protos {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ void SNXFormatTime(char *pBuffer, int iBufLen);@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro defined by scraps ?, ?, ?, ?, ?, ?, ?.
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
SNXFormatTime formats the current system time in a form compatible to the
NeXus standard. Input parameters is a Buffer to hold the string and a
length of the buffer. Maximum iBufLen characters will be copied to that
buffer.
SNXStartEntry creates a new entry corresponding to iNew in the Nexus file
Nfil. SNXStartEntry will position Nfil in this new entry. Any data items
labeled as Comment or intent will be written to the file as well.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap5}
$\langle$Protos {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ int SNFinishFile(NXhandle Nfil);@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro defined by scraps ?, ?, ?, ?, ?, ?, ?.
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
SNFinishFile will end a Nexus file properly.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap6}
$\langle$Protos {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ int SNMakeDMC(SConnection *pCon, SicsInterp *pSics);@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro defined by scraps ?, ?, ?, ?, ?, ?, ?.
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
SNMakeDMC produces a Nexus DMC data file from the currently valid
information. It orchestrates all of the above.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap7}
$\langle$Protos {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@int SNStoreDMC(SConnection *pCon, SicsInterp *pSics, void *pData, int argc,@\\
\mbox{}\verb@ char *argv[]);@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro defined by scraps ?, ?, ?, ?, ?, ?, ?.
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
SNStoreData is the wrapper function used to install a DMC data storage
command in the Sics interpreter.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap8}
\verb@"nxdata.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-------------------------------------------------------------------------@\\
\mbox{}\verb@ N X D A T A@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Some routines for handling Nexus data file writing.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, April 1997@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ copyright: see implementation file.@\\
\mbox{}\verb@--------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSNXDATA@\\
\mbox{}\verb@#define SICSNXDATA@\\
\mbox{}\verb@@$\langle$Protos {\footnotesize ?, \ldots\ }$\rangle$\verb@ @\\
\mbox{}\verb@#endif @\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

3053
doc/programmer/nxdict.tex Normal file

File diff suppressed because it is too large Load Diff

42
doc/programmer/nxsans.tex Normal file
View File

@@ -0,0 +1,42 @@
\subsection{NXUTIL}
Ther are some utility functions for writing NeXus data files from
SICS with the NXDICT-API. These are collected in the files nxutil.h
and nxutil.c.
\begin{description}
\item[int SNXSPutMotor(SicsInterp *pSics, SConnection *pCon, NXhandle hFil,
NXdict pDict, char *pAlias, char *pName)] writes the
value of a motor to file. The parameters are: \begin{description}
\item[pSics] The SICS interpreter to search for the motor.
\item[pCon] The connection object to which to print errors.
\item[hFil] The handle of the NeXus file to write.
\item[pDict] The handle of the NeXus dictionary to use.
\item[pAlias] The alias name to use for writing.
\item[pName] The name of the motor.
\end{description}
\item[SNXSPutMotorNULL] writes the motor zero point. Same parameters
as above.
\item[int SNXSPutVariable(SicsInterp *pSics, SConnection *pCon,\\
NXHandle hFil, NXdict pDict, char *pAlias,\\
char *pName)] writes a SICS variable to a NeXus file
using the dictionary. Parameters similar to SNXSPutMotor.
\item[SNXSPutEVVar(NXhandle hfil,NXdict pDict,char *pName, SConnection
*pCon,\\ char *pValAlias, char *pStddevAlias)]
This writes an environment variable pName to the file described by hfil,
using the dictionary pDict. A warning is printed if the variable is
not configured. If a variable is found its value and standard
deviation are written to file using the aliases given as parameters.
\item[SNXSPutGlobals] writes global data to the file.
\item[SNXSFormatTime] returns the current time formatted according to
the NeXus specification in buffer. Max iLen characters will be copied
to buffer.
\item[SNXSMakeFileName] returns a pointer to a buffer containing a new
file name for a data file. This function assembles the filename from
the DataNUmber and various SICS variables. The caller has to free the
buffer containg the name.
\item[SNXSPutDrivable] writes any variable adhering to the drivable
interface.
\end{description}

42
doc/programmer/o2t.tex Normal file
View File

@@ -0,0 +1,42 @@
\subsection{Omega 2Theta}
This is an example for a simple virtual motor. It uses two motors and runs
the second one to exactly the double value of the first one. It can be used
to implement omega--two--theta (o2t) scans at reflectometers of four circle
diffractometers using the normal scan command.
The o2t module uses the following data structure:
\begin{verbatim}
typedef struct __SicsO2T {
pObjectDescriptor pDes;
pIDrivable pDrivInt;
pMotor pOmega;
pMotor pTheta;
} SicsO2T;
\end{verbatim}
The fields:
\begin{description}
\item[pDes] A pointer to the usual SICS object descriptor.
\item[pDrivInt] A pointer to the drivable interface implemented by this
variable.
\item[pOmega] A pointer to the first motor to use.
\item[pTheta] A pointer to the motor data structure of the second (double)
motor to use.
\end{description}
Most of this modules action lives in the drivable interface. The rest is
achieved through the following functions:
\begin{description}
\item[pSicsO2T MakeO2T(char *omega, char *theta, SicsInterp *pSics)] creates
a new o2t object from motors omega and theta. Returns NULL on failure and a
pointer to an o2t data structure on success.
\item[void DeleteO2T(void *pData)] deletes an o2t object.
\item[int CreateO2T(SConnection *pCon, SicsInterp *pSics, void *pData,\\
int argc, char *argv[])] The object factory function for o2t
objects.
\end{description}
Please note, that o2t is just a helper variable and can not be manipualted
from the SICS interpreter.

44
doc/programmer/obpar.tex Normal file
View File

@@ -0,0 +1,44 @@
\subsection{SICS Parameter Array}
This thing holds an array of floating point numbers, their names and their access codes.
It is used in SICS object implementations to hold larger amounts of
configurable parameters. It provides functions for simplifying the
management of such parameters.
Each parameter is described by a structure shown below:
\begin{verbatim}
typedef struct {
char *name;
float fVal;
int iCode;
} ObPar;
\end{verbatim}
The fields are: \begin{description}
\item[name] The name of the parameter.
\item[fVal] The parameters value.
\item[iCode] The access code necessary to modify the parameter.
\end{description}
Parameter arrays are maintained by the functions described below:
\begin{description}
\item[ float ObVal(ObPar *self, int i)] gets the value of parameter i from
the array self. This call is for module internal usage.
\item[int ObParLength(ObPar *self)]
finds the length of an ObPar array.
\item[ObPar *ObParFind(ObPar *self, char *name)]
finds a ObPar struct for a name, return NULL if none.
\item[int ObParInit(ObPar *self,int i, char *name, float fVal, int iCode)]
sets a ObPar entry. self is a pointer to the array.
\item[int ObParSet(ObPar *self, char *obname,char *name, float fVal, SConnection
*pCon)]
checks if the connections permissions are alright and changes value
if so. Returns 1 on success, 0 on failure. Prints errors directly to
pCon. The parameter obname is the name of the object the parameters belong
to. Needed for error printing. name is the parameter name, fVal the new
value.
\item[void ObParDelete(ObPar *self)]
Deletes an ObPar array.
\item[ObPar *ObParCreate(int iArrayLong)]
creates an array with iASrrayLong entries. Returns NULL on failure, else
a pointer to the array.
\end{description}

24
doc/programmer/ofac.tex Normal file
View File

@@ -0,0 +1,24 @@
\subsection{The Object Factory}
SICS is a highly configurable system. This module implements
the configurable. Configuration is meant to happen via a Tcl-
configuration script. This module will initialize commands which
create SICS-objects. Than an initialization file is evaluated
via the macro facility. As most of the initialization commands
will no longer be needed after this, they will be deleted.
All this will be run with a higly privileged connection which
prints to stdout/stdin. This module contains the file static functions:
InitIniCommands and KillIniCommands. {\bf InitIniCommands}
intializes all SICS common commands plus the object creation
commands. Once a new class has been devised its object
creation function needs to be entered into this
function. {\bf KillIniCommands} removes all the initialization
commands no longer needed after the initialization file has
been evaluated. Make sure to add an entry for your new
classes creation command here as well.
The interface consists of a single function: \begin{verbatim}
int InitObjectCommands(pServer pServ, char *file);
\end{verbatim}
Commands will be initialized for the server pServ from the file file.

804
doc/programmer/oguide.tex Normal file
View File

@@ -0,0 +1,804 @@
\chapter{Guide To SICS Object Writers}
This chapter describes the necessary steps for adding new objects to the SICS server. In order to live
happily within SICS an object is obliged to stick to a set of rules and interfaces already defined. Such
interfaces will be described here as well. For the following text it is assumed, that the reader has studied
the SICS overview and kernel guide.
In general the following steps will be necessary in order to introduce a new object into SICS:
\begin{enumerate}
\item Define a new object data structure.
\item Define a function capable of deleting the object from memory.
\item Define a set of functions which define the operations on this object.
\item Create an object wrapper function which defines the user commands
the object can handle.
\item Create an object creation function, which is capable of initializing
the object and creates a new command in the SICS interpreter.
\item Add the new objects creation command into the IniInitCommand and
KillIniCommands functions defined in ofac.c.
\item Document the new object.
\end{enumerate}
All these steps will now be discussed together with some additional SICS
concepts applicable to writing new objects. Not all of the above mentioned
steps will be necessary in all cases. If a new general SICS object is defined,
no object creation function may be needed. Then it is sufficient to register
the new object/command with the SICS interpreter in IniInitCommands, file ofac.c.
In the rare cases where an object needs no data structure, the system will provide a dumb
default which will not harm the system. Some objects may have more then one
command associated with them. Some more care has to be taken when adding a
new piece of hardware into the system. If it is just a variant of an already
known type (for instance a new type of motor) it will be sufficient to introduce
a new driver into the system. The procedures for doing this will be described
in the reference sections for the appropriate device. Otherwise the SICS rule
to divide a hardware object into a logical object and a driver should be
observed. At minimum two drivers are necessary anyway in the first place:
the driver for the actual device and a simulation driver which permits some
debugging to take place while the hardware is still unavailable.
\section{Mapping Object Oriented Concepts into ANSI--C}
SICS is in principle an object oriented system. However, it is implemented
in ANSI--C. Therefore object oriented concepts must be mapped into C. The
three object oriented concepts which need to be mapped are:
\begin{itemize}
\item Data Encapsulation.
\item Polymorphism.
\item Inheritance.
\end{itemize}
Of these, data encapsulation is by far the most important concept. Objects
in computer science can be understood as little boxes which contain some
data describing their state and which understand messages sent by other
objects. If such a message comes in, the object performs some action,
perhaps changes its internal state or sends new messages to other objects.
It is understood that changes to the internal data of the object can be
achieved only through messages to the object and not by directly manipulating
variables from the outside. In ANSI--C an object maps to a structure holding
the objects data and the messages map to functions which act upon the data
structure. In order to do this, the functions must take a pointer to the
objects data structure as first parameter. In order to prevent messing with
an objects data structure, only a pointer to a structure is declared in the
header file. The actual definition of the data structure happens only in
the implementation file. All functions belonging to an object are defined in that
implementation file and have full access to the data structure.
Users of the object see only the header file and thus only a pointer to the
objects data structure which prevents
them from messing with the objects data directly.
In order to illustrate the concepts lets look at
a primitive integer object defined in such a way.
\begin{verbatim}
/*-----------------------------------------------------------------------
ExampleInt.h
------------------------------------------------------------------------*/
typedef struct __ExampleInt *pExampleInt;
int GetInt(pExampleInt self);
void SetInt(pExampleInt self, int iNew);
/*------------------- EOF ExampleInt.h---------------------------------*/
/*----------------------------------------------------------------------
ExampleInt.c, Implementation file
-----------------------------------------------------------------------*/
typedef struct __ExampleInt {
int iExample;
} ExampleInt;
/*--------------------------------------------------------------------*/
int GetInt(pExampleInt self)
{
return self->iExample;
}
/*---------------------------------------------------------------------*/
void SetInt(pExampleInt self, int iNew)
{
self->iExample = iNew;
}
\end{verbatim}
Using this scheme all code changing the internal state of an object lives
in one file. Changes to the objects data structure affect only the
implementation file and no other files.
This scheme is used for almost all SICS objects. A few system objects and
older SICS objects define their data structures in header files. This is
either a relic or had to be done for performance reasons.
The next concept is polymorphism. This describes the situation when a group
of objects respond to the same message but doing different things. For
instance a whole set of objects would implement a write functionality
which writes the objects state to a file. Higher level would then not need
to know of which type the actual object is, it just can send the write message
and the rest is taken care of by the object. This concept is used for all
hardware drivers in SICS. Mapping this to C requires to expose the objects
data structure and let the data structure include a pointer to that polymorphic
function. As an example, the ExampleInteger with a write function:
\begin{verbatim}
/*-----------------------------------------------------------------------
ExampleInt.h
------------------------------------------------------------------------*/
typedef struct __ExampleInt{
int iExample;
void (*write)(struct __ExampleInt *self, FILE *fd);
} *pExampleInt, ExampleInt;
pExampleInt MakeInt(int iNew);
int GetInt(pExampleInt self);
void SetInt(pExampleInt self, int iNew);
/*------------------- EOF ExampleInt.h---------------------------------*/
/*----------------------------------------------------------------------
ExampleInt.c, Implementation file
-----------------------------------------------------------------------*/
static void ExampleWrite(struct _-ExampleInt *self, FILE *fd)
{
fprintf(fd,"INT = %d",self->iExample);
}
/*---------------------------------------------------------------------*/
pExampleInt MakeInt(int iNew)
{
pExampleInt pNew = NULL;
pNew = (pExampleInt)malloc(sizeof(ExampleInt));
pNew->iExample = iNew;
pNew->write = ExampleWrite;
return pNew;
}
.
.
.
\end{verbatim}
This can then be called:
\begin{verbatim}
void SomeFunc()
{
pExampleInt pTest;
pTest = MakeInt(25);
.
.
.
pTest->write(pTest,fd);
}
\end{verbatim}
This example also illustrates the concept of a special function which creates
a new object of the appropriate type and initializes its data structure
properly.
The last concept to discuss is inheritance. Inheritance can be used when
an object is a derivative of another object. For instance a truck is a
derivative of a motor car. Much of the behavior of a motor car will be the
same as for a truck. In order to prevent rewriting of code, the truck
should use the same data structures and code as the motor car. And add
or modify only what is special. Inheritance is not much used in SICS. It can
be implemented by overlaying data structures. This means the derived
classes data structure has the same fields in the same order as the parent
class and adds its specials at the end. For example:
\begin{verbatim}
typedef struct __MotorCar {
int iWheels;
float fSpeed;
} *pMotorCar, MotorCar;
typedef struct __Truck {
int iWheels;
float fSpeed; /* same as MotorCar */
double dPayLoad; /* special for Truck */
} *pTruck, Truck;
\end{verbatim}
Thus functions defined for motor car can operate on trucks as well.
For more details study the relationship between the ITC4 controller and
general environment controllers. This is the only place where SICS
currently uses inheritance.
\section{The Object Data Structure}
Nearly all SICS objects require some data. This data is collected in a
C structure typical for the object. This is just a normal C struct with one
exception:
\begin{center}
\rule{9cm}{2mm}
\end{center}
\leftline{{\huge Rule 1}}
The first item in a SICS object data structure MUST be a pointer to a
ObjectDescriptor data structure. This looks like:
\begin{verbatim}
typedef struct __MyObject {
pObjectDescriptor pDes;
int iMyExtremlyImportantInt;
.
.
.
} MyObject;
\end{verbatim}
\begin{center}
\rule{9cm}{2mm}
\end{center}
Otherwise the SICS server will crash on you sooner or later. The reason for
this is that SICS needs a means to identify a object and its capabilities
from inside its code. For example a user has typed: {\em drive mot1 26} into
the server. Now drive needs to verify that mot1 is really a motor or
something else which can be driven. This can be done in the following way:
\begin{enumerate}
\item First find the object in the SICS interpreter
(function FindCommand, SCinter.h).
\item Get the pointer to the objects data structure.
\item Assign this pointer to a dummy data structure (defined in obdes.h)
which has a pointer to the ObjectDescriptor as single element.
\item Ask the ObjectDescriptor if the object can be driven.
\end{enumerate}
In object speak this is called run time type information (RTTI).
It is interesting to look at the object descriptor in more detail. It is
again a data structure and a good example for polymorphism:
\begin{verbatim}
typedef struct {
char *name;
int (*SaveStatus)(void *self, char *name,FILE *fd);
void *(*GetInterface)(void *self, int iInterfaceID);
} ObjectDescriptor, *pObjectDescriptor;
\end{verbatim}
The first field contains a string defining a type name. The next field is a
pointer to a save function. This function is automatically called for all objects
in the SICS interpreter when the server shuts down. This function is supposed to
write all SICS commands necessary to reconfigure the object back into its current state
into file fd. The middle parameter is the name of the object in the interpreter
which must not necessarily be known to the object.
The next field, a pointer to a function GetInterface is used in order to inquire
the capabilities of an object. Object capabilities in SICS are defined in terms of
{\bf {\Large Interfaces}}. An Interface in the SICS sense is again a data structure
which contains data fields and pointers to functions implementing the capability. As
an example see the Drivable interface which is implemented by motors, environment
devices and variables such as lambda which can be driven to a new value:
\begin{verbatim}
typedef struct {
int ID;
int (*Halt)(void *self);
int (*CheckLimits)(void *self, float fVal,
char *error, int iErrLen);
long (*SetValue)(void *self, SConnection *pCon,
float fVal);
int (*CheckStatus)(void *self, SConnection *pCon);
float (*GetValue)(void *self, SConnection *pCon);
} IDrivable, *pIDrivable;
\end{verbatim}
Each SICS interface is identified by an integer ID number (defined in interface.h).
GetInterface returns a pointer to an interface data structure for an ID if the object
implements that interface. If not a NULL is returned.
\section{SICS Interfaces}\label{gow}
Thus SICS interfaces define the capabilities of an object. The concept of
Interfaces is similar to interfaces in the Java programming language
or abstract base classes in C++ or other object oriented languages.
As can be seen from the example
given above, the interface implements the most common operations on an object with
capabilities as defined by the interface. Currently, SICS knows four different kinds of
Interfaces:
\begin{description}
\item[Drivable] The Drivable interface for objects such as motors, adjustable parameters
and the like. Anything which can be driven to a value.
\item[Countable] The Countable interface used for everything which can count: single
counters, histogram memories or whatever may creep up.
\item[CallBack] The CallBack interface introduces some component programming techniques
into SICS. This technique lets an object, name it object A, issue events when its internal
state changes. For example if object A is a motor, any time it drives to a new value
an event is issued. Then another object, name it object B, can register an interest in
such events with object A. It does so by giving A the address of a function to call
when such an event occurs. A now calls all functions thus registered when the event
occurs. Object B thus gets automatically notified when A changes its state. Currently
this scheme is only used for implementing automatic notifications of clients when a
SICS object changes its state. But there is a lot of potential in this scheme.
\item[Environment] The Environment device is a interface implemented by all devices which
need to be regularly monitored by the environment monitor.
\end{description}
For more details about the SICS interfaces see the reference section: \ref{interref}.
The list of SICS interfaces can be extended when a novel abstract capability of an object
is needed. This is also the main reason why this sophisticated scheme was chosen.
The question may arise how to use SICS interfaces. For example consider an object defining
a drivable variable. The following steps are necessary:
\begin{enumerate}
\item Define functions with matching parameters to the ones requested by the interface.
Tip: the first parameter, the pointer to void, is always the pointer to the object data
structure to operate on. These functions must implement appropriate actions. What these
are: see the documentation of the interface.
\item Define a GetInterface function which returns a suitable interface
data structure when asked for an interface with the Drivable ID. The fields of the interface
structure returned must be set to the addresses of the functions you defined in step 1.
\item Create an object initialization function.
\item In this object initialization function: assign the object descriptors filed GetInterface
to the address of your GetInterface function.
\end{enumerate}
Usually, the interfaces an object implements are made a field in the objects data
structure. This interface is then initialized with appropriate function pointers when
creating the object. GetInterface then returns this pointer when the interface is
requested. Due to this usage a rule exits:
\begin{center}
\rule{9cm}{2mm}
\end{center}
\leftline{{\huge Rule 2}}
Any interface data structure provided by an object belongs to the object providing
it. The owner object is responsible for deleting it. Never free an interface data structure
provided by another object.
\begin{center}
\rule{9cm}{2mm}
\end{center}
Note, that the SICS interfaces are not the only interfaces to take care of. As SICS uses
this duality between logical hardware objects and hardware drivers, the interfaces defined
by the logical hardware devices can been seen as yet another internal interface. This leads to:
\begin{center}
\rule{9cm}{2mm}
\end{center}
\leftline{{\huge Recommendation}}
Watch your neighbors! Use the interfaces provided by the logical hardware objects for
your objects business, when applicable.
\begin{center}
\rule{9cm}{2mm}
\end{center}
\section{The Object Deletion Function}
When the SICS server exits or when a command is removed from the SICS
interpreter the interpreter will call a function which should free the memory
associated with the deleted object. This is absolutely necessary in order to
prevent memory leakage. Such a function has the form:
\begin{verbatim}
void ObjectKiller(void *pData);
\end{verbatim}
with pData being the pointer to the object to delete.
\section{Writing Object Functions}
The rules specified in this section apply to all kinds of object functions:
those which implement functionality as well as the object wrapper
functions. Please note, that any SICS object has two interfaces: an internal
C--language interface and a user visible interface defined by the object
wrapper functions. There are reasons why those two interfaces might not
provide equivalent functionality.
\subsection{Input and OutPut}
\begin{center}
\rule{9cm}{2mm}
\end{center}
\leftline{{\huge Rule 3}}
All input and output to the client executing the command must go through the
connection object functions SCWrite and SCPrompt.
\begin{center}
\rule{9cm}{2mm}
\end{center}
These function will now be inspected in more detail:
\begin{verbatim}
int SCWrite(SConnection *pCon, char *pText, int eCode);
int SCPrompt(SConnection *pCon, char *pPrompt, char *pBuffer, int iBufLen);
\end{verbatim}
SCWrite writes the data pText to the connection specified by pCon. The
parameter eCode denotes the output code of the data in pText. SICS clients
can choose to suppress some I/O from the SICS server. For instance a
GUI--client might chooses not to receive scan status reports. For this
purpose it was necessary to stick an output code onto each message to the
client. Possible output codes are: eError, eWarning, eValue, eStatus and
some internal codes. The names are self explaining. eValue denotes a value
which has been explicitly asked for by the client. The rule specified above
becomes understandable and thus bearable when looking at all the things
SCWrite does with the message:
\begin{itemize}
\item It is written to the client connection socket, subject to the output
code specified.
\item The message is written to all log files configured for the client
connection.
\item The message is written to the server log together with the socket
number of the connection.
\item SCWrite stores the message into the Tcl macro interpreter in order to
enable processing of data from SICS commands in Tcl scripts.
\item SCWrite suppresses all messages to the client while executing a macro.
This stops spurious output to appear at the client connection when running a
command defined in the macro language. The exception are messages of type
eError and eWarning. Such messages are always sent to the client.
\end{itemize}
SCPrompt prompts the user at the client connection for data. The prompt
string pPrompt is sent. Data entered by the user is returned in buffer
pBuffer. Maximum iBufLen character are returned. While waiting for client to
provide data, the SICS task switcher runs.
There is another convenience function SCSendOK(SConnection *pCon) which is
just a wrapper around SCWrite. SCSendOk sends an 'OK' to the client. It is good
practice to let the user know that the operation requested had been
performed.
Given the rule stated above, it follows that connection objects have to
be passed through the system to nearly everywhere. Especially where
reportable errors are found.
All other I/O, for instance to files sitting at the computer running the
SICS server, is not subjected to Rule 3.
\subsection{Error Handling}
Error handling is two thirds of the code written. Errors can be caused by
faulty users or faulty hardware. In any case, the first thing to do is:
report it using SCWrite! The next thing is to get the system into a state
that it can continue execution. This is particularly important for a server
program which might run for months on end. This means, free all memory used
before the error occurred, get system variables into safe values and the
like.
Sometimes error conditions arise in lower level code which should cause all
upper level code to finish execution. Such conditions may be the result of a
critical hardware fault or may even be requested by a user who wants to
abort an operation. A standard method for communicating such conditions
through the system is necessary. SICS uses interrupts for such conditions.
The current interrupt active interrupt is located at the connection object
and can be retrieved with {\bf SCGetInterrupt} and set with {\bf
SCSetInterrupt}. Interrupt codes are defined in interrupt.h and are ordered
into a hierarchy:
\begin{description}
\item[eContinue] Everything is just fine.
\item[eAbortOperation] Stop the current scan point or whatever is done,
but do not stop altogether.
\item[eAbortScan] Abort the current scan, but continue processing of further
commands in R\"unbuffers or command files.
\item[eAbortBatch] Aborts everything, operations, scans and batch processing
and leaves the system ready to enter new commands.
\item[eHaltSystem] As eAbortBatch, but lock the system.
\item[eFreeSystem] Unlocks a system halted with eHaltSystem.
\item[eEndServer] Makes the SICS server run down and exit.
For internal usage only.
\end{description}
In most cases interrupts shall only effect the client connection executing
the command. In such cases user code should use SCSetInterrupt in order to
set an interrupt at the connection executing the command only. Very rarely
conditions occur when an interrupt should affect the whole system. Then
SetInterrupt (defined in intserv.h) should be used. SetInterrupt forwards
the interrupt to all running tasks.
Objects implementing higher level commands such as scan commands might be
able to handle interrupt conditions and thus consume an interrupt. Then the
interrupt must be released with SCSetInterrupt and setting the interrupt to
eContinue. The interrupt on a connection will automatically be set to
eContinue when executing a new command from the command stack.
Objects are responsible for checking for interrupt conditions when
applicable. This is specially true for objects performing complex or
lengthy
operations with hardware. Whenever a hardware operation finishes, the
interrupt must be checked for and handled. The called hardware object or
the user might have set an interrupt which needs to be honored.
Thus two new rules can be defined:
\begin{center}
\rule{9cm}{2mm}
\end{center}
\leftline{{\huge Rule 4}}
Signal critical error conditions with interrupts.
\begin{center}
\rule{9cm}{2mm}
\end{center}
\begin{center}
\rule{9cm}{2mm}
\end{center}
\leftline{{\huge Rule 5}}
Check for pending interrupts wherever applicable.
\begin{center}
\rule{9cm}{2mm}
\end{center}
\subsection{Authorisation}
Objects are also responsible for checking if the client requesting an
operation may actually perform the operation. There are two cases when an
operation may be forbidden:
\begin{itemize}
\item The user is not suitably authorized.
\item The user is about to change critical parameters affecting a running
measurement.
\end{itemize}
Both conditions must be checked for by the objects code. Where else then at
the object can be known which operations are critical or not? This gives a
new rule:
\begin{center}
\rule{9cm}{2mm}
\end{center}
\leftline{{\huge Rule 6}}
Objects have to check authorisation!
\begin{center}
\rule{9cm}{2mm}
\end{center}
The user rights code for a client connection can be retrieved with
SCGetRights. SCGetGrab finds out if a connection has the control token.
A match with a value can be checked for with SCMatchRights which
returns true (1) if the connection has a user rights equal or higher then the
one necessary. SCMatchRights also checks for the status of the control token
and prints messages. SCMatchRights is the recommended function for checking
access rights in SICS.
An object can find out if some hardware operation is running by calling
the function isInRunMode prototyped in devexec.h.
An object can find out, if it is executing in a macro by calling SCinMacro.
Might be useful if the code is dependent on this condition. Usually all
details associated with running in a macro are dealt with by the system.
\subsection{Driving Hardware}
\begin{center}
\rule{9cm}{2mm}
\end{center}
\leftline{{\huge Rule 7}}
Use the device executor!
\begin{center}
\rule{9cm}{2mm}
\end{center}
With respect to hardware, there are two different kinds of objects in SICS:
some objects represent hardware. Examples are motors, counters. This group
also includes drivable variables which implement coordinated movements of
hardware. Such objects have to implement the necessary interfaces: either
the drivable or the countable interface. The second class are objects which
implement commands which use the hardware. For instance a drive command.
This second class of commands has to find the necessary hardware objects and
then run the actual hardware through the device executor. The function to
use is StartDevice or its derivatives, prototyped in devexec.h. After this
is done, there are tow options. In a scan command it might be needed to wait for
the hardware to finish before continuing your code. In this case use
function TaskWait, prototyped in tasker.h.
In other cases execution of the function may just
continue. The device executor will the take care of the task of monitoring
the hardware operation. The following code snippet gives an example how to
start a counter properly and wait for it to finish:
\begin{verbatim}
/*-------------- count */
pDum = (pDummy)self->pCounterData;
iRet = StartDevice(pServ->pExecutor, /* the executor, from global pServ */
"ScanCounter", /* a name */
pDum->pDescriptor, /* the descriptor of the cter */
self->pCounterData, /* pointer to counter data */
self->pCon, /* pointer to connection object */
self->fPreset); /* count preset */
if(!iRet)
{
SCWrite(self->pCon,"ERROR: Cannot Count, Scan aborted",eError);
return 0;
}
/* wait for finish */
lTask = GetDevexecID(pServ->pExecutor); /* get ID of device
executor task */
if(lTask > 0);
{
TaskWait(pServ->pTasker,lTask);
}
/* finished, check for interrupts. Whatever happened, user
interrupt or HW interrupt, it will be on our connection
*/
iInt = SCGetInterrupt(self->pCon);
switch(iInt)
{
case eContinue:
break;
case eAbortOperation:
continue;
break;
case eAbortScan:
SCWrite(self->pCon,"ERROR: Scan aborted",eError);
/* eat the interrupt, the requested op has been
done
*/
SCSetInterrupt(self->pCon,eContinue);
return 0;
break;
default: /* all others */
SCWrite(self->pCon,"ERROR: Scan aborted",eError);
return 0;
break;
}
\end{verbatim}
The above code (taken from the implementation of the scan command) also
shows an example for handling interrupts as a followup to running hardware.
Such a procedure is highly recommended.
\subsection{Working with the CallBack Interface}
Working with the callback interface is usually simple: just use the
functions as defined in interface.h. Add new event codes to event.h, in
order to make them known. A problem arises if an object which has callbacks
registered with other objects gets deleted. For the following discussion:
let us denote the object registering the callback as the client object and
the object which generates the event (where the callback was registered) as
source object. A typical example for a client is a
connection object which had configured itself to be automatically notified
of motor movements, variable changes and the like. Typically this is a
status display client. In such cases the client object has to keep
track of the callbacks it registered and delete them when the client objects gets
deleted. Otherwise the source object would invoke a callback on an non
existing client object. This usually results in a lovely core dump. For the
connection object this is taken care of automatically. The only thing needed
to be done, is to register the callback on the connection object with
SCRegister prototyped in conman.h. If user codes removes a callback later on,
it may call SCUnregister on the connection object to remove it from the
connection objects callback database as well. All registered callback will
be properly removed when the connection object is deleted.
\begin{center}
\rule{9cm}{2mm}
\end{center}
\leftline{{\huge Rule 8}}
Remove registered callbacks when deleting an object. For connection objects:
register your callbacks!
\begin{center}
\rule{9cm}{2mm}
\end{center}
\section{The Object Wrapper Function}
The object wrapper function makes the SICS object visible as a command in
the interpreter. It has to analyze parameters given to the command and act
accordingly. The object wrapper function has the following form:
\begin{verbatim}
int ObjectWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
\end{verbatim}
The parameters are:
\begin{itemize}
\item A pointer to the connection object and the client invoking the command.
\item A pointer to the SICS interpreter in which the command was executed.
As the interpreter also doubles as a database for objects it is often needed
to locate other objects.
\item A pointer to the objects data structure (pData).
\item The number of arguments specified to the command.
\item The text of the arguments specified. \verb+argv[0]+ is the name of the
command invoked. The argc, \verb+argv[]+ are almost the same as the argc,
\verb+argv[]+ pair given to a C main program.
\end{itemize}
In order to give the macro interpreter a hint if things are okay, the object
wrapper function has to return 1 for success and 0 if it fails. The rules
stated above for normal object functions apply.
\section{The Object Creation Function}
The object creation function has the same form as the object wrapper
function. Its purpose is to analyze parameters and to create the requested
object from them. In the end the object creation function will probably
create a new command in the SICS interpreter. The function to do this is the
AddCommand function. The prototype for AddCommand looks like this:
\begin{verbatim}
int AddCommand(SicsInterp *pSics,
char *name,
ObjectFunc pObFunc,
KillFunc pKill,
void *pData);
\end{verbatim}
The parameters are:
\begin{itemize}
\item A pointer to the SICS interpreter into which the new command shall be
installed.
\item The name of the new command.
\item The object function implementing the command.
\item An optional function which is able to remove the object data structure
given as last parameter from memory. This is mandatory for any object with
an own data structure.
\item A pointer to the object data structure.
\end{itemize}
\section{Writing Data}
For simple ASCII files at instruments doing scans, see the SICS manager
documentation for the template file description. Other instruments should
use the NeXus data format. Especially the NXDICT implementation. For more
documentation see the napi and nxdict documents. An example for using NXDICT
is given in the file nxsans.c.
\section{Hardware Objects}
\begin{center}
\rule{9cm}{2mm}
\end{center}
\leftline{{\huge Rule 9}}
Obey the division between driver code and logical object for hardware
objects.
\begin{center}
\rule{9cm}{2mm}
\end{center}
The concept of separating a hardware object in two components: a driver
which implements primitive operations and a logical object with which SICS
interacts internally has proven very valuable. First of all two drivers are
needed anyway: a simulation driver for simulating hardware and a
driver for the real hardware. Simulating hardware proved invaluable for
debugging of higher level code and can be used later on for testing command
files.
Please note that sample environment devices are handled slightly
differently. There exists a more general sample environment object which
handles many aspects of such a device. If the logical interface provided by
this general sample environment objects suffices, a new sample environment
device requires just a new driver. If the sample environment needs some
specials the study the relationship between the itc4 object and the general sample
environment object. Basically such a derived object implements in its
functions just the specials and calls the appropriate functions of the
general environment device object at the end. This is a simple form of
inheritance by delegation. This scheme has been devised in order to reduce
the need for code duplication when introducing new environment devices. For
more details see the reference section on environment devices.
\section{Examples}
For a deeper understanding of the concepts explained above it may help to
look at some source code. A nice example for the whole SICS object setup
including a callback interface is the implementation of the SICS variables
in files sicsvar.h and sicvar.c. For the implementation of a hardware object
including a drivable interface, the code in motor.h, motor.c and the motor
drivers: simdriv.c, el734dc.c and el734driv.c may be a suitable example. The
motor object creation function also shows how to handle multiple drivers for
a logical object.
SICS knows a omega-two-theta variable o2t. This variable coordinates two
motors in a way that the second motor has exactly the double value of the
first. This was meant to implement a omega-two-theta scan. Anyway, o2t is
a good example for implementing a drivable interface and how to handle such
coordinated movements. An example for the implementation of a countable
interface can be found in counter.h, counter.c for a single counter.
\section{Documentation}
If a new object has been defined two documentation files should be provided:
\begin{itemize}
\item A html file which describes the user interface to the object.
\item A latex file which describes the data structures used to implement the
object, the interface to the object and as much internal knowledge about the
working of the object as you care to provide. Being generous with
information helps maintaining the code later on!
\end{itemize}
Furthermore it is required to update the SICS managers documentation so that
the object creation function is known.
\section{Introducing a new Hardware Driver}
A new hardware driver for an existing objects can be introduced into the
system with the following two steps:
\begin{itemize}
\item Write the new driver. Use an existing driver as template.
\item Locate the objects factory function. Modify it so that it knows about
the new driver and how to initialise it.
\item Depending of the implementation of the object, the object deletion
function may need to know about the new driver as well in order to delete it
properly.
\end{itemize}
Do not forget to update the SICS manager documentation to include the new
driver!
\section{Coding Considerations}
The header file {\em sics.h} includes all the SICS kernel header files in
the right order. It is recommended to include sics.h at the top of
your implementation file.
A server program has to run for times on end. Thus a server program is more
sensitive than any other program to memory leakage or memory overwrites.
Therefore the current SICS implementation utilizes a memory debugging tool
called fortify. It is highly recommended to include fortify.h into your
implementation file in order to enable memory debugging. More information
about the inner working and usage of fortify can be found in the file fortify.doc in
the sics source code directory. Fortify has given some false alarms already
but it also helped to eliminate a couple of nasty problems at a very early
stage. A nasty feature of fortify is that its header file, fortify.h, has
to be included in ALL relevant source files. Otherwise nasty pseudo bugs
creep up when fortify is enabled. Please note, that fortify is only enabled
when all source files have been compiled with the flag -DFORTIFY. Otherwise
fortify compiles to nothing. More information about fortify can be found in
file fortify.h.
Names in the SICS source code are often made up along the following pattern:
\begin{itemize}
\item Use the full name of the thing or sensible and command abbreviations.
Write the variable as one word, with word boundaries being marked by capital
letters.
\item Most variables are prefixed with a letter denoting type. Letters used
are:
\begin{itemize}
\item p for pointer.
\item i for integer.
\item f for float.
\item d for double.
\item l for long.
\item s for struct.
\end{itemize}
Combinations of letters are also possible.
\end{itemize}
Some more general data structure implementations are used in SICS: There is
a general linked list package from a dutch men documented in lld.h. There is
a dynamical array in dynar.* and a parameter array in obpar.*.

196
doc/programmer/optimise.tex Normal file
View File

@@ -0,0 +1,196 @@
\subsection{Optimise}
In instrument control the need arises to optimise a peak with respect to
several variables. This is usually the case during instrument calibration.
Four circle diffractometers however use this facility on a day to day basis
for finding and verifying the exact position of reflections. In order to
support both usages a more general module has been implemented. The way of
operation is like this:
\begin{verbatim}
while errors > precision and cycles < maxcycles
for all variables treated
do a scan
Try find the maximum, two halfwidth points and the peak center.
if failure extend the scan.
if success shift the variable, remember last shift.
If shift < precicison mark this variable as done
end for
end while
\end{verbatim}
Possible outcomes of this procedure are: success, the peak was lost or the
maximum number of cycles was reached. This routine requires that the
instrument is currently placed somewhere on the peak and not miles away.
In order to use this scheme some general control variables are required:
\begin{description}
\item[iMaxCycles] The maximum number of cycles to run.
\item[lThreshold] A threshold value used when determining if the peak was
lost.
\item[eMode] The counter mode to count in.
\item[fPreset] The preset to use when counting.
\item[iChannel] The channel to use as signal when counting. This is to
support this technique on a monitor rather then with a counter. Useful for
calibration.
\end{description}
For each variable to optimise we have to hold the following items:
\begin{description}
\item[name] Variable name.
\item[fStep] The step size to use for scanning
\item[nStep] The number of steps to go in each direction by default. This
parameter and the step size should together encompass somewhat more then the
width of the peak.
\item[fPrecision] The precision required or expected for this variable.
\item[fShift] The shift necessary for the last variable.
\end{description}
Of this the user is required to enter: name, fStep, nStep and fPrecision.
For some of its work, this module relies on the scan object (scan.*) and the
fitcenter object (fitcenter.*).
Internally the optimiser uses the following data structures:
\begin{verbatim}
typedef struct {
char *pName;
float fStep;
int iStep;
float fPrecision;
float fCenter;
float fShift;
pIDrivable pDriv;
void *pData;
int iLost;
} OVarEntry, *pOVarEntry;
\end{verbatim}
This is the data structure for each variable to optimise during an
optimser run. The fields are:
\begin{description}
\item[pName] the name of the variable.
\item[fStep] The step width to use for scanning the variable.
\item[fPrecision] The precision required for this variable. Used to
mark this variable OK if the last shift is less then this precision
value.
\item[fCenter] The calculated center of this variable.
\item[fShift] The last shift calculated for this variable.
\item[pDriv] A pointer to the drivable interface of this variable.
\item[pData] A pointer to this variables data structure.
\item[iLost] A flag which marks if the peak has been lost with respect
to this variable.
\end{description}
The optimiser itself uses the following data structure:
\begin{verbatim}
typedef struct __OptimiseStruct {
pObjectDescriptor pDes;
int iMaxCycles;
CounterMode eCount;
float fPreset;
int iChannel;
float fThreshold;
int iVar;
pDynar pVariables;
pScanData pScanner;
pFit pPeakFitter;
} Optimiser;
\end{verbatim}
The fields are:
\begin{description}
\item[pDes]The usual object descriptor.
\item[iMaxCycles] The maximum number of cycles to perform.
\item[eCount] The countmode to use for scanning.
\item[fPreset] The preset to use for scanning.
\item[iChannel] The channel to use for scanning.
\item[fThreshold] The threshold to use for identifying lost peaks.
\item[iVar] The number of variables to optimise.
\item[pVariables] A dynamic array of variables to optimise.
\item[pScanner] The scan object to use for scanning.
\item[pFit] The peak center determination object to use.
\end{description}
The interface to this object looks like this:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
\verb@"optimise.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-------------------------------------------------------------------------@\\
\mbox{}\verb@ O P T I M I S E@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Optimise a peak with respect to several variables.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see copyright.h@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, March 1998-1999@\\
\mbox{}\verb@-----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSOPTIMISE@\\
\mbox{}\verb@#define SICSOPTIMISE@\\
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __OptimiseStruct *pOptimise;@\\
\mbox{}\verb@@\\
\mbox{}\verb@/*------------------- live & death -----------------------------------------*/@\\
\mbox{}\verb@ pOptimise CreateOptimiser(pCounter pCount);@\\
\mbox{}\verb@ void DeleteOptimiser(void *pData);@\\
\mbox{}\verb@ int MakeOptimiser(SConnection *pCon, SicsInterp *pSics,@\\
\mbox{}\verb@ void *pData, int argc, char *argv[]);@\\
\mbox{}\verb@/*------------------- operation -------------------------------------------*/@\\
\mbox{}\verb@#define PEAKLOST -1@\\
\mbox{}\verb@#define MAXCYCLE -2@\\
\mbox{}\verb@#define SCANERROR -3@\\
\mbox{}\verb@#define SCANABORT -4@\\
\mbox{}\verb@#define SYSERROR -5@\\
\mbox{}\verb@#define DRIVEERROR -6@\\
\mbox{}\verb@#define VARREDO -7@\\
\mbox{}\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@ void OptimiserClear(pOptimise self);@\\
\mbox{}\verb@ int OptimiserAdd(pOptimise self,@\\
\mbox{}\verb@ char *pVarName, @\\
\mbox{}\verb@ float fStep, @\\
\mbox{}\verb@ int nStep, @\\
\mbox{}\verb@ float fPrecision);@\\
\mbox{}\verb@ int OptimiserSetPar(pOptimise self, char *name, float fVal);@\\
\mbox{}\verb@ int OptimiserGetPar(pOptimise self, char *name, float *fVal);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int OptimiserRun(pOptimise self, SConnection *pCon); @\\
\mbox{}\verb@@\\
\mbox{}\verb@ int OptimiserAction(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
All functions except the installation functions take a pointer to the
optimiser structure as first parameter. The function reference:
\begin{description}
\item[CreateOptimiser] creates an optimiser object. Takes a pointer to
a counter object as a parameter. Returns a pointer to a nice and good
optimiser object on return. Or NULL, if there was some sort of
problem.
\item[DeleteOptimiser] is the deletion function used in the
interpreter for properly removing the optimiser object from the
system.
\item[MakeOptimiser] is the installation function which configures an
optimiser into SICS.
\item[OptimiserClear] removes all configured optimisation variables
and all remnants of a previous optimiser run.
\item[OptimiserAdd] adds a variable to be optimised. Parameter to this
call are: pVarName, the name of the variable to optimise, fStep, the
step width to use for scanning, nStep, the initial number of steps to
use for scanning, fPrecision, the precision to achive for this
variable.
\item[OptimiserSetPar] sets the configuration parameters for the
optimiser. The parameter name is the same name as stated in the
command reference.
\item[OptimiserGetPar] retrieves the value of a configuration
parameters for the
optimiser. The parameter name is the same name as stated in the
command reference.
\item[OptimiserRun] starts the optimser run with the current
parameters. Output is sent to the connection pCon.
\item[OptimiserAction] is the interpreter interface function for the
optimiser.
\end{description}

437
doc/programmer/overview.tex Normal file
View File

@@ -0,0 +1,437 @@
\chapter{SICS Overview}
\section{Introduction}
At the new spallation source SINQ at PSI a whole set of new neutron
scattering instruments are being installed. All these new instruments need a
computer instrument control control system. After a review of similar systems
out in the market it was found that none fully met the requirements defined
for SINQ or could easily be extended to do so. Therefore it was decided to
design a new system. This new system SICS, the SINQ Instrument Control
System, had to meet the following specifications:
\begin{itemize}
\item Control the instrument reliably.
\item Good remote access to the instrument via the internet.
\item Portability across operating system platforms.
\item Enhanced portability across instrument hardware. This means that it
should be easy to add other types of motors, counters or other hardware to
the system.
\item Support authorization on the command and variable level. This means
that certain instrument settings can be protected against random changes by
less knowledgable users.
\item Good maintainability and extendability.
\item Be capable to acomodate graphical user interfaces (GUI).
\item One code base for all instruments.
\item Powerful macro language.
\end{itemize}
A suitable new system was implemented using an object oriented design which
matches the above criteria.
\section{The SINQ Hardware Setup}
SICS had to take in account the SINQ hardware setup which had been decided
upon earlier on. Most hardware such as motors and counters is controlled via
RS--232 interfaces. These devices connect to a Macintosh PC which has a
terminal server program running on it. This terminal server program collects
request to the hardware from a TCP/IP port and forwards them to the serial
device. The instrument control program runs on a workstation running
DigitalUnix. Communication with the hardware happens via TCP/IP through the
terminal server. Some hardware devices, such as the histogram memory, can handle
TCP/IP themselves. With such devices the instrument control program
communicates directly through TCP/IP, without a terminal server. All
hardware devices take care of their real time needs themselves. Thus the
only task of the instrument control program is to orchestrate the hardware
devices. SICS is designed with this setup up in mind, but is not restricted
to this setup. A schematic view of this setup is given in picture
\ref{hard}.
\begin{figure}
%% \epsfxsize=0.65\textwidth
\epsfxsize=160mm
\epsffile{hart.eps}
\caption{Instrument control hardware setup at SINQ}\label{hard}
\end{figure}
\section{SICS Overall Design}
In order to achieve the design goals stated above it was decided to divide
the system into a client server system. This means that there are at least
two programs necessary to run an instrument: a client program and a server
program. The server program, the SICS server, does all the work and
implements the actual instrument control. The SICS server usually runs on
the DAQ computer. The client program may run on any computer on the world
and implements the user interface to the instrument. Any numbers of clients
can communicate with one SICS server. The SICS server and the clients
communicate via a simple ASCII command protocol through TCP/IP sockets.
With this design good remote control through the network is easily achieved.
As clients can be implemented in any language or system capable of handling
TCP/IP the user interface and the functional aspect are well separated. This
allows for easy exchange of user interfaces by writing new clients.
\section{SICS Clients}
SICS Clients implement the SICS user interface. Current client
programs are mostly implemented in Java for platform independence.
This is a real concern at SINQ where VMS,
Intel-PC, Macintosh and Unix users have to be satisfied.
As many instrument scientists still prefer
the command line for interacting with instruments, the most used client is a
visual command line client. Status displays are another sort of specialized
client programs. Graphical user interfaces are under consideration for some
instruments. As an example for a client a screen shot of the status display
client for a powder diffractometer is given in picture \ref{dmc}
\ref{hard}.
\begin{figure}
%% \epsfxsize=0.65\textwidth
\epsfxsize=160mm
%% \epsffile{dmc.eps}
\caption{Example for a SICS client: Powder Diffractometer Status Display}\label{dmc}
\end{figure}
\section{The SICS Server}
The SICS server is the core component of the SICS system. The SICS server is
responsible for doing all the work in instrument control. Additionally the
server has to answer the requests of possibly multiple clients.
The SICS server can be subdivided into three subsystems: The kernel, a database
of SICS objects and an interpreter. The SICS server kernel takes care of
client multitasking and the preservation of the proper I/O and error context
for each client command executing.
SICS objects are software modules which represent all aspects
of an instrument: hardware devices, commands, measurement strategies
and data storage. This database of objects is initialized at server startup
time from an initialization script. The third SICS server component is an
interpreter which allows to issue commands to the objects in the objects database.
The schematic drawing of the SICS server's structure is given in picture
\ref{newsics}.
\begin{figure}
%% \epsfxsize=0.65\textwidth
\epsfxsize=160mm
\epsffile{newsics.eps}
\caption{Schematic Representation of the SICS server's structure}\label{sicsnew}
\end{figure}
\subsection{The SICS Server Kernel}
In more detail the SICS server kernel has the following tasks:
\begin{itemize}
\item Accept and verify client connection requests.
\item Read and execute client commands.
\item Maintain the I/O and error context for each client connection.
\item Serialize data access.
\item Serialize hardware access.
\item Monitor HW--operations.
\item Monitor environment devices.
\end{itemize}
Any server serving multiple clients has the problem how to organize multiple
clients accessing the same server and how to stop one client reading data,
which another client is just writing. The approach used for the SICS server
is a combination of polling and cooperative multitasking. This scheme is
simple and can be implemented in an operating system independent manner. One
way to look at the SICS server is as a series of tasks in a circular queue
executing one after another. The servers main loop does nothing but
executing the tasks in this circular buffer in an endless loop.
There are several system tasks and one such
task for each living client connection. Thus only one task executes at any
given time and data access is efficiently serialized. One of the main system
tasks (and the one which will be always there) is the network reader. The
network reader has a list of open network connections and checks each of
them for pending requests. What happens when a data is pending on an open
network port depends on the type of port: If it is the servers main
connection port, the network reader will try to accept and verify a new
client connection and create the associated data structures. If the port
belongs to an open client connection the network reader will read the
command pending and put it onto a command stack existing for each client
connection. When it is time for a client task to execute, it will fetch a
command from its very own command stack and execute it. When the net reader
finds an user interrupt pending, the interrupt is executed.
This is how the SICS server deals with client requests.
The scheme described above relies on the fact that most SICS command need
only very little time to execute. A command needing time extensive
calculations may effectively block the server. Implementations of such
commands have to take care that control passes back to the task switching
loop at regular intervalls in order to prevent the server from blocking.
Another problem in a server handling multiple client requests is how to
maintain the proper execution context for each client. This includes the
clients I/O-context (socket), the authorisation of the client and possible
error conditions pending for a
client connection. SICS does this via a connection object, a special
data structure holding all the above information plus a set of functions
operating on this data structure. This connection object is passed along
with many calls throughout the whole system.
Multiple clients issuing commands to the SICS server may mean that multiple
clients might try to move motors or access other hardware in conflicting
ways. As there is only one set of instrument hardware this needs to be
prevented. This is achieved by a convention. No SICS object drives hardware
directly but registers it's request with a special object, the device
executor. This device executor starts the requested operation and reserves
the hardware for the length of the operation. During the execution of such
an hardware request all other clients requests to drive the hardware will
return an error. The device executor is also responsible for monitoring the
progress of an hardware operation. It does so by adding a special task into
the system which checks the status of the operation each time this tasks
executes. When the hardware operation is finished (one way or another) this
device executor task will end. A special system facility allows a client
task to wait for the device executor task to end while the rest of the task
queue is still executing. In this way time intensive hardware operations can
be performed by drive, count or scan commands without blocking the whole
system for other clients. \label{devexec}
The SICS server can be configured to support another security feature, the
token system. In this scheme a client can grab control of the instrument.
With the control token grabbed, only the client which has the token may
control the instrument. Any other client may look at things in the SICS server
but does not have permission to change anything. Passing the control token
requires that the client which has the token releases the token so that
another client may grab it. There exists a password protected back door for
SICS managers which allows to force the release of a control token.
Most experiments do not happen at ambient room conditions but
require some special environment for the sample. Mostly this is temperature
but it can also be magnetic of electric fields etc. Most of such devices
can regulate themselves but the data acquisition program needs to monitor
such devices. Within SICS this is done via a special system object, the
environment monitor. A environment device, for example a temperature
controller, registers it's presence with this object. Then an special system
task will control this device when it is executing, check for possible out
of range errors and initiates the proper error handling if such a problem is
encountered.
\subsection{The SICS Interpreter}
When a task belonging to a client connection executes a command it will pass
the command along with the connection object to the SICS interpreter. The
SICS interpreter will then analyze the command and forward it to the
appropriate SICS object in the object database for further action. The SICS
interpreter is very much modeled after the Tcl interpreter as devised by
John Ousterhout$^{1}$. For each SICS object visible from the interpreter there is
a wrapper function. Using the first word of the command as a key, the
interpreter will locate the objects wrapper function. If such a function is
found it is passed the command parameters, the interpreter object and the
connection object for further processing. An interface exists to add and
remove commands to this interpreter very easily. Thus the actual command
list can be configured easily to match the instrument in question, sometimes
even at run time. Given the closeness of the design of the SICS interpreter
to the Tcl interpreter, the reader may not be surprised to learn that the
SICS server incorporates Tcl as its internal macro language. The internal
macro language may use Tcl commands as well as SICS commands.
\subsection{SICS Objects}
As already said, SICS objects implement the true functionality of SICS
instrument control. All hardware, all commands and procedures, all data
handling strategies are implemented as SICS objects. Hardware objects, for
instance motors deserve some special attention. Such objects are divided
into two objects in the SICS system: A logical hardware object and a driver
object. The logical object is responsible for implementing all the nuts and
bolts of the hardware device, whereas the driver defines a set of primitive
operations on the device. The benefit of this scheme is twofold:
switching to new hardware, for instance a new type of motor, just requires
to incorporate a new driver into the system. Internally, independent from
the actual hardware, all hardware object of the same type (for example
motors) look the same and can be treated the same by higher level objects.
No need to rewrite a scan command because a motor changed.
In order to live happily within the SICS system SICS object have to adhere
to a system of protocols. There are protocols for:
\begin{itemize}
\item Input/Output to the client.
\item Error handling.
\item Interaction with the interpreter.
\item For identification of the object to the system at run time.
\item For interacting with hardware (see device executor above).
\item For checking the authorisation of the client who wants to execute the
command.
\end{itemize}
SICS uses NeXus$^{2}$, the upcoming standard for data exchange for neutron
and x\_ray scattering as its raw data format.
SICS objects have the ability to notify clients and other objects of
internal state changes. For example when a motor is driven, the motor object
can be configured to tell SICS clients or other SICS objects about his new
position.
\section{SICS Working Examples}
In order to get a better feeling for the internal working of SICS the course
of a few different requests through the SICS system is traced in this
section. The examples traced will be:
\begin{itemize}
\item A request for a new client connection.
\item A simple command.
\item A command to drive a motor in blocking mode.
\item A command to drive a motor which got interrupted by the user.
\item A command to drive a motor in non blocking mode.
\end{itemize}
For the whole discussion it is assumed that the main loop is running,
executing cyclically each single task registered in the server. Task switching is
done by a special system component, the task switcher.
\subsection{The Request for a new Client Connection}
\begin{itemize}
\item The network reader recognizes pending data on its main server port.
\item The network reader accepts the connection and tries to read a
username/password pair.
\item If such a username/password pair comes within a suitable time
intervals it is checked for validity. On failure the connection is closed
again.
\item If a valid connection has been found: A new connection object is
created, a new task for this client connection is introduced into the
system and the network reader registers a new client port to check for
pending commands.
\item Control is passed back to the task switcher.
\end{itemize}
\subsection{A Simple Command}
\begin{itemize}
\item The network reader finds data pending at one of the client ports.
\item The network reader reads the command, splits it into single lines and
put those on the top of the client connections command stack. The network
reader passes control to the task switcher.
\item In due time the client connection task executes, inspects its command
stack, pops the command pending and forwards it together with a pointer to
itself to the SICS interpreter.
\item The SICS interpreter inspects the first word of the command. Using
this key the interpreter finds the objects wrapper function and passes
control to that function.
\item The object wrapper function will check further arguments, checks the
clients authorisation if appropriate for the action requested. Depending on
the checks, the wrapper function will create an error message or do its
work.
\item This done, control passes back through the interpreter and the connection
task to the task switcher.
\item The next task executes.
\end{itemize}
\subsection{A Drive Command in Blocking Mode}
\begin{itemize}
\item The network reader finds data pending at one of the client ports.
\item The network reader reads the command, splits it into single lines and
put those on the top of the client connections command stack. The network
reader passes control to the task switcher.
\item In due time the client connection task executes, inspects its command
stack, pops the command pending and forwards it together with a pointer to
itself to the SICS interpreter.
\item The SICS interpreter inspects the first word of the command. Using
this key the interpreter finds the drive command wrapper function and passes
control to that function.
\item The drive command wrapper function will check further arguments,
checks the
clients authorisation if appropriate for the action requested. Depending on
the checks, the wrapper function will create an error message or do its
work.
\item Assuming everything is OK, the motor is located in the system.
\item The drive command wrapper function asks the device executor to run the
motor.
\item The device executor verifies that nobody else is driving, then starts
the motor and grabs hardware control. The device executor also starts a task
monitoring the activity of the motor.
\item The drive command wrapper function now enters a wait state. This means
the task switcher will execute other tasks, except the connection task
requesting the wait state. The client connection and task executing the drive command
will not be able to process further commands.
\item The device executor task will keep on monitoring the progress of the motor
driving whenever the task switcher allows it to execute.
\item In due time the device executor task will find that the motor finished
driving. The task will then die. The clients grab of the hardware driving
permission will be released.
\item At this stage the drive command wrapper function will awake and
continue execution. This means inspecting errors and reporting to the client
how things worked out.
\item This done, control passes back through the interpreter and the connection
task to the task switcher. The client connection is free to execute
other commands.
\item The next task executes.
\end{itemize}
\subsection{A Drive Command Interrupted}
\begin{itemize}
\item The network reader finds data pending at one of the client ports.
\item The network reader reads the command, splits it into single lines and
put those on the top of the client connections command stack. The network
reader passes control to the task switcher.
\item In due time the client connection task executes, inspects its command
stack, pops the command pending and forwards it together with a pointer to
itself to the SICS interpreter.
\item The SICS interpreter inspects the first word of the command. Using
this key the interpreter finds the drive command wrapper function and passes
control to that function.
\item The drive command wrapper function will check further arguments,
checks the
clients authorisation if appropriate for the action requested. Depending on
the checks, the wrapper function will create an error message or do its
work.
\item Assuming everything is OK, the motor is located in the system.
\item The drive command wrapper function asks the device executor to run the
motor.
\item The device executor verifies that nobody else is driving, then starts
the motor and grabs hardware control. The device executor also starts a task
monitoring the activity of the motor.
\item The drive command wrapper function now enters a wait state. This means
the task switcher will execute other tasks, except the connection task
requesting the wait state.
\item The device executor task will keep on monitoring the progress of the
driving of the motor when it is its turn to execute.
\item The network reader finds a user interrupt pending. The interrupt will
be forwarded to all tasks in the system.
\item In due time the device executor task will try to check on the progress
of the motor. It will recognize the interrupt. If appropriate the motor will
get a halt command. The task will then die.
The clients grab of the hardware driving permission will be released.
\item At this stage the drive command wrapper function will awake and
continue execution. This means it finds the interrupt, tells the user what he
already knows: an interrupt was issued.
\item This done, control passes back through drive command wrapper,
the interpreter and the connection
task to the task switcher.
\item The next task executes.
\end{itemize}
\subsection{A Run Command in Non Blocking Mode}
\begin{itemize}
\item The network reader finds data pending at one of the client ports.
\item The network reader reads the command, splits it into single lines and
put those on the top of the client connections command stack. The network
reader passes control to the task switcher.
\item In due time the client connection task executes, inspects its command
stack, pops the command pending and forwards it together with a pointer to
itself to the SICS interpreter.
\item The SICS interpreter inspects the first word of the command. Using
this key the interpreter finds the drive command wrapper function and passes
control to that function.
\item The run command wrapper function will check further arguments,
checks the
clients authorisation if appropriate for the action requested. Depending on
the checks, the wrapper function will create an error message or do its
work.
\item Assuming everything is OK, the motor is located in the system.
\item The drive command wrapper function asks the device executor to run the
motor.
\item The device executor verifies that nobody else is driving, then starts
the motor and grabs hardware control. The device executor also starts a task
monitoring the activity of the motor.
\item The run command wrapper function passes control through the interpreter and
the clients task function back to the task switcher. The client connection can handle
new commands.
\item The device executor task will keep on monitoring the progress of the motor
driving whenever the task switcher allows it to execute.
\item In due time the device executor task will find that the motor finished
driving. The task will then die silently. The clients grab of the hardware driving
permission will be released. If errors occurred, however a they will be reported.
\item At this stage the drive command wrapper function will awake and
continue execution. This means inspecting errors and reporting to the client
how things worked out.
\item This done, control passes back through the interpreter and the connection
task to the task switcher. The client connection is free to execute
other commands.
\item The next task executes.
\end{itemize}
All this seems to be pretty complex and time consuming. But it is the complexity needed to
do so many things, especially the non blocking mode of operation requested
by users. Tests have shown that the task switcher manages +900 cycles per second
through
the task list on a DigitalUnix machine and 50 cycles per second on a pentium 133mhz
machine running linux. Both data were obtained with software simulation of
hardware devices. With real SINQ hardware these numbers drop 4 cycles per
second. This shows clearly that the communication with the hardware is the
systems bottleneck and not the task switching scheme.

20
doc/programmer/passwd.tex Normal file
View File

@@ -0,0 +1,20 @@
\subsection{The Password Database}
This is just a simple password database. It keeps for each user an
record containing username, password and an integer code. The code
is meant to encode the users rights within the system. On
initialisation the information is read from a file. Currently there
is no encryption in this. Rely on the filesytem protection mechanisms
for protecting passwords. Though SICS will have only a limited number
of different user levels, the password class is designed to cope with
more and stores its data in a linked list. Currently user names and
passwords are entered into the database through the SicsUser
initialization command.
The interface:\begin{itemize}
\item {\bf int InitPasswd(char *filename) } reads user data from the file specified. Returns True on success, false else.
\item {\bf void AddUser(char *name, char *passwd, int iCode) }, adds a new user to the database.
\item {\bf int IsValidUser(char *name, char *passwd) }, checks a users authorisation information. Returns a negative value if the user is invalid, the users rights code if he is valid.
\item {\bf void KillPasswd(void) }, deletes the password data structures, when it is no longer needed. Omission of this call will result in wasted memory.
\end{itemize}

119
doc/programmer/perfmon.tex Normal file
View File

@@ -0,0 +1,119 @@
\subsection{Performance Monitor}
This object implements a performance monitor for SICS. Please note that SICS
performance is determined not only by processor speed but by a whole range
of factors:
\begin{itemize}
\item Processor speed and memory.
\item Speed of network connctions to hardware devices.
\item Number of clients connected.
\end{itemize}
The PerfMonTask is called from the SICS task modules main loop. It will then
increment a cycle counter and check if a predefined intergration time has
passed. If so a new
value for cycle per seconds will be calculated. This is also the main
output of PerfMon. PerfMon implements a callback interface in order to allow
automatical notification about system performance.
PerfMon has a little datastructure:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$pdata {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __PerfMon {@\\
\mbox{}\verb@ pObjectDescriptor pDes;@\\
\mbox{}\verb@ pICallBack pCall;@\\
\mbox{}\verb@ int iLog; /* flag for@\\
\mbox{}\verb@ serverlog writing */ @\\
\mbox{}\verb@ float fCPS; /* cycles per seconds */@\\
\mbox{}\verb@ int iInteg; /* integration time */@\\
\mbox{}\verb@ int iCount;@\\
\mbox{}\verb@ time_t tLast; /* last time calculated */@\\
\mbox{}\verb@ time_t tTarget; /* next target time */@\\
\mbox{}\verb@ int iEnd;@\\
\mbox{}\verb@ }PerfMon;@\\
\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 interface consists of the following functions:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$pInter {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __PerfMon *pPerfMon;@\\
\mbox{}\verb@/*---------------------- live and death ----------------------------------*/@\\
\mbox{}\verb@ pPerfMon CreatePerfMon(int iInteg);@\\
\mbox{}\verb@ void DeletePerfMon(void *pData);@\\
\mbox{}\verb@/*---------------------- increment ---------------------------------------*/@\\
\mbox{}\verb@ int IncrementPerfMon(pPerfMon self);@\\
\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
\mbox{}\verb@ float GetPerformance(pPerfMon self);@\\
\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
\mbox{}\verb@ int PerfMonWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@/*-----------------------------------------------------------------------*/@\\
\mbox{}\verb@ int PerfMonTask(void *pPerf);@\\
\mbox{}\verb@ void PerfMonSignal(void *pPerf, int iSignal, void *pSigData); @\\
\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}
There is really not much to this.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
\verb@"perfmon.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-------------------------------------------------------------------------@\\
\mbox{}\verb@ P E R F M O N@\\
\mbox{}\verb@ A performance monitor for SICS. Maintains and calculates a value for@\\
\mbox{}\verb@ cycles per seconds. @\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, Juli 1997@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see implementation file@\\
\mbox{}\verb@---------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSPERFMON@\\
\mbox{}\verb@#define SICSPERFMON@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\langle$pInter {\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@"perfmon.i"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------@\\
\mbox{}\verb@ The P E R F M O N datastructure.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, Juli 1997@\\
\mbox{}\verb@---------------------------------------------------------------------------*/@\\
\mbox{}\verb@@$\langle$pdata {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

View File

@@ -0,0 +1,67 @@
\subsubsection{Physik Instrumente DC-Motor Controller}
This is a mainly a driver for a C-804 DC-motor Controller as produced by the
Company Physik Instrumente. This controller drives up to four high precision
motors. These motors do not have reference points and have variable speeds.
Therefore some additional code is needed to handle motor specific commands.
This problem is solved by handling these specific additional commands in a
new wrapper routine which finally calls the main motor wrapper routine for
all the other commands. Of course, a special factory method is needed for
this device as well.
The public interface for this motor includes the following functions:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$pimoti {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int PIMotorWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ int PIMotorFactory(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int PISetSpeed(pMotor self, SConnection *pCon, float fNew);@\\
\mbox{}\verb@ int PIGetSpeed(pMotor self, SConnection *pCon, float *fVal);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int PIHome(pMotor self, SConnection *pCon);@\\
\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@"pimotor.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------@\\
\mbox{}\verb@ P I M O T O R@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Driver and add on code for the Physik Instrument Motor Controller C-804.@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ Mark Koennecke, September 1998@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef PIMOTOR@\\
\mbox{}\verb@#define PIMOTOR@\\
\mbox{}\verb@@$\langle$pimoti {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{Physik Instrument Piezo Controller E-255}
This is piezo translator. A voltage is set and it elongates. It is
handled as a motor because it is going to be scanned. A driver has
been implemented in the file pipiezo.c. For
the command protocoll, see the documentation coming with the gadget.

View File

@@ -0,0 +1,47 @@
\chapter{SICS Programmers Reference}
This chapter is a boring listing of the interfaces and functions provided by
the SICS modules.
\section{Kernel Objects and Modules}
This section describes the objects and modules defining the SICS kernel.
\include{nserver}
\include{nread}
\include{nconman}
\include{emonitor}
\include{event}
\include{interface}
\include{devexec}
\include{perfmon}
\include{ini}
\include{inter}
\include{macro}
\include{network}
\include{passwd}
\section{SICS Objects}
This section describes the SICS objects implementing commands and hardware
objects.
\include{velo}
\include{velodorn}
\include{scan}
\include{evcontroller}
\include{center}
\include{danu}
\include{evcontroller}
\include{itc4}
\include{histogram}
\include{histsim}
\include{sinqhmdriv}
\include{nxdata}
\section{Helper Objects}
This section describes helper objects which implement useful data
structures or utilities.
\include{varlog}
\include{dynar}
\include{costa}
\include{stringdict}
\include{splitter}

View File

@@ -0,0 +1,37 @@
% Copyleft (c) 1997-2000 by Mark Koennecke at PSI, Switzerland.
%
%
%
\documentclass[12pt]{report}
\usepackage{epsf}
\setlength{\oddsidemargin}{-.1in}
\setlength{\evensidemargin}{0in}
\setlength{\topmargin}{0in}
\addtolength{\topmargin}{-\headheight}
\addtolength{\topmargin}{-\headsep}
\setlength{\textheight}{8.9in}
\setlength{\textwidth}{6.2in}
\setlength{\marginparwidth}{0.5in}
\begin{document}
\title{The SICS Programmers Reference}
\author{Mark K\"onnecke\\
Labor f\"ur Neutronenstreuung\\
Paul Scherrer Institut\\
CH-5232 Villigen PSI\\
Switzerland\\
Mark.Koennecke@psi.ch \\
}
\maketitle
\tableofcontents
\include{overview}
\include{proto}
\include{kernelguide}
\include{oguide}
\end{document}

61
doc/programmer/proto.tex Normal file
View File

@@ -0,0 +1,61 @@
\chapter{The SICS Server Client Protocol}
This short chapter describes the command protocol between the SICS server
and possible SICS clients. All this is very simple.
\section{Logging in to the SICS Server}
In order to log in to the SICS server it needs to be known on which
machine the server runs and at which port number the server listens for
connection requests. Also needed is a valid username/ password pair for the
SICS server in question. Given that the procedure for connecting to a SICS
server requires the following steps:
\begin{enumerate}
\item Open a TCP/IP connection to the SICS server port at the machine
where it is running.
\item Immediately after opening the connection send the username/password
pair. If everything is OK, a string OK is sent. Else the server will break
the connection again.
\end{enumerate}
\section{Sending Commands}
After login, two means of communications exist. The communication
protocoll is choosen through the server port the client connects too.
The recommended way is
to adhere to the telnet protocoll as described in RFC-854. Just a
basic NVT (Network Virtual Terminal) with no options is
implemented. Binary communication is not possible on a telnet port.
The older way of communication is to send commands directly on the
TCP/IP port. Commands are strings terminated by a \verb+\n+. Return
messages from the server have the same format. This scheme is
obsolete but it has been left in because the need for a binary
communication may arise and this would help implement such a thing.
For a list of possible commands consult the
user documentation.
\section{Issuing Interrupts}
In some cases a user might want to stop the operation of the server. In
order to do this the client must send an interrupt to the SICS server. There
are two ways to do this: through the normal connection socket and through
the a special UDP message to the server. Let us first discuss the first
method, which uses the normal command socket for sending an interrupt.
In order to send an interrupt through the normal command socket a special
message must be sent, consisting of a special command string. The command
string is again all ASCII. The first part of this command string must read:
INT1712, followed by a number denoting the interrupt. The meaning of these
numbers is resolved in file interrupt.h. For example, the string 'INT1712 2'
will abort the current scan. The presence of an interrupt string will be
checked for already by the network reader. This means that such interrupts
will even be honored when the client connection is waiting for some hardware
to finish its job and would not accept normal commands. \label{prot1}
The SICS server also checks a special TCP/IP port for UDP messages which
denote an interrupt. In order to send an interrupt through this channel, a
UDP connection to the SICS servers UDP port must be opened. Then an special
ASCII string of the form: {\bf SICSINT num} must be sent. num must be
replaced by the number of the interrupt to issue. Again interrupt codes are
resolved in file interrupt.h.

346
doc/programmer/pub.tex Normal file
View File

@@ -0,0 +1,346 @@
% Copyleft (c) 1997 by Mark Koennecke at PSI, Switzerland.
%
%
%
\documentclass[12pt]{article}
\usepackage{epsf}
\setlength{\oddsidemargin}{-.1in}
\setlength{\evensidemargin}{0in}
\setlength{\topmargin}{0in}
\addtolength{\topmargin}{-\headheight}
\addtolength{\topmargin}{-\headsep}
\setlength{\textheight}{8.9in}
\setlength{\textwidth}{6.2in}
\setlength{\marginparwidth}{0.5in}
\parindent=0pt
\parskip=0.3cm
\begin{document}
\title{SICS: SINQ Instrument Control Software}
\author{Mark K\"onnecke\\
Heinz Heer\\
Labor f\"ur Neutronenstreuung\\
Paul Scherrer Institut\\
CH-5232 Villigen PSI\\
Switzerland\\
Mark.Koennecke@psi.ch \\
Heinz.Heer@psi.ch \\
}
\maketitle
\section{Introduction}
At the new spallation source SINQ at PSI a whole set of new neutron
scattering instruments are being installed. All these new instruments need a
instrument control control system. After a review of similar systems
out in the market it was found that none fully met the requirements defined
for SINQ or could easily be extended to do so. Therefore it was decided to
design a new system. This new system SICS, the SINQ Instrument Control
System, had to meet the following specifications:
\begin{itemize}
\item Control the instrument reliably.
\item Good remote access to the instrument via the internet.
\item Portability across operating system platforms.
\item Enhanced portability across instrument hardware. This means that it
should be easy to add other types of motors, counters or other hardware to
the system.
\item Support authorization on the command and variable level. This means
that certain instrument settings can be protected against harmful changes by
less knowledgable users.
\item Good maintainability and extendability.
\item Be capable to acomodate graphical user interfaces (GUI).
\item Single code base for all instruments.
\item Powerful macro language.
\end{itemize}
A suitable new system was implemented using an object oriented design which
matches the above criteria.
\section{The SINQ Hardware Setup}
SICS had to take in account the SINQ hardware setup which had been decided
upon earlier on. Most hardware such as motors and counters is controlled via
RS--232 interfaces. These devices connect to a Macintosh PC which has a
terminal server program running on it. This terminal server program collects
request to the hardware from a TCP/IP port and forwards them to the serial
device. The instrument control program runs on a workstation running
DigitalUnix. Communication with the hardware happens via TCP/IP through the
terminal server. Some hardware devices, such as the histogram memory, can handle
TCP/IP themselves. With such devices the instrument control program
communicates directly through TCP/IP, without a terminal server. All
hardware devices take care of their real time needs themselves. Thus the
only task of the instrument control program is to orchestrate the hardware
devices. SICS is designed with this setup up in mind, but is not restricted
to it. A schematic view of the SINQ hardware setup is given in picture
\ref{hard}.
\begin{figure}
\epsfxsize=0.65\textwidth
%% \epsfxsize=160mm
\epsffile{hart.eps}
\caption{Instrument control hardware setup at SINQ}\label{hard}
\end{figure}
\section{SICS Overall Design}
In order to achieve the design goals stated above it was decided to divide
the system into a client server system. This means that there are at least
two programs necessary to run an instrument: a client program and a server
program. The server program, the SICS server, does all the work and
implements the actual instrument control. The SICS server usually runs on
the DAQ computer. The client program may run on any computer on the world
and implements the user interface to the instrument. Any numbers of clients
can communicate with one SICS server. The SICS server and the clients
communicate via a simple ASCII command protocol through TCP/IP sockets.
With this design good remote control through the network is easily achieved.
SICS clients can be implemented in any language or system capable of handling
TCP/IP. Thus the user interface and the functional aspect are well separated. This
allows for easy exchange of user interfaces by writing new clients.
\section{SICS Clients}
SICS Clients implement the SICS user interface. Current client programs have
been written in Tcl/TK$^{1}$, but work is under way to recode clients in Java for
maximum platform portability. This is a real concern at SINQ where VMS,
Intel-PC, Macintosh and Unix users have to be satisfied. As many instrument scientists still prefer
the command line for interacting with instruments, the most used client is a
visual command line client. Status displays are another sort of specialized
client programs. Graphical user interfaces are under consideration for some
instruments. As an example for a client a screen shot of the command line
client is given in picture \ref{dmc}.
\begin{figure}[h]
\epsfxsize=0.9\textwidth
%% \epsfxsize=160mm
\epsffile{dmccom.eps}
\caption{Example for a SICS client: The Command line client}\label{dmc}
\end{figure}
\section{The SICS Server}
The SICS server is the core component of the SICS system. The SICS server is
responsible for doing all the work in instrument control. Additionally the
server has to answer the requests of possibly multiple clients.
The SICS server can be subdivided into three subsystems: The kernel, a database
of SICS objects and an interpreter. The SICS server kernel takes care of
client multitasking and the preservation of the proper I/O and error context
for each client command executing.
SICS objects are software modules which represent all aspects
of an instrument: hardware devices, commands, measurement strategies
and data storage. The SICS server's database of objects is initialized at server startup
time from an initialization script. The third SICS server component is an
interpreter which allows to issue commands to the objects in the objects database.
A schematic drawing of the SICS server's structure is given in picture
\ref{sicsnew}.
\begin{figure}
\epsfxsize=0.9\textwidth
\epsfysize=100mm
%% \epsfxsize=160mm
\epsffile{newsics.eps}
\caption{Schematic Representation of the SICS server's structure}\label{sicsnew}
\end{figure}
\subsection{The SICS Server Kernel}
Any server-program has the problem how to organize multiple
clients accessing the same server and how to stop one client reading data,
which another client is just writing. The approach used for the SICS server
is a combination of polling and cooperative multitasking. This scheme is
simple and can be implemented in an operating system independent manner. One
way to look at the SICS server is as a series of tasks in a circular queue
executing one after another. There are several system tasks and one
task for each living client connection. The servers main loop does nothing but
executing the tasks in this circular buffer in an endless loop.
Thus only one task executes at any
given time and data access is efficiently serialized.
One of the main system
tasks (and the one which will be always there) is the network reader. The
network reader has a list of open network connections and checks each of
them for pending requests. What happens when data is pending on an open
network port depends on the type of port: If it is the servers main
connection port, the network reader will try to accept and verify a new
client connection and create the associated data structures. If the port
belongs to an open client connection the network reader will read the
command pending and put it onto a command stack existing for each client
connection. When it is time for a client task to execute, it will fetch a
command from its very own command stack and execute it. When the net reader
finds an user interrupt pending, the interrupt is executed.
This is how the SICS server deals with client requests.
The scheme described above relies on the fact that most SICS command need
only very little time to execute. A command needing time extensive
calculations may effectively block the server. Implementations of such
commands have to take care that control passes back to the task switching
loop at regular intervalls in order to prevent the server from blocking.
Another problem in a server handling multiple client requests is how to
maintain the proper execution context for each client. This includes the
clients I/O-context (socket), the authorisation of the client and possible
error conditions pending for a
client connection. SICS does this via a connection object, a special
data structure holding all the above information plus a set of functions
operating on this data structure. This connection object is passed along
with many calls throughout the whole system.
Multiple clients issuing commands to the SICS server may mean that multiple
clients might try to move motors or access other hardware in conflicting
ways. As there is only one set of instrument hardware this needs to be
prevented. This is achieved by a convention. No SICS object drives hardware
directly but registers it's request with a special object, the device
executor. This device executor starts the requested operation and reserves
the hardware to the client for the length of the operation. During the execution of such
an hardware request all other clients requests to drive the hardware will
return an error. The device executor is also responsible for monitoring the
progress of an hardware operation. It does so by adding a special task into
the system which checks the status of the operation each time this tasks
executes. When the hardware operation is finished this
device executor task will end. A special system facility allows a client
task to wait for the device executor task to end while the rest of the task
queue is still executing. In this way time intensive hardware operations can
be performed by drive, count or scan commands without blocking the whole
system for other clients. \label{devexec}
Most experiments do not happen at ambient room conditions but
require some special environment for the sample. Mostly this is temperature
but it can also be magnetic of electric fields etc. Most of such devices
can regulate themselves but the data acquisition program needs to monitor
such devices. Within SICS this is done via a special system object, the
environment monitor. A environment device, for example a temperature
controller, registers it's presence with this object. Then an special system
task will control this device when it is executing, check for possible out
of range errors and initiates the proper error handling if such a problem is
encountered.
\subsection{The SICS Interpreter}
When a task belonging to a client connection executes a command it will pass
the command along with the connection object to the SICS interpreter. The
SICS interpreter will then analyze the command and forward it to the
appropriate SICS object in the object database for further action. The SICS
interpreter is very much modeled after the Tcl interpreter as devised by
John Ousterhout$^{1}$. For each SICS object visible from the interpreter there is
a wrapper function. Using the first word of the command as a key, the
interpreter will locate the objects wrapper function. If such a function is
found it is passed the command parameters, the interpreter object and the
connection object for further processing. An interface exists to add and
remove commands to this interpreter very easily. Thus the actual command
list can be configured easily to match the instrument in question, sometimes
even at run time. Given the closeness of the design of the SICS interpreter
to the Tcl interpreter, the reader may not be surprised to learn that the
SICS server incorporates Tcl as its internal macro language. The internal
macro language may use Tcl commands as well as SICS commands.
\subsection{SICS Objects}
As already said, SICS objects implement the true functionality of SICS
instrument control. All hardware, all commands and procedures, all data
handling strategies are implemented as SICS objects. Hardware objects, for
instance motors deserve some special attention. Such objects are divided
into two objects in the SICS system: A logical hardware object and a driver
object. The logical object is responsible for implementing all the nuts and
bolts of the hardware device, whereas the driver defines a set of primitive
operations on the device. The benefit of this scheme is twofold:
switching to new hardware, for instance a new type of motor, just requires
to incorporate a new driver into the system. Internally, independent from
the actual hardware, all hardware object of the same type (for example
motors) look the same and can be treated the same by higher level objects.
No need to rewrite a scan command because a motor changed.
In order to live happily within the SICS system SICS object have to adhere
to a system of protocols. There are protocols for:
\begin{itemize}
\item Input/Output to the client.
\item Error handling.
\item Interaction with the interpreter.
\item For identification of the object to the system at run time.
\item For interacting with hardware (see device executor above).
\item For checking the authorisation of the client who wants to execute the
command.
\end{itemize}
SICS uses NeXus$^{2}$, the upcoming standard for data exchange for neutron
and X\_ray scattering as its raw data format.
SICS objects have the ability to notify clients and other objects of
internal state changes. For example when a motor is driven, the motor object
can be configured to tell SICS clients or other SICS objects about his new
position.
The SICS server has been implemented in ANSI--C for maximum portability.
ANSI--C proved powerful enough to support SICS's object oriented programming
concepts.
\section{SICS Working Example}
In order to illustrate the inner working of the SICS server a command to
drive a motor will be traced through the system.
\begin{itemize}
\item The network reader finds data pending at one of the client ports.
\item The network reader reads the command, splits it into single lines and
put those on the top of the client connections command stack. The network
reader passes control to the task switcher.
\item In due time the client connection task executes, inspects its command
stack, pops the command pending and forwards it together with a pointer to
itself to the SICS interpreter.
\item The SICS interpreter inspects the first word of the command. Using
this key the interpreter finds the drive command wrapper function and passes
control to that function.
\item The drive command wrapper function will check further arguments,
checks the
clients authorisation if appropriate for the action requested. Depending on
the checks, the wrapper function will create an error message or do its
work.
\item Assuming everything is OK, the motor is located in the system.
\item The drive command wrapper function asks the device executor to run the
motor.
\item The device executor verifies that nobody else is driving, then starts
the motor and grabs hardware control. The device executor also starts a task
monitoring the activity of the motor.
\item The drive command wrapper function now enters a wait state. This means
the task switcher will execute other tasks, except the connection task
requesting the wait state. The client connection and task executing the drive command
will not be able to process further commands.
\item The device executor task will keep on monitoring the progress of the motor
driving whenever the task switcher allows it to execute.
\item In due time the device executor task will find that the motor finished
driving. The task will then die. The clients grab of the hardware driving
permission will be released.
\item At this stage the drive command wrapper function will awake and
continue execution. This means inspecting errors and reporting to the client
how things worked out.
\item This done, control passes back through the interpreter and the connection
task to the task switcher. The client connection is free to execute
other commands.
\item The next task executes.
\end{itemize}
\section{Current Status}
Currently, SICS is in operation on the powder diffractometer DMC, the two circle
diffractometer TOPSI and the small angle scattering diffractometer SANS.
First clients have been
implemented in Tcl/TK$^{1}$ and ANSI--C for a command line interface and status
displays. First experiences with the system were positive. SICS currently
supports the following hardware:
\begin{itemize}
\item SINQ EL734 motor controller.
\item SINQ EL737 counter box.
\item SINQ Histogram Memory.
\item Dornier Velocity Selector.
\item Oxford Instruments ITC4 temperature controller.
\end{itemize}
SICS is in
ongoing development. Support for the reactor time--of--flight instrument
FOCUS, the
reflectometer AMOR and the four circle diffractometer TRICS will be added in near
future. Support for chopper control and more sample environment devices
is on the way. More clients will be written in the Java programming language for
optimal portability. Parties interested in using SICS or wishing to
collaborate in its development are kindly asked to contact the authors.
\section{References}
\begin{enumerate}
\item John K Ousterhout: Tcl and the Tk toolkit, Addison--Wesley, 1994.
\end{enumerate}
\end{document}

View File

@@ -0,0 +1,313 @@
% Copyleft (c) 1997-2000 by Mark Koennecke at PSI, Switzerland.
%
%
% This software is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You may already have a copy of the GNU General Public License; if
% not, write to the Free Software Foundation, Inc., 675 Mass Ave,
% Cambridge, MA 02139, USA.
%
\documentclass[12pt]{article}
\usepackage{epsf}
\setlength{\oddsidemargin}{-.1in}
\setlength{\evensidemargin}{0in}
\setlength{\topmargin}{0in}
\addtolength{\topmargin}{-\headheight}
\addtolength{\topmargin}{-\headsep}
\setlength{\textheight}{8.9in}
\setlength{\textwidth}{6.2in}
\setlength{\marginparwidth}{0.5in}
\begin{document}
\title{SICS Reference Manual}
\author{Mark K\"onnecke\\
Labor f\"ur Neutronenstreuung\\
Paul Scherrer Institut\\
CH-5232 Villigen PSI\\
Switzerland\\
Mark.Koennecke@psi.ch \\
}
\maketitle
\clearpage
\tableofcontents
\clearpage
\section{SICS Programmers Reference}
This document is mostly a boring listing of the interfaces and functions provided by
the SICS modules. In order to get an idea of what is going on, please look
at the SICS user documentation, the SICS manager documentation, and the SICS
programmer guide.
{\huge Warning} This document serves as
internal document for SICS developers only. It has not been proofread to any
standards!
\section{Coding Practicalities}
\subsection{Files}
Any module or object has at least the following files associated with it:
\begin{description}
\item[.h] a header file with the external function definitions and
often a typedef for the object data structure. The idea is that object
data structures are exposed only where absolutely necessary.
\item[.c] the implementation file. Often data structures are only
defined in here.
\item[.tex] a latex file describing the module or object, its data
structures and its interface functions. To be included into this document.
\end{description}
Quite often, there are further files:
\begin{description}
\item[.i] descriptions of internal data structures.
\item[.w] nuweb literate programming files. .w file contain a mixture
of latex commands and code. The idea is that the code is embedded with
the documentation. There are special commands to craete additional
output files suitable for a compiler. The .w files are processed by
the nuweb utility which will create tex documentation and code files
from it. In SICS this is used to document data structures and
interfaces and provide general information about each object. Then
.tex, .h and .i files are created by nuweb. The use of this facility is
recommended.
\end{description}
\subsection{Building SICS}
This document describes how to build the SICS software and where to find it.
There are two sections: Building the SICS applications and building the Java
clients. For both categories tarballs with all necessary files can be
found in the /data/lnslib/src/sics directory. There are two tar files:
sics.tar which contains the sources for the SICS server and additional C or
F77 applications and java.tar which contains the code for the Java clients.
\subsubsection{Building the SICS Server and Applications}
The first step is to untar the sics.tar file. As a result a directory sics
with several subdirectories will be created. These subdirectories are:
\begin{description}
\item[hardsup] contains David Madens and other hardware drivers.
\item[motor] contains the unix version of David Madens el734\_test program.
\item[doc/programmer]holds programming documentation for SICS.
\item[doc/user] The html sources for the user documentation. Also everything
necessary for creating the printed documentation.
\item[bin] Holds the final binary files.
\item[tcl] Some Tcl helper code.
\item[doc/manager]The SICS managers documentation.
\item[difrac] The DIFRAC four circle diffraction subsystem.
\end{description}
For most programs makefiles are provided.
Makefiles may need a little editing to correct the location of libraries.
All necessary headers should be available in /data/lnslib/include and the
libraries in /data/lnslib/lib.
Building things within this hierarchy basically require to steps:
\begin{enumerate}
\item cd into the hardsup and difrac directories and type make in
each. This builds required libraries for linking other applications.
\item cd into the directory of the program you wish to compile and type make.
For instance for building the SICServer, move into the main sics directory and
type make.
\end{enumerate}
\subsubsection{Building Java Clients}
Again the first step is the untaring of tha java.tar file. This creates a
java subdirectory which holds several other subdirectories:
\begin{description}
\item[focus] contains files special to the FOCUS status display.
\item[lnsutil] a number of utility classes used by many SICs Java applications.
\item[misc] several older classes kept for the purpose of documentation.
\item[param] A package for building parameter displays.
\item[ptplot] A XY-plot package.
\item[sics] The Java command line client.
\item[tablelayout] a special AWT layout manager used in the NeXus network
Data Browser.
\item[varwatch] Files special to the Varwatcher client.
\item[cmapper] A package for mapping 2D-data arrays to colour pictures. Used
for SANS.
\item[htmlv] A html display package used for the help system.
\item[lnet] Special network related utilities for the SICS Java applications.
\item[lnswidgets] custom user interface components.
\item[nndb] The NeXus Network Data Browser.
\item[powder] The powder status display for DMC and HRPT.
\item[sans] The SANS status display.
\item[spread] Another layout manager package.
\item[topsi] The topsi and general scan status display.
\item[amor] The AMOR user interface program.
\end{description}
Furthermore there are some Java source file in the main directory together
with some htm files and makefiles. For each of the Java clients a makefile
is provided: make.focus, make.nndb, make.sans, make.topsi, make.powder,
make.sics, makr.amor and make.watch. The purpose of each makefile can be deduced from
its name. Building the Java clients requires two steps each: 1) compiling and
2) building the jar file. The jar-file is a container file which contains
all the classes necessary for running the application. This is the standard
distribution format for the SICS Java clients. The necessary commands are
using the powder status display as example:
\begin{description}
\item[Compiling] make -f make.powder
\item[Jar-File] make -f make.powder jar
\end{description}
\section{Kernel Objects and Modules}
This section describes the modules defining the SICS kernel.
\include{task}
\include{nserver}
\include{ini}
\include{passwd}
\include{network}
\include{nread}
\include{telnet}
\include{nconman}
\include{costa}
\include{interface}
\include{event}
\include{devexec}
\include{SCinter}
\include{macro}
\include{emonitor}
\include{perfmon}
\include{interrupt}
\include{ofac}
\include{servlog}
\subsection{The commandlog}
This is yet another logging facility of SICS. The idea is that all I/O
going to connections with user or manager level rights is logged.
This allows to figure out what really happened at an instrument. From
this base a scheme was introduced to automatically generate command
log files for each day. Additionally time stamps can be printed into
the commandlog at predefined intervalls. In terms of an external
interface the commandlog just has a few functions for installing and
configuring the commandlog from the interpreter plus a function for
writing to it. The rest is implemented as file statics in commandlog.c.
\section{SICS Core Objects}
This section describes the SICS objects implementing commands and objects
common to all SICS instruments.
\include{scan}
\include{center}
\include{danu}
\include{drive}
\include{alias}
\include{buffer}
\include{ruli}
\include{o2t}
\include{selector}
\include{sicsexit}
\include{status}
\include{cron}
\include{optimise}
\include{token}
\include{udpquieck}
\include{xytable}
\section{SICS Hardware Objects}
This section deals with objects and modules representing instrument
hardware. Please be reminded that a hardware object within SICS
usually consists of two layers:
\begin{itemize}
\item The logical layer building the interface to SICS.
\item The driver layer actually interfacing to the hardware.
\end{itemize}
This allows for the easy adaption to new hardware by exchanging
drivers.
The next thing to note is that most SICS hardware objects implement
at least one of the standard SICS interfaces:
\begin{itemize}
\item The drivable interface
\item The countable interface
\item The environment interface
\item The callback interface.
\end{itemize}
Please note, that there is some history in SICS hardware access. At
first there were no interfaces and objects implemented special
functions for themselves. These are still in the code. Some have their
right as utility functions. However, the preferred and supported way of
accessing SICS hardware objects is through the interface functions.
\include{velo}
\include{velodorn}
\include{evcontroller}
\include{itc4}
\include{bruker}
\include{tclev}
\include{evdrivers}
\include{motor}
\include{pimotor}
\include{counter}
\include{histogram}
\include{sinqhmdriv}
\include{histsim}
\include{choco}
\include{serial}
\include{serialwait}
\include{sps}
\section{Powder Diffraction Specific Objects}
\include{dmc}
\include{nxdata}
\section{SANS specific Objects}
\include{mumo}
\subsection{NXSans}
The files nxsans.h and nxsans.c implement the NeXus writing functions for SANS. Also interpreter commands for configuring SANS data writing into SICS and for triggering data writing are implemented.
\include{sanswave}
\section{FOCUS Specific Objects}
\include{faverage}
\include{fowrite}
\section{AMOR Specific Objects}
\include{amor2t}
\include{amorscan}
\include{amorstat}
\include{nxamor}
\section{Four-Circle Diffraction Specific Objects}
\include{hkl}
\include{hklscan}
\include{integrate}
\include{mesure}
\include{tricsnex}
\include{difrac}
\section{Helper Objects}
This section describes helper objects which implement useful data
structures or utilities.
\include{serialsinq}
\include{varlog}
\include{dynar}
\include{splitter}
\include{obpar}
\include{stringdict}
\include{fupa}
\include{nxsans}
\subsection{Further Helper Code}
Further helper code includes lld.*. This is a general linked list package.
It is documented in lld.h. All credits go to its original author. lld.c has
been modified slightly to resolve a memory problem.
napi.* is the NeXus API. This is documented in a separate document.
nxdict.* is the NeXus dictionary API, which is documented in another
separate document.
strdup.* is a fortified implementation of the standard utility strdup.
strrepl.c is the implmentation of a string replace.
uubuffer.* is a utility function which UUencodes a buffer.
uusend.c is some helper code for sending UUencoded messages.
scaldate.* is an implementation of some julian date conversion
utilities. Is used in commandlog for incrementing date.
circular.* is the implementation of a circular buffer.
\end{document}

45
doc/programmer/ruli.tex Normal file
View File

@@ -0,0 +1,45 @@
\subsection{The R\"unlist}
The R\"unlist is part of the LNS R\"unbuffer system. It is a stack of
r\"unbuffers. When started, the last r\"unbuffer of the stack is executed.
While this is happening it is
possible to modify, delete and add r\"unbuffers to the stack.
The R\"unlist is characterized by the following data structure:
\begin{verbatim}
typedef struct {
pObjectDescriptor pDes;
int iList;
} RuenStack, *pRuenStack;
\end{verbatim}
The fields are:
\begin{description}
\item[pDes] A pointer to the usual SICS object descriptor.
\item[iList] A lld--list of r\"unbuffers.
\end{description}
Interaction with the R\"unlist happens through the interface functions given
below. If not stated otherwise functions return 1 on success, 0 on failure.
Most functions take as first parameter a pointer to a r\"unlist structure.
\begin{description}
\item[pRuenStack CreateRuenStack(void)] creates a new r\"unlist. Returns the
pointer to a new r\"unlist structure on success, NULL on failure.
\item[void DeleteRuenStack(void *self)] deletes a r\"unlist.
\item[int RuenStackAdd(pRuenStack self,pRuenBuffer pVictim)] puts
r\"unbuffer pVictim on top of the r|'unlist.
\item[int RuenStackUnlink(pRuenStack self, int iLine)] removes r\"unbuffer
number iLine from the r\"unlist. This command does NOT delete the
r\"unbuffer.
\item[int RuenStackInsert(pRuenStack self, int iLine, pRuenBuffer pVictim)]
inserts r\"unbuffer pVictim after line iLine into the r\"unlist.
\item[int RuenStackList(pRuenStack self, SConnection *pCon)] list the
contents of the r\"unlist onto the connection pCon.
\item[int RuenStackRun(pRuenStack self,SConnection *pCon, SicsInterp
*pSics)] executes the r\"unlist. Ends when the r\"unlist is empty.
\item[int RuenStackBatch(pRuenStack self,SConnection *pCon, SicsInterp
*pSics)] executes the r\"unlist. If the list is empty RuenStackBatch
continues and checks for new r\"unbuffers being added to the list.
\item[int RuenStackAction(SConnection *pCon, SicsInterp *pSics, void *pData,\\
int argc, char *argv[])] The object wrapper function
for the R\"unlist.
\end{description}

100
doc/programmer/sanswave.tex Normal file
View File

@@ -0,0 +1,100 @@
\subsection{SANS Wavelength Calculation}
The instrument SANS has a neutron velocity selector. A wavelength is
selected by varying tilt angle and rotation speed of the velocity selector.
The relation between tilt angle and rotation speed to wavelength is given by
a formula: \begin{eqnarray}
\lambda & = & A + \frac{B}{rot}\\
\lambda & = & wavelength in nm\\
rot & = & rotation speed in revolutions per minute.
\end{eqnarray}
A and B are coefficients which are calculated from fourth degree polynoms.
The coefficients of these polynoms have been obtained by fitting them
against experimental data. This module now provides for this calculation and
the driving of wavelength. This code does not vary tilt angle.
This object data structure is simple:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$wavedat {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __SANSwave {@\\
\mbox{}\verb@ pObjectDescriptor pDes;@\\
\mbox{}\verb@ pIDrivable pDrivInt;@\\
\mbox{}\verb@ pVelSel pSelector;@\\
\mbox{}\verb@ };@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro never referenced.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
The fields are:
\begin{description}
\item[pDes] The standard SICS object descriptor.
\item[pDrivInt] A standard drivable interface.
\item[pSelector] The velocity selector to act upon.
\end{description}
Most functionality of this module is hidden in the functions comprising the
drivable interface. Thus the external functions of this object are limited
to:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$sanswaveint {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __SANSwave *pSANSWave;@\\
\mbox{}\verb@/*-----------------------------------------------------------------------*/@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int CalculateLambda(float fRot, float fTilt, float *fLambda);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int MakeSANSWave(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int SANSWaveAction(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}
The coefficients for the calculation of A and B are hidden in the module
static function CalculateCoefficients.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
\verb@"sanswave.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*---------------------------------------------------------------------------@\\
\mbox{}\verb@ S A N S W A V E@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Wavelength calculations for a neutron velocity selector. Allows to drive@\\
\mbox{}\verb@ the neutron wavelength directly.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see copyright.h@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, October 1998@\\
\mbox{}\verb@---------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SANSWAVE@\\
\mbox{}\verb@#define SANSWAVE@\\
\mbox{}\verb@@$\langle$sanswaveint {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif @\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

334
doc/programmer/scan.tex Normal file
View File

@@ -0,0 +1,334 @@
\subsection{Scan}
The first version of the scan command was implemented in Tcl. This prooved
to be inefficient. Therefore the main loop for scan was reimplemented in
C. A scan is in principle simple. However some complications are due to the
fact that data files need to be written. Disk files need to be updated after
each scan point. It must be possible to create derivations of the scan
command which create other data formats or scan strategies. This
configurability is catered for the function pointers in the ScanData
structure. Individual functions can be exchanged and thus differently
behaving scans created.
Another complication is, that users might want to interrupt scans and
restart from the last safe position. For this purpose
there exists the recover option.
Scan also uses a scheme for creating scan data data files from a
template. For more information about the template file see the SICS Managers
documentation.
There are currently two schemes for modifying scans: The first works
by implementing different scan handling functions and to assign them
to the function pointers in the ScanData structure. The second works
by defining a macro which will be called at each scan point and which
has to return the a list with the counts and monitors collected.
This has grown to be overly complex. A path for a redesign might
follow the idea of configurable functions to be called at various
steps in scan processing which is already partly implemented.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$scandata {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct {@\\
\mbox{}\verb@ char Name[132];@\\
\mbox{}\verb@ pIDrivable pInter;@\\
\mbox{}\verb@ pDummy pObject;@\\
\mbox{}\verb@ float fStart;@\\
\mbox{}\verb@ float fStep;@\\
\mbox{}\verb@ float *fData;@\\
\mbox{}\verb@ }VarEntry, *pVarEntry;@\\
\mbox{}\verb@/*--------------------------------------------------------------------------*/@\\
\mbox{}\verb@ typedef struct {@\\
\mbox{}\verb@ int i;@\\
\mbox{}\verb@ long lCount;@\\
\mbox{}\verb@ long Monitors[10];@\\
\mbox{}\verb@ float fTime;@\\
\mbox{}\verb@ } CountEntry, *pCountEntry;@\\
\mbox{}\verb@/*---------------------------------------------------------------------------*/ @\\
\mbox{}\verb@ typedef struct __ScanData {@\\
\mbox{}\verb@ pObjectDescriptor pDes;@\\
\mbox{}\verb@ pICallBack pCall;@\\
\mbox{}\verb@ pDynar pScanVar;@\\
\mbox{}\verb@ int iScanVar;@\\
\mbox{}\verb@ int iNP;@\\
\mbox{}\verb@ int iMode;@\\
\mbox{}\verb@ float fPreset;@\\
\mbox{}\verb@ char pFile[1024];@\\
\mbox{}\verb@ char ext[5];@\\
\mbox{}\verb@ FILE *fd;@\\
\mbox{}\verb@ SicsInterp *pSics;@\\
\mbox{}\verb@ SConnection *pCon;@\\
\mbox{}\verb@ char pRecover[1024];@\\
\mbox{}\verb@ char pHeaderFile[1024];@\\
\mbox{}\verb@ int (*WriteHeader)(pScanData self);@\\
\mbox{}\verb@ int (*WriteScanPoints)@\\
\mbox{}\verb@ (pScanData self, @\\
\mbox{}\verb@ int iPoint);@\\
\mbox{}\verb@ int (*ScanDrive)(pScanData self, @\\
\mbox{}\verb@ int i);@\\
\mbox{}\verb@ int (*ScanCount)(pScanData self,@\\
\mbox{}\verb@ int i);@\\
\mbox{}\verb@ int (*CollectScanData)@\\
\mbox{}\verb@ (pScanData self,@\\
\mbox{}\verb@ int iP);@\\
\mbox{}\verb@ long lPos;@\\
\mbox{}\verb@ void *pCounterData;@\\
\mbox{}\verb@ char pCounterName[512];@\\
\mbox{}\verb@ int iChannel;@\\
\mbox{}\verb@ pDynar pCounts;@\\
\mbox{}\verb@ int iCounts;@\\
\mbox{}\verb@ int iActive;@\\
\mbox{}\verb@ int iWindow;@\\
\mbox{}\verb@ char *pCommand;@\\
\mbox{}\verb@ void *pSpecial;@\\
\mbox{}\verb@ } ScanData;@\\
\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 VarEntry structure holds the data for each single scan variable.
These are its name, its object data structures, the start and step
values for the scan and in fData the positions actually reached during
the scan.
The CountEntry structure holds the entries for one counting
operations. These are the lCounts collected, up to 10 monitors and the
time needed for counting. This is the time read from the counter box.
The ScanData datastructure contains the following fields:
\begin{description}
\item[pDes] The standard SICS object descriptor.
\item[pCall] A pointer to the standard SICS callback interface. Scan support
the SCANPOINT message which will be executed after each
scan point.
\item[pScanVar, iScanVar] A dynamic array of VarEntry structures which
define the variables to drive in the scan. iScanVar is the total number of
scan variables. A scan might drive more then one motor or variable.
\item[iNP] is the number of scan points.
\item[iMode] is the counter mode to use.
\item[fPreset] is the preset value for the counter at each scan point. The
exponents set for the counter apply.
\item[pFile] is the name of the data file to write. This will be created
automatically from SICS variables at the start of a scan.
\item[fd] is the file descriptor for the open file when writing. fd will
be opened by WriteHeader and closed again after WriteScanPoints.
\item[pRecover] is the name of the recover file. After each scan point scan
writes some data to file which allows to restart an aborted scan.
\item[pHeaderFile] is the name of a template file which will be used for
generating the scan file header. Its format is simple: Everything except a
few keywords will be copied verbatim. The keywords will be replaced by their
apropriate values. Valid keywords are: !!DATE!! for the current date,
!!VAR(name)!! for the value of a simple Sics variable, !!DRIV(name)!! for a Sics scan
variable. The name of the variable is given in parenthesis.
!!VAR!! and !!DRIV!! can be distinguished easily: Try a run or
drive command on the variable in question. If it works and does not
complain, it is the second sort. The second sort are mostly motors or
collective variables such as lambda etc. Only one value of such a type per
line is permitted.
\item[pSics] a pointer to a SICS interpreter to use while running for
finding data.
\item[pCon] The connection object to use for error reporting during scan
execution.
\item[WriteHeader] is a pointer to a function which writes the header part
of the scan file. Replace this function if another data format is needed.
\item[WriteScanPoints] is a pointer to a function which will be called after
each scan point to write the scan data to the data file. Replace this
function when another data format is needed.
\item[ScanDrive] is executed when the next point of a scan has to be reached.
i is the point of the scan.
\item[ScanCount] is executed when a scan point had been reached and a
counting operation has to be performed. i is the scan point where we are.
This function together with ScanDrive and the data writing functions allow for
customized scans.
\item[CollectScanData] reads all the scan data into the scan's data
structures after any scan point. Overload this if a different storage
scheme is required especiallay for polarising scans.
\item[pCounterData] is a pointer to a counter structure. This defines the
counter to use and is initialized at creation of the scan data structure.
\item[pCountername] is the name of the counter used.
\item[iChannel] is the channel to use for counting. 0 is the main counter,
everything baove one of the monitors.
\item[pCount, iCounts] is a dynamic array containing iCounts sets of
counting infomation. For each scan point this array holds the counts
measured. iCounts is also the current scan position.
\item[iWindow] the width of the window used for peak integration. See
integrate.w,c for more details.
\item[pCommand] It turned out that a way is needed to define user defined
speciality scans. This is implemented by setting the channel number to -10
and then have the scan command execute a Tcl script for each scan point.
This Tcl script has to return a Tcl list containing the values to enter for
counter and monitor for the scan point. pCommand now is the name of the
Tcl procedure to invoke.
\item[pSpecial] Usually NULL. A entry which allows customized scans to keep
some additional data in the scan data structure.
\end{description}
The functional interface to the scan module includes the following
functions:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$scaninter {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*------------------------- live & death ----------------------------------*/@\\
\mbox{}\verb@ pScanData CreateScanObject(char *pRecover, char *pHeader, @\\
\mbox{}\verb@ pCounter pCount);@\\
\mbox{}\verb@ void DeleteScanObject(void *self);@\\
\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
\mbox{}\verb@ int AddScanVar(pScanData self, SicsInterp *pSics, SConnection *pCon, @\\
\mbox{}\verb@ char *name, float fStart, float fStep);@\\
\mbox{}\verb@ int ClearScanVar(pScanData self);@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ int DoScan(pScanData self, int iNP, int iMode, float fPreset,@\\
\mbox{}\verb@ SicsInterp *pSics, SConnection *pCon);@\\
\mbox{}\verb@ int SilentScan(pScanData self, int iNP, int iMode, float fPreset,@\\
\mbox{}\verb@ SicsInterp *pSics, SConnection *pCon);@\\
\mbox{}\verb@ int RecoverScan(pScanData self, SicsInterp *pSics, SConnection *pCon);@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ int GetScanCounts(pScanData self, long *lData, int iDataLen);@\\
\mbox{}\verb@ int GetScanVar(pScanData self, int iWhich, float *fData, int iDataLen);@\\
\mbox{}\verb@ int GetSoftScanVar(pScanData self, int iWhich, float *fData, int iDataLen);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int GetScanVarName(pScanData self, int iWhich, @\\
\mbox{}\verb@ char *pName, int iLength);@\\
\mbox{}\verb@ int GetScanVarStep(pScanData self, int iWhich, @\\
\mbox{}\verb@ float *fStep);@\\
\mbox{}\verb@ int GetScanMonitor(pScanData self, int iWhich, @\\
\mbox{}\verb@ long *lData, int iDataLen);@\\
\mbox{}\verb@ int GetScanNP(pScanData self);@\\
\mbox{}\verb@ float GetScanPreset(pScanData self);@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ int ScanIntegrate(pScanData self, float *fSum, float *fVariance);@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ int SimScan(pScanData self, float fPos, float FHWM, float fHeight);@\\
\mbox{}\verb@ /* @\\
\mbox{}\verb@ creates a simulated gaussian shaped peak with the parameters given.@\\
\mbox{}\verb@ */@\\
\mbox{}\verb@ int ResetScanFunctions(pScanData self);@\\
\mbox{}\verb@ /*@\\
\mbox{}\verb@ resets the configurable scan functions to their default values.@\\
\mbox{}\verb@ */@\\
\mbox{}\verb@@\\
\mbox{}\verb@/*------------------------ Interpreter Interface --------------------------*/@\\
\mbox{}\verb@ int ScanFactory(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int ScanWrapper(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}
All functions take a pointer to a ScanData structure as their first
parameter. The functions:
\begin{description}
\item[CreateScanObject] creates a scan object. The parameters are the
path to a recovery file, the path to a template file for file
generation and a pointer to a counter object.
\item[DeleteScanObject] removes the ScanData structure from memory
properly.
\item[AddScanVar] adds a variable to be scanned. Parameters are the
name of the scan variable, the start and step values for the scan and
a connection object to which errors shall be printed.
\item[ClearScanVar] clears all scan variables.
\item[DoScan] performs the actual scan. Parameters are the number of
points, the counter mode and preset, the connection object for which
the scan is done and the SICS interpreter executing the scan command.
\item[SilentScan] does the same as DoScan but suppresses all output to
data files. This is good for internal scans as in the optimize or
mesure modules.
\item[RecoverScan] loads the data about an aborted scan from the
recovery file and continues to execute it. This most certainly will
not work with custom scans. But is known to work with SICS TOPSI like
standard scans.
\item[GetScanCounts] allows to retrieve the counts collected in the
scan. Max iDatLen entries will be copied into lData.
\item[GetScanVar] retrieves the scan positions for the scan variable
number i. Max iDatLen entries get copied into fData.
\item[GetSoftScanVar] retrieves the scan positions for the scan variable
number i. The soft positions are retrieved, not the hard position stored
during the scan.
\item[GetScanVarName] retrieves the name of scan variable i.
\item[GetScanVarStep] gets the step of the scan variable i.
\item[GetScanMonitor] allows to retrieve the monitor counts collected
in monitor i during the
scan. Max iDatLen entries will be copied into lData.
\item[GetScanNP] returns the number of points in the scan.
\item[GetScanPreset] returns the counter preset value for the scan.
\item[ScanIntegrate] integrates the peak after a scan. Returns the
summed counts and the variance. See the section on integrate for more
details.
\item[ResetScanFunctions] reinstalls the default functions for scan
processing into the ScanData structure.
\item[SimScan] creates a simulated gaussian peak with the given
parameters. Used for debugging several things.
\item[ScanFactory] is the SICS interpreter object creation function
for the scan object.
\item[ScanWrapper] is the SICS interpreter object function for
interacting with the scan module.
\end{description}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
\verb@"scan.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*---------------------------------------------------------------------------@\\
\mbox{}\verb@ S C A N@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Header file for the SICS scan object.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, October 1997@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see copyright.h@\\
\mbox{}\verb@-----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSSCAN1@\\
\mbox{}\verb@#define SICSSCAN1@\\
\mbox{}\verb@ typedef struct __ScanData *pScanData;@\\
\mbox{}\verb@/*--------------------------------------------------------------------------*/@\\
\mbox{}\verb@#include "counter.h"@\\
\mbox{}\verb@@$\langle$scaninter {\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@"scan.i"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------@\\
\mbox{}\verb@ Internal header file holding the definition of the scan objects data@\\
\mbox{}\verb@ structure.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, October 1997@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#include "sdynar.h"@\\
\mbox{}\verb@@$\langle$scandata {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

131
doc/programmer/selector.tex Normal file
View File

@@ -0,0 +1,131 @@
\subsection{Monochromators}
The code in these modules support standard crystal monochromators. The code
is divided into two groups: There is the selector module which does most of
the monochromator handling. And there are selvars, virtual motors which
allow to drive the wavelength or the energy (for those triple axis guys)
directly via the drive command. The monochromator module does not only
adjust theta and two theta for the monochromator but also horizontal and
vertical benders. The formula used for calculating the bending radius is: $b
= C1 + \frac{C2}{sin(Theta)}$. This object is implemented in the
files selector.h and selector.c.
As the configuration parameters of this object include the scattering
sense, ss, it is also suitable for running the analyzer of a triple
axis instrument.
\subsubsection{The Selector Device}
The monochromator is described by the following data structure:
\begin{verbatim}
typedef struct __SicsSelector {
ObjectDescriptor *pDes;
ObPar *pParams;
char *name;
pMotor pTheta;
pMotor pTwoTheta;
pMotor pBend1;
pMotor pBend2;
char *pType;
} SicsSelector;
\end{verbatim}
The fields:
\begin{description}
\item[pDes] A pointer to the usual SICS object descriptor.
\item[pParams] A pointer to a SICS parameter array (see helper modules for
more details).
\item[name] The name of the monochromator.
\item[pTheta] A pointer to the data structure for the Theta motor.
\item[pTwoTheta] A pointer to the data structure for the Two Theta motor.
\item[pBend1] A pointer to the data structure for the first bender motor.
\item[pBend2] A pointer to the data structure for the second bender motor.
\end{description}
Please note, that troughout the code the bender motors are handled as
optional.
The monochromator can be accessed with the following functions:
\begin{description}
\item[pSicsSelector CreateSelector(char *name, pMotor pTheta, pMotor pTwoTheta,\\
pMotor pBend1, pMotor pBend2)]
creates a new monochromator name with motors. The bender motors are
optional, theta and two theta are required. Returns a pointer to a new
monochromator data structure on success or NULL on failure.
\item[int MonoInit(SConnection *pCon,SicsInterp *pSics, void *pData, \\
int argc, char *argv[])] The monochromator factory function.
\item[void DeleteSelector(void *self)] deletes a monochromator.
\item[int MonoAction(SConnection *pCon, SicsInterp *pSics, void *pData,\\
int argc, char *argv[])] The object wrapper function for
the monochromator.
\item[int MonoRun(pSicsSelector self, SConnection *pCon, float fWaveLength)]
starts the selector to run to wavelength fWaveLength. Does not wait for
finish. Eventual error messages are sent to pCon.
\item[int MonoLimits(pSicsSelector self, float fWaveLength, char *error, \\
int iErrLen)] checks if fWaveLength violates any motor
limits. If so maximum iErrLen characters of description are copied to error.
\item[int MonoCheck(pSicsSelector self, SConnection *pCon)] does a status
check on all the monochromator motors. The result is the worst of the
motor status codes as returned from the motors.
\item[int MonoHalt(pSicsSelector self)] emergency halts the monochromator.
\item[float GetMonoPosition(pSicsSelector self, SConnection *pCon)] get the
current wavelength of the monochromator. Possible errors are rported to
pcon. On error this function returns -999, else the current wavelength is
returned.
\item[char *MonoGetType(pSicsSelector self)] gets the type of the
monochromator.
\item[int GetMonoPositions(pSicsSelector self, SConnection *pCon, \\
float *fTheta, float *fTwtTh, float *fB1, float
*fB2)] gets the positions for all the monochromators motors.
\end{description}
\subsubsection{The Monochromator Virtual Motors}
This module implements the wavelength or energy variable to act upon a
monochromator. Both types are represented by a special data structure:
\begin{verbatim}
typedef struct __SelVar {
pObjectDescriptor pDes;
pSicsSelector pSel;
pIDrivable pDrivInt;
float fValue;
char *name;
} SelVar;
\end{verbatim}
The fields:
\begin{description}
\item[pDes] A pointer to the usual SICS object descriptor.
\item[pSel] A pointer to the monochromator object to use for adjusting.
\item[pDrivInt] A pointer to the drivable interface implemented.
\item[fValue] The current value of the variable.
\item[name] The name of the virtual motor.
\end{description}
Most of the action for these variables is hidden in the drivable interface.
This is also where the conversions between energy and wavelength are done.
Consequently the interface to this module consists mostly of creation and
deletion functions:
\begin{description}
\item[pSelVar CreateWLVar(char *name, pSicsSelector pSel)] creates a
wavelength variable.
\item[pSelVar CreateEnergy(char *name, pSicsSelector pSel)] creates an
energy variable for monochromator pSel Both functions return NULL on failure
and a pointer to a selector variable data structure in case of success.
\item[void DeleteSelVar(void *pSelf)] deletes a selector variable.
\item[int MakeWaveLengthVar(SConnection *pCon, SicsInterp *pSics, void *pData,\\
int argc, char *argv[])] factory function for a
wavelength variable.
\item[int MakeEnergyVar(SConnection *pCon, SicsInterp *pSics, void *pData,\\
int argc, char *argv[])] factory function for a energy
variable.
\item[float GetSelValue(pSelVar self, SConnection *pCon)] retrieves the
current value of the variable. In case of errors -999 is returned and error
messages are printed to pCon.
\item[int WaveLengthAction(SConnection *pCon, SicsInterp *pSics, void *pData,\\
int argc, char *argv[])] The object wrapper function
for a wavelength variable.
\item[int EnergyAction(SConnection *pCon, SicsInterp *pSics, void *pData,\\
int argc, char *argv[])] The object wrapper function
for a energy variable.
\end{description}
Please note, that most of the important variables for handling a
monochromator reside with the monochromator object and not with the virtual
motors.

37
doc/programmer/serial.tex Normal file
View File

@@ -0,0 +1,37 @@
\subsection{Serial Connections}
This object allows to send arbitrary strings to a serial port in the SINQ
hardware setup system. This means a message is packaged and forwarded to to
the Macintosh serving the port. And data is read back again from there. This
facility has been devised in order to write environment device drivers in
the macro language and as help for SICS instrument managers.
In contrast to the many SICS objects this object is defined for the Tcl
interpreter. This is because it is in use within the psish Tcl interpreter
as well. There is only one function, SerialInit, which adds the serial
command to the SICS interpreter.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
\verb@"serial.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------@\\
\mbox{}\verb@ S I C S S E R I A L@\\
\mbox{}\verb@@\\
\mbox{}\verb@ This object adds the serial command to the Tcl-interpreter within SICS.@\\
\mbox{}\verb@ Furthermore the commands sr1-sr6 are added as predefined names for @\\
\mbox{}\verb@ possible connections. @\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, January 1998@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSERIAL@\\
\mbox{}\verb@#define SICSERIAL@\\
\mbox{}\verb@ int SerialInit(SConnection *pCon,SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

View File

@@ -0,0 +1,168 @@
\subsection{Command Forwarding Through the Serial Line}
This is a set of utility routines which transport commands and
responses to and from a serial port connected to a Macintosh terminal
server. This is derived from the
routines provided by David Maden for the EL734 motor controller. This
utility is used by many of the SICS drivers. These
functions are implemented in sinqserial.*. The following functions are
defined:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$ss {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ int SerialOpen(void **pData, char *pHost, int iPort, int iChannel);@\\
\mbox{}\verb@ int SerialForceOpen(void **pData, char *pHost, int iPort, int iChannel);@\\
\mbox{}\verb@ int SerialConfig(void **pData, int iTmo);@\\
\mbox{}\verb@ int SerialGetTmo(void **pData);@\\
\mbox{}\verb@ int SerialATerm(void **pData, char *pTerm);@\\
\mbox{}\verb@ int SerialAGetTerm(void **pData, char *pTerm, int iTermLen);@\\
\mbox{}\verb@ int SerialSendTerm(void **pData, char *pTerm);@\\
\mbox{}\verb@ int SerialGetSocket(void **pData);@\\
\mbox{}\verb@ int SerialClose(void **pData);@\\
\mbox{}\verb@ int SerialSend(void **pData, char *pCommand);@\\
\mbox{}\verb@ int SerialReceive(void **pData, char *pBuffer, int iBufLen);@\\
\mbox{}\verb@ int SerialError(int iError, char *pError, int iErrLen);@\\
\mbox{}\verb@ int SerialWriteRead(void **pData, char *pCommand, @\\
\mbox{}\verb@ char *pBuffer, int iBufLen); @\\
\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}
Each of these functions returns 1 on success or a negative value on the
likely event of an error. These negative values double as error codes.
These error codes can be translated into text with SerialError.
{\bf SerialOpen} opens a connection to a RS--232 at the computer pHost. The
terminal server is leistening at port iPort and the serial line is
iChannel. pData is a void pointer. It will be initialized with a data
structure holding internal connection information. This pointer must be
passed along with each of the other functions.
{\bf SerialNewOpen} is a second form of SerialOpen. The difference is in
connection management. SerialOpen uses an existing network connection to the
Macintosh, if existing. Thus data transfer is shared between many devices.
This is fine as long as the devices reply to messages quick enough. But a
slow device may block all communication.
SerialNewOpen forces a new socket to be opened. Thereby a new thread is
started in the Macintosh serial port server and devices get decoupled.
This scheme is recommended for devices which reply slowly to RS--232
requests.
{\bf SerialConfig} configure the timeout to iTmo. This is the timeout the
terminal server waits for commands to appear. pData is
the pointer as initialized by SerialOpen.
{\bf GetSerialTmo} returns the currently valid timeout value.
{\bf SerialATerm} sets the expected string terminator to pTerm.
{\bf SerialAGetTerm} copies maximum iTermLen characters of teminator
information to pTerm.
{\bf SerialSendTerm} sets the default terminator to send after each command.
{\bf SerialClose} closes the connection to the RS--232 connection. pData is
the pointer as initialized by SerialOpen.
{\bf SerialSend} sends pCommand onto the serial connection. pData is
the pointer as initialized by SerialOpen. Please note, that this command
clears the receive buffer at the terminal server. This means any answers
pending from prior commands are deleted. This function can send only one
single command. The Dornier velocity selector cannot handle more, anyway.
{\bf SerialReceive} reads from the RS--232 connection into the buffer
pBuffer, but maximum iBufLen characters. This version check with select for
pending data and returns NODATA if nothing is available. pData is
the pointer as initialized by SerialOpen.
{\bf SerialError} translates any of the negative error codes into a readable
form. The error code is iError. Maximum iErrLen characters of text will
be copied to pError. pData is
the pointer as initialized by SerialOpen.
{\bf SerialWriteRead} writes the command pCommand to the port and tries
to read a reply during the timeout period. Maximum iBufLen characters of
answer will be copied to pBuffer. This function return a positive value
on success or a negative error code. In case of an error pBuffer will
be filled with an error message instead.
SerialWriteRead loops on SerialReceive until data becomes available. But
only for the maximum period specified as time out. In this loop
SerialWriteRead calls a function which waits some time. By default this
function maps to the system function sleep. However, an application might
choose to specify another function instead. For instance a yield in a
window system or a SicsWait in a SICS system. This feature may allow an
application to do further processing while waiting for data to appear
at a serial line. In order to do this the
following typedef and function are necessary.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$sf {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef int (*SerialSleep)(void *pData, int iTime);@\\
\mbox{}\verb@ void SetSerialSleep(void **pData, SerialSleep pFunc, void *pUserData);@\\
\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 sleep function must take two parameters: A void pointer described below
and an integer time value to waist.
{\bf SetSerialSleep} takes a pointer as returned by SetialOpen as first
parameter. The second parameter is the sleep function. The third parameter
is a pointer to an application defined data structure which will be passed
on as first parameter to the sleep function by the system.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
\verb@"serialsinq.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*----------------------------------------------------------------------------@\\
\mbox{}\verb@ S E R I A L S I N Q@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Utility functions for maintaining a connection to a RS--232 port on a@\\
\mbox{}\verb@ Macintosh computer running the SINQ terminal server application.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, Juli 1997@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see implementation file@\\
\mbox{}\verb@------------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SERIALSINQ@\\
\mbox{}\verb@#define SERIALSINQ@\\
\mbox{}\verb@#define NOREPLY -100@\\
\mbox{}\verb@#define NOCONNECTION -121@\\
\mbox{}\verb@#define SELECTFAIL -120@\\
\mbox{}\verb@#define TIMEOUT -130@\\
\mbox{}\verb@#define INTERRUPTED -132;@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\langle$ss {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@/*-------------------------- The sleeperette -----------------------------*/@\\
\mbox{}\verb@@$\langle$sf {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

View File

@@ -0,0 +1,64 @@
\subsection{Serial Wait}
This module is a very SINQ specific function. At SINQ, serial devices are
controlled through a serial port server program running on a Macintosh PC.
This program blocks, if the serial device is very slow. This blocks the
Macintosh as well as the SICS server. This module solves this problem. It
does so using the following logic:
The command to execute is sent with a zero timeout.
A special sics task, the SerialPoller, is started to monitor the device.
The routine issuing the command waits for the SerialPoller to finish. If
somebody issues new commands while this is going on, an error must be
returned.
The SerialPoller sends commands of zero length and with a zero timeout to
the Macintosh. Usually the reply will be a ?TMO because no data is
available. If data becomes available, two situations have to be handled:
In the first case all data was read including the terminator. Then a reply
without a ?TMO will be returned. If there is a slight delay in getting all
the data, a ?TMO followed by data bytes is returned. In that case the data
has to be appended to the data buffer. Then a null command with a sensible
timeout is sent. If a new timeout comes in on that onew, there is an error.
Else the data is appended to the data already read and we are finished.
It has been choosen to implement this logic separatly from the serialsinq
stuff as it interacts very much with rest of SICS.
Just one function is exported:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
\verb@"serialwait.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------@\\
\mbox{}\verb@ S E R I A L W A I T@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Executes a command on a serial port and waits for replies coming@\\
\mbox{}\verb@ along by polling with null commands.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see copyright.h@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, June 1998@\\
\mbox{}\verb@---------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SERIALSICSWAIT@\\
\mbox{}\verb@#define SERIALSICSWAIT@\\
\mbox{}\verb@#include "sics.h"@\\
\mbox{}\verb@#include "hardsup/serialsinq.h"@\\
\mbox{}\verb@ int SerialSicsExecute(void **pData, char *pCommand, char *pReply, @\\
\mbox{}\verb@ int iBufLen);@\\
\mbox{}\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
Parameters and return values are the same as defined for the
SerialWriteRead function.
I am not sure if this facility works as expected. I think there was a
problem with crosstalk on the serial line.

View File

@@ -0,0 +1,22 @@
\subsection{The Server Logfile}
The SIVS server maintains a server log file. In this log file, all commands
and answers are written as well as diagnostic messages from all parts of the
system.In order to prevent the log files from growing to endless sizes they
are limited in length. When one file is finished the next file is written.
This happend for a predefined number of files. Then the first file is
reused. This scheme is configured by defines in servlog.c.
The interface to this module is simple:
\begin{description}
\item[void SICSLogWrite(char *ptext, OutCode eOut )] writes text with
outcode eOut to the server log. The outcodes are the same as used for
outpout through SCWrite in conman.h.
\item[int LogCapture(SConnection *pCon, SicsInterp *pInter, void *pData,
int argc, char *argv[])]
Wrapper function which allows the connection pCon to redirect output to the
server log file to its socket. For details see the user documentation.
\item[int KillCapture(SConnection *pCon)] This function is automatically
called when a connection object dies. It releases all LogCapture entries for
the connection.
\end{description}

View File

@@ -0,0 +1,8 @@
\subsection{SicsExit}
For closing down the SICS server properly.
\begin{verbatim}
int SicsExit(SConnection *pCon,SicsInterp *pInterp, void *pData, int argc,
char *argv[]);
\end{verbatim}
Just the object wrapper function implementing the command. Does so by
sending a signal to all tasks in the task loop.

View File

@@ -0,0 +1,107 @@
\subsubsection{SINQ Histogram memory}
This is a driver for the SINQ developed histogram memory. This HM can
operate in normal, TOF and stroboscopic mode. All the real time processing
for this HM is done by an on-board computer in a VME crate. This on board
computer also runs TCP/IP and a server program which allows for
configuration and communication with the HM. A tricky bit is, that
configuration and communication operate differently. For configuration an
connection to the main server is installed which handles the configuration
requests. For starting data collection and retrieval of information a second
connection is needed. This is obtained by sending a request to the main
server on the on board computer. This main server will than spawn a second
process on the on board computer which is dedicated to serving our requests.
The mainserver sends a packet containing the new port number our secondary
server is listening to. Than the driver can connect to this secondary server
in order to exchange data. More details on this scheme can be found in the
manual for the SINQ-histogram memory. A further complication arises from the
fact that the actual counting control, such as monitor handling, starting
and stopping etc. is handled via a EL737 counter box, which needs to be kept
track off as well. All this results in a rather complicated driver. This is
already reflected by the driver private data structure:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$SQType {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __SinqHMDriv {@\\
\mbox{}\verb@ pCounter pCounter;@\\
\mbox{}\verb@ pSINQHM pMaster;@\\
\mbox{}\verb@ int iLastHMError;@\\
\mbox{}\verb@ int iLastCTError;@\\
\mbox{}\verb@ } SinqHMDriv;@\\
\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}
pCounter is a pointer to the EL737 counter box to use for count control.
pMaster is an internal data structure for the interface functions to the
SINQ histogram memory. iLastHMError keeps the last histogram memory error,
iLasyCTError is set to 1 when a counter error happened. This is necessary to
implement the GetError function.
Please note that this driver needs some options in the histogram memories
database:
\begin{itemize}
\item Control must have as value a configured EL737 counter box.
\item HMComputer is the name of the histogram memory computer.
\item HMPort is the port on which the histogram memory computer listens for
requests.
\end{itemize}
The driver implements all the functions specified in the driver interface.
Please note that these contain functions for the deletion of driver private
data structures which will be automatically called form DeleteHistDriver.
Therefore the only function to define is CreateSINQDriver which sets things
up.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$Protos {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ pHistDriver CreateSINQDriver(pStringDict pOption);@\\
\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@"sinqhmdriv.i"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------@\\
\mbox{}\verb@ S I N Q H M @\\
\mbox{}\verb@@\\
\mbox{}\verb@ A driver for the SINQ histogram memory.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, April 1997@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see implementation file@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SINQHMDRIVER@\\
\mbox{}\verb@#define SINQHMDRIVER@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\langle$SQType {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
\mbox{}\verb@@$\langle$Protos {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

View File

@@ -0,0 +1,40 @@
\subsection{The Splitter-Tokenizer}
SICS needs some command interpretation for its job. In order to facilitate this a few functions have been devised which decompose a line into its words and figures out if the words are text or numerical values. The words are than put into an ordered linked list which can be scanned by client programs. The interface:
\begin{verbatim}
typedef enum {eText, eInt, eFloat, eUndefined } eType;
\end{verbatim}
The Types a word can have.
\begin{verbatim}
typedef struct _TokenEntry {
eType Type;
char *text;
long iVal;
float fVal;
struct _TokenEntry *pNext;
struct _TokenEntry *pPrevious;
} TokenList;
\end{verbatim}
This is the data structure available for each word. This is kept in a doubly linked list as SICS might require to splice a parameter into a given command (i.e a pointer to a connection class).
The interface functions:\begin{itemize}
\item {\bf TokenList *SplitText(char *pLine) }, splits a given text into words. Returns a pointer to the head of the list on success, NULL on failure.
\item {\bf TokenList *SplitArguments(int argc, char *argv) }, does the same as above for a argc, argv type pairs.
\item {\bf Text2Arg(char *text, int argc, cahr *argv) } decomposes a text string into argc, argv paisr as used in command invocation.
\item {\bf void DeleteTokenList(TokenList *pList) }. A client uses this
to remove the word list when it is done with it. Omission of this call will result in wasted memory.
\item {\bf int Text2Arg(char *line, int *argc, char **argv[])} This call
converts the text in line into an argc, argv[] pair. Suitable space in
memory will be allocated. It is the callers responsability to free the
argv[] array after use.
\item {\bf int Arg2Text(int argc, char *argv[], char *buf, int iBufLen)}
This call converts an argc, argv[] pair back into a text. Maximum iBufLen
characters of result will be copied to buf.
\item {\bf int GetShellLine(FILE *fd, char *buf, int iBufLen);} reads a line
from file fd. Thereby ignoring lines starting with \verb+#+.
\end{itemize}

198
doc/programmer/sps.tex Normal file
View File

@@ -0,0 +1,198 @@
\subsection{SPS Controllers}
This module is very specific to SINQ. At SINQ there are Siemens SPS
controllers which are used to put beam components in, lift air cushions etc.
Essentially these are push button devices. There exists a protocoll for
pushing buttons through a RS--232 interface. This protocoll is described
elsewhere.
These obscure SPS devices support three types of functionalities:
\begin{itemize}
\item Bits may be flipped. This correcponds to pushing a button. There are
12b bytes of those with 8 bits each.
\item Status bits may be read. This allows to figure out if an operation
succeeded. 128 status bits are available.
\item Furthermore this thing has up to 8 ADC inputs. These can be read as
well.
\end{itemize}
This module implements a means to communicate with SPS devices. It will
support the three functionalities in the list above. This is more a module
providing a basic functionality. In practice this will and should be wrapped
into Tcl wrapper functions. This is the best solution because bit
assignements vary between instruments and tend to change all the time. Or at
least seem to, as the electricians don't talk to us. As this is no general
device the usual SICS division between hardware object and hardware driver
will not be upheld.
There is a problem with pushing buttons. Not all buttons may be pushed
remotely, for instance it may not be permitted to operate the beam shutter
remotely. Not all of the bits in the SPS actually correspond to a pressable
button but are set as consequence of a pushed button. In order to run all
this a permission list must be configured for each SPS controller. This list
holds the adress of the bit and the privelege required to operate this
button. If a bit is not in the list permission is automatically not given to
operate it. Each entry in this permission list looks like this:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$permlist {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct {@\\
\mbox{}\verb@ int iByte;@\\
\mbox{}\verb@ int iBit;@\\
\mbox{}\verb@ int iPrivilege;@\\
\mbox{}\verb@ }Permission, *pPermission;@\\
\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 fields are: the byte we refer to, the bit in the byte and the Privilege
required to operate this switch. Entries of this kind will be held in a
standard linked list.
In order to run the SPS, the following data strucure is required:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$spsdata {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __SPS {@\\
\mbox{}\verb@ pObjectDescriptor pDes;@\\
\mbox{}\verb@ int iMode;@\\
\mbox{}\verb@ int iLastError;@\\
\mbox{}\verb@ char *pHost;@\\
\mbox{}\verb@ int iPort;@\\
\mbox{}\verb@ int iChannel;@\\
\mbox{}\verb@ int lPermissions;@\\
\mbox{}\verb@ void *pData;@\\
\mbox{}\verb@ } SPS;@\\
\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 fields are:
\begin{description}
\item[pDes] The SICS standard object descriptor.
\item[iMode] The SPS can be operated in simulation mode for software
testing. This flag denotes that.
\item[iLastError] an integer code representing the last error, if any.
\item[pHost] The Macintosh computer running the serial port server.
\item[iPort] The TCP/IP port number where the Macintosh serial port server
is listening.
\item[iChannel] The serial port ID to which the SPS controller is connected
to.
\item[lPermissions] The linked list where the permissions are stored.
\item[pData] The private data structure for serial communication with the
SPS.
\end{description}
The external interface to this module looks like this:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
$\langle$spshead {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __SPS *pSPS;@\\
\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
\mbox{}\verb@ int SPSSetButton(pSPS self, SConnection *pCon, int iByte, int iBit);@\\
\mbox{}\verb@ int SPSGetStatus(pSPS self, int iStatus, int *iSet);@\\
\mbox{}\verb@ int SPSGetSANS(pSPS self, float *fVal);@\\
\mbox{}\verb@ int SPSGetADC(pSPS self, int iWhich, int *iValue);@\\
\mbox{}\verb@ void SPSAddPermission(pSPS self, int iByte, int iBit, int iRight);@\\
\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
\mbox{}\verb@ int SPSFactory(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int SPSAction(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}
The functions and their meaning are described below. All function return 1
on success and 0 on failure.
\begin{description}
\item[SPSSetButton] Tries to set the button described by iByte and iBit.
pCon is needed to determine user rights associated with the request. Please note that a
successful return from this function means that the button has been pressed
but not that the SPS has successfully completed the requested action. In
order to check for that you have to check the associated status bit.
\item[SPSGetStatus] Requests the value of the status bit iStatus. iSet will
be set to 1 if the bit is set or 0 if not.
\item[SPSGetSANS] is a special function for reading the collimation
length from the SANS collimator SPS controller. This requires checking tons
of bits. For efficiency this has been put into a separate function.
\item[SPSGetADC] requests the value of the ADC channel iWhich. The value is
returned in iValue. Please note that this is probably a meaningless integer
value which has to be converted to a physically meaningful value.
\item[SPSFactory] is the interpreter factory function which will be used to
create command in the interpreter representing SPS controllers.
\item[SPSAction] implements the actual commands in the SICS interpreter for
interacting with the SPS controller.
\end{description}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap4}
\verb@"sps.i"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------@\\
\mbox{}\verb@ SPS Controller module internal header file. Do not include. Leave @\\
\mbox{}\verb@ alone. Is automatically created from another file.@\\
\mbox{}\verb@---------------------------------------------------------------------------*/@\\
\mbox{}\verb@@$\langle$permlist {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\langle$spsdata {\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@"sps.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*------------------------------------------------------------------------@\\
\mbox{}\verb@ S P S@\\
\mbox{}\verb@@\\
\mbox{}\verb@ A module to handle Siemens SPS controllers at SINQ. For more information @\\
\mbox{}\verb@ see sps.tex@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, Juli 1998@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSSPS@\\
\mbox{}\verb@#define SICSSPS@\\
\mbox{}\verb@@$\langle$spshead {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

42
doc/programmer/status.tex Normal file
View File

@@ -0,0 +1,42 @@
\subsection{The Status Object}
Again a simple thing which maintains a string describinh what the SICSserver
is up to. The codes recognized are:
\begin{description}
\item[eEager] ready to execute commands.
\item[eUserWait] user requested wait.
\item[eCounting] counting something.
\item[eOutOfBeam] there is no beam.
\item[ePaused] paused.
\item[eDriving] driving bits around.
\item[eRunning] moving somewhere.
\item[eScanning] doing a scan.
\item[eBatch] processing a batch file.
\item[eHalted] halt has been called, not used.
\item[eDead] server is dead, not used.
\item[eInput] waiting for user input in prompting mode.
\end{description}
Status can be interfaced with:
\begin{description}
\item[void SetStatus(Status eNew)] sets a new status.
\item[int SetStatusFromText(char *text)] sets a new status from text.
\item[void KillStatus(void *pData)] deletes status data structures. Status
can have callbacks associated with it, these need to be remved by this
function.
\item[Status GetStatus(void)] retrives the current status.
\item[void GetStatusText(char *buf, int iBufLen)] retrieves the status as text.
\item[int UserStatus(SConnection *pCon, SicsInterp *pSics, void *pData,\\
int argc, char *argv[])] The object wrapper function for
the status object.
\item[int ResetStatus(SConnection *pCon, SicsInterp *pSics, void *pData,\\
int argc, char *argv[])] The wrapper function
implementing the reset command.
\item[int BackupStatus(SConnection *pCon, SicsInterp *pSics, void *pData,\\
int argc, char *argv[])] is the object wrapper function
implementing the backup command which saves the server status into a file.
This is all of the server. This function does not really belong here.
\item[int RestoreStatus(SConnection *pCon, SicsInterp *pSics, void *pData,\\
int argc, char *argv[])] complement to BackupStatus. Reads
SICS server status back from file.
\end{description}

View File

@@ -0,0 +1,91 @@
\subsection{Dictionary}
This is just a simple implementation of an dictionary of name value strings
on top of the LLD linked list package. It is needed in the histogram memory
module and several other places. This module provides the following functions:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$Protos {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ pStringDict CreateStringDict(void);@\\
\mbox{}\verb@ void DeleteStringDict(pStringDict self);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int StringDictAddPair(pStringDict self, char *name, char *value);@\\
\mbox{}\verb@ int StringDictExists(pStringDict self, char *name);@\\
\mbox{}\verb@ int StringDictUpdate(pStringDict self, char *name, char *value);@\\
\mbox{}\verb@ int StringDictGet(pStringDict self, char *name, char *pResult, int iLen);@\\
\mbox{}\verb@ int StringDictGetAsNumber(pStringDict self, char *name, float *fVal);@\\
\mbox{}\verb@ int StringDictDelete(pStringDict self, char *name);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ const char *StringDictGetNext(pStringDict self, @\\
\mbox{}\verb@ char *pValue, int iValLen);@\\
\mbox{}\verb@ void StringDictKillScan(pStringDict 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}
As usual, all function return 1 on success, 0 if there is a problem.
CreateStringDict creates and initialises a new string dictionanry.
DeleteStringDict deletes the whole dictionary and all ist values from
memory. self will point to rubbish afterwards.
StringDictAddPair adds a new name value pair to the dictionary.
StringDictExists test for the existence of name in the Dictionary.
StringDictUpdate replaces the value for name with the new one specified.
StringDictGet copies the value for name into the string pResult, but maximum
iLen characters. If pResult is NULL, this function returns the length of the
value string.
StringDictDelete deletes the entry for name from the dictionary.
StringDictGetNext implements a scan through the whole dictionary. It returns
a pointer to the current key or NULL if the dictionary is exhausted.
Maximum iValLen characters of value information will be copied into pValue.
NEVER, ever delete the pointer passed from StringDictGetNext. A core dump
will be your reward. Please note, that each call to the usual search
functions will mess up a dictionary traversal.
StringDictKillScan clears the scan flag in a way that a new one is done
with the next call to StringDictGetNext.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
\verb@"stringdict.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------@\\
\mbox{}\verb@ S T R I N G D I C T@\\
\mbox{}\verb@@\\
\mbox{}\verb@ A module which implements a general purpose string dictionary.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see implementation file@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, April 1997@\\
\mbox{}\verb@---------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSSTRINGDICT@\\
\mbox{}\verb@#define SICSSTRINGDICT@\\
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __StringDict *pStringDict;@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\langle$Protos {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

135
doc/programmer/task.tex Normal file
View File

@@ -0,0 +1,135 @@
\subsection{The Task Switcher}
This is a portable task switching module. It effectively implments a form of
cooperative multitasking. A task in this context is a function of type
TaskFunc which defines the task. The task function looks like this: \\
\centerline{int (*TaskFunc)(void *pData)}\\
pData is a pointer to a user defined data structure which should contain the
data the task is going to need in order to do its job. This function returns
1 if it shall continue, or 0 if it is finally ended and should be deleted from
the list of tasks. Please note, that the whole task switcher is blocked when
a task executes a very lengthy operation. In such cases a task function
should call either TaksWait or TaskYield at apropriate
places in the code in order to give other tasks a chance to execute.
This module now keeps a list of such tasks and calls the task functions one
after another. Actually, the tasks are kept in a special data structure in a
doubly linked list. When the end of this list has been reached, the code
jumps to the list head automatically. The data structure for each task looks
like this:
\begin{verbatim}
typedef struct __TaskHead {
long lID;
int iStatus;
long lWait;
TaskFunc pRun;
SignalFunc pSignal;
void *pData;
TaskKillFunc pKill;
pTaskHead pNext;
pTaskHead pPrevious;
} TaskHead;
\end{verbatim}
The fields have the following meanings: \begin{description}
\item[lID] A unique task ID.
\item[iStatus] is a status flag. A task can be READY or WAITING for another task
to finish.
\item[lWait] If the task is in wait state, lWait denotes the task ID to wait
for.
\item[pRun] is the tasks task function.
\item[pSignal] is the tasks signal function. This implements some form of
inter task communication. A signal function looks like this:\\
\centerline{typedef void (*SignalFunc)(void *pUser,int iSignal, void
*pSigData);}\\
pUser is a pointer to the task data structure, iSignal is the ID of a signal
sent. It is the applications job to define these signal codes. pSigData is a
pointer to a signal data structure. Again it is the applications job to
define this data structure for each signal.
\item[pData] is the tasks data structure. It will be passed into each call
to the task and signal function.
\item[pKill] is a pointer to a function capable of deleting the task data
structure. This function will be automatically called when the task ends.
\item[pNext, pPrevious] are pointers which maintain the doubly linked list
of tasks.
\end{description}
The other data structure used in the task switching module is the task
managers data structure. It looks like this:
\begin{verbatim}
typedef struct __TaskMan {
int iID;
int iStop;
pTaskHead pCurrent;
pTaskHead pHead;
} TaskMan;
\end{verbatim}
The fields:
\begin{description}
\item[iID] a ID to characterize the task manager data structure. Will be
used to test if this structure has been corrupted or the user passed in
some shit.
\item[iStop] is used for stopping the task switcher.
\item[pCurrent] denotes the current task executing.
\item[pHead] define the head of the task list.
\end{description}
In order to use this module it is needed to provide these items for each
task:\begin{itemize}
\item A task data structure.
\item A data structure removal function if applicable.
\item A task function.
\item A signal function, if the task is going to react on signals.
\end{itemize}
Interaction with the task switching module happens through the functions
defined below. All functions return 0 on failure and 1 on success if not
sated otherwise. For encapsulation, the following pointers are defined:
\begin{verbatim}
typedef struct __TaskHead *pTaskHead;
typedef struct __TaskMan *pTaskMan;
\end{verbatim}
\begin{description}
\item[int TaskerInit(pTaskMan *self)]
Initalises a Task Manager.
\item[int TaskerDelete(pTaskMan *self)]
Stops all running tasks and clears all data structures associated with
tasks and the TaskManager.
\item[long TaskRegister(pTaskMan self, TaskFunc pTaskRun,
SignalFunc pSignalFunc, \\
TaskKillFunc pKillFunc,
void *pData,
int iPriority)]
This call enter a new task into the system. The caller has to
specify:
\begin{itemize}
\item a TaskFunction [Required]
\item a SignalFunction [Optional, can be NULL]
\item a KillFunction for task private data.
[Optional, can be NULL]
\item a pointer to task private data
[Optional, can be NULL]
\item a priority for this task. This is currently unused.
\end{itemize}
On Success a positive value denoting the ID of the task is returned.
On error a negative value is returned.
\item[int TaskSchedule(pTaskMan self)]
Starts task switching.
\item[int TaskStop(pTaskMan self)]
Interrupts task switching all together
\item[int TaskContinue(pTaskMan self)]
Continues an task switching session interrupted by TaskStop. After this
the apopriate TaskYield, TaskSchedule or whatever has to be called.
\item[int TaskWait(pTaskMan self, long lID)]
Waits until the task specified by lID has finished. lID is obtained from
a call to TaskRegister.
\item[int TaskYield(pTaskman self)] does one cycle through the main loop.
Should be called by tasks performing lengthy operations now and then in
order to allow other tasks to execute. This is not yet implemented.
\item[int TaskSignal(pTaskMan self, int iSignal, void *pSigData)]
Invokes each Task's signal function with parameters iSignal and
pSigData.
\end{description}

169
doc/programmer/tclev.tex Normal file
View File

@@ -0,0 +1,169 @@
\subsubsection{The Tcl Environment Driver}
Sometimes a quick way for defining an environment
device driver is needed. A suitable way for doing this
is to define the device driver in the SICS servers Tcl macro language. Then
a device driver can even be developed and tested offline from a psish before
inclusion in the server. Clearly a means of communication between SICs and
the actual device is needed. Usually this communication happens via
a RS--232 serial port. Such a communication is catered for by the SICS
serialport command. This section describes the environment device driver
which links the SICS C code with Tcl. For each of the device drivers
functions a C language wrapper function is provided, which in turn calls
the Tcl interpreter with some parameters. This scheme is initialised by
providing the Tcl environment device driver with the name of a Tcl array
which has to hold Tcl implementations for all the necessary driver functions.
The name of this array will also be passed to each of the Tcl procedures as
first parameter. The Tcl procedures to define for a Tcl driver are:
\begin{description}
\item[Init] to be called at initialisation of the driver. This Tcl procedure must connect
to the device and prepare it for accepting further commands. The parameters to
init are all the parameters still left in the command line after the name
of the Tcl array in the EVFactory command line.
\item[Close] should close down the connection to the device after bringing the
device into a clean state.
\item[SetValue] will be called with a float value as second parameter. It
should issue a command to set the device to a new value. The return value is an
integer error code, defined by the driver. Error returns use the normal Tcl mechanism
with the Tcl error command. On errors a negative error code defined by the driver
must be returned.
\item[GetValue] reads the current value from the device. The return value is
either the floating point value of the current control variable or the
string pending if the request is still pending. In case of failure an error
is returned with a negative integer error code.
\item[Send] should concatenate all parameters and send them down to the
device. Returns error codes as described above.
\item[GetError] gets as a parameter the negative error code possibly returned
from one of the calls above. GetError should return a textual description
of the error.
\item[TryFixIt] gets as a parameter a negative error code as returned from one
of the calls described above. TryFixIt should do everything possible in
software to get the device working again: perhaps send some commands,
reopen the connection or whatever apropriate. Depending on the success
of this TryFixIt returns either DEVREDO if the command shall be resend or
DEVFAIL if the problem cannot be fixed without human intervention.
\item[Wrapper] This function will will be called by the environment variable
interpreter wrapper function before the general part of the wrapper
function gets executed. Its purpose is the handling of subcommands special
to the specific environment device. For instance modifying its mode of
operation or setting special variables not covered in the general
environment device setup. It has to return 1 on success, 0 on failure. On
failure it has to print error messages as well.
\end{description}
In order to do all this a new driver must be defined. This driver needs the
following data structure:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$tclevdat {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __TclEv {@\\
\mbox{}\verb@ char *pArray;@\\
\mbox{}\verb@ char *pInit;@\\
\mbox{}\verb@ char *pClose;@\\
\mbox{}\verb@ char *pSetValue;@\\
\mbox{}\verb@ char *pGetValue;@\\
\mbox{}\verb@ char *pSend;@\\
\mbox{}\verb@ char *pGetError;@\\
\mbox{}\verb@ char *pTryFixIt;@\\
\mbox{}\verb@ char *pWrapper;@\\
\mbox{}\verb@ char *pName;@\\
\mbox{}\verb@ Tcl_Interp *pTcl;@\\
\mbox{}\verb@ int iLastError;@\\
\mbox{}\verb@ } TclEv, *pTclEv;@\\
\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 fields correspond to the names of the Tcl functions to call for each of the
functions specified above. Plus the name of a Tcl array used for storing
driver special data in Tcl. iLastError will be used to keep the last error code.
pName is the name of the device in SICS. This will be copied into the
Tcl-array describing the device as MyName. May be used to set general
evcontroller parameters from within driver code and for error messages.
SICS sees this driver through the following interface:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$tclevint {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ pEVDriver CreateTclDriver(int argc, char *argv[],char *pName, SConnection *pCon);@\\
\mbox{}\verb@ int UpdateTclVariable(pEVDriver self, char *name, float fVal);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int TclEnvironmentWrapper(SConnection *pCon, SicsInterp *pSics, @\\
\mbox{}\verb@ void *pData, 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[CreateTclDriver] creates the Tcl driver and initialises it.
\item[UpdateTclVariable] will be called from the general environment
variable parameter update code in order to allow updating of Tcl variables
as well.
\item[TclEnvironmentWrapper] is the interpreter wrapper function for a Tcl
driver.
\end{description}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
\verb@"tclev.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*---------------------------------------------------------------------------@\\
\mbox{}\verb@ T C L E N V I R O N M E N T@\\
\mbox{}\verb@@\\
\mbox{}\verb@ This is the header file for an environment device driver defined in @\\
\mbox{}\verb@ the Tcl macro language. Dor more details see tclev.tex@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see copyright.h@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, February 1998@\\
\mbox{}\verb@------------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSTCLEV@\\
\mbox{}\verb@#define SICSTCLEV@\\
\mbox{}\verb@ @\\
\mbox{}\verb@@$\langle$tclevint {\footnotesize ?}$\rangle$\verb@ @\\
\mbox{}\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap4}
\verb@"tclev.i"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*---------------------------------------------------------------------------@\\
\mbox{}\verb@ Tcl environment device driver data structure definition file. @\\
\mbox{}\verb@@\\
\mbox{}\verb@ No general usable header file.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koenencke, February 1998@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@@$\langle$tclevdat {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

108
doc/programmer/telnet.tex Normal file
View File

@@ -0,0 +1,108 @@
\subsection{SICS Telnet Connection}
SICS support communication through the standard TCP/IP telnet protocoll as
described in RFC-854. SICS implements telnet in the most primitive way: i.e.
no options are supported. In a later stage binary data transfer and
authentication options may be supported. But not in its first
implementation. After a telnet connection has been accepted a SICS task is
installed. In the first stage this task will answer any commands with a
'Fuck--off' message. Only if a special login command is given, the
connection will be verified and finally opened for commands or rejected.
If no login command has been sent within a reasonable intervall of time the
connection will be closed as well. This logic is implemented into a special
task function associated with a telnet connection. The rest of the telnet
logic is so tightly integrated with the network reading, that it has to live
in the network reader module. This section describes the special task
function and its associated data structure.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$teldat {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typdef struct __TelTask {@\\
\mbox{}\verb@ SConnection *pCon;@\\
\mbox{}\verb@ int iLogin;@\\
\mbox{}\verb@ char pLoginWord[132];@\\
\mbox{}\verb@ time_t tStart;@\\
\mbox{}\verb@ } TelTask;@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro never referenced.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
The fields are: \begin{description}
\item[pCon] The connection object to act upon.
\item[iLogin] If the connection is logged in or not.
\item[pLoginWord] The login word to use. This word will be set as a SICS
server option.
\item[tStart] The start time of the telnet connection. Used to check for
timeout on the connection.
\end{description}
The interface to this module looks like this:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$telint {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __TelTask *pTelTask;@\\
\mbox{}\verb@/*--------------------------------------------------------------------------*/@\\
\mbox{}\verb@ pTelTask CreateTelnet(SConnection *pCon);@\\
\mbox{}\verb@ void DeleteTelnet(void *pData);@\\
\mbox{}\verb@/*---------------------------------------------------------------------------*/@\\
\mbox{}\verb@ int TelnetTask(void *pData);@\\
\mbox{}\verb@ void TelnetSignal(void *pData, int iSignal, void *pSigData);@\\
\mbox{}\verb@/*--------------------------------------------------------------------------*/@\\
\mbox{}\verb@ void InstallTelnet(void);@\\
\mbox{}\verb@ void KillTelnet(void);@\\
\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[CreateTelnet] creates a new telnet task object. Returns NULL on
failure, else apointer to a new data structure.
\item[DeleteTelnet] The deletion function for a telnet task.
\item[TelnetTask] The telnet task function.
\item[TelnetSignal] The telnet signal function.
\item[InstallTelnet] installs a telnet server port into the SICS system.
\item[KillTelnet] deletes the telnet server port from the system.
\end{description}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
\verb@"telnet.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-------------------------------------------------------------------------@\\
\mbox{}\verb@ S I C S T E L N E T S U P P O R T@\\
\mbox{}\verb@@\\
\mbox{}\verb@ This file defines the telnet task function and its associated data@\\
\mbox{}\verb@ structures. The body of the telnet handling code lives in the network@\\
\mbox{}\verb@ reader module.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, January 1998@\\
\mbox{}\verb@---------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSTELNET@\\
\mbox{}\verb@#define SICSTELNET@\\
\mbox{}\verb@@$\langle$telint {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@ @\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

View File

@@ -0,0 +1,44 @@
% Copyleft (c) 1997 by Mark Koennecke at PSI, Switzerland.
%
%
% This software is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You may already have a copy of the GNU General Public License; if
% not, write to the Free Software Foundation, Inc., 675 Mass Ave,
% Cambridge, MA 02139, USA.
%
\documentclass[12pt]{article}
\usepackage[dvips]
\setlength{\oddsidemargin}{-.1in}
\setlength{\evensidemargin}{0in}
\setlength{\topmargin}{0in}
\addtolength{\topmargin}{-\headheight}
\addtolength{\topmargin}{-\headsep}
\setlength{\textheight}{8.9in}
\setlength{\textwidth}{6.2in}
\setlength{\marginparwidth}{0.5in}
\begin{document}
\title{The NeXus Application Programmer's Interface}
\author{Mark K\"onnecke\\
Labor f\"ur Neutronenstreuung\\
Paul Scherrer Institut\\
CH-5232 Villigen PSI\\
Switzerland\\
Mark.Koennecke@psi.ch \\
Przemek K\l{}osowski\\
U. of Maryland \& NIST \\
przemek.klosowski@nist.gov
}
}
\maketitle
\tableofcontents
\end{document}

82
doc/programmer/token.tex Normal file
View File

@@ -0,0 +1,82 @@
\subsection{Token Management}
In SICS any client can issue commands to the SICS server. This
is a potential cause for trouble with users issuing conflicting
commands without knowing. In order to deal with this problem a
token mechanism has been developed. A connection can grab a
token and then has full control over the SICS server. Any other
connection will not be priviledged to do anything useful, except
looking at things. A token can be released manually with a
special command or is automatically released when the connection
dies. Another command exists which allows a SICS manager to
force his way into the SICS server.
This token scheme is implemented using the signal system of the
task management facility and the connection object. The connection
object has a field called iGrap which is true if the connection is the
ultimate and only control connection. This field will be modified
either directly through commands or via the signal system of the SICS
task manager. This must be so as all connections need to be notified
if one connection has grabbed control.
This object implements the user interface to the token system.
It checks privileges and issues the necessary signals. No own
data structure is needed. Just a wrapper function is
implemented.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
\verb@"token.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*---------------------------------------------------------------@\\
\mbox{}\verb@ S I C S T O K E N@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ This is the header file for the SICS token management@\\
\mbox{}\verb@ functions. It implements the token command.@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ Mark Koenencke, January 1998@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ copyright: see copyright.h@\\
\mbox{}\verb@ @\\
\mbox{}\verb@----------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSTOKEN@\\
\mbox{}\verb@#define SICSTOKEN@\\
\mbox{}\verb@ int TokenInit(SConnection *pCon, SicsInterp *pSics, @\\
\mbox{}\verb@ void *pData, int argc, char *argv[]);@\\
\mbox{}\verb@ /*@\\
\mbox{}\verb@ The Token Factory function.@\\
\mbox{}\verb@ */ @\\
\mbox{}\verb@ int TokenWrapper(SConnection *pCon, SicsInterp *pSics, @\\
\mbox{}\verb@ void *pData, int argc, char *argv[]);@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ /* @\\
\mbox{}\verb@ The wrapper function for the token command.@\\
\mbox{}\verb@ */ @\\
\mbox{}\verb@ @\\
\mbox{}\verb@ int TokenGrabActive(void);@\\
\mbox{}\verb@ /*@\\
\mbox{}\verb@ Returns 1, if a token grab is active, else 0@\\
\mbox{}\verb@ */ @\\
\mbox{}\verb@ @\\
\mbox{}\verb@ void TokenRelease(void);@\\
\mbox{}\verb@ /* @\\
\mbox{}\verb@ Releases a Token Grab@\\
\mbox{}\verb@ */ @\\
\mbox{}\verb@#endif @\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
The functions are:
\begin{description}
\item[TokenInit] is the installation routine which configures the
token system into SICS. Called from the initialisation script.
\item[TokenWrapper] is the interpreter interface function for the
token system. Implements the active run time commands.
\item[TokenGrapActive] returns true (1) if a connection has grabbed
control or false (0) otherwise.
\item[TokenRelease] releases the current control token.
\end{description}

100
doc/programmer/tricsnex.tex Normal file
View File

@@ -0,0 +1,100 @@
\subsection{TRICS NeXus Data Files}
This section describes the data file handling for the four circle
diffractometer TRICS at SinQ. TRICS collects a lot of detector frames in
time intervalls of days or weeks. The data writing scheme has to adress the
issue, that the HDF routines cannot ensure that there is no data corruption
when writing data files.
Thus the following scheme is implemented: With a special command, the user
enforces a new file. At that time header information is written. After that
the file is closed. With another command, the file is reopened and a frame
is added to it. Each frame data group will hold a flag which decides if the
frame is valid or not. After writing the frame, the file is closed again.
This scheme minimises the danger of data corruption.
The current frame number is kept in a non NeXus standard field in the data file
itself. This allows to reopen files and append data to it.
The interface to this object looks like this:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$nxtrics {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __NexTrics *pNexTrics;@\\
\mbox{}\verb@@\\
\mbox{}\verb@/*----------------------------- live & death -----------------------------*/@\\
\mbox{}\verb@ pNexTrics CreateNexTrics(pDataNumber pNum, char *pRoot, char *pDict,@\\
\mbox{}\verb@ SicsInterp *pSics);@\\
\mbox{}\verb@ void DeleteNexTrics(void *pData);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int NexTricsFactory(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@/*----------------------------- interaction ------------------------------*/@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int StartFile(pNexTrics self, SConnection *pCon);@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ int ReopenFile(pNexTrics self, char *filename);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int DumpFrame(pNexTrics self, SConnection *pCon);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int NexTricsAction(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[CreateNexTrics] creates a new TRICS NeXus data file writing object.
Parameters are a data number object for the automatic creation of file names
and the directory name where the data files ought to live. The next
parameter is the name of the NeXus dictionary file to use for writing.
\item[DeleteNexTrics] deletes a NexTrics object. The last parameter is the
name of the SICS interpreter to search for objects. NexTrics will maintain a
cache of frequently used SICS objects for writing.
\item[NexTricsFactory] is the interpreter wrapper function for the command
to install the nexus data writing object for Trics into the system.
\item[StartFile] will automatically create a new file and write the header
information to it.
\item[DumpFrame] will dump a frame worth of data to the file. Thereby
reopening and closing it. This will be called for each detector shot, i.e.
in the end three frames will be written when all three detectors have been
installed at TRICS.
\item[NexTricsAction] is the command interface to the TRICS NeXus data file
writing object.
\end{description}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
\verb@"nextrics.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*----------------------------------------------------------------------------@\\
\mbox{}\verb@ N E X T R I C S@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ An object for writing NeXus data files for the four ciclre diffractometer@\\
\mbox{}\verb@ TRICS at PSI. Can be used as basis for writing files for other four@\\
\mbox{}\verb@ circles equiped with a PSD as well.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see copyright.h@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, April 1998@\\
\mbox{}\verb@------------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef NEXTRICS@\\
\mbox{}\verb@#define NEXTRICS@\\
\mbox{}\verb@@$\langle$nxtrics {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

View File

@@ -0,0 +1,94 @@
\subsection{UDPquieck}
At SinQ a requirement is that newly created data files are automatically
copied to another computer. This is for data safety. To have this done by
the instrument control program would raise stability problems: what to do
when the remote computer fails, when transfers are to slow or all data has
to be transferred again. Therefore the copying of files was delegated to a
second process. Now a a means is needed to tell the second process, that a
new data file has been created. This means is this module. It sends a UDP
message on a predefined port. The data copying process can receive or not
and act accordingly. Furthermore this scheme can be used to have other
processes act upon a new data file as well. The message sent is simple: it
consists of the string QUIECK/ followed by the filename. A new command is
implemented with the name udpquieck. This shall be a hidden command. As only
one such facility is needed for a given SICS server, all necessary data is
held in the implementation file udpquieck.c. Anyway, there is only one
structure holding network data.
The configuration of the udpport is done via a special server
option QuieckPort.
Laater on this facility may be extended to send arbitrary messages to
the UDP port for further coordination tasks. This is catered for by
having different message types. However, as of now only file messages
are supported.
Needless to say, that the second process must be able to interpret the
uDP messages sent by the SICS server.
The following interface is implemented:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$quieck {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@#define QUIECK 1@\\
\mbox{}\verb@@\\
\mbox{}\verb@ void KillQuieck(void *pData);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int SendQuieck(int iType, char *filename);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int QuieckAction(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{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
\verb@"udpquieck.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*------------------------------------------------------------------------@\\
\mbox{}\verb@ U D P Q U I E C K@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ udpquieck sends a notification message on a UDP port when a new data@\\
\mbox{}\verb@ file has been created. @\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, August 1998@\\
\mbox{}\verb@---------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef UDPQUIECK@\\
\mbox{}\verb@#define UDPQUIECK@\\
\mbox{}\verb@@$\langle$quieck {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
The functions:
\begin{description}
\item[KillQuieck] closes the network port at shutdown. Is the
KillFunction used in the SICS interpreter command structure.
\item[SendQuieck] sends a message of type iType and the text filename
to the UDP port. The only supported iType value is QUIECK as defined
in udpquieck.h. Further message types can be supported by adding more
support in this function.
\item[QuieckAction] is the interpreter interface function to this
facility. Yes, messages may be issued by a commadn from the
interpreter for instance within scripts. Again, this seems more useful
when this facility has been extended.
\end{description}

91
doc/programmer/varlog.tex Normal file
View File

@@ -0,0 +1,91 @@
\subsection{VarLog}
This is a lillte helper class which can be used to keep a log of a
variable. A variables value is stored together with time information in a
list. Various functions allow to interact with this list and retrieve the
log. For the list the lld package is used again. Thus the only data
required by this module is the integer ID of the list.
The following functions are provided:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$logint {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*---------------------------- birth and death ----------------------------*/ @\\
\mbox{}\verb@ typedef struct __VarLog *pVarLog;@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int VarlogInit(pVarLog *self);@\\
\mbox{}\verb@ int VarlogDelete(pVarLog self);@\\
\mbox{}\verb@/*----------------------------- operation -------------------------------*/@\\
\mbox{}\verb@ int VarlogClear(pVarLog self);@\\
\mbox{}\verb@ int VarlogAdd(pVarLog self, float fVal);@\\
\mbox{}\verb@/*------------------------------ data recovery -------------------------*/@\\
\mbox{}\verb@ int VarlogLength(pVarLog self, int *iLength);@\\
\mbox{}\verb@ int VarlogGetTime(pVarLog self, time_t *tTime);@\\
\mbox{}\verb@ int VarlogGetVal(pVarLog self, float *fValues);@\\
\mbox{}\verb@ int VarlogGetMean(pVarLog self, float *fMean, float *fStdDev);@\\
\mbox{}\verb@/*------------------------------ interpreter ---------------------------*/@\\
\mbox{}\verb@ int VarlogWrapper(pVarLog self, int *iSwitch, SConnection *pCon, @\\
\mbox{}\verb@ char *subcommand, char *sub2,char *pVarName);@\\
\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 return 1 on success, 0 on failure if not mentioned otherwise.
\begin{description}
\item [ValogInit] creates a new varlog and prepares for data collection.
Only parameter is a pointer to an int which will be initialised to the list
ID to use.
\item [VarlogDelete] deletes a varlog and frees the list. Single parameter
is a pointer to an int holding the ID of the list to kill.
\item [VarlogClear] clears old logged data but keeps the varlog alive for
further data collection.
\item [VarlogAdd] adds the float value fVal to the log denoted by iList. The
time stamp will be generated automatically.
\item [VarlogLength] retrieves the length of the current log.
\item [VarlogGetTime] retrieves the array of time stamps as provided by the
system function time from the log.
\item [VarlogGetVal] retrieves the array of values from the log.
\item [VarlogGetMean] retrieves the mean value of the values from the log
denoted by iList and their standard deviation.
\item [VarlogWrapper] is a function which may be invoked from an object
wrapper function in order to interpret and handle the var logs subcommands.
Parameters are: the varlog list, a switch variable which will be set to 1
if logging is enabled and to 0 if not, a connection object to which data
will be written and finally the subcommand to evaluate.
\end{description}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
\verb@"varlog.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------@\\
\mbox{}\verb@ V A R L O G@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ A module which keeps a log of a variable.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, September 1997@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see implementation file@\\
\mbox{}\verb@ @\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSVARLOG@\\
\mbox{}\verb@#define SICSVARLOG@\\
\mbox{}\verb@#include <time.h>@\\
\mbox{}\verb@@$\langle$logint {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

412
doc/programmer/velo.tex Normal file
View File

@@ -0,0 +1,412 @@
\subsection{The Velocity Selector}
A velocity selector is a kind of turbine in the neutron beam. Only neutrons
which manage to travel through the device between two turbine blades make it
through the device, the rest is annihilated in the blades or the turbine
housing. Thus, a velocity selector is a kind of monochromator.
The behaviour of a velocity selector is determined by two
parameters: the rotation speed and the dejustment of the velocity selector
to the neutron beam, the tilt angle. The velocity
(wavelength) of the neutrons coming through is determined by the rotation speed
of the thing. The tilt angle determines the velocity distribution function.
Velocity selectors have a few peculiarities due to the fact that they
rotate rather quickly. This may give rise to resonances at certain
rotation speeds which may damage the device and the surroundings of it. This
problem is coped with by having forbidden regions of rotation speeds which
cannot be selected. The second implication of the fast rotation is, that the
rotation needs to stop or be below a certain threshold before the tilt
angle may be changed. So, changing tilt has to go in three steps:
first stop rotation, drive tilt, accelerate rotation to the former speed.
Tilt is usually controlled by some stepper motor.
The rotation speed of the velocity selector needs to be monitored at regular
intervalls. If it goes out of tolerances, a error handling procedure must be
initiated. Furthermore logging of the rotation speeds of the velocity
selector may be required. All this is already realised in the environment
controller code. In order to minimise duplication of code, these facilities
are implemented by installing a environment controller for the velocity
selector. This environement controller will have a dummy driver which does
not allow the velocity selector to be driven through the environment
controller. An object is installed into the SICServer with the name of the
velocity selector and watch appended to it. Through this object such things
as tolerances, error handling procedures and logging of velocity selector
values can be configured. The only task left for the velocity selector code
is to maintain the proper state of the environment controller mode at
apropriate places.
From this introduction the necessary datastructure for this beast can be
easily deduced. Besides the usual objectdescriptor we need:
\begin{itemize}
\item A list of forbidden regions, realised as a standard linked list of
min, max values.
\item A motor to drive the tilt with.
\item Fields to hold rotation and tilt and some auxilliary parameters.
\item Various interrupt to trigger in case of failures.
\item As an interface a drivable interface for the rotation is needed in
oder to use the device executor for changing rotation speed.
\item A pointer to the environment controller object monitoring the velocity
selector.
\item A driver for actually driving the velocity selector.
\end{itemize}
A suitable datastructure looks like this:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$data {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*------------------ The velocity selector datastructure -----------------*/ @\\
\mbox{}\verb@ @\\
\mbox{}\verb@ typedef struct __VelSel {@\\
\mbox{}\verb@ pObjectDescriptor pDes;@\\
\mbox{}\verb@ char *pName;@\\
\mbox{}\verb@ pIDrivable pDrivInt;@\\
\mbox{}\verb@ pICallBack pCall;@\\
\mbox{}\verb@ int iForbidden;@\\
\mbox{}\verb@ ObPar *pPar;@\\
\mbox{}\verb@ pMotor pTilt;@\\
\mbox{}\verb@ float fRot;@\\
\mbox{}\verb@ float fTilt;@\\
\mbox{}\verb@ pEVControl pMonitor;@\\
\mbox{}\verb@ pVelSelDriv pDriv;@\\
\mbox{}\verb@ } VelSel; @\\
\mbox{}\verb@/*----------------- Forbidden region single item -------------------------*/@\\
\mbox{}\verb@ typedef struct __Verbot {@\\
\mbox{}\verb@ float fMin;@\\
\mbox{}\verb@ float fMax;@\\
\mbox{}\verb@ } Verbot, *pVerbot;@\\
\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 fields are:
\begin{description}
\item[pDes] The usual object descriptor.
\item[pName] The velocity selector name.
\item[pDrivInt] The drivable interface.
\item[pCall] The callback interface.
\item[iForbidden] The handle to the lsit of forbidden regions.
\item[pPar] The velocity selector parameters.
\item[pTilt] The motor to use for tilting the turbine.
\item[pMonitor] The environment controller object representing the velocity
selector in the environment control subsystem.
\item[pDriv] The velocity selector driver.
\end{description}
Verbot is a trivial little data structure holding a single forbidden
region for the vlocity selector. This is the structure held in the
forbidden list. Please note that the upper and lower limits of the
device are held in that list as well.
In order to interface with this a few functions will be defined. All
functions starts with VS. Functions returning an int return 0 on failure, 1
on success for the rest of this discussion. The first set of functions
deals with creating and configuring a velocity selector.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$proto1 {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __VelSel *pVelSel;@\\
\mbox{}\verb@ typedef struct __VelSelDriv *pVelSelDriv;@\\
\mbox{}\verb@@\\
\mbox{}\verb@ pVelSel VSCreate(pMotor pTilt, pVelSelDriv pDriv);@\\
\mbox{}\verb@ void VSDestroy(void *self);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int VSAddVerbot(pVelSel self, float fMin, float fMax);@\\
\mbox{}\verb@ int VSSetPar(pVelSel self,SConnection *pCon, char *name, float fVal);@\\
\mbox{}\verb@ int VSGetPar(pVelSel self,char *name, float *fVal);@\\
\mbox{}\verb@ int VSGetRotation(pVelSel self, float *fRot);@\\
\mbox{}\verb@ int VSGetTilt(pVelSel self, float *fTilt);@\\
\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}
Most functions take a pointer to a velocity selector data structure as
first parameter. This parameter is not discussed furtheron.
\begin{description}
\item[VSCreate] Creates a velocity selector object. A driver and a
motor for the tiliting operation need to be given as parameters. On
return either a pointer to a newly allocated velocity selector data
structure is returned or NULL as indication of failure.
The velocity selector will make sure that the tilt motor is only
accessible with internal
privilege. This effectively reserves the tilt motor to the velocity
selector object. This obliges the velocity selector to set a lower
privilege
while running that motor and to set it back again afterwards.
The idea behind this
scheme is to prevent a user from accidentally tampering with the tilt motor
without passing through the velocity selector interface.
\item[VSDestroy] is a function which properly frees all data
structures associated with the velocity selector. This is the function
to specify as KillFunction for the interpreter.
\item[VSAddVerbot] adds a forbidden region between fMin and fmax
rotation speeds.
\item[VSSetPar, VSGetPar] set and retrive velocity selector
parameters. Parameter names given as parameter name are the same as in
the user documentation.
\item[VSGetRotation] retrieves the current rotation speed.
\item[VSGetTilt] retrieves the current tilt angle.
\end{description}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
$\langle$protos2 {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*@\\
\mbox{}\verb@ int VSSetRotation(pVelSel self, SConnection *pCon, float fNew);@\\
\mbox{}\verb@ int VSSetTilt(pVelSel self, SConnection *pCon, float FNewTilt);@\\
\mbox{}\verb@*/@\\
\mbox{}\verb@ int VSSetTiltRot(pVelSel self, SConnection *pCon,@\\
\mbox{}\verb@ float fNewRot, float fNewTilt);@\\
\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[VSSetTiltRot] sets both rotation speed and tilt angle to new
values.
\end{description}
Please note, that further manipulation functions are hidden in the Drivable
interface functions for the rotation which this module defines.
Another common task for a velocity selector is to measure its loss current.
This is done regularly in order to catch possible problems with the
velocity selector early on.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap4}
$\langle$protos4 {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ int VSGetLossCurrent(pVelSel self, SConnection *pCon, float *fLoss);@\\
\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}
Last not least a velocity selector needs an interface to the interpreter as
well. As usual there are two functions: a creation function and a bigger
action function which takes the widget commands.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap5}
$\langle$protos3 {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ int VelSelFactory(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ int VelSelAction(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}
\subsubsection{The velocity selector driver}
As usual for hardware devices in SICS the velocity selector consists of the
logical selector described above and a hardware driver which takes care of
simulating actual hardware or talking to it. This driver is described here.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap6}
$\langle$Driver {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __VelSelDriv {@\\
\mbox{}\verb@ void *pPrivate;@\\
\mbox{}\verb@ void (*DeletePrivate)(void *pData);@\\
\mbox{}\verb@ float fTolerance;@\\
\mbox{}\verb@ int (*Halt)(pVelSelDriv self);@\\
\mbox{}\verb@ int (*GetError)(pVelSelDriv self,@\\
\mbox{}\verb@ int *iCode, char *pError,@\\
\mbox{}\verb@ int iErrlen);@\\
\mbox{}\verb@ int (*TryAndFixIt)(pVelSelDriv self,@\\
\mbox{}\verb@ int iCode);@\\
\mbox{}\verb@ int (*GetRotation)(pVelSelDriv self,@\\
\mbox{}\verb@ float *fRot);@\\
\mbox{}\verb@ int (*SetRotation)(pVelSelDriv self,@\\
\mbox{}\verb@ float fRot);@\\
\mbox{}\verb@ int (*GetStatus)(pVelSelDriv self, @\\
\mbox{}\verb@ int *iCall, float *fCur);@\\
\mbox{}\verb@ int (*GetDriverText)(pVelSelDriv self,@\\
\mbox{}\verb@ char *pText, @\\
\mbox{}\verb@ int iTextLen);@\\
\mbox{}\verb@ int (*GetLossCurrent)(pVelSelDriv self,@\\
\mbox{}\verb@ float *fLoss);@\\
\mbox{}\verb@ int (*Init)(pVelSelDriv self, @\\
\mbox{}\verb@ SConnection *pCon);@\\
\mbox{}\verb@ }VelSelDriv; @\\
\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}
pPrivate is an area where individual drivers may store their necessary data.
DeletePrivate is a function which will be automatically called when the
driver is destroyed with pPrivate passed as parameter. This functions
purpose is to destroy pPrivate and remove all memory associated with it.
Each driver is resonsible for filling the right thing in here.
The description of the rest of the functions is very much like as described
for the motor interface. Possible return values for GetStatus can be:
\begin{itemize}
\item VSNOCON: connection to velocity selector lost.
\item VSACCEL: selector accelerating or breaking.
\item VSFAIL: velocity selector failure.
\item VSOK: all fine, at requested velocity.
\end{itemize}
Special is the GetDriverText which is meant to
return a formatted string of hardware specific information from the device.
This is put into pText, but maximum iTextlen characters.
Another special is the GetLossCurrent. This is a special self test of the
velocity selector which helps to identify possible problems with the device
early on. This test must be made regularly and, of course, the driver must
support it.
Init is meant to do what it says, initialize the velocity selector. This is
here in order to support restarting the velocity selector in case of a
problem.
At the time of writing (Juli 1997) two drivers for velocity selectors exist:
a simulation driver and a driver for a Dornier velocity selector run
through a Macintosh--PC terminal server communicating with the velocity
selector control PC. Please note, that the Dornier program had been slightly
modified in order to make this scheme work.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap7}
\verb@"velo.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-------------------------------------------------------------------------@\\
\mbox{}\verb@@\\
\mbox{}\verb@ V E L O C I T Y S E L E C T O R@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Header file for the SICS velocity selector module. For documentation@\\
\mbox{}\verb@ see velo.w.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, Juli 1997@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see implementation file@\\
\mbox{}\verb@-----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSVELO@\\
\mbox{}\verb@#define SICSVELO@\\
\mbox{}\verb@@\\
\mbox{}\verb@/*------------------------- live & death & shape ------------------------*/@\\
\mbox{}\verb@@$\langle$proto1 {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@/*------------------------- drive around -----------------------------------*/@\\
\mbox{}\verb@@$\langle$protos2 {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@$\langle$protos4 {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@/*------------------------- Interpreter interface ------------------------*/@\\
\mbox{}\verb@@$\langle$protos3 {\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{scrap8}
\verb@"velo.i"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Internal header file describing the velocity selector data structure.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, Juli, 1997@\\
\mbox{}\verb@@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef VELOINTERNAL@\\
\mbox{}\verb@#define VELOINTERNAL@\\
\mbox{}\verb@@$\langle$data {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#define VELOREDO 2@\\
\mbox{}\verb@#define VELOFAIL 0@\\
\mbox{}\verb@#define VELOOK 1@\\
\mbox{}\verb@@\\
\mbox{}\verb@#define VSNOCON 0@\\
\mbox{}\verb@#define VSOK 1@\\
\mbox{}\verb@#define VSACCEL -7@\\
\mbox{}\verb@#define VSFAIL -2@\\
\mbox{}\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{scrap9}
\verb@"velodriv.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------@\\
\mbox{}\verb@ V E L O C I T Y S E L E C T O R D R I V E R@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Header file for the velocity selector driver and its related functions.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, Juli 1997@\\
\mbox{}\verb@ copyright: see implementation file@\\
\mbox{}\verb@-----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef VELODRIV@\\
\mbox{}\verb@#define VELODRIV@\\
\mbox{}\verb@#include <tcl.h>@\\
\mbox{}\verb@@$\langle$Driver {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@/*-------------------- live & death ----------------------------------------*/@\\
\mbox{}\verb@ pVelSelDriv VSCreateSim(void);@\\
\mbox{}\verb@ pVelSelDriv VSCreateDornierSINQ(char *name,Tcl_Interp *pTcl);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ void VSDeleteDriver(pVelSelDriv self);@\\
\mbox{}\verb@@\\
\mbox{}\verb@#endif @\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

113
doc/programmer/velodorn.tex Normal file
View File

@@ -0,0 +1,113 @@
\subsection{The hardware driver for the Dornier velocity selector at SINQ}
SANS uses a velocity selector provided by Dornier, Germany. This velocity
selector comes with a IBM--compatible PC for control. On this PC there is a
control program for the velocity selector. This program can be operated from
the PC's monitor and keyboard or remotely, from a host computer,
through a RS--232 connection. The protocoll on this RS--232 connection is a
simple ASCII command protocoll detailed in the documentation delivered by
Dornier. At SINQ this velocity selcector control PC is connected via the
RS--232 connection to a Macintosh computer. This Mac is connected to the
network by TCP/IP. The Mac runs a terminal server program. This program
forwards commands sent by TCP/IP to the apropriate RS--232 port. Due to this
complicated setup, the hardware driver for the Dornier velocity selector has
three layers:
\begin{itemize}
\item A command forwarding layer, which sends command to the selector via
TCP/IP, the MAC and RS--232 and collects answers. This is fairly general
code, used for many SICS hardware drivers.
\item A primitive operations layer which implements simple command on the
selector. This layer is based on code provided by Dr. Emmelmann, HMI.
\item At the end, there is the actual SICS hardware driver which builds the
interface to the SICS system.
\end{itemize}
The implementation of the Dornier velocity selector driver is further
complicated by the fact that it is very slow in responding to commands
and moreover due to the fact that it has different modes:
\begin{itemize}
\item Starting is just after starting the velocity selector
\item regel is the normal mode.
\item halting is the mode when the velocity selector has been asked to
stop.
\end{itemize}
Unfortunately the actions necessary to run a Dornier velocity
selector to a desired speed depend on those modes. For instance if the
Dornier velocity
selector is stopped it first needs to be started and then, when a
certain speed has been reached, the command to set the desired
rotation speed can be sent. The necessary mode dependent switching is
done in the DornierStat function.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$dh {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ int GetDornierStatus(void **pData, pDornierStatus pDornier);@\\
\mbox{}\verb@ int DornierSend(void **pData, char *pCommand, char *pReply, int iLen);@\\
\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@"velodorn.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*---------------------------------------------------------------------------@\\
\mbox{}\verb@ V E L O D O R N@\\
\mbox{}\verb@@\\
\mbox{}\verb@ a set of utility functions needed in order to communicate with a @\\
\mbox{}\verb@ Dornier velocity selector through the SINQ system. @\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, Juli 1997@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see implementation file.@\\
\mbox{}\verb@------------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef VELODORN@\\
\mbox{}\verb@#define VELODORN@\\
\mbox{}\verb@/*-------------------- a data structure for status analysis ---------------*/@\\
\mbox{}\verb@ typedef struct {@\\
\mbox{}\verb@ char echo[30]; /* echo of command */@\\
\mbox{}\verb@ char rm[10]; /* operation status: REG == adjusting, STB == idle, @\\
\mbox{}\verb@ BRE == braking */@\\
\mbox{}\verb@ int nom_rpm; /* envisaged rotation */@\\
\mbox{}\verb@ int cur_rpm; /* actual rotation speed */ @\\
\mbox{}\verb@ int pwr; /* loss current, only valid after check */@\\
\mbox{}\verb@ float curr; /* electircal current */@\\
\mbox{}\verb@ int rot_temp; /* temperature of rotor */@\\
\mbox{}\verb@ int cont_temp; /* temperature of housing */@\\
\mbox{}\verb@ int inl_temp; /* in temperature of cooling water */@\\
\mbox{}\verb@ int outl_temp; /* temperature of cooling water after @\\
\mbox{}\verb@ velocity selector */@\\
\mbox{}\verb@ float cool_wat; /* cooling water flow (l/minute) */@\\
\mbox{}\verb@ float vacuum; /* vacuum (mbar) */@\\
\mbox{}\verb@ float accel; /* rotation acceleration (g) */@\\
\mbox{}\verb@ int komm; /* communication status PC-Host,@\\
\mbox{}\verb@ 0 = enabled, 1 = disabled @\\
\mbox{}\verb@ */@\\
\mbox{}\verb@ int iHz;@\\
\mbox{}\verb@ } DornierStatus, *pDornierStatus; @\\
\mbox{}\verb@@\\
\mbox{}\verb@/*--------- error codes */@\\
\mbox{}\verb@#define NOCOMMAND -300@\\
\mbox{}\verb@#define ECHOMISSING -302@\\
\mbox{}\verb@#define BADANALYSIS -303@\\
\mbox{}\verb@#define STARTTIMEOUT -304@\\
\mbox{}\verb@#define INVALIDSTATUS -305@\\
\mbox{}\verb@/*------ functions */@\\
\mbox{}\verb@@$\langle$dh {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

129
doc/programmer/xytable.tex Normal file
View File

@@ -0,0 +1,129 @@
\subsection{Xytable}
Xytable is an object which holds a list of x-y values. This can be used as a
tool for doing very special scans or storing interesting data from command
files. This class allows to retrieve the data in uuencoded form which
is understood and displayed by the variable watcher SICS client. Furthermore
data can be written to a file. The table entries are kept in a linked
list in the following data structure.
The following data structures will be used:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$xydata {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct {@\\
\mbox{}\verb@ float x;@\\
\mbox{}\verb@ float y;@\\
\mbox{}\verb@ } TableEntry, *pTableEntry;@\\
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __XYTABLE {@\\
\mbox{}\verb@ pObjectDescriptor pDes;@\\
\mbox{}\verb@ int iList; @\\
\mbox{}\verb@ int iCount;@\\
\mbox{}\verb@ }XYTable;@\\
\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 entries in the TableEntry are self explianing: just the
values. The XYTable structure holds the following fields:
\begin{description}
\item[pDes] The standard object descriptor.
\item[iList] the handle for the lld-list holding the table entries.
\item[iCount] The number of entries in the table.
\end{description}
The following functions are defined:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$xyfunc {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __XYTABLE *pXYTable;@\\
\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
\mbox{}\verb@ int XYClear(pXYTable self);@\\
\mbox{}\verb@ int XYAdd(pXYTable self, float x, float y);@\\
\mbox{}\verb@ int XYWrite(pXYTable self, FILE *fd);@\\
\mbox{}\verb@ int XYSendUU(pXYTable self, SConnection *pCon);@\\
\mbox{}\verb@ int XYList(pXYTable self, SConnection *pCon);@\\
\mbox{}\verb@/*----------------------- interpreter interface --------------------------*/@\\
\mbox{}\verb@ int XYFactory(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ int XYAction(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}
Most functions take a pointer to an XYTbale data structure as fist
parameter and return 1 on success and 0 on failure. The functions are:
\begin{description}
\item[XYClear] clears all entries.
\item[XYAdd] appends a new pair of x and y values to the list.
\item[XYWrite] writes the XY-list to the file fd. This file must
already have been opened for writing by the calling routine.
[item[XYSendUU] sends the XY-table in uuencoded form compatible with
the SICS variabel watcher to connection pCon.
\item[XYList] prints the content of the XY-table to connection pCon.
\item[XYFactory] is the implentation of the installation command for
the SICS initialisation process.
\item[XYAction] implements the interface to the SICS interpreter for
the xytable command.
\end{description}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
\verb@"xytable.i"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*----------------------------------------------------------------------@\\
\mbox{}\verb@ Internal data structures for the XYTable class. Do not modify@\\
\mbox{}\verb@------------------------------------------------------------------------*/@\\
\mbox{}\verb@@$\langle$xydata {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap4}
\verb@"xytable.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*------------------------------------------------------------------------@\\
\mbox{}\verb@ X Y T A B L E @\\
\mbox{}\verb@@\\
\mbox{}\verb@ a helper class for holding an X-Y list of values.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see copyright.h@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, June 1999@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef XYTABLE@\\
\mbox{}\verb@#define XYTABLE@\\
\mbox{}\verb@@$\langle$xyfunc {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}