\subsection{The Velocity Selector} A velocity selector is a kind of turbine in the neutron beam. Only neutrons which manage to travel through the device between two turbine blades make it through the device, the rest is annihilated in the blades or the turbine housing. Thus, a velocity selector is a kind of monochromator. The behaviour of a velocity selector is determined by two parameters: the rotation speed and the dejustment of the velocity selector to the neutron beam, the tilt angle. The velocity (wavelength) of the neutrons coming through is determined by the rotation speed of the thing. The tilt angle determines the velocity distribution function. Velocity selectors have a few peculiarities due to the fact that they rotate rather quickly. This may give rise to resonances at certain rotation speeds which may damage the device and the surroundings of it. This problem is coped with by having forbidden regions of rotation speeds which cannot be selected. The second implication of the fast rotation is, that the rotation needs to stop or be below a certain threshold before the tilt angle may be changed. So, changing tilt has to go in three steps: first stop rotation, drive tilt, accelerate rotation to the former speed. Tilt is usually controlled by some stepper motor. The rotation speed of the velocity selector needs to be monitored at regular intervalls. If it goes out of tolerances, a error handling procedure must be initiated. Furthermore logging of the rotation speeds of the velocity selector may be required. All this is already realised in the environment controller code. In order to minimise duplication of code, these facilities are implemented by installing a environment controller for the velocity selector. This environement controller will have a dummy driver which does not allow the velocity selector to be driven through the environment controller. An object is installed into the SICServer with the name of the velocity selector and watch appended to it. Through this object such things as tolerances, error handling procedures and logging of velocity selector values can be configured. The only task left for the velocity selector code is to maintain the proper state of the environment controller mode at apropriate places. From this introduction the necessary datastructure for this beast can be easily deduced. Besides the usual objectdescriptor we need: \begin{itemize} \item A list of forbidden regions, realised as a standard linked list of min, max values. \item A motor to drive the tilt with. \item Fields to hold rotation and tilt and some auxilliary parameters. \item Various interrupt to trigger in case of failures. \item As an interface a drivable interface for the rotation is needed in oder to use the device executor for changing rotation speed. \item A pointer to the environment controller object monitoring the velocity selector. \item A driver for actually driving the velocity selector. \end{itemize} A suitable datastructure looks like this: @d data @{ /*------------------ The velocity selector datastructure -----------------*/ typedef struct __VelSel { pObjectDescriptor pDes; char *pName; pIDrivable pDrivInt; pICallBack pCall; int iForbidden; ObPar *pPar; pMotor pTilt; float fRot; float fTilt; pEVControl pMonitor; pVelSelDriv pDriv; } VelSel; /*----------------- Forbidden region single item -------------------------*/ typedef struct __Verbot { float fMin; float fMax; } Verbot, *pVerbot; @} The fields are: \begin{description} \item[pDes] The usual object descriptor. \item[pName] The velocity selector name. \item[pDrivInt] The drivable interface. \item[pCall] The callback interface. \item[iForbidden] The handle to the lsit of forbidden regions. \item[pPar] The velocity selector parameters. \item[pTilt] The motor to use for tilting the turbine. \item[pMonitor] The environment controller object representing the velocity selector in the environment control subsystem. \item[pDriv] The velocity selector driver. \end{description} Verbot is a trivial little data structure holding a single forbidden region for the vlocity selector. This is the structure held in the forbidden list. Please note that the upper and lower limits of the device are held in that list as well. In order to interface with this a few functions will be defined. All functions starts with VS. Functions returning an int return 0 on failure, 1 on success for the rest of this discussion. The first set of functions deals with creating and configuring a velocity selector. @d proto1 @{ typedef struct __VelSel *pVelSel; typedef struct __VelSelDriv *pVelSelDriv; pVelSel VSCreate(pMotor pTilt, pVelSelDriv pDriv); void VSDestroy(void *self); int VSAddVerbot(pVelSel self, float fMin, float fMax); int VSSetPar(pVelSel self,SConnection *pCon, char *name, float fVal); int VSGetPar(pVelSel self,char *name, float *fVal); int VSGetRotation(pVelSel self, float *fRot); int VSGetTilt(pVelSel self, float *fTilt); @} Most functions take a pointer to a velocity selector data structure as first parameter. This parameter is not discussed furtheron. \begin{description} \item[VSCreate] Creates a velocity selector object. A driver and a motor for the tiliting operation need to be given as parameters. On return either a pointer to a newly allocated velocity selector data structure is returned or NULL as indication of failure. The velocity selector will make sure that the tilt motor is only accessible with internal privilege. This effectively reserves the tilt motor to the velocity selector object. This obliges the velocity selector to set a lower privilege while running that motor and to set it back again afterwards. The idea behind this scheme is to prevent a user from accidentally tampering with the tilt motor without passing through the velocity selector interface. \item[VSDestroy] is a function which properly frees all data structures associated with the velocity selector. This is the function to specify as KillFunction for the interpreter. \item[VSAddVerbot] adds a forbidden region between fMin and fmax rotation speeds. \item[VSSetPar, VSGetPar] set and retrive velocity selector parameters. Parameter names given as parameter name are the same as in the user documentation. \item[VSGetRotation] retrieves the current rotation speed. \item[VSGetTilt] retrieves the current tilt angle. \end{description} @d protos2 @{ /* int VSSetRotation(pVelSel self, SConnection *pCon, float fNew); int VSSetTilt(pVelSel self, SConnection *pCon, float FNewTilt); */ int VSSetTiltRot(pVelSel self, SConnection *pCon, float fNewRot, float fNewTilt); @} \begin{description} \item[VSSetTiltRot] sets both rotation speed and tilt angle to new values. \end{description} Please note, that further manipulation functions are hidden in the Drivable interface functions for the rotation which this module defines. Another common task for a velocity selector is to measure its loss current. This is done regularly in order to catch possible problems with the velocity selector early on. @d protos4 @{ int VSGetLossCurrent(pVelSel self, SConnection *pCon, float *fLoss); @} Last not least a velocity selector needs an interface to the interpreter as well. As usual there are two functions: a creation function and a bigger action function which takes the widget commands. @d protos3 @{ int VelSelFactory(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]); int VelSelAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]); @} \subsubsection{The velocity selector driver} As usual for hardware devices in SICS the velocity selector consists of the logical selector described above and a hardware driver which takes care of simulating actual hardware or talking to it. This driver is described here. @d Driver @{ typedef struct __VelSelDriv { void *pPrivate; void (*DeletePrivate)(void *pData); float fTolerance; int (*Halt)(pVelSelDriv self); int (*GetError)(pVelSelDriv self, int *iCode, char *pError, int iErrlen); int (*TryAndFixIt)(pVelSelDriv self, int iCode); int (*GetRotation)(pVelSelDriv self, float *fRot); int (*SetRotation)(pVelSelDriv self, float fRot); int (*GetStatus)(pVelSelDriv self, int *iCall, float *fCur); int (*GetDriverText)(pVelSelDriv self, char *pText, int iTextLen); int (*GetLossCurrent)(pVelSelDriv self, float *fLoss); int (*Init)(pVelSelDriv self, SConnection *pCon); }VelSelDriv; @} pPrivate is an area where individual drivers may store their necessary data. DeletePrivate is a function which will be automatically called when the driver is destroyed with pPrivate passed as parameter. This functions purpose is to destroy pPrivate and remove all memory associated with it. Each driver is resonsible for filling the right thing in here. The description of the rest of the functions is very much like as described for the motor interface. Possible return values for GetStatus can be: \begin{itemize} \item VSNOCON: connection to velocity selector lost. \item VSACCEL: selector accelerating or breaking. \item VSFAIL: velocity selector failure. \item VSOK: all fine, at requested velocity. \end{itemize} Special is the GetDriverText which is meant to return a formatted string of hardware specific information from the device. This is put into pText, but maximum iTextlen characters. Another special is the GetLossCurrent. This is a special self test of the velocity selector which helps to identify possible problems with the device early on. This test must be made regularly and, of course, the driver must support it. Init is meant to do what it says, initialize the velocity selector. This is here in order to support restarting the velocity selector in case of a problem. At the time of writing (Juli 1997) two drivers for velocity selectors exist: a simulation driver and a driver for a Dornier velocity selector run through a Macintosh--PC terminal server communicating with the velocity selector control PC. Please note, that the Dornier program had been slightly modified in order to make this scheme work. @o velo.h -d @{ /*------------------------------------------------------------------------- V E L O C I T Y S E L E C T O R Header file for the SICS velocity selector module. For documentation see velo.w. Mark Koennecke, Juli 1997 copyright: see implementation file -----------------------------------------------------------------------------*/ #ifndef SICSVELO #define SICSVELO /*------------------------- live & death & shape ------------------------*/ @< proto1 @> /*------------------------- drive around -----------------------------------*/ @< protos2 @> @< protos4 @> /*------------------------- Interpreter interface ------------------------*/ @< protos3 @> #endif @} @o velo.i -d @{ /*-------------------------------------------------------------------------- Internal header file describing the velocity selector data structure. Mark Koennecke, Juli, 1997 ----------------------------------------------------------------------------*/ #ifndef VELOINTERNAL #define VELOINTERNAL @< data @> #define VELOREDO 2 #define VELOFAIL 0 #define VELOOK 1 #define VSNOCON 0 #define VSOK 1 #define VSACCEL -7 #define VSFAIL -2 #endif @} @o velodriv.h -d @{ /*-------------------------------------------------------------------------- V E L O C I T Y S E L E C T O R D R I V E R Header file for the velocity selector driver and its related functions. Mark Koennecke, Juli 1997 copyright: see implementation file -----------------------------------------------------------------------------*/ #ifndef VELODRIV #define VELODRIV #include @< Driver @> /*-------------------- live & death ----------------------------------------*/ pVelSelDriv VSCreateSim(void); pVelSelDriv VSCreateDornierSINQ(char *name,Tcl_Interp *pTcl); void VSDeleteDriver(pVelSelDriv self); #endif @}