#define ident "1D08" #ifdef VAXC #module EL734_Utility ident #endif #ifdef __DECC #pragma module EL734_Utility ident #endif /* ** +--------------------------------------------------------------+ ** | Paul Scherrer Institute | ** | Department ASQ | ** | | ** | This software may be used freely by non-profit organizations.| ** | It may be copied provided that the name of P.S.I. and of the | ** | author is included. Neither P.S.I. nor the author assume any | ** | responsibility for the use of this software outside of P.S.I.| ** +--------------------------------------------------------------+ ** ** Module Name . . . . . . . . : [...LIB.SINQ]EL734_Utility.C ** ** Author . . . . . . . . . . : D. Maden ** Date of creation . . . . . . : Nov 1995 ** ** To compile this module, use: $ import tasmad $ define/group sinq_c_tlb mad_lib:sinq_c.tlb $ cc /debug /noopt /obj=[]EL734_Utility - tasmad_disk:[mad.psi.lib.sinq]EL734_Utility + - sinq_c_tlb/lib ** To include this module in SINQ.OLB, use: $ import tasmad $ define/group sinq_c_tlb mad_lib:sinq_c.tlb $ $ define/group sinq_olb mad_lib:sinq_dbg.olb $ @tasmad_disk:[mad.lib.sinq]sinq_olb EL734_Utility debug $ $ define/group sinq_olb mad_lib:sinq.olb $ @tasmad_disk:[mad.lib.sinq]sinq_olb EL734_Utility ** ** Updates: ** 1A01 2-Nov-1995 DM. Initial version. ** 1B01 21-Mar-1996 DM. Move from DELTAT.OLB to SINQ.OLB. ** 1C01 3-Mar-1997 DM. Add "Forced-close" capability. ** 1C02 14-Apr-1997 DM. Add EL734__BAD_STP to EL734_MoveNoWait. ** 1C11 18-Jun-1998 DM. Modify EL734_GetZeroPoint. ** 1D01 4-Aug-1998 DM. Put messages into a .MSG file. **============================================================================ ** The entry points included in this module are described below. Prototypes ** can be defined via: ** ** #include ** ** EL734_AddCallStack - Add a routine name to the call stack. ** EL734_Close - Close a connection to a motor. ** EL734_Config - Configure a connection to a motor. ** EL734_EncodeMSR - Encode the MSR status into text. ** EL734_EncodeSS - Encode the SS flags into text. ** EL734_ErrInfo - Return detailed status from last operation. ** EL734_GetAirCush - Get W and AC register values. ** EL734_GetEncGearing - Get FD register values. ** EL734_GetId - Get ID register value. ** EL734_GetLimits - Get H register values. ** EL734_GetMotorGearing - Get FM register values. ** EL734_GetNullPoint - Get V register value. ** EL734_GetPosition - Get U register value = current position. ** EL734_GetPrecision - Get A register value. ** EL734_GetRefMode - Get K register value. ** EL734_GetRefParam - Get Q register value. ** EL734_GetSpeeds - Get G, J and E register values. ** EL734_GetStatus - Get MSR/SS/U register values. ** EL734_GetZeroPoint - Get zero-point of motor. ** EL734_MoveNoWait - Move motor and don't wait for completion. ** EL734_MoveWait - Move motor and wait for completion. ** EL734_Open - Open a connection to a motor. ** EL734_PutOffline - Put the EL734 off-line. ** EL734_PutOnline - Put the EL734 on-line. ** EL734_SendCmnd - Send a command to RS232C server. ** EL734_SetAirCush - Set the air-cushion (AC register). ** EL734_SetErrcode - Set up EL734_errcode. ** EL734_SetHighSpeed - Set the max speed (J register). ** EL734_SetLowSpeed - Set the start/stop speed (G register). ** EL734_SetRamp - Set the start/stop ramp (E register). ** EL734_Stop - Send a stop command to motor. ** EL734_WaitIdle - Wait till MSR goes to zero. ** EL734_ZeroStatus - Zero the "ored-MSR" and fault counters. **--------------------------------------------------------------------- ** int EL734_AddCallStack (&handle, &name) ** ------------------ ** Add a routine name to the call stack (internal use). ** Input Args: ** struct EL734info *handle - The pointer to the structure returned by ** EL734_Open. ** char *name - The name to be added to the call stack. ** Output Args: ** none ** Modified Args: ** none ** Return status: ** False if an error is detected, otherwise True. ** Routines called: ** none ** Description: ** If an error has already occurred (EL734_errcode != 0), the routine ** simply returns False. Otherwise, *name is added to the call stack. ** Then *handle is checked. ** If NULL, error EL734__NOT_OPEN is set and False is returned. ** Otherwise, the connection's TCP/IP socket number is checked. ** If zero, error EL734__NO_SOCKET is set and False is returned. ** If negative, error EL734__FORCED_CLOSE is set and False is returned. ** Otherwise, True is returned. **--------------------------------------------------------------------- ** int EL734_Close (&handle, int force_flag) ** ----------- ** Close a connection to a motor. ** Input Args: ** int force_flag - if non-zero, all connections using the same socket ** will also be closed (this gets AsynSrv_Close to ** actually close the socket and is needed for error ** recovery operations). ** Output Args: ** none ** Modified Args: ** void **handle - The pointer to the structure returned by EL734_Open. ** On return, the pointer is set to NULL. ** Return status: ** True always (error returns from close and free are not checked). ** Routines called: ** AsynSrv_Close ** Description: ** The routine calls AsynSrv_Close to close the connection to the RS232C ** server. If 'force_flag' is non-zero, all other connections to the ** RS232C server which use the same socket will also be closed. ** ** The 'force_flag' can be useful in error recovery situations. The AsynSrv ** utility operates by only opening a socket for each separate combination ** of host/port. Hence, if several connections are open to the ** motors on an EL734, then calling EL734_Close doesn't actually close ** the socket until all connections have been closed. In the situation ** where an error has been detected on a motor, it is often desirable to ** close and re-open the socket as part of the recovery procedure. Calling ** EL734_Close with 'force_flag' non-zero will force the socket to be ** closed and will mark all connections using this socket so that they ** will be informed of the event when they next call an EL734_utility ** routine. ** ** Note: The force-close action is effected by the AsynSrv package. A ** force-close will thus also close any connections to other ** RS-232-C devices (e.g. EL737 neutron cntr) on the same server. **------------------------------------------------------------------------- ** int EL734_Config (&handle, &par_id, par_val, ...) ** ------------ ** Configure a connection to a motor. ** Input Args: ** char* par_id - Text string identifying the next argument (see below). ** NULL indicates the end of the argument list. ** par_val - The value to set for the argument. The type of the ** argument can depend on par_id. ** Output Args: ** none ** Modified Args: ** void **handle - The pointer to the structure returned by EL734_Open. ** It is used to hold the config info for the connection. ** Return status: ** True if no problems detected, otherwise False and EL734_errcode ** is set to indicate the nature of the problem as follows: ** EL734__BAD_PAR --> Unrecognised par_id or msecTmo < 100 or ** msecTmo > 999'999 or bad eot or .. ** Routines called: ** none ** Description: ** The routine sets values in the EL734info data structure. Values which ** may be taken by par_id (warning -- par_id is case-sensitive) and the ** corresponding variable type of par_val are: ** ** "msecTmo" int The time-out response for commands sent to ** the EL734. The valid range is 100 to ** 999'999. Default is 10'000. ** "eot" char* The expected terminators in responses to ** commands sent to the EL734. The first ** character specifies the number of ** terminators (max=3). Default is "1\r". ** "motor" int The index of the motor in the range 1-12 to be ** associated with this connection. ** "chan" int The RS-232-C channel number of the EL734 ** controller associated with this connection. **------------------------------------------------------------------------- ** char *EL734_EncodeMSR (&text, text_len, msr, ored_msr, fp_cntr, fr_cntr) ** --------------- ** Encode the MSR status into text. ** Input Args: ** int text_len - The size of text. ** int msr - The current MSR. ** int ored_msr - The 'ored' MSR to be encoded. ** int fp_cntr - The counter of *FP faults. ** int fr_cntr - The counter of *FR faults. ** Output Args: ** char *text - The resulting text string is stored here. ** Modified Args: ** none ** Return status: ** A pointer to "text". ** Routines called: ** none ** Description: ** The routine makes an intelligible message out of the MSR input data. **------------------------------------------------------------------------- ** char *EL734_EncodeSS (&text, text_len, ss) ** -------------- ** Encode the SS flags into text. ** Input Args: ** int text_len - The size of text. ** int ss - The value of SS register. ** Output Args: ** char *text - The resulting text string is stored here. ** Modified Args: ** none ** Return status: ** A pointer to "text". ** Routines called: ** none ** Description: ** The routine makes an intelligible message out of the input SS data. **------------------------------------------------------------------------- ** void EL734_ErrInfo (&entry_txt_ptr, &errcode, &my_errno, &vaxc_errno) ** ------------- ** Return detailed status from last operation. ** Input Args: ** None ** Output Args: ** char **entry_txt_ptr - Pointer to a text string giving the call stack ** at the time that the error was detected. ** int *errcode - An internal error code indicating the detected error. ** int *my_errno - Saved value of errno. ** int *vaxc_errno - Saved value of vaxc$errno (OpenVMS only). ** Modified Args: ** none ** Return status: ** none ** Routines called: ** none ** Description: ** Returns detailed status of the last operation. Once an error has been ** detected, the error status is frozen until this routine has been called. **------------------------------------------------------------------------- ** int EL734_GetAirCush (&handle, &present, &state) ** ---------------- ** Get W and AC register values. ** Input Args: ** void **handle - The pointer to the structure returned by EL734_Open. ** Output Args: ** int *present - The W register. If non-zero, motor has an air-cushion. ** int *state - The AC register. If non-zero, air-cushion is up. ** Description: ** The routine is the same as EL734_GetEncGearing except that it issues ** a "W" command and then an "AC" command instead of an "FD" command to ** the controller. **------------------------------------------------------------------------- ** int EL734_GetEncGearing (&handle, &numerator, &denominator) ** ------------------- ** Get FD register values. ** Input Args: ** void **handle - The pointer to the structure returned by EL734_Open. ** Output Args: ** int *numerator - The encoder gearing numerator. ** int *denominator - The encoder gearing denominator. ** Modified Args: ** none ** Return status: ** True if no problems detected, otherwise False and EL734_ErrInfo ** can be called to identify the problem. Values of Errcode set by ** EL734_GetEncGearing are (other values may be set by the called ** routines): ** EL734__BAD_TMO, BAD_LOC, BAD_CMD, BAD_OFL, ** BAD_ADR, EMERG_STOP --> see EL734_Open. ** EL734__BAD_ILLG --> the response was probably not 2 integers. ** This could happen if there is noise on the ** RS232C connection to the EL734. ** If an error is detected, *numerator and *denominator are set to 0. ** Routines called: ** EL734_AddCallStack, AsynSrv_SendCmnds, AsynSrv_GetReply ** Description: ** The routine issues an "FD" command to the controller and analyses ** the result. The two parameters of the "FD" command are the numerator ** and denominator respectively. **------------------------------------------------------------------------- ** int EL734_GetId (&handle, &id_txt, id_len) ** ----------- ** Get ID register value. ** Input Args: ** void **handle - The pointer to the structure returned by EL734_Open. ** int id_len - The size of the buffer in bytes. ** Output Args: ** char *id_txt - The EL734 identifier ("ID" parameter). ** Description: ** The routine is the same as EL734_GetEncGearing except that it issues ** an "ID" command instead of an "H" command to the controller. **------------------------------------------------------------------------- ** int EL734_GetLimits (&handle, &lo, &hi) ** --------------- ** Get H register values. ** Input Args: ** void **handle - The pointer to the structure returned by EL734_Open. ** Output Args: ** float *lo - The lower software limit. ** float *hi - The higher software limit. ** Description: ** The routine is the same as EL734_GetEncGearing except that it issues ** an "H" command instead of an "FD" command to the controller. **------------------------------------------------------------------------- ** int EL734_GetMotorGearing (&handle, &numerator, &denominator) ** --------------------- ** Get FM register values. ** Input Args: ** void **handle - The pointer to the structure returned by EL734_Open. ** Output Args: ** int *numerator - The motor gearing numerator. ** int *denominator - The motor gearing denominator. ** Description: ** The routine is the same as EL734_GetEncGearing except that it issues ** an "FM" command instead of an "FD" command to the controller. The ** two parameters of the "FM" command are the numerator and denominator ** respectively. **------------------------------------------------------------------------- ** int EL734_GetNullPoint (&handle, &null_pt) ** ------------------ ** Get V register value. ** Input Args: ** void **handle - The pointer to the structure returned by EL734_Open. ** Output Args: ** int *null_pt - The null point ("V" parameter) of the EL734. ** Description: ** The routine is the same as EL734_GetEncGearing except that it issues ** a "V" command instead of an "FD" command to the controller. **------------------------------------------------------------------------- ** int EL734_GetPosition (&handle, &ist_posit) ** ----------------- ** Get U register value = current position. ** Input Args: ** void **handle - The pointer to the structure returned by EL734_Open. ** Output Args: ** float *ist_posit - The current position (U command) of the motor. ** Description: ** The routine is the same as EL734_GetEncGearing except that it issues ** a "U" command instead of an "FD" command to the controller. **------------------------------------------------------------------------- ** int EL734_GetPrecision (&handle, &n_dec) ** ------------------ ** Get A register value. ** Input Args: ** void **handle - The pointer to the structure returned by EL734_Open. ** Output Args: ** int *n_dec - The precision ("A" parameter) of the EL734. ** Description: ** The routine is the same as EL734_GetEncGearing except that it issues ** a "A" command instead of an "FD" command to the controller. **------------------------------------------------------------------------- ** int EL734_GetRefMode (&handle, &mode) ** ---------------- ** Get K register value. ** Input Args: ** void **handle - The pointer to the structure returned by EL734_Open. ** Output Args: ** int *mode - The reference seek mode ("K" parameter) of the EL734. ** Description: ** The routine is the same as EL734_GetEncGearing except that it issues ** a "K" command instead of an "FD" command to the controller. **------------------------------------------------------------------------- ** int EL734_GetRefParam (&handle, ¶m) ** ----------------- ** Get Q register value. ** Input Args: ** void **handle - The pointer to the structure returned by EL734_Open. ** Output Args: ** float *param - The reference seek param ("Q" parameter) of the EL734. ** Description: ** The routine is the same as EL734_GetEncGearing except that it issues ** a "Q" command instead of an "FD" command to the controller. **------------------------------------------------------------------------- ** int EL734_GetSpeeds (&handle, &lo, &hi, &ramp) ** --------------- ** Get G, J and E register values. ** Input Args: ** void **handle - The pointer to the structure returned by EL734_Open. ** Output Args: ** int *lo - The start/stop speed (G register). Units = Steps/sec. ** int *hi - The maximum speed (J register). Units = Steps/sec. ** int *ramp - The start/stop ramp (E register). Units = kHz/sec. ** Description: ** The routine is the same as EL734_GetEncGearing except that it issues ** a "G", "J" and "E" commands instead of an "FD" command to the ** controller. **------------------------------------------------------------------------- ** int EL734_GetStatus (&handle, &msr, &ored_msr, &fp_cntr, &fr_cntr, ** --------------- &ss, &ist_posit) ** Get MSR/SS/U register values. ** Input Args: ** void **handle - The pointer to the structure returned by EL734_Open. ** Output Args: ** int *msr - The MSR register. ** int *ored_msr - The 'ored'-MSR register. This gets zeroed every time ** a 'positioning' command is executed. ** int *fp_cntr - A counter of the 'Position Faults' (*FP). This gets ** zeroed whenever ored_msr is zeroed. ** int *fr_cntr - A counter of the 'Run Faults' (*FR). This gets ** zeroed whenever ored_msr is zeroed. ** int *ss - The SS register. This will be -1 if the motor is busy. ** float *ist_posit - The current position (U command) of the motor. ** Modified Args: ** none ** Return status: ** True if no problems detected, otherwise False and EL734_ErrInfo ** can be called to identify the problem. Values of Errcode set by ** EL734_GetStatus are (other values may be set by the called routines): ** EL734__BAD_TMO, BAD_LOC, BAD_CMD, BAD_OFL, ** BAD_ADR, EMERG_STOP --> see EL734_Open. ** EL734__BAD_ILLG --> one of the responses could probably not ** be decoded. This could happen if there is noise ** on the RS232C connection to the EL734. ** If an error is detected, ist_posit is set to 0.0 and all other ** arguments to -1. ** Routines called: ** EL734_AddCallStack, AsynSrv_SendCmnds, AsynSrv_GetReply ** Description: ** The routine issues an "MSR", "SS" and "U" command to the controller and ** analyses the result. A count is kept of each time the *FP and *FR bits ** are found to be set and an inclusive-or value of MSR is maintained. **------------------------------------------------------------------------- ** int EL734_GetZeroPoint (&handle, &zero_pt) ** ------------------ ** Get zero-point of motor. ** Input Args: ** void **handle - The pointer to the structure returned by EL734_Open. ** Output Args: ** float *zero_pt - The zero point of the EL734. ** Return status: ** Any of the errors generated by the called routines is possible plus: ** EL734__BAD_OVFL --> The encoder gearing ratio is zero so ** the conversion would overflow. ** Routines called: ** EL734_AddCallStack, EL734_GetEncGearing, EL734_GetNullPoint ** Description: ** This routine returns the zero point of the motor in the same units ** as used by the "P" and "U" commands. In other words, it reads the ** "V" parameter and converts it from "encoder-step" units to physical ** units using the encoder-gearing parameters. **------------------------------------------------------------------------- ** int EL734_MoveNoWait (&handle, soll_posit) ** ---------------- ** Move motor and don't wait for completion. ** Input Args: ** void **handle - The pntr to the structure returned by EL734_Open. ** float soll_posit - The position to which the motor should move. ** Output Args: ** none ** Modified Args: ** none ** Return status: ** True if no problems detected, otherwise False and EL734_ErrInfo ** can be called to identify the problem. Values of Errcode set by ** EL734_MoveNoWait are (other values may be set by the called routines): ** EL734__BAD_TMO, BAD_LOC, BAD_CMD, BAD_OFL, ** BAD_ADR, EMERG_STOP --> see EL734_Open. ** EL734__BAD_RNG --> Destination is out-of-range. ** EL734__BAD_STP --> Motor is disabled via Hardware "Stop" ** signal. ** EL734__BAD_ILLG --> some other response obtained from EL734. ** This could happen if there is noise ** on the RS232C connection to the EL734. ** Routines called: ** EL734_AddCallStack, AsynSrv_SendCmnds, AsynSrv_GetReply ** Description: ** The appropriate "P" command is sent to the motor and the response ** checked to check that it has been accepted. The fields "ored_msr", ** "fp_cntr" and "fr_cntr" in the handle are cleared, if so. **------------------------------------------------------------------------- ** int EL734_MoveWait (&handle, soll_posit, &ored_msr, &fp_cntr, &fr_cntr, ** -------------- &ist_posit) ** Move motor and wait for completion. ** Input Args: ** void **handle - The pntr to the structure returned by EL734_Open. ** float soll_posit - The position to which the motor should move. ** Output Args: ** int *ored_msr \ ** int *fp_cntr \ Same as EL734_WaitIdle. ** int *fr_cntr / ** float *ist_posit / ** none ** Modified Args: ** none ** Return status: ** True if no problems detected, otherwise False. If False, errcode (see ** EL734_ErrInfo) will have been set by EL734_MoveNoWait or EL734_WaitIdle. ** Routines called: ** EL734_AddCallStack, EL734_MoveNoWait, EL734_WaitIdle ** Description: ** The routine calls EL734_MoveNoWait and, if successful, EL734_WaitIdle. **------------------------------------------------------------------------- ** int EL734_Open (&handle, host, port, chan, motor, id) ** ---------- ** Open a connection to a motor. ** Input Args: ** char *host - Name of host offering the TCP/IP service. ** int port - Number of TCP/IP port of TCP/IP server. ** int chan - RS-232-C Channel number on the TCP/IP server. ** int motor - The motor to be driven. ** char *id - The expected ID of the device, normally "STPMC EL734". ** If id is NULL, the device ID is not checked. ** Output Args: ** void *handle - A pointer to a structure of type EL734info needed for ** subsequent calls to EL734_... routines. Buffer space ** for the structure is allocated dynamically. It gets ** released via a call to EL734_Close. ** Modified Args: ** none ** Return status: ** True if no problems detected, otherwise False. If False, EL734_ErrInfo ** can be called to identify the problem. Values of Errcode set by ** EL734_Open are (other values may be set by the called routines): ** EL734__BAD_TMO --> Time-out error ("?TMO" - this gets ** generated by the RS232C server). ** EL734__BAD_LOC --> EL734 off-line ("?LOC"). This should not ** happen on calls to EL734_Open since it ** sends an "RMT 1" cmnd. ** EL734__BAD_CMD --> Command error ("?CMD"). This could be ** caused by noise in the RS-232-C ** transmission. ** EL734__BAD_OFL --> Connection to EL734 broken ("?OFL"). ** This can get generated by RS232C_SRV ** if, for example, the connection is via ** a terminal server and the terminal ** server loses power. ** EL734__BAD_ILLG --> Some other unrecognised response. This ** should never occur, of course! ** EL734__BAD_SOCKET --> Call to "AsynSrv_Open" failed. ** EL734__BAD_DEV --> Device has wrong ID ** EL734__BAD_MALLOC --> Call to "malloc" failed ** EL734__BAD_ADR --> Bad motor address ("?ADR"). Probably ** a non-existent motor has been addressed. ** EL734__EMERG_STOP --> Emergency stop ("*ES") detected. ** Routines called: ** AsynSrv_Open, the memory alloc routine "malloc", StrJoin, ** EL734_Config, AsynSrv_SendCmnds, AsynSrv_GetReply, ** AsynSrv_Close (if an error is detected). ** Description: ** The routine calls AsynSrv_Open to open a TCP/IP connection to a server ** offering the "RS-232-C" service for an EL734 Motor Controller. "RMT 1" ** and "ECHO 0" commands are sent to ensure the device is on-line, an "ID" ** command is sent (only if 'id' is non-NULL) to ensure that an EL734 is ** being addressed and an "MSR " command is sent to ensure that ** the motor exists. ** Note: ** For all error status returns, there is no open connection to the server ** and the handle is set to zero. **------------------------------------------------------------------------- ** int EL734_PutOffline (&handle) ** ---------------- ** Send "ECHO 1" and "RMT 0" commands to EL734 server. ** Input Args: ** void **handle - The pntr to the structure returned by EL734_Open. ** Output Args: ** none ** Modified Args: ** none ** Return status: ** True if no problems detected, otherwise False and errcode (see ** EL734_ErrInfo) is set to indicate the nature of the problem. ** Values of Errcode set by EL734_PutOffline are (other values may be set ** by the called routines): ** EL734__BAD_ASYNSRV --> An error occurred in AsynSrv_Utility. ** Call AsynSrv_ErrInfo for more info. ** EL734__BAD_ILLG --> an unrecognised response. This ** should never occur, of course! ** Routines called: ** EL734_AddCallStack, AsynSrv_SendCmnds, AsynSrv_GetReply ** Description: ** The routine calls AsynSrv_SendCmnds to execute "RMT 1", "ECHO 1" ** and "RMT 0" commands. The replies are checked. **------------------------------------------------------------------------- ** int EL734_PutOnline (&handle, echo) ** --------------- ** Send "RMT 1" and "ECHO x" commands to EL734 server. ** Input Args: ** void **handle - The pntr to the structure returned by EL734_Open. ** int echo - The value for the ECHO command. ** Output Args: ** none ** Modified Args: ** none ** Return status: ** True if no problems detected, otherwise False and errcode (see ** EL734_ErrInfo) is set to indicate the nature of the problem. ** Values of Errcode set by EL734_PutOnline are (other values may be set ** by the called routines): ** EL734__BAD_PAR --> "echo" is not 0, 1 or 2. ** EL734__BAD_ASYNSRV --> An error occurred in AsynSrv_Utility. ** Call AsynSrv_ErrInfo for more info. ** EL734__BAD_ILLG --> an unrecognised response. This ** should never occur, of course! ** Routines called: ** EL734_AddCallStack, AsynSrv_SendCmnds, AsynSrv_GetReply ** Description: ** The routine calls AsynSrv_SendCmnds to execute "RMT 1" and "ECHO x" ** commands. The replies are checked. **------------------------------------------------------------------------- ** int EL734_SendCmnd (&handle, &cmnd, &rply, rply_size) ** -------------- ** Send a command to RS232C server. ** Input Args: ** void **handle - The pntr to the structure returned by EL734_Open. ** char *cmnd - A command, terminated by NULL, for sending to the ** EL734 counter controller. The command must have ** any necessary \r character included. ** int rply_size - the size of the buffer. ** Output Args: ** char *rply - A buffer for receiving the reply. ** Modified Args: ** none ** Return status: ** True if no problems detected, otherwise False and errcode (see ** EL734_ErrInfo) is set to indicate the nature of the problem. ** Values of Errcode set by EL734_SendCmnd are (other values may be set ** by the called routines): ** EL734__BAD_ASYNSRV --> An error occurred in AsynSrv_Utility. ** Call AsynSrv_ErrInfo for more info. ** Routines called: ** EL734_AddCallStack, AsynSrv_SendCmnds, AsynSrv_GetReply ** Description: ** The command is passed to AsynSrv_SendCmnds and the reply extracted. **------------------------------------------------------------------------- ** int EL734_SetAirCush (&handle, state) ** ---------------- ** Set AC register value. ** Input Args: ** void **handle - The pointer to the structure returned by EL734_Open. ** Input Args: ** int state - The new state of the AC register. 0 --> down ** non-zero --> up ** Output Args: ** none ** Modified Args: ** none ** Return status: ** True if no problems detected, otherwise False and EL734_ErrInfo ** can be called to identify the problem. Values of Errcode set by ** EL734_SetAirCush are (other values may be set by the called ** routines): ** EL734__BAD_TMO, BAD_LOC, BAD_CMD, BAD_OFL, ** BAD_ADR, EMERG_STOP --> see EL734_Open. ** EL734__VFY_ERR --> the value for the AC register returned by the ** call to EL734_GetAirCush was not the value which ** was sent via the AC command. This could happen ** if there is noise on the RS232C connection to ** the EL734. ** Routines called: ** EL734_AddCallStack, AsynSrv_SendCmnds, AsynSrv_GetReply, ** EL734_GetAirCush ** Description: ** The routine issues an "AC" command to the controller to set the air- ** cushions of the motor up or down. It then calls EL734_GetAirCush ** to check that the air-cushions were set correctly. **------------------------------------------------------------------------- ** int EL734_SetErrcode (&info_ptr, &response, &cmnd) ** ---------------- ** Set up EL734_errcode (for internal use only) ** Input Args: ** struct EL734info *info_ptr - The pntr to the structure returned by ** EL734_Open. ** char *response - The response received from a command. ** char *cmnd - The command which was sent. ** Output Args: ** none ** Modified Args: ** none ** Return status: ** The value of EL734_errcode. ** Routines called: ** AsynSrv_SendCmnds ** Description: ** The command checks *response for certain keywords. If not recognised, ** extra action is undertaken to try to see if the emergency stop state ** is active or not. **------------------------------------------------------------------------- ** int EL734_SetHighSpeed (&handle, hi) ** ------------------ ** Set J register value. ** Input Args: ** void **handle - The pointer to the structure returned by EL734_Open. ** Input Args: ** int hi - The maximum speed (J register). Units = Steps/sec. ** Output Args: ** none ** Modified Args: ** none ** Return status: ** True if no problems detected, otherwise False and EL734_ErrInfo ** can be called to identify the problem. Values of Errcode set by ** EL734_SetHighSpeed are (other values may be set by the called ** routines): ** EL734__BAD_TMO, BAD_LOC, BAD_CMD, BAD_OFL, ** BAD_ADR, EMERG_STOP --> see EL734_Open. ** EL734__VFY_ERR --> the value for the J register returned by the call ** to EL734_GetSpeeds was not the value which was ** sent via the J command. This could happen if ** there is noise on the RS232C connection to ** the EL734. ** Routines called: ** EL734_AddCallStack, AsynSrv_SendCmnds, AsynSrv_GetReply, EL734_GetSpeeds ** Description: ** The routine issues a "J" command to the controller to set the max speed ** of the motor. It then calls EL734_GetSpeeds to check that the speed ** was set correctly. **------------------------------------------------------------------------- ** int EL734_SetLowSpeed (&handle, hi) ** ----------------- ** Set G register value. ** Input Args: ** void **handle - The pointer to the structure returned by EL734_Open. ** Input Args: ** int lo - The start/stop speed (G register). Units = Steps/sec. ** Description: ** The routine is identical to the EL734_SetHighSpeed routine except that ** a "G" command rather than a "J" command is issued to the controller to ** set the start/stop speed. **------------------------------------------------------------------------- ** int EL734_SetRamp (&handle, ramp) ** ------------- ** Set E register value. ** Input Args: ** void **handle - The pointer to the structure returned by EL734_Open. ** Input Args: ** int ramp - The start/stop ramp (E register). Units = kHz/sec. ** Description: ** The routine is identical to the EL734_SetHighSpeed routine except that ** an "E" command rather than a "J" command is issued to the controller to ** set the start/stop ramp. **------------------------------------------------------------------------- ** int EL734_Stop (&handle) ** ---------- ** Send a stop command to motor ** Input Args: ** void **handle - The pointer to the structure returned by EL734_Open. ** Output Args: ** None ** Description: ** The routine is similar to EL734_GetEncGearing except that it issues ** a "Q m" command instead of an "FD" command to the controller and ** a null response (rather than parameter values) is expected. **------------------------------------------------------------------------- ** int EL734_WaitIdle (&handle, &ored_msr, &fp_cntr, &fr_cntr, &ist_posit) ** -------------- ** Wait till MSR goes to zero. ** Input Args: ** void **handle - The pntr to the structure returned by EL734_Open. ** Output Args: ** int *ored_msr \ ** int *fp_cntr \ Same as EL734_GetStatus. ** int *fr_cntr / ** float *ist_posit / ** none ** Modified Args: ** none ** Return status: ** True if no problems detected, otherwise False and Errcode (see ** EL734_ErrInfo) will have been set by the called routines to indicate ** the nature of the problem. ** Routines called: ** EL734_AddCallStack, EL734_GetStatus ** Description: ** Routine EL734_GetStatus is called repeatedly at a predefined frequency ** until the MSR__BUSY bit in the MSR register is zero. **------------------------------------------------------------------------- ** void EL734_ZeroStatus (&handle) ** ----------------- ** Zero the "ored-MSR" and fault counters. ** Input Args: ** void **handle - The pntr to the structure returned by EL734_Open. ** Output Args: ** none ** Modified Args: ** none ** Return status: ** none ** Routines called: ** none ** Description: ** The "ored-MSR" and fault counters in the handle are zeroed. **============================================================================*/ /* **--------------------------------------------------------------------------- ** Global Definitions */ #include #include #include #include #include #include #include #include #include #ifdef __VMS #include #else #include #ifdef FORTIFY #include #endif #endif /*-----------------------------------------------------------------*/ #include #include #include #include #define True 1 #define False 0 /*-------------------------------------------------------------------------- ** Global Variables */ static int EL734_call_depth = 0; static char EL734_routine[5][64]; static int EL734_errcode = 0; static int EL734_errno, EL734_vaxc_errno; char EL734_IllgText[256]; /* **--------------------------------------------------------------------------- ** EL734_AddCallStack: Add a routine name to the call stack. ** This allows EL734_ErrInfo to generate a ** trace-back in case of error. */ int EL734_AddCallStack( /* ================== */ struct EL734info *pntr, char *name) { if (EL734_errcode != 0) return False; if (EL734_call_depth < 5) { strcpy(EL734_routine[EL734_call_depth], name); EL734_call_depth++; } if (pntr == NULL) { EL734_errcode = EL734__NOT_OPEN; return False; } if (pntr->asyn_info.skt <= 0) { memset(pntr->from_host.msg_size, '0', sizeof(pntr->from_host.msg_size)); EL734_errcode = (pntr->asyn_info.skt < 0) ? EL734__FORCED_CLOSED : EL734__NO_SOCKET; return False; } return True; } /* **--------------------------------------------------------------------------- ** EL734_Close: Close a connection to a motor. */ int EL734_Close( /* =========== */ void **handle, int force_flag) { struct EL734info *info_ptr; char buff[4]; info_ptr = (struct EL734info *) *handle; if (info_ptr == NULL) return True; if (info_ptr->asyn_info.skt != 0) { if (info_ptr->asyn_info.skt > 0) { AsynSrv_Close(*handle, force_flag); } } free(*handle); *handle = NULL; return True; } /* **--------------------------------------------------------------------------- ** EL734_Config: Configure a connection to a motor. */ int EL734_Config( /* ============ */ void **handle, ...) { char buff[16]; va_list ap; /* Pointer to variable args */ char *txt_ptr; int intval; struct EL734info *info_ptr; /*---------------------------------------------- */ info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_Config")) return False; /*---------------------------------------------- */ va_start(ap, handle); /* Set up var arg machinery */ txt_ptr = va_arg(ap, char *); /* Get pntr to first parameter ident */ while (txt_ptr != NULL) { if (strcmp(txt_ptr, "msecTmo") == 0) { intval = va_arg(ap, int); if ((intval < 100) || (intval > 999999)) { EL734_errcode = EL734__BAD_PAR; return False; } sprintf(buff, "%04d", intval / 100); /* Convert to ASCII as .. ** .. deci-secs */ memcpy(info_ptr->asyn_info.tmo, buff, 4); } else if (strcmp(txt_ptr, "eot") == 0) { txt_ptr = va_arg(ap, char *); if (txt_ptr == NULL) { EL734_errcode = EL734__BAD_PAR; return False; } memcpy(info_ptr->asyn_info.eot, "\0\0\0\0", 4); switch (txt_ptr[0]) { case '3': info_ptr->asyn_info.eot[3] = txt_ptr[3]; case '2': info_ptr->asyn_info.eot[2] = txt_ptr[2]; case '1': info_ptr->asyn_info.eot[1] = txt_ptr[1]; case '0': info_ptr->asyn_info.eot[0] = txt_ptr[0]; break; default: EL734_errcode = EL734__BAD_PAR; return False; } } else if (strcmp(txt_ptr, "motor") == 0) { intval = va_arg(ap, int); if ((intval < 1) || (intval > 12)) { EL734_errcode = EL734__BAD_PAR; return False; } info_ptr->motor = intval; } else if (strcmp(txt_ptr, "chan") == 0) { intval = va_arg(ap, int); if ((intval < 0) || (intval > 255)) { EL734_errcode = EL734__BAD_PAR; return False; } info_ptr->asyn_info.chan = intval; sprintf(buff, "%04d", intval); /* Convert to ASCII */ memcpy(info_ptr->asyn_info.chan_char, buff, 4); } else { EL734_errcode = EL734__BAD_PAR; return False; } txt_ptr = va_arg(ap, char *); /* Get pntr to next parameter ident */ } if (EL734_errcode != 0) return False; EL734_call_depth--; return True; } /* **--------------------------------------------------------------------------- ** EL734_EncodeMSR: Encode the MSR status into text. */ char *EL734_EncodeMSR(char *text, int text_len, /* =============== */ int msr, int ored_msr, int fp_cntr, int fr_cntr) { int len; char my_text[132]; char my_text_0[32]; if (msr == 0) { ored_msr = ored_msr & ~(MSR__BUSY); /* Zero "Busy" bit */ if (ored_msr == MSR__OK) { StrJoin(text, text_len, "Status, MSR = Idle. Positioned OK.", ""); } else { if ((ored_msr & MSR__OK) != 0) { StrJoin(text, text_len, "Status, MSR = Idle. Positioned OK. ", ""); } else { StrJoin(text, text_len, "Status, MSR = Idle. ", ""); } if ((ored_msr & MSR__REF_OK) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); StrJoin(text, text_len, my_text, "Ref. Pos'n OK. "); } if ((ored_msr & MSR__LIM_ERR) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); StrJoin(text, text_len, my_text, "Limit Switch Problem. "); } if ((ored_msr & MSR__AC_FAIL) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); StrJoin(text, text_len, my_text, "Air-Cushion Error. "); } if ((ored_msr & MSR__REF_FAIL) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); StrJoin(text, text_len, my_text, "Ref. Pos'n Fail. "); } if ((ored_msr & MSR__POS_FAIL) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); StrJoin(text, text_len, my_text, "Pos'n Fail. "); } if ((ored_msr & MSR__POS_FAULT) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); if (fp_cntr == 1) { StrJoin(text, text_len, my_text, "1 Pos'n Fault. "); } else { sprintf(my_text_0, "%d Pos'n Faults. ", fp_cntr); StrJoin(text, text_len, my_text, my_text_0); } } if ((ored_msr & MSR__RUN_FAIL) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); StrJoin(text, text_len, my_text, "Run Fail. "); } if ((ored_msr & MSR__RUN_FAULT) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); if (fr_cntr == 1) { StrJoin(text, text_len, my_text, "1 Run Fault. "); } else { sprintf(my_text_0, "%d Run Faults. ", fr_cntr); StrJoin(text, text_len, my_text, my_text_0); } } if ((ored_msr & MSR__HALT) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); StrJoin(text, text_len, my_text, "Halt. "); } if ((ored_msr & MSR__HI_LIM) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); StrJoin(text, text_len, my_text, "Hit HiLim. "); } if ((ored_msr & MSR__LO_LIM) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); StrJoin(text, text_len, my_text, "Hit LoLim. "); } if ((ored_msr & MSR__STOPPED) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); StrJoin(text, text_len, my_text, "Stopped. "); } } } else if ((msr & ~(0x2fff)) != 0) { StrJoin(text, text_len, "Status, MSR = ??", ""); } else { sprintf(my_text, "%#x ", msr); StrJoin(text, text_len, "Status, MSR = ", my_text); if ((msr & MSR__LIM_ERR) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); StrJoin(text, text_len, my_text, "Limit Switch Problem/"); } if ((msr & MSR__AC_FAIL) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); StrJoin(text, text_len, my_text, "Air-Cushion Error/"); } if ((msr & MSR__REF_FAIL) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); StrJoin(text, text_len, my_text, "Ref. Pos'n Fail/"); } if ((msr & MSR__POS_FAIL) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); StrJoin(text, text_len, my_text, "Pos'n Fail/"); } if ((msr & MSR__POS_FAULT) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); StrJoin(text, text_len, my_text, "Pos'n Fault/"); } if ((msr & MSR__RUN_FAIL) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); StrJoin(text, text_len, my_text, "Run Fail/"); } if ((msr & MSR__RUN_FAULT) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); StrJoin(text, text_len, my_text, "Run Fault/"); } if ((msr & MSR__HALT) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); StrJoin(text, text_len, my_text, "Halt/"); } if ((msr & MSR__HI_LIM) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); StrJoin(text, text_len, my_text, "Hit HiLim/"); } if ((msr & MSR__LO_LIM) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); StrJoin(text, text_len, my_text, "Hit LoLim/"); } if ((msr & MSR__STOPPED) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); StrJoin(text, text_len, my_text, "Stopped/"); } if ((msr & MSR__REF_OK) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); StrJoin(text, text_len, my_text, "Ref. Pos'n OK/"); } if ((msr & MSR__OK) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); StrJoin(text, text_len, my_text, "OK/"); } if ((msr & MSR__BUSY) != 0) { StrJoin(my_text, sizeof(my_text), text, ""); StrJoin(text, text_len, my_text, "Busy/"); } len = strlen(text); text[len - 1] = '\0'; } return text; } /* **--------------------------------------------------------------------------- ** EL734_EncodeSS: Encode the SS flags into text. */ char *EL734_EncodeSS(char *text, int text_len, int ss) { /* ============== */ int len; char my_text[132]; char my_text_0[32]; if (ss == 0) { StrJoin(text, text_len, "Flags, SS = 0", ""); } else if ((ss & ~(0x3f)) != 0) { StrJoin(text, text_len, "Flags, SS = ??", ""); } else { sprintf(my_text, "Flags, SS = 0x%02X ", ss); my_text_0[0] = '\0'; if ((ss & 0x20) != 0) strcat(my_text_0, "LSX/"); if ((ss & 0x10) != 0) strcat(my_text_0, "LS2/"); if ((ss & 0x08) != 0) strcat(my_text_0, "LS1/"); if ((ss & 0x04) != 0) strcat(my_text_0, "STP/"); if ((ss & 0x02) != 0) strcat(my_text_0, "CCW/"); if ((ss & 0x01) != 0) strcat(my_text_0, "HLT/"); len = strlen(my_text_0); my_text_0[len - 1] = '\0'; StrJoin(text, text_len, my_text, my_text_0); } return text; } /* **------------------------------------------------------------------------- ** EL734_ErrInfo: Return detailed status from last operation. */ void EL734_ErrInfo( /* ============= */ char **entry_txt, int *errcode, int *my_errno, int *vaxc_errno) { int i; char buff[80], *txt; int asyn_errcode, asyn_errno, asyn_vaxerrno; char *asyn_errtxt; if (EL734_call_depth <= 0) { strcpy(EL734_routine[0], "EL734_no_error_detected"); *errcode = 0; *my_errno = 0; *vaxc_errno = 0; } else { if (EL734_call_depth > 1) { /* Concatenate the names */ for (i = 1; i < EL734_call_depth; i++) { strcat(EL734_routine[0], "/"); StrJoin(EL734_routine[0], sizeof(EL734_routine), EL734_routine[0], EL734_routine[i]); } } *errcode = EL734_errcode; *my_errno = EL734_errno; *vaxc_errno = EL734_vaxc_errno; switch (EL734_errcode) { case EL734__BAD_ADR: txt = "/EL734__BAD_ADR"; break; case EL734__BAD_ASYNSRV: txt = "/EL734__BAD_ASYNSRV"; break; case EL734__BAD_CMD: txt = "/EL734__BAD_CMD"; break; case EL734__BAD_DEV: txt = "/EL734__BAD_DEV"; break; case EL734__BAD_ILLG: txt = "/EL734__BAD_ILLG"; break; case EL734__BAD_LOC: txt = "/EL734__BAD_LOC"; break; case EL734__BAD_MALLOC: txt = "/EL734__BAD_MALLOC"; break; case EL734__BAD_OFL: txt = "/EL734__BAD_OFL"; break; case EL734__BAD_OVFL: txt = "/EL734__BAD_OVFL"; break; case EL734__BAD_PAR: txt = "/EL734__BAD_PAR"; break; case EL734__BAD_RNG: txt = "/EL734__BAD_RNG"; break; case EL734__BAD_SOCKET: txt = "/EL734__BAD_SOCKET"; break; case EL734__BAD_STP: txt = "/EL734__BAD_STP"; break; case EL734__BAD_TMO: txt = "/EL734__BAD_TMO"; break; case EL734__EMERG_STOP: txt = "/EL734__EMERG_STOP"; break; case EL734__FORCED_CLOSED: txt = "/EL734__FORCED_CLOSED"; break; case EL734__NOT_OPEN: txt = "/EL734__NOT_OPEN"; break; case EL734__NO_SOCKET: txt = "/EL734__NO_SOCKET"; break; default: sprintf(buff, "/EL734__unknown_err_code: %d", EL734_errcode); txt = buff; } StrJoin(EL734_routine[0], sizeof(EL734_routine), EL734_routine[0], txt); } AsynSrv_ErrInfo(&asyn_errtxt, &asyn_errcode, &asyn_errno, &asyn_vaxerrno); if (asyn_errcode != 0) { strcat(EL734_routine[0], "/"); StrJoin(EL734_routine[0], sizeof(EL734_routine), EL734_routine[0], asyn_errtxt); } *entry_txt = EL734_routine[0]; EL734_call_depth = 0; EL734_errcode = 0; } /* **--------------------------------------------------------------------------- ** EL734_GetAirCush: Get W and AC register values. */ int EL734_GetAirCush( /* ================ */ void **handle, int *present, int *state) { int status; struct EL734info *info_ptr; char cmnd0[10], cmnd1[10]; char *rply_ptr, *rply_ptr0, *rply_ptr1; /*---------------------------------------------- */ *present = *state = 0; info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_GetAirCush")) return False; /*---------------------------------------------- ** Send W and AC cmnds to EL734 */ sprintf(cmnd0, "w %d\r", info_ptr->motor); sprintf(cmnd1, "ac %d\r", info_ptr->motor); status = AsynSrv_SendCmnds(&info_ptr->asyn_info, &info_ptr->to_host, &info_ptr->from_host, cmnd0, cmnd1, NULL); if (!status) { *present = *state = 0; EL734_errcode = EL734__BAD_ASYNSRV; return False; } else { rply_ptr1 = NULL; rply_ptr0 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL); if (rply_ptr0 != NULL) rply_ptr1 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, rply_ptr0); if (rply_ptr0 == NULL) rply_ptr0 = "?no_response"; if (rply_ptr1 == NULL) rply_ptr1 = "?no_response"; if ((sscanf(rply_ptr0, "%d", present) != 1) || (sscanf(rply_ptr1, "%d", state) != 1)) { if (*rply_ptr0 == '?') { rply_ptr = rply_ptr0; } else if (*rply_ptr1 == '?') { rply_ptr = rply_ptr1; } else { rply_ptr = "?funny_response"; } *present = *state = 0; EL734_SetErrcode(info_ptr, rply_ptr, "W\" or \"AC"); return False; } } if (EL734_errcode != 0) return False; EL734_call_depth--; return True; } /* **--------------------------------------------------------------------------- ** EL734_GetEncGearing: Get FD register values. */ int EL734_GetEncGearing( /* =================== */ void **handle, int *nominator, int *denominator) { int status; struct EL734info *info_ptr; char cmnd0[10]; char *rply_ptr0; /*---------------------------------------------- */ *nominator = *denominator = 0; info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_GetEncGearing")) return False; /*---------------------------------------------- ** Send FD cmnd to EL734 */ sprintf(cmnd0, "fd %d\r", info_ptr->motor); status = AsynSrv_SendCmnds(&info_ptr->asyn_info, &info_ptr->to_host, &info_ptr->from_host, cmnd0, NULL); if (!status) { *nominator = *denominator = 0; EL734_errcode = EL734__BAD_ASYNSRV; return False; } else { rply_ptr0 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL); if (rply_ptr0 == NULL) rply_ptr0 = "?no_response"; if (sscanf(rply_ptr0, "%d %d", nominator, denominator) == 2) { if (EL734_errcode != 0) return False; EL734_call_depth--; return True; } *nominator = *denominator = 0; EL734_SetErrcode(info_ptr, rply_ptr0, "FD"); return False; } } /* **--------------------------------------------------------------------------- ** EL734_GetId: Get ID register value. */ int EL734_GetId( /* =========== */ void **handle, char *id_txt, int id_len) { int status; struct EL734info *info_ptr; char *rply_ptr0; /*---------------------------------------------- */ *id_txt = '\0'; info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_GetId")) return False; /*---------------------------------------------- ** Send ID cmnd to EL734 */ status = AsynSrv_SendCmnds(&info_ptr->asyn_info, &info_ptr->to_host, &info_ptr->from_host, "id\r", NULL); if (!status) { EL734_errcode = EL734__BAD_ASYNSRV; return False; } else { rply_ptr0 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL); if ((rply_ptr0 != NULL) && (*rply_ptr0 != '\0') && (*rply_ptr0 != '?')) { StrJoin(id_txt, id_len, rply_ptr0, ""); if (EL734_errcode != 0) return False; EL734_call_depth--; return True; } if (rply_ptr0 == NULL) rply_ptr0 = "?no_response"; EL734_SetErrcode(info_ptr, rply_ptr0, "ID"); return False; } } /* **--------------------------------------------------------------------------- ** EL734_GetLimits: Get H register values. */ int EL734_GetLimits( /* =============== */ void **handle, float *lo, float *hi) { int status; struct EL734info *info_ptr; char cmnd0[10]; char *rply_ptr0; /*---------------------------------------------- */ *lo = *hi = 0.0; info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_GetLimits")) return False; /*---------------------------------------------- ** Send H cmnd to EL734 */ sprintf(cmnd0, "h %d\r", info_ptr->motor); status = AsynSrv_SendCmnds(&info_ptr->asyn_info, &info_ptr->to_host, &info_ptr->from_host, cmnd0, NULL); if (!status) { *lo = *hi = 0.0; EL734_errcode = EL734__BAD_ASYNSRV; return False; } else { rply_ptr0 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL); if (rply_ptr0 == NULL) rply_ptr0 = "?no_response"; if (sscanf(rply_ptr0, "%f %f", lo, hi) == 2) { if (EL734_errcode != 0) return False; EL734_call_depth--; return True; } *lo = *hi = 0.0; EL734_SetErrcode(info_ptr, rply_ptr0, "H"); return False; } } /* **--------------------------------------------------------------------------- ** EL734_GetMotorGearing: Get FM register values. */ int EL734_GetMotorGearing( /* ===================== */ void **handle, int *nominator, int *denominator) { int status; struct EL734info *info_ptr; char cmnd0[10]; char *rply_ptr0; /*---------------------------------------------- */ *nominator = *denominator = 0; info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_GetMotorGearing")) return False; /*---------------------------------------------- ** Send FM cmnd to EL734 */ sprintf(cmnd0, "fm %d\r", info_ptr->motor); status = AsynSrv_SendCmnds(&info_ptr->asyn_info, &info_ptr->to_host, &info_ptr->from_host, cmnd0, NULL); if (!status) { *nominator = *denominator = 0; EL734_errcode = EL734__BAD_ASYNSRV; return False; } else { rply_ptr0 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL); if (rply_ptr0 == NULL) rply_ptr0 = "?no_response"; if (sscanf(rply_ptr0, "%d %d", nominator, denominator) == 2) { if (EL734_errcode != 0) return False; EL734_call_depth--; return True; } *nominator = *denominator = 0; EL734_SetErrcode(info_ptr, rply_ptr0, "FM"); return False; } } /* **--------------------------------------------------------------------------- ** EL734_GetNullPoint: Get V register value. */ int EL734_GetNullPoint( /* ================== */ void **handle, int *null_pt) { int status; struct EL734info *info_ptr; char cmnd0[10]; char *rply_ptr0; /*---------------------------------------------- */ *null_pt = 0; info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_GetNullPoint")) return False; /*---------------------------------------------- ** Send V cmnd to EL734 */ sprintf(cmnd0, "v %d\r", info_ptr->motor); status = AsynSrv_SendCmnds(&info_ptr->asyn_info, &info_ptr->to_host, &info_ptr->from_host, cmnd0, NULL); if (!status) { *null_pt = 0; EL734_errcode = EL734__BAD_ASYNSRV; return False; } else { rply_ptr0 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL); if (rply_ptr0 == NULL) rply_ptr0 = "?no_response"; if (sscanf(rply_ptr0, "%d", null_pt) == 1) { if (EL734_errcode != 0) return False; EL734_call_depth--; return True; } *null_pt = 0; EL734_SetErrcode(info_ptr, rply_ptr0, "V"); return False; } } /* **--------------------------------------------------------------------------- ** EL734_GetPosition: Get U register value, the current position. */ int EL734_GetPosition( /* ================= */ void **handle, float *ist_posit) { int status; struct EL734info *info_ptr; char cmnd0[10]; char *rply_ptr0; /*---------------------------------------------- */ *ist_posit = 0.0; info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_GetPosition")) return False; /*---------------------------------------------- ** Send U cmnd to EL734 */ sprintf(cmnd0, "u %d\r", info_ptr->motor); status = AsynSrv_SendCmnds(&info_ptr->asyn_info, &info_ptr->to_host, &info_ptr->from_host, cmnd0, NULL); if (!status) { *ist_posit = 0.0; EL734_errcode = EL734__BAD_ASYNSRV; return False; } else { rply_ptr0 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL); if (rply_ptr0 == NULL) rply_ptr0 = "?no_response"; if (sscanf(rply_ptr0, "%f", ist_posit) == 1) { if (EL734_errcode != 0) return False; EL734_call_depth--; return True; } *ist_posit = 0.0; EL734_SetErrcode(info_ptr, rply_ptr0, "U"); return False; } } /* **--------------------------------------------------------------------------- ** EL734_GetPrecision: Get A register value. */ int EL734_GetPrecision( /* ================== */ void **handle, int *n_dec) { int status; struct EL734info *info_ptr; char cmnd0[10]; char *rply_ptr0; /*---------------------------------------------- */ *n_dec = 3; info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_GetPrecision")) return False; /*---------------------------------------------- ** Send A cmnd to EL734 */ sprintf(cmnd0, "a %d\r", info_ptr->motor); status = AsynSrv_SendCmnds(&info_ptr->asyn_info, &info_ptr->to_host, &info_ptr->from_host, cmnd0, NULL); if (!status) { *n_dec = 3; EL734_errcode = EL734__BAD_ASYNSRV; return False; } else { rply_ptr0 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL); if (rply_ptr0 == NULL) rply_ptr0 = "?no_response"; if (sscanf(rply_ptr0, "%d", n_dec) == 1) { if (EL734_errcode != 0) return False; EL734_call_depth--; return True; } *n_dec = 3; EL734_SetErrcode(info_ptr, rply_ptr0, "A"); return False; } } /* **--------------------------------------------------------------------------- ** EL734_GetRefMode: Get K register value. */ int EL734_GetRefMode( /* ================ */ void **handle, int *mode) { int status; struct EL734info *info_ptr; char cmnd0[10]; char *rply_ptr0; /*---------------------------------------------- */ *mode = 0; info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_GetRefMode")) return False; /*---------------------------------------------- ** Send K cmnd to EL734 */ sprintf(cmnd0, "k %d\r", info_ptr->motor); status = AsynSrv_SendCmnds(&info_ptr->asyn_info, &info_ptr->to_host, &info_ptr->from_host, cmnd0, NULL); if (!status) { *mode = 0; EL734_errcode = EL734__BAD_ASYNSRV; return False; } else { rply_ptr0 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL); if (rply_ptr0 == NULL) rply_ptr0 = "?no_response"; if (sscanf(rply_ptr0, "%d", mode) == 1) { if (EL734_errcode != 0) return False; EL734_call_depth--; return True; } *mode = 0; EL734_SetErrcode(info_ptr, rply_ptr0, "K"); return False; } } /* **--------------------------------------------------------------------------- ** EL734_GetRefParam: Get Q register value. */ int EL734_GetRefParam( /* ================= */ void **handle, float *param) { int status; struct EL734info *info_ptr; char cmnd0[10]; char *rply_ptr0; /*---------------------------------------------- */ *param = 0.0; info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_GetRefParam")) return False; /*---------------------------------------------- ** Send Q cmnd to EL734 */ sprintf(cmnd0, "q %d\r", info_ptr->motor); status = AsynSrv_SendCmnds(&info_ptr->asyn_info, &info_ptr->to_host, &info_ptr->from_host, cmnd0, NULL); if (!status) { *param = 0.0; EL734_errcode = EL734__BAD_ASYNSRV; return False; } else { rply_ptr0 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL); if (rply_ptr0 == NULL) rply_ptr0 = "?no_response"; if (sscanf(rply_ptr0, "%f", param) == 1) { if (EL734_errcode != 0) return False; EL734_call_depth--; return True; } *param = 0.0; EL734_SetErrcode(info_ptr, rply_ptr0, "Q"); return False; } } /* **--------------------------------------------------------------------------- ** EL734_GetSpeeds: Get G/J/E register values. */ int EL734_GetSpeeds( /* =============== */ void **handle, int *lo, int *hi, int *ramp) { int status; struct EL734info *info_ptr; char cmnd0[10]; char cmnd1[10]; char cmnd2[10]; char *rply_ptr; char *rply_ptr0; char *rply_ptr1; char *rply_ptr2; /*---------------------------------------------- */ *lo = *hi = *ramp = 0; info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_GetSpeeds")) return False; /*---------------------------------------------- ** Send G, J and E cmnds to EL734 */ sprintf(cmnd0, "g %d\r", info_ptr->motor); sprintf(cmnd1, "j %d\r", info_ptr->motor); sprintf(cmnd2, "e %d\r", info_ptr->motor); status = AsynSrv_SendCmnds(&info_ptr->asyn_info, &info_ptr->to_host, &info_ptr->from_host, cmnd0, cmnd1, cmnd2, NULL); if (!status) { *lo = *hi = *ramp = 0; EL734_errcode = EL734__BAD_ASYNSRV; return False; } else { rply_ptr1 = rply_ptr2 = NULL; rply_ptr0 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL); if (rply_ptr0 != NULL) rply_ptr1 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, rply_ptr0); if (rply_ptr1 != NULL) rply_ptr2 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, rply_ptr1); if (rply_ptr0 == NULL) rply_ptr0 = "?no_response"; if (rply_ptr1 == NULL) rply_ptr1 = "?no_response"; if (rply_ptr2 == NULL) rply_ptr2 = "?no_response"; if ((sscanf(rply_ptr0, "%d", lo) != 1) || (sscanf(rply_ptr1, "%d", hi) != 1) || (sscanf(rply_ptr2, "%d", ramp) != 1)) { if (*rply_ptr0 == '?') { rply_ptr = rply_ptr0; } else if (*rply_ptr1 == '?') { rply_ptr = rply_ptr1; } else if (*rply_ptr2 == '?') { rply_ptr = rply_ptr2; } else { rply_ptr = "?funny_response"; } *lo = *hi = *ramp = 0; EL734_SetErrcode(info_ptr, rply_ptr, "G\", \"J\" or \"E"); return False; } } if (EL734_errcode != 0) return False; EL734_call_depth--; return True; } /* **--------------------------------------------------------------------------- ** EL734_GetStatus: Get MSR/SS/U register values. */ int EL734_GetStatus( /* =============== */ void **handle, int *msr, int *ored_msr, int *fp_cntr, int *fr_cntr, int *ss, float *ist_posit) { int status; struct EL734info *info_ptr; char cmnd0[10]; char cmnd1[10]; char cmnd2[10]; char *rply_ptr; char *rply_ptr0; char *rply_ptr1; char *rply_ptr2; /*---------------------------------------------- */ *msr = *ored_msr = *fp_cntr = *fr_cntr = *ss = -1; *ist_posit = 0.0; info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_GetStatus")) return False; /*---------------------------------------------- ** Send MSR, SS and U cmnds to EL734 */ sprintf(cmnd0, "msr %d\r", info_ptr->motor); sprintf(cmnd1, "ss %d\r", info_ptr->motor); sprintf(cmnd2, "u %d\r", info_ptr->motor); status = AsynSrv_SendCmnds(&info_ptr->asyn_info, &info_ptr->to_host, &info_ptr->from_host, cmnd0, cmnd1, cmnd2, NULL); if (!status) { *msr = *ored_msr = *fp_cntr = *fr_cntr = *ss = -1; *ist_posit = 0.0; EL734_errcode = EL734__BAD_ASYNSRV; return False; } else { rply_ptr1 = rply_ptr2 = NULL; rply_ptr0 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL); if (rply_ptr0 != NULL) rply_ptr1 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, rply_ptr0); if (rply_ptr1 != NULL) rply_ptr2 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, rply_ptr1); if (rply_ptr0 == NULL) rply_ptr0 = "?no_response"; if (rply_ptr1 == NULL) rply_ptr1 = "?no_response"; if (rply_ptr2 == NULL) rply_ptr2 = "?no_response"; if ((sscanf(rply_ptr0, "%x", msr) == 1) && (sscanf(rply_ptr2, "%f", ist_posit) == 1)) { info_ptr->ored_msr = info_ptr->ored_msr | *msr; if ((*msr & MSR__POS_FAULT) != 0) info_ptr->fp_cntr++; if ((*msr & MSR__RUN_FAULT) != 0) info_ptr->fr_cntr++; *ored_msr = info_ptr->ored_msr; *fp_cntr = info_ptr->fp_cntr; *fr_cntr = info_ptr->fr_cntr; /* Remember: we may get "?BSY" for SS and ** this should not be treated as an error! */ if (sscanf(rply_ptr1, "%x", ss) != 1) *ss = -1; } else { if (*rply_ptr0 == '?') { rply_ptr = rply_ptr0; } else if (*rply_ptr1 == '?') { rply_ptr = rply_ptr1; } else if (*rply_ptr2 == '?') { rply_ptr = rply_ptr2; } else { rply_ptr = "?funny_response"; } *msr = *ored_msr = *fp_cntr = *fr_cntr = *ss = -1; *ist_posit = 0.0; EL734_SetErrcode(info_ptr, rply_ptr, "MSR\", \"SS\" or \"U"); return False; } } if (EL734_errcode != 0) return False; EL734_call_depth--; return True; } /* **--------------------------------------------------------------------------- ** EL734_GetZeroPoint: Get zero point (= converted V register value) */ int EL734_GetZeroPoint( /* ================== */ void **handle, float *zero_pt) { int status, null_pt, nom, denom; struct EL734info *info_ptr; char cmnd0[10]; char *rply_ptr0; /*---------------------------------------------- */ *zero_pt = 0.0; info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_GetZeroPoint")) return False; /*---------------------------------------------- ** Get V register value. */ status = EL734_GetNullPoint(handle, &null_pt); if (!status) return False; /*---------------------------------------------- ** FD register values. */ status = EL734_GetEncGearing(handle, &nom, &denom); if (!status) return False; if (nom == 0) { EL734_errcode = EL734__BAD_OVFL; /* Encoder gearing ratio is zero */ return False; } *zero_pt = ((float) denom) / ((float) nom); *zero_pt *= (float) null_pt; if (EL734_errcode != 0) return False; EL734_call_depth--; return True; } /* **--------------------------------------------------------------------------- ** EL734_MoveNoWait: Move motor and don't wait for completion. */ int EL734_MoveNoWait( /* ================ */ void **handle, float soll_posit) { int status; struct EL734info *info_ptr; char cmnd0[32]; char *rply_ptr0; /*---------------------------------------------- */ info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_MoveNoWait")) return False; /*---------------------------------------------- ** Send P cmnd to EL734 */ sprintf(cmnd0, "p %d %.3f\r", info_ptr->motor, soll_posit); status = AsynSrv_SendCmnds(&info_ptr->asyn_info, &info_ptr->to_host, &info_ptr->from_host, cmnd0, NULL); if (!status) { EL734_errcode = EL734__BAD_ASYNSRV; return False; } else { rply_ptr0 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL); if (rply_ptr0 == NULL) rply_ptr0 = "?no_response"; if (*rply_ptr0 == '\0' || *rply_ptr0 == '\r') { /* ** The command was accepted - so zero the statistics ** fields in the handle and return to caller. */ info_ptr->ored_msr = info_ptr->fp_cntr = info_ptr->fr_cntr = 0; if (EL734_errcode != 0) return False; EL734_call_depth--; return True; } EL734_SetErrcode(info_ptr, rply_ptr0, "P"); return False; } } /* **--------------------------------------------------------------------------- ** EL734_MoveWait: Move motor and wait for completion. */ int EL734_MoveWait( /* ============== */ void **handle, float soll_posit, int *ored_msr, int *fp_cntr, int *fr_cntr, float *ist_posit) { int status; struct EL734info *info_ptr; /*---------------------------------------------- */ *ored_msr = *fp_cntr = *fr_cntr = -1; *ist_posit = 0.0; info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_MoveWait")) return False; /*---------------------------------------------- ** Start the movement. */ status = EL734_MoveNoWait(handle, soll_posit); if (status) { status = EL734_WaitIdle(handle, ored_msr, fp_cntr, fr_cntr, ist_posit); } if (status && (EL734_errcode == 0)) EL734_call_depth--; if (EL734_errcode != 0) return False; return status; } /* **--------------------------------------------------------------------------- ** EL734_Open: Open a connection to a motor. */ int EL734_Open( /* ========== */ void **handle, char *host, int port, int chan, int motor, char *device_id) { int my_msr, status; struct EL734info *my_handle; char tmo_save[4]; char msr_cmnd[20]; char *rply_ptr; char *rply_ptr0; char *rply_ptr1; char *rply_ptr2; char *rply_ptr3; /*-------------------------------------------------------- ** Initialise the error info stack and pre-set the ** routine name (in case of error). */ EL734_errcode = EL734_errno = EL734_vaxc_errno = 0; strcpy(EL734_routine[0], "EL734_Open"); EL734_call_depth = 1; /*-------------------------------------------------------- ** Assume trouble */ *handle = NULL; /*-------------------------------------------------------- ** Reserve space for the data we need to store. */ my_handle = (struct EL734info *) malloc(sizeof(*my_handle)); if (my_handle == NULL) { EL734_errcode = EL734__BAD_MALLOC; /* malloc failed!! */ return False; } memset(my_handle, 0, sizeof(*my_handle)); /*-------------------------------------------------------- ** Set up the connection */ StrJoin(my_handle->asyn_info.host, sizeof(my_handle->asyn_info.host), host, ""); my_handle->asyn_info.port = port; my_handle->asyn_info.chan = chan; status = AsynSrv_Open(&my_handle->asyn_info); if (!status) { EL734_errcode = EL734__BAD_SOCKET; GetErrno(&EL734_errno, &EL734_vaxc_errno); /* Save errno info */ fprintf(stderr, "\nEL734_Open/AsynSrv_Open: " "Failed to make connection.\n"); free(my_handle); return False; } memcpy(tmo_save, my_handle->asyn_info.tmo, 4); /* Save time-out */ EL734_Config((void *) &my_handle, "msecTmo", 500, /* Set a short time-out initially since ** there should be no reason for the RMT, ** ECHO or ID commands to take very long. */ "eot", "1\r", "motor", motor, NULL); my_handle->ored_msr = 0; my_handle->fp_cntr = 0; my_handle->fr_cntr = 0; /* ** Now ensure the EL734 is on-line. The first "RMT 1" command can ** fail due to pending characters in the EL734 input buffer causing ** the "RMT 1" to be corrupted. The response of the EL734 to this ** command is ignored for this reason (but the AsynSrv_SendCmnds ** status must be OK otherwise it indicates a network problem). */ status = AsynSrv_SendCmnds(&my_handle->asyn_info, &my_handle->to_host, &my_handle->from_host, "rmt 1\r", NULL); sprintf(msr_cmnd, "msr %d\r", motor); if (status) { if (device_id != NULL) { status = AsynSrv_SendCmnds(&my_handle->asyn_info, &my_handle->to_host, &my_handle->from_host, "rmt 1\r", "echo 0\r", "id\r", msr_cmnd, NULL); } else { status = AsynSrv_SendCmnds(&my_handle->asyn_info, &my_handle->to_host, &my_handle->from_host, "rmt 1\r", "echo 0\r", "echo 0\r", msr_cmnd, NULL); } } memcpy(my_handle->asyn_info.tmo, tmo_save, 4); /* Restore time-out */ if (!status) { /* Some error occurred in AsynSrv_SendCmnds */ EL734_errcode = EL734__BAD_ASYNSRV; AsynSrv_Close(&my_handle->asyn_info, False); free(my_handle); return False; } else { /* Check the responses carefully. The 3rd response should ** be the device identifier (if to be checked). The 4th ** response should be a hex integer. ** MK: But first we check for *ES, emergency stop. ** The desired behaviour is that we continue in this ** case and hope for the best. */ rply_ptr1 = rply_ptr2 = rply_ptr3 = NULL; rply_ptr0 = AsynSrv_GetReply(&my_handle->asyn_info, &my_handle->from_host, NULL); if (rply_ptr0 != NULL) rply_ptr1 = AsynSrv_GetReply(&my_handle->asyn_info, &my_handle->from_host, rply_ptr0); if (rply_ptr1 != NULL) rply_ptr2 = AsynSrv_GetReply(&my_handle->asyn_info, &my_handle->from_host, rply_ptr1); if (rply_ptr2 != NULL) rply_ptr3 = AsynSrv_GetReply(&my_handle->asyn_info, &my_handle->from_host, rply_ptr2); if (rply_ptr0 == NULL) rply_ptr0 = "?no_response"; if (rply_ptr1 == NULL) rply_ptr1 = "?no_response"; if (rply_ptr2 == NULL) rply_ptr2 = "?no_response"; if (rply_ptr3 == NULL) rply_ptr3 = "?no_response"; if (strstr(rply_ptr0, "*ES") != NULL) { *handle = my_handle; EL734_call_depth--; return True; } if (*rply_ptr1 == '?') rply_ptr0 = rply_ptr1; if (*rply_ptr2 == '?') rply_ptr0 = rply_ptr2; if (*rply_ptr3 == '?') rply_ptr0 = rply_ptr3; if (*rply_ptr0 != '?') { if (device_id != NULL) { /* Check device ID? */ if (*rply_ptr2 == '\0') { /* Yes. But if response is blank, it ** may be because Emergency Stop is set. */ EL734_SetErrcode(my_handle, rply_ptr2, "ID"); AsynSrv_Close(&my_handle->asyn_info, False); free(my_handle); return False; } else { if (strncmp(rply_ptr2, device_id, strlen(device_id)) != 0) { EL734_errcode = EL734__BAD_DEV; /* Device has wrong ID */ AsynSrv_Close(&my_handle->asyn_info, False); free(my_handle); return False; } } } if (sscanf(rply_ptr3, "%x", &my_msr) != 1) { /* MSR response is bad */ EL734_SetErrcode(my_handle, rply_ptr3, msr_cmnd); /* Check for *ES */ if (EL734_errcode != EL734__EMERG_STOP) EL734_errcode = EL734__BAD_DEV; AsynSrv_Close(&my_handle->asyn_info, False); free(my_handle); return False; } /* ** The connection is complete. Pass the data structure ** back to the caller as a handle. */ *handle = my_handle; if (EL734_errcode != 0) return False; EL734_call_depth--; return True; } else { EL734_errcode = EL734__BAD_DEV; if (strcmp(rply_ptr0, "?OFL") == 0) EL734_errcode = EL734__BAD_OFL; if (strcmp(rply_ptr0, "?CMD") == 0) EL734_errcode = EL734__BAD_CMD; if (strcmp(rply_ptr0, "?LOC") == 0) EL734_errcode = EL734__BAD_LOC; if (strcmp(rply_ptr0, "?ADR") == 0) EL734_errcode = EL734__BAD_ADR; if (strcmp(rply_ptr0, "*ES") == 0) EL734_errcode = EL734__EMERG_STOP; if (strncmp(rply_ptr0, "?TMO", 4) == 0) EL734_errcode = EL734__BAD_TMO; if (EL734_errcode == EL734__BAD_DEV) fprintf(stderr, " Unrecognised initial response: \"%s\"\n", rply_ptr0); } } AsynSrv_Close(&my_handle->asyn_info, False); free(my_handle); return False; } /* **--------------------------------------------------------------------------- ** EL734_PutOffline: put the EL734 off-line */ int EL734_PutOffline( /* ================ */ void **handle) { int status; struct EL734info *info_ptr; char *rply_ptr0, *rply_ptr1, *rply_ptr2; /*---------------------------------------------- */ info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_PutOffline")) return False; /*---------------------------------------------- ** The problem which this routine has is that the EL734 ** may already be off-line. The following is, therefore, ** rather pedantic for most cases which occur in practice. */ status = AsynSrv_SendCmnds(&info_ptr->asyn_info, &info_ptr->to_host, &info_ptr->from_host, "\r", "rmt 1\r", "echo 1\r", "rmt 0\r", NULL); if (!status) { EL734_errcode = EL734__BAD_ASYNSRV; return False; } status = AsynSrv_SendCmnds(&info_ptr->asyn_info, &info_ptr->to_host, &info_ptr->from_host, "RMT\r", "", NULL); if (!status) { EL734_errcode = EL734__BAD_ASYNSRV; return False; } rply_ptr0 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL); rply_ptr1 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, rply_ptr0); if (rply_ptr0 == NULL) rply_ptr0 = "?no_response"; if (rply_ptr1 == NULL) rply_ptr1 = "?no_response"; if ((strcmp(rply_ptr0, "RMT") == 0) && (strcmp(rply_ptr1, "\n0") == 0)) { EL734_call_depth--; return True; } EL734_SetErrcode(info_ptr, rply_ptr0, "RMT"); return False; } /* **--------------------------------------------------------------------------- ** EL734_PutOnline: put the EL734 on-line */ int EL734_PutOnline( /* =============== */ void **handle, int echo) { int status, my_echo; struct EL734info *info_ptr; char cmnd0[10]; char *rply_ptr0; /*---------------------------------------------- */ info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_PutOnline")) return False; /*---------------------------------------------- */ if ((echo != 0) && (echo != 1) && (echo != 2)) { EL734_errcode = EL734__BAD_PAR; return False; } /*---------------------------------------------- ** The problem which this routine has is that the state ** of the EL734 is not known. The following is, therefore, ** rather pedantic for most cases which occur in practice. */ sprintf(cmnd0, "echo %d\r", echo); status = AsynSrv_SendCmnds(&info_ptr->asyn_info, &info_ptr->to_host, &info_ptr->from_host, "\r", "rmt 1\r", cmnd0, NULL); if (!status) { EL734_errcode = EL734__BAD_ASYNSRV; return False; } status = AsynSrv_SendCmnds(&info_ptr->asyn_info, &info_ptr->to_host, &info_ptr->from_host, "echo\r", NULL); if (!status) { EL734_errcode = EL734__BAD_ASYNSRV; return False; } rply_ptr0 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL); if (rply_ptr0 == NULL) rply_ptr0 = "?no_response"; if (strcmp(rply_ptr0, "ECHO") == 0) { rply_ptr0 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, rply_ptr0); if (rply_ptr0 == NULL) rply_ptr0 = "?no_response"; } if ((sscanf(rply_ptr0, "%d", &my_echo) == 1) && (my_echo == echo)) { EL734_call_depth--; return True; } EL734_SetErrcode(info_ptr, rply_ptr0, "ECHO"); return False; } /* **--------------------------------------------------------------------------- ** EL734_SendCmnd - Send a command to RS232C server. */ int EL734_SendCmnd( /* ============== */ void **handle, char *cmnd, char *rply, int rply_size) { struct EL734info *info_ptr; int my_status; char *rply_ptr; /*---------------------------------------------- */ info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_SendCmnd")) return False; /*---------------------------------------------- ** Send command to EL734. */ my_status = AsynSrv_SendCmnds(&info_ptr->asyn_info, &info_ptr->to_host, &info_ptr->from_host, cmnd, NULL); if (!my_status) { EL734_errcode = EL734__BAD_ASYNSRV; return False; } else { rply_ptr = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL); if (rply_ptr == NULL) rply_ptr = "?no_response"; StrJoin(rply, rply_size, rply_ptr, ""); } if (EL734_errcode != 0) return False; EL734_call_depth--; return True; } /* **--------------------------------------------------------------------------- ** EL734_SetAirCush: Set the air-cushion register (AC register) */ int EL734_SetAirCush( /* ================ */ void **handle, int state) { int status, dum1, my_state; struct EL734info *info_ptr; char cmnd0[32]; char *rply_ptr0; /*---------------------------------------------- */ info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_SetAirCush")) return False; /*---------------------------------------------- ** Send AC cmnd to EL734 */ if (state != 0) state = 1; sprintf(cmnd0, "ac %d %d\r", info_ptr->motor, state); status = AsynSrv_SendCmnds(&info_ptr->asyn_info, &info_ptr->to_host, &info_ptr->from_host, cmnd0, NULL); if (!status) { EL734_errcode = EL734__BAD_ASYNSRV; return False; } else { rply_ptr0 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL); if (rply_ptr0 == NULL) rply_ptr0 = "?no_response"; if (*rply_ptr0 == '\0') { /* ** The command was accepted - check value is set OK. */ status = EL734_GetAirCush(handle, &dum1, &my_state); if (!status) return False; if (state != my_state) { EL734_errcode = EL734__VFY_ERR; return False; } EL734_call_depth--; return True; } EL734_SetErrcode(info_ptr, rply_ptr0, "AC"); return False; } } /* **--------------------------------------------------------------------------- ** EL734_SetErrcode - Set up EL734_errcode */ int EL734_SetErrcode( /* ================ */ struct EL734info *info_ptr, char *response, char *cmnd) { int status; char *rply; char tmo_save[4]; char eot_save[4]; EL734_errcode = EL734__BAD_ILLG; if (strcmp(response, "?OFL") == 0) EL734_errcode = EL734__BAD_OFL; if (strcmp(response, "?CMD") == 0) EL734_errcode = EL734__BAD_CMD; if (strcmp(response, "?LOC") == 0) EL734_errcode = EL734__BAD_LOC; if (strcmp(response, "?ADR") == 0) EL734_errcode = EL734__BAD_ADR; if (strcmp(response, "?RNG") == 0) EL734_errcode = EL734__BAD_RNG; if (strcmp(response, "*ES") == 0) EL734_errcode = EL734__EMERG_STOP; if (strcmp(response, "*MS") == 0) EL734_errcode = EL734__BAD_STP; if (strncmp(response, "?TMO", 4) == 0) EL734_errcode = EL734__BAD_TMO; if (EL734_errcode != EL734__BAD_ILLG) return EL734_errcode; /* ** The response is not recognised. Perhaps the emergency stop ** signal is set. To check this, it is necessary to turn off ** terminator checking since the EL734 prefixes its "*ES" ** response with a character. We also therefore set ** a very short time-out. */ memcpy(tmo_save, info_ptr->asyn_info.tmo, 4); /* Save time-out */ memcpy(eot_save, info_ptr->asyn_info.eot, 4); /* Save terminators */ AsynSrv_Config(&info_ptr->asyn_info, "msecTmo", 100, /* Set short time-out */ "eot", "0", /* Set no terminator */ NULL); status = AsynSrv_SendCmnds(&info_ptr->asyn_info, &info_ptr->to_host, &info_ptr->from_host, "ID\r", NULL); memcpy(info_ptr->asyn_info.eot, eot_save, 4); /* Restore terminators */ memcpy(info_ptr->asyn_info.tmo, tmo_save, 4); /* Restore time-out */ if (status) { rply = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL); if (rply == NULL) rply = "?no_response"; } else { rply = "?no_response"; } if (strstr(rply, "*ES") != NULL) EL734_errcode = EL734__EMERG_STOP; if ((EL734_errcode == EL734__BAD_ILLG) && (cmnd != NULL)) { fprintf(stderr, " Unrecognised response to \"%s\" command: \"%s\"\n", cmnd, response); strcpy(EL734_IllgText, cmnd); strcat(EL734_IllgText, " : "); strcat(EL734_IllgText, response); } return EL734_errcode; } /* **--------------------------------------------------------------------------- ** EL734_SetHighSpeed: Set the max speed (J register) */ int EL734_SetHighSpeed( /* ================== */ void **handle, int hi) { int status, my_lo, my_hi, my_ramp; struct EL734info *info_ptr; char cmnd0[32]; char *rply_ptr0; /*---------------------------------------------- */ info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_SetHighSpeed")) return False; /*---------------------------------------------- ** Send J cmnd to EL734 */ sprintf(cmnd0, "j %d %d\r", info_ptr->motor, hi); status = AsynSrv_SendCmnds(&info_ptr->asyn_info, &info_ptr->to_host, &info_ptr->from_host, cmnd0, NULL); if (!status) { EL734_errcode = EL734__BAD_ASYNSRV; return False; } else { rply_ptr0 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL); if (rply_ptr0 == NULL) rply_ptr0 = "?no_response"; if (*rply_ptr0 == '\0') { /* ** The command was accepted - check value is set OK. */ status = EL734_GetSpeeds(handle, &my_lo, &my_hi, &my_ramp); if (!status) return False; if (hi != my_hi) { EL734_errcode = EL734__VFY_ERR; return False; } EL734_call_depth--; return True; } EL734_SetErrcode(info_ptr, rply_ptr0, "J"); return False; } } /* **--------------------------------------------------------------------------- ** EL734_SetLowSpeed: Set the start/stop speed (G register) */ int EL734_SetLowSpeed( /* ================= */ void **handle, int lo) { int status, my_lo, my_hi, my_ramp; struct EL734info *info_ptr; char cmnd0[32]; char *rply_ptr0; /*---------------------------------------------- */ info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_SetLowSpeed")) return False; /*---------------------------------------------- ** Send G cmnd to EL734 */ sprintf(cmnd0, "g %d %d\r", info_ptr->motor, lo); status = AsynSrv_SendCmnds(&info_ptr->asyn_info, &info_ptr->to_host, &info_ptr->from_host, cmnd0, NULL); if (!status) { EL734_errcode = EL734__BAD_ASYNSRV; return False; } else { rply_ptr0 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL); if (rply_ptr0 == NULL) rply_ptr0 = "?no_response"; if (*rply_ptr0 == '\0') { /* ** The command was accepted - check value is set OK. */ status = EL734_GetSpeeds(handle, &my_lo, &my_hi, &my_ramp); if (!status) return False; if (lo != my_lo) { EL734_errcode = EL734__VFY_ERR; return False; } EL734_call_depth--; return True; } EL734_SetErrcode(info_ptr, rply_ptr0, "G"); return False; } } /* **--------------------------------------------------------------------------- ** EL734_SetRamp: Set the start/stop ramp (E register) */ int EL734_SetRamp( /* ============= */ void **handle, int ramp) { int status, my_lo, my_hi, my_ramp; struct EL734info *info_ptr; char cmnd0[32]; char *rply_ptr0; /*---------------------------------------------- */ info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_SetRamp")) return False; /*---------------------------------------------- ** Send E cmnd to EL734 */ sprintf(cmnd0, "e %d %d\r", info_ptr->motor, ramp); status = AsynSrv_SendCmnds(&info_ptr->asyn_info, &info_ptr->to_host, &info_ptr->from_host, cmnd0, NULL); if (!status) { EL734_errcode = EL734__BAD_ASYNSRV; return False; } else { rply_ptr0 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL); if (rply_ptr0 == NULL) rply_ptr0 = "?no_response"; if (*rply_ptr0 == '\0') { /* ** The command was accepted - check value is set OK. */ status = EL734_GetSpeeds(handle, &my_lo, &my_hi, &my_ramp); if (!status) return False; if (ramp != my_ramp) { EL734_errcode = EL734__VFY_ERR; return False; } EL734_call_depth--; return True; } EL734_SetErrcode(info_ptr, rply_ptr0, "E"); return False; } } /* **--------------------------------------------------------------------------- ** EL734_Stop: Send a stop command to motor. */ int EL734_Stop( /* ========== */ void **handle) { int status; struct EL734info *info_ptr; char cmnd0[10]; char *rply_ptr0; /*---------------------------------------------- */ info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_Stop")) return False; /*---------------------------------------------- ** Send S cmnd to EL734 */ sprintf(cmnd0, "s %d\r", info_ptr->motor); status = AsynSrv_SendCmnds(&info_ptr->asyn_info, &info_ptr->to_host, &info_ptr->from_host, cmnd0, NULL); if (!status) { EL734_errcode = EL734__BAD_ASYNSRV; return False; } else { rply_ptr0 = AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL); if (rply_ptr0 == NULL) rply_ptr0 = "?no_response"; if (rply_ptr0[0] == '\0') { if (EL734_errcode != 0) return False; EL734_call_depth--; return True; } EL734_SetErrcode(info_ptr, rply_ptr0, "S"); return False; } } /* **--------------------------------------------------------------------------- ** EL734_WaitIdle: Wait till MSR goes to zero. */ int EL734_WaitIdle( /* ============== */ void **handle, int *ored_msr, int *fp_cntr, int *fr_cntr, float *ist_posit) { #ifdef __VMS #include #define hibernate lib$wait (0.25) #else #include #include struct timespec delay = { 0, 250000000 }; struct timespec delay_left; #ifdef LINUX #define hibernate nanosleep(&delay, &delay_left) #else #define hibernate nanosleep_d9 (&delay, &delay_left) #endif #endif int msr, ss; struct EL734info *info_ptr; /*---------------------------------------------- */ *ored_msr = *fp_cntr = *fr_cntr = -1; *ist_posit = 0.0; info_ptr = (struct EL734info *) *handle; if (!EL734_AddCallStack(info_ptr, "EL734_WaitIdle")) return False; /*---------------------------------------------- ** Poll the motor status till not moving. */ while (EL734_GetStatus(handle, &msr, ored_msr, fp_cntr, fr_cntr, &ss, ist_posit)) { if ((msr & MSR__BUSY) == 0) { if (EL734_errcode != 0) return False; EL734_call_depth--; return True; } hibernate; } return False; /* Error detected in EL734_GetStatus */ } /* **--------------------------------------------------------------------------- ** EL734_ZeroStatus: Zero the "ored-MSR" and fault counters. */ void EL734_ZeroStatus( /* ================ */ void **handle) { struct EL734info *info_ptr; /* ** Do nothing if no handle! */ info_ptr = (struct EL734info *) *handle; if (info_ptr == NULL) return; /* ** Zero the data structure items. */ info_ptr->ored_msr = 0; info_ptr->fp_cntr = 0; info_ptr->fr_cntr = 0; memset(info_ptr->from_host.msg_size, '0', sizeof(info_ptr->from_host.msg_size)); return; } /*-------------------------------------------- End of EL734_Utility.C =======*/