\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:
@d evdata @{
   typedef struct __EVControl {
                               pObjectDescriptor  pDes;
                               pIDrivable         pDrivInt;
                               pEVInterface       pEnvir;
                               pEVDriver          pDriv;
                               EVMode             eMode;
                               float              fTarget;
                               char               *pName;
                               ObPar              *pParam;
                               int                iLog;
                               pVarLog            pLog;
                               int                iWarned;
                               int                iTcl;
                               int                iStop;
                               void *pPrivate;
                               void (*KillPrivate)(void *pData);
                               } EVControl;
@} 

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: 

@d evdriv @{
   typedef struct __EVDriver {
                             int (*SetValue)(pEVDriver self, float fNew);
                             int (*GetValue)(pEVDriver self, float *fPos);
                             int (*Send)(pEVDriver self, char *pCommand,
                                         char *pReplyBuffer, int iReplBufLen); 
                             int (*GetError)(pEVDriver self, int *iCode,
                                             char *pError, int iErrLen);
                             int (*TryFixIt)(pEVDriver self, int iCode);
                             int (*Init)(pEVDriver self);
                             int (*Close)(pEVDriver self);
                             void *pPrivate;
                             void (*KillPrivate)(void *pData);
                            } EVDriver;
@}

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. 

@d dvfunc @{
/*--------------------------- live & death --------------------------------*/   
  typedef struct __EVControl *pEVControl;
  typedef struct __EVDriver  *pEVDriver;

  pEVControl CreateEVController(pEVDriver pDriv, char *pName, int *iErr);
  void       DeleteEVController(void *pData);

/*-------------------------- driving  ---------------------------------*/
  int EVCDrive(pEVControl self,SConnection *pCon, float fNew);
  int EVCGetPos(pEVControl self, SConnection *pCon,float *fVal);

/*------------------------ parameters ----------------------------------*/
  EVMode EVCGetMode(pEVControl self);
  int    EVCSetMode(pEVControl self, EVMode eNew);
  int EVCSetPar(pEVControl self, char *name, float fNew, SConnection *pCon);
  int EVCGetPar(pEVControl self, char *name, float *fVal);
  int EVCList(pEVControl self, SConnection *pCon);
/*------------------------- logging -----------------------------------*/
   pVarLog EVCGetVarLog(pEVControl self);
/*----------------- Interface to SICS interpreter -----------------------*/
  int EVControlWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
                       int argc, char *argv[]);
  
  int EVControlFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
                       int argc, char *argv[]);
  

@} 
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}

@o evcontroller.h -d @{
/*--------------------------------------------------------------------------
             E N V I R O N M E N T   C O N T R O L L E R

  This is the base class for all environment controllers. 

  Mark Koennecke, Juli 1997

  copyright: see implementation file
----------------------------------------------------------------------------*/
#ifndef SICSEVCONTROL
#define SICSEVCONTROL
#include "varlog.h"
@<dvfunc@>
#endif
@}

@o evcontroller.i -d @{
/*-------------------------------------------------------------------------
    Environment controller datastructure
    
    Mark Koennecke, Juli 1997

---------------------------------------------------------------------------*/
/*-------- Parameter defines */
#define TOLERANCE 0
#define ACCESS 1
#define ERRORHANDLER 2
#define INTERRUPT 3
#define UPLIMIT   4
#define LOWLIMIT  5
#define SAFEVALUE 6

@<evdata@>
@}

@o evdriver.i -d @{
/*-------------------------------------------------------------------------
    Environment device driver datastructure
    
    Mark Koennecke, Juli 1997

---------------------------------------------------------------------------*/
#define DEVOK 1
#define DEVFAULT 0
#define DEVREDO 2

@<evdriv@>
/*-------------------- life & death of  a driver  --------------------------*/
     pEVDriver CreateEVDriver(int argc, char *argv[]);
     void DeleteEVDriver(pEVDriver pDriv);
@}

