#define	    ident	"2B03"
#ifdef VAXC
#module	    EL737_Utility	ident
#endif
#ifdef __DECC
#pragma	    module	    EL737_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]EL737_Utility.C
**
** Author   . . . . . . . . . . : D. Maden
** Date of creation . . . . . . : Apr 1996
**
**  To compile this module, use:

	$ import tasmad
	$ define/group sinq_c_tlb mad_lib:sinq_c.tlb
	$ cc /debug /noopt /obj=[]EL737_Utility -
			tasmad_disk:[mad.psi.lib.sinq]EL737_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 EL737_Utility debug
  $
  $ define/group sinq_olb mad_lib:sinq.olb
  $ @tasmad_disk:[mad.lib.sinq]sinq_olb EL737_Utility
**
** Updates:
**  1A01  2-Nov-1995 DM.	Initial version.
**  1B01 21-Mar-1996 DM.	Move from DELTAT.OLB to SINQ.OLB.
**  1C01 16-Jul-1997 DM.	Add code for EL737_Pause
**  2A01  6-Aug-1997 DM.	Cope with new RA response format (= timer first)
**				Add EL737_GetLongStatus.
**  2B01  5-Aug-1998 DM.	Put messages into a .MSG file.
**  2B02 22-Apr-1999 DM.	Add EL737_GetThresh and EL737_SetThresh.
**============================================================================
** The entry points included in this module are described below. Prototypes
** can be defined via:
**
**    #include <sinq_prototypes.h>
**
**	EL737_Close		- Close a connection to an EL737 counter.
**	EL737_Config		- Configure a connection to an EL737 counter.
**	EL737_Continue		- Continue a measurement with an EL737 counter.
**	EL737_EnableThresh	- Enable/disable threshold monitoring.
**	EL737_ErrInfo		- Return detailed status from last operation.
**	EL737_GetMonIntegTime	- Get Monitor Integration Time (DI register).
**	EL737_GetRateIntegTime	- Get Rate Integration Time (DT register).
**	EL737_GetStatus		- Get 4 counters and counter status.
**	EL737_GetStatusExtra	- Get counters 5 to 8.
**	EL737_GetThresh		- Get threshold monitoring status.
**	EL737_Open		- Open a connection to an EL737 counter.
**	EL737_Pause		- Pause a measurement with an EL737 counter.
**	EL737_SendCmnd		- Send a command to RS232C server.
**	EL737_SetErrcode	- Set up EL737_errcode.
**	EL737_SetThresh		- Set threshold monitoring level.
**	EL737_StartCnt		- Start a preset cnt measurement with an EL737.
**	EL737_StartTime		- Start a preset time measurement with an EL737.
**	EL737_Stop		- Stop a measurement with an EL737 counter.
**	EL737_StopFast		- Same as EL737_Stop but no registers are returned.
**	EL737_WaitIdle		- Wait till status goes to zero.
**---------------------------------------------------------------------
**    int EL737_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 EL737_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 a server,
**	then calling EL737_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 EL737_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 try to be used.
**
**	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.
**-------------------------------------------------------------------------
**   int  EL737_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 EL737_Open.
**			  It is used to hold the config info for the connection.
**  Return status:
**	True if no problems detected, otherwise False and EL737_errcode
**	is set to indicate the nature of the problem as follows:
**	    EL737__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 EL737info 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 EL737. The valid range is 100 to
**				    999'999. Default is 10'000.
**	    "eot"	char*	The expected terminators in responses to
**				    commands sent to the EL737. The first
**				    character specifies the number of
**				    terminators (max=3). Default is "1\r".
**-------------------------------------------------------------------------
**   int  EL737_Continue (&handle, &status)
**	  --------------
**  Input Args:
**	void **handle	- The pointer to the structure returned by EL737_Open.
**  Output Args:
**	int  *status	- The status (RS) of the counter after the CO cmnd.
**  Modified Args:
**	none
**  Return status:
**	True if no problems detected, otherwise False and EL737_ErrInfo
**	can be called to identify the problem. Values of Errcode set by
**	EL737_Continue are (other values may be set by the called routines):
**	    EL737__OFL, __BAD_CMD, __BAD_TMO, __BAD_ASYNSRV --> see EL737_Open.
**	    EL737__BAD_ILLG --> the response to the RS command was probably not
**				an integer. This could happen if there is noise
**				on the RS232C connection to the EL737.
**	If an error is detected, *status is set to 0.
**  Routines called:
**	AsynSrv_SendCmnds
**  Description:
**	EL737_Continue sends a CO command to the counter to get it to continue
**	a paused measurement and then an RS command to read its status.
**-------------------------------------------------------------------------
**   int  EL737_EnableThresh (&handle, indx)
**	  ------------------
**  Input Args:
**	void **handle	- The pointer to the structure returned by EL737_Open.
**	int    indx	- The number of the counter to select as the "active"
**			    threshold monitoring counter. If (indx == 0),
**			    threshold monitoring is disabled.
**  Output Args:
**	none
**  Modified Args:
**	none
**  Return status:
**	True if no problems detected, otherwise False and EL737_ErrInfo
**	can be called to identify the problem. Values of Errcode set by
**	EL737_EnableThresh are (other values may be set by the called routines):
**	    EL737__OFL, __BAD_CMD, __BAD_TMO, __BAD_ASYNSRV --> see EL737_Open.
**	    EL737__BAD_BSY  --> "?2" response received - cntr probably in
**					wrong state.
**	    EL737__BAD_PAR  --> Bad parameter. Illegal value for <indx> or "?3"
**				    or "?4" response received.
**	    EL737__BAD_ILLG --> the response to the commands was illegal in
**				some way. This could happen if there is noise
**				on the RS232C connection to the EL737.
**  Routines called:
**	AsynSrv_SendCmnds
**  Description:
**	A "DR <indx>" command is sent to select counter <indx> to be the
**	"active" threshold monitoring counter. A value of 0 causes
**	threshold monitoring to be disabled in the EL737. The threshold
**	for the selected counter will not be changed. If it is required
**	to set a threshold value as well as enabling monitoring, it is
**	simplest to use EL737_SetThresh.
**-------------------------------------------------------------------------
**    void EL737_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 EL737_GetMonIntegTime (&handle, indx, &mon_integ_time)
**	  ---------------------
**  Input Args:
**	void **handle	- The pointer to the structure returned by EL737_Open.
**	int    indx	- The counter whose integ time is wanted.
**  Output Args:
**	float *mon_integ_time	- The integration time used for monitoring
**				    the rate threshold.
**  Modified Args:
**	none
**  Return status:
**	True if no problems detected, otherwise False and EL737_ErrInfo
**	can be called to identify the problem. Values of Errcode set by
**	EL737_GetMonIntegTime are (other values may be set by the called
**	routines):
**	    EL737__BAD_TMO, _LOC, _CMD, _OFL, _ADR, _ASYNSRV --> see EL737_Open.
**	    EL737__BAD_ILLG --> the response was probably not a floating point
**				number. This could happen if there is noise
**				on the RS232C connection to the EL737.
**	If an error is detected, *mon_integ_time is set to 0.1.
**  Routines called:
**	AsynSrv_SendCmnds
**  Description:
**	The routine issues a "DI <indx>" command to the controller and
**	analyses the result.
**-------------------------------------------------------------------------
**    int EL737_GetRateIntegTime (&handle, &rate_integ_time)
**	  ----------------------
**  Input Args:
**	void **handle	- The pointer to the structure returned by EL737_Open.
**  Output Args:
**	float *rate_integ_time	- The integration time used for calculating
**				    the rates.
**  Modified Args:
**	none
**  Return status:
**	True if no problems detected, otherwise False and EL737_ErrInfo
**	can be called to identify the problem. Values of Errcode set by
**	EL737_GetRateIntegTime are (other values may be set by the called
**	routines):
**	    EL737__BAD_TMO, _LOC, _CMD, _OFL, _ADR, _ASYNSRV --> see EL737_Open.
**	    EL737__BAD_ILLG --> the response was probably not a floating point
**				number. This could happen if there is noise
**				on the RS232C connection to the EL737.
**	If an error is detected, *rate_integ_time is set to 0.1.
**  Routines called:
**	AsynSrv_SendCmnds
**  Description:
**	The routine issues a DT command to the controller and
**	analyses the result.
**-------------------------------------------------------------------------
**    int EL737_GetStatus (&handle, &c1, &c2, &c3, &c4, &timer, &rs)
**	  ---------------
**  Input Args:
**	void **handle	- The pointer to the structure returned by EL737_Open.
**  Output Args:
**	int   *c1	- Counter 1 (Monitor).
**	int   *c2	- Counter 2 (Detector).
**	int   *c3	- Counter 3.
**	int   *c4	- Counter 4.
**	float *timer	- The measured time.
**	int   *rs	- The counter status (RS command).
**  Modified Args:
**	none
**  Return status:
**	True if no problems detected, otherwise False and EL737_ErrInfo
**	can be called to identify the problem. Values of Errcode set by
**	EL737_GetStatus are (other values may be set by the called routines):
**	    EL737__BAD_TMO, _LOC, _CMD, _OFL, _ADR, _ASYNSRV --> see EL737_Open.
**	    EL737__BAD_ILLG --> one of the responses could probably not be
**				decoded. This could happen if there is noise
**				on the RS232C connection to the EL737.
**	If an error is detected, all arguments are set to 0.
**  Routines called:
**	AsynSrv_SendCmnds
**  Description:
**	The routine issues an RA and RS command to the controller and
**	analyses the result. If a syntax error is detected in either the RA
**	or RS response, the routine tries up to 3 times to get a meaningful
**	reply.
**-------------------------------------------------------------------------
**    int EL737_GetStatusExtra (&handle, &c5, &c6, &c7, &c8)
**	  --------------------
**  Input Args:
**	void **handle	- The pointer to the structure returned by EL737_Open.
**  Output Args:
**	int   *c5	- Counter 5.
**	int   *c6	- Counter 6.
**	int   *c7	- Counter 7.
**	int   *c8	- Counter 8.
**  Modified Args:
**	none
**  Return status:
**	True always.
**  Routines called:
**	None
**  Description:
**	The routine returns values for the counters 5, 6, 7 and 8 from the
**	counter's structure. A successful call to any of the routines which
**	return values for counters 1, 2, 3 and 4 must precede a call to
**	EL737_GetStatusExtra.
**-------------------------------------------------------------------------
**    int EL737_GetThresh (&handle, &indx, &val)
**	  ---------------
**  Input Args:
**	void **handle	- The pointer to the structure returned by EL737_Open.
**  Output Args:
**	int   *indx	- The number of the threshold monitor counter. If =0,
**			    threshold monitoring is disabled.
**	float *val	- If *indx != 0, the value of the threshold. Otherwise,
**			    it is zero.
**  Modified Args:
**	none
**  Return status:
**	True if no problems detected, otherwise False and EL737_ErrInfo
**	can be called to identify the problem. Values of Errcode set by
**	EL737_GetThresh are (other values may be set by the called routines):
**	    EL737__BAD_TMO, _LOC, _CMD, _OFL, _ADR, _ASYNSRV --> see EL737_Open.
**	    EL737__BAD_ILLG --> one of the responses could probably not be
**				decoded. This could happen if there is noise
**				on the RS232C connection to the EL737.
**	If an error is detected, all arguments are set to 0.
**  Routines called:
**	AsynSrv_SendCmnds
**  Description:
**	The routine issues a DR and, if threshold monitoring is enabled,
**	a "DL <indx>" command to the controller and analyses the responses.
**-------------------------------------------------------------------------
**    int EL737_Open (&handle, &host, port, chan)
**	  ----------
**  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.
**  Output Args:
**	void *handle	- A pointer to a structure of type EL737info needed for
**			   subsequent calls to EL737_... routines. Buffer space
**			   for the structure is allocated dynamically. It gets
**			   released via a call to EL737_Close.
**  Modified Args:
**	none
**  Return status:
**	True if no problems detected, otherwise False. If False, EL737_ErrInfo
**	can be called to identify the problem. Values of Errcode set by
**	EL737_Open are (other values may be set by the called routines):
**	  EL737__BAD_TMO     --> Time-out error ("?TMO" - this gets
**					generated by the RS232C server).
**	  EL737__BAD_LOC     --> EL737 off-line ("?OF"). This should not
**					happen on calls to EL737_Open since it
**					sends an "RMT 1" cmnd.
**	  EL737__BAD_CMD     --> Syntax error ("?1"). This could be
**					caused by noise in the RS-232-C
**					transmission.
**	  EL737__BAD_OFL     --> Connection to EL737 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.
**	  EL737__BAD_ILLG    --> Some other unrecognised response. This
**					should never occur, of course!
**	  EL737__BAD_DEV     --> Device doesn't seem to be an EL737. The
**					response to the RA command was bad.
**	  EL737__BAD_MALLOC  --> Call to "malloc" failed.
**	  EL737__BAD_ASYNSRV --> Call to AsynSrv_SendCmnds failed. Use
**					 AsynSrv_ErrInfo to get more details.
**  Routines called:
**	AsynSrv_Open, memory allocation routine "malloc" and AsynSrv_SendCmnds.
**  Description:
**	The routine opens a TCP/IP connection to a server offering the
**	"RS-232-C" service for an EL737 Neutron Counter. "RMT 1" and
**	"ECHO 2" commands are sent to ensure the device is on-line and an RA
**	command is sent to ensure that an EL737 is being addressed.
**-------------------------------------------------------------------------
**    int EL737_Pause (&handle, &status)
**	  -----------
**  Input Args:
**	void **handle	- The pointer to the structure returned by EL737_Open.
**  Output Args:
**	int  *status	- The status (RS) of the counter after the PS cmnd.
**  Modified Args:
**	none
**  Return status:
**	True if no problems detected, otherwise False and EL737_ErrInfo
**	can be called to identify the problem. Values of Errcode set by
**	EL737_Pause are (other values may be set by the called routines):
**	    EL737__OFL, __BAD_CMD, __BAD_TMO, __BAD_ASYNSRV --> see EL737_Open.
**	    EL737__BAD_ILLG --> the response to the RS command was probably not
**				an integer. This could happen if there is noise
**				on the RS232C connection to the EL737.
**	If an error is detected, *status is set to 0.
**  Routines called:
**	AsynSrv_SendCmnds
**  Description:
**	EL737_Pause sends a PS command to the counter to get it to pause
**	a measurement and then an RS command to read its status.
**-------------------------------------------------------------------------
**    int   EL737_SendCmnd (&handle, &cmnd, &rply, rply_size)
**	    --------------
**  Input Args:
**	void   **handle	- The pntr to the structure returned by EL737_Open.
**	char	*cmnd	- A command, terminated by NULL, for sending to the
**			    EL737 counter controller. The command must have
**			    any necessary \r character included.
**	int	 rply_size - the size of the <rply> 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
**	EL737_ErrInfo) is set to indicate the nature of the problem.
**	EL737_errcode may be set as follows:
**	    EL737__BAD_ASYNSRV --> An error occurred in AsynSrv_Utility.
**					    Call AsynSrv_ErrInfo for more info.
**  Routines called:
**	AsynSrv_SendCmnds
**  Description:
**	The command is passed to AsynSrv_SendCmnds and the reply extracted.
**-------------------------------------------------------------------------
**    int   EL737_SetErrcode (&info_ptr, &response, &cmnd)
**	    ----------------
**			    Set up EL737_errcode (for internal use only)
**  Input Args:
**	struct EL737info *info_ptr - The pntr to the structure returned by
**					EL737_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 EL737_errcode.
**  Routines called:
**	none
**  Description:
**	The command checks *response for certain keywords and sets EL737_errcode
**	accordingly.
**-------------------------------------------------------------------------
**   int  EL737_SetThresh (&handle, indx, val)
**	  ---------------
**  Input Args:
**	void **handle	- The pointer to the structure returned by EL737_Open.
**	int    indx	- The number of the counter whose threshold is to
**			    be set. If (indx == 0), threshold monitoring is
**			    disabled and val is not used.
**	float  val	- The value of the threshold to be set.
**  Output Args:
**	none
**  Modified Args:
**	none
**  Return status:
**	True if no problems detected, otherwise False and EL737_ErrInfo
**	can be called to identify the problem. Values of Errcode set by
**	EL737_SetThresh are (other values may be set by the called routines):
**	    EL737__OFL, __BAD_CMD, __BAD_TMO, __BAD_ASYNSRV --> see EL737_Open.
**	    EL737__BAD_BSY  --> "?2" response received - cntr probably in
**					wrong state.
**	    EL737__BAD_PAR  --> Bad parameter. Illegal value for <indx> or "?3"
**				    or "?4" response received.
**	    EL737__BAD_ILLG --> the response to the commands was illegal in
**				some way. This could happen if there is noise
**				on the RS232C connection to the EL737.
**  Routines called:
**	AsynSrv_SendCmnds, EL737_EnableThresh
**  Description:
**   a)	If (indx == 0):	EL737_SetThresh simply calls EL737_EnableThresh to
**			send a "DR 0" command which will disable threshold
**			monitoring by the counter.
**
**   b)	If (indx != 0):	First of all, a "DL <indx> |<val>|" command is sent
**			to the counter to set the threshold for counter <indx>
**			to the absolute value of <val>.
**			Then, if (val >= 0), EL737_EnableThresh is then called
**			to select counter <indx> to be the "active" threshold
**			monitoring counter. Otherwise, the "active" counter
**			is not changed.
**-------------------------------------------------------------------------
**   int  EL737_StartCnt (&handle, count, &status)
**	  --------------
**  Input Args:
**	void **handle	- The pointer to the structure returned by EL737_Open.
**	int    count	- The preset-count for the measurement.
**  Output Args:
**	int  *status	- The status (RS) of the counter after the MP cmnd.
**  Modified Args:
**	none
**  Return status:
**	True if no problems detected, otherwise False and EL737_ErrInfo
**	can be called to identify the problem. Values of Errcode set by
**	EL737_StartCnt are (other values may be set by the called routines):
**	    EL737__OFL, __BAD_CMD, __BAD_TMO, __BAD_ASYNSRV --> see EL737_Open.
**	    EL737__BAD_BSY  --> "?2" response received - cntr probably in
**					wrong state.
**	    EL737__BAD_PAR  --> "?3" response received - bad parameter.
**	    EL737__BAD_ILLG --> the response to the RS command was probably not
**				an integer. This could happen if there is noise
**				on the RS232C connection to the EL737.
**	If an error is detected, *status is set to 0.
**  Routines called:
**	AsynSrv_SendCmnds
**  Description:
**	EL737_StartCnt sends a MP command to the counter to get it to start
**	a preset-count measurement and then an RS command to read its status.
**-------------------------------------------------------------------------
**   int  EL737_StartTime (&handle, timer, &status)
**	  ---------------
**  Input Args:
**	void **handle	- The pointer to the structure returned by EL737_Open.
**	float  timer	- The preset-time for the measurement.
**  Output Args:
**	int  *status	- The status (RS) of the counter after the TP cmnd.
**  Modified Args:
**	none
**  Return status:
**	True if no problems detected, otherwise False and EL737_ErrInfo
**	can be called to identify the problem. Values of Errcode set by
**	EL737_StartTime are (other values may be set by the called routines):
**	    EL737__OFL, __BAD_CMD, __BAD_TMO, __BAD_ASYNSRV --> see EL737_Open.
**	    EL737__BAD_BSY  --> "?2" response received - cntr probably in
**					wrong state.
**	    EL737__BAD_PAR  --> "?3" response received - bad parameter.
**	    EL737__BAD_ILLG --> the response to the RS command was probably not
**				an integer. This could happen if there is noise
**				on the RS232C connection to the EL737.
**	If an error is detected, *status is set to 0.
**  Routines called:
**	AsynSrv_SendCmnds
**  Description:
**	EL737_StartTime sends a TP command to the counter to get it to start
**	a preset-time measurement and then an RS command to read its status.
**-------------------------------------------------------------------------
**   int  EL737_Stop (&handle, &c1, &c2, &c3, &c4, &timer, &rs)
**	  ----------
**  Input Args:
**	void **handle	- The pointer to the structure returned by EL737_Open.
**  Output Args:
**	int   *c1	- Counter 1 (Monitor).
**	int   *c2	- Counter 2 (Detector).
**	int   *c3	- Counter 3.
**	int   *c4	- Counter 4.
**	float *timer	- The measured time.
**	int   *rs	- The counter status (RS command) after the S cmnd.
**  Modified Args:
**	none
**  Return status:
**	True if no problems detected, otherwise False and EL737_ErrInfo
**	can be called to identify the problem. Values of Errcode set by
**	EL737_Stop are (other values may be set by the called routines):
**	    EL737__OFL, __BAD_CMD, __BAD_TMO, __BAD_ASYNSRV --> see EL737_Open.
**	    EL737__BAD_ILLG --> the response to the RA or RS command was
**				probably not an integer. This could happen if
**				there is noise on the RS232C connection to the
**				EL737.
**	If an error is detected, all output args are set to 0.
**  Routines called:
**	AsynSrv_SendCmnds
**  Description:
**	EL737_Stop sends an S command to the counter to get it to stop
**	a measurement. It then calls EL737_GetStatus to read the registers
**	and status.
**-------------------------------------------------------------------------
**   int  EL737_StopFast (&handle)
**	  --------------
**  Input Args:
**	void **handle	- The pointer to the structure returned by EL737_Open.
**  Output Args:
**	None
**  Modified Args:
**	none
**  Return status:
**	See EL737_Stop
**  Routines called:
**	AsynSrv_SendCmnds
**  Description:
**	EL737_StopFast sends an S command to the counter to get it to stop
**	a measurement. Unlike EL737_Stop, the registers are not read out.
**-------------------------------------------------------------------------
**    int   EL737_WaitIdle (&handle, &c1, &c2, &c3, &c4, &timer)
**	    --------------
**  Input Args:
**	void  **handle	    - The pntr to the structure returned by EL737_Open.
**  Output Args:
**	int	*c1	\
**	int	*c2	 \
**	int	*c3	  \	Same as EL737_GetStatus.
**	int	*c4	  /
**	float	*timer	 /
**  Modified Args:
**	none
**  Return status:
**	True if no problems detected, otherwise False and Errcode (see
**	EL737_ErrInfo) will have been set by the called routines to indicate
**	the nature of the problem.
**  Routines called:
**	EL737_GetStatus
**  Description:
**	Routine EL737_GetStatus is called repeatedly at a predefined frequency
**	until the RS register is zero.
**============================================================================*/
/*
**---------------------------------------------------------------------------
**					Global Definitions
*/
#include    <stdlib.h>
#include    <stdio.h>
#include    <stdarg.h>
#include    <math.h>
#include    <errno.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>
#ifdef FORTIFY
#include    <fortify.h>
#endif
#endif
/*-----------------------------------------------------------------*/
#include    <sinq_prototypes.h>
#include    <el737_def.h>
#include    <rs232c_def.h>

#define True	1
#define False	0
/*--------------------------------------------------------------------------
**					Global Variables
*/
static int EL737_call_depth = 0;
static char EL737_routine[5][64];
static int EL737_errcode = 0;
static int EL737_errno, EL737_vaxc_errno;
/*
**---------------------------------------------------------------------------
**		EL737_AddCallStack:  Add a routine name to the call stack.
**				     This allows EL737_ErrInfo to generate a
**				     trace-back in case of error.
*/
int EL737_AddCallStack(
/*	==================
*/ struct EL737info *pntr,
                        char *name)
{

  if (EL737_errcode != 0)
    return False;

  if (EL737_call_depth < 5) {
    strcpy(EL737_routine[EL737_call_depth], name);
    EL737_call_depth++;
  }

  if (pntr == NULL) {
    EL737_errcode = EL737__NOT_OPEN;
    return False;
  }

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

/*
**---------------------------------------------------------------------------
**		EL737_Close:  Close a connection to an EL737 counter.
*/
int EL737_Close(
/*	===========
*/ void **handle,
                 int force_flag)
{

  struct EL737info *info_ptr;
  char buff[4];

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

/*
**---------------------------------------------------------------------------
**		EL737_Config:  Configure a connection to an EL737 counter.
*/
int EL737_Config(
/*	============
*/ void **handle,
                  ...)
{

  char buff[16];
  va_list ap;                   /* Pointer to variable args */
  char *txt_ptr;
  int intval;
  struct EL737info *info_ptr;
                    /*----------------------------------------------
		    */
  info_ptr = (struct EL737info *) *handle;

  if (!EL737_AddCallStack(info_ptr, "EL737_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)) {
        EL737_errcode = EL737__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) {
        EL737_errcode = EL737__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:
        EL737_errcode = EL737__BAD_PAR;
        return False;
      }
    } else {
      EL737_errcode = EL737__BAD_PAR;
      return False;
    }
    txt_ptr = va_arg(ap, char *);       /* Get pntr to next parameter ident */
  }

  if (EL737_errcode != 0)
    return False;
  EL737_call_depth--;
  return True;
}

/*
**---------------------------------------------------------------------------
**		EL737_Continue:  Continue a measurement with an EL737 counter.
*/
int EL737_Continue(
/*	==============
*/ void **handle,
                    int *status)
{

  int my_status;
  struct EL737info *info_ptr;
  char *rply_ptr0, *rply_ptr1;
                    /*----------------------------------------------
		    */
  *status = 0;
  info_ptr = (struct EL737info *) *handle;

  if (!EL737_AddCallStack(info_ptr, "EL737_Continue"))
    return False;
                    /*----------------------------------------------
		    ** Send CO and RS cmnds to EL737
		    */
  my_status = AsynSrv_SendCmnds(&info_ptr->asyn_info,
                                &info_ptr->to_host, &info_ptr->from_host,
                                "CO\r", "RS\r", NULL);
  if (!my_status) {
    EL737_errcode = EL737__BAD_ASYNSRV;
    return False;
  }
  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 = "?";
  if (rply_ptr1 == NULL)
    rply_ptr1 = "?";
  if (((*rply_ptr0 == '\0') || (*rply_ptr0 == '\r')) &&
      (sscanf(rply_ptr1, "%d", status) == 1)) {
    if (EL737_errcode != 0)
      return False;
    EL737_call_depth--;
    return True;
  }
  *status = 0;
  EL737_SetErrcode(info_ptr, rply_ptr0, "CO\" or \"RS");
  return False;
}

/*
**---------------------------------------------------------------------------
**		EL737_EnableThresh:  Enable/disable Threshold Monitoring.
*/
int EL737_EnableThresh(
/*	==================
*/ void **handle,
                        int indx)
{

  int status;
  char cmnd[20];
  struct EL737info *info_ptr;
  char *rply_ptr0;
                    /*----------------------------------------------
		    */
  info_ptr = (struct EL737info *) *handle;

  if (!EL737_AddCallStack(info_ptr, "EL737_EnableThresh"))
    return False;

  if ((indx < 0) || (indx > 8)) {
    EL737_errcode = EL737__BAD_PAR;
    return False;
  }
                    /*----------------------------------------------
		    ** Send "DR <indx>" cmnd to EL737 to select the
		    ** "active" threshold rate counter.
		    */
  sprintf(cmnd, "DR %d\r", indx);
  status = AsynSrv_SendCmnds(&info_ptr->asyn_info,
                             &info_ptr->to_host, &info_ptr->from_host,
                             cmnd, NULL);
  if (!status) {
    EL737_errcode = EL737__BAD_ASYNSRV;
    return False;
  }
  rply_ptr0 =
      AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL);
  if (rply_ptr0 == NULL)
    rply_ptr0 = "?";
  if ((*rply_ptr0 == '\0') || (*rply_ptr0 == '\r')) {
    EL737_call_depth--;
    return True;
  }
  EL737_SetErrcode(info_ptr, rply_ptr0, cmnd);
  return False;
}

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

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

  if (EL737_call_depth <= 0) {
    strcpy(EL737_routine[0], "EL737_no_error_detected");
    *errcode = 0;
    *my_errno = 0;
    *vaxc_errno = 0;
  } else {
    if (EL737_call_depth > 1) { /* Concatenate the names */
      for (i = 1; i < EL737_call_depth; i++) {
        strcat(EL737_routine[0], "/");
        StrJoin(EL737_routine[0], sizeof(EL737_routine),
                EL737_routine[0], EL737_routine[i]);
      }
    }
    *errcode = EL737_errcode;
    *my_errno = EL737_errno;
    *vaxc_errno = EL737_vaxc_errno;
    switch (EL737_errcode) {
    case EL737__BAD_ASYNSRV:
      strcpy(buff, "/EL737__BAD_ASYNSRV");
      break;
    case EL737__BAD_BSY:
      strcpy(buff, "/EL737__BAD_BSY");
      break;
    case EL737__BAD_CMD:
      strcpy(buff, "/EL737__BAD_CMD");
      break;
    case EL737__BAD_CNTR:
      strcpy(buff, "/EL737__BAD_CNTR");
      break;
    case EL737__BAD_DEV:
      strcpy(buff, "/EL737__BAD_DEV");
      break;
    case EL737__BAD_ILLG:
      strcpy(buff, "/EL737__BAD_ILLG");
      break;
    case EL737__BAD_LOC:
      strcpy(buff, "/EL737__BAD_LOC");
      break;
    case EL737__BAD_MALLOC:
      strcpy(buff, "/EL737__BAD_MALLOC");
      break;
    case EL737__BAD_OFL:
      strcpy(buff, "/EL737__BAD_OFL");
      break;
    case EL737__BAD_OVFL:
      strcpy(buff, "/EL737__BAD_OVFL");
      break;
    case EL737__BAD_PAR:
      strcpy(buff, "/EL737__BAD_PAR");
      break;
    case EL737__BAD_SOCKET:
      strcpy(buff, "/EL737__BAD_SOCKET");
      break;
    case EL737__BAD_TMO:
      strcpy(buff, "/EL737__BAD_TMO");
      break;
    case EL737__CNTR_OVFL:
      strcpy(buff, "/EL737__CNTR_OVFL");
      break;
    case EL737__FORCED_CLOSED:
      strcpy(buff, "/EL737__FORCED_CLOSED");
      break;
    case EL737__NOT_OPEN:
      strcpy(buff, "/EL737__NOT_OPEN");
      break;
    case EL737__NO_SOCKET:
      strcpy(buff, "/EL737__NO_SOCKET");
      break;
    case EL737__NO_VALUE:
      strcpy(buff, "/EL737__NO_VALUE");
      break;
    default:
      sprintf(buff, "/EL737__unknown_err_code: %d", EL737_errcode);
    }
    StrJoin(EL737_routine[0], sizeof(EL737_routine), EL737_routine[0],
            buff);
  }
  AsynSrv_ErrInfo(&asyn_errtxt, &asyn_errcode, &asyn_errno,
                  &asyn_vaxerrno);
  if (asyn_errcode != 0) {
    strcat(EL737_routine[0], "/");
    StrJoin(EL737_routine[0], sizeof(EL737_routine),
            EL737_routine[0], asyn_errtxt);
  }
  *entry_txt = EL737_routine[0];
  EL737_call_depth = 0;
  EL737_errcode = 0;
}

/*
**---------------------------------------------------------------------------
**		EL737_GetMonIntegTime:  Get DI register value for a counter.
*/
int EL737_GetMonIntegTime(
/*	=====================
*/ void **handle,
                           int indx, float *mon_integ_time)
{

  int status;
  char cmnd[20];
  struct EL737info *info_ptr;
  char *rply_ptr0;
                    /*----------------------------------------------
		    */
  *mon_integ_time = 0.1;
  info_ptr = (struct EL737info *) *handle;

  if (!EL737_AddCallStack(info_ptr, "EL737_GetMonIntegTime"))
    return False;
                    /*----------------------------------------------
		    ** Send "DI <indx>" cmnd to EL737
		    */
  sprintf(cmnd, "DI %d\r", indx);
  status = AsynSrv_SendCmnds(&info_ptr->asyn_info,
                             &info_ptr->to_host, &info_ptr->from_host,
                             cmnd, NULL);
  if (!status) {
    EL737_errcode = EL737__BAD_ASYNSRV;
    return False;
  } else {
    rply_ptr0 =
        AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL);
    if (rply_ptr0 == NULL)
      rply_ptr0 = "?";
    if (sscanf(rply_ptr0, "%f", mon_integ_time) == 1) {
      if (EL737_errcode != 0)
        return False;
      EL737_call_depth--;
      return True;
    }
    *mon_integ_time = 0.1;
    EL737_SetErrcode(info_ptr, rply_ptr0, cmnd);
    return False;
  }
}

/*
**---------------------------------------------------------------------------
**		EL737_GetRateIntegTime:  Get DT register value.
*/
int EL737_GetRateIntegTime(
/*	======================
*/ void **handle,
                            float *rate_integ_time)
{

  int status;
  struct EL737info *info_ptr;
  char *rply_ptr0;
                    /*----------------------------------------------
		    */
  *rate_integ_time = 0.1;
  info_ptr = (struct EL737info *) *handle;

  if (!EL737_AddCallStack(info_ptr, "EL737_GetRateIntegTime"))
    return False;
                    /*----------------------------------------------
		    ** Send DT cmnd to EL737
		    */
  status = AsynSrv_SendCmnds(&info_ptr->asyn_info,
                             &info_ptr->to_host, &info_ptr->from_host,
                             "DT\r", NULL);
  if (!status) {
    EL737_errcode = EL737__BAD_ASYNSRV;
    return False;
  } else {
    rply_ptr0 =
        AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL);
    if (rply_ptr0 == NULL)
      rply_ptr0 = "?";
    if (sscanf(rply_ptr0, "%f", rate_integ_time) == 1) {
      if (EL737_errcode != 0)
        return False;
      EL737_call_depth--;
      return True;
    }
    EL737_SetErrcode(info_ptr, rply_ptr0, "DT");
    *rate_integ_time = 0.1;
    return False;
  }
}

/*
**---------------------------------------------------------------------------
**		EL737_GetStatus:  Get RA/RS register values.
*/
int EL737_GetStatus(
/*	===============
*/ void **handle,
                     int *c1,
                     int *c2, int *c3, int *c4, float *timer, int *rs)
{

  int i, status, nvals;
  struct EL737info *info_ptr;
  char *rply_ptr, *p_cmnd;
                    /*----------------------------------------------
		    */
  *c1 = *c2 = *c3 = *c4 = *rs = 0;
  *timer = 0.0;
  info_ptr = (struct EL737info *) *handle;

  if (!EL737_AddCallStack(info_ptr, "EL737_GetStatus"))
    return False;
  info_ptr->c5 = info_ptr->c6 = info_ptr->c7 = info_ptr->c8 = 0;
                    /*----------------------------------------------
		    ** Send RA and RS cmnds to EL737. Since this routine gets
		    ** used such a lot, try up to 3 times if a syntax error in
		    ** the reply is detected.
		    */
  for (i = 0; i < 3; i++) {
    status = AsynSrv_SendCmnds(&info_ptr->asyn_info,
                               &info_ptr->to_host, &info_ptr->from_host,
                               "RA\r", "RS\r", NULL);
    if (!status) {
      EL737_errcode = EL737__BAD_ASYNSRV;
      return False;
    }
    p_cmnd = "RA";
    rply_ptr =
        AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL);
    if (rply_ptr != NULL) {
      nvals = sscanf(rply_ptr, "%f %d %d %d %d %d %d %d %d",
                     timer, c1, c2, c3, c4,
                     &info_ptr->c5, &info_ptr->c6,
                     &info_ptr->c7, &info_ptr->c8);
      if (nvals != 9)
        nvals = sscanf(rply_ptr, "%d %d %d %d %f", c1, c2, c3, c4, timer);
      if (nvals == 5) {
        info_ptr->c5 = info_ptr->c6 = info_ptr->c7 = info_ptr->c8 = 0;
        nvals = 9;
      }
      if (nvals == 9) {
        p_cmnd = "RS";
        rply_ptr =
            AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host,
                             rply_ptr);
        if (rply_ptr != NULL) {
          if (sscanf(rply_ptr, "%d", rs) == 1) {
            EL737_call_depth--;
            return True;
          }
        }
      }
    }
  }
  if (rply_ptr == NULL)
    rply_ptr = "?";
  EL737_SetErrcode(info_ptr, rply_ptr, p_cmnd);
  *c1 = *c2 = *c3 = *c4 = *rs = 0;
  *timer = 0.0;
  return False;
}

/*
**---------------------------------------------------------------------------
**		EL737_GetStatusExtra:  Get values of extra counters.
*/
int EL737_GetStatusExtra(
/*	====================
*/ void **handle,
                          int *c5, int *c6, int *c7, int *c8)
{

  struct EL737info *info_ptr;
                    /*----------------------------------------------
		    */
  *c5 = *c6 = *c7 = *c8 = 0;
  info_ptr = (struct EL737info *) *handle;

  if (!EL737_AddCallStack(info_ptr, "EL737_GetStatusExtra"))
    return False;

  *c5 = info_ptr->c5;
  *c6 = info_ptr->c6;
  *c7 = info_ptr->c7;
  *c8 = info_ptr->c8;

  if (EL737_errcode != 0)
    return False;
  EL737_call_depth--;
  return True;
}

/*
**---------------------------------------------------------------------------
**		EL737_GetThresh:  Get threshold monitoring status.
*/
int EL737_GetThresh(
/*	===============
*/ void **handle,
                     int *indx, float *val)
{

  int status, my_indx;
  float my_val;
  char cmnd[20];
  struct EL737info *info_ptr;
  char *rply_ptr0;
                    /*----------------------------------------------
		    */
  *indx = 0;
  *val = 0.0;
  info_ptr = (struct EL737info *) *handle;

  if (!EL737_AddCallStack(info_ptr, "EL737_GetThresh"))
    return False;
                    /*----------------------------------------------
		    ** Send DR cmnd to EL737 to get the number of the
		    ** "active" threshold rate counter.
		    */
  status = AsynSrv_SendCmnds(&info_ptr->asyn_info,
                             &info_ptr->to_host, &info_ptr->from_host,
                             "DR\r", NULL);
  if (!status) {
    EL737_errcode = EL737__BAD_ASYNSRV;
    return False;
  }
  rply_ptr0 =
      AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL);
  if (rply_ptr0 == NULL)
    rply_ptr0 = "?";
  if ((sscanf(rply_ptr0, "%d", &my_indx) == 1) &&
      (my_indx >= 0) && (my_indx <= 8)) {
    *indx = my_indx;
    if (my_indx != 0) {
                    /*----------------------------------------------
		    ** Now send DL cmnd to EL737 to get the threshold value.
		    */
      sprintf(cmnd, "DL %d\r", my_indx);
      status = AsynSrv_SendCmnds(&info_ptr->asyn_info,
                                 &info_ptr->to_host, &info_ptr->from_host,
                                 cmnd, NULL);
      if (!status) {
        EL737_errcode = EL737__BAD_ASYNSRV;
        return False;
      }
      rply_ptr0 =
          AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host,
                           NULL);
      if (rply_ptr0 == NULL)
        rply_ptr0 = "?";
      if (sscanf(rply_ptr0, "%f", &my_val) == 1) {
        *val = my_val;
        EL737_call_depth--;
        return True;
      }
    } else {
      *val = 0.0;
      EL737_call_depth--;
      return True;
    }
  }
  EL737_SetErrcode(info_ptr, rply_ptr0, cmnd);
  return False;
}

/*
**---------------------------------------------------------------------------
**		EL737_Open:  Open a connection to an EL737 counter.
*/
int EL737_Open(
/*	==========
*/ void **handle,
                char *host, int port, int chan)
{

  int status, c1, c2, c3, c4, nvals;
  float timer;
  struct EL737info *my_handle;
  char tmo_save[4];
  char *rply_ptr;
  char *rply_ptr0;
  char *rply_ptr1;
  char *rply_ptr2;
/*--------------------------------------------------------
**			Initialise the error info stack and pre-set the
**			routine name (in case of error).
*/
  EL737_errcode = EL737_errno = EL737_vaxc_errno = 0;
  strcpy(EL737_routine[0], "EL737_Open");
  EL737_call_depth = 1;
/*--------------------------------------------------------
**				    Assume trouble
*/
  *handle = NULL;
/*--------------------------------------------------------
**			    Reserve space for the data we need to store.
*/
  my_handle = (struct EL737info *) malloc(sizeof(*my_handle));
  if (my_handle == NULL) {
    EL737_errcode = EL737__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) {
    EL737_errcode = EL737__BAD_SOCKET;
    GetErrno(&EL737_errno, &EL737_vaxc_errno);  /* Save errno info */
    fprintf(stderr, "\nEL737_Open/AsynSrv_Open: "
            "Failed to make connection.\n");
    free(my_handle);
    return False;
  }

  memcpy(tmo_save, my_handle->asyn_info.tmo, 4);
  EL737_Config((void *) &my_handle, "msecTmo", 500,     /* Set a short time-out initially since
                                                         ** there should be no reason for the RMT,
                                                         ** ECHO or RA commands to take very long
                                                         */
               "eot", "1\r", NULL);
  /*
   ** Now ensure the EL737 is on-line. The first "RMT 1" command can
   ** fail due to pending characters in the EL737 input buffer causing
   ** the "RMT 1" to be corrupted. The response of the EL737 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);
  if (status) {
    status = AsynSrv_SendCmnds(&my_handle->asyn_info,
                               &my_handle->to_host, &my_handle->from_host,
                               "RMT 1\r", "ECHO 2\r", "RA\r", NULL);
  }
  if (!status) {
    /* Some error occurred in AsynSrv_SendCmnds */
    EL737_errcode = EL737__BAD_ASYNSRV;
    AsynSrv_Close(&my_handle->asyn_info, False);
    free(my_handle);
    return False;
  } else {
    /* Check the responses carefully.
     */
    rply_ptr1 = rply_ptr2 = 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_ptr0 == NULL)
      rply_ptr0 = "?";
    if (rply_ptr1 == NULL)
      rply_ptr1 = "?";
    if (rply_ptr2 == NULL)
      rply_ptr2 = "?";

    if (*rply_ptr1 == '?')
      rply_ptr0 = rply_ptr1;
    if (*rply_ptr2 == '?')
      rply_ptr0 = rply_ptr2;
    if (*rply_ptr0 != '?') {
      nvals = sscanf(rply_ptr2, "%f %d %d %d %d %d %d %d %d",
                     &timer, &c1, &c2, &c3, &c4,
                     &my_handle->c5, &my_handle->c6,
                     &my_handle->c7, &my_handle->c8);
      if (nvals != 9)
        nvals = sscanf(rply_ptr2, "%d %d %d %d %f",
                       &c1, &c2, &c3, &c4, &timer);
      if (nvals == 5) {
        my_handle->c5 = my_handle->c6 = my_handle->c7 = my_handle->c8 = 0;
        nvals = 9;
      }
      if (nvals != 9) {
        EL737_errcode = EL737__BAD_DEV; /* Device is not EL737 */
        AsynSrv_Close(&my_handle->asyn_info, False);
        free(my_handle);
        return False;
      }
      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 (EL737_errcode != 0)
        return False;
      EL737_call_depth--;
      return True;
    } else {
      EL737_SetErrcode(my_handle, rply_ptr0, "RMT\", \"ECHO\" or \"RA");
    }
  }
  AsynSrv_Close(&my_handle->asyn_info, False);
  free(my_handle);
  return False;
}

/*
**---------------------------------------------------------------------------
**		EL737_Pause:  Pause a measurement with an EL737 counter.
*/
int EL737_Pause(
/*	===========
*/ void **handle,
                 int *status)
{

  int my_status;
  struct EL737info *info_ptr;
  char *rply_ptr0, *rply_ptr1;
                    /*----------------------------------------------
		    */
  *status = 0;
  info_ptr = (struct EL737info *) *handle;

  if (!EL737_AddCallStack(info_ptr, "EL737_Pause"))
    return False;
                    /*----------------------------------------------
		    ** Send PS and RS cmnds to EL737
		    */
  my_status = AsynSrv_SendCmnds(&info_ptr->asyn_info,
                                &info_ptr->to_host, &info_ptr->from_host,
                                "PS\r", "RS\r", NULL);
  if (!my_status) {
    EL737_errcode = EL737__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 = "?";
    if (rply_ptr1 == NULL)
      rply_ptr1 = "?";
    if (((*rply_ptr0 == '\0') || (*rply_ptr0 == '\r')) &&
        (sscanf(rply_ptr1, "%d", status) == 1)) {
      if (EL737_errcode != 0)
        return False;
      EL737_call_depth--;
      return True;
    }
    EL737_SetErrcode(info_ptr, rply_ptr0, "PS\" or \"RS");
    *status = 0;
    return False;
  }
}

/*
**---------------------------------------------------------------------------
**		EL737_SendCmnd - Send a command to RS232C server.
*/
int EL737_SendCmnd(
/*	==============
*/ void **handle,
                    char *cmnd, char *rply, int rply_size)
{

  struct EL737info *info_ptr;
  int my_status;
  char *rply_ptr;
                    /*----------------------------------------------
		    */
  info_ptr = (struct EL737info *) *handle;

  if (!EL737_AddCallStack(info_ptr, "EL737_SendCmnd"))
    return False;
                    /*----------------------------------------------
		    ** Send command to EL737.
		    */
  my_status = AsynSrv_SendCmnds(&info_ptr->asyn_info,
                                &info_ptr->to_host, &info_ptr->from_host,
                                cmnd, NULL);
  if (!my_status) {
    EL737_errcode = EL737__BAD_ASYNSRV;
    return False;
  } else {
    rply_ptr =
        AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL);
    if (rply_ptr == NULL)
      rply_ptr = "?";
    StrJoin(rply, rply_size, rply_ptr, "");
  }

  if (EL737_errcode != 0)
    return False;
  EL737_call_depth--;
  return True;
}

/*
**---------------------------------------------------------------------------
**		EL737_SetErrcode - Set up EL737_errcode
*/
int EL737_SetErrcode(
/*	================
*/ struct EL737info *info_ptr,
                      char *response, char *cmnd)
{

  int status, s_len;
  char *rply;
  char tmo_save[4];
  char eot_save[4];

  EL737_errcode = EL737__BAD_ILLG;
  if (strcmp(response, "?OF") == 0)
    EL737_errcode = EL737__BAD_LOC;
  if (strcmp(response, "?OFL") == 0)
    EL737_errcode = EL737__BAD_OFL;
  if (strcmp(response, "?OV") == 0)
    EL737_errcode = EL737__BAD_OVFL;
  if (strcmp(response, "?1") == 0)
    EL737_errcode = EL737__BAD_CMD;
  if (strcmp(response, "?2") == 0)
    EL737_errcode = EL737__BAD_BSY;
  if (strcmp(response, "?3") == 0)
    EL737_errcode = EL737__BAD_PAR;
  if (strcmp(response, "?4") == 0)
    EL737_errcode = EL737__BAD_CNTR;
  if (strcmp(response, "?5") == 0)
    EL737_errcode = EL737__NO_VALUE;
  if (strcmp(response, "?6") == 0)
    EL737_errcode = EL737__CNTR_OVFL;
  if (strncmp(response, "?TMO", 4) == 0)
    EL737_errcode = EL737__BAD_TMO;

  if ((EL737_errcode == EL737__BAD_ILLG) && (cmnd != NULL)) {
    s_len = strlen(cmnd);
    if (cmnd[s_len - 1] == '\r')
      s_len--;
    fprintf(stderr, " Unrecognised response to \"%.*s\" command: \"%s\"\n",
            s_len, cmnd, response);
  }

  return EL737_errcode;
}

/*
**---------------------------------------------------------------------------
**		EL737_SetThresh:  Set threshold monitoring level.
*/
int EL737_SetThresh(
/*	===============
*/ void **handle,
                     int indx, float val)
{

  int status;
  char cmnd[32];
  struct EL737info *info_ptr;
  char *rply_ptr0;
                    /*----------------------------------------------
		    */
  info_ptr = (struct EL737info *) *handle;

  if (!EL737_AddCallStack(info_ptr, "EL737_SetThresh"))
    return False;

  if ((indx < 0) || (indx > 8)) {
    EL737_errcode = EL737__BAD_PAR;
    return False;
  }
                    /*----------------------------------------------
		    ** If <indx> is zero, simply call EL737_EnableThresh to
		    ** disable threshold monitoring by the counter.
		    */
  if (indx == 0) {
    return EL737_EnableThresh(handle, 0);
  }
                    /*----------------------------------------------
		    ** Send "DR <indx> |<val>|" cmnd to EL737 to set the
		    ** threshold for counter <indx>.
		    */
  sprintf(cmnd, "DL %d %.3f\r", indx, fabs(val));
  status = AsynSrv_SendCmnds(&info_ptr->asyn_info,
                             &info_ptr->to_host, &info_ptr->from_host,
                             cmnd, NULL);
  if (!status) {
    EL737_errcode = EL737__BAD_ASYNSRV;
    return False;
  }
  rply_ptr0 =
      AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL);
  if (rply_ptr0 == NULL)
    rply_ptr0 = "?";
  if ((*rply_ptr0 == '\0') || (*rply_ptr0 == '\r')) {
    if (val >= 0)
      return EL737_EnableThresh(handle, indx);
    EL737_call_depth--;
    return True;
  }
  EL737_SetErrcode(info_ptr, rply_ptr0, cmnd);
  return False;
}

/*
**---------------------------------------------------------------------------
**		EL737_StartCnt:  Start a preset cnt measurement with an EL737.
*/
int EL737_StartCnt(
/*	==============
*/ void **handle,
                    int count, int *status)
{

  int my_status;
  char cmnd[20];
  struct EL737info *info_ptr;
  char *rply_ptr0, *rply_ptr1;
                    /*----------------------------------------------
		    */
  *status = 0;
  info_ptr = (struct EL737info *) *handle;

  if (!EL737_AddCallStack(info_ptr, "EL737_StartCnt"))
    return False;
                    /*----------------------------------------------
		    ** Send MP and RS cmnds to EL737
		    */
  sprintf(cmnd, "MP %d\r", count);      /* Encode an appropriate command */
  my_status = AsynSrv_SendCmnds(&info_ptr->asyn_info,   /* Send it */
                                &info_ptr->to_host, &info_ptr->from_host,
                                cmnd, "RS\r", NULL);
  if (!my_status) {
    EL737_errcode = EL737__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 = "?";
    if (rply_ptr1 == NULL)
      rply_ptr1 = "?";
    if (((*rply_ptr0 == '\0') || (*rply_ptr0 == '\r')) &&
        (sscanf(rply_ptr1, "%d", status) == 1)) {
      if (EL737_errcode != 0)
        return False;
      EL737_call_depth--;
      return True;
    }
    EL737_SetErrcode(info_ptr, rply_ptr0, cmnd);
    *status = 0;
    return False;
  }
}

/*
**---------------------------------------------------------------------------
**		EL737_StartTime:  Start a preset time measurement with an EL737.
*/
int EL737_StartTime(
/*	===============
*/ void **handle,
                     float timer, int *status)
{

  int my_status;
  char cmnd[20];
  struct EL737info *info_ptr;
  char *rply_ptr0, *rply_ptr1;
                    /*----------------------------------------------
		    */
  *status = 0;
  info_ptr = (struct EL737info *) *handle;

  if (!EL737_AddCallStack(info_ptr, "EL737_StartTime"))
    return False;
                    /*----------------------------------------------
		    ** Send TP and RS cmnds to EL737
		    */
  sprintf(cmnd, "TP %.2f\r", timer);    /* Encode an appropriate command */
  my_status = AsynSrv_SendCmnds(&info_ptr->asyn_info,   /* Send it */
                                &info_ptr->to_host, &info_ptr->from_host,
                                cmnd, "RS\r", NULL);
  if (!my_status) {
    EL737_errcode = EL737__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 = "?";
    if (rply_ptr1 == NULL)
      rply_ptr1 = "?";
    if (((*rply_ptr0 == '\0') || (*rply_ptr0 == 'r')) &&
        (sscanf(rply_ptr1, "%d", status) == 1)) {
      if (EL737_errcode != 0)
        return False;
      EL737_call_depth--;
      return True;
    }
    EL737_SetErrcode(info_ptr, rply_ptr0, cmnd);
    *status = 0;
    return False;
  }
}

/*
**---------------------------------------------------------------------------
**		EL737_Stop:  stop a measurement with an EL737 counter.
*/
int EL737_Stop(
/*	==========
*/ void **handle,
                int *c1, int *c2, int *c3, int *c4, float *timer, int *rs)
{

  int my_status, nvals;
  struct EL737info *info_ptr;
  char *rply_ptr0, *rply_ptr1, *rply_ptr2;
                    /*----------------------------------------------
		    */
  *c1 = *c2 = *c3 = *c4 = *rs = 0;
  *timer = 0.0;
  info_ptr = (struct EL737info *) *handle;

  if (!EL737_AddCallStack(info_ptr, "EL737_Stop"))
    return False;
                    /*----------------------------------------------
		    ** Send S, RS and RA cmnds to EL737
		    */
  my_status = AsynSrv_SendCmnds(&info_ptr->asyn_info,
                                &info_ptr->to_host, &info_ptr->from_host,
                                "S\r", "RS\r", "RA\r", NULL);
  if (!my_status) {
    EL737_errcode = EL737__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 = "?";
    if (rply_ptr1 == NULL)
      rply_ptr1 = "?";
    if (rply_ptr2 == NULL)
      rply_ptr2 = "?";

    nvals = sscanf(rply_ptr2, "%f %d %d %d %d %d %d %d %d",
                   timer, c1, c2, c3, c4,
                   &info_ptr->c5, &info_ptr->c6,
                   &info_ptr->c7, &info_ptr->c8);
    if (nvals != 9)
      nvals = sscanf(rply_ptr2, "%d %d %d %d %f", c1, c2, c3, c4, timer);
    if (nvals == 5) {
      info_ptr->c5 = info_ptr->c6 = info_ptr->c7 = info_ptr->c8 = 0;
      nvals = 9;
    }
    if (((*rply_ptr0 == '\0') || (*rply_ptr0 == '\r')) &&
        (sscanf(rply_ptr1, "%d", rs) == 1) && (nvals == 9)) {
      if (EL737_errcode != 0)
        return False;
      EL737_call_depth--;
      return True;
    }
    if (*rply_ptr0 != '?') {
      if (*rply_ptr1 == '?')
        rply_ptr0 = rply_ptr1;
      if (*rply_ptr0 == '?')
        rply_ptr0 = rply_ptr2;
    }
    EL737_SetErrcode(info_ptr, rply_ptr0, "S\", \"RS\" or \"RA");
    *c1 = *c2 = *c3 = *c4 = *rs = 0;
    *timer = 0.0;
    return False;
  }
}

/*
**---------------------------------------------------------------------------
**		EL737_StopFast:  stop a measurement with an EL737 counter.
*/
int EL737_StopFast(
/*	==============
*/ void **handle)
{

  int my_status, nvals;
  struct EL737info *info_ptr;
  char *rply_ptr0;
                    /*----------------------------------------------
		    */
  info_ptr = (struct EL737info *) *handle;

  if (!EL737_AddCallStack(info_ptr, "EL737_StopFast"))
    return False;
                    /*----------------------------------------------
		    ** Send S cmnd to EL737
		    */
  my_status = AsynSrv_SendCmnds(&info_ptr->asyn_info,
                                &info_ptr->to_host, &info_ptr->from_host,
                                "S\r", NULL);
  if (!my_status) {
    EL737_errcode = EL737__BAD_ASYNSRV;
    return False;
  } else {
    rply_ptr0 =
        AsynSrv_GetReply(&info_ptr->asyn_info, &info_ptr->from_host, NULL);

    if (rply_ptr0 == NULL)
      rply_ptr0 = "?";

    if ((*rply_ptr0 == '\0' || (*rply_ptr0 == '\r'))) {
      if (EL737_errcode != 0)
        return False;
      EL737_call_depth--;
      return True;
    }
    EL737_SetErrcode(info_ptr, rply_ptr0, "S");
    return False;
  }
}

/*
**---------------------------------------------------------------------------
**		EL737_WaitIdle:  Wait till RS goes to zero.
*/
int EL737_WaitIdle(
/*	==============
*/ void **handle,
                    int *c1, int *c2, int *c3, int *c4, float *timer)
{
#ifdef __VMS
#include	<lib$routines.h>
#define hibernate   lib$wait (0.25)
#else
#include    <unistd.h>
#include    <time.h>
  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 my_rs;
  struct EL737info *info_ptr;
                    /*----------------------------------------------
		    */
  *c1 = *c2 = *c3 = *c4 = 0;
  *timer = 0.0;
  info_ptr = (struct EL737info *) *handle;

  if (!EL737_AddCallStack(info_ptr, "EL737_WaitIdle"))
    return False;
                    /*----------------------------------------------
		    ** Keep reading status till idle.
		    */
  while (EL737_GetStatus(handle, c1, c2, c3, c4, timer, &my_rs)) {
    if (my_rs == 0) {
      if (EL737_errcode != 0)
        return False;
      EL737_call_depth--;
      return True;
    }
    hibernate;
  }
  return False;                 /* Error detected in EL737_GetStatus */
}

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