#define	    ident	"1A05"
/*---------------------------------------------------------------------------*/
#ifdef __DECC
#pragma	    module	    SINQHM_CTRL	    ident
#endif
/*
** Link_options - Here is the Linker Option File
**!	sinqhm_ctrl
**!	sinq_olb/lib/inc=deltat_messages
**!!
**!!	    To build SINQHM_CTRL on LNSA09
**!!
**!!	$ import tasmad
**!!	$ define/job deltat_c_tlb sinq_c_tlb
**!!	$ sss := ud0:[maden.pss123.wind.sinqhm]
**!!	$ bui 'sss'sinqhm_ctrl debug
** Link_options_end
**
**	Building on Alpha OSF/1:
**
	    cc -std1 -g -o ~/bin/sinqhm_ctrl -I/public/lib/include	\
			-transitive_link -L/public/lib -lsinq -lrt	\
			~/SinqHM/sinqhm_ctrl.c
**
** +--------------------------------------------------------------+
** |                  Paul Scherrer Institute                     |
** |                     Computing Section                        |
** |                                                              |
** | 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  . . . . . . . . : [...HMSR]SINQHM_CTRL.C
**
** Author   . . . . . . . . . . : D. Maden
** Date of creation . . . . . . : Dec 1996
**
** Purpose
** =======
**    SINQHM_CTRL.C is an Internet Client which can be used to send control
**    messages to a front-end processor running the SINQHM histogram
**    memory server process. Control messages may be sent to configure,
**    de-configure, rundown, set the level of debug printing, start data
**    acquisition, stop data acquisition, show the status of SINQHM_SRV, or
**    zero the histogram memory.
**
**  1) Configure:
**     =========
**    The configuration information is obtained from the logical name
**    table. The following logical name definitions are used ...
**
**	SINQHM_FRONTEND "<node> <port> <pkt_size>"
**		    <node>	is the node where SINQHM_SRV is running,
**		    <port>	is SINQHM_SRV's TCP/IP port number (dflt=2400),
**		    <pkt_size>  is max packet size for send/rcve (dflt = 8192).
**	SINQHM_NHISTS	    The number of histograms (dflt = 1).
**	SINQHM_NBINS	    The number of bins per histogram (no dflt).
**	SINQHM_BINWID	    The number of bytes per bin (dflt = 4).
**
**    Once the configuration information has been obtained from the logical
**    names, a connection is made to the SINQHM_SRV root process on the
**    front-end and a configure message is sent. SINQHM_SRV will check the
**    information, start up a child process, FILLER, which will do the work of
**    filling histograms, and then send a reply.
**
**    Note: If SINQHM_SRV has already been successfully configured, i.e. it
**	    already has an active FILLER child process, it must be
**	    de-configured first.
**
**  2) Debug:
**     ======
**    The level of debug printing in the SINQHM_SRV root process can be set. The
**    higher the level, the more print-out on the front-end processor's console
**    occurs. The debug level is inherited by any server children (or FILLER)
**    which subsequently get started.
**
**  3) De-configure:
**     ============
**    "De-configuration" involves terminating any child processes of the
**    SINQHM_SRV root process. Normally, it is expected that the server children
**    will have been terminated via the protocol between the servers and their
**    clients so that a de-configure involves simply the termination of FILLER.
**    This is a so-called "gentle" de-configure. However, in order to facilitate
**    the recovery from error situations, it is possible to specify a "harsh"
**    de-configure in which any active server children will also be terminated.
**    A gentle de-configure will fail if there are active children.
**
**  4) Rundown:
**     =======
**    "Rundown" implies the termination not only of the SINQHM_SRV children but
**    also of the root process itself. Once a rundown has been performed,
**    intervention will be required on the front-end (e.g. reboot or creation
**    of a new SINQHM_SRV root job from the front-end console) before SINQHM_SRV
**    can be used again.
**
**  5) Show-Status:
**     ===========
**    The status of SINQHM_SRV is illicited and printed out.
**
**  6) Start-Data-Acquisition
**     ======================
**    The SinqHM-Filler process in the HM is instructed to start data-acq.
**
**  7) Stop-Data-Acquisition
**     =====================
**    The SinqHM-Filler process in the HM is instructed to stop data-acq.
**
**  8) Zero:
**     ====
**    The complete histogram area is set to zero.
**
** Use:
** ===
**	Define the foreign command:
**
**	    $ sinqhm_ctrl :== $mad_exe:sinqhm_ctrl
**
**	Then issue the command:
**
**	    $ sinqhm_ctrl <cmnd> <modifier>
**
**	where <cmnd> may be "CONFIG", "DEBUG", "DECONFIG", "GO", "HELP",
**	"RUNDOWN", "SHOW", "STOP" or "ZERO". If <cmnd> is omitted or none of
**	the above or if any error occurs obtaining the configuration
**	information for the "CONFIG" command, a "HELP" command will be assumed.
**
**	For the "CONFIG" command, <modifier> may be specified as "SUSPEND".
**	If so, the filler task in the front-end will suspend as soon as it
**	starts so that it can be debugged.
**
**	For the "DEBUG" command, <modifier> is an integer specifying the debug
**	level. <modifier> may also be specified as "ON" or "OFF", corresponding
**	to levels 1 and 0 respectively. If <modifier> is anything else (or
**	absent), "ON" is assumed.
**
**	For the "DECONFIG" command, <modifier> is used to specify the
**	"harshness" of the de-configure. If <modifier> is specified as
**	"HARSH", the de-configure will be "harsh". If <modifier> is anything
**	else (or absent) the de-configure will be gentle.
**
**  Communication between SINQHM_CTRL and the server is via TCP/IP protocol.
**
** Updates:
**  1A01 18-Dec-1996 DM.	Initial version.
**====================================================================
*/
#include    <errno.h>
#include    <netdb.h>
#include    <stdio.h>
#include    <stdlib.h>
#include    <time.h>

#include    <netinet/in.h>
#include    <arpa/inet.h>

#include    <ctype.h>
#include    <math.h>
#include    <sys/socket.h>
#include    <string.h>
#include    <sys/types.h>

/*
**====================	Global Definitions =====================================
*/
#include    "sinq_prototypes.h"
#include    "sinqhm_def.h"

#define SUCCESS	       1
#define ERROR	       0
#define NIL	       '\0'

#define HM_SIZE	   65536	/* Number of Bins in Hist Mem */
/*
**====================	Some functions and structures =====================
**
**					Fixed-Length Descriptor:
*/
    struct  dsc__descriptor_s {
	unsigned short  dsc__w_length;   /* length of data item in bytes */
	unsigned char   dsc__b_dtype;    /* data type code */
	unsigned char   dsc__b_class;    /* descriptor class code */
	char		*dsc__a_pointer; /* address of data storage */
    };
/*
**====================	Global Variables ======================================
*/
  int		    My_errno, My_vaxc_errno;

  struct req_buff_struct	    Req_buff;
  struct rply_buff_struct	    Rply_buff;

  char		Rmt_node[10];
  int		Rmt_port;
  int		Pkt_size;

  int		Hm_mode;	/* The histogramming mode */
  int		Nhists;		/* The number of histograms to fill */
  int		Lo_bin;		/* The first bin */
  int		Nbins;		/* The number of bins to fill */
  int		Binwid;		/* The number of bytes per bin */
  int		Compress;	/* The bin compression factor */

  struct dsc__descriptor_s Name_desc;

  extern int	 C_gbl_status;	    /*  Return status from C_... routines */
/*
**=============================================================================
**  Local routines.
**
**  get_SINQHM_FRONTEND	: Extract info from SINQHM_FRONTEND environment variable
**  show_help		: Display the help text.
**  strMatch		: Match 2 strings.
**----------------------------------------------------------------------------
**							    Prototypes
*/
  int	    getenv_integer (char *name, int *value, int dflt_value);
  void	    get_SINQHM_FRONTEND (char	*node, int node_l, char *node_dflt,
				 int	*port,		   int   port_dflt,
				 int	*pktlen,	   int   pktlen_dflt);
  void	    show_help (char *modifier);
  int	    strMatch (char *str1, char *str2);
/*
**--------------------------------------------------------------------------*/
  int	getCheckStatusResponse (
/*	======================
**			    Wait for the status response from SinqHM and
**			    check it for errors.
**
*/		int			 skt,	    /* The socket for recv */
		struct rply_buff_struct	*reply,	    /* The buffer to use */
		int			 rlen) {    /* Size of buffer */

    int	    status;

    status = recv (skt, (char *) reply, rlen, 0);
    if (status == -1) {
      FailInet ("\n\007SINQHM_CTRL -- recv error");
      return ERROR;
    } else if (status != rlen) {
      printf ("\007"
	    "SINQHM_CTRL --  recv error - unexpected byte count: %d/%d\n",
		    rlen, status);
      return ERROR;
    }
    if (ntohl (reply->bigend) != 0x12345678) {
      printf ("\007"
	    "SINQHM_CTRL -- big-endian/little-endian problem!\n"
	    "    Buffer received in non-network byte order!\n");
      return ERROR;
    }
    status = ntohl (reply->status);
    if (status == KER__SUCCESS) {
      return SUCCESS;
    }else if (status == KER__BAD_CREATE) {
      printf ("\007 Status response is KER__BAD_CREATE\n");
      printf (" Sub-status = %d\n", ntohl (reply->sub_status));
    }else if (status == KER__BAD_STATE) {
      printf ("\007 Status response is KER__BAD_STATE\n");
    }else if (status == KER__BAD_VALUE) {
      printf ("\007 Status response is KER__BAD_VALUE\n");
    }else if (status == KER__BAD_RECV) {
      printf ("\007 Status response is KER__BAD_RECV\n");
    }else if (status == KER__BAD_ALLOC) {
      printf ("\007 Status response is KER__BAD_ALLOC\n");
    }else {
      printf ("\007 Bad and unrecognised status response: 0x%x\n",
		    status);
    }
    if (reply->u.message[0] != NIL) {
      printf (" Message = \"%s\"\n", &reply->u.message[0]);
    }
    return ERROR;
  }
/*
**--------------------------------------------------------------------------*/
  int	getenv_integer (char *name, int *value, int dflt_value) {
/*      ==============
**			    Extract an integer from an
**			    environment variable.
*/
    char *p_env;

    p_env = getenv (name);	/* Get pointer to env var */
    if (p_env == NULL) {
			    /* Env. var. not found, return default */
      *value	= dflt_value;
      return EXIT_FAILURE;
    }else {		    /* Convert it to binary */
      if (sscanf (p_env, "%d", value) != 1) {
	*value = dflt_value;	    /* Value is not integer, return default */
	return EXIT_FAILURE;
      }else {
	return EXIT_SUCCESS;
      }
    }
  }
/*
**--------------------------------------------------------------------------*/
  void get_SINQHM_FRONTEND (
/*     ===================
**			    Extract info from the SINQHM_FRONTEND
**			    environment variable.
**
*/		char	*node, int node_l, char *node_dflt,
		int	*port,		   int	 port_dflt,
		int	*pktlen,	   int	 pktlen_dflt) {

    int	  env_len;
    char *p_env, *token;
    char  my_env[100];

    p_env = getenv ("SINQHM_FRONTEND");    /* Get pointer to env var */
    if (p_env == NULL) {
			    /* Env. var. not found, return defaults */
      StrJoin (node, node_l, node_dflt, "");
      *port	= port_dflt;
      *pktlen	= pktlen_dflt;
    }else {	    /* Make a local copy of it in case the original is in ..
		    ** .. read-protected memory (strtok needs to be able to ..
		    ** .. modify it */
      env_len = sizeof (my_env);
      StrEdit (my_env, p_env, "uncomment compress trim", &env_len);
      token = (env_len == 0) ? NULL : strtok (my_env, " ,"); /* Get node token */
      if ((token == NULL) || (token[0] == ' ')) {
			    /* Node token not found, return defaults */
	StrJoin (node, node_l, node_dflt, "");
        *port	= port_dflt;
        *pktlen	= pktlen_dflt;
      }else {
        StrJoin (node, node_l, token, "");
	token = strtok (NULL, " ,");	/* Get port token */
	if (token == NULL) {
	  *port   = port_dflt;	/* Port token not found, return defaults */
	  *pktlen = pktlen_dflt;
	}else {
	  if (sscanf (token, "%d", port) != 1) {
	    *port   = port_dflt;    /* Port token illegal, return defaults */
	    *pktlen = pktlen_dflt;
	  }else {
	    token = strtok (NULL, " ,");    /* Get packet-size token */
	    if (token == NULL) {
	      *pktlen = pktlen_dflt; /* Packet-size token not found, use dflt */
	    }else {
	      if (sscanf (token, "%d", pktlen) != 1) {
	        *pktlen = pktlen_dflt;	/* Packet-size token illegal, use dflt */
	      }
	    }
	  }
	}
      }
    }
  }
/*
**--------------------------------------------------------------------------*/
  void show_help (char *modifier) {
/*     =========
*/
    int len;

    len = strlen (modifier);
    if (len == 0) goto sh_basic;

    if (strMatch (modifier, "CONFIG")   >= 1) goto sh_config;
    if (strMatch (modifier, "DEBUG")    >= 3) goto sh_debug;
    if (strMatch (modifier, "DECONFIG") >= 3) goto sh_deconfig;
    if (strMatch (modifier, "GO")       >= 1) goto sh_go;
    if (strMatch (modifier, "RUNDOWN")	>= 1) goto sh_rundown;
    if (strMatch (modifier, "SETUP")    >= 2) goto sh_setup;
    if (strMatch (modifier, "SHOW")	>= 1) goto sh_show;
    if (strMatch (modifier, "STOP")	>= 2) goto sh_stop;
    if (strMatch (modifier, "ZERO")	>= 1) goto sh_zero;

sh_basic:
    printf ("\n"
	" The following commands are recognised by SINQHM_CTRL:\n"
	"    CONFIG <mode>         - configure the hist memory.\n"
	"    DEBUG <level>         - sets the debug level.\n"
	"    DECONFIG <harshness>  - de-configure the hist memory.\n"
	"    GO		           - start data acquisition.\n"
	"    HELP <subject>        - generate help text.\n"
	"    RUNDOWN               - run down SinqHM server.\n"
	"    SHOW                  - get status of hist memory.\n"
	"    STOP                  - stop data acquisition.\n"
	"    ZERO                  - zero the HM buffer.\n"
	"\n"
	" In order to use SINQHM_CTRL on a VMS system, a \"foreign command\" must\n"
	" be defined, e.g:\n"
	"                   $ ctrl :== $mad_exe:sinqhm_ctrl\n"
	"\n"
	" To get more help, issue the command:    ctrl help <subject>\n"
	"\n"
	" where <subject> may be any of\n"
	"\n"
	"  CONFIG    DEBUG    DECONFIG    GO      RUNDOWN\n"
	"  Setup     SHOW     STOP        ZERO\n"
	"\n");
    return;

  sh_setup:
    printf ("\nSetup:\n"
	"\n"
	" The histogram memory with which SINQHM_CTRL is to communicate is\n"
	" specified on Unix systems via an environment variable, thus:\n"
	"\n"
	"           setenv SINQHM_FRONTEND \"<host> <port> <pkt-size>\"\n"
	"\n"
	" In addition, the following environment variables are used by CONFIG\n"
	"\n"
	"           setenv SINQHM_HM_MODE  <mode>     (Dflt = SQHM__HM_DIG)\n"
	"           setenv SINQHM_NHISTS   <nhists>   (Dflt = 1)\n"
	"           setenv SINQHM_LOW_BIN  <lo_bin>   (Dflt = 0)\n"
	"           setenv SINQHM_NBINS    <nbins>    (Dflt = none)\n"
	"           setenv SINQHM_BINWID   <binwid>   (Dflt = 4)\n"
	"           setenv SINQHM_COMPRESS <cmprs>    (Dflt = 0)\n"
	"\n"
	" On VMS systems, logical names are used instead, e.g.\n"
	"\n"
	"           define/group sinqhm_frontend \"<host> <port> <pkt-size>\"\n"
	"           define/group sinqhm_hm_mode <mode>\n"
	"\n"
	" Defaults:      <host> = None   <port> = 2400   <pkt-size> = 8192\n"
	"\n");
    return;

  sh_config:
    printf ("\n"
	"    CONFIG <mode>          - configure the hist memory.\n"
	"\n"
	" See \"help setup\" for a list of the environment variables which may be\n"
	" used for specifying the configuration parameters.\n"
	"\n"
	" The filler process in the hist memory will be started.\n"
	"\n"
	" If <mode> is specified as \"SUSPEND\", the filler process will\n"
	" immediately enter a suspended state so that it can be debugged.\n"
	"\n");
    return;

  sh_debug:
    printf ("\n"
	" Debug:\n"
	"\n"
	"    DEBUG <level>   - sets the level of debug messages to the\n"
	"                      hist memory console.\n"
	"\n"
	" <level> may be \"OFF\", \"ON\", 0, 1, 2 or 3.\n"
	"\n"
	" \"OFF\" is equivalent to 0\n"
	" \"ON\"  is equivalent to 1\n"
	" The default is \"ON\".\n"
	"\n");
    return;

  sh_deconfig:
    printf ("\n"
	" Deconfig:\n"
	"\n"
	"    DECONFIG <harshness>  - de-configure the hist memory.\n"
	"\n"
	" If <harshness> is not specified, there must be no active clients\n"
	" for the command to be accepted.\n"
	"\n"
	" If <harshness> is specified as \"HARSH\", any active clients will\n"
	" be killed.\n"
	"\n"
	" The filler task is also terminated.\n"
	"\n");
    return;

  sh_go:
    printf ("\n"
	" Go:\n"
	"\n"
	"    GO      - start data acquisition by SinqHM-filler\n"
	"\n"
	" An SQHM_DAQ/DAQ__GO command will be sent to SinqHM-master to cause\n"
	" SinqHM-filler to start data acquisition.\n"
	"\n");
    return;

  sh_rundown:
    printf ("\n"
	" Rundown:\n"
	"\n"
	"                    USE WITH CAUTION\n"
	"                    ================\n"
	"\n"
	"    RUNDOWN        - runs down SinqHM\n"
	"\n"
	" SinqHM-master, SinqHM-filler and all SinqHM-servers will\n"
	" be terminated.\n"
	"\n"
	" After issuing this command, manual intervention on the\n"
	" histogram memory will be necessary in order to restart\n"
	" SinqHM.\n"
	"\n");
    return;

  sh_show:
    printf ("\n"
	" Show:\n"
	"\n"
	"    SHOW  - get and display the status of the hist memory.\n"
	"\n");
    return;

  sh_stop:
    printf ("\n"
	" Stop:\n"
	"\n"
	"    STOP    - stop data acquisition by SinqHM-filler\n"
	"\n"
	" An SQHM_DAQ/DAQ__STOP command will be sent to SinqHM-master to cause\n"
	" SinqHM-filler to stop data acquisition.\n"
	"\n");
    return;

  sh_zero:
    printf ("\n"
	" Zero:\n"
	"\n"
	"    ZERO    - zero the histogram memory buffer\n"
	"\n"
	" An SQHM_ZERO command will be sent to SinqHM-master. The values of\n"
	" hist_no, first_bin and n_bins will be set to -1 so that the entire\n"
	" histogram memory buffer will be set to zero.\n"
	"\n");
    return;
  }
/*
**--------------------------------------------------------------------------*/
  int	strMatch (char *str1, char *str2) {
/*	========
**		    See if str1 matches str2. Case is ignored.
**		    The length of str1 must be less than or equal to the
**		    length of str2.
**		    Return zero if no match, otherwise the length of str1.
*/
    int	    i = 0;

    while ((tolower (str1[i]) == tolower (str2[i])) && (str1[i] != '\0')) i++;
    if (str1[i] != '\0') i = 0;

    return i;
  }
/*
**==========================================================================
**
**  Main line program
**  ------------------
**==========================================================================*/
  main (int argc, char *argv[]) {
/*==========================================================================*/
    int			i, j, k, status;
    int			is1, is2;
    char		*p_addr, tmp_ch;
    char		*cmnd, *modifier, buff[8];
    unsigned int	daq_state_now;
    unsigned int	daq_state_was;
    unsigned int	filler_mask;
    int			cnct_skt;	/* Connect socket */
    int			rw_skt;		/* Read/write socket */
    struct sockaddr_in	lcl_sockname;
    struct sockaddr_in	rmt_sockname;
    int			rmt_inet_addr;
    struct in_addr	*rmt_inet_addr_pntr;
    struct hostent	*rmt_hostent;
    int			rmt_sockname_len;
/*============================================================================*/
    printf ("\n SinqHM_Ctrl Ident %s.", ident);
/*============================================================================
**		Analyse the arguments to see what has to be done.
*/
    if (argc > 1) {				/* First arg is <cmnd> */
      cmnd = argv[1];
      for (i = 0; i < strlen (cmnd); i++) {	/* Convert to upper case */
        cmnd[i] = toupper (cmnd[i]);
      }
      if (cmnd[0] == '-') cmnd++;	/* Ignore a leading "-" (i.e. get .. */
					/* .. ready for porting to UNIX */
    }else {
      cmnd = "?";
    }
    if ((strMatch (cmnd, "CONFIG")   == 0) &&
	(strMatch (cmnd, "DEBUG")    <  3) &&
	(strMatch (cmnd, "DECONFIG") <  3) &&
	(strMatch (cmnd, "GO")	     == 0) &&
	(strMatch (cmnd, "RUNDOWN")  <  7) &&
	(strMatch (cmnd, "HELP")     == 0) &&
	(strMatch (cmnd, "?")	     == 0) &&
	(strMatch (cmnd, "SHOW")     == 0) &&
	(strMatch (cmnd, "STOP")     <  2) &&
	(strMatch (cmnd, "ZERO")     == 0)) cmnd = "HELP";

    if (argc > 2) {				/* Second arg is <modifier> */
      modifier = argv[2];
      for (i = 0; i < strlen (modifier); i++) {	/* Convert to upper case */
        modifier[i] = toupper (modifier[i]);
      }
    }else {
      modifier = "";
    }
    if (strMatch (cmnd, "HELP") != 0) goto help;
    if (strMatch (cmnd, "?")    != 0) goto help;
/*============================================================================
**	    Start out by finding the TCP/IP location of SINQHM_SRV and making
**	    a connection to it. Any errors during this phase cause the program
**	    to exit with an error status.
*/
    get_SINQHM_FRONTEND (Rmt_node, sizeof (Rmt_node), "",
			 &Rmt_port, PORT_BASE,
			 &Pkt_size, 8192);
    if (Rmt_node[0] == NIL) {
      printf ("\n");
      modifier = "SETUP";
      show_help (modifier);
      printf ("\007\n"
	" The histogram memory is not defined correctly.\n"
	"\n"
	" If this is a UNIX system, check that the environment variable\n"
	" \"SINQHM_FRONTEND\" is defined correctly.\n"
	"\n"
	" If this is a VMS system, check that the logical name "
						"\"SINQHM_FRONTEND\" is\n"
	" defined correctly.\n"
	"\n");
      return EXIT_FAILURE;
    }
/*
**	    Get Internet address of the front-end.
*/
    rmt_hostent = gethostbyname (Rmt_node);
    if (rmt_hostent == NULL) {
      for (i = 0; i < strlen (Rmt_node); i++)
        Rmt_node[i] = toupper (Rmt_node[i]);
      if (strcmp (Rmt_node, "SQFE01") == 0) {
        rmt_inet_addr_pntr = (struct in_addr *) &rmt_inet_addr;
	rmt_inet_addr = inet_addr ("129.129.56.181");
      } else {
	printf ("Server Node is %s.\n", Rmt_node);
        FailInet ("\nGethostbyname error.");
      }
    } else {
      rmt_inet_addr_pntr = (struct in_addr *) rmt_hostent->h_addr_list[0];
    }
    printf (" Server is %s ", Rmt_node);
    printf ("(%s),", inet_ntoa (*rmt_inet_addr_pntr));
    printf (" Port %d.\n", Rmt_port);
/*
**  	   Create a TCP/IP socket for connecting to SINQHM_SRV root and bind it.
*/
    cnct_skt = socket (AF_INET, SOCK_STREAM, 0);
    if (cnct_skt == -1) FailInet ("\nSocket error.");

    lcl_sockname.sin_family = AF_INET;
    lcl_sockname.sin_port   = htons (0);
    lcl_sockname.sin_addr.s_addr = 0;
    status = bind (cnct_skt, (struct sockaddr *) &lcl_sockname,
					sizeof (lcl_sockname));
    if (status == -1) FailInet ("\nBind error.");
/*
**		Connect to SINQHM_SRV root.
*/
    rmt_sockname_len = sizeof (rmt_sockname);
    rmt_sockname.sin_family	 = AF_INET;
    rmt_sockname.sin_port	 = htons (Rmt_port);
    rmt_sockname.sin_addr.s_addr = rmt_inet_addr_pntr->s_addr;
    status = connect (cnct_skt, (struct sockaddr *) &rmt_sockname,
				    sizeof (rmt_sockname));
    if (status == -1) {
      GetErrno (&My_errno, &My_vaxc_errno);
      FailInet ("\nConnect error");
    }
/*============================================================================
**		Switch according to value of <cmnd>
*/
    if (strMatch (cmnd, "CONFIG")   >  0) goto config;
    if (strMatch (cmnd, "DEBUG")    >= 3) goto debug;
    if (strMatch (cmnd, "DECONFIG") >= 3) goto deconfig;
    if (strMatch (cmnd, "GO")	    >  0) goto go;
    if (strMatch (cmnd, "RUNDOWN")  == 7) goto rundown;
    if (strMatch (cmnd, "STOP")     >= 2) goto stop;
    if (strMatch (cmnd, "ZERO")     >  0) goto zero;
    goto show;
/*============================================================================*/
  config:
/*======		Configure - Extract values from the logical names.
*/
    getenv_integer ("SINQHM_HM_MODE",  &Hm_mode, SQHM__HM_DIG);
    getenv_integer ("SINQHM_NHISTS",   &Nhists,  1);
    getenv_integer ("SINQHM_LOW_BIN",  &Lo_bin,  0);
    is1 = getenv_integer ("SINQHM_NBINS", &Nbins, 0);
    getenv_integer ("SINQHM_BINWID",   &Binwid,   4);
    getenv_integer ("SINQHM_COMPRESS", &Compress, 0);
    if (is1 != EXIT_SUCCESS) {
      printf ("\n\007 SINQHM setup is not defined or not complete.\n");
      printf (" Here is some help ...\n");
      show_help ("SETUP");
      if (is1 != EXIT_SUCCESS) {
	printf (" The problem is with SINQHM_NBINS\n");
      }
      printf ("\n");
      close (cnct_skt);
      return EXIT_FAILURE;
    }
/*
**		    Set up and send the configure message.
*/
    if (strMatch (modifier, "SUSPEND") >= 3) {
      Hm_mode |= SQHM__DEBUG;
    }

    Req_buff.bigend = htonl (0x12345678);
    Req_buff.cmnd   = htonl (SQHM_CONFIG);

    Req_buff.u.cnfg.mode     = htonl (Hm_mode);
    Req_buff.u.cnfg.n_hists  = htonl (Nhists);
    Req_buff.u.cnfg.lo_bin   = htonl (Lo_bin);
    Req_buff.u.cnfg.num_bins = htonl (Nbins);
    Req_buff.u.cnfg.binwid   = htonl (Binwid);
    Req_buff.u.cnfg.compress = htonl (Compress);

    printf (" Configuration:\n"
	    "   Histogramming mode is 0x%08x\n", Hm_mode);
    printf ("   Number of histograms         = %5d\n"
	    "   Index of first bin           = %5d\n"
	    "   Number of bins per histogram = %5d\n"
	    "   Number of bytes per bin      = %5d\n"
	    "   Bin compression factor       = %5d\n",
			Nhists, Lo_bin, Nbins, Binwid, Compress);
    if ((Hm_mode & SQHM__DEBUG) != 0)
      printf ("\007\n   Warning -- SQHM__DEBUG suspend flag is set!\n\n");
    printf (" Configuring ...");

    status = send (cnct_skt, (char *) &Req_buff, sizeof (Req_buff), 0);
    if (status == -1) FailInet ("\nSINQHM_CTRL -- send error");
    if (status != sizeof (Req_buff)) {
      printf ("\nSINQHM_CTRL -- wrong number of bytes sent: %d", status);
      return EXIT_FAILURE;
    }
/*
**		    Wait for the status response.
*/
    status = getCheckStatusResponse (cnct_skt, &Rply_buff, sizeof (Rply_buff));
    if (status == SUCCESS) {
      printf (" done.\n");
    }
/*
**		Close the connection.
*/
    status = close (cnct_skt);
    if ((status != 0) && (errno != ECONNRESET))
	    FailInet ("\nSINQHM_CTRL -- close error");
    return EXIT_SUCCESS;
/*============================================================================*/
  debug:
/*=====		Debug. Set up the debug level of the front-end..
*/
    Req_buff.bigend = htonl (0x12345678);
    Req_buff.cmnd   = htonl (SQHM_DBG);
    if (strcmp (modifier, "ON") == 0) {	/* "modifier" may be "ON", "OFF" ..
					**  .. or an integer. */
      Req_buff.u.dbg.level = htonl (1);		    /* Turn on, level 1 */
      printf (" Setting SinqHM debug level on (1) ...");
    }else if (strcmp (modifier, "OFF") == 0) {
      Req_buff.u.dbg.level = 0;			    /* Turn off, level 0 */
      printf (" Setting SinqHM debug level off (0) ...");
    }else if (strcmp (modifier, "") == 0) {
      Req_buff.u.dbg.level = htonl (1);		    /* Turn on, level 1 */
      printf (" \"DEBUG ON\" assumed ..."
	      " setting SinqHM debug level = 1 ...");
    }else {
      status = sscanf (modifier, "%i", &i);
      status = sscanf (modifier, "%i", &Req_buff.u.dbg.level);
      if (status == 1) {
        Req_buff.u.dbg.level = htonl (i);
	printf (" Setting SinqHM debug level = %d ...", i);
      }else {
        Req_buff.u.dbg.level = htonl (1);	/* Turn on, if error */
        printf (" Invalid DEBUG command. \"DEBUG ON\" assumed ...");
      }
    }
    status = send (cnct_skt, (char *) &Req_buff, sizeof (Req_buff), 0);
    if (status == -1) FailInet ("\nSINQHM_CTRL -- send error");
    if (status != sizeof (Req_buff)) {
      printf ("SINQHM_CTRL -- wrong number of bytes sent: %d", status);
      return EXIT_FAILURE;
    }
/*
**		Wait for the status response.
*/
    status = getCheckStatusResponse (cnct_skt, &Rply_buff, sizeof (Rply_buff));
    if (status == SUCCESS) {
      printf (" done.\n");
    }
/*
**		Close the connection.
*/
    status = close (cnct_skt);
    if ((status != 0) && (errno != ECONNRESET))
	    FailInet ("\nSINQHM_CTRL -- close error");
    return EXIT_SUCCESS;
/*============================================================================*/
  deconfig:
/*========		De-configure. Set up and send the deconfig message.
*/
    Req_buff.bigend = htonl (0x12345678);
    Req_buff.cmnd   = htonl (SQHM_DECONFIG);
    Req_buff.u.decnfg.sub_code = 0;		/* Be gentle, by default */
    if (strcmp (modifier, "HARSH") == 0) {
      Req_buff.u.decnfg.sub_code = htonl (1);	/* But be harsh, if ordered */
      printf (" Deconfiguring (mit Gewalt!) ...");
    }else {
      printf (" Deconfiguring ...");
    }
    
    status = send (cnct_skt, (char *) &Req_buff, sizeof (Req_buff), 0);
    if (status == -1) FailInet ("\nSINQHM_CTRL -- send error");
    if (status != sizeof (Req_buff)) {
      printf ("SINQHM_CTRL -- wrong number of bytes sent: %d", status);
      return EXIT_FAILURE;
    }
/*
**		Wait for the status response.
*/
    status = getCheckStatusResponse (cnct_skt, &Rply_buff, sizeof (Rply_buff));
    if (status == SUCCESS) {
      printf (" done.\n");
    }
/*
**		Close the connection.
*/
    status = close (cnct_skt);
    if ((status != 0) && (errno != ECONNRESET))
	    FailInet ("\nSINQHM_CTRL -- close error");
    return EXIT_SUCCESS;
/*============================================================================*/
  go:
/*==		Go. Get SinqHM-filler to start taking data.
*/
    printf (" Starting data acquisition ...");

    Req_buff.bigend	    = htonl (0x12345678);
    Req_buff.cmnd	    = htonl (SQHM_DAQ);
    Req_buff.u.daq.sub_cmnd = htonl (DAQ__GO);

    status = send (cnct_skt, (char *) &Req_buff, sizeof (Req_buff), 0);
    if (status == -1) FailInet ("\nSINQHM_CTRL -- send error");
    if (status != sizeof (Req_buff)) {
      printf ("SINQHM_CTRL -- wrong number of bytes sent: %d", status);
      return EXIT_FAILURE;
    }
/*
**		Wait for the status response.
*/
    status = getCheckStatusResponse (cnct_skt, &Rply_buff, sizeof (Rply_buff));
    if (status == SUCCESS) {
      daq_state_now = ntohl (Rply_buff.u.daq.daq_now);
      daq_state_was = ntohl (Rply_buff.u.daq.daq_was);
      filler_mask	  = ntohl (Rply_buff.u.daq.filler_mask);
      if (daq_state_now == 0) {
	if (daq_state_was == 0) {
	  printf (" done. It was already active!\n");
	}else {
	  printf (" done.\n");
	}
      }else {
	printf ("\n\007 Data acquisition is still disabled.\n"
	      " Dsbl_Mask   is 0x%08x\n"
	      " Filler_Mask is 0x%08x\n", daq_state_now, filler_mask);
      }
    }
/*
**		Close the connection.
*/
    status = close (cnct_skt);
    if ((status != 0) && (errno != ECONNRESET))
	    FailInet ("\nSINQHM_CTRL -- close error");
    return EXIT_SUCCESS;
/*============================================================================*/
  rundown:
/*=======		Rundown. Set up and send the rundown message.
*/
    printf (" Sending SQHM_EXIT command to SinqHM ...");
    Req_buff.bigend = htonl (0x12345678);
    Req_buff.cmnd   = htonl (SQHM_EXIT);
    
    status = send (cnct_skt, (char *) &Req_buff, sizeof (Req_buff), 0);
    if (status == -1) FailInet ("\nSINQHM_CTRL -- send error");
    if (status != sizeof (Req_buff)) {
      printf ("SINQHM_CTRL -- wrong number of bytes sent: %d", status);
      return EXIT_FAILURE;
    }
/*
**		Wait for the status response.
*/
    status = getCheckStatusResponse (cnct_skt, &Rply_buff, sizeof (Rply_buff));
    if (status == SUCCESS) {
      printf (" done.\n");
    }
/*
**		Close the connection.
*/
    status = close (cnct_skt);
    if ((status != 0) && (errno != ECONNRESET))
	    FailInet ("\nSINQHM_CTRL -- close error");
    return EXIT_SUCCESS;
/*============================================================================*/
  show:
/*====		    Show-status. Set up and send the status message.
*/
    printf (" Getting status of SinqHM ...");

    Req_buff.bigend = htonl (0x12345678);
    Req_buff.cmnd   = htonl (SQHM_STATUS);
    
    status = send (cnct_skt, (char *) &Req_buff, sizeof (Req_buff), 0);
    if (status == -1) FailInet ("\nSINQHM_CTRL -- send error");
    if (status != sizeof (Req_buff)) {
      printf ("SINQHM_CTRL -- wrong number of bytes sent: %d", status);
      return EXIT_FAILURE;
    }
/*
**		Wait for the status response.
*/
    status = getCheckStatusResponse (cnct_skt, &Rply_buff, sizeof (Rply_buff));
    if (status == SUCCESS) {
			/*
			**    Display the status obtained.
			*/
      memcpy (buff, (char *) &Rply_buff.sub_status, 4); /* Get SinqHM Ident */
      buff[4] = '\0';
      if (Rply_buff.u.status.cfg_state == 0) {
	printf ("\n   SINQHM has not yet been configured.\n");
	printf ("   SinqHM Identifier is \"%s\"\n", buff);
	printf ("   Maximum number of histograms = %d\n",
	    ntohl (Rply_buff.u.status.max_n_hists));
	printf ("   Maximum number of bins per histogram = %d\n",
	    ntohl (Rply_buff.u.status.max_num_bins));
	printf ("   Maximum number of active connections supported = %d\n",
	    Rply_buff.u.status.max_srvrs);
	printf ("   Maximum space available for histograms = %d bytes\n",
	    ntohl (Rply_buff.u.status.max_block));
      }else {
	printf ("\n   SinqHM Identifier is \"%s\"\n", buff);
	printf ("   Histogramming Mode = 0x%x\n",
	    ntohl (Rply_buff.u.status.cfg_state));
	printf ("   Number of histograms/Current histogram = %d/%d\n",
	    ntohs (Rply_buff.u.status.n_hists),
	    ntohs (Rply_buff.u.status.curr_hist));
	printf ("   Number of bins per histogram = %d\n",
	    ntohl (Rply_buff.u.status.num_bins));
	printf ("   Number of bytes per bin = %d\n", Rply_buff.u.status.binwid);
	printf ("   Maximum number of active connections supported = %d\n",
	    Rply_buff.u.status.max_srvrs);
	printf ("   Current number of active connections = %d\n",
	    Rply_buff.u.status.act_srvrs);
	printf ("   Maximum block of free memory = %d bytes\n",
	    ntohl (Rply_buff.u.status.max_block));
	if (Rply_buff.u.status.daq_now == 0) {
	  printf ("   Data acquisition is active\n");
	}else {
	  printf ("   Data acquisition is not active\n");
	}
      }
    }
/*
**		Close the connection.
*/
    status = close (cnct_skt);
    if ((status != 0) && (errno != ECONNRESET))
	    FailInet ("\nSINQHM_CTRL -- close error");
    return EXIT_SUCCESS;
/*============================================================================*/
  stop:
/*====		Stop. Get SinqHM-filler to stop taking data.
*/
    printf (" Stopping data acquisition ...");

    Req_buff.bigend	    = htonl (0x12345678);
    Req_buff.cmnd	    = htonl (SQHM_DAQ);
    Req_buff.u.daq.sub_cmnd = htonl (DAQ__STOP);

    status = send (cnct_skt, (char *) &Req_buff, sizeof (Req_buff), 0);
    if (status == -1) FailInet ("\nSINQHM_CTRL -- send error");
    if (status != sizeof (Req_buff)) {
      printf ("SINQHM_CTRL -- wrong number of bytes sent: %d", status);
      return EXIT_FAILURE;
    }
/*
**		Wait for the status response.
*/
    status = getCheckStatusResponse (cnct_skt, &Rply_buff, sizeof (Rply_buff));
    if (status == SUCCESS) {
      daq_state_now = ntohl (Rply_buff.u.daq.daq_now);
      daq_state_was = ntohl (Rply_buff.u.daq.daq_was);
      filler_mask   = ntohl (Rply_buff.u.daq.filler_mask);
      if (daq_state_now != 0) {
	if (daq_state_was == 0) {
	  printf (" done.\n");
	}else {
	  printf (" done. It was already stopped!\n");
	}
      }else {
	printf ("\n\007 Data acquisition is still enabled!\n"
		" Dsbl_Mask   is 0x%08x\n"
		" Filler_Mask is 0x%08x\n", daq_state_now, filler_mask);
      }
    }
/*
**		Close the connection.
*/
    status = close (cnct_skt);
    if ((status != 0) && (errno != ECONNRESET))
	    FailInet ("\nSINQHM_CTRL -- close error");
    return EXIT_SUCCESS;
/*============================================================================*/
  zero:
/*====		Zero. Zero the complete histogram buffer
*/
    Req_buff.bigend = htonl (0x12345678);
    Req_buff.cmnd   = htonl (SQHM_ZERO);
    Req_buff.u.zero.hist_no   = htonl (-1);
    Req_buff.u.zero.first_bin = htonl (-1);
    Req_buff.u.zero.n_bins    = htonl (-1);
    printf (" Zeroing the histogram memory buffer ...");

    status = send (cnct_skt, (char *) &Req_buff, sizeof (Req_buff), 0);
    if (status == -1) FailInet ("\nSINQHM_CTRL -- send error");
    if (status != sizeof (Req_buff)) {
      printf ("\nSINQHM_CTRL -- wrong number of bytes sent: %d", status);
      return EXIT_FAILURE;
    }
/*
**		Wait for the status response.
*/
    status = getCheckStatusResponse (cnct_skt, &Rply_buff, sizeof (Rply_buff));
    if (status == SUCCESS) {
      printf (" done.\n");
    }
/*
**		Close the connection.
*/
    status = close (cnct_skt);
    if ((status != 0) && (errno != ECONNRESET))
	    FailInet ("\nSINQHM_CTRL -- close error");
    return EXIT_SUCCESS;
/*============================================================================*/
  help:
/*====		Help - give some help.
*/
    show_help (modifier);
    return EXIT_SUCCESS;
  }
/*================================================ End of SINQHM_CTRL.C =====*/
