\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 text 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); /*------------------------------------------------------------------------*/ void KillChoco(void *pData); 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 @ #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" @ #ifdef CHOCOINTERNAL @ #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" @ #ifdef CHADAINTERNAL @ @ #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.