\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; pICallBack pCall; int callCount; pEVDriver pDriv; EVMode eMode; float fTarget; time_t start; time_t lastt; char *pName; char *driverName; char *errorScript; ObPar *pParam; int iLog; pVarLog pLog; int iWarned; int iTcl; int iStop; SConnection *conn; char *creationArgs; char *runScript; 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. Then there is a pointer to a callback interface. The fifth 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. start and lastt are used to control the settling time. pName is a pointer to a string representing the name of the controller. driverName is the name of the driver used by this device. errorScript is the name of a script command to run when the controller goes out of tolerance. 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. creationArgs are the arguments needed to recreate the device. runScript is a script called on every run or drive command. This script is intended to set control parameters depending on the targetValue. The script is called with the target temperature as argument. 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 (*GetValues)(pEVDriver self, float *fTarget, float *fPos, float *fDelta); 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 (*SavePars)(pEVDriver self, FILE *fil); 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 [SavePars] Saves persistent parameters to status file. \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 stated 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); pEVControl MakeEVController(pEVDriver pDriv, SConnection *pCon, ObjectFunc wrapper, int argc, char *argv[]); /*-------------------------- 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" @ #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 #define MAXWAIT 7 #define SETTLE 8 @ @} @o evdriver.i -d @{ /*------------------------------------------------------------------------- Environment device driver datastructure Mark Koennecke, Juli 1997 ---------------------------------------------------------------------------*/ #define DEVOK 1 #define DEVFAULT 0 #define DEVREDO 2 @ /*-------------------- life & death of a driver --------------------------*/ pEVDriver CreateEVDriver(int argc, char *argv[]); void DeleteEVDriver(pEVDriver pDriv); @}