\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:
@d codri @{
   typedef struct __CODRI *pCodri;
   typedef struct __CODRI {
                             int (*Init)(pCodri self);
                             int (*Close)(pCodri self);
                             int (*Delete)(pCodri self);
                             int (*SetPar)(pCodri self, 
                                           char *parname,
                                           float fValue);
                             int (*SetPar2)(pCodri self, 
                                           char *parname,
                                           char *value);
                             int (*GetPar)(pCodri self,
                                           char *parname,
                                           char *pBuffer,
                                           int iBufLen);
                             int (*CheckPar)(pCodri self, 
                                             char *parname);
                             int (*GetError)(pCodri self, int *iCode,
                                             char *pError, 
                                             int iErrLen);
                             int (*TryFixIt)(pCodri self, int iCode);
                             int (*Halt)(pCodri self);
                             char *pParList;
                             void *pPrivate;
                             }Codri;
                             
@}   
All functions take a pointer to the controller driver itself as a
parameter. All functions except TryFixIt and CheckPar
 return 0 on failure and 1 for success.
\begin{description}
\item[Init] initializes the controller driver. The parameters argc,
argv are main() style parameters for the initialization of the
controller driver.
\item[Close] closes the connection to the controller but does not delete a thing.
\item[Delete] closes the connection to the controller and deletes private data structures. Called when deleting the controller. 
\item[SetPar] tries to set the parameter parname to the value 
fValue. The last is floating point which covers the frequent
occurence of numeric values. 
\item[SetPar2] The same as SetPar but uses test string as input for
parameter setting. 
\item[GetPar] retrieves the parameter parname formatted as 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 shall not be messed with by upper level code.
\end{description}

\subsubsection{The Controller Object}
This is the general controller object visible from the SICS
interpreter. This object allows to list all possible
parameters. Internal functions are provided for setting
parameters. But this is meant to be operated through a drive adapter
object (see below) in SICS. Thus the interface to this object
includes:
@d chocoint @{
  typedef struct __CHOCO *pChoco;
/*------------------------------------------------------------------------*/
  int CHGetParameter(pChoco self, char *pParName, 
                      char *pParValue, int iBuflen); 
  
  pCodri CHGetDriver(pChoco self);
  int    CHList(pChoco self, SConnection *pCon, char *name);
/*------------------------------------------------------------------------*/
  int  ChocoAction(SConnection *pCon, SicsInterp *pSics, void *pData,
                   int argc, char *argv[]);
  int  ChocoFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
                   int argc, char *argv[]);
 
@}
\begin{description}
\item[CHGetParameter] retrieves the value of the parameter ParName
converted to text. Maximum iBufLen of result or error text are copied into the
buffer pParvalue.
\item[CHGetDriver] returns a pointer to the controller driver. This
function will be used by the drive adapters for interfacing with the
driver directly.
\item[CHList] prints a listing of all parameters to the client
described by pCon. name is the name of the controller.
\item[ChocoAction] is the SICS interpreter interface function for the
controller.
\item[ChocoFactory] is the SICS interpreter interface function which
installs a controller into SICS.  
\end{description}

Most of the actual work of the controller is left to the driver. Thus
the internal data structure for a controller object is very simple:
@d chocodata @{
   typedef struct __CHOCO {
                            pObjectDescriptor pDes;
                            pCodri            pDriv;
                          } Choco;
@} 
It consists just of the standard SICS object descriptor and a pointer
to the driver.

\subsubsection{The Drive 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:
@d adapter @{
   typedef struct __CHADAPTER *pCHAdapter;
/*-----------------------------------------------------------------------*/
   int CHAdapterFactory(SConnection *pCon, SicsInterp *pSics, 
                        void *pData,
                        int argc, char *argv[]);
               
   int CHAdapterAction(SConnection *pCon, SicsInterp *pSics, 
                        void *pData,
                        int argc, char *argv[]);

   pEVDriver MakeControllerEnvironmentDriver(int argc, char *argv[]);
               
@}
\begin{description}
\item[CHAdapterFactory] is the SICS interpreter factory function for
creating a drive adapter.
\item[CHAdapterAction] is the SICS interpreter function for
representing the object in SICS. Just a single action is supported:
request the value of the parameter. 
\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:
@d adadata @{
   typedef struct __CHADAPTER {
                                pObjectDescriptor pDes;
                                pCodri  pDriv;
                                pIDrivable pInt;
                                float fUpper;
                                float fLower;
                                float fTarget;
                                char *pParName;
                              }CHAdapter;
@}
\begin{description}
\item[pDes] is the standard object descriptor.
\item[pDriv] is a pointer to the controller driver.
\item[pInt] is a pointer to the drivable interface implemented by the
 adapter.
\item[fUpper] upper limit for the parameter.
\item[fLower] lower limit for the parameter.
\item[pParName] is the name of the parameter which is driven through
this adapter.
\end{description}

This is the data structure  for the private part of the environment
controller driver:
@d evada @{
   typedef struct __CHEV {
                          char *pParName;
                          pCodri pDriv;
                          int iLastError;
                         }CHev, *pCHev;
@}

@o codri.h @{
/*-------------------------------------------------------------------------
                 C o n t r o l l e r D r i v e r

 This file contains the description of the data structure for a
 general controller driver.

 Mark Koennecke, January 1998
--------------------------------------------------------------------------*/
#ifndef CODRIV
#define CODRIV
#define CHFAIL -1
#define CHREDO -2
#define CHOK   -3
@<codri@>
#endif

@}

@o choco.h @{
/*-----------------------------------------------------------------------
                C h o p p e r C o n t r o l l e r

  This is both the header file for a general controller and a SICS
  chopper controller.

  Mark Koennecke, January 1998
--------------------------------------------------------------------------*/
#ifndef CHOCOSICS
#define CHOCOSICS
#include "codri.h"
@<chocoint@>
#ifdef CHOCOINTERNAL
@<chocodata@>
#endif
#endif 
@}


@o chadapter.h @{
/*------------------------------------------------------------------------
                    C H a d a p t e  r

 This is the header file for a drive adapter for collaboration with a
 general device controller as implemented in choco.*

 Mark Koennecke, January 1998
--------------------------------------------------------------------------*/
#ifndef SICSCHADA
#define SICSCHADA
#include "codri.h"
@<adapter@>
#ifdef CHADAINTERNAL
@<adadata@>
@<evada@>
#endif
#endif
@}


\subsubsection{To Do}
This scheme seems to be quite promising for handling many SICS
objects. The following enhancements could be considered. Allow to set
certain primitive parameters without a drivable interface. And add an
adapter for an environment variable in the controller.
  









