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