#define	    ident	"1A04"
#ifdef VAXC
#module	    EL755_Utility	ident
#endif
#ifdef __DECC
#pragma	    module	    EL755_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  . . . . . . . . : TAS_SRC:[PSI.LIB.SINQ]EL755_Utility.C
**
** Author   . . . . . . . . . . : D. Maden
** Date of creation . . . . . . : Sep 1998
**
**  To compile this module, use:

	$ import tasmad
	$ define/group sinq_c_tlb mad_lib:sinq_c.tlb
	$ cc /debug /noopt /obj=[]EL755_Utility -
			tas_src:[psi.lib.sinq]EL755_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 EL755_Utility debug
  $
  $ define/group sinq_olb mad_lib:sinq.olb
  $ @tasmad_disk:[mad.lib.sinq]sinq_olb EL755_Utility
**
** Updates:
**  1A01  8-Sep-1998 DM.	Initial version.
**============================================================================
** The entry points included in this module are described below. Prototypes
** can be defined via:
**
**    #include <sinq_prototypes.h>
**
**	EL755_AddCallStack  - Add a routine name to the call stack.
**	EL755_Close	    - Close a connection to an EL755 controller.
**	EL755_Config	    - Configure a connection to an EL755 controller.
**	EL755_ErrInfo	    - Return detailed status from last operation.
**	EL755_GetCurrents   - Get the actual settings of the EL755 currents.
**	EL755_Open	    - Open a connection to an EL755 controller.
**	EL755_PutOffline    - Put the EL755 off-line.
**	EL755_PutOnline	    - Put the EL755 on-line.
**	EL755_SendTillSameStr - Repeatedly send a command to EL755 controller
**				until the same reply is received twice.
**	EL755_SendTillSameVal - Repeatedly send a command to EL755 controller
**				until the first token of the reply is the
**				same fl.pnt. value twice in succession.
**	EL755_SetCurrent    - Set the EL755 current.
**---------------------------------------------------------------------
**    int EL755_AddCallStack (&info_pntr, &name)
**	  ------------------
**  Input Args:
**	struct EL755info *info_pntr - Pointer to structure returned by
**				EL755_Open. Note that the type of the pointer
**				is "struct EL755info".
**	char  *name	- The name of the routine to be added to the call stack.
**  Output Args:
**	none
**  Modified Args:
**	none
**  Return status:
**	True if no problems detected, otherwise False and EL755_errcode
**	is set to indicate the nature of the problem as follows:
**	    EL755__NOT_OPEN	 --> there is no connection open to the EL755,
**					i.e. info_pntr is NULL.
**	    EL755__FORCED_CLOSED --> the connection has been force-closed
**					(probably as a result of an error
**					on another device on the same host).
**	    EL755__NO_SOCKET	 --> The connection has no socket - probably
**					it was closed after a previous error.
**	Note that EL755_errcode may have been set prior to the call to
**	EL755_AddCallStack. In this case, the routine simply returns False.
**  Routines called:
**	None
**  Description:
**	The routine is designed to simplify the building of the call-stack
**	which is available to the user via EL755_ErrInfo if an error occurs.
**	It is intended for internal use only.
**	
**	If an error has aready occurred prior to the call to EL755_AddCallStack
**	(i.e. EL755_errcode is non-zero), the routine simply returns False
**	to prevent redundant information being added to the stack.
**
**	Otherwise, the caller's name is added to the stack and basic checks
**	are made of the EL755info structure.
**---------------------------------------------------------------------
**    int EL755_Close (&handle, force_flag)
**	  -----------
**  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 EL755_Open.
**			  On return, the pointer is set to NULL.
**  Return status:
**	True always (error returns from close and free are not checked).
**  Routines called:
**	Socket library, "close" and memory release routine, "free".
**  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 a server,
**	then calling EL755_Close doesn't actually close the socket until all
**	connections have been closed. In the situation where an error has been
**	detected, it is often desirable to close and re-open the socket as part
**	of the recovery procedure. Calling EL755_Close with 'force_flag'
**	non-zero will force the socket to be closed and will mark all other
**	connections using this socket so that they will be informed of the
**	event when they next call an AsynSrv 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. EL734 motors) on the same server.
**-------------------------------------------------------------------------
**   void EL755_Config (&handle, &par_id, par_val, ...)
**	  ------------
**  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 EL755_Open.
**			  It is used to hold the config info for the connection.
**  Return status:
**	True if no problems detected, otherwise False and EL755_errcode
**	is set to indicate the nature of the problem. Values of Errcode set by
**	EL755_Config are (other values may be set by the called routines):
**	    EL755__BAD_PAR --> Unrecognised par_id or msecTmo < 100 or
**					msecTmo > 999'999 or bad eot or ..
**  Routines called:
**	EL755_AddCallStack
**  Description:
**	The routine sets values in the EL755info data structure and may modify
**	the state of the temperature controller. Values which may be taken by
**	par_id (par_id is case-insensitive) and the corresponding variable
**	type of par_val are:
**
**	    "msecTmo"	int	The time-out response for commands sent to
**				    the EL755. The valid range is 100 to
**				    999'999. Default is 3'000.
**	    "eot"	char*	The expected terminators in responses to
**				    commands sent to the EL755. The first
**				    character specifies the number of
**				    terminators (max=3). Default is "1\n".
**	    "index"	int	The DAC index in the range 1 to 8 to be
**				    referenced via this EL755info structure.
**-------------------------------------------------------------------------
**    void EL755_ErrInfo (&entry_txt_ptr, &errcode, &my_errno, &vaxc_errno)
**	   -------------
**  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  EL755_GetCurrents (&handle, &soll, &ist)
**	  -----------------
**
**  Input Args:
**	void **handle     - The pointer to the structure returned by EL755_Open
**  Output Args:
**	float *soll	  - the requested current.
**	float *ist	  - the actual current. This may me different to *soll
**				since the controller ramps to a new current.
**  Modified Args:
**	none
**  Return status:
**	True if no problems detected, otherwise False and EL755_ErrInfo
**	can be called to identify the problem. Values of Errcode set by
**	EL755_GetCurrents are (other values may be set by the called
**	routines):
**	    EL755__BAD_ASYNSRV --> Call to AsynSrv_SendCmnds failed. Use
**					AsynSrv_ErrInfo to get more details.
**	    EL755__BAD_ILLG --> The response to the "I" command was probably not
**				    two numbers. This could happen if there is
**				    noise on the RS232C connection to the EL755.
**	    EL755__BAD_TMO  --> Time-out error ("?TMO" - this gets generated
**				    by the RS232C server).
**	    EL755__OFFLINE  --> The EL755 is offline ("?OF").
**	    EL755__TOO_MANY --> The command was repeated too many times
**					and never received the same response
**					on 2 consecutive occasions.
**
**	If an error is detected, *soll and *ist are undefined.
**  Routines called:
**	EL755_AddCallStack, AsynSrv_SendCmnds
**  Description:
**	EL755_Getcurrents sends an "I" command to the controller to obtain the
**	currents. The command is repeated until the "soll" value is twice the
**	same.
**   Note: If the power supply is off or not connected (response is
**	    "?power-supply OFF", then no error is indicated and *soll=*ist=0.0
**	    is returned.
**-------------------------------------------------------------------------
**    int EL755_Open (&handle, host, port, chan, indx)
**	  ----------
**  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   indx	- The DAC index in the range 1 to 8. This selects which
**			    of the 8 outputs from the EL755 are to be used.
**  Output Args:
**	void *handle	- A pointer to a structure of type EL755info needed for
**			   subsequent calls to EL755_??? routines.
**  Modified Args:
**	none
**  Return status:
**	True if no problems detected, otherwise False. If False, EL755_ErrInfo
**	can be called to identify the problem. Values of Errcode set by
**	EL755_Open are (other values may be set by the called routines):
**	  EL755__BAD_MALLOC  --> Call to "malloc" failed
**	  EL755__BAD_SOCKET  --> Call to AsynSrv_Open failed. Use
**					 AsynSrv_ErrInfo to get more details.
**	  EL755__BAD_TMO     --> Time-out error ("?TMO" - this gets
**					generated by the RS232C server).
**	  EL755__BAD_OFL     --> Connection to EL755 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.
**	  EL755__BAD_DEV     --> Device doesn't seem to be an EL755. The
**					response to the "ID\r" command was bad.
**	  EL755__BAD_ILLG    --> Some other unrecognised response. This
**					should never occur, of course!
**	  EL755__BAD_ASYNSRV --> Call to AsynSrv_SendCmnds failed. Use
**					 AsynSrv_ErrInfo to get more details.
**  Routines called:
**	"calloc"	- memory allocation routine.
**	AsynSrv_Open
**	AsynSrv_Close	- called if an error detected after connection opened.
**	EL755_Config
**	EL755_SendTillSameStr
**  Description:
**	The routine opens a TCP/IP connection to a server offering the
**	"RS-232-C" service for an EL755 Controller. "RMT 1", "ECHO 0" and
**	"ID" commands are sent to ensure the device is an EL755 controller.
**-------------------------------------------------------------------------
**    int   EL755_PutOffline (&handle)
**	    ----------------
**			    Send "ECHO 1" and "RMT 0" commands to EL755 server.
**  Input Args:
**	void   **handle	- The pntr to the structure returned by EL755_Open.
**  Output Args:
**	none
**  Modified Args:
**	none
**  Return status:
**	True if no problems detected, otherwise False and errcode (see
**	EL755_ErrInfo) is set to indicate the nature of the problem.
**	Values of Errcode set by EL755_PutOffline are (other values may be set
**	by the called routines):
**	    EL755__BAD_ASYNSRV --> An error occurred in AsynSrv_Utility.
**					    Call AsynSrv_ErrInfo for more info.
**	    EL755__BAD_ILLG    --> an unrecognised response. This
**					should never occur, of course!
**  Routines called:
**	EL755_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   EL755_PutOnline (&handle, echo)
**	    ---------------
**			    Send "RMT 1" and "ECHO x" commands to EL755 server.
**  Input Args:
**	void   **handle	- The pntr to the structure returned by EL755_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
**	EL755_ErrInfo) is set to indicate the nature of the problem.
**	Values of Errcode set by EL755_PutOnline are (other values may be set
**	by the called routines):
**	    EL755__BAD_PAR --> "echo" is not 0, 1 or 2.
**	    EL755__BAD_ASYNSRV --> An error occurred in AsynSrv_Utility.
**					    Call AsynSrv_ErrInfo for more info.
**	    EL755__BAD_ILLG    --> an unrecognised response. This
**					should never occur, of course!
**  Routines called:
**	EL755_AddCallStack, AsynSrv_SendCmnds, AsynSrv_GetReply
**  Description:
**	The routine calls AsynSrv_SendCmnds to execute "RMT 1" and "ECHO x"
**	commands. The replies are checked.
**-------------------------------------------------------------------------
**    int EL755_SendTillSameStr (&handle, &cmnd, &rply, rply_len)
**	  ---------------------
**  Input Args:
**	char  *cmnd	- The command to be sent (incl. terminators).
**	int    rply_len	- The size of <rply>.
**  Output Args:
**	char  *rply	- The response to <cmnd>.
**  Modified Args:
**	void **handle   - The pointer to the structure returned by EL755_Open.
**  Return status:
**	True if no problems detected, otherwise False. If False, EL755_ErrInfo
**	can be called to identify the problem. Values of Errcode set by
**	EL755_SendTillSameStr are (other values may be set by the called routines):
**	  EL755__BAD_ASYNSRV	--> Call to AsynSrv_SendCmnds failed. Use
**					AsynSrv_ErrInfo to get more details.
**	  EL755__BAD_ILLG --> The response to the "I" command was probably not
**				    two numbers. This could happen if there is
**				    noise on the RS232C connection to the EL755.
**	  EL755__BAD_TMO	--> Time-out error ("?TMO" - this gets
**					generated by the RS232C server).
**	  EL755__BAD_CMD	--> Bad command ("?syntax failure")
**	  EL755__BAD_OFL	--> Connection to EL755 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.
**	  EL755__TOO_MANY	--> The command was repeated too many times
**					and never received the same response
**					on 2 consecutive occasions.
**	  EL755__OFFLINE	--> The EL755 is offline ("?OF").
**  Routines called:
**	EL755_AddCallStack, EL755_ErrorLog, AsynSrv_SendCmnds, AsynSrv_GetReply
**  Description:
**	The routine sends the specified command to the EL755 Controller and
**	reads the response. The command is repeated up to 5 times until the same
**	response is received twice in succession.
**   Note:
**	The error EL755__TOO_MANY could indicate that <rply> is not big enough
**	to hold the complete reply.
**-------------------------------------------------------------------------
**    int EL755_SendTillSameVal (&handle, &cmnd, &val)
**	  ---------------------
**  Input Args:
**	char  *cmnd	- The command to be sent (incl. terminators).
**  Output Args:
**	float *val	- The response to <cmnd>.
**  Modified Args:
**	void **handle   - The pointer to the structure returned by EL755_Open.
**  Return status:
**	True if no problems detected, otherwise False. If False, EL755_ErrInfo
**	can be called to identify the problem. Values of Errcode set by
**	EL755_SendTillSameVal are (other values may be set by the called
**	routines):
**	  EL755__BAD_ASYNSRV	--> Call to AsynSrv_SendCmnds failed. Use
**					AsynSrv_ErrInfo to get more details.
**	  EL755__BAD_ILLG --> The response to the "I" command was probably not
**				    two numbers. This could happen if there is
**				    noise on the RS232C connection to the EL755.
**	  EL755__BAD_TMO	--> Time-out error ("?TMO" - this gets
**					generated by the RS232C server).
**	  EL755__BAD_CMD	--> Bad command ("?syntax failure")
**	  EL755__BAD_OFL	--> Connection to EL755 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.
**	  EL755__TOO_MANY	--> The command was repeated too many times
**					and never received the same response
**					on 2 consecutive occasions.
**	  EL755__OFFLINE	--> The EL755 is offline ("?OF").
**  Routines called:
**	EL755_AddCallStack, EL755_ErrorLog, AsynSrv_SendCmnds, AsynSrv_GetReply
**  Description:
**	The routine sends the specified command to the EL755 Controller and
**	reads the response. The command is repeated up to 5 times until the
**	first token is the same fl.pnt value twice in succession.
**   Note 1:
**	The error EL755__TOO_MANY could indicate that <rply> is not big enough
**	to hold the complete reply.
**   Note 2: If the power supply is off or not connected (response is
**	    "?power-supply OFF") then a zero value is returned and the
**	    return status is True
**-------------------------------------------------------------------------
**   int  EL755_SetCurrent (&handle, soll)
**	  ----------------
**
**  Input Args:
**	void **handle     - The pointer to the structure returned by EL755_Open
**	float  soll	  - the requested current.
**  Output Args:
**	none
**  Modified Args:
**	none
**  Return status:
**	True if no problems detected, otherwise False and EL755_ErrInfo
**	can be called to identify the problem. Values of Errcode set by
**	EL755_SetCurrent are (other values may be set by the called
**	routines):
**	    EL755__TURNED_OFF --> The EL755 power supply on this channel is
**				    turned off ("?power-supply OFF").
**	    EL755__OUT_OF_RANGE --> The set value is out of
**					range ("?value out of range").
**	    EL755__TOO_LARGE --> The set value is too
**					large ("?current limitation").
**	    EL755__BAD_ILLG --> the response to the first "I" command was
**				not null (indicating that the command was
**				rejected) or the response to the second
**				"I" command was probably not two numbers.
**				This could happen if there is noise
**				on the RS232C connection to the EL755.
**  Routines called:
**	EL755_SendTillSameStr, EL755_GetCurrests
**  Description:
**	EL755_SetCurrent sends an "I" command to the controller to set the
**	current for the DAC index selected for the handle. An "I" is sent
**	to check that the value was sent correctly.
**   Note: If the power supply is off or not connected (response is
**	    "?power-supply OFF") and soll == 0.0, then return status is True.
**============================================================================*/
/*
**---------------------------------------------------------------------------
**					Global Definitions
*/
#include    <stdlib.h>
#include    <stdio.h>
#include    <stdarg.h>
#include    <errno.h>
#include    <math.h>
#include    <signal.h>
#include    <netdb.h>
#include    <sys/socket.h>
#include    <netinet/in.h>

#include    <string.h>

#ifdef	__VMS
#include    <unixio.h>
#else
#include    <unistd.h>
#endif
/*-----------------------------------------------------------------*/
#include    <sinq_prototypes.h>
#include    <el755_def.h>
#include    <rs232c_def.h>

#define True	1
#define False	0
#define NIL	'\0'
/*--------------------------------------------------------------------------
**					Global Variables
*/
static int EL755_call_depth = 0;
static char EL755_routine[5][64];
static int EL755_errcode = 0;
static int EL755_errno, EL755_vaxc_errno;
/*
**---------------------------------------------------------------------------
**		EL755_AddCallStack:  Add a routine name to the call stack.
**				     This allows EL755_ErrInfo to generate a
**				     trace-back in case of error.
*/
int EL755_AddCallStack(
/*	==================
*/ struct EL755info *pntr,
                        char *name)
{

  if (EL755_errcode != 0)
    return False;

  if (EL755_call_depth < 5) {
    StrJoin(EL755_routine[EL755_call_depth], sizeof(EL755_routine[0]),
            name, "");
    EL755_call_depth++;
  }

  if (pntr == NULL) {
    EL755_errcode = EL755__NOT_OPEN;
    return False;
  }

  if (pntr->asyn_info.skt <= 0) {
    memset(pntr->from_host.msg_size,
           '0', sizeof(pntr->from_host.msg_size));
    EL755_errcode = (pntr->asyn_info.skt < 0) ? EL755__FORCED_CLOSED
        : EL755__NO_SOCKET;
    return False;
  }
  return True;
}

/*
**---------------------------------------------------------------------------
**		EL755_Close:  Close a connection to an EL755 controller.
*/
int EL755_Close(
/*	===========
*/ void **handle,
                 int force_flag)
{

  struct EL755info *info_ptr;
  char buff[4];

  info_ptr = (struct EL755info *) *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;
}

/*
**---------------------------------------------------------------------------
**		EL755_Config:  Configure a connection to an EL755 controller.
*/
int EL755_Config(
/*	============
*/ void **handle,
                  ...)
{

  struct EL755info *info_ptr;
  char buff[80], rply[256], my_txt[16];
  va_list ap;                   /* Pointer to variable args */
  char *txt_ptr;
  int intval, my_txt_l;
                    /*----------------------------------------------
		    */
  info_ptr = (struct EL755info *) *handle;

  if (!EL755_AddCallStack(info_ptr, "EL755_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) {
    my_txt_l = sizeof(my_txt);
    StrEdit(my_txt, txt_ptr, "lowercase", &my_txt_l);
            /*------------------------------------*/
    if (strcmp(my_txt, "msectmo") == 0) {
      intval = va_arg(ap, int);
      if ((intval < 100) || (intval > 999999)) {
        EL755_errcode = EL755__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(my_txt, "eot") == 0) {
      txt_ptr = va_arg(ap, char *);
      if (txt_ptr == NULL) {
        EL755_errcode = EL755__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:
        EL755_errcode = EL755__BAD_PAR;
        return False;
      }
            /*------------------------------------*/
    } else if (strcmp(txt_ptr, "index") == 0) {
      intval = va_arg(ap, int);
      if ((intval < 1) || (intval > 8)) {
        EL755_errcode = EL755__BAD_PAR;
        return False;
      }
      info_ptr->index = intval;
            /*------------------------------------*/
    } else {
      EL755_errcode = EL755__BAD_PAR;
      return False;
    }
            /*------------------------------------*/
    txt_ptr = va_arg(ap, char *);       /* Get pntr to next parameter ident */
  }

  if (EL755_errcode == 0)
    EL755_call_depth--;
  return True;
}

/* 
** -------------------------------------------------------------------------
** EL755_ErrInfo:  Return detailed status from last operation.
*/
void EL755_ErrInfo(
/*	=============
*/ char **entry_txt,
                    int *errcode, int *my_errno, int *vaxc_errno)
{

  int i, j, k;
  char buff[80];
  int asyn_errcode, asyn_errno, asyn_vaxerrno;
  char *asyn_errtxt;

  if (EL755_call_depth <= 0) {
    strcpy(EL755_routine[0], "EL755_no_error_detected");
    *errcode = 0;
    *my_errno = 0;
    *vaxc_errno = 0;
  } else {
    if (EL755_call_depth > 1) { /* Concatenate the names */
      for (i = 1; i < EL755_call_depth; i++) {
        strcat(EL755_routine[0], "/");
        StrJoin(EL755_routine[0], sizeof(EL755_routine),
                EL755_routine[0], EL755_routine[i]);
      }
    }
    *errcode = EL755_errcode;
    *my_errno = EL755_errno;
    *vaxc_errno = EL755_vaxc_errno;
    switch (EL755_errcode) {
    case EL755__BAD_ASYNSRV:
      strcpy(buff, "/EL755__BAD_ASYNSRV");
      break;
    case EL755__BAD_CMD:
    case EL755__BAD_DEV:
      strcpy(buff, "/EL755__BAD_DEV");
      break;
    case EL755__BAD_ILLG:
      strcpy(buff, "/EL755__BAD_ILLG");
      break;
    case EL755__BAD_MALLOC:
      strcpy(buff, "/EL755__BAD_MALLOC");
      break;
    case EL755__BAD_OFL:
      strcpy(buff, "/EL755__BAD_OFL");
      break;
    case EL755__BAD_PAR:
      strcpy(buff, "/EL755__BAD_PAR");
      break;
    case EL755__BAD_SOCKET:
      strcpy(buff, "/EL755__BAD_SOCKET");
      break;
    case EL755__BAD_TMO:
      strcpy(buff, "/EL755__BAD_TMO");
      break;
    case EL755__FORCED_CLOSED:
      strcpy(buff, "/EL755__FORCED_CLOSED");
      break;
    case EL755__NOT_OPEN:
      strcpy(buff, "/EL755__NOT_OPEN");
      break;
    case EL755__NO_SOCKET:
      strcpy(buff, "/EL755__NO_SOCKET");
      break;
    case EL755__OFFLINE:
      strcpy(buff, "/EL755__OFFLINE");
      break;
    case EL755__OUT_OF_RANGE:
      strcpy(buff, "/EL755__OUT_OF_RANGE");
      break;
    case EL755__OVFLOW:
      strcpy(buff, "/EL755__OVFLOW");
      break;
    case EL755__TOO_LARGE:
      strcpy(buff, "/EL755__TOO_LARGE");
      break;
    case EL755__TOO_MANY:
      strcpy(buff, "/EL755__TOO_MANY");
      break;
    case EL755__TURNED_OFF:
      strcpy(buff, "/EL755__TURNED_OFF");
      break;
    default:
      sprintf(buff, "/EL755__unknown_err_code: %d", EL755_errcode);
    }
    StrJoin(EL755_routine[0], sizeof(EL755_routine), EL755_routine[0],
            buff);
  }
  AsynSrv_ErrInfo(&asyn_errtxt, &asyn_errcode, &asyn_errno,
                  &asyn_vaxerrno);
  if (asyn_errcode != 0) {
    strcat(EL755_routine[0], "/");
    StrJoin(EL755_routine[0], sizeof(EL755_routine),
            EL755_routine[0], asyn_errtxt);
  }
  *entry_txt = EL755_routine[0];
  EL755_call_depth = 0;
  EL755_errcode = 0;
}

/*
**---------------------------------------------------------------------------
**		EL755_GetCurrents:  Get currents from EL755.
*/
int EL755_GetCurrents(
/*	=================
*/ void **handle,
                       float *soll, float *ist)
{

  int iret;
  char cmnd[32];
  struct EL755info *info_ptr;
                    /*----------------------------------------------
		    */
  *soll = *ist = 0.0;
  info_ptr = (struct EL755info *) *handle;

  if (!EL755_AddCallStack(info_ptr, "EL755_GetCurrents"))
    return False;
                    /*----------------------------------------------
		    ** Send I command to get EL755 currents. Repeat until
		    ** first value is same 2 times consecutively.
		    */
  sprintf(cmnd, "I %d\r", info_ptr->index);
  iret = EL755_SendTillTwoVals(handle, cmnd, soll, ist);
  if (!iret)
    return False;

  if (EL755_errcode == 0)
    EL755_call_depth--;
  return True;
}

/*
**---------------------------------------------------------------------------
**		EL755_Open:  Open a connection to an EL755 controller.
*/
int EL755_Open(
/*	==========
*/ void **handle,
                char *host, int port, int chan, int indx)
{

  int status, i;
  char tmo_save[4];
  char *rply_ptr0, *rply_ptr1, *rply_ptr2;
  struct EL755info *my_handle;
/*--------------------------------------------------------
**			Initialise the error info stack and pre-set the
**			routine name (in case of error).
*/
  EL755_errcode = EL755_errno = EL755_vaxc_errno = 0;
  strcpy(EL755_routine[0], "EL755_Open");
  EL755_call_depth = 1;
/*--------------------------------------------------------
**				    Assume trouble
*/
  *handle = NULL;
/*--------------------------------------------------------
**			    Reserve space for the data we need to store.
*/
  my_handle = (struct EL755info *) calloc(1, sizeof(*my_handle));
  if (my_handle == NULL) {
    EL755_errcode = EL755__BAD_MALLOC;  /* calloc failed!! */
    return False;
  }
/*--------------------------------------------------------
**				    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) {
    EL755_errcode = EL755__BAD_SOCKET;
    GetErrno(&EL755_errno, &EL755_vaxc_errno);  /* Save errno info */
    EL755_ErrorLog("EL755_Open/AsynSrv_Open",
                   "Failed to make connection.");
    free(my_handle);
    return False;
  }
  memcpy(tmo_save, my_handle->asyn_info.tmo, 4);
  status = EL755_Config((void *) &my_handle, "msecTmo", 100,    /* 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", "index", indx, NULL);
  if (!status) {
    /* Some error occurred in EL755_Config - should be impossible!
     */
    AsynSrv_Close(&my_handle->asyn_info, False);
    free(my_handle);
    return False;
  }
  /*
   ** Now ensure that there's an EL755 connected to the line. The first
   ** "RMT 1" command can fail due to pending characters in the EL755
   ** input buffer causing the command to be corrupted. The response is
   ** ignored for this reason.
   */
  status = AsynSrv_SendCmnds(&my_handle->asyn_info, &my_handle->to_host, &my_handle->from_host, "RMT 1\r",      /* Try to put EL755 on-line */
                             "RMT 1\r", /* Try again in case type-ahead chars corrupted ..
                                         ** .. the first attempt. */
                             "ECHO 0\r",        /* And turn off echoing */
                             NULL);
  status = AsynSrv_SendCmnds(&my_handle->asyn_info,
                             &my_handle->to_host, &my_handle->from_host,
                             "RMT 1\r", "ECHO 0\r", "ID\r", NULL);
  if (!status) {
    /* Some error occurred in AsynSrv_SendCmnds.
     */
    AsynSrv_Close(&my_handle->asyn_info, False);
    free(my_handle);
    EL755_errcode = EL755__BAD_ASYNSRV;
    return False;
  }

  rply_ptr0 = AsynSrv_GetReply(&my_handle->asyn_info,
                               &my_handle->from_host, NULL);
  rply_ptr1 = AsynSrv_GetReply(&my_handle->asyn_info,
                               &my_handle->from_host, rply_ptr0);
  rply_ptr2 = AsynSrv_GetReply(&my_handle->asyn_info,
                               &my_handle->from_host, rply_ptr1);
  if ((rply_ptr0 == NULL) || (rply_ptr1 == NULL) || (rply_ptr2 == NULL)) {
    /* Some error occurred in AsynSrv_GetReply.
     */
    EL755_AddCallStack(my_handle, "NULL response");
    AsynSrv_Close(&my_handle->asyn_info, False);
    EL755_errcode = EL755__BAD_DEV;
    free(my_handle);
    return False;
  }
  if (rply_ptr0[0] != '\0') {
    EL755_AddCallStack(my_handle, rply_ptr0);
    AsynSrv_Close(&my_handle->asyn_info, False);        /* Bad response! */
    EL755_errcode = EL755__BAD_DEV;
    free(my_handle);
    return False;
  }
  if (rply_ptr1[0] != '\0') {
    EL755_AddCallStack(my_handle, rply_ptr1);
    AsynSrv_Close(&my_handle->asyn_info, False);        /* Bad response! */
    EL755_errcode = EL755__BAD_DEV;
    free(my_handle);
    return False;
  }
  if (strncmp(rply_ptr2, "EL755 MAGST", 11) != 0) {
    EL755_AddCallStack(my_handle, rply_ptr2);
    AsynSrv_Close(&my_handle->asyn_info, False);        /* Bad response! */
    EL755_errcode = EL755__BAD_DEV;
    free(my_handle);
    return False;
  }
  /* The device seems to be an EL755! */

  memcpy(my_handle->asyn_info.tmo, tmo_save, 4);        /* Restore time-out */
  /*
   ** The connection is complete. Pass the data structure
   ** back to the caller as a handle.
   */
  *handle = my_handle;
  if (EL755_errcode == 0)
    EL755_call_depth--;
  return True;
}

/*
**---------------------------------------------------------------------------
**		EL755_PutOffline:  put the EL755 off-line
*/
int EL755_PutOffline(
/*	================
*/ void **handle)
{

  int status;
  struct EL755info *info_ptr;
  char *rply_ptr0, *rply_ptr1, *rply_ptr2;
  char buff[132];
                    /*----------------------------------------------
		    */
  info_ptr = (struct EL755info *) *handle;

  if (!EL755_AddCallStack(info_ptr, "EL755_PutOffline"))
    return False;
                    /*----------------------------------------------
		    ** The problem which this routine has is that the EL755
		    ** 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,
                             "RMT 1\r",
                             "RMT 1\r", "ECHO 1\r", "RMT 0\r", NULL);
  if (!status) {
    EL755_errcode = EL755__BAD_ASYNSRV;
    return False;
  }

  status = AsynSrv_SendCmnds(&info_ptr->asyn_info,
                             &info_ptr->to_host, &info_ptr->from_host,
                             "RMT\r", "", NULL);
  if (!status) {
    EL755_errcode = EL755__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_ptr1 == NULL)) {
    EL755_AddCallStack(info_ptr, "NULL response");
    EL755_errcode = EL755__BAD_ILLG;
    return False;
  }

  if ((strcmp(rply_ptr0, "RMT") == 0) && (strcmp(rply_ptr1, "\n0") == 0)) {
    EL755_call_depth--;
    return True;
  }

  if (strcmp(rply_ptr0, "?OF") == 0) {
    EL755_errcode = EL755__OFFLINE;
  } else if (strcmp(rply_ptr0, "?OFL") == 0) {
    EL755_errcode = EL755__BAD_OFL;
  } else if (strcmp(rply_ptr0, "?syntax failure") == 0) {
    EL755_errcode = EL755__BAD_CMD;
  } else if (strncmp(rply_ptr0, "?TMO", 4) == 0) {
    EL755_errcode = EL755__BAD_TMO;
  } else {
    sprintf(buff, "Cmnd=\"RMT.\" Rply0=\"%.10s\" Rply1=\"%.10s\"",
            rply_ptr0, rply_ptr1);
    MakePrintable(buff, sizeof(buff), buff);
    EL755_AddCallStack(info_ptr, buff);

    sprintf(buff, "Unrecognised responses to RMT command: \"%s\" \"%s\"",
            rply_ptr0, rply_ptr1);
    MakePrintable(buff, sizeof(buff), buff);
    EL755_ErrorLog(EL755_routine[EL755_call_depth - 1], buff);

    EL755_errcode = EL755__BAD_ILLG;
  }
  return False;
}

/*
**---------------------------------------------------------------------------
**		EL755_PutOnline:  put the EL755 on-line
*/
int EL755_PutOnline(
/*	===============
*/ void **handle,
                     int echo)
{

  int status, my_echo;
  struct EL755info *info_ptr;
  char cmnd0[10], buff[132];
  char *rply_ptr;
                    /*----------------------------------------------
		    */
  info_ptr = (struct EL755info *) *handle;

  if (!EL755_AddCallStack(info_ptr, "EL755_PutOnline"))
    return False;
                    /*----------------------------------------------
		    */
  if ((echo != 0) && (echo != 1)) {
    EL755_errcode = EL755__BAD_PAR;
    return False;
  }
                    /*----------------------------------------------
		    ** The problem which this routine has is that the state
		    ** of the EL755 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,
                             "RMT 1\r", "RMT 1\r", cmnd0, NULL);
  if (!status) {
    EL755_errcode = EL755__BAD_ASYNSRV;
    return False;
  }

  status = AsynSrv_SendCmnds(&info_ptr->asyn_info,
                             &info_ptr->to_host, &info_ptr->from_host,
                             "ECHO\r", NULL);
  if (!status) {
    EL755_errcode = EL755__BAD_ASYNSRV;
    return False;
  }

  rply_ptr =
      AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL);
  if (rply_ptr == NULL) {
    EL755_AddCallStack(info_ptr, "NULL response");
    EL755_errcode = EL755__BAD_ILLG;
    return False;
  }

  if ((echo == 1) && (strcmp(rply_ptr, "ECHO") == 0)) {
    EL755_call_depth--;
    return True;
  } else if ((echo == 0) &&
             (sscanf(rply_ptr, "%d", &my_echo) == 1) &&
             (my_echo == echo)) {
    EL755_call_depth--;
    return True;
  }

  if (strcmp(rply_ptr, "?OF") == 0) {
    EL755_errcode = EL755__OFFLINE;
  } else if (strcmp(rply_ptr, "?OFL") == 0) {
    EL755_errcode = EL755__BAD_OFL;
  } else if (strcmp(rply_ptr, "?syntax failure") == 0) {
    EL755_errcode = EL755__BAD_CMD;
  } else if (strncmp(rply_ptr, "?TMO", 4) == 0) {
    EL755_errcode = EL755__BAD_TMO;
  } else {
    sprintf(buff, "Cmnd=\"ECHO.\" Rply=\"%.10s\"", rply_ptr);
    MakePrintable(buff, sizeof(buff), buff);
    EL755_AddCallStack(info_ptr, buff);

    sprintf(buff, "Unrecognised response to ECHO command: \"%s\"",
            rply_ptr);
    MakePrintable(buff, sizeof(buff), buff);
    EL755_ErrorLog(EL755_routine[EL755_call_depth - 1], buff);

    EL755_errcode = EL755__BAD_ILLG;
  }
  return False;
}

/*
**---------------------------------------------------------------------------
**		EL755_SendTillSameStr:  Repeat a command until we get the same
**				    response on 2 successive occasions.
**
**		    This routine is intended for internal use only!
**		    If too many retries, EL755_errcode is set to EL755__TOO_MANY.
*/
int EL755_SendTillSameStr(
/*	=====================
*/ void **handle,
                           char *cmnd, char *rply, int rply_len)
{

  int iret, i, j, n_ovfl;
  struct EL755info *info_ptr;
  char *rply_ptr;
  char buff[132];
  char replies[6][64];
                    /*----------------------------------------------
		    */
  info_ptr = (struct EL755info *) *handle;

  if (!EL755_AddCallStack(info_ptr, "EL755_SendTillSameStr"))
    return False;
                    /*----------------------------------------------
		    ** Send command. Do it in a
		    ** loop until we get the same response twice to guard
		    ** against RS-232-C problems with the EL755.
		    */
  i = n_ovfl = 0;
  StrJoin(rply, rply_len, "#", "");

  while (i < 6) {
    iret = AsynSrv_SendCmnds(&info_ptr->asyn_info,
                             &info_ptr->to_host, &info_ptr->from_host,
                             cmnd, NULL);
    if (!iret) {
      EL755_errcode = EL755__BAD_ASYNSRV;
      return False;
    }
    rply_ptr =
        AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL);
    if (rply_ptr == NULL) {
      EL755_AddCallStack(info_ptr, "NULL response");
      EL755_errcode = EL755__BAD_ILLG;
      return False;
    }
    if (strncmp(rply_ptr, "?TMO", 4) == 0) {
      EL755_errcode = EL755__BAD_TMO;
      return False;
    }
    if (strcmp(rply_ptr, "?OF") == 0) {
      EL755_errcode = EL755__OFFLINE;
      return False;
    }
    if (strcmp(rply_ptr, "?OFL") == 0) {
      EL755_errcode = EL755__BAD_OFL;
      return False;
    }
    if (strcmp(rply_ptr, "?syntax failure") == 0) {
      EL755_errcode = EL755__BAD_CMD;
      return False;
    }
    if (strcmp(rply_ptr, "?OV") == 0) { /* Check for overflow. This seems
                                         ** to be an EL755 problem which
                                         ** needs fixing. In the meantime,
                                         ** just force a repeat.
                                         */
      sprintf(buff, "Warning -- \"?OV\" received in response to \"%s\".",
              cmnd);
      MakePrintable(buff, sizeof(buff), buff);
      EL755_ErrorLog(EL755_routine[EL755_call_depth - 1], buff);
      n_ovfl++;
      if (n_ovfl > 10) {
        EL755_errcode = EL755__TOO_MANY;
        return False;
      }
    } else {
      n_ovfl = 0;
      if (strncmp(rply, rply_ptr, rply_len) == 0)
        break;
      StrJoin(rply, rply_len, rply_ptr, "");
      MakePrintable(replies[i], sizeof(replies[0]), rply_ptr);
      i++;
    }
  }
  if (strncmp(rply, rply_ptr, rply_len) != 0) {
    EL755_errcode = EL755__TOO_MANY;
    return False;
  }
  if (i > 1) {
    sprintf(buff, "Warning -- %d retries needed for Cmnd = \"%s\".",
            (i - 1), cmnd);
    MakePrintable(buff, sizeof(buff), buff);
    EL755_ErrorLog(EL755_routine[EL755_call_depth - 1], buff);
    for (j = 0; j < i; j++)
      fprintf(stderr, "  %d: \"%s\"\n", j, replies[j]);
  }

  if (EL755_errcode != 0)
    return False;
  EL755_call_depth--;
  return True;
}

/*
**---------------------------------------------------------------------------
**		EL755_SendTillSameVal:  Repeat a command until we get the same
**				 response value on 2 successive occasions.
**
**		    This routine is intended for internal use only!
**		    If too many retries, EL755_errcode is set to EL755__TOO_MANY.
*/
int EL755_SendTillSameVal(
/*	=====================
*/ void **handle,
                           char *cmnd, float *val)
{

  int iret, i, n_ovfl, cnt;
  struct EL755info *info_ptr;
  float last_val;
  char *rply_ptr, *tok;
  char buff[132];
                    /*----------------------------------------------
		    */
  info_ptr = (struct EL755info *) *handle;

  if (!EL755_AddCallStack(info_ptr, "EL755_SendTillSameVal"))
    return False;
                    /*----------------------------------------------
		    ** Send command. Do it in a
		    ** loop until we get the same response twice to guard
		    ** against RS-232-C problems with the EL755.
		    */
  i = n_ovfl = 0;
  *val = 9999.999;
  last_val = *val - 1.0;

  while (i < 6) {
    iret = AsynSrv_SendCmnds(&info_ptr->asyn_info,
                             &info_ptr->to_host, &info_ptr->from_host,
                             cmnd, NULL);
    if (!iret) {
      EL755_errcode = EL755__BAD_ASYNSRV;
      return False;
    }

    rply_ptr =
        AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL);
    if (rply_ptr == NULL) {
      EL755_AddCallStack(info_ptr, "NULL response");
      EL755_errcode = EL755__BAD_ILLG;
      return False;
    }

    if (strcmp(rply_ptr, "?OV") == 0) { /* Check for overflow. This seems
                                         ** to be an EL755 problem which
                                         ** needs fixing. In the meantime,
                                         ** just force a repeat.
                                         */
      sprintf(buff, "Warning -- \"?OV\" received in response to \"%s\".",
              cmnd);
      MakePrintable(buff, sizeof(buff), buff);
      EL755_ErrorLog(EL755_routine[EL755_call_depth - 1], buff);
      n_ovfl++;
      if (n_ovfl > 10) {
        EL755_errcode = EL755__TOO_MANY;
        return False;
      }
    } else {
      n_ovfl = 0;
      if (strcmp(rply_ptr, "?OF") == 0) {
        EL755_errcode = EL755__OFFLINE;
        return False;
      }
      if (strcmp(rply_ptr, "?OFL") == 0) {
        EL755_errcode = EL755__BAD_OFL;
        return False;
      }
      if (strcmp(rply_ptr, "?syntax failure") == 0) {
        EL755_errcode = EL755__BAD_CMD;
        return False;
      }
      if (strcmp(rply_ptr, "?power-supply OFF") == 0) { /* If off, return 0 */
        *val = 0.0;
        EL755_call_depth--;
        return True;
      } else {
        tok = strtok(rply_ptr, " ");
        if ((tok == NULL) ||
            (sscanf(tok, "%f%n", val, &cnt) != 1) ||
            (cnt != strlen(tok))) {
          EL755_AddCallStack(info_ptr, rply_ptr);
          EL755_errcode = EL755__BAD_ILLG;
          return False;
        }
        if (*val == last_val)
          break;
        last_val = *val;
      }
      i++;
    }
  }
  if (last_val != *val) {
    EL755_errcode = EL755__TOO_MANY;
    return False;
  }

  if (i > 1) {
    sprintf(buff, "Warning -- %d retries needed for Cmnd = \"%s\".",
            (i - 1), cmnd);
    MakePrintable(buff, sizeof(buff), buff);
    EL755_ErrorLog(EL755_routine[EL755_call_depth - 1], buff);
  }

  if (EL755_errcode != 0)
    return False;
  EL755_call_depth--;
  return True;
}

/*
**---------------------------------------------------------------------------
**		EL755_SendTillTwoVals:  Repeat a command until we get 2 fl.pt.
**				values and the first is the same on 2
**				successive occasions.
**
**		    This routine is intended for internal use only! It is
**		    intended to read the Soll- and Ist-currents where the
**		    Soll-value should be the same but the Ist-value could be
**		    changing as the power supply ramps to a new value.
**		    If too many retries, EL755_errcode is set to EL755__TOO_MANY.
*/
int EL755_SendTillTwoVals(
/*	=====================
*/ void **handle,
                           char *cmnd, float *val0, float *val1)
{

  int iret, i, n_ovfl, cnt0, cnt1;
  struct EL755info *info_ptr;
  float last_val;
  char *rply_ptr, *tok0, *tok1;
  char buff[132];
                    /*----------------------------------------------
		    */
  info_ptr = (struct EL755info *) *handle;

  if (!EL755_AddCallStack(info_ptr, "EL755_SendTillTwoVals"))
    return False;
                    /*----------------------------------------------
		    ** Send command. Do it in a
		    ** loop until we get the same response twice to guard
		    ** against RS-232-C problems with the EL755.
		    */
  i = n_ovfl = 0;
  *val0 = 9999.999;
  last_val = *val0 - 1.0;

  while (i < 6) {
    iret = AsynSrv_SendCmnds(&info_ptr->asyn_info,
                             &info_ptr->to_host, &info_ptr->from_host,
                             cmnd, NULL);
    if (!iret) {
      EL755_errcode = EL755__BAD_ASYNSRV;
      return False;
    }

    rply_ptr =
        AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL);
    if (rply_ptr == NULL) {
      EL755_AddCallStack(info_ptr, "NULL response");
      EL755_errcode = EL755__BAD_ILLG;
      return False;
    }

    if (strcmp(rply_ptr, "?OV") == 0) { /* Check for overflow. This seems
                                         ** to be an EL755 problem which
                                         ** needs fixing. In the meantime,
                                         ** just force a repeat.
                                         */
      sprintf(buff, "Warning -- \"?OV\" received in response to \"%s\".",
              cmnd);
      MakePrintable(buff, sizeof(buff), buff);
      EL755_ErrorLog(EL755_routine[EL755_call_depth - 1], buff);
      n_ovfl++;
      if (n_ovfl > 10) {
        EL755_errcode = EL755__TOO_MANY;
        return False;
      }
    } else {
      n_ovfl = 0;
      if (strcmp(rply_ptr, "?OF") == 0) {
        EL755_errcode = EL755__OFFLINE;
        return False;
      }
      if (strcmp(rply_ptr, "?OFL") == 0) {
        EL755_errcode = EL755__BAD_OFL;
        return False;
      }
      if (strcmp(rply_ptr, "?syntax failure") == 0) {
        EL755_errcode = EL755__BAD_CMD;
        return False;
      }
      if (strcmp(rply_ptr, "?power-supply OFF") == 0) { /* If off, return 0 */
        *val0 = 0.0;
        *val1 = 0.0;
        EL755_call_depth--;
        return True;
      } else {
        tok0 = strtok(rply_ptr, " ");
        tok1 = strtok(NULL, " ");
        if ((tok0 == NULL) ||
            (tok1 == NULL) ||
            (sscanf(tok0, "%f%n", val0, &cnt0) != 1) ||
            (sscanf(tok1, "%f%n", val1, &cnt1) != 1) ||
            (cnt0 != strlen(tok0)) || (cnt1 != strlen(tok1))) {
          EL755_AddCallStack(info_ptr, rply_ptr);
          EL755_errcode = EL755__BAD_ILLG;
          return False;
        }
        if (*val0 == last_val)
          break;
        last_val = *val0;
      }
      i++;
    }
  }
  if (last_val != *val0) {
    EL755_errcode = EL755__TOO_MANY;
    return False;
  }

  if (i > 1) {
    sprintf(buff, "Warning -- %d retries needed for Cmnd = \"%s\".",
            (i - 1), cmnd);
    MakePrintable(buff, sizeof(buff), buff);
    EL755_ErrorLog(EL755_routine[EL755_call_depth - 1], buff);
  }

  if (EL755_errcode != 0)
    return False;
  EL755_call_depth--;
  return True;
}

/*
**---------------------------------------------------------------------------
**		EL755_SetCurrent:  Sets current via EL755.
*/
int EL755_SetCurrent(
/*	================
*/ void **handle,
                      float soll)
{

  int i, iret;
  float my_soll, my_ist;
  char cmnd[32], cmnd0[32], buff[132], buff1[132];
  struct EL755info *info_ptr;
                    /*----------------------------------------------
		    */
  info_ptr = (struct EL755info *) *handle;

  if (!EL755_AddCallStack(info_ptr, "EL755_SetCurrent"))
    return False;
                    /*----------------------------------------------
		    ** Send I command to set EL755 current and I command
		    ** to read back the set value.
		    ** Repeat until set value is correct.
		    */
  sprintf(cmnd, "I %d %.4f\r", info_ptr->index, soll);
  sprintf(cmnd0, "I %d\r", info_ptr->index);
  i = 0;
  my_soll = soll + 1.0;

  while ((i < 6) && (fabs(soll - my_soll) > 0.01)) {
    iret = EL755_SendTillSameStr(handle, cmnd, buff, sizeof(buff));
    if (!iret)
      return False;
    if (buff[0] == NIL) {       /* We should get a null response */
      iret = EL755_SendTillSameVal(handle, cmnd0, &my_soll);
      if (!iret)
        return False;
    } else if (strcmp(buff, "?value out of range") == 0) {
      EL755_errcode = EL755__OUT_OF_RANGE;
      return False;
    } else if (strcmp(buff, "?current limitation") == 0) {
      EL755_errcode = EL755__TOO_LARGE;
      return False;
    } else if (strcmp(buff, "?power-supply OFF") == 0) {
      if (soll == 0.0) {        /* Suppress error if trying to set zero and
                                   .. power supply is off! */
        if (EL755_errcode != 0)
          return False;
        EL755_call_depth--;
        return True;
      } else {
        EL755_errcode = EL755__TURNED_OFF;
        return False;
      }
    } else {
      sprintf(buff1, "Cmnd=\"%s\" Rply=\"%.10s\"", cmnd, buff);
      MakePrintable(buff1, sizeof(buff1), buff1);
      EL755_AddCallStack(info_ptr, buff1);
      EL755_errcode = EL755__BAD_ILLG;
      return False;
    }
    i++;
  }

  if (fabs(soll - my_soll) > 0.01) {
    EL755_errcode = EL755__TOO_MANY;
    return False;
  }

  if (i > 1) {
    sprintf(buff, "Warning -- %d retries needed for Cmnd = \"%s\".",
            (i - 1), cmnd);
    MakePrintable(buff, sizeof(buff), buff);
    EL755_ErrorLog(EL755_routine[EL755_call_depth - 1], buff);
  }
  if (EL755_errcode != 0)
    return False;
  EL755_call_depth--;
  return True;
}

/*
**---------------------------------------------------------------------------
**		EL755_Send sends a command to the EL755 and gets a reply
**
**		    This routine is intended for internal use only!
*/
int EL755_Send(
/*	=====================
*/ void **handle,
                char *cmnd, char *rply, int rply_len)
{

  int iret, i, j, n_ovfl;
  struct EL755info *info_ptr;
  char *rply_ptr;
  char buff[132];
  char replies[6][64];
                    /*----------------------------------------------
		    */
  info_ptr = (struct EL755info *) *handle;

  if (!EL755_AddCallStack(info_ptr, "EL755_SendTillSameStr"))
    return False;
                    /*----------------------------------------------
		    ** Send command. 
		    */
  i = n_ovfl = 0;
  StrJoin(rply, rply_len, "#", "");


  iret = AsynSrv_SendCmnds(&info_ptr->asyn_info,
                           &info_ptr->to_host, &info_ptr->from_host,
                           cmnd, NULL);
  if (!iret) {
    EL755_errcode = EL755__BAD_ASYNSRV;
    return False;
  }
  rply_ptr =
      AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL);
  if (rply_ptr == NULL) {
    EL755_AddCallStack(info_ptr, "NULL response");
    EL755_errcode = EL755__BAD_ILLG;
    return False;
  }
  if (strncmp(rply_ptr, "?TMO", 4) == 0) {
    EL755_errcode = EL755__BAD_TMO;
    return False;
  }
  if (strcmp(rply_ptr, "?OF") == 0) {
    EL755_errcode = EL755__OFFLINE;
    return False;
  }
  if (strcmp(rply_ptr, "?OFL") == 0) {
    EL755_errcode = EL755__BAD_OFL;
    return False;
  }
  if (strcmp(rply_ptr, "?syntax failure") == 0) {
    EL755_errcode = EL755__BAD_CMD;
    return False;
  }
  if (strcmp(rply_ptr, "?OV") == 0) {   /* Check for overflow. This seems
                                         ** to be an EL755 problem which
                                         ** needs fixing. In the meantime,
                                         ** just force a repeat.
                                         */
    sprintf(buff, "Warning -- \"?OV\" received in response to \"%s\".",
            cmnd);
    MakePrintable(buff, sizeof(buff), buff);
    EL755_ErrorLog(EL755_routine[EL755_call_depth - 1], buff);
    n_ovfl++;
    if (n_ovfl > 10) {
      EL755_errcode = EL755__TOO_MANY;
      return False;
    }
  } else {
    n_ovfl = 0;
    if (strncmp(rply, rply_ptr, rply_len) == 0) {
      return False;
    }
    StrJoin(rply, rply_len, rply_ptr, "");
    MakePrintable(replies[i], sizeof(replies[0]), rply_ptr);
    i++;
  }
  if (EL755_errcode != 0)
    return False;
  EL755_call_depth--;
  return True;
}

/*-------------------------------------------- End of EL755_Utility.C =======*/
