\subsection{Motors} Most neutron scattering instruments have lots of motors to drive monochromators, samples and detectors through space.This module implements support for them. As usual for hardware objects in SICS motors are subdivided into a driver and the logical object. \subsubsection{The Motor Driver} There is a problem here. There are some data fields and functions which must be present for any motor driver. Then there are fields which are specific just to a special implementation of a mot driver. There are several ways to deal with this. The way chosen for the motor driver is a kind of overlay. The first few fields of a valid motor driver structure MUST be specified in the same order as given below. A special motor driver can add additional fields at the end of the standard list. As an example for this scheme compare the AbstractMoDriv structure with the one for the EL734 motor driver. \begin{verbatim} typedef struct __AbstractMoDriv { /* general motor driver interface fields. REQUIRED! */ float fUpper; /* upper limit */ float fLower; /* lower limit */ char *name; int (*GetPosition)(void *self, float *fPos); int (*RunTo)(void *self,float fNewVal); int (*GetStatus)(void *self); void (*GetError)(void *self, int *iCode, char *buffer, int iBufLen); int (*TryAndFixIt)(void *self, int iError,float fNew); int (*ContinueAfterWarn)(void *self); int (*Halt)(void *self); } MotorDriver; \end{verbatim} All functions return 0 on failure or 1 on success, if not stated otherwise. The first parameter is always a pointer to the motor driver structure. The fields and their meanings: \begin{description} \item[fUpper,fLower] The hardware upper and lower limits for the motor. These are the real hardware limits as implemented by limit switches bolted to the instrument. \item[name] The real motor name. \item[GetPosition] retrieves the current hardware position of the motor into fPos. \item[RunTo] starts the motor to run to fNewVal. This sends a command to the motor and returns immediately. \item[GetStatus] requests the status from the motor. Possible answers are: \begin{description} \item[HWIdle, OKOK] The motor has finished or is idle. \item[HWFault] A fault has been found at the motor. \item[HWBusy] The motor is busy moving. \item[HWWarn] The motor hardware complained but managed to reach the requested position. \item[HWPosFault] The motor could not go where it should go for some reason. However, the motor is intact and ready to move somewhere else. This can happen when there is a concrete block in the instruments way which is not accounted for by a limit switch. This can also happen when the motor hits a limit switch. However, the general idea of SICS is that the limits will be checked for before even starting to run the motor. In order for this to work, the limits SICS knows about must macth those actually implemented. \end{description} \item[GetError] This gets called when an error has been detected during one of the previous operations. The function has to return more information about the error: iCode an driver dependent integer error code and maximum iErrLen characters of problem description in error. \item[TryAndFixIt] takes the integer error code returned in iCode from GetError and tries to solve the problem with the hardware. This function can either return MOTREDO which means the problem has been fixed and the operation needs to be redone, MOTOK when the problem has been fixed and no resending of a command is necessary or MOTFAIL which means that it is not possible to resolve the problem in software. \item[ContinueAfterWarn] will be called after a warning from the motor. This function is supposed to do whatever is needed to clear the warning from the motor and keep him going. \item[Halt] emergency stop the motor, NOW. \end{description} As an example for a derived motor driver the SINQ EL734 motor driver is shown below. It add to the general fields the special things for that motor: host, port and channel number of the motor controller and a pointer to the driver communications structure. \begin{verbatim} typedef struct __MoDriv { /* general motor driver interface fields. REQUIRED! */ float fUpper; /* upper limit */ float fLower; /* lower limit */ char *name; int (*GetPosition)(void *self,float *fPos); int (*RunTo)(void *self, float fNewVal); int (*GetStatus)(void *self); void (*GetError)(void *self, int *iCode, char *buffer, int iBufLen); int (*TryAndFixIt)(void *self,int iError, float fNew); int (*ContinueAfterWarn)(void *self); int (*Halt)(void *self); /* EL-734 specific fields */ int iPort; char *hostname; int iChannel; int iMotor; void *EL734struct; int iMSR; } EL734Driv; \end{verbatim} Most of the interaction with the motor driver happens through the functions defined in its data structure. The rest is creation and deletion: \begin{description} \item[MotorDriver *CreateEL734(SConnection *pCon, int argc, char *argv[])] creates a EL734 motor driver. The argc, \verb+argv[]+ pair contains the necessary drive parameters. \item[MotorDriver *CreateEL734DC(SConnection *pCon, int argc, char *argv[])] created an EL734 DC motor driver. \item[void KillEL734(void *pData)] deletes a EL734 motor driver. \item[MotorDriver *CreateSIM(SConnection *pCon, int argc, char *argv[])] creates a simulation motor driver. \item[void KillSIM(void *pData)] deletes a simulated motor driver. \end{description} \subsubsection{The Motor Logical Object} The motor object represents the motor to SICS. One of its responsibilities is to drive motor operations and error checking. The scheme implemented is that the motor object tries to bring the motor to its position at least three times before a failure is recorded. Also the motor object keeps track of a count of failed operations. If this count gets too high an interrupt is issued to stop the instrument. This was put in after Druechal tried to drive over a slab of concrete for a whole night and subsequently broke a clutch. Motors are represented by the following data structure: \begin{verbatim} typedef struct __Motor { pObjectDescriptor pDescriptor; ObPar *ParArray; pIDrivable pDrivInt; pICallBack pCall; char *drivername; char *name; MotorDriver *pDriver; float fTarget; float fPosition; } Motor; typedef Motor *pMotor; \end{verbatim} The fields: \begin{description} \item[pDescriptor] The usual SICS object descriptor. \item[ParArray] A dictionary of parameter names and float values. This array holds all the different parameters used to operate the motor. \item[pDrivInt] A pointer to the drivable interface implemented by the motor object. \item[pCall] A pointer to the callback interface implemented by the motor object. \item[drivername] The name of the motor driver. \item[name] The name of the motor. \item[pDriver] A pointer to the motor driver to use. \item[fTarget] The target position for the motor. \item[fPosition] The last known position of the motor. \end{description} Much of the action of the motor is hidden in the implementation of the drivable interface to the motor. Additionally the functions as given below are defined. All functions take a pointer to the motor object data structure as a parameter. They return 0 on success or 1 on failure while not stated otherwise. \begin{description} \item[int MotorGetPar(pMotor self, char *name, float *fVal)] retrieves the value of the parameter name in fVal. \item[int MotorSetPar(pMotor self, SConnection *pCon, char *name, float fVal)] tries to write fVal to the parameter name. Errors are written to the connection pCon. \item[long MotorRun(void *self, SConnection *pCon, float fNew)] starts a motor running to fNew. Does not wait for the motor to finish. \item[int MotorCheckBoundary(pMotor self, float fVal, float *fHard, char *error, int iErrLen)] checks if the position fVal violates any of the motors software or hardware limits. In case of success a new hardware position is returned in fHard. fHard is then corrected for possible software zero points. In case of a limit violation maximum iErrLen characters of error information are returned in error. \item[int MotorCheckPosition(void *self, SConnection *pCon)] returns 1 if the motor is at the target position, 0 else, or -1 if the motor could not be read. \item[int MotorGetSoftPosition(pMotor self,SConnection *pCon, float *fVal)] reads the current motor position into fVal. This position is corrected for software zero points. \item[int MotorGetHardPosition(pMotor self,SConnection *pCon, float *fVal)] reads the current position of the motor as returned from the hardware. \item[int MakeMotor(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[])] the motor factory function. To be hacked when a new driver needs to be included. \item[pMotor MotorInit(char *drivername,char *name, MotorDriver *pDriv)] creates a new motor object with driver pDriv. Returns NULL on failure. \item[void MotorKill(void *self)] deletes a motor object. Needs to be modified for a new driver in order to clean out the new driver properly. \item[int MotorAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[])] the object wrapper function for the motor. Implements the user interface. \item[pMotor FindMotor(SicsInterp *pSics, char *name)] finds a motor name in the interpreter pSics. This is a convenience function. Returns NULL if no motor could be found, else a pointer to its data structure. \end{description}