1016 lines
36 KiB
C
1016 lines
36 KiB
C
#define ident "1A01"
|
||
#ifdef VAXC
|
||
#module VelSel_Utility ident
|
||
#endif
|
||
#ifdef __DECC
|
||
#pragma module VelSel_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]VelSel_Utility.C
|
||
**
|
||
** Author . . . . . . . . . . : D. Maden
|
||
** Date of creation . . . . . . : June 1997
|
||
**
|
||
** To compile this module, use:
|
||
|
||
$ import tasmad
|
||
$ define/group sinq_c_tlb mad_lib:sinq_c.tlb
|
||
$ cc /debug /noopt /obj=[]VelSel_Utility -
|
||
tasmad_disk:[mad.psi.lib.sinq]VelSel_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 VelSel_Utility debug
|
||
$
|
||
$ define/group sinq_olb mad_lib:sinq.olb
|
||
$ @tasmad_disk:[mad.lib.sinq]sinq_olb VelSel_Utility
|
||
**
|
||
** Updates:
|
||
** 1A01 13-Jun-1997 DM. Initial version.
|
||
**============================================================================
|
||
** The entry points included in this module are described below. Prototypes
|
||
** can be defined via:
|
||
**
|
||
** #include <sinq_prototypes.h>
|
||
**
|
||
** VelSel_Close - Close a connection to a Velocity Selector.
|
||
** VelSel_Config - Configure a connection to a Velocity Selector.
|
||
** VelSel_ErrInfo - Return detailed status from last operation.
|
||
** VelSel_GetReply - Get next reply from a reply buffer.
|
||
** VelSel_GetStatus - Get "???" response.
|
||
** VelSel_Open - Open a connection to a Velocity Selector.
|
||
** VelSel_SendCmnds - Send commands to RS232C server.
|
||
**---------------------------------------------------------------------
|
||
** int VelSel_Close (&handle, int 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 VelSel_Open.
|
||
** On return, the pointer is set to NULL.
|
||
** Return status:
|
||
** True always (error returns from close and free are not checked).
|
||
** Routines called:
|
||
** AsynSrv_Close
|
||
** Description:
|
||
** The routine calls AsynSrv_Close to close the connection to the RS232C
|
||
** server. If 'force_flag' is non-zero, all other connections to the
|
||
** RS232C server which use the same socket will also be closed.
|
||
**
|
||
** The 'force_flag' can be useful in error recovery situations. The AsynSrv
|
||
** utility operates by only opening a socket for each separate combination
|
||
** of host/port. Hence, if several connections are open to the server,
|
||
** then calling VelSel_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
|
||
** VelSel_Close with 'force_flag' non-zero will force the socket to be
|
||
** closed and will mark all connections using this socket so that they
|
||
** will be informed of the event when they next call any AsynSrv
|
||
** dependent routine.
|
||
**
|
||
** Note: The force-close action is effected by the AsynSrv package. A
|
||
** force-close will thus also close any connections to other
|
||
** RS-232-C devices (e.g. EL737 neutron cntr) on the same server.
|
||
**-------------------------------------------------------------------------
|
||
** void VelSel_Config (&handle, msec_tmo, eot_str)
|
||
** -------------
|
||
** Input Args:
|
||
** void **handle - The pointer to the structure returned by VelSel_Open.
|
||
** int msec_tmo - The time-out for responses. Dflt = 10000.
|
||
** char *eot_str - A string of up to 3 characters specifying terminating
|
||
** characters for input.
|
||
** Output Args:
|
||
** none
|
||
** Modified Args:
|
||
** none
|
||
** Return status:
|
||
** none
|
||
** Routines called:
|
||
** none
|
||
** Description:
|
||
** The routine sets values in the VelSel_info data structure.
|
||
**-------------------------------------------------------------------------
|
||
** void VelSel_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.
|
||
**-------------------------------------------------------------------------
|
||
** void *VelSel_GetReply (&handle, last_rply)
|
||
** ---------------
|
||
** Input Args:
|
||
** void **handle - The pntr to the structure returned by VelSel_Open.
|
||
** void *last_rply - Address of last reply processed or NULL.
|
||
** Output Args:
|
||
** none
|
||
** Modified Args:
|
||
** none
|
||
** Return status:
|
||
** Address of next reply structure in the buffer or NULL if no more.
|
||
** Routines called:
|
||
** none
|
||
** Description:
|
||
** VelSel_GetReply is a utility routine mainly intended for internal use
|
||
** by the VelSel_Utility package. It unpacks the replies in the response
|
||
** packet from the RS232C server.
|
||
**
|
||
** Having received a response from the server to a sequence of commands,
|
||
** VelSel_GetReply is called with last_rply = NULL. The return value is
|
||
** a pointer to the first reply sub-structure in the response. On calling
|
||
** VelSel_GetReply again with last_rply set to this address, one receives
|
||
** the address of the second reply sub-structure and so on, until NULL
|
||
** is returned when all responses have been exhausted. The structure of
|
||
** a reply sub-structure is RS__RplyStruct.
|
||
**-------------------------------------------------------------------------
|
||
** int VelSel_GetStatus (&handle, &status_str, status_str_len)
|
||
** ----------------
|
||
** Input Args:
|
||
** void **handle - The pointer to the structure returned by VelSel_Open.
|
||
** int status_str_len - The length of status_str.
|
||
** Output Args:
|
||
** char *status_str - Pointer to a buffer to save the status.
|
||
** Modified Args:
|
||
** none
|
||
** Return status:
|
||
** True if no problems detected, otherwise False and VelSel_ErrInfo
|
||
** can be called to identify the problem. Values of Errcode set by
|
||
** VelSel_GetStatus are (other values may be set by the called routines):
|
||
** VELSEL__BAD_TMO, _LOC, _CMD, _OFL, _ADR --> see VelSel_Open.
|
||
** VELSEL__BAD_ILLG = -5 --> one of the responses could probably not be
|
||
** decoded. This could happen if there is noise
|
||
** on the RS232C connection to the Velocity
|
||
** Selector.
|
||
** If an error is detected, ist_posit is set to 0.0 and all other
|
||
** arguments to -1.
|
||
** Routines called:
|
||
** VelSel_SendCmnds
|
||
** Description:
|
||
** The routine issues a "???" command to the Velocity Selector and
|
||
** analyses the result.
|
||
**-------------------------------------------------------------------------
|
||
** int VelSel_Open (&handle, host, port, chan, id)
|
||
** -----------
|
||
** 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.
|
||
** char *id - The expected ID of the device, normally "????".
|
||
** If id is NULL, the device ID is not checked.
|
||
** Output Args:
|
||
** void *handle - A pointer to a structure of type VelSel_info needed
|
||
** for subsequent calls to VelSel_... routines. Buffer
|
||
** space for the structure is allocated dynamically.
|
||
** It gets released via a call to VelSel_Close.
|
||
** Modified Args:
|
||
** none
|
||
** Return status:
|
||
** True if no problems detected, otherwise False. If False, VelSel_ErrInfo
|
||
** can be called to identify the problem. Values of Errcode set by
|
||
** VelSel_Open are (other values may be set by the called routines):
|
||
** VELSEL__BAD_TMO = -1 --> Time-out error ("?TMO" - this gets
|
||
** generated by the RS232C server).
|
||
** VELSEL__BAD_LOC = -2 --> Off-line ("?LOC"). This should not
|
||
** happen on calls to VelSel_Open since it
|
||
** sends an "RMT 1" cmnd.
|
||
** VELSEL__BAD_CMD = -3 --> Command error ("?CMD"). This could be
|
||
** caused by noise in the RS-232-C
|
||
** transmission.
|
||
** VELSEL__BAD_OFL = -4 --> Connection 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.
|
||
** VELSEL__BAD_ILLG = -5 --> Some other unrecognised response. This
|
||
** should never occur, of course!
|
||
** VELSEL__BAD_HOST = -6 --> Call to "gethostbyname" failed to get
|
||
** network addr of host.
|
||
** VELSEL__BAD_SOCKET = -7 --> Call to "socket" failed.
|
||
** VELSEL__BAD_BIND = -8 --> Call to "bind" failed.
|
||
** VELSEL__BAD_CONNECT = -9 --> Call to "connect" failed.
|
||
** VELSEL__BAD_DEV = -10 --> Bad cmnd response - is device a VelSel?
|
||
** VELSEL__BAD_MALLOC = -11 --> Call to "malloc" failed
|
||
** Routines called:
|
||
** AsynSrv_open, the memory alloc routine "malloc" and VelSel_SendCmnds.
|
||
** Description:
|
||
** The routine calls AsynSrv_open to open a TCP/IP connection to a server
|
||
** offering the "RS-232-C" service for a Velocity Selector. "RMT 1"
|
||
** and "ECHO 0" commands are sent to ensure the device is on-line.
|
||
**-------------------------------------------------------------------------
|
||
** int VelSel_SendCmnds (&handle, ...)
|
||
** ----------------
|
||
** Input Args:
|
||
** void **handle - The pntr to the structure returned by VelSel_Open.
|
||
** char * ... - A list of commands, terminated by NULL, for
|
||
** sending to the Velocity Selector. The commands must
|
||
** have any necessary \r characters included.
|
||
** Output Args:
|
||
** none
|
||
** Modified Args:
|
||
** none
|
||
** Return status:
|
||
** True if no problems detected, otherwise False and errcode (see
|
||
** VelSel_ErrInfo) is set to indicate the nature of the problem.
|
||
** VelSel_errcode may be set as follows:
|
||
** VELSEL__BAD_SENDLEN = -12 --> Too much to send; either too many
|
||
** commands or too long. The buffer
|
||
** is 232 bytes long and each command
|
||
** has a 2-byte header.
|
||
** Errors -13 to -16 are related to network errors whilst sending the
|
||
** message buffer to the server:
|
||
** VELSEL__BAD_SEND = -13 --> Network problem - server has
|
||
** probably abended.
|
||
** VELSEL__BAD_SEND_PIPE = -14 --> Network pipe broken - probably same
|
||
** cause as VELSEL__BAD_SEND.
|
||
** VELSEL__BAD_SEND_NET = -15 --> Some other network problem. "errno"
|
||
** may be helpful.
|
||
** VELSEL__BAD_SEND_UNKN = -16 --> Some other network problem happened
|
||
** resulting in the message not
|
||
** getting sent completely. "errno" is
|
||
** probably not helpful in this case.
|
||
** Errors VELSEL__BAD_RECV, VELSEL__BAD_RECV_PIPE, VELSEL__BAD_RECV_NET
|
||
** and VELSEL__BAD_RECV_UNKN (-17 to -20) are related to network
|
||
** errors whilst receiving the 4-byte response header. They are
|
||
** analogous to VELSEL__BAD_SEND to VELSEL__BAD_SEND_UNKN.
|
||
** VELSEL__BAD_NOT_BCD = -21 --> The 4-byte response header is not an
|
||
** ASCII coded decimal integer.
|
||
** VELSEL__BAD_RECVLEN = -22 --> The body of the response would be too
|
||
** big to fit in the input buffer. The
|
||
** buffer is 244 bytes long and each
|
||
** response has a 3-byte header and a
|
||
** trailing zero-byte. The response
|
||
** is flushed.
|
||
** VELSEL__BAD_FLUSH = -23 --> Some network error was detected
|
||
** during flushing. This is an "or"
|
||
** of errors VELSEL__BAD_RECV to
|
||
** VELSEL__BAD_RECV_UNKN.
|
||
** VELSEL__FORCED_CLOSED = -32 --> The connection to the Velocity
|
||
** Selector has been forcefully
|
||
** closed. See below.
|
||
** VELSEL__BAD_REPLY = -34 --> The n_rply field of the response was
|
||
** either non-numeric or <0, indicating
|
||
** that the Terminal Server detected an
|
||
** error. The reply is added to the
|
||
** routine call stack for debug purposes.
|
||
**
|
||
** Errors VELSEL__BAD_RECV1, VELSEL__BAD_RECV1_PIPE and
|
||
** VELSEL__BAD_RECV1_NET (-24 to -26) are related to network
|
||
** errors whilst receiving the body of the response. They are
|
||
** equivalent to errors VELSEL__BAD_RECV, to VELSEL__BAD_RECV_NET.
|
||
**
|
||
** VELSEL__FORCED_CLOSED occurs if AsynSrv_Close has been called (e.g.
|
||
** via a call to VelSel_Close) for another device on the same
|
||
** server and the 'force_flag' was set (see VelSel_Close). The
|
||
** caller should call VelSel_Close and then VelSel_Open to
|
||
** re-establish a connection to the Velocity Selector.
|
||
** Routines called:
|
||
** Socket library routines send and recv.
|
||
** Description:
|
||
** The list of commands is assembled into a message buffer with appropriate
|
||
** header information and sent off to the server. The response is then
|
||
** awaited and read in when it arrives.
|
||
**
|
||
** For any of the following errors:
|
||
** VELSEL__BAD_SEND (Note: VELSEL__BAD_SENDLEN and
|
||
** VELSEL__BAD_SEND_PIPE VELSEL__BAD_RECVLEN do not cause a close
|
||
** VELSEL__BAD_SEND_NET
|
||
** VELSEL__BAD_SEND_UNKN
|
||
** VELSEL__BAD_RECV
|
||
** VELSEL__BAD_RECV_PIPE
|
||
** VELSEL__BAD_RECV_NET
|
||
** VELSEL__BAD_RECV_UNKN
|
||
** VELSEL__BAD_NOT_BCD
|
||
** VELSEL__BAD_FLUSH
|
||
** VELSEL__BAD_RECV1
|
||
** VELSEL__BAD_RECV1_PIPE
|
||
** VELSEL__BAD_RECV1_NET
|
||
** the network link to the server is force-closed via a call to VelSel_Close.
|
||
** Once the error has been corrected, the link can be re-opened via a
|
||
** call to VelSel_Open. As a result of the force-close, other active handles
|
||
** will need to be released via a call to VelSel_Close before VelSel_Open is
|
||
** called.
|
||
**
|
||
** Note: neither of the errors VELSEL__BAD_SENDLEN, VELSEL__BAD_RECVLEN
|
||
** nor VELSEL__BAD_REPLY cause the link to be closed.
|
||
**============================================================================*/
|
||
/*
|
||
**---------------------------------------------------------------------------
|
||
** Global Definitions
|
||
*/
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
#include <stdarg.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>
|
||
#endif
|
||
/*-----------------------------------------------------------------*/
|
||
#include <rs232c_def.h>
|
||
#include <asynsrv_def.h>
|
||
#include <VelSel_def.h>
|
||
#include <sinq_prototypes.h>
|
||
|
||
#define True 1
|
||
#define False 0
|
||
/*--------------------------------------------------------------------------
|
||
** Global Variables
|
||
*/
|
||
static int VelSel_call_depth = 0;
|
||
static char VelSel_routine[5][64];
|
||
static int VelSel_errcode = 0;
|
||
static int VelSel_errno, VelSel_vaxc_errno;
|
||
/*
|
||
**---------------------------------------------------------------------------
|
||
** VelSel_Close: Close a connection to a Velocity Selector.
|
||
*/
|
||
int VelSel_Close(
|
||
/* ===========
|
||
*/ void **handle,
|
||
int force_flag)
|
||
{
|
||
|
||
struct VelSel_info *info_ptr;
|
||
char buff[4];
|
||
|
||
info_ptr = (struct VelSel_info *) *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;
|
||
}
|
||
|
||
/*
|
||
**---------------------------------------------------------------------------
|
||
** VelSel_Config: Configure a connection to a Velocity Selector.
|
||
*/
|
||
void VelSel_Config(
|
||
/* ============
|
||
*/ void **handle,
|
||
int msec_tmo, char *eot_str)
|
||
{
|
||
|
||
int i;
|
||
struct VelSel_info *info_ptr;
|
||
|
||
info_ptr = (struct VelSel_info *) *handle;
|
||
if (info_ptr == NULL)
|
||
return;
|
||
/*-------------------------
|
||
** Set up the time-out
|
||
*/
|
||
if (msec_tmo < 0) {
|
||
info_ptr->tmo = -1;
|
||
} else {
|
||
info_ptr->tmo = (msec_tmo + 99) / 100; /* Convert to deci-secs */
|
||
if (info_ptr->tmo > 9999)
|
||
info_ptr->tmo = 9999;
|
||
}
|
||
/*---------------------------------
|
||
** Set up the end-of-text string
|
||
*/
|
||
if (eot_str != NULL) {
|
||
for (i = 0; i < sizeof(info_ptr->eot); i++)
|
||
info_ptr->eot[i] = '\0';
|
||
|
||
for (i = 0; i < sizeof(info_ptr->eot); i++) {
|
||
if (eot_str[i] == '\0')
|
||
break;
|
||
info_ptr->eot[i + 1] = eot_str[i];
|
||
}
|
||
info_ptr->eot[0] = '0' + i;
|
||
}
|
||
return;
|
||
}
|
||
|
||
/*
|
||
** -------------------------------------------------------------------------
|
||
** VelSel_ErrInfo: Return detailed status from last operation.
|
||
*/
|
||
void VelSel_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 (VelSel_call_depth <= 0) {
|
||
strcpy(VelSel_routine[0], "VelSel_no_error_detected");
|
||
*errcode = 0;
|
||
*my_errno = 0;
|
||
*vaxc_errno = 0;
|
||
} else {
|
||
if (VelSel_call_depth > 1) { /* Concatenate the names */
|
||
for (i = 1; i < VelSel_call_depth; i++) {
|
||
strcat(VelSel_routine[0], "/");
|
||
StrJoin(VelSel_routine[0], sizeof(VelSel_routine),
|
||
VelSel_routine[0], VelSel_routine[i]);
|
||
}
|
||
}
|
||
*errcode = VelSel_errcode;
|
||
*my_errno = VelSel_errno;
|
||
*vaxc_errno = VelSel_vaxc_errno;
|
||
switch (VelSel_errcode) {
|
||
case VELSEL__BAD_TMO:
|
||
strcpy(buff, "/VELSEL__BAD_TMO");
|
||
break;
|
||
case VELSEL__BAD_CMD:
|
||
strcpy(buff, "/VELSEL__BAD_CMD");
|
||
break;
|
||
case VELSEL__BAD_OFL:
|
||
strcpy(buff, "/VELSEL__BAD_OFL");
|
||
break;
|
||
case VELSEL__BAD_ILLG:
|
||
strcpy(buff, "/VELSEL__BAD_ILLG");
|
||
break;
|
||
case VELSEL__BAD_HOST:
|
||
strcpy(buff, "/VELSEL__BAD_HOST");
|
||
break;
|
||
case VELSEL__BAD_SOCKET:
|
||
strcpy(buff, "/VELSEL__BAD_SOCKET");
|
||
break;
|
||
case VELSEL__BAD_BIND:
|
||
strcpy(buff, "/VELSEL__BAD_BIND");
|
||
break;
|
||
case VELSEL__BAD_CONNECT:
|
||
strcpy(buff, "/VELSEL__BAD_CONNECT");
|
||
break;
|
||
case VELSEL__BAD_DEV:
|
||
strcpy(buff, "/VELSEL__BAD_DEV");
|
||
break;
|
||
case VELSEL__BAD_MALLOC:
|
||
strcpy(buff, "/VELSEL__BAD_MALLOC");
|
||
break;
|
||
case VELSEL__BAD_SENDLEN:
|
||
strcpy(buff, "/VELSEL__BAD_SENDLEN");
|
||
break;
|
||
case VELSEL__BAD_SEND:
|
||
strcpy(buff, "/VELSEL__BAD_SEND");
|
||
break;
|
||
case VELSEL__BAD_SEND_PIPE:
|
||
strcpy(buff, "/VELSEL__BAD_SEND_PIPE");
|
||
break;
|
||
case VELSEL__BAD_SEND_NET:
|
||
strcpy(buff, "/VELSEL__BAD_SEND_NET");
|
||
break;
|
||
case VELSEL__BAD_SEND_UNKN:
|
||
strcpy(buff, "/VELSEL__BAD_SEND_UNKN");
|
||
break;
|
||
case VELSEL__BAD_RECV:
|
||
strcpy(buff, "/VELSEL__BAD_RECV");
|
||
break;
|
||
case VELSEL__BAD_RECV_PIPE:
|
||
strcpy(buff, "/VELSEL__BAD_RECV_PIPE");
|
||
break;
|
||
case VELSEL__BAD_RECV_NET:
|
||
strcpy(buff, "/VELSEL__BAD_RECV_NET");
|
||
break;
|
||
case VELSEL__BAD_RECV_UNKN:
|
||
strcpy(buff, "/VELSEL__BAD_RECV_UNKN");
|
||
break;
|
||
case VELSEL__BAD_NOT_BCD:
|
||
strcpy(buff, "/VELSEL__BAD_NOT_BCD");
|
||
break;
|
||
case VELSEL__BAD_RECVLEN:
|
||
strcpy(buff, "/VELSEL__BAD_RECVLEN");
|
||
break;
|
||
case VELSEL__BAD_FLUSH:
|
||
strcpy(buff, "/VELSEL__BAD_FLUSH");
|
||
break;
|
||
case VELSEL__BAD_RECV1:
|
||
strcpy(buff, "/VELSEL__BAD_RECV1");
|
||
break;
|
||
case VELSEL__BAD_RECV1_PIPE:
|
||
strcpy(buff, "/VELSEL__BAD_RECV1_PIPE");
|
||
break;
|
||
case VELSEL__BAD_RECV1_NET:
|
||
strcpy(buff, "/VELSEL__BAD_RECV1_NET");
|
||
break;
|
||
case VELSEL__BAD_PAR:
|
||
strcpy(buff, "/VELSEL__BAD_PAR");
|
||
break;
|
||
case VELSEL__BAD_BSY:
|
||
strcpy(buff, "/VELSEL__BAD_BSY");
|
||
break;
|
||
case VELSEL__BAD_OPEN:
|
||
strcpy(buff, "/VELSEL__BAD_OPEN");
|
||
break;
|
||
case VELSEL__FORCED_CLOSED:
|
||
strcpy(buff, "/VELSEL__FORCED_CLOSED");
|
||
break;
|
||
case VELSEL__BAD_STP:
|
||
strcpy(buff, "/VELSEL__BAD_STP");
|
||
break;
|
||
case VELSEL__BAD_REPLY:
|
||
strcpy(buff, "/VELSEL__BAD_REPLY");
|
||
break;
|
||
default:
|
||
sprintf(buff, "/VELSEL__unknown_err_code: %d", VelSel_errcode);
|
||
}
|
||
StrJoin(VelSel_routine[0], sizeof(VelSel_routine), VelSel_routine[0],
|
||
buff);
|
||
}
|
||
AsynSrv_ErrInfo(&asyn_errtxt, &asyn_errcode, &asyn_errno,
|
||
&asyn_vaxerrno);
|
||
if (asyn_errcode != 0) {
|
||
strcat(VelSel_routine[0], "/");
|
||
StrJoin(VelSel_routine[0], sizeof(VelSel_routine),
|
||
VelSel_routine[0], asyn_errtxt);
|
||
}
|
||
*entry_txt = VelSel_routine[0];
|
||
VelSel_call_depth = 0;
|
||
VelSel_errcode = 0;
|
||
}
|
||
|
||
/*
|
||
**---------------------------------------------------------------------------
|
||
** VelSel_GetReply - Get next reply from a reply buffer.
|
||
*/
|
||
void *VelSel_GetReply(
|
||
/* ==============
|
||
*/ void **handle, /* Pointer to structure containing
|
||
** message to pull apart */
|
||
void *last_rply)
|
||
{ /* Starting point */
|
||
|
||
int rply_len;
|
||
struct RS__RplyStruct *ptr;
|
||
struct VelSel_info *my_info_ptr;
|
||
struct RS__RplyStruct *my_last_rply;
|
||
|
||
ptr = NULL;
|
||
my_info_ptr = (struct VelSel_info *) *handle;
|
||
my_last_rply = (struct RS__RplyStruct *) last_rply;
|
||
|
||
if (my_last_rply == NULL) { /* Start with first reply? */
|
||
/* Yes */
|
||
if (sscanf(my_info_ptr->from_host.n_rply, "%4d",
|
||
&my_info_ptr->max_replies) != 1)
|
||
my_info_ptr->max_replies = 0;
|
||
if (my_info_ptr->max_replies > 0)
|
||
ptr = (struct RS__RplyStruct *) my_info_ptr->from_host.u.rplys;
|
||
my_info_ptr->n_replies = 1;
|
||
} else {
|
||
my_info_ptr->n_replies++;
|
||
if (my_info_ptr->n_replies <= my_info_ptr->max_replies) {
|
||
if (sscanf(my_last_rply->rply_len, "%2d", &rply_len) == 1) {
|
||
ptr =
|
||
(struct RS__RplyStruct *) ((char *) my_last_rply + rply_len +
|
||
2);
|
||
}
|
||
}
|
||
}
|
||
return (void *) ptr;
|
||
}
|
||
|
||
/*
|
||
**---------------------------------------------------------------------------
|
||
** VelSel_GetStatus: Get "???" response from Vel Selector
|
||
*/
|
||
int VelSel_GetStatus(
|
||
/* ===============
|
||
*/ void **handle,
|
||
char *status_str, int status_str_len)
|
||
{
|
||
|
||
int status;
|
||
struct VelSel_info *info_ptr;
|
||
struct RS__RplyStruct *rply_ptr;
|
||
struct RS__RplyStruct *rply_ptr0;
|
||
/*----------------------------------------------
|
||
*/
|
||
status_str[0] = '\0';
|
||
/*----------------------------------------------
|
||
** Pre-set the routine name (in case of error)
|
||
*/
|
||
if (VelSel_errcode == 0 && VelSel_call_depth < 5) {
|
||
strcpy(VelSel_routine[VelSel_call_depth], "VelSel_GetStatus");
|
||
VelSel_call_depth++;
|
||
}
|
||
/*----------------------------------------------
|
||
** Do nothing if no connection - the connection gets
|
||
** closed if an error is detected.
|
||
*/
|
||
info_ptr = (struct VelSel_info *) *handle;
|
||
if (info_ptr == NULL) {
|
||
return False;
|
||
}
|
||
if (info_ptr->asyn_info.skt <= 0) {
|
||
memset(info_ptr->from_host.msg_size,
|
||
'0', sizeof(info_ptr->from_host.msg_size));
|
||
if ((VelSel_errcode == 0) && (info_ptr->asyn_info.skt < 0)) {
|
||
VelSel_errcode = VELSEL__FORCED_CLOSED;
|
||
}
|
||
return False;
|
||
}
|
||
/*----------------------------------------------
|
||
** Send "???" command to Velocity Selector
|
||
*/
|
||
status = VelSel_SendCmnds(handle, "???", NULL);
|
||
if (!status) {
|
||
/* Error in VelSel_SendCmnds */
|
||
return False;
|
||
} else {
|
||
rply_ptr0 = VelSel_GetReply(handle, NULL);
|
||
if (rply_ptr0 == NULL)
|
||
rply_ptr0 = (struct RS__RplyStruct *) "06\rNULL";
|
||
StrJoin(status_str, status_str_len, rply_ptr0->rply, "");
|
||
}
|
||
VelSel_call_depth--;
|
||
return True;
|
||
}
|
||
|
||
/*
|
||
**---------------------------------------------------------------------------
|
||
** VelSel_Open: Open a connection to a Velocity Selector.
|
||
*/
|
||
int VelSel_Open(
|
||
/* ==========
|
||
*/ void **handle,
|
||
char *host, int port, int chan)
|
||
{
|
||
|
||
int status;
|
||
struct VelSel_info *my_handle;
|
||
struct RS__RplyStruct *rply_ptr;
|
||
struct RS__RplyStruct *rply_ptr0;
|
||
struct RS__RplyStruct *rply_ptr1;
|
||
struct RS__RplyStruct *rply_ptr2;
|
||
struct RS__RplyStruct *rply_ptr3;
|
||
/*--------------------------------------------------------
|
||
** Initialise the error info stack and pre-set the
|
||
** routine name (in case of error).
|
||
*/
|
||
VelSel_errcode = VelSel_errno = VelSel_vaxc_errno = 0;
|
||
strcpy(VelSel_routine[0], "VelSel_Open");
|
||
VelSel_call_depth = 1;
|
||
/*--------------------------------------------------------
|
||
** Assume trouble
|
||
*/
|
||
*handle = NULL;
|
||
/*--------------------------------------------------------
|
||
** Reserve space for the data we need to store.
|
||
*/
|
||
my_handle = (struct VelSel_info *) malloc(sizeof(*my_handle));
|
||
if (my_handle == NULL) {
|
||
VelSel_errcode = VELSEL__BAD_MALLOC; /* malloc 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) {
|
||
VelSel_errcode = VELSEL__BAD_SOCKET;
|
||
GetErrno(&VelSel_errno, &VelSel_vaxc_errno); /* Save errno info */
|
||
fprintf(stderr, "\nVelSel_Open/AsynSrv_Open: "
|
||
"Failed to make connection.\n");
|
||
free(my_handle);
|
||
return False;
|
||
}
|
||
|
||
my_handle->tmo = 25; /* Set a short time-out initially since
|
||
** there should be no reason for the REM
|
||
** command to take very long
|
||
*/
|
||
strcpy(my_handle->eot, "1\n\0\0");
|
||
my_handle->msg_id = 0;
|
||
/*
|
||
** Now ensure the VelSel is on-line. The first "REM" command can
|
||
** fail due to pending characters in the VelSel input buffer causing
|
||
** the "REM" to be corrupted. The response of the VelSel to this
|
||
** command is ignored for this reason (but the VelSel_SendCmnds
|
||
** status must be OK otherwise it indicates a network problem).
|
||
*/
|
||
status = VelSel_SendCmnds((void *) &my_handle, "REM", NULL);
|
||
if (status) {
|
||
status = VelSel_SendCmnds((void *) &my_handle, "REM", NULL);
|
||
}
|
||
if (!status) {
|
||
/* Some error occurred in VelSel_SendCmnds - Errcode will
|
||
** have been set up there.
|
||
*/
|
||
AsynSrv_Close(&my_handle->asyn_info, False);
|
||
free(my_handle);
|
||
return False;
|
||
}
|
||
/*
|
||
** Check the responses carefully.
|
||
*/
|
||
rply_ptr0 = VelSel_GetReply((void *) &my_handle, NULL);
|
||
|
||
if (rply_ptr0 == NULL)
|
||
rply_ptr0 = (struct RS__RplyStruct *) "06\rNULL";
|
||
if (rply_ptr0->rply[0] == '?') {
|
||
VelSel_errcode = VELSEL__BAD_DEV; /* Error response - not a VelSel? */
|
||
AsynSrv_Close(&my_handle->asyn_info, False);
|
||
free(my_handle);
|
||
return False;
|
||
}
|
||
/*
|
||
** The connection is complete. Pass the data structure
|
||
** back to the caller as a handle.
|
||
*/
|
||
my_handle->tmo = 100; /* Default time-out is 10 secs */
|
||
*handle = my_handle;
|
||
VelSel_call_depth--;
|
||
return True;
|
||
}
|
||
|
||
/*
|
||
**---------------------------------------------------------------------------
|
||
** VelSel_SendCmnds - Send commands to RS232C server.
|
||
*/
|
||
int VelSel_SendCmnds(
|
||
/* ================
|
||
*/ void **handle,
|
||
...)
|
||
{ /* Now we have list of commands -
|
||
** char *txt = pntr to cmnd strng
|
||
** Terminate list with *txt = NULL.
|
||
*/
|
||
struct VelSel_info *info_ptr;
|
||
int i, status, c_len, size, max_size, ncmnds;
|
||
int bytes_to_come, bytes_left;
|
||
char *nxt_byte_ptr;
|
||
char err_text[80];
|
||
char text[20];
|
||
va_list ap; /* Pointer to variable args */
|
||
char *txt_ptr;
|
||
char *cmnd_lst_ptr;
|
||
/*----------------------------------------------
|
||
** Pre-set the routine name (in case of error)
|
||
*/
|
||
if (VelSel_errcode == 0 && VelSel_call_depth < 5) {
|
||
strcpy(VelSel_routine[VelSel_call_depth], "VelSel_SendCmnds");
|
||
VelSel_call_depth++;
|
||
}
|
||
/*----------------------------------------------
|
||
** Do nothing if no connection - the connection gets
|
||
** closed if an error is detected. The connection may
|
||
** also be marked to have been forcefully closed.
|
||
*/
|
||
info_ptr = (struct VelSel_info *) *handle;
|
||
if (info_ptr == NULL) {
|
||
return False;
|
||
}
|
||
if (info_ptr->asyn_info.skt <= 0) {
|
||
memset(info_ptr->from_host.msg_size,
|
||
'0', sizeof(info_ptr->from_host.msg_size));
|
||
if ((VelSel_errcode == 0) && (info_ptr->asyn_info.skt < 0)) {
|
||
VelSel_errcode = VELSEL__FORCED_CLOSED;
|
||
}
|
||
return False;
|
||
}
|
||
/*----------------------------------------------
|
||
** Build message for Vel Selector from the list of commands.
|
||
*/
|
||
info_ptr->n_replies = info_ptr->max_replies = 0;
|
||
|
||
info_ptr->msg_id++; /* Set up an incrementing message id */
|
||
if (info_ptr->msg_id > 9999)
|
||
info_ptr->msg_id = 1;
|
||
sprintf(info_ptr->to_host.msg_id, "%04.4d", info_ptr->msg_id);
|
||
|
||
memcpy(info_ptr->to_host.c_pcol_lvl, RS__PROTOCOL_ID,
|
||
sizeof(info_ptr->to_host.c_pcol_lvl));
|
||
sprintf(info_ptr->to_host.serial_port, "%04.4d",
|
||
info_ptr->asyn_info.chan);
|
||
sprintf(info_ptr->to_host.tmo, "%04.4d", info_ptr->tmo);
|
||
|
||
memcpy(info_ptr->to_host.terms, info_ptr->eot,
|
||
sizeof(info_ptr->to_host.terms));
|
||
memcpy(info_ptr->to_host.n_cmnds, "0000",
|
||
sizeof(info_ptr->to_host.n_cmnds));
|
||
|
||
va_start(ap, handle); /* Set up var arg machinery */
|
||
|
||
txt_ptr = va_arg(ap, char *); /* Get pntr to next cmnd string */
|
||
ncmnds = 0;
|
||
cmnd_lst_ptr = &info_ptr->to_host.cmnds[0];
|
||
bytes_left = sizeof(info_ptr->to_host) -
|
||
OffsetOf(struct RS__MsgStruct, cmnds[0]);
|
||
|
||
while (txt_ptr != NULL) {
|
||
size = 2 + strlen(txt_ptr);
|
||
if (size > bytes_left) {
|
||
VelSel_errcode = VELSEL__BAD_SENDLEN; /* Too much to send */
|
||
fprintf(stderr, "\nVelSel_SendCmnds/send: too much to send"
|
||
" - request ignored.\n");
|
||
memset(info_ptr->from_host.msg_size,
|
||
'0', sizeof(info_ptr->from_host.msg_size));
|
||
return False;
|
||
} else {
|
||
strcpy(cmnd_lst_ptr + 2, txt_ptr);
|
||
c_len = strlen(txt_ptr);
|
||
sprintf(text, "%02.2d", c_len);
|
||
memcpy(cmnd_lst_ptr, text, 2);
|
||
cmnd_lst_ptr = cmnd_lst_ptr + c_len + 2;
|
||
ncmnds++;
|
||
bytes_left = bytes_left - size;
|
||
txt_ptr = va_arg(ap, char *);
|
||
}
|
||
}
|
||
sprintf(text, "%04.4d", ncmnds);
|
||
memcpy(info_ptr->to_host.n_cmnds,
|
||
text, sizeof(info_ptr->to_host.n_cmnds));
|
||
|
||
size = cmnd_lst_ptr - info_ptr->to_host.msg_id;
|
||
size = (size + 3) & (~3); /* Round up to multiple of 4 */
|
||
sprintf(text, "%04.4d", size);
|
||
memcpy(info_ptr->to_host.msg_size, text, 4);
|
||
|
||
status = send(info_ptr->asyn_info.skt,
|
||
(char *) &info_ptr->to_host, size + 4, 0);
|
||
if (status != (size + 4)) {
|
||
GetErrno(&VelSel_errno, &VelSel_vaxc_errno);
|
||
if (status == 0) {
|
||
VelSel_errcode = VELSEL__BAD_SEND; /* Server exited (probably) */
|
||
fprintf(stderr, "\nVelSel_SendCmnds/send: probable network problem");
|
||
} else if (status == -1) {
|
||
if (VelSel_errno == EPIPE) {
|
||
VelSel_errcode = VELSEL__BAD_SEND_PIPE; /* Server exited (probably) */
|
||
fprintf(stderr, "\nVelSel_SendCmnds/send: broken network pipe");
|
||
} else {
|
||
VelSel_errcode = VELSEL__BAD_SEND_NET; /* It's some other net problem */
|
||
perror("VelSel_SendCmnds/send");
|
||
}
|
||
} else {
|
||
VelSel_errcode = VELSEL__BAD_SEND_UNKN; /* TCP/IP problems */
|
||
fprintf(stderr, "\nVelSel_SendCmnds/send: probable TCP/IP problem");
|
||
}
|
||
VelSel_Close(handle, True); /* Force close TCP/IP connection */
|
||
fprintf(stderr, " - link to server force-closed.\n");
|
||
return False;
|
||
}
|
||
|
||
size = sizeof(info_ptr->from_host.msg_size);
|
||
status = recv(info_ptr->asyn_info.skt,
|
||
info_ptr->from_host.msg_size, size, 0);
|
||
if (status != size) {
|
||
GetErrno(&VelSel_errno, &VelSel_vaxc_errno);
|
||
if (status == 0) {
|
||
VelSel_errcode = VELSEL__BAD_RECV; /* Server exited (probably) */
|
||
fprintf(stderr, "\nVelSel_SendCmnds/recv: probable network problem");
|
||
} else if (status == -1) {
|
||
if (VelSel_errno == EPIPE) {
|
||
VelSel_errcode = VELSEL__BAD_RECV_PIPE; /* Server exited (probably) */
|
||
fprintf(stderr, "\nVelSel_SendCmnds/recv: broken network pipe");
|
||
} else {
|
||
VelSel_errcode = VELSEL__BAD_RECV_NET; /* It's some other net problem */
|
||
perror("VelSel_SendCmnds/recv");
|
||
}
|
||
} else {
|
||
VelSel_errcode = VELSEL__BAD_RECV_UNKN; /* TCP/IP problems */
|
||
fprintf(stderr, "\nVelSel_SendCmnds/recv: probable TCP/IP problem");
|
||
}
|
||
VelSel_Close(handle, True); /* Force close TCP/IP connection */
|
||
fprintf(stderr, " - link to server force-closed.\n");
|
||
return False;
|
||
}
|
||
if (sscanf(info_ptr->from_host.msg_size, "%4d", &bytes_to_come) != 1) {
|
||
VelSel_errcode = VELSEL__BAD_NOT_BCD; /* Header not an ASCII BCD integer */
|
||
VelSel_Close(handle, True); /* Force close TCP/IP connection */
|
||
fprintf(stderr, "\nVelSel_SendCmnds/recv: non-BCD byte count"
|
||
" - link to server force-closed.\n");
|
||
return False;
|
||
}
|
||
max_size = sizeof(info_ptr->from_host) -
|
||
sizeof(info_ptr->from_host.msg_size);
|
||
if (bytes_to_come > max_size) {
|
||
VelSel_errcode = VELSEL__BAD_RECVLEN;
|
||
fprintf(stderr,
|
||
"\nVelSel_SendCmnds/recv: pending message length too big"
|
||
" - flushing ...\n");
|
||
nxt_byte_ptr = &info_ptr->from_host.msg_size[size];
|
||
while (bytes_to_come > 0) { /* Flush out the incoming message */
|
||
bytes_left = bytes_to_come;
|
||
if (bytes_left > max_size)
|
||
bytes_left = max_size;
|
||
status = recv(info_ptr->asyn_info.skt, nxt_byte_ptr, bytes_left, 0);
|
||
if (status <= 0) {
|
||
VelSel_errcode = VELSEL__BAD_FLUSH; /* TCP/IP problem whilst flushing */
|
||
GetErrno(&VelSel_errno, &VelSel_vaxc_errno);
|
||
VelSel_Close(handle, True); /* Force close TCP/IP connection */
|
||
fprintf(stderr, "\nVelSel_SendCmnds/recv: network problem during"
|
||
" flush.\nLink to server force-closed.\n");
|
||
return False;
|
||
}
|
||
bytes_to_come = bytes_to_come - status;
|
||
}
|
||
fprintf(stderr, "\n flushed OK.\n");
|
||
memset(info_ptr->from_host.msg_size,
|
||
'0', sizeof(info_ptr->from_host.msg_size));
|
||
return False;
|
||
} else {
|
||
nxt_byte_ptr = &info_ptr->from_host.msg_size[size];
|
||
bytes_left = bytes_to_come;
|
||
while (bytes_left > 0) { /* Read the rest of the response */
|
||
status = recv(info_ptr->asyn_info.skt, nxt_byte_ptr, bytes_left, 0);
|
||
if (status <= 0) {
|
||
GetErrno(&VelSel_errno, &VelSel_vaxc_errno);
|
||
if (status == 0) {
|
||
VelSel_errcode = VELSEL__BAD_RECV1; /* Server exited (probably) */
|
||
fprintf(stderr, "\nVelSel_SendCmnds/recv/1: probable network "
|
||
"problem");
|
||
} else {
|
||
if (VelSel_errno == EPIPE) {
|
||
VelSel_errcode = VELSEL__BAD_RECV1_PIPE; /* Server exited (probably) */
|
||
fprintf(stderr,
|
||
"\nVelSel_SendCmnds/recv/1: broken network pipe");
|
||
} else {
|
||
VelSel_errcode = VELSEL__BAD_RECV1_NET; /* It's some other net fault */
|
||
perror("VelSel_SendCmnds/recv/1");
|
||
}
|
||
}
|
||
VelSel_Close(handle, True); /* Force close TCP/IP connection */
|
||
fprintf(stderr, " - link to server force-closed.\n");
|
||
return False;
|
||
}
|
||
bytes_left = bytes_left - status;
|
||
nxt_byte_ptr = nxt_byte_ptr + status;
|
||
}
|
||
if ((sscanf(info_ptr->from_host.n_rply, "%4d",
|
||
&info_ptr->max_replies) != 1) ||
|
||
(info_ptr->max_replies < 0)) {
|
||
VelSel_errcode = VELSEL__BAD_REPLY; /* Reply is bad */
|
||
if (VelSel_call_depth < 5) { /* Add reply to routine stack */
|
||
bytes_to_come = bytes_to_come + 4;
|
||
if (bytes_to_come >= sizeof(VelSel_routine[0]))
|
||
bytes_to_come = sizeof(VelSel_routine[0]) - 1;
|
||
for (i = 0; i < bytes_to_come; i++) {
|
||
if (info_ptr->from_host.msg_size[i] == '\0')
|
||
info_ptr->from_host.msg_size[i] = '.';
|
||
}
|
||
info_ptr->from_host.msg_size[bytes_to_come] = '\0';
|
||
strcpy(VelSel_routine[VelSel_call_depth],
|
||
info_ptr->from_host.msg_size);
|
||
VelSel_call_depth++;
|
||
}
|
||
return False;
|
||
}
|
||
}
|
||
VelSel_call_depth--;
|
||
return True;
|
||
}
|
||
|
||
/*-------------------------------------------- End of VelSel_Utility.C =======*/
|