#define	    IDENT	"1B06"
/*
** +--------------------------------------------------------------+
** |                  Paul Scherrer Institute                     |
** |                     SINQ Division				  |
** |                                                              |
** | 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  . . . . . . . . : [...SinqHM]SinqHM_srv_routines.c
**
** Author   . . . . . . . . . . : D. Maden
** Date of creation . . . . . . : Dec 1996
**
** Updates:
**  1A01 12-Dec-1996 DM	    Initial version.
**  1A06 16-Jul-1997 DM	    Flush fibre-optic FIFO on SQHM_ZERO and SQHM_WRITE.
**  1B01 11-Jun-1999 DM	    Add SQHM__HRPT mode.
**  1B02 10-Aug-1999 DM	    Make Lwl_hdr_daq_mask/Lwl_hdr_daq_soll dependent
**				on the instrument.
**  1B03 May-2001    MK     Added code for AMOR/TRICS PSD
**  1B04 August 2001 MK     Added code for AMOR to PROJECT handling
**---------------------------------------------------------------------------
**  SinqHM_srv_routines.c is part of the SINQ Histogram Memory process
**  which will run in a front-end processor and perform the necessary
**  operations for a SINQ multi-detector. It provides various utility routines.
**
**  To compile this program for VxWorks on PSS123, use:
**
	    ccvx SinqHM_srv_routines.c
** where
	    ccvx = ccppc -O0			\
		    -mcpu=603			\
		    -I${WIND_BASE}/target/h	\
		    -fno-builtin		\
		    -fno-for-scope		\
		    -nostdinc			\
		    -DCPU=PPC603		\
		    -D_GNU_TOOL			\
		    -gdwarf -c -Wimplicit
**====================================================================
*/
#include    <vxWorks.h>
#include    <taskLib.h>
#include    <msgQLib.h>
#include    <sockLib.h>
#include    <hostLib.h>
#include    <inetLib.h>
#include    <sysLib.h>
#ifdef MEN_A012
/*
#include <MEN/men_typs.h>
#include <sysLib_men.h>
*/
extern PART_ID sysHighMemPart;
#endif
#include    <tickLib.h>

#include    <stdlib.h>
#include    <stdio.h>
#include    <ioLib.h>
#include    <signal.h>
#include    <timers.h>
#include    <string.h>
#include    <errno.h>
#include    <netinet/in.h>
#include    <unistd.h>
#include    <setjmp.h>
#include    <vme.h>


/*
**====================	Global Definitions =====================================
*/
#include    "SinqHM_def.h"
#include    "SinqHM_gbl.h"
#include    "vmio10_def.h"

  extern    char    *vxWorksVersion;	/* Version string of vxWorks */
  extern    char    *creationDate;	/* Creation Date string of vxWorks */
/*========================== Define some prototypes ================*/
/*

**=============================================================================
**  Routines in this Module:
**
**  SinqHM_routines_setup_id	: copy some ident information to global vars.
**
**  catch_int_signal	 : SIGINT signal catching routine.
**  catch_machine_check	 : SIGBUS signal catching routine.
**  catch_signal	 : Signal catching routine.
**  chk_config_alloc	 : Check a configuration request and allocate memory.
**  cleanup_children	 : Find out which child(ren) have exited.
**  close_down_offspring : Close down FILLER and, possibly, other children.
**  do_SQHM__HM_DIG_alloc: SQHM__HM_DIG aux routine for chk_config_alloc.
**  do_SQHM__HRPT_alloc	 : SQHM__HRPT   aux routine for chk_config_alloc.
**  do_SQHM__TOF_alloc	 : SQHM__TOF    aux routine for chk_config_alloc.
**  do_SQHM__PSD_alloc	 : SQHM__PSD    aux routine for chk_config_alloc.
**  do_SQHM__TRANS_alloc : SQHM__TRANS  aux routine for chk_config_alloc.
**  do_command		 : Routine to handle a network command.
**  do_daq		 : Action routine for SINQHM_DAQ command.
**  do_project		 : Read projected histogram data.
**  do_read		 : Read  a block of the histogram memory.
**  do_write		 : Write a block of the histogram memory.
**  do_zero		 : Action routine for SINQHM_ZERO command.
**  failInet		 : Call to report fatal network failure.
**  failInet_port	 : Call to failInet with an extra parameter.
**  free_HM_memory	 : Release any allocated data structures.
**  getErrno		 : Get local copy of errno.
**  get_pid		 : Get our process ID (= TaskID under VxWorks).
**  kill_children	 : Send stop signals to all children to stop them.
**  lwl_Fifo_Flush	 : Flush out any data in the fibre-optic FIFO.
**  lwl_Packet_Read	 : Read out current packet from the fibre-optic FIFO.
**  make_child		 : Make a child process and activate it.
**  make_filler		 : Make the filler process and activate it.
**  net_flush		 : Flush out data from socket.
**  process_coinc_tsi	 : Process a "coincidence" type TSI packet.
**  process_no_coinc_tsi : Process a "normal" type TSI packet.
**  rply_status_send	 : Send a reply status message to client.
**  rply_status_setup	 : Setup a reply status message to client.
**  rply_status_setup_and_send	 : Setup & send a reply status msg to client.
**  selectNewBuffer	 : Move to new buffer in SQHM_TRANS mode.
**  setupLevelGenerator	 : Set up VMIO10 module for generating timing signals.
**  setup_inet_info	 : Used to get Internet Node name and addr from system.
**  sleep		 : Go to sleep for a bit.
**  StrJoin		 : join 2 strings.
**==============================================================================
*/
  void	SinqHM_routines_setup_id () {
/*	========================
**		Simply copy some ident information to global variables
**		for use by the SQHM_IDENT request.
*/
    StrJoin (Sqhm_rout_ident, sizeof (Sqhm_rout_ident), IDENT, "");
    StrJoin (Sqhm_rout_date,  sizeof (Sqhm_rout_date),  __DATE__, ", ");
    StrJoin (Sqhm_rout_date,  sizeof (Sqhm_rout_date),  Sqhm_rout_date, __TIME__);
  }
/*
**--------------------------------------------------------------------------*/
  void catch_int_signal (int signo) {
/*     ================
**	    Action Routine for catching SIGINT signals. This is a signal
**	    from the parent to get its child to exit. An exit will be performed.
*/
    int	    i, is;
    pid_t   my_pid;

    my_pid = get_pid ();
			    /*
			    ** Try to find our index by searching the PID list
			    */
    if (my_pid == Filler_pid) {
      if (FillTimer_active) {	    /* If Filler, kill off timer */
	is = timer_cancel (FillTimerId);
	if (is != 0) printf ("Problem cancelling FillTimer\n");
	is = timer_delete (FillTimerId);
	if (is != 0) printf ("Problem deleting FillTimer\n");
	FillTimer_active = False;
      }
    }else {
      for (i = MAX_CLIENTS; i > 0; i--) if (my_pid == Child_pid[i]) break;
      if (i > 0) {
	if (Child_rw_skt[i] != 0) {
	  printf ("\nClosing r/w socket of task %s\n", Tsk_name[i]);
	  close (Child_rw_skt[i]);
	  Child_rw_skt[i] = 0;
	}
	if (Child_cnct_skt[i] != 0) {
	  printf ("\nClosing connect socket of task %s\n", Tsk_name[i]);
	  close (Child_cnct_skt[i]);
	  Child_cnct_skt[i] = 0;
	}
      }
    }

    if (Dbg_lev0) printf ("catch_int_signal: Signal %d received by PID 0x%x.\n",
				    signo, my_pid);
    switch (signo) {
     case SIGINT:	    /* A SIGINT signal has been received. Exit. */
       exit (KER__SUCCESS);
       break;
     default:
       printf ("catch_int_signal: Unexpected signal %d received by PID 0x%x.\n",
				    signo, my_pid);
    }
  }
/*
**--------------------------------------------------------------------------*/
  void catch_machine_check (int signo) {
/*     ===================
*/
    longjmp (Vmio_trap_env, 1);	    /* Return to trapped code */
  }
/*
**--------------------------------------------------------------------------
*/
  void catch_signal (int signo) {
/*     ============
**		    Action Routine for catching signals from Child Processes.
*/
    pid_t   my_pid;

    my_pid = get_pid ();
    if (Dbg_lev0) printf ("catch_signal: Signal %d received by PID 0x%x.\n",
						    signo, my_pid);
    switch (signo) {
     case SIGUSR1:	    /* A child is about to exit. */
       Cnt_SIGUSR1++;
       sleep (1);	    /* Give it a chance to disappear! */
       break;
     default:
       printf ("catch_signal: Unexpected signal received by PID 0x%x: %d.\n",
				    my_pid, signo);
    }
  }
/*
**--------------------------------------------------------------------------*/
  int chk_config_alloc (
/*    ================
*/			int			 skt,
			struct req_buff_struct	*request,
			struct rply_buff_struct	*reply) {
/*
**
**	    Routine to check a configuration request and reserve the
**	    space for the histogram data.
**		Return	OK    if configuration request OK.
**			ERROR if error.
*/
    int	    i, mask, s_stat;

    Hm_mode_ALL = ntohl (request->u.cnfg.mode);	/* The histogramming mode */

    Hm_mode	    = Hm_mode_ALL & (~SQHM__SUB_MODE_MSK);
    Hm_mode_DEBUG   = Hm_mode_ALL & SQHM__DEBUG;
    Hm_mode_UD	    = Hm_mode_ALL & SQHM__UD;
    Hm_mode_BO	    = Hm_mode_ALL & SQHM__BO_MSK;
    Hm_mode_STROBO  = Hm_mode_ALL & SQHM__STROBO;
    Hm_mode_REFLECT = Hm_mode_ALL & SQHM__REFLECT;
    Hm_mode_NO_STAT = Hm_mode_ALL & SQHM__NO_STAT;

    switch (Hm_mode) {
     /*----------------------------*/
     case SQHM__TRANS:
      s_stat = do_SQHM__TRANS_alloc (request, reply);
      if (s_stat != OK) return ERROR;
      break;
     /*----------------------------*/
     case SQHM__HM_DIG:
      s_stat = do_SQHM__HM_DIG_alloc (request, reply);
      if (s_stat != OK) return ERROR;
      break;
     /*----------------------------*/
     case SQHM__HRPT:
      s_stat = do_SQHM__HRPT_alloc (request, reply);
      if (s_stat != OK) return ERROR;
      break;
     /*----------------------------*/
     case SQHM__HM_PSD:
      s_stat = do_SQHM__PSD_alloc (skt, request, reply);
      if (s_stat != OK) return ERROR;
      break;
     /*----------------------------*/
     case SQHM__TOF:
      s_stat = do_SQHM__TOF_alloc (skt, request, reply);
      if (s_stat != OK) return ERROR;
      break;
     /*----------------------------*/
     default:
      printf ("\nchk_config_alloc: "
		"unrecognised histogramming mode: %d.\n", Hm_mode);
      rply_status_setup (reply, KER__BAD_VALUE, 0, "Unrecognised hist mem mode");
      return ERROR;
     /*----------------------------*/
    }
    Cfgn_done = 1;
    return OK;
  }
/*
**--------------------------------------------------------------------------*/
  void cleanup_children () {
/*     ================
**		    Find out which child(ren) have exited and update the
**		    list of task PID's so the associated task slot becomes
**		    free.
**
**		    If FILLER has fallen off, then any active children will
**		    be told to exit and we shall set our state to "deconfig".
*/
    int		i, status, n_active;
    char       *t_name;
    pid_t	pid;

    if (Filler_pid != 0) {
      if (Dbg_lev0) printf ("\n  ... checking state of %s ...", Filler_name);
      t_name = taskName (Filler_pid);
      if (t_name == NULL) {
        if (Dbg_lev0) printf (" it has exited.");
        Filler_pid = 0;
      }else {
        if (Dbg_lev0) printf (" it is still active.");
      }
    }

    n_active = 0;
    for (i = 1; i <= MAX_CLIENTS; i++) {
      if (Child_pid[i] != 0) {
	if (Dbg_lev0) printf ("\n  ... checking state of SRV_%02d ...", i);
	t_name = taskName (Child_pid[i]);
	if (t_name == NULL) {
	  if (Dbg_lev0) printf (" it has exited.");
	  Child_pid[i] = 0;
	}else {
	  if (Dbg_lev0) printf (" it is still active.");
	  n_active += 1;
	}
      }
    }
    Cnt_SIGUSR1 = 0;

    if ((Filler_pid == 0) && (n_active > 0)) {	/* Must we force a de-config? */
      for (;;) {			     /* Loop for ever till programmed */
	printf ("\n\007hmFill has terminated abnormally. A de-configure must"
					    "be forced\n"
	      "This has not yet been programmed.\n"
	      "Re-boot the histogram memory!!\n");
	sleep (5);
      }
    }
  }
/*
**--------------------------------------------------------------------------*/
  int close_down_offspring (
/*    ====================
*/			    struct req_buff_struct  *request,
			    struct rply_buff_struct *reply) {
/*
**		    Close down FILLER and, if directed, other children too.
*/
    int		i, j;
    int		n_children = 0, new_c = 0;

    n_children = 0;		/* See if any server children are active */
    for (i = 1; i <= MAX_CLIENTS; i++) {
      if (Child_pid[i] != 0) n_children += 1;
    }
    if (n_children > 0) {   /* If so, only proceed if asked to be ruthless */
      if (ntohl (request->u.decnfg.sub_code) == 0) {
	printf ("\nDe-configure error. ");
        if (n_children == 1) printf ("1 server is");
        if (n_children != 1) printf ("%d servers are", n_children);
	printf (" still active.\n");
	return KER__BAD_STATE;
      }else {
        if (n_children == 1) printf (" -- 1 server is still active. It");
        if (n_children != 1) printf (" -- %d servers are still active. They",
						n_children);
	printf (" will be terminated.\n");
      }
    }

    kill_children ();		    /* Kill FILLER and any server children */
    sleep (1);			    /* Give them chance to exit */
    cleanup_children ();	    /* Update the PIDs */

    for (j = 0; j < n_children; j++) {	    /* Check to see if all gone */
      if (Filler_pid == 0) new_c = 0; else new_c = 1;  /* Count remainder */
      for (i = MAX_CLIENTS; i > 0; i--) {
	if (Child_pid[i] != 0) new_c += 1;
      }
      if (new_c == 0) break;
      sleep (1);
      cleanup_children ();
    }
    if (new_c != 0) {
      printf ("     ... failed to tidy up. %d children still active.\n", new_c);
      return KER__BAD_STATE;
    }else {
      return KER__SUCCESS;
    }
  }
/*
**--------------------------------------------------------------------------*/
  int do_SQHM__HM_DIG_alloc (
/*    =====================
*/			struct req_buff_struct  *request,
			struct rply_buff_struct	*reply) {
/*
**		Routine to allocate memory for the SQHM__HM_DIG
**		configure request.
**
*/
    int		i;

    N_hists = ntohl (request->u.cnfg.u.hm_dig.n_hists);   /* The # of
					** histograms (used in strobo (gummi)
					** and Up/Down mode).
					*/
    Lo_bin   = ntohl (request->u.cnfg.u.hm_dig.lo_bin);   /* The index of
					** first bin in histogram
					*/
    N_bins   = ntohl (request->u.cnfg.u.hm_dig.num_bins); /* The # of bins
					** in each histogram
					*/
    Bytes_per_bin = ntohl (request->u.cnfg.u.hm_dig.bytes_per_bin); /* The # of
							      ** bytes per bin
							      */
    Compress = ntohl (request->u.cnfg.u.hm_dig.compress); /* The compression
							  ** factor
							  */
    Curr_hist = 0;				/* The selected histogram */
    if (Compress      == 0) Compress	  = 1;
    if (Bytes_per_bin == 0) Bytes_per_bin = 4;

    if (N_hists > N_HISTS_MAX) {
      printf ("do_SQHM__HM_DIG_alloc: Illegal number of histograms: %d.\n",
		    N_hists);
      rply_status_setup (reply, KER__BAD_VALUE, 0, "Bad number of histograms");
      return ERROR;
    }else if (Hm_mode_UD && (N_hists & 1)) {
      printf ("do_SQHM__HM_DIG_alloc: SQHM_UD is set.\n"
	      "       Number of histograms should be multiple of 2.\n"
	      "       %d is therefore illegal.\n", N_hists);
      rply_status_setup (reply, KER__BAD_VALUE, 0,
	    "Number of histograms not multiple of 2");
      return ERROR;
    }else if (Hm_mode_STROBO && (N_hists & 15)) {
      printf ("do_SQHM__HM_DIG_alloc: SQHM_STROBO is set.\n"
	      "       Number of histograms should be multiple of 16.\n"
	      "       %d is therefore illegal.\n", N_hists);
      rply_status_setup (reply, KER__BAD_VALUE, 0,
	    "Number of histograms not multiple of 16");
      return ERROR;
    }else if (Hm_mode_UD && Hm_mode_STROBO && (N_hists & 31)) {
      printf ("do_SQHM__HM_DIG_alloc: SQHM_UD and SQHM_STROBO are both set.\n"
	      "       Number of histograms should be multiple of 32.\n"
	      "       %d is therefore illegal.\n", N_hists);
      rply_status_setup (reply, KER__BAD_VALUE, 0,
	    "Number of histograms not multiple of 32");
      return ERROR;
    }

    if (Lo_bin > N_BINS_MAX) {
      printf ("do_SQHM__HM_DIG_alloc: Illegal first bin: %d.\n", Lo_bin);
      rply_status_setup (reply, KER__BAD_VALUE, 0, "Bad first bin");
      return ERROR;
    }

    if (N_bins > (N_BINS_MAX + 1)) {
      printf ("do_SQHM__HM_DIG_alloc: Illegal number of bins: %d.\n", N_bins);
      rply_status_setup (reply, KER__BAD_VALUE, 0, "Bad # bins");
      return ERROR;
    }

    Hi_bin = Lo_bin + N_bins - 1;
    if (Hi_bin > N_BINS_MAX) {
      printf ("do_SQHM__HM_DIG_alloc: Illegal first-bin and/or number-of-bins:"
		" %d %d.\n", Lo_bin, N_bins);
      rply_status_setup (reply, KER__BAD_VALUE, 0, "Bad bin definition");
      return ERROR;
    }

    if ((Bytes_per_bin != 1) && (Bytes_per_bin != 2) && (Bytes_per_bin != 4)) {
      printf ("do_SQHM__HM_DIG_alloc: Illegal bin width: %d.\n", Bytes_per_bin);
      rply_status_setup (reply, KER__BAD_VALUE, 0, "Bad bytes-per-bin");
      return ERROR;
    }

    Total_bytes = N_hists * N_bins * Bytes_per_bin;
    if (Total_bytes > N_TOTAL_BYTES) {	     /* Check it's not too much */
      printf ("do_SQHM__HM_DIG_alloc: Illegal overall size: %d.\n", Total_bytes);
      printf ("                       Permitted max:        %d.\n", N_TOTAL_BYTES);
      rply_status_setup (reply, KER__BAD_VALUE, 0,
	    "Total histogram size too big");
      return ERROR;
    }
    
    printf ("\n    Histogramming mode is \"SQHM__HM_DIG\"\n");
    printf ("    Number of histograms   = %5d\n", N_hists);
    printf ("    First bin              = %5d\n", Lo_bin);
    printf ("    Number of bins         = %5d\n", N_bins);
    printf ("    Bytes per bin          = %5d\n", Bytes_per_bin);
    printf ("    Bin compression factor = %5d\n", Compress);
    if (Hm_mode_UD != 0)
      printf ("    Up/Down mode selected\n");
    if (Hm_mode_STROBO != 0)
      printf ("    Stroboscopic mode selected\n");
    if (Hm_mode_REFLECT != 0)
      printf ("    Histograms will be reflected\n");
    printf ("    Bin-overflow action is ");
    switch (Hm_mode_BO) {
     case SQHM__BO_IGN:	 printf ("\"Ignore\"\n"); break;
     case SQHM__BO_SMAX: printf ("\"Stop-at-Max\"\n"); break;
     case SQHM__BO_CNT:	 printf ("\"Count\"\n"); break;
     default:		 printf ("\"Undefined\"\n");
    }

    i = memFindMax ();	    /* Get size of biggest free memory block */
    if (i > Total_bytes) {
      Hist_base_addr = calloc (Total_bytes, sizeof (char));
    }else {
      Hist_base_addr = NULL;
    }
    if (Hist_base_addr == NULL) {
      printf ("\007do_SQHM__HM_DIG_alloc:\n"
	" Unable to reserve %d bytes of memory!\n"
	" Largest block available = %d.\n", Total_bytes, i);
      rply_status_setup (reply, KER__BAD_ALLOC, i,
	    "Failed to get buffer for histograms");
      return ERROR;
    }
    Cnts_lo = Cnts_hi = 0;
    N_events = N_skipped = N_no_coin_tsi = N_coin_tsi = 0;
    Print_hdr = True;

    printf ("    Histogram base address = 0x%08x\n", Hist_base_addr);
    printf ("    SQHM__HM_DIG mode configured.\n");
    return OK;
  }
/*
**--------------------------------------------------------------------------*/
  int do_SQHM__HRPT_alloc (
/*    ===================
*/			struct req_buff_struct  *request,
			struct rply_buff_struct	*reply) {
/*
**		Routine to allocate memory for the SQHM__HRPT
**		configure request.
**
*/
    int		i;

    N_hists = ntohl (request->u.cnfg.u.hm_dig.n_hists);   /* The # of
					** histograms (used in strobo (gummi)
					** and Up/Down mode).
					*/
    Lo_bin   = ntohl (request->u.cnfg.u.hm_dig.lo_bin);   /* The index of
					** first bin in histogram
					*/
    N_bins   = ntohl (request->u.cnfg.u.hm_dig.num_bins); /* The # of bins
					** in each histogram
					*/
    Bytes_per_bin = ntohl (request->u.cnfg.u.hm_dig.bytes_per_bin); /* The # of
							      ** bytes per bin
							      */
    Compress = ntohl (request->u.cnfg.u.hm_dig.compress); /* The compression
							  ** factor
							  */
    Curr_hist = 0;				/* The selected histogram */
    if (Compress      == 0) Compress	  = 1;
    if (Bytes_per_bin == 0) Bytes_per_bin = 4;

    if (N_hists > N_HISTS_MAX) {
      printf ("do_SQHM__HRPT_alloc: Illegal number of histograms: %d.\n",
		    N_hists);
      rply_status_setup (reply, KER__BAD_VALUE, 0, "Bad number of histograms");
      return ERROR;
    }else if (Hm_mode_UD && (N_hists & 1)) {
      printf ("do_SQHM__HRPT_alloc: SQHM_UD is set.\n"
	      "       Number of histograms should be multiple of 2.\n"
	      "       %d is therefore illegal.\n", N_hists);
      rply_status_setup (reply, KER__BAD_VALUE, 0,
	    "Number of histograms not multiple of 2");
      return ERROR;
    }else if (Hm_mode_STROBO && (N_hists & 15)) {
      printf ("do_SQHM__HRPT_alloc: SQHM_STROBO is set.\n"
	      "       Number of histograms should be multiple of 16.\n"
	      "       %d is therefore illegal.\n", N_hists);
      rply_status_setup (reply, KER__BAD_VALUE, 0,
	    "Number of histograms not multiple of 16");
      return ERROR;
    }else if (Hm_mode_UD && Hm_mode_STROBO && (N_hists & 31)) {
      printf ("do_SQHM__HRPT_alloc: SQHM_UD and SQHM_STROBO are both set.\n"
	      "       Number of histograms should be multiple of 32.\n"
	      "       %d is therefore illegal.\n", N_hists);
      rply_status_setup (reply, KER__BAD_VALUE, 0,
	    "Number of histograms not multiple of 32");
      return ERROR;
    }

    if (Lo_bin > N_BINS_MAX) {
      printf ("do_SQHM__HRPT_alloc: Illegal first bin: %d.\n", Lo_bin);
      rply_status_setup (reply, KER__BAD_VALUE, 0, "Bad first bin");
      return ERROR;
    }

    if (N_bins > (N_BINS_MAX + 1)) {
      printf ("do_SQHM__HRPT_alloc: Illegal number of bins: %d.\n", N_bins);
      rply_status_setup (reply, KER__BAD_VALUE, 0, "Bad # bins");
      return ERROR;
    }

    Hi_bin = Lo_bin + N_bins - 1;
    if (Hi_bin > N_BINS_MAX) {
      printf ("do_SQHM__HRPT_alloc: Illegal first-bin and/or number-of-bins:"
		" %d %d.\n", Lo_bin, N_bins);
      rply_status_setup (reply, KER__BAD_VALUE, 0, "Bad bin definition");
      return ERROR;
    }

    if ((Bytes_per_bin != 1) && (Bytes_per_bin != 2) && (Bytes_per_bin != 4)) {
      printf ("do_SQHM__HRPT_alloc: Illegal bin width: %d.\n", Bytes_per_bin);
      rply_status_setup (reply, KER__BAD_VALUE, 0, "Bad bytes-per-bin");
      return ERROR;
    }

    Total_bytes = N_hists * N_bins * Bytes_per_bin;
    if (Total_bytes > N_TOTAL_BYTES) {	     /* Check it's not too much */
      printf ("do_SQHM__HRPT_alloc: Illegal overall size: %d.\n", Total_bytes);
      printf ("                       Permitted max:        %d.\n", N_TOTAL_BYTES);
      rply_status_setup (reply, KER__BAD_VALUE, 0,
	    "Total histogram size too big");
      return ERROR;
    }
    
    printf ("\n    Histogramming mode is \"SQHM__HRPT\"\n");
    printf ("    Number of histograms   = %5d\n", N_hists);
    printf ("    First bin              = %5d\n", Lo_bin);
    printf ("    Number of bins         = %5d\n", N_bins);
    printf ("    Bytes per bin          = %5d\n", Bytes_per_bin);
    printf ("    Bin compression factor = %5d\n", Compress);
    if (Hm_mode_UD != 0)
      printf ("    Up/Down mode selected\n");
    if (Hm_mode_STROBO != 0)
      printf ("    Stroboscopic mode selected\n");
    if (Hm_mode_REFLECT != 0)
      printf ("    Histograms will be reflected\n");
    printf ("    Bin-overflow action is ");
    switch (Hm_mode_BO) {
     case SQHM__BO_IGN:	 printf ("\"Ignore\"\n"); break;
     case SQHM__BO_SMAX: printf ("\"Stop-at-Max\"\n"); break;
     case SQHM__BO_CNT:	 printf ("\"Count\"\n"); break;
     default:		 printf ("\"Undefined\"\n");
    }

    i = memFindMax ();	    /* Get size of biggest free memory block */
    if (i > Total_bytes) {
      Hist_base_addr  = calloc (Total_bytes, sizeof (char));
      Frame_base_addr = calloc (((N_bins + 2) * Bytes_per_bin), sizeof (char));
    }else {
      Hist_base_addr  = NULL;
      Frame_base_addr = NULL;
    }
    if (Hist_base_addr == NULL) {
      free_HM_memory (NULL);
      printf ("\007do_SQHM__HRPT_alloc:\n"
	" Unable to reserve %d bytes of memory!\n"
	" Largest block available = %d.\n", Total_bytes, i);
      rply_status_setup (reply, KER__BAD_ALLOC, i,
	    "Failed to get buffer for histograms");
      return ERROR;
    }
    if (Frame_base_addr == NULL) {
      free_HM_memory (NULL);
      printf ("\007do_SQHM__HRPT_alloc:\n"
	" Unable to reserve %d bytes of memory for frame buffer!\n"
	" Largest block available = %d.\n", ((N_bins + 2) * Bytes_per_bin), i);
      rply_status_setup (reply, KER__BAD_ALLOC, i,
	    "Failed to get frame buffer");
      return ERROR;
    }
    Cnts_lo = Cnts_hi = 0;
    N_events = N_skipped = N_no_coin_tsi = N_coin_tsi = 0;
    Print_hdr = True;

    printf ("    Histogram    base address = 0x%08x\n", Hist_base_addr);
    printf ("    Frame buffer base address = 0x%08x\n", Frame_base_addr);
    printf ("    SQHM__HRPT mode configured.\n");
    return OK;
  }
/*
**--------------------------------------------------------------------------*/
  int do_SQHM__TRANS_alloc (
/*    ====================
*/			struct req_buff_struct  *request,
			struct rply_buff_struct	*reply) {
/*
**		Routine to allocate memory for the SQHM__TRANS
**		configure request.
*/
    int		i;

    N_hists = ntohl (request->u.cnfg.u.trans.n_buffs);  /* The # of buffers */
    N_bins  = ntohl (request->u.cnfg.u.trans.n_bytes);	/* The buffer size */
    Bytes_per_bin = 1;
    Curr_hist     = 0;			/* Start with the first buffer */
    Bytes_free	  = N_bins;

    Lo_cntr = Lo_bin = Hi_bin = Compress = Cnts_lo = Cnts_hi = 0;

    if ((N_hists == 0) || (N_hists > N_HISTS_MAX)) {
      printf ("do_SQHM__TRANS_alloc: Illegal number of buffers: %d.\n",
		    N_hists);
      rply_status_setup (reply, KER__BAD_VALUE, 0, "Bad number of buffers");
      return ERROR;
    }

    if ((N_bins < 23) || (N_bins > (N_BINS_MAX + 1))) {
      printf ("do_SQHM__TRANS_alloc: Illegal buffer size: %d.\n", N_bins);
      rply_status_setup (reply, KER__BAD_VALUE, 0, "Illegal buffer size");
      return ERROR;
    }

    Total_bytes = N_hists * (N_bins + 4);
    if (Total_bytes > N_TOTAL_BYTES) {	     /* Check it's not too much */
      printf ("do_SQHM__TRANS_alloc: Illegal overall size: %d.\n", Total_bytes);
      printf ("                      Permitted max:        %d.\n", N_TOTAL_BYTES);
      rply_status_setup (reply, KER__BAD_VALUE, 0,
	    "Total buffer size too big");
      return ERROR;
    }
    
    printf ("\n    Histogramming mode is \"SQHM__TRANS\"\n");
    printf ("    Number of buffers = %5d\n", N_hists);
    printf ("    Buffer size       = %5d bytes\n", N_bins);

    i = memFindMax ();	    /* Get size of biggest free memory block */
    if (i > Total_bytes) {
      Hist_base_addr = calloc (Total_bytes, sizeof (char));
    }else {
      Hist_base_addr = NULL;
    }
    if (Hist_base_addr == NULL) {
      printf ("\007do_SQHM__TRANS_alloc:\n"
	" Unable to reserve %d bytes of memory!\n"
	" Largest block available = %d.\n", Total_bytes, i);
      rply_status_setup (reply, KER__BAD_ALLOC, i,
	    "Failed to get space for buffers");
      return ERROR;
    }

    Tran_buff_base = Hist_base_addr;
    Next_char = Tran_buff_base + 4;
    printf ("    Buffer base address = 0x%08x\n", Hist_base_addr);
    printf ("    SQHM__TRANS mode configured.\n");
    return OK;
  }
/*
**--------------------------------------------------------------------------*/
  int do_SQHM__TOF_alloc (
/*    ==================
*/			int			 skt,
			struct req_buff_struct  *request,
			struct rply_buff_struct	*reply) {
/*
**		Routine to allocate memory for the SQHM__TOF
**		configure request.
**
**    Definitions:
**	Edge-Array
**		An 'edge-array' is a structure which specifies the lower edge
**		of each bin in the histogram. This is to allow variable width
**		histogram bins.
**	Counter Bank
**		A 'counter bank' is a contiguous group of counters, all of
**		which share the same parameters. In particular, all the counters
**		in the bank have the same number of bins and same bin edges.
*/
    int			     i, j, k, n_bytes_got;
    uint	     n_extra_bytes, n_banks, com2, nchar;
    uint	     first, n_cntrs, edge_indx, bytes_per_bin;
    uint	     n_bins, flag, edge_0, edge_1, bin_span, top_edge;
    uint	     bytes_needed, sizeof_edge_arr;
    uint	     time_span, n_total_bins;
    struct tof_edge_info    *edge_info_pntr;
    struct tof_edge_arr	    *edge_arr_pntr;
    struct tof_bank	    *bank_pntr;
    void		    *nxt_hist_addr;
    struct req_buff_struct  *my_rqst;
    char		    *p_addr, buff[64];

    Total_bytes = 0;

    n_extra_bytes = ntohl (request->u.cnfg.u.tof.n_extra_bytes);  /* The # of
					** extra bytes needed to be read from
					** the client to complete the configure
					** request.
					*/
    if (n_extra_bytes == 0) {
      my_rqst = request;
    }else {
		/*
		** There is extra data to be read. Get buffer space for the
		** extra stuff plus space to copy over what has already been
		** read so that everything is in a contiguous buffer.
		*/
      bytes_needed = n_extra_bytes + sizeof (*request);
      bytes_needed = (bytes_needed + 3) & (~3); /* Round up to multiple of 4 */
      p_addr = calloc (bytes_needed, sizeof (char));
      if (p_addr == NULL) {
	printf ("\007do_SQHM__TOF_alloc:\n"
		" cannot allocate memory for extra config data!\n");
	net_flush (skt, n_extra_bytes);
	rply_status_setup (reply, KER__BAD_ALLOC, 0,
	    "Failed to get buffer for extra config data");
	return ERROR;
      }
      memcpy (p_addr, request, sizeof (*request));  /* Copy in what has already
						    ** been read.
						    */
      my_rqst = (struct req_buff_struct *) p_addr;

      bytes_needed = n_extra_bytes;	    /* And read the rest */
      p_addr = p_addr + sizeof (*request);
      while (bytes_needed > 0) {
        n_bytes_got = recv (skt, p_addr, bytes_needed, 0);
        if (n_bytes_got <= 0) break;
        Rw_bytes_got += n_bytes_got;
        bytes_needed -= n_bytes_got;
        p_addr += n_bytes_got;
      }
      if (n_bytes_got < 0) {
        printf ("\007"
                "%s -- R/W-Socket recv error\n", Tsk_name[0]);
        printf ("%s -- Connection will be closed.\n", Tsk_name[0]);
	rply_status_setup (reply, KER__BAD_VALUE, 0, "recv failed");
	if (n_extra_bytes != 0) free (my_rqst);
	return ERROR;
      }
    }

    printf ("\n    Histogramming mode is \"SQHM__TOF\"\n");

    if (Hm_mode_UD != 0)
      printf ("    Up/Down mode selected\n");
    if (Hm_mode_STROBO != 0)
      printf ("    Stroboscopic mode selected\n");
    printf ("    Bin-overflow action is ");
    switch (Hm_mode_BO) {
     case SQHM__BO_IGN:	 printf ("\"Ignore\"\n"); break;
     case SQHM__BO_SMAX: printf ("\"Stop-at-Max\"\n"); break;
     case SQHM__BO_CNT:	 printf ("\"Count\"\n"); break;
     default:		 printf ("\"Undefined\"\n");
    }

    N_tof_edges = ntohs (my_rqst->u.cnfg.u.tof.n_edges);    /* The # of
					** different 'edge-arrays' which are
					** to be defined.
					*/
    printf ("    Number of Edge Arrays   = %2d\n", N_tof_edges);
    if (N_tof_edges > MAX_TOF_EDGE) {
      printf ("do_SQHM__TOF_alloc: Illegal number of edge-arrays: %u.\n",
		    N_tof_edges);
      rply_status_setup (reply, KER__BAD_VALUE, 0, "Too many edge-arrays");
      if (n_extra_bytes != 0) free (my_rqst);
      return ERROR;
    }

    n_banks = ntohs (my_rqst->u.cnfg.u.tof.n_banks);	    /* The # of
					** 'banks' of counters which are
					** to be defined.
					*/
    printf ("    Number of Counter Banks = %2d\n", n_banks);
    if (n_banks == 0) {
      rply_status_setup (reply, KER__BAD_VALUE, 0, "Illegal n_banks");
      printf ("do_SQHM__TOF_alloc: Illegal number of banks: %u.\n",
		    n_banks);
      if (n_extra_bytes != 0) free (my_rqst);
      return ERROR;
    }

    Tof_dts_soll = ntohl (my_rqst->u.cnfg.u.tof.preset_delay); /* The
					** required "Delay-Time-to-Start" */
    if ((Tof_dts_soll & (~LWL_TSI_DTS_MSK)) != 0) {
      rply_status_setup (reply, KER__BAD_VALUE, 0, "Bad Delay-Time-to-Start");
      printf ("do_SQHM__TOF_alloc: Delay-Time-to-Start illegal: 0x%x\n",
				    Tof_dts_soll);
      if (n_extra_bytes != 0) free (my_rqst);
      return ERROR;
    }
    com2 = open ("/tyCo/1", O_RDWR, 0);	    /* Send DTS to MDI via COM2 port */
    if (com2 == ERROR) {
      rply_status_setup (reply, KER__BAD_VALUE, 0, "COM2 open failed");
      printf ("do_SQHM__TOF_alloc: error opening COM2 port. "
		"Delay-Time-to-Start not set.\n");
      if (n_extra_bytes != 0) free (my_rqst);
      return ERROR;
    }else {
      ioctl (com2, FIOBAUDRATE, 9600);
      write (com2, "\r", 1);
      write (com2, "RMT 1\r", 6);
      nchar = sprintf (buff, "DT %d\r", Tof_dts_soll);
      if (write (com2, buff, nchar) != nchar) {
	rply_status_setup (reply, KER__BAD_VALUE, 0,
			    "Setting D-T-to-S failed");
	printf ("do_SQHM__TOF_alloc: error setting Delay-Time-to-Start.\n");
	if (n_extra_bytes != 0) free (my_rqst);
	close (com2);
	return ERROR;
      }else {
	printf ("    Delay-Time-to-Start     = %d\n", Tof_dts_soll);
      }
      close (com2);
    }
		/*
		** Loop over all the edge arrays
		*/
    edge_arr_pntr = &my_rqst->u.cnfg.u.tof.edge_0;
    for (i = 0; i < N_tof_edges; i++) {
      n_bins = ntohl (edge_arr_pntr->n_bins);
      flag   = ntohl (edge_arr_pntr->flag);
      edge_0 = ntohl (edge_arr_pntr->edges[0]);
      edge_1 = ntohl (edge_arr_pntr->edges[1]);
      printf ("    Edge Array %d:\n", i);
      printf ("      Number of bins          = %5d\n", n_bins);
      printf ("      Flag                    = %5d\n", flag);
      printf ("      Lower edge              = %5d\n", edge_0);
      if ((n_bins == 0) || (n_bins > MAX_TOF_NBINS)) {
	printf ("do_SQHM__TOF_alloc: Illegal # bins: %u.\n",
		    n_bins);
	rply_status_setup (reply, KER__BAD_VALUE, 0, "Bad number of bins");
	free_HM_memory (NULL);
	if (n_extra_bytes != 0) free (my_rqst);
	return ERROR;
      }
      if ((edge_0 & (~LWL_HDR_TS_MASK)) != 0) {
	printf ("do_SQHM__TOF_alloc: histog start is > 20 bits: %u\n",
		edge_0);
	rply_status_setup (reply, KER__BAD_VALUE, 0,
		"Bin edges overflow 20 bits");
	free_HM_memory (NULL);
	if (n_extra_bytes != 0) free (my_rqst);
	return ERROR;
      }
      if ((edge_1 & (~LWL_HDR_TS_MASK)) != 0) {
	printf ("do_SQHM__TOF_alloc: first bin is > 20 bits: %u\n",
		edge_1);
	rply_status_setup (reply, KER__BAD_VALUE, 0,
		"First bin overflows 20 bits");
	free_HM_memory (NULL);
	if (n_extra_bytes != 0) free (my_rqst);
	return ERROR;
      }
      bytes_needed = OffsetOf (struct tof_edge_info, edges) +
				    ((n_bins + 1) * sizeof (int));
      Tof_edges[i] = calloc (bytes_needed, sizeof (char)); /* Allocate space for
						      ** edge-array structure */
      if (Tof_edges[i] == NULL) {
	printf ("do_SQHM__TOF_alloc: unable to alloc memory for edge array.\n");
	rply_status_setup (reply, KER__BAD_ALLOC, 0,
	    "Failed to get memory for edge-array");
	free_HM_memory (NULL);
	if (n_extra_bytes != 0) free (my_rqst);
	return ERROR;
      }
      Tof_edges[i]->n_bins = n_bins;
      Tof_edges[i]->flag = flag;
      if ((flag & FLAG__VAR_BIN) == 0) {	    /* Fixed width bins? */
	printf ("      Bin width               = %5d\n", (edge_1 - edge_0));
        if (edge_0 >= edge_1) {			    /* Yes. Check bin width */
	  printf ("do_SQHM__TOF_alloc: bin width is zero or negative!\n");
	  rply_status_setup (reply, KER__BAD_VALUE, 0, "illegal bin width");
	  free_HM_memory (NULL);
	  if (n_extra_bytes != 0) free (my_rqst);
	  return ERROR;
	}
	bin_span = edge_1 - edge_0;
	Tof_edges[i]->bin_span = bin_span;
	top_edge = edge_0 + (n_bins * bin_span) - 1;
	if ((top_edge & (~LWL_HDR_TS_MASK)) != 0) {
	  printf ("do_SQHM__TOF_alloc: histog last bin is > 20 bits: %u\n",
		top_edge);
	  rply_status_setup (reply, KER__BAD_VALUE, 0,
		"Last bin overflows 20 bits");
	  free_HM_memory (NULL);
	  if (n_extra_bytes != 0) free (my_rqst);
	  return ERROR;
	}
	for (j=0; j <= n_bins; j++) Tof_edges[i]->edges[j] = edge_0+j*bin_span;
	Tof_edges[i]->hi_edge = top_edge;
	sizeof_edge_arr = OffsetOf (struct tof_edge_arr, edges) +
					    2 * sizeof (uint);
      }else {
					/* Variable width bins */
	bin_span = edge_1 - edge_0;	/* Note: even though the edges are
					** defined as variable, they may, in
					** fact, all be the same width. Check
					** for this so that we can make a brief
					** report rather than listing all
					** the bin edges.
					*/
	Tof_edges[i]->bin_span = 0;
	Tof_edges[i]->edges[0] = edge_0;
	for (j = 1; j <= n_bins; j++) {
	  Tof_edges[i]->edges[j] = ntohl (edge_arr_pntr->edges[j]);
	  if ((Tof_edges[i]->edges[j] & (~LWL_HDR_TS_MASK)) != 0) {
	    printf ("do_SQHM__TOF_alloc: histog bin is > 20 bits: %d %u\n",
		j, Tof_edges[i]->edges[j]);
	    rply_status_setup (reply, KER__BAD_VALUE, 0,
		    "Bin edge overflows 20 bits");
	    free_HM_memory (NULL);
	    if (n_extra_bytes != 0) free (my_rqst);
	    return ERROR;
	  }
	  if (Tof_edges[i]->edges[j-1] >= Tof_edges[i]->edges[j]) {
	    printf ("do_SQHM__TOF_alloc: bin edges are not in sequence: %d %d\n",
		i, j);
	    rply_status_setup (reply, KER__BAD_VALUE, 0,
		    "Bin edges not in sequence");
	    free_HM_memory (NULL);
	    if (n_extra_bytes != 0) free (my_rqst);
	    return ERROR;
	  }
	  if ((Tof_edges[i]->edges[j] - Tof_edges[i]->edges[j-1]) != bin_span)
	    bin_span = 0;   /* Set bin_span to zero if bin widths really are
			    ** variable */
	}
	if (bin_span != 0) {
	  printf ("      Variable width bins but width of all bins = %d\n",
				bin_span);
	}else {
	  printf ("      Variable width bins. Upper bin edges are:\n");
	  for (j = 1; j <= n_bins; j += 10) {
	    for (k = 0; ((k + j) <= n_bins) && (k < 10); k++)
	      printf ("%7d", Tof_edges[i]->edges[j+k]);
	    printf ("\n");
	  }
	}
	Tof_edges[i]->hi_edge = Tof_edges[i]->edges[n_bins] - 1;
	sizeof_edge_arr = OffsetOf (struct tof_edge_arr, edges) +
				((n_bins + 1) * sizeof (uint));
      }
      edge_arr_pntr = (struct tof_edge_arr *) (	   /* Move to next edge array */
	    (char *) edge_arr_pntr + sizeof_edge_arr);
    }
		/*
		** Loop over all the counter banks
		*/
    bank_pntr = (struct tof_bank *) edge_arr_pntr;

    for (i = 0; i < n_banks; i++) {

      first	    = ntohs (bank_pntr->first);
      n_cntrs	    = ntohs (bank_pntr->n_cntrs);
      edge_indx     = ntohs (bank_pntr->edge_indx);
      bytes_per_bin = ntohs (bank_pntr->bytes_per_bin);

      printf ("    Counter Bank %d:\n", i);
      printf ("      Number of counters      = %5d\n", n_cntrs);
      printf ("      First counter           = %5d\n", first);
      if (N_tof_edges > 1) {
	printf ("      Edge array #%d\n", edge_indx);
      }
      printf ("      Bytes per bin           = %5d\n", bytes_per_bin);

      if (first >= MAX_TOF_CNTR) {
	printf ("do_SQHM__TOF_alloc: Illegal first counter number: %u.\n",
		    first);
	rply_status_setup (reply, KER__BAD_VALUE, 0,
		    "Bad first counter number");
	free_HM_memory (NULL);
	if (n_extra_bytes != 0) free (my_rqst);
	return ERROR;
      }

      if ((n_cntrs == 0) || ((first+n_cntrs) > MAX_TOF_CNTR)) {
	printf ("do_SQHM__TOF_alloc: Illegal # counters: %u %u.\n",
		    first, n_cntrs);
	rply_status_setup (reply, KER__BAD_VALUE, 0, "Bad # counters");
	free_HM_memory (NULL);
	if (n_extra_bytes != 0) free (my_rqst);
	return ERROR;
      }

      if (edge_indx >= N_tof_edges) {
	printf ("do_SQHM__TOF_alloc: Illegal edge index: %u.\n",
		    edge_indx);
	rply_status_setup (reply, KER__BAD_VALUE, 0, "Bad edge-array index");
	free_HM_memory (NULL);
	if (n_extra_bytes != 0) free (my_rqst);
	return ERROR;
      }
      edge_info_pntr = Tof_edges[edge_indx];
      n_bins = edge_info_pntr->n_bins;
      flag   = edge_info_pntr->flag;

      if (bytes_per_bin == 0) bytes_per_bin = 4;
      if ((bytes_per_bin != 1) &&
	  (bytes_per_bin != 2) &&
	  (bytes_per_bin != 4)) {
	printf ("do_SQHM__TOF_alloc: Illegal bytes per bin: %d.\n",
		    bytes_per_bin);
	rply_status_setup (reply, KER__BAD_VALUE, 0, "Bad bytes-per-bin");
	free_HM_memory (NULL);
	if (n_extra_bytes != 0) free (my_rqst);
	return ERROR;
      }

      Total_bytes += (n_cntrs * n_bins * bytes_per_bin);
      if (Hm_mode_UD != 0) Total_bytes += (n_cntrs * n_bins * bytes_per_bin);

      for (j = first; j < (first + n_cntrs); j++) {
	if (Tof_descr[j] != NULL) {
	  printf ("do_SQHM__TOF_alloc: Doubly defined counter: %d.\n",
		    (j));
	  rply_status_setup (reply, KER__BAD_VALUE, 0, "Doubly defined counter");
	  free_HM_memory (NULL);
	  if (n_extra_bytes != 0) free (my_rqst);
	  return ERROR;
	}
	Tof_descr[j] = calloc (1, sizeof (struct tof_histog));
	if (Tof_descr[j] == NULL) {
	  printf ("do_SQHM__TOF_alloc: unable to alloc memory for "
			"histogram structure.\n");
	  rply_status_setup (reply, KER__BAD_ALLOC, 0,
		"Failed to get buffer for Tof_descr structure");
	  free_HM_memory (NULL);
	  if (n_extra_bytes != 0) free (my_rqst);
	  return ERROR;
	}
	Tof_descr[j]->cntr_nmbr	     = first + j;
	Tof_descr[j]->lo_edge	     = edge_info_pntr->edges[0];
	Tof_descr[j]->hi_edge	     = edge_info_pntr->hi_edge;
	Tof_descr[j]->flag	     = flag;
	Tof_descr[j]->bytes_per_bin  = bytes_per_bin;
	Tof_descr[j]->n_bins	     = n_bins;
	Tof_descr[j]->cnt_early_up   = 0;
	Tof_descr[j]->cnt_late_up    = 0;
	Tof_descr[j]->cnt_early_down = 0;
	Tof_descr[j]->cnt_late_down  = 0;
	Tof_descr[j]->bin_edge	     = edge_info_pntr->edges;
	Tof_descr[j]->u.b_bin_data   = NULL;
      }

      if (i == 0) {	    /* Use the first counter bank to define some .. */
	N_hists = n_cntrs;  /* .. globals since we expect there usually to .. */
			    /* .. be only 1 counter bank. */
	N_bins = n_bins;
	Lo_cntr = first;
	Lo_bin = edge_info_pntr->edges[0];
	Hi_bin = edge_info_pntr->hi_edge;
	Compress = ((flag & FLAG__VAR_BIN) == 0) ?
			edge_info_pntr->edges[1] - edge_info_pntr->edges[0] :
			0;
	Bytes_per_bin = bytes_per_bin;
	Cnts_lo = Cnts_hi = 0;
      }	    

      bank_pntr++;	    /* Move to next counter bank */
    }

    if (n_extra_bytes != 0) free (my_rqst);

    i = memFindMax ();	    /* Get size of biggest free memory block */
    if (i > Total_bytes) {
      Hist_base_addr = calloc (Total_bytes, sizeof (char));
    }else {
      Hist_base_addr = NULL;
    }
    if (Hist_base_addr == NULL) {
      printf ("\007do_SQHM__TOF_alloc:\n"
	" Unable to reserve %d bytes of memory!\n"
	" Largest block available = %d.\n", Total_bytes, i);
      rply_status_setup (reply, KER__BAD_ALLOC, i,
	    "Failed to get buffer for histograms");
      reply->sub_status = htonl (i);
      return ERROR;
    }
    nxt_hist_addr = Hist_base_addr;
    for (i = 0; i < MAX_TOF_CNTR; i++) {
      if (Tof_descr[i] != NULL) {
	Tof_descr[i]->u.b_bin_data = nxt_hist_addr;
	j = Tof_descr[i]->n_bins * Tof_descr[i]->bytes_per_bin;
	if (Hm_mode_UD != 0) j = j * 2;
	nxt_hist_addr += j;
      }
    }
    Cnts_lo = Cnts_hi = 0;
    N_events = N_skipped = N_no_coin_tsi = N_coin_tsi = 0;
    Print_hdr = True;

    printf ("    Histogram base address = 0x%08x\n", Hist_base_addr);
    printf ("    SQHM__TOF mode configured.\n");
    return OK;
  }
/*
**--------------------------------------------------------------------------*/
  int do_SQHM__PSD_alloc (
/*    ==================
*/			int			 skt,
			struct req_buff_struct  *request,
			struct rply_buff_struct	*reply) {
/*
**		Routine to allocate memory for the SQHM__PSD
**		configure request.
**
**    Definitions:
**	Edge-Array
**		An 'edge-array' is a structure which specifies the lower edge
**		of each bin in the histogram. This is to allow variable width
**		histogram bins.
**	Counter Bank
**		A 'counter bank' is a contiguous group of counters, all of
**		which share the same parameters. In particular, all the counters
**		in the bank have the same number of bins and same bin edges.
*/
    int			     i, j, k, n_bytes_got;
    uint	     n_extra_bytes, n_banks, com2, nchar;
    uint	     first, n_cntrs, edge_indx, bytes_per_bin;
    uint	     n_bins, flag, edge_0, edge_1, bin_span, top_edge;
    uint	     bytes_needed, sizeof_edge_arr;
    uint	     time_span, n_total_bins;
    struct tof_edge_info    *edge_info_pntr;
    struct tof_edge_arr	    *edge_arr_pntr;
    struct tof_bank	    *bank_pntr;
    void		    *nxt_hist_addr;
    struct req_buff_struct  *my_rqst;
    char		    *p_addr, buff[64];

    Total_bytes = 0;

    /*
      switch debugging on by default
      Dbg_lev1 = 0; 
    */

    /*
     read additional configuration information
    */
    n_extra_bytes = ntohl (request->u.cnfg.u.psd.n_extra_bytes);  /* The # of
					** extra bytes needed to be read from
					** the client to complete the configure
					** request.
					*/
 
    if (n_extra_bytes == 0) {
      my_rqst = request;
    }else {
		/*
		** There is extra data to be read. Get buffer space for the
		** extra stuff plus space to copy over what has already been
		** read so that everything is in a contiguous buffer.
		*/
      bytes_needed = n_extra_bytes + sizeof (*request);
      bytes_needed = (bytes_needed + 3) & (~3); /* Round up to multiple of 4 */
      p_addr = calloc (bytes_needed, sizeof (char));
      if (p_addr == NULL) {
	printf ("\007do_SQHM__PSD_alloc:\n"
		" cannot allocate memory for extra config data!\n");
	net_flush (skt, n_extra_bytes);
	rply_status_setup (reply, KER__BAD_ALLOC, 0,
	    "Failed to get buffer for extra config data");
	return ERROR;
      }


      memcpy (p_addr, request, sizeof (*request));  /* Copy in what has already
						    ** been read.
						    */
      my_rqst = (struct req_buff_struct *) p_addr;

      bytes_needed = n_extra_bytes;	    /* And read the rest */
      p_addr = p_addr + sizeof (*request);
      while (bytes_needed > 0) {
        n_bytes_got = recv (skt, p_addr, bytes_needed, 0);
        if (n_bytes_got <= 0) break;
        Rw_bytes_got += n_bytes_got;
        bytes_needed -= n_bytes_got;
        p_addr += n_bytes_got;
      }
      if (n_bytes_got < 0) {
        printf ("\007"
                "%s -- R/W-Socket recv error\n", Tsk_name[0]);
        printf ("%s -- Connection will be closed.\n", Tsk_name[0]);
	rply_status_setup (reply, KER__BAD_VALUE, 0, "recv failed");
	if (n_extra_bytes != 0) free (my_rqst);
	return ERROR;
      }
    }

    printf ("\n    Histogramming mode is \"SQHM__PSD\"\n");

    /*
     decode general configuration information
    */
    if (Hm_mode_UD != 0)
      printf ("    Up/Down mode selected\n");
    if (Hm_mode_STROBO != 0)
      printf ("    Stroboscopic mode selected\n");
    printf ("    Bin-overflow action is ");
    switch (Hm_mode_BO) {
     case SQHM__BO_IGN:	 printf ("\"Ignore\"\n"); break;
     case SQHM__BO_SMAX: printf ("\"Stop-at-Max\"\n"); break;
     case SQHM__BO_CNT:	 printf ("\"Count\"\n"); break;
     default:		 printf ("\"Undefined\"\n");
    }

    N_tof_edges = ntohs (my_rqst->u.cnfg.u.psd.n_edges);    /* The # of
					** different 'edge-arrays' which are
					** to be defined.
					*/
    printf ("    Number of Edge Arrays   = %2d\n", N_tof_edges);
    if (N_tof_edges > MAX_TOF_EDGE) {
      printf ("do_SQHM__PSD_alloc: Illegal number of edge-arrays: %u.\n",
		    N_tof_edges);
      rply_status_setup (reply, KER__BAD_VALUE, 0, "Too many edge-arrays");
      if (n_extra_bytes != 0) free (my_rqst);
      return ERROR;
    }

    n_banks = ntohs (my_rqst->u.cnfg.u.psd.n_banks);	    /* The # of
					** 'banks' of counters which are
					** to be defined.
					*/
    printf ("    Number of Counter Banks = %2d\n", n_banks);
    if (n_banks == 0) {
      rply_status_setup (reply, KER__BAD_VALUE, 0, "Illegal n_banks");
      printf ("do_SQHM__PSD_alloc: Illegal number of banks: %u.\n",
		    n_banks);
      if (n_extra_bytes != 0) free (my_rqst);
      return ERROR;
    }

    psdXOffset = ntohs(my_rqst->u.cnfg.u.psd.xOffset);
    psdXFactor = ntohs(my_rqst->u.cnfg.u.psd.xFactor);
    printf("\tX-Offset = %4d, X-Factor = %4d\n",
           psdXOffset, psdXFactor);

    psdYOffset = ntohs(my_rqst->u.cnfg.u.psd.yOffset);
    psdYFactor = ntohs(my_rqst->u.cnfg.u.psd.yFactor);
    printf("\tY-Offset = %4d, Y-Factor = %4d\n",
           psdYOffset, psdYFactor);

    psdFlashCount = 0;
    psdHitCount = 0;

    psdXSize = ntohs(my_rqst->u.cnfg.u.psd.xSize);
    psdYSize = ntohs(my_rqst->u.cnfg.u.psd.ySize);
    printf("\txSize = %4d, ySize = %4d\n", 
           psdXSize, psdYSize);
    N_hists = psdXSize*psdYSize+MAX_PSD_ED;

    Tof_dts_soll = ntohl (my_rqst->u.cnfg.u.psd.preset_delay); /* The
					** required "Delay-Time-to-Start" */
    if ((Tof_dts_soll & (~LWL_TSI_DTS_MSK)) != 0) {
      rply_status_setup (reply, KER__BAD_VALUE, 0, "Bad Delay-Time-to-Start");
      printf ("do_SQHM__PSD_alloc: Delay-Time-to-Start illegal: 0x%x\n",
				    Tof_dts_soll);
      if (n_extra_bytes != 0) free (my_rqst);
      return ERROR;
    }
    /*
     send DTS to MDI through COM2 port. But only if we have more then one
     time channel. Else we are operating in non-TOF mode.
    */
    if(N_tof_edges > 1) {
       com2 = open ("/tyCo/1", O_RDWR, 0);	   
       if (com2 == ERROR) {
	 rply_status_setup (reply, KER__BAD_VALUE, 0, "COM2 open failed");
	 printf ("do_SQHM__PSD_alloc: error opening COM2 port. "
		   "Delay-Time-to-Start not set.\n");
	 if (n_extra_bytes != 0) free (my_rqst);
	 return ERROR;
       }else {
	 ioctl (com2, FIOBAUDRATE, 9600);
	 write (com2, "\r", 1);
	 write (com2, "RMT 1\r", 6);
	 nchar = sprintf (buff, "DT %d\r", Tof_dts_soll);
	 if (write (com2, buff, nchar) != nchar) {
	   rply_status_setup (reply, KER__BAD_VALUE, 0,
			       "Setting D-T-to-S failed");
	   printf ("do_SQHM__PSD_alloc: error setting Delay-Time-to-Start.\n");
	   if (n_extra_bytes != 0) free (my_rqst);
	   close (com2);
	   return ERROR;
	 }else {
	   printf ("    Delay-Time-to-Start     = %d\n", Tof_dts_soll);
	 }
	 close (com2);
       }
    }
		/*
		** Loop over all the edge arrays
		*/
    edge_arr_pntr = &my_rqst->u.cnfg.u.psd.edge_0;
    for (i = 0; i < N_tof_edges; i++) {
      n_bins = ntohl (edge_arr_pntr->n_bins);
      N_bins = n_bins;
      flag   = ntohl (edge_arr_pntr->flag);
      edge_0 = ntohl (edge_arr_pntr->edges[0]);
      edge_1 = ntohl (edge_arr_pntr->edges[1]);
      printf ("    Edge Array %d:\n", i);
      printf ("      Number of bins          = %5d\n", n_bins);
      printf ("      Flag                    = %5d\n", flag);
      printf ("      Lower edge              = %5d\n", edge_0);
      if ((n_bins == 0) || (n_bins > MAX_TOF_NBINS)) {
	printf ("do_SQHM__PSD_alloc: Illegal # bins: %u.\n",
		    n_bins);
	rply_status_setup (reply, KER__BAD_VALUE, 0, "Bad number of bins");
	free_HM_memory (NULL);
	if (n_extra_bytes != 0) free (my_rqst);
	return ERROR;
      }
      if ((edge_0 & (~LWL_HDR_TS_MASK)) != 0) {
	printf ("do_SQHM__PSD_alloc: histog start is > 20 bits: %u\n",
		edge_0);
	rply_status_setup (reply, KER__BAD_VALUE, 0,
		"Bin edges overflow 20 bits");
	free_HM_memory (NULL);
	if (n_extra_bytes != 0) free (my_rqst);
	return ERROR;
      }
      if ((edge_1 & (~LWL_HDR_TS_MASK)) != 0) {
	printf ("do_SQHM__PSD_alloc: first bin is > 20 bits: %u\n",
		edge_1);
	rply_status_setup (reply, KER__BAD_VALUE, 0,
		"First bin overflows 20 bits");
	free_HM_memory (NULL);
	if (n_extra_bytes != 0) free (my_rqst);
	return ERROR;
      }
      bytes_needed = OffsetOf (struct tof_edge_info, edges) +
				    ((n_bins + 1) * sizeof (int));
      Tof_edges[i] = calloc (bytes_needed, sizeof (char)); /* Allocate space for
						      ** edge-array structure */
      if (Tof_edges[i] == NULL) {
	printf ("do_SQHM__PSD_alloc: unable to alloc memory for edge array.\n");
	rply_status_setup (reply, KER__BAD_ALLOC, 0,
	    "Failed to get memory for edge-array");
	free_HM_memory (NULL);
	if (n_extra_bytes != 0) free (my_rqst);
	return ERROR;
      }
      Tof_edges[i]->n_bins = n_bins;
      Tof_edges[i]->flag = flag;
      if ((flag & FLAG__VAR_BIN) == 0) {	    /* Fixed width bins? */
	printf ("      Bin width               = %5d\n", (edge_1 - edge_0));
        if (edge_0 >= edge_1) {			    /* Yes. Check bin width */
	  printf ("do_SQHM__PSD_alloc: bin width is zero or negative!\n");
	  rply_status_setup (reply, KER__BAD_VALUE, 0, "illegal bin width");
	  free_HM_memory (NULL);
	  if (n_extra_bytes != 0) free (my_rqst);
	  return ERROR;
	}
	bin_span = edge_1 - edge_0;
	Tof_edges[i]->bin_span = bin_span;
	top_edge = edge_0 + (n_bins * bin_span) - 1;
	if ((top_edge & (~LWL_HDR_TS_MASK)) != 0) {
	  printf ("do_SQHM__PSD_alloc: histog last bin is > 20 bits: %u\n",
		top_edge);
	  rply_status_setup (reply, KER__BAD_VALUE, 0,
		"Last bin overflows 20 bits");
	  free_HM_memory (NULL);
	  if (n_extra_bytes != 0) free (my_rqst);
	  return ERROR;
	}
	for (j=0; j <= n_bins; j++) Tof_edges[i]->edges[j] = edge_0+j*bin_span;
	Tof_edges[i]->hi_edge = top_edge;
	sizeof_edge_arr = OffsetOf (struct tof_edge_arr, edges) +
					    2 * sizeof (uint);
      }else {
					/* Variable width bins */
	bin_span = edge_1 - edge_0;	/* Note: even though the edges are
					** defined as variable, they may, in
					** fact, all be the same width. Check
					** for this so that we can make a brief
					** report rather than listing all
					** the bin edges.
					*/
	Tof_edges[i]->bin_span = 0;
	Tof_edges[i]->edges[0] = edge_0;
	for (j = 1; j <= n_bins; j++) {
	  Tof_edges[i]->edges[j] = ntohl (edge_arr_pntr->edges[j]);
	  if ((Tof_edges[i]->edges[j] & (~LWL_HDR_TS_MASK)) != 0) {
	    printf ("do_SQHM__PSD_alloc: histog bin is > 20 bits: %d %u\n",
		j, Tof_edges[i]->edges[j]);
	    rply_status_setup (reply, KER__BAD_VALUE, 0,
		    "Bin edge overflows 20 bits");
	    free_HM_memory (NULL);
	    if (n_extra_bytes != 0) free (my_rqst);
	    return ERROR;
	  }
	  if (Tof_edges[i]->edges[j-1] >= Tof_edges[i]->edges[j]) {
	    printf ("do_SQHM__PSD_alloc: bin edges are not in sequence: %d %d\n",
		i, j);
	    rply_status_setup (reply, KER__BAD_VALUE, 0,
		    "Bin edges not in sequence");
	    free_HM_memory (NULL);
	    if (n_extra_bytes != 0) free (my_rqst);
	    return ERROR;
	  }
	  if ((Tof_edges[i]->edges[j] - Tof_edges[i]->edges[j-1]) != bin_span)
	    bin_span = 0;   /* Set bin_span to zero if bin widths really are
			    ** variable */
	}
	if (bin_span != 0) {
	  printf ("      Variable width bins but width of all bins = %d\n",
				bin_span);
	}else {
	  printf ("      Variable width bins. Upper bin edges are:\n");
	  for (j = 1; j <= n_bins; j += 10) {
	    for (k = 0; ((k + j) <= n_bins) && (k < 10); k++)
	      printf ("%7d", Tof_edges[i]->edges[j+k]);
	    printf ("\n");
	  }
	}
	Tof_edges[i]->hi_edge = Tof_edges[i]->edges[n_bins] - 1;
	sizeof_edge_arr = OffsetOf (struct tof_edge_arr, edges) +
				((n_bins + 1) * sizeof (uint));
      }
      edge_arr_pntr = (struct tof_edge_arr *) (	   /* Move to next edge array */
	    (char *) edge_arr_pntr + sizeof_edge_arr);
    }
		/*
		** Loop over all the counter banks
		*/
    bank_pntr = (struct tof_bank *) edge_arr_pntr;

    for (i = 0; i < n_banks; i++) {

      first	    = ntohs (bank_pntr->first);
      n_cntrs	    = psdXSize*psdYSize;
      edge_indx     = ntohs (bank_pntr->edge_indx);
      bytes_per_bin = ntohs (bank_pntr->bytes_per_bin);
      Bytes_per_bin = bytes_per_bin; /* update global var */

      printf ("    Counter Bank %d:\n", i);
      printf ("      Number of counters      = %5d\n", n_cntrs);
      printf ("      First counter           = %5d\n", first);
      if (N_tof_edges > 1) {
	printf ("      Edge array #%d\n", edge_indx);
      }
      printf ("      Bytes per bin           = %5d\n", bytes_per_bin);

      if (first >= MAX_PSD_CNTR) {
	printf ("do_SQHM__PSD_alloc: Illegal first counter number: %u.\n",
		    first);
	rply_status_setup (reply, KER__BAD_VALUE, 0,
		    "Bad first counter number");
	free_HM_memory (NULL);
	if (n_extra_bytes != 0) free (my_rqst);
	return ERROR;
      }

      if ((n_cntrs == 0) || ((first+n_cntrs) > MAX_PSD_CNTR)) {
	printf ("do_SQHM__PSD_alloc: Illegal # counters: %u %u.\n",
		    first, n_cntrs);
	rply_status_setup (reply, KER__BAD_VALUE, 0, "Bad # counters");
	free_HM_memory (NULL);
	if (n_extra_bytes != 0) free (my_rqst);
	return ERROR;
      }

      if (edge_indx >= N_tof_edges) {
	printf ("do_SQHM__PSD_alloc: Illegal edge index: %u.\n",
		    edge_indx);
	rply_status_setup (reply, KER__BAD_VALUE, 0, "Bad edge-array index");
	free_HM_memory (NULL);
	if (n_extra_bytes != 0) free (my_rqst);
	return ERROR;
      }
      edge_info_pntr = Tof_edges[edge_indx];
      n_bins = edge_info_pntr->n_bins;
      flag   = edge_info_pntr->flag;

      if (bytes_per_bin == 0) bytes_per_bin = 4;
      if ((bytes_per_bin != 1) &&
	  (bytes_per_bin != 2) &&
	  (bytes_per_bin != 4)) {
	printf ("do_SQHM__PSD_alloc: Illegal bytes per bin: %d.\n",
		    bytes_per_bin);
	rply_status_setup (reply, KER__BAD_VALUE, 0, "Bad bytes-per-bin");
	free_HM_memory (NULL);
	if (n_extra_bytes != 0) free (my_rqst);
	return ERROR;
      }

      /*
       here there is a tricky bit: AMOR has two additional single 
       detectors which need to be binned. They are appended after the
       normal PSD-histogram
      */
      Total_bytes += ((n_cntrs + MAX_PSD_ED) * n_bins * bytes_per_bin);
      if (Hm_mode_UD != 0) 
	Total_bytes += ((n_cntrs + MAX_PSD_ED) * n_bins * bytes_per_bin);

      if (i == 0) {	    /* Use the first counter bank to define some .. */
	N_hists = n_cntrs+MAX_PSD_ED;  
	                   /* .. globals since we expect there usually to .. */
			    /* .. be only 1 counter bank. */
	N_bins = n_bins;
	Lo_cntr = first;
	Lo_bin = edge_info_pntr->edges[0];
	Hi_bin = edge_info_pntr->hi_edge;
	Compress = ((flag & FLAG__VAR_BIN) == 0) ?
			edge_info_pntr->edges[1] - edge_info_pntr->edges[0] :
			0;
	Bytes_per_bin = bytes_per_bin;
	Cnts_lo = Cnts_hi = 0;
      }	    

      bank_pntr++;	    /* Move to next counter bank */
    }

    if (n_extra_bytes != 0) free (my_rqst);

#ifdef MEN_A012
    Hist_base_addr = NULL;
    printf("Calling memPartAlloc with %d, %d\n",
	   (int)sysHighMemPart, Total_bytes);
    Hist_base_addr  = memPartAlloc(sysHighMemPart,Total_bytes);
    Hist_base_MEN_alloc = 1;
#else
    i = memFindMax ();	    /* Get size of biggest free memory block */
    if (i > Total_bytes) {
       Hist_base_addr = calloc (Total_bytes, sizeof (char));
    }else {
      Hist_base_addr = NULL;
    }
#endif
    printf("Successfully allocated %d bytes\n", Total_bytes);
    if (Hist_base_addr == NULL) {
      printf ("\007do_SQHM__PSD_alloc:\n"
	" Unable to reserve %d bytes of memory!\n"
	" Largest block available = %d.\n", Total_bytes, i);
      rply_status_setup (reply, KER__BAD_ALLOC, i,
	    "Failed to get buffer for histograms");
      reply->sub_status = htonl (i);
      return ERROR;
    }

    Cnts_lo = Cnts_hi = 0;
    N_events = N_skipped = N_no_coin_tsi = N_coin_tsi = 0;
    Print_hdr = True;

    printf ("    Histogram base address = 0x%08x\n", Hist_base_addr);
    printf ("    SQHM__PSD mode configured.\n");
    return OK;
  }
/*
**--------------------------------------------------------------------------*/
  int  do_command (
/*     ==========
*/		int			 index,
		int			 skt,
		int			 pkt_size,
		struct req_buff_struct	*rqst,
		struct rply_buff_struct *reply) {
/*
**			Action routine for an SQHM_??? command.
**			The command is processed (including returning a
**			status response message).
*/
    int		status, indx, is, suspendMode, i, j, sub_cmnd;
    int		txt_len, txt_offset, bytes_to_go;
    int		my_first_bin, my_nbins, my_bytes_per_bin, my_hist_no;
    int		my_sub_code, my_x_lo, my_nx, my_y_lo, my_ny, my_xdim, my_h_slct;
    time_t	secs;
    char       *msge, *p_buff, *p_txt;

    reply->bigend = htonl (0x12345678);  /* Put in the "endian" flag. */
    rply_status_setup (reply, KER__SUCCESS, 0, "All OK");

    switch (ntohl (rqst->cmnd)) {

     case SQHM_CLOSE:		     /* Close the connection. */
      return ERROR;		     /* Do nothing. */

     case SQHM_CNCT:		     /* Make a new connection. */
      printf ("%s -- connecting ..", Tsk_name[index]);

      time (&secs);
      secs = secs - Sqhm_start_time;
      reply->u.cnct.up_time = htonl (secs);

      if (Cfgn_done == 0) {		     /* Check we've been configured */
	printf ("\007 but not yet configured!\n");
	is = rply_status_setup_and_send (skt, reply, KER__BAD_STATE, 0,
					    "Not configured");
      }else if (index != 0) {
	printf ("\007 but not issued to SinqHM-master!\n");
	is = rply_status_setup_and_send (skt, reply, KER__BAD_STATE, 0,
					    "Not SinqHM-master");
      }else {
	pkt_size = ntohl (rqst->u.cnct.max_pkt);
	if ((pkt_size < 1024) || (pkt_size > 8192)) pkt_size = 8192;
	pkt_size = pkt_size & ~3;     /* Ensure pkt_size is multiple of 4 */
	indx = make_child (SinqHM_server,
			ntohl (rqst->u.cnct.strt_mode),
			pkt_size);
	if (indx <= 0) {	          /* Child created and ready? */
	  printf ("\n\007%s -- creation of child failed: %d.\n",
					Tsk_name[0], indx);
	  switch (indx) {
	   case -1: msge = "Spawn failed"; break;
	   case -2: msge = "No more ports"; break;
	   case -3: msge = "Time-out of child start-up"; break;
	   case -4: msge = "Child could not get started"; break;
	   default: msge = "Bad status from make_child";
	  }
	  is = rply_status_setup_and_send (skt, reply, KER__BAD_CREATE,
						    indx, msge);
	}else {			    /* Yes, child is up and ready. */
	  reply->u.cnct.port	      = htonl (Port_base + indx);
	  reply->u.cnct.pkt_size      = htonl (pkt_size);
	  reply->u.cnct.hm_mode	      = htonl (Hm_mode_ALL);
	  reply->u.cnct.n_hists	      = htonl (N_hists);
	  reply->u.cnct.num_bins      = htonl (N_bins);
	  reply->u.cnct.bytes_per_bin = htonl (Bytes_per_bin);
	  reply->u.cnct.curr_hist     = htonl (Curr_hist);
	  reply->u.cnct.max_block = htonl (memFindMax ());  /* Max free mem */
	  reply->u.cnct.total_bytes = htonl (Total_bytes);
	  reply->u.cnct.lo_cntr = htonl (Lo_cntr);
	  reply->u.cnct.lo_bin = htonl (Lo_bin);
	  reply->u.cnct.compress = htonl (Compress);
	  printf (" %s started. Packet size = %d.\n", Tsk_name[indx], pkt_size);
	  is = rply_status_send (skt, reply);
	}
      }
      if (is != OK)
	printf ("\n%s -- send of status reply failed.\n", Tsk_name[index]);
      return is;

     case SQHM_CONFIG:
      printf ("%s: Configure ..", Tsk_name[index]);
      if (Cfgn_done) {
	is = rply_status_setup_and_send (skt, reply, KER__BAD_STATE, 0,
					    "Already configured");
	printf ("\007 already configured!\n");
	return ERROR;
      }

      free_HM_memory (NULL);	/* There should be no memory allocated but
				** go and release it anyway!
				*/
      is = chk_config_alloc (skt, rqst, reply);	/* No, check config msg .. */
      if (is != OK) {				/* .. and alloc mem */
	rply_status_send (skt, reply);
	return ERROR;
      }

      suspendMode = (Hm_mode_DEBUG != 0) ? 1 : 0;  /* The mode for Filler */
      is = make_filler (suspendMode);  /* If OK so far, start FILLER. */
      if (is <= 0) {		       /* Was FILLER created OK? */
	rply_status_setup_and_send (skt, reply, KER__BAD_CREATE, is,  /* No */
					    "Filler creation failed");
	printf ("\n%s -- creation of FILLER failed: %d.\n",
				    Tsk_name[index], is);
	free_HM_memory (NULL);
	Cfgn_done = 0;
	return ERROR;
      }else {			    /* Yes, child is up and ready. */
	printf ("    .. configuration complete, %s has been started.\n",
			    Filler_name);
	is = rply_status_send (skt, reply);
	if (is != OK)
	    printf ("\n%s -- send of status reply failed.\n", Tsk_name[index]);
	return is;
      }

     case SQHM_DAQ:		    /* Start or stop data acquisition. */
      printf ("%s: DAQ", Tsk_name[index]);
      if (!Cfgn_done) {			      /* Configured yet? */
	rply_status_setup_and_send (skt, reply, KER__BAD_STATE, 0,  /* No */
					    "Not configured");
	printf ("\007: not configured!\n");
	return ERROR;
      }
      sub_cmnd = ntohl (rqst->u.daq.sub_cmnd);
      if (sub_cmnd == DAQ__CLR)  printf ("/DAQ__CLR:");
      if (sub_cmnd == DAQ__GO)   printf ("/DAQ__GO:");
      if (sub_cmnd == DAQ__INH)  printf ("/DAQ__INH:");
      if (sub_cmnd == DAQ__STOP) printf ("/DAQ__STOP:");
      if (sub_cmnd == DAQ__TST)  printf ("/DAQ__TST:");

      do_daq (reply, index, sub_cmnd);

      if (SinqHM_Dsbl_Mask == 0) {
	printf (" data acquisition is active.\n");
      }else {
	printf (" data acquisition is inhibited.\n");
      }

      is = rply_status_send (skt, reply);
      if (is != OK)
	    printf ("\n%s -- send of status reply failed.\n", Tsk_name[index]);
      return is;

     case SQHM_DBG:			     /* Set debug parameters. */
      Dbg_mask = ntohl (rqst->u.dbg.mask);
      Dbg_lev0 = ((Dbg_mask & 1) != 0) ? 1 : 0;
      Dbg_lev1 = ((Dbg_mask & 2) != 0) ? 1 : 0;
      Dbg_lev2 = ((Dbg_mask & 4) != 0) ? 1 : 0;
      Dbg_lev3 = ((Dbg_mask & 8) != 0) ? 1 : 0;
      printf ("%s: Debug mask = 0x%x\n", Tsk_name[index], Dbg_mask);
      is = rply_status_setup_and_send (skt, reply, KER__SUCCESS, 0, NULL);
      if (is != OK)
	    printf ("\n%s -- send of status reply failed.\n", Tsk_name[index]);
      return is;

     case SQHM_DECONFIG:	    /* Close down FILLER (and any servers)? */
      printf ("%s: De-configure", Tsk_name[index]);
      if (!Cfgn_done) {			    /* Anything to do? */
	printf (" -- already de-configured!\n");
	is = rply_status_setup_and_send (skt, reply, KER__SUCCESS, 0, NULL);
      }else if (index != 0) {
	printf ("\007 -- not issued to SinqHM-master!\n");
	is = rply_status_setup_and_send (skt, reply, KER__BAD_STATE, 0,
					    "Not SinqHM-master");
      }else {
	is = close_down_offspring (rqst, reply);
	if (is == KER__SUCCESS) {
	  printf (" done.\n");
	  Cfgn_done = 0;
	  is = rply_status_setup_and_send (skt, reply, KER__SUCCESS, 0, NULL);
	}else {
	  printf ("\n\007Failed! Problem terminating children.\n");
	  is = rply_status_setup_and_send (skt, reply, KER__BAD_STATE, is,
					    "Problem terminating children");
	}
	free_HM_memory (NULL);	    /* Release all reserved memory */
      }
      if (is != OK)
	    printf ("\n%s -- send of status reply failed.\n", Tsk_name[index]);
      return is;

     case SQHM_EXIT:				    /* Rundown */
      printf ("%s: Run-down", Tsk_name[index]);
      if (index != 0) {
	printf ("\007 -- not issued to SinqHM-master!\n");
	is = rply_status_setup_and_send (skt, reply, KER__BAD_STATE, 0,
					    "Not SinqHM-master");
      }else {
	rqst->u.decnfg.sub_code = htonl (1);	    /* Set "harshness" = 1 */
	is = close_down_offspring (rqst, reply);
	if (is == KER__SUCCESS) {
	  printf (" done.\n");
	  Cfgn_done = 0;
	  is = rply_status_setup_and_send (skt, reply, KER__SUCCESS, 0, NULL);
	}else {
	  printf ("\007 -- warning -- problem terminating children.\n");
	  is = rply_status_setup_and_send (skt, reply, KER__BAD_STATE, is,
					    "Problem terminating children");
	}
	free_HM_memory (NULL);	    /* Release all reserved memory */
      }
      if (is != OK)
	    printf ("\n%s -- send of status reply failed.\n", Tsk_name[index]);
      return OK;

     case SQHM_IDENT:		     /* Give info on software identification. */
      txt_len = IDENT_MSGE_LEN;
      txt_offset = 0;
      p_buff = calloc (txt_len, 1);	    /* Get a buffer for text info */
      if (p_buff == NULL) {
	printf ("\n\007%s -- SQHM_IDENT: failed to get buffer!\n",
	    Tsk_name[index]);
	rply_status_setup_and_send (skt, reply, KER__BAD_ALLOC, 0,
	    "Failed to get buffer for composing Ident");
	return ERROR;
      }
      time (&secs);
      secs = secs - Sqhm_start_time;
      reply->u.ident.up_time = htonl (secs);
      reply->u.ident.n_extra_bytes = htonl (IDENT_MSGE_LEN);
      p_txt = p_buff;

      reply->u.ident.offset_vxWorks_ident = htons (txt_offset);
      StrJoin (p_txt, txt_len, vxWorksVersion, "");
      i = strlen (p_txt) + 1;
      txt_offset += i; p_txt += i; txt_len -= i;
      
      reply->u.ident.offset_vxWorks_date = htons (txt_offset);
      StrJoin (p_txt, txt_len, creationDate, "");
      i = strlen (p_txt) + 1;
      txt_offset += i; p_txt += i; txt_len -= i;

      reply->u.ident.offset_instr = htons (txt_offset);
      StrJoin (p_txt, txt_len, Instr_name, "");
      i = strlen (p_txt) + 1;
      txt_offset += i; p_txt += i; txt_len -= i;

      reply->u.ident.offset_def_ident = htons (txt_offset);
      StrJoin (p_txt, txt_len, Def_ident, "");
      i = strlen (p_txt) + 1;
      txt_offset += i; p_txt += i; txt_len -= i;

      reply->u.ident.offset_sinqhm_main_ident = htons (txt_offset);
      StrJoin (p_txt, txt_len, Sqhm_main_ident, "");
      i = strlen (p_txt) + 1;
      txt_offset += i; p_txt += i; txt_len -= i;

      reply->u.ident.offset_sinqhm_main_date = htons (txt_offset);
      StrJoin (p_txt, txt_len, Sqhm_main_date, "");
      i = strlen (p_txt) + 1;
      txt_offset += i; p_txt += i; txt_len -= i;

      reply->u.ident.offset_sinqhm_server_ident = htons (txt_offset);
      StrJoin (p_txt, txt_len, Sqhm_serv_ident, "");
      i = strlen (p_txt) + 1;
      txt_offset += i; p_txt += i; txt_len -= i;

      reply->u.ident.offset_sinqhm_server_date = htons (txt_offset);
      StrJoin (p_txt, txt_len, Sqhm_serv_date, "");
      i = strlen (p_txt) + 1;
      txt_offset += i; p_txt += i; txt_len -= i;

      reply->u.ident.offset_sinqhm_filler_ident = htons (txt_offset);
      StrJoin (p_txt, txt_len, Sqhm_fill_ident, "");
      i = strlen (p_txt) + 1;
      txt_offset += i; p_txt += i; txt_len -= i;

      reply->u.ident.offset_sinqhm_filler_date = htons (txt_offset);
      StrJoin (p_txt, txt_len, Sqhm_fill_date, "");
      i = strlen (p_txt) + 1;
      txt_offset += i; p_txt += i; txt_len -= i;

      reply->u.ident.offset_sinqhm_routines_ident = htons (txt_offset);
      StrJoin (p_txt, txt_len, Sqhm_rout_ident, "");
      i = strlen (p_txt) + 1;
      txt_offset += i; p_txt += i; txt_len -= i;

      reply->u.ident.offset_sinqhm_routines_date = htons (txt_offset);
      StrJoin (p_txt, txt_len, Sqhm_rout_date, "");
      i = strlen (p_txt) + 1;
      txt_offset += i; p_txt += i; txt_len -= i;

      is = rply_status_send (skt, reply);
		    /*
		    ** Now send the data
		    */
      p_txt = p_buff;
      bytes_to_go = IDENT_MSGE_LEN;
      while (bytes_to_go > 0) {
	i = (bytes_to_go > pkt_size) ? pkt_size : bytes_to_go;
	is = send (skt, p_txt, i, 0);
	if (is > 0) {
	  Rw_bytes_put += is;
	  bytes_to_go  -= is;
	  p_txt        += is;
	}else {
	  free (p_buff);
	  printf ("\n\007%s -- SQHM_IDENT: failed to send extra data!\n",
				    Tsk_name[index]);
	  return ERROR;		    /* Fatal error on send */
	}
      }
      free (p_buff);
      return OK;

     case SQHM_PROJECT:	    /* Read a projected "rectangle" of the HM. */
      if (Cfgn_done == 0) {		     /* Check we've been configured */
	printf ("\007%s -- projecting but not yet configured!\n", Tsk_name[index]);
	is = rply_status_setup_and_send (skt, reply, KER__BAD_STATE, 0,
					    "Not configured");
	return ERROR;
      }else {
	if (Dbg_lev0) printf ("%s -- projecting ..", Tsk_name[index]);
	my_sub_code = ntohl (rqst->u.project.sub_code);
	my_x_lo     = ntohl (rqst->u.project.x_lo);
	my_nx       = ntohl (rqst->u.project.nx);
	my_y_lo     = ntohl (rqst->u.project.y_lo);
	my_ny       = ntohl (rqst->u.project.ny);
	my_xdim     = ntohl (rqst->u.project.xdim);
	my_h_slct   = ntohl (rqst->u.project.nhist);
	is = do_project (index, reply, skt, pkt_size,
	       my_sub_code, my_x_lo, my_nx, my_y_lo, my_ny, my_xdim, my_h_slct);
	if (is != OK) {
	  printf ("\n%s -- SQHM_PROJECT fatal error sending status reply or "
			"histo data.\n", Tsk_name[index]);
	}else {
	  if (Dbg_lev0) printf (" done.\n");
	}
	return is;
      }

     case SQHM_READ:	/* Read a section of the HM. */
      if (Cfgn_done == 0) {		     /* Check we've been configured */
	printf ("\007%s -- reading but not yet configured!\n", Tsk_name[index]);
	is = rply_status_setup_and_send (skt, reply, KER__BAD_STATE, 0,
					    "Not configured");
	return ERROR;
      }else {
	if (Dbg_lev0) printf ("%s -- reading ..", Tsk_name[index]);
	my_hist_no   = ntohl (rqst->u.read.hist_no);
	my_first_bin = ntohl (rqst->u.read.first_bin);
	my_nbins     = ntohl (rqst->u.read.n_bins);
	is = do_read (index, reply, skt, pkt_size,
		    my_nbins, my_first_bin, my_hist_no);
	if (is != OK) {
	  printf ("\n%s -- SQHM_READ fatal error sending status reply or "
			"histo data.\n", Tsk_name[index]);
	}else {
	  if (Dbg_lev0) printf (" done.\n");
	}
	return is;
      }

     case SQHM_SELECT:	    /* SQHM_SELECT still needs to be programmed. */
      printf ("%s: Select ..\n", Tsk_name[index]);
      is = rply_status_setup_and_send (skt,
		    reply, KER__BAD_VALUE, 0, "Not yet available!");
      if (is != OK) {
	printf ("\n%s -- send of status reply failed.\n", Tsk_name[index]);
      }else {
	printf (" has been ignored but acknowledged.\n");
      }
      return is;

     case SQHM_STATUS:			/* Get-Status request */
      if (Dbg_lev0) printf ("%s: Status ..", Tsk_name[index]);
		    /*
		    ** Build up info
		    */
      reply->status = htonl (KER__SUCCESS);	/* Indicate success */
      strcpy ((char *) &reply->sub_status,	/* Set up the Ident */
			    SINQHM_DEF_ID);	/* This does not need htonl! */
      reply->u.status.max_n_hists  = htonl (N_HISTS_MAX);
      reply->u.status.max_num_bins = htonl (N_BINS_MAX + 1);
      reply->u.status.max_srvrs    = MAX_CLIENTS;
      reply->u.status.max_block    = htonl (memFindMax ());  /* Max free mem */
      if (Cfgn_done == 0) {
	reply->u.status.cfg_state     = 0;
	reply->u.status.n_hists	      = 0;
	reply->u.status.curr_hist     = 0;
	reply->u.status.num_bins      = 0;
	reply->u.status.act_srvrs     = 0;
	reply->u.status.bytes_per_bin = 0;
	reply->u.status.compress      = 0;
	reply->u.status.daq_now	      = 0;
	reply->u.status.filler_mask   = 0;
	reply->u.status.tsi_status    = 0;
	reply->u.status.flags	      = 0;
	reply->u.status.dt_or_dts.both = 0;
	reply->u.status.num_bad_events = 0;
      }else {
	reply->u.status.cfg_state    = htonl (Hm_mode_ALL);
	reply->u.status.n_hists	     = htons (N_hists);
	reply->u.status.curr_hist    = htons (Curr_hist);
	reply->u.status.num_bins     = htonl (N_bins);

	for (j = 0, i = MAX_CLIENTS; i > 0; i--) if (Child_pid[i] != 0) j++;
	reply->u.status.act_srvrs  = j;

	reply->u.status.bytes_per_bin = Bytes_per_bin;
	reply->u.status.compress      = Compress;
	reply->u.status.daq_now	      = htons (SinqHM_Dsbl_Mask);
	reply->u.status.filler_mask   = htons (Server_masks[0]);
	reply->u.status.tsi_status    = htons (Tsi_status_info);
	reply->u.status.flags	      = htons (Tsi_flags);
	reply->u.status.dt_or_dts.both = htonl (Dt_or_dts.both);
	reply->u.status.num_bad_events = htonl (Num_bad_events);
      }
      time (&secs);
      secs = secs - Sqhm_start_time;
      reply->u.status.up_time = htonl (secs);

      is = rply_status_send (skt, reply);
      if (Dbg_lev0) {
	if (is != OK) {
	  printf ("\n%s -- send of status reply failed.\n", Tsk_name[index]);
	}else {
	  printf (" has been sent.\n");
	}
      }
      return is;

     case SQHM_WRITE:	/* Write a section of the HM.
			**
			** NOTE: always call do_write, even if not configured
			** ====  since network data has always to be read.
			*/
      printf ("%s: writing ..", Tsk_name[index]);
      my_hist_no       = ntohl (rqst->u.write.hist_no);
      my_first_bin     = ntohl (rqst->u.write.first_bin);
      my_nbins	       = ntohl (rqst->u.write.n_bins);
      my_bytes_per_bin = ntohl (rqst->u.write.bytes_per_bin);
      is = do_write (index, rqst, reply, skt, pkt_size,
			my_nbins, my_first_bin, my_bytes_per_bin, my_hist_no);
      if (is != OK) {
	printf ("\n%s -- send of status reply failed.\n", Tsk_name[index]);
      }else {
	printf (" done.\n");
      }
      return is;

     case SQHM_ZERO:
      if (Cfgn_done == 0) {		     /* Check we've been configured */
	printf ("\007%s -- zeroing but not yet configured!\n", Tsk_name[index]);
	is = rply_status_setup_and_send (skt, reply, KER__BAD_STATE, 0,
					    "Not configured");
	return ERROR;
      }else {
        printf ("%s -- zeroing ..", Tsk_name[index]);

	my_hist_no   = ntohl (rqst->u.zero.hist_no);
	my_first_bin = ntohl (rqst->u.zero.first_bin);
        my_nbins     = ntohl (rqst->u.zero.n_bins);

	do_zero (reply, index, my_nbins, my_first_bin, my_hist_no);
	is = rply_status_send (skt, reply);
	if (is != OK) {
	  printf ("\n%s -- send of status reply failed.\n", Tsk_name[index]);
	}else {
	  printf (" done.\n");
	}
	return is;
      }

     default:
      printf ("%s: Unrecognised command received ..\n", Tsk_name[index]);
      is = rply_status_setup_and_send (skt,
		    reply, KER__BAD_VALUE, 0, "Unrecognised command!");
      if (is != OK) {
	printf ("\n%s -- send of status reply failed.\n", Tsk_name[index]);
      }else {
	printf (" it has been acknowledged.\n");
      }
      return is;
    }
    printf ("\007Software error in do_command - switch statement completed!\n");
    return ERROR;
  }
/*
**--------------------------------------------------------------------------*/
  void do_daq (
/*     ======
*/		struct rply_buff_struct *reply,
		int			 index,
		int			 sub_cmnd) {
/*
**			Action routine for SQHM_DAQ command. Send a
**			message to SinqHM-filler to get the command done.
**
**	    To send a message to SinqHM-filler:
**		a) Claim Sem_Filler to gain access to the messageQ to filler;
**		b) Set Filler_flag = 1 to warn SinqHM-filler that a message
**		    is coming. If SinqHM-filler is taking data, this gets it
**		    to break out of its data acquisition loop and wait for
**		    a message. This is to avoid SinqHM-filler having to do
**		    a system call in its innermost daq loop.
**		c) Send the message with msgQSend (remembering to set up the
**		    index in the message correctly so that SinqHM-filler knows
**		    to whom it should send a reply).
**		d) Wait for the reply with msgQReceive.
**		e) Release Sem_Filler.
*/
    int				is, status;
    char			recd[80];
    struct msg_to_filler_struct msg;

    reply->status = htonl (KER__SUCCESS);	     /* Assume success */
    reply->u.daq.daq_was = htons (SinqHM_Dsbl_Mask); /* Return old daq state */
    reply->u.daq.filler_mask = htons (Server_masks[0]);	    /* Filler's mask */
    reply->u.daq.server_mask = htons (Server_masks[index]); /* Server's mask */

    if (sub_cmnd == DAQ__TST) {	    /* DAQ__TST is special - we just give the ..
				    ** .. caller a snapshot without invoking ..
				    ** .. SinqHM-filler. */
      reply->u.daq.daq_now = reply->u.daq.daq_was;
      return;
    }

    if (Dbg_lev0) printf ("\nDO_DAQ_%02d - claiming Sem_Filler\n", index);
    if (Use_sem_tmo) {
      is = (int) semTake (Sem_Filler, Sem_tmo);
    }else {
      is = (int) semTake (Sem_Filler, WAIT_FOREVER);
    }
    if (Dbg_lev0)
      printf ("DO_DAQ_%02d - completed Sem_Filler claim: %d\n", index, is);
    if (is != OK) {
      kill (Parent_pid, SIGUSR1);   /* Inform parent that we are in trouble */
      sprintf (recd, "DO_DAQ_%02d - sem claim err\n", index);
      perror (recd);
      exit (KER__BAD_VALUE);
    }

    Filler_flag = 1;	/* Warn SinqHM-filler that a message is coming */

    msg.u.uu.cmnd  = sub_cmnd;
    msg.u.uu.index = index;
    is = msgQSend (MsgQ_to_filler,
			(char *) &msg,
			sizeof (msg),
			WAIT_FOREVER, MSG_PRI_NORMAL);
    if (is != OK) {
      printf ("do_daq -- error status from msgQSend: %d\n", is);
      exit (KER__BAD_VALUE);
    }
    is = msgQReceive (MsgQ_to_server[index],
			(char *) &msg,
			sizeof (msg),
			WAIT_FOREVER);
    if (is <= 0) {
      printf ("do_daq -- error status from msgQReceive: %d\n", is);
      exit (KER__BAD_VALUE);
    }
				    /* Complete the status response message */
    reply->u.daq.daq_now = htons (msg.u.uu.new_mask);	    /* New daq state */

    if (Dbg_lev0) printf ("DO_DAQ_%02d - releasing sem\n", index);
    is = (int) semGive (Sem_Filler);	/* Release the semaphore */
    if (Dbg_lev0)
      printf ("DO_DAQ_%02d - completed sem release: %d\n", index, is);
    if (is != OK) {
      kill (Parent_pid, SIGUSR1);   /* Inform parent that we are in trouble */
      sprintf (recd, "DO_DAQ_%02d - sem release err\n", index);
      perror (recd);
      exit (KER__BAD_VALUE);
    }
  }
/**
 * --------------------------------------------------------------------------
 * project_frame reads one time frame of a TOF or PSD histogram
 */
static int project_frame(int rw_skt, int pkt_size, int nx){
  struct rply_buff_struct rply;
  uint *buffer = NULL; 
  uchar *bufPtr;
  int i, bytesToSend, nSend, bytesSent;
    register union {
      void	    *base;
      uchar	    *ch;
      usint	    *i2;
      uint	    *i4;
    } hm_pntr;
    long sum;

  printf("PROJECT: Trying to retrieve time frame: %d\n", nx);

  /*
    check arguments
  */
  if(nx < 0 || nx >= N_bins){
    printf("PROJECT FRAME: bad time frame requested: 0 < %d < %d\n",
	   nx,N_bins);
    rply_status_setup (&rply, KER__BAD_VALUE, 0, "Bad argument"); 
    rply_status_send (rw_skt, &rply);
    return OK;
  }
  
  /*
    allocate space
  */
  buffer = (uint *)malloc(N_hists*sizeof(uint));
  if(!buffer){
    printf ("\n\007 -- SQHM_PROJECT-FRAME: failed to get buffer!\n");
      rply_status_setup_and_send (rw_skt, &rply, KER__BAD_ALLOC, 0,
	    "Failed to get buffer for projecting data");
      return OK;
  }
  
  /*
    fill buffer
    FIX: This works only OK with 4 byte HM data. 
  */
  hm_pntr.i4 = Hist_base_addr;
  for(i = 0, sum = 0; i < N_hists;i++){
    buffer[i] = htonl(*(hm_pntr.i4 + (i*N_bins) + nx));
    sum += *(hm_pntr.i4+(i*N_bins) +nx);
  }

  printf("Frame %d contained %d counts \n",nx,sum);
  /*
    build reply and send data
  */
  rply.bigend = 0x12345678;
  rply.u.project.n_bins = htonl(N_hists);
  rply.u.project.bytes_per_bin = htonl(4);
  rply.u.project.cnts_lo = 0;
  rply.u.project.cnts_hi = 0;
  rply_status_setup_and_send (rw_skt, &rply, KER__SUCCESS, 0, NULL);
  bufPtr = (uchar *)buffer;
  bytesToSend = N_hists*4;
  while(bytesToSend > 0){
    nSend = (bytesToSend > pkt_size) ? pkt_size : bytesToSend;
    bytesSent = send(rw_skt,bufPtr,nSend,0);
    if(bytesSent > 0){
      bytesToSend -= bytesSent;
      bufPtr += bytesSent;
    } else {
      return ERROR;
    }
  }
  free(buffer);

  return OK;
}
/*
**--------------------------------------------------------------------------*/
  int do_project (
/*    ==========
*/		int			index,
		struct rply_buff_struct *rply_bf,
		int			rw_skt,
		int			pkt_size,
		uint			sub_code,
		uint			x_lo,
		uint			nx,
		uint			y_lo,
		uint			ny,
		uint			xdim,
		uint			h_slct) {
/*
**                  Read a "rectangular" region of Hist Mem and send it
**		    to the client.
*/
    register int	i, j, k, offs, dataPtr, nTime;
    register uint	my_bin_lo,  my_bin_hi;
    register uint	my_hist_lo, my_hist_hi;

    uint		    my_xdim, eff_nhists;
    int			    my_nbins, is, status, bytes_to_go, nput, nxtbin, nb;
    int			    my_daq_save;
    struct rply_buff_struct dummy_rply;
    uchar		   *buff_pntr, *last_byte;
    uchar		    buff[pkt_size];

    register union {
      void	    *base;
      uchar	    *ch;
      usint	    *i2;
      uint	    *i4;
    } my_pntr, hm_pntr;

    rply_status_setup (rply_bf, KER__BAD_VALUE, 0, "Bad argument"); /* Assume ..
						** .. we shall find a bad arg */
/*--------------------------------------------------------------------
**	    The SQHM_PROJECT command is histogram mode dependent. Switch
**	    accordingly.
*/

    /*    
  printf("\nProject with hm-mode : %d, subcode = %d\n", Hm_mode, sub_code); 
    */


    switch (Hm_mode) {
		/*-----------------------------------------------------------*/
     case SQHM__HM_DIG:	/* SQHM__HM_DIG and SQHM__HRPT are handled the same. */
     case SQHM__HRPT:
      if ((sub_code & PROJECT__1_DIM) == 0) {  /* Check for pseudo-2-dim mode */
				    /* Non-pseudo-2-dim mode. Check the args */
	my_hist_lo = y_lo;
	if (my_hist_lo >= N_hists) {
	  printf ("\n\007%s -- SQHM_PROJECT: Bad y_lo!\n", Tsk_name[index]);
	  is = rply_status_send (rw_skt, rply_bf);
	  return OK;
	}
	my_hist_hi = (ny != 0) ? (y_lo + ny - 1) : (N_hists - 1);
	  if ((my_hist_hi < my_hist_lo) || (my_hist_hi >= N_hists)) {
	  printf ("\n\007%s -- SQHM_PROJECT: Bad ny!\n", Tsk_name[index]);
	  is = rply_status_send (rw_skt, rply_bf);
	  return OK;
	}
	my_bin_lo = x_lo;
	if (my_bin_lo >= N_bins) {
	  printf ("\n\007%s -- SQHM_PROJECT: Bad x_lo!\n", Tsk_name[index]);
	  is = rply_status_send (rw_skt, rply_bf);
	  return OK;
	}
	my_bin_hi = (nx != 0) ? (x_lo + nx - 1) : (N_bins - 1);
	if ((my_bin_hi < my_bin_lo) || (my_bin_hi >= N_bins)) {
	  printf ("\n\007%s -- SQHM_PROJECT: Bad nx!\n", Tsk_name[index]);
	  is = rply_status_send (rw_skt, rply_bf);
	  return OK;
	}
      }else {					/* It is pseudo-2-dim mode */
	if (h_slct >= N_hists) {
	  printf ("\n\007%s -- SQHM_PROJECT: Bad h_slct!\n", Tsk_name[index]);
	  is = rply_status_send (rw_skt, rply_bf);
	  return OK;
	}
	if ((xdim == 0) ||
	    (xdim > N_bins) ||
	    ((N_bins % xdim) != 0)) {
	  printf ("\n\007%s -- SQHM_PROJECT: Bad xdim!\n", Tsk_name[index]);
	  is = rply_status_send (rw_skt, rply_bf);
	  return OK;
	}
	eff_nhists = N_bins/xdim;
	my_hist_lo = y_lo;
	if (my_hist_lo >= eff_nhists) {
	  printf ("\n\007%s -- SQHM_PROJECT: Bad y_lo!\n", Tsk_name[index]);
	  is = rply_status_send (rw_skt, rply_bf);
	  return OK;
	}
	my_hist_hi = (ny != 0) ? (y_lo + ny - 1) : (eff_nhists - 1);
	  if ((my_hist_hi < my_hist_lo) || (my_hist_hi >= eff_nhists)) {
	  printf ("\n\007%s -- SQHM_PROJECT: Bad ny!\n", Tsk_name[index]);
	  is = rply_status_send (rw_skt, rply_bf);
	  return OK;
	}
	my_bin_lo = x_lo;
	if (my_bin_lo >= xdim) {
	  printf ("\n\007%s -- SQHM_PROJECT: Bad x_lo!\n", Tsk_name[index]);
	  is = rply_status_send (rw_skt, rply_bf);
	  return OK;
	}
	my_bin_hi = (nx != 0) ? (x_lo + nx - 1) : (xdim - 1);
	if ((my_bin_hi < my_bin_lo) || (my_bin_hi >= xdim)) {
	  printf ("\n\007%s -- SQHM_PROJECT: Bad nx!\n", Tsk_name[index]);
	  is = rply_status_send (rw_skt, rply_bf);
	  return OK;
	}
      }
		    /*
		    ** All the arguments are OK. Drop through to common code
		    ** for reserving buffer space.
		    */
      break;
		/*-----------------------------------------------------------*/
     case SQHM__TOF:		/* Time-of-Flight Mode */
       if(sub_code == PROJECT__FRAME){
	 return project_frame(rw_skt,pkt_size,nx);
       }

      if ((sub_code & PROJECT__1_DIM) != 0) {
	printf ("\n\007%s -- SQHM_PROJECT: SQHM__TOF+PROJECT__1_DIM not yet "
			"implemented!\n", Tsk_name[index]);
	is = rply_status_setup_and_send (rw_skt, rply_bf, KER__BAD_VALUE, 0,
			    "Not yet implemented");
	return OK;
      }
					    /* Check the arguments */
      my_hist_lo = y_lo;
      if (my_hist_lo >= MAX_TOF_CNTR) {
	printf ("\n\007%s -- SQHM_PROJECT: Bad y_lo!\n", Tsk_name[index]);
	is = rply_status_send (rw_skt, rply_bf);
	return OK;
      }
      my_hist_hi = (ny != 0) ? (y_lo + ny - 1) : (N_hists - 1);
      if ((my_hist_hi < my_hist_lo) || (my_hist_hi >= MAX_TOF_CNTR)) {
	printf ("\n\007%s -- SQHM_PROJECT: Bad ny!\n", Tsk_name[index]);
	is = rply_status_send (rw_skt, rply_bf);
	return OK;
      }
					/*
					** Check that all hists are defined
					*/
      for (i = my_hist_lo; i <= my_hist_hi; i++) {
        if (Tof_descr[i] == NULL) {
	  printf ("\n\007%s -- SQHM_PROJECT: Bad counter range!\n",
					Tsk_name[index]);
	  is = rply_status_send (rw_skt, rply_bf);
	  return OK;
	}
      }
				    /*
				    ** Check that all have the same edge array.
				    */
      for (i = (my_hist_lo + 1); i <= my_hist_hi; i++) {
        if (Tof_descr[i]->bin_edge != Tof_descr[i-1]->bin_edge) {
	  printf ("\n\007%s -- SQHM_PROJECT: Bad histogram edges!\n",
					Tsk_name[index]);
	  is = rply_status_send (rw_skt, rply_bf);
	  return OK;
	}
      }

      my_bin_lo = x_lo;
      if (my_bin_lo >= Tof_descr[my_hist_lo]->n_bins) {
	printf ("\n\007%s -- SQHM_PROJECT: Bad x_lo!\n", Tsk_name[index]);
	is = rply_status_send (rw_skt, rply_bf);
	return OK;
      }
      my_bin_hi = (nx != 0) ?
		    (x_lo + nx - 1) : (Tof_descr[my_hist_lo]->n_bins - 1);
      if ((my_bin_hi < my_bin_lo) ||
	  (my_bin_hi >= Tof_descr[my_hist_lo]->n_bins)) {
	printf ("\n\007%s -- SQHM_PROJECT: Bad nx!\n", Tsk_name[index]);
	is = rply_status_send (rw_skt, rply_bf);
	return OK;
      }
		    /*
		    ** All the arguments are OK. Drop through to common code
		    ** for reserving buffer space.
		    */
      break;
     case SQHM__HM_PSD:
                    /*
		    ** code for TRICS, AMOR PSD
                    */
       if( (sub_code & PROJECT__FRAME) == 0){
	 return project_frame(rw_skt,pkt_size,nx);
       }

       if(sub_code == PROJECT__COLL){
	 my_nbins = psdXSize * psdYSize;	 
         nTime = Tof_edges[0]->n_bins;
       } else if(sub_code == PROJECT__SAMPLE) {
	 if(x_lo < 0 || x_lo + nx > psdXSize){
	  printf ("\n\007%s -- SQHM_PROJECT:Bad x_range lo %d, n %d,max %d\n", 
             Tsk_name[index], x_lo,nx,psdXSize);
 	  is = rply_status_send (rw_skt, rply_bf);
	  return OK;
         }
	 if(y_lo < 0 || y_lo + ny > psdYSize){
	  printf ("\n\007%s -- SQHM_PROJECT:Bad y_range lo %d, n %d,max %d\n", 
             Tsk_name[index], y_lo,ny,psdYSize);
 	  is = rply_status_send (rw_skt, rply_bf);
	  return OK;
         }
         my_nbins = Tof_edges[0]->n_bins;
         nTime = Tof_edges[0]->n_bins;
       } else {
	  printf ("\n\007%s -- SQHM_PROJECT:Bad subcode for PSD\n", 
             Tsk_name[index]);
 	  is = rply_status_send (rw_skt, rply_bf);
	  return OK;
       }
       break;
		/*-----------------------------------------------------------*/
     default:	/* SQHM_PROJECT is not supported in other modes. */
      printf ("\n\007%s -- SQHM_PROJECT: bad Hm_mode!\n", Tsk_name[index]);
      is = rply_status_setup_and_send (rw_skt, rply_bf, KER__BAD_VALUE, 0,
			    "Bad Hm_mode");
      return OK;
    }
/*-------------------------------------------------------------------------
*/		    /*
		    ** All the arguments have been checked. Reserve some space
		    ** for projecting the data. The amount of space that we
		    ** need for the projection depends on whether the
		    ** projection is onto the x-axis or y-axis.
		    */

    if(Hm_mode != SQHM__HM_PSD){
      my_nbins = ((sub_code & PROJECT__ON_Y) == 0) ?
		  (my_bin_hi - my_bin_lo + 1) : (my_hist_hi - my_hist_lo + 1);
    }

    my_pntr.base = calloc (my_nbins, sizeof (uint));
    if (my_pntr.base == NULL) {
      printf ("\n\007%s -- SQHM_PROJECT: failed to get buffer!\n",
				Tsk_name[index]);
      rply_status_setup_and_send (rw_skt, rply_bf, KER__BAD_ALLOC, 0,
	    "Failed to get buffer for projecting data");
      return OK;
    }
		    /*-----------------------------------------------------
		    ** We got some buffer space so inhibit data acqu ...
		    */
    my_daq_save = SinqHM_Dsbl_Mask & Server_masks[index]; /* Remember the ..
							  ** .. state of our ..
							  ** .. inhibit bit */
    if (my_daq_save == 0) do_daq (&dummy_rply, index, DAQ__INH);
		    /*-----------------------------------------------------
		    ** ... then do the projection ...
		    */
    switch (Hm_mode) {

     case SQHM__HM_DIG:	    /* HM_DIG & HRPT Mode */
     case SQHM__HRPT:
      if ((sub_code & PROJECT__1_DIM) == 0) {  /* Check for pseudo-2-dim mode */
				 /* Non-pseudo-2-dim mode. Do a simple proj'n */
	if ((sub_code & PROJECT__ON_Y) == 0) {
	  for (i = my_hist_lo; i <= my_hist_hi; i++) {
	    hm_pntr.base = Hist_base_addr + (i * N_bins * Bytes_per_bin);
	    for (j = my_bin_lo; j <= my_bin_hi; j++) {
	      switch (Bytes_per_bin) {
	       case 1: my_pntr.i4[j-my_bin_lo] += hm_pntr.ch[j]; break;
	       case 2: my_pntr.i4[j-my_bin_lo] += hm_pntr.i2[j]; break;
	       case 4: my_pntr.i4[j-my_bin_lo] += hm_pntr.i4[j];
	      }
	    }
	  }
	}else {
	  for (i = my_hist_lo; i <= my_hist_hi; i++) {
	    hm_pntr.base = Hist_base_addr + (i * N_bins * Bytes_per_bin);
	    offs = i - my_hist_lo;
	    for (j = my_bin_lo; j <= my_bin_hi; j++) {
	      switch (Bytes_per_bin) {
	       case 1: my_pntr.i4[offs] += hm_pntr.ch[j]; break;
	       case 2: my_pntr.i4[offs] += hm_pntr.i2[j]; break;
	       case 4: my_pntr.i4[offs] += hm_pntr.i4[j];
	      }
	    }
	  }
	}
      }else {					/* It is pseudo-2-dim mode */
	hm_pntr.base = Hist_base_addr + (h_slct * N_bins * Bytes_per_bin);
	if ((sub_code & PROJECT__ON_Y) == 0) {
	  for (i = my_hist_lo; i <= my_hist_hi; i++) {
	    for (j = my_bin_lo; j <= my_bin_hi; j++) {
	      switch (Bytes_per_bin) {
	       case 1: my_pntr.i4[j-my_bin_lo] += hm_pntr.ch[xdim*i+j]; break;
	       case 2: my_pntr.i4[j-my_bin_lo] += hm_pntr.i2[xdim*i+j]; break;
	       case 4: my_pntr.i4[j-my_bin_lo] += hm_pntr.i4[xdim*i+j];
	      }
	    }
	  }
	}else {
	  for (i = my_hist_lo; i <= my_hist_hi; i++) {
	    offs = i - my_hist_lo;
	    for (j = my_bin_lo; j <= my_bin_hi; j++) {
	      switch (Bytes_per_bin) {
	       case 1: my_pntr.i4[offs] += hm_pntr.ch[xdim*i+j]; break;
	       case 2: my_pntr.i4[offs] += hm_pntr.i2[xdim*i+j]; break;
	       case 4: my_pntr.i4[offs] += hm_pntr.i4[xdim*i+j];
	      }
	    }
	  }
	}
      }
      break;

     case SQHM__TOF:		/* Time-of-Flight Mode */
      if ((sub_code & PROJECT__ON_Y) == 0) {
	for (i = my_hist_lo; i <= my_hist_hi; i++) {
	  hm_pntr.base = (void *) Tof_descr[i]->u.l_bin_data;
	  for (j = my_bin_lo; j <= my_bin_hi; j++) {
	    switch (Bytes_per_bin) {
	     case 1: my_pntr.i4[j-my_bin_lo] += hm_pntr.ch[j]; break;
	     case 2: my_pntr.i4[j-my_bin_lo] += hm_pntr.i2[j]; break;
	     case 4: my_pntr.i4[j-my_bin_lo] += hm_pntr.i4[j];
	    }
	  }
	}
      }else {
	for (i = my_hist_lo; i <= my_hist_hi; i++) {
	  hm_pntr.base = (void *) Tof_descr[i]->u.l_bin_data;
	  offs = i - my_hist_lo;
	  for (j = my_bin_lo; j <= my_bin_hi; j++) {
	    switch (Bytes_per_bin) {
	     case 1: my_pntr.i4[offs] += hm_pntr.ch[j]; break;
	     case 2: my_pntr.i4[offs] += hm_pntr.i2[j]; break;
	     case 4: my_pntr.i4[offs] += hm_pntr.i4[j];
	    }
	  }
	}
      }
      break;
    case SQHM__HM_PSD:
              /*
	      ** code for TRICS/AMOR PSD
              **
	      */
      if(sub_code == PROJECT__COLL){
        hm_pntr.base = 	Hist_base_addr;
	for(i = 0; i < psdXSize; i++){
	  for(j = 0; j < psdYSize; j++){
	    offs = j * psdXSize + i;
	    dataPtr = j*psdXSize*nTime + i*nTime;
	    my_pntr.i4[offs] = 0;
	    for(k = 0; k < nTime; k++){
	      switch(Bytes_per_bin)
	      {
		case 1:
		  my_pntr.i4[offs] += hm_pntr.ch[dataPtr + k];
		  break;
		case 2:
		  my_pntr.i4[offs] += hm_pntr.i2[dataPtr + k];
		  break;
		case 4:
		  my_pntr.i4[offs] += hm_pntr.i4[dataPtr + k];
		  break;
	      }         
            }
          }
        }
      } else if(sub_code == PROJECT__SAMPLE){
        hm_pntr.base = 	Hist_base_addr;
	for(i = 0; i < nTime; i++){
	  my_pntr.i4[i] = 0;
        }
	for(i = x_lo; i < x_lo + nx; i++){
	  for(j = y_lo; j < y_lo + ny; j++){
	    dataPtr = j*psdXSize*nTime  + i*nTime;
            for(k = 0; k < nTime; k++){
	      my_pntr.i4[k] += hm_pntr.i4[dataPtr +k];
            }   
          }
        }
      }
      break;

     default:
    }
		    /*-----------------------------------------------------
		    ** ... projection complete so let Filler continue and
		    **     send data back to client.
		    */
    if (my_daq_save == 0) do_daq (&dummy_rply, index, DAQ__CLR);

    rply_bf->u.project.n_bins	     = htonl (my_nbins);
    rply_bf->u.project.bytes_per_bin = htonl (sizeof (uint));
    rply_bf->u.project.cnts_lo	     = htonl (Cnts_lo);
    rply_bf->u.project.cnts_hi	     = htonl (Cnts_hi);


    if (rply_bf->bigend != 0x12345678) {    /* If byte swapping needed, ...
					    ** .. then swap them! */
      for (i = 0; i < my_nbins; i++) my_pntr.i4[i] = htonl (my_pntr.i4[i]);
    }


    is = rply_status_setup_and_send (rw_skt, rply_bf, KER__SUCCESS, 0, NULL);

    bytes_to_go = my_nbins * sizeof (uint);
    buff_pntr = (uchar *) my_pntr.base;

    while (bytes_to_go > 0) {
      nput = (bytes_to_go > pkt_size) ? pkt_size : bytes_to_go;
      is = send (rw_skt, buff_pntr, nput, 0);
      if (is > 0) {
	Rw_bytes_put += is;
	bytes_to_go  -= is;
	buff_pntr    += is;
      }else {
	free (my_pntr.base);
	return ERROR;	    /* Fatal error on send */
      }
    }
    free (my_pntr.base);	    /* Release our bit of memory */

    return OK;
  }
/*
**--------------------------------------------------------------------------*/
  int do_read (
/*    =======
*/		int			index,
		struct rply_buff_struct *rply_bf,
		int			rw_skt,
		int			pkt_size,
		uint			nbins,
		uint			first,
		uint			hist_no) {
/*
**                  Read a consecutive region of 'nbins' bins of the Hist Mem
**		    starting with bin 'first' and send it to the client.
*/
    register int	    i, my_fstbin, my_topbin;
    int			    is, my_nbins, status, bytes_to_go, nput, nxtbin, nb;
    int			    my_daq_save;
    struct rply_buff_struct dummy_rply;
    uchar		   *buff_pntr, *last_byte;
    uchar		    buff[pkt_size];

    register union {
      void	    *base;
      uchar	    *ch;
      usint	    *i2;
      uint	    *i4;
    } my_pntr, hm_pntr;

    rply_status_setup (rply_bf, KER__BAD_VALUE, 0, "Bad argument"); /* Assume ..
						** .. we shall find a bad arg */
/*--------------------------------------------------------------------
**	    SQHM__TRANS mode is a special case since we must always suspend
**	    data acq so that we can move FILLER on to the next buffer safely
**	    and take a private copy of the current buffer.
*/
    if (Hm_mode == SQHM__TRANS) {
		/*
		** SQHM__TRANS mode: start by ensuring user's buffer size is OK.
		*/
      nbins = nbins & (~3);	/* Ensure <nbins> is a multiple of 4 */
      if (nbins	< 16) {
	if (Dbg_lev0) printf ("\n");
	printf ("\007%s -- SQHM_READ: bad NBINS!\n", Tsk_name[index]);
	is = rply_status_setup_and_send (rw_skt, rply_bf, KER__BAD_VALUE, 0,
			    "\"n_bins\" < 16");
	return OK;
      }
		/*
		** Ensure data acq is disabled
		*/
      my_daq_save = SinqHM_Dsbl_Mask & Server_masks[index]; /* Remember the ..
					    ** .. state of our inhibit bit */
      if (my_daq_save == 0) do_daq (&dummy_rply, index, DAQ__INH);
		/*
		** Now we can manipulate the buffer "safely". Actually,
		** we should really use semaphore access to the buffer
		** pointers since another SinqHM client could be running
		** in parallel with us. We shall ignore this refinement
		** for the time being!
		*/
      hm_pntr.base = Tran_buff_base;
      last_byte = Next_char;
      selectNewBuffer (last_byte);  /* Move data acquisition to next buffer */

      bytes_to_go = (last_byte - hm_pntr.ch + 4) & (~3);
      my_pntr.base = malloc (bytes_to_go);
      if (buff_pntr == NULL) {
	rply_status_setup_and_send (rw_skt, rply_bf, KER__BAD_ALLOC, 0,
		"Failed to get buffer for data transfer");
	return OK;
      }
      *my_pntr.i4 = htonl (*hm_pntr.i4);
      memcpy (my_pntr.ch+4, hm_pntr.ch+4, bytes_to_go-4);
		    /*
		    ** Copy complete so let Filler continue.
		    */
      if (my_daq_save == 0) do_daq (&dummy_rply, index, DAQ__CLR);

      if (bytes_to_go > nbins) bytes_to_go = nbins;
		    /*
		    ** Everything seems to be OK.
		    ** Tell client he's about to get some data!
		    */
      rply_bf->u.read.first_bin	    = htonl (0);
      rply_bf->u.read.n_bins	    = htonl (bytes_to_go);
      rply_bf->u.read.bytes_per_bin = htonl (1);
      rply_bf->u.read.cnts_lo	    = htonl (0);
      rply_bf->u.read.cnts_hi	    = htonl (0);
      is = rply_status_setup_and_send (rw_skt, rply_bf, KER__SUCCESS, 0, NULL);
		    /*
		    ** Now send the data
		    */
      buff_pntr = my_pntr.ch;
      while (bytes_to_go > 0) {
	nput = (bytes_to_go > pkt_size) ? pkt_size : bytes_to_go;
	is = send (rw_skt, buff_pntr, nput, 0);
	if (is > 0) {
	  Rw_bytes_put += is;
	  bytes_to_go  -= is;
	  buff_pntr    += is;
	}else {
	  free (my_pntr.base);
	  return ERROR;		    /* Fatal error on send */
	}
      }
      free (my_pntr.base);
      return OK;
    }
/*--------------------------------------------------------------------
**	    Non-transparent mode: Start by checking arguments.
*/
    if ((hist_no == -1) && (first == -1) && (nbins == -1)) {
      my_fstbin = 0;
      my_nbins  = N_hists * N_bins;
    }else {
      if (nbins	< 0) {
	if (Dbg_lev0) printf ("\n");
	printf ("\007%s -- SQHM_READ: bad NBINS!\n", Tsk_name[index]);
	is = rply_status_setup_and_send (rw_skt, rply_bf, KER__BAD_VALUE, 0,
			    "\"n_bins\" < 0");
	return OK;
      }
      if (first < 0) {
	if (Dbg_lev0) printf ("\n");
	printf ("\007%s -- SQHM_READ: bad FIRST!\n", Tsk_name[index]);
	is = rply_status_setup_and_send (rw_skt, rply_bf, KER__BAD_VALUE, 0,
			    "\"first_bin\" < 0");
	return OK;
      }
      my_nbins = nbins;
      if (hist_no == -1) {
        my_fstbin = first;
	my_topbin = my_fstbin + my_nbins;
	if ((my_topbin <= 0) || (my_topbin > N_hists * N_bins)) {
	  if (Dbg_lev0) printf ("\n");
	  printf ("\007%s -- SQHM_READ: bad parameters!\n", Tsk_name[index]);
	  is = rply_status_setup_and_send (rw_skt, rply_bf, KER__BAD_VALUE, 0,
			    "Bad parameters");
	  return OK;
	}
      }else {
	if ((hist_no < 0) || (hist_no >= N_hists)) {
	  if (Dbg_lev0) printf ("\n");
	  printf ("\007%s -- SQHM_READ: bad HIST_NO!\n", Tsk_name[index]);
	  is = rply_status_setup_and_send (rw_skt, rply_bf, KER__BAD_VALUE, 0,
			    "Bad \"hist_no\"");
	  return OK;
	}
	my_fstbin = (hist_no * N_bins) + first;
	my_topbin    = my_fstbin + my_nbins;
      }
    }
		    /*
		    ** The args are OK.
		    ** Tell client he's about to get some data!
		    */
    rply_bf->u.read.first_bin	    = htonl (my_fstbin);
    rply_bf->u.read.n_bins	    = htonl (my_nbins);
    rply_bf->u.read.bytes_per_bin   = htonl (Bytes_per_bin);
    rply_bf->u.read.cnts_lo	    = htonl (Cnts_lo);
    rply_bf->u.read.cnts_hi	    = htonl (Cnts_hi);
    is = rply_status_setup_and_send (rw_skt, rply_bf, KER__SUCCESS, 0, NULL);
		    /*
		    ** See if we can reserve some space for making a
		    ** copy of the histogram data.
		    */
    my_pntr.base = NULL;
    i = memFindMax ();	    /* Get size of biggest free memory block */
    if (i > (my_nbins * Bytes_per_bin)) my_pntr.base =
					    malloc (my_nbins * Bytes_per_bin);
		    /*
		    ** If we got a private buffer, inhibit Filler whilst we
		    ** make a quick copy.
		    */
    if (my_pntr.base != NULL) {
		    /*
		    ** We got a private copy
		    */
      my_daq_save = SinqHM_Dsbl_Mask & Server_masks[index]; /* Remember the ..
							   ** .. state of our ..
							   ** .. inhibit bit */
      if (my_daq_save == 0) do_daq (&dummy_rply, index, DAQ__INH);
      memcpy (my_pntr.base,
	      ((char *) Hist_base_addr) + (my_fstbin * Bytes_per_bin),
	      (my_nbins * Bytes_per_bin));
		    /*
		    ** Copy complete so let Filler continue.
		    */
      if (my_daq_save == 0) do_daq (&dummy_rply, index, DAQ__CLR);
      bytes_to_go = my_nbins * Bytes_per_bin;
      buff_pntr = (char *) my_pntr.base;

      while (bytes_to_go > 0) {
	nput = (bytes_to_go > pkt_size) ? pkt_size : bytes_to_go;
	is = send (rw_skt, buff_pntr, nput, 0);
	if (is > 0) {
	  Rw_bytes_put += is;
	  bytes_to_go  -= is;
	  buff_pntr    += is;
	}else {
	  free (my_pntr.base);
	  return ERROR;	    /* Fatal error on send */
	}
      }
      free (my_pntr.base);	    /* Release our bit of memory */
    }else {
    		    /*
		    ** We did not get a private copy. We'll have to copy
		    ** out of the HM area as we send - this would cause a much
		    ** longer inhibit of Filler so we let Filler keep running.
		    ** If the user wants unskewed data, he must inhibit DAQ
		    ** first using DAQ__INH.
		    */
      bytes_to_go = my_nbins * Bytes_per_bin;
      nxtbin = my_fstbin;

      my_pntr.base = buff;
      hm_pntr.base = Hist_base_addr;

      while (bytes_to_go > 0) {
	nput = (bytes_to_go > pkt_size) ? pkt_size : bytes_to_go;
	nb = nput/Bytes_per_bin;
	switch (Bytes_per_bin) {
	 case 1:
	  for (i=0; i<nb; i++) my_pntr.ch[i] = hm_pntr.ch[nxtbin+i];
	  break;
	 case 2:
	  for (i=0; i<nb; i++) my_pntr.i2[i] = htons (hm_pntr.i2[nxtbin+i]);
	  break;
	 case 4:
	  for (i=0; i<nb; i++) my_pntr.i4[i] = htonl (hm_pntr.i4[nxtbin+i]);
	  break;
	}
	buff_pntr = buff;
	while (nput > 0) {
	  is = send (rw_skt, buff_pntr, nput, 0);
	  if (is > 0) {
	    Rw_bytes_put += is;
	    nput	 -= is;
	    bytes_to_go	 -= is;
	    buff_pntr    += is;
	  }else {
	    return ERROR;	/* Fatal error on send */
	  }
	}
	nxtbin += nb;
      }
    }
    return OK;
  }
/*
**--------------------------------------------------------------------------*/
  int do_write (
/*    ========
*/		int			index,
		struct req_buff_struct	*req_bf,
		struct rply_buff_struct *rply_bf,
		int			rw_skt,
		int			pkt_size,
		int			nbins,
		int			first,
		int			bytes_per_bin,
		int			hist_no) {
/*
**                  Preset a consecutive region of the Hist Mem. The number of
**		    bins to preset is 'nbins' starting with bin 'first'. The
**		    data for the bins is read from the client.
*/
    int         i, is, status, bytes_to_come, nget;
    uchar	*b_pntr;
    usint	*w_pntr;
    uint	*l_pntr;

    if ((nbins <= 0) || (bytes_per_bin <= 0)) { /* If nothing to do, do nothing! */
      is = rply_status_setup_and_send (rw_skt, rply_bf, KER__SUCCESS, 0, NULL);
      return is;
    }
	/*
	** Check that we've been configured. If not, flush the data from
	** the client and return an error.
	*/
    if (Cfgn_done == 0) {
      printf ("\007 but not yet configured!\n");
      net_flush (rw_skt, nbins * bytes_per_bin);
      is = rply_status_setup_and_send (rw_skt, rply_bf, KER__BAD_STATE, 0,
				"Not configured!");
      return ERROR;
    }
	/*
	** Check that parameters are valid.
	*/
    if ((bytes_per_bin != Bytes_per_bin) ||
	(first  <  0) ||
	((first+nbins) > (N_hists*N_bins))) {
      printf ("\007 but invalid parameters!\n");
      net_flush (rw_skt, nbins * bytes_per_bin);
      is = rply_status_setup_and_send (rw_skt, rply_bf, KER__BAD_VALUE, 0,
			"Bad \"first_bin\", \"n_bins\" or \"bytes_per_bin\"!");
      return ERROR;
    }

    bytes_to_come = nbins * Bytes_per_bin;
    b_pntr = (char *) Hist_base_addr;
    while (bytes_to_come > 0) {
      nget = (bytes_to_come > pkt_size) ? pkt_size : bytes_to_come;
      is = recv (rw_skt, b_pntr, nget, 0);
      if (is > 0) {
	Rw_bytes_got += is;
	bytes_to_come -= is;
	b_pntr += is;
      }else {
	net_flush (rw_skt, bytes_to_come);
	is = rply_status_setup_and_send (rw_skt, rply_bf, KER__BAD_RECV, is,
			"DO_WRITE: recv error status");
	return ERROR;
      }
    }

    if (0x12345678 != ntohl (0x12345678)) {	/* Swap bytes, if necessary */
      switch (Bytes_per_bin) {
       case 1:
	break;
       case 2:
	w_pntr = (usint *) Hist_base_addr;
	for (i=0; i<nbins; i++) w_pntr[i] = ntohs (w_pntr[i]);
	break;
       case 4:
	l_pntr = (uint *) Hist_base_addr;
	for (i=0; i<nbins; i++) l_pntr[i] = ntohl (l_pntr[i]);
	break;
      }
    }

    lwl_Fifo_Flush ();		/* Ensure the fibre-optic FIFO is empty */

    is = rply_status_setup_and_send (rw_skt, rply_bf, KER__SUCCESS, 0, NULL);
    return is;
  }
/*
**--------------------------------------------------------------------------*/
  void do_zero (
/*     =======
*/		struct rply_buff_struct	*reply,
		int			 index,
		int			 nbins,
		int			 first_bin,
		int			 hist_no) {
/*
**			    Action routine for SQHM_ZERO command.
*/
    register int	    i, my_first_bin, my_topbin;
    int			    is, my_nbins;
    int			    my_daq_save;
    char		    recd[80];
    struct rply_buff_struct dummy_rply;

    register uchar	*b_pntr;
    register usint	*w_pntr;
    register uint	*l_pntr;

    reply->status = KER__BAD_VALUE;	/* Assume we shall find a bad arg */
    if ((hist_no == -1) && (first_bin == -1) && (nbins == -1)) {
      my_first_bin = 0;
      my_nbins	   = N_hists * N_bins;
      my_topbin	   = my_first_bin + my_nbins;
    }else {
      if (nbins	    < 0) return;
      if (first_bin < 0) return;
      if (hist_no == -1) {
        my_first_bin = first_bin;
	my_nbins     = nbins;
	my_topbin    = my_first_bin + my_nbins;
	if ((my_topbin <= 0) || (my_topbin > N_hists * N_bins)) return;
      }else {
	if ((hist_no < 0) || (hist_no >= N_hists)) return;
	my_first_bin = (hist_no * N_bins) + first_bin;
	my_topbin    = my_first_bin + my_nbins;
      }
    }

    reply->status = KER__SUCCESS;	/* The args are OK -- inhibit Filler */

    my_daq_save = SinqHM_Dsbl_Mask & Server_masks[index];  /* Remember the ..
							   ** .. state of our ..
							   ** .. inhibit bit */
    if (my_daq_save == 0) {
      do_daq (&dummy_rply, index, DAQ__INH);
    }

    switch (Bytes_per_bin) {
     case 1:
      b_pntr = (uchar *) Hist_base_addr;
      for (i = my_first_bin; i < my_topbin; i++) b_pntr[i] = 0;
      break;
     case 2:
      w_pntr = (usint *) Hist_base_addr;
      for (i = my_first_bin; i < my_topbin; i++) w_pntr[i] = 0;
      break;
     case 4:
      l_pntr = (uint *) Hist_base_addr;
      for (i = my_first_bin; i < my_topbin; i++) l_pntr[i] = 0;
      break;
    }
    Cnts_lo = Cnts_hi = 0;
    N_events = N_skipped = N_no_coin_tsi = N_coin_tsi = 0;
    Print_hdr = True;

    lwl_Fifo_Flush ();		/* Ensure the fibre-optic FIFO is empty */

    /* 
     clear PSD counts 
    */
    psdHitCount = 0;
    psdFlashCount = 0;

    if (my_daq_save == 0) {
      do_daq (&dummy_rply, index, DAQ__CLR);  /* Remove our inhibit on Filler */
    }
  }
/*
**--------------------------------------------------------------------------*/
  void failInet (char *text) {
/*     ========
**		    Output the given text and exit the process.
*/
    int    my_errno;
    static int showMem = 0;

    if(showMem == 0)
    {
      memShowInit();
      showMem = 1;
    } 

    getErrno (&my_errno);
    printf ("### Internet Error ###\n");
    printf ("                   ### errno = %d.\n", my_errno);
    perror (text);
    memShow(1);
    exit (EXIT_FAILURE);
  }
/*--------------------------------------------------------------------------*/
  void failInet_port (char *text, int port) {
/*     =============
**			    Call to failInet with an extra parameter.
*/
    char    my_buff[132];

    kill (Parent_pid, SIGUSR1);   /* Inform the parent that we are in trouble */

    sprintf (my_buff, text, port);
    failInet (my_buff);
  }
/*
**--------------------------------------------------------------------------*/
  void	free_HM_memory (void *extras) {
/*	===============
**			    Free any memory allocated for TOF histograms
*/
    int	    i;
			/*
			** Release a possible pending buffer
			*/
    free (extras);
			/*
			** Release any allocated histogram buffer
			*/
#ifdef MEN_A012
    if(Hist_base_MEN_alloc == 1){
      memPartFree(sysHighMemPart, Hist_base_addr);
    } else {
      free (Hist_base_addr);
    }
    Hist_base_MEN_alloc = 0;
#else
    free(Hist_base_addr);
#endif
    Hist_base_addr = NULL;
    free (Frame_base_addr);
    Frame_base_addr = NULL;
			/*
			** Release the tof_edge_info structures
			*/
    for (i = 0; i < MAX_TOF_EDGE; i++) {
      free (Tof_edges[i]);
      Tof_edges[i] = NULL;
    }
			/*
			** Release the tof_edge_info structures
			*/
    for (i = 0; i < MAX_TOF_CNTR; i++) {
      free (Tof_descr[i]);
      Tof_descr[i] = NULL;
    }
  }
/*
**--------------------------------------------------------------------------*/
  void	getErrno (int *his_errno) {
/*      ========
*/
    *his_errno = errno;	    /* Make copy of errno   */
    return;
  }
/*
**--------------------------------------------------------------------------*/
  pid_t get_pid () {
/*      =======
*/
    int	    my_tid;

    my_tid = taskIdSelf ();

    return (pid_t) my_tid;
  }
/*
**--------------------------------------------------------------------------*/
  void kill_children () {
/*     =============
**		    Send signals to all our offspring to cause them to terminate
*/
    int	    i, is;

    if (Filler_pid != 0) {
      printf (" .. closing down %s ..", Filler_name);
      is = kill (Filler_pid, SIGINT);
      if (is == ERROR) printf ("Bad status killing FILLER.\n");
    }
    for (i = MAX_CLIENTS; i > 0; i--) {
      if (Child_pid[i] != 0) {
        printf ("\n    Terminating %s ..", Tsk_name[i]);
        is = kill (Child_pid[i], SIGINT);
	if (is == ERROR) printf ("Bad status killing server.\n");
      }
    }
  }
/*
**--------------------------------------------------------------------------*/
  void lwl_Fifo_Flush () {
/*     ==============
**			    Flush out any data in the fibre-optic FIFO.
*/
    register int	    i;
    register uint	   *my_lwl_fifo;
    register union {
      uint     ui4;
      usint    ui2[2];
      uchar    byte[4];
    } lwl_hdr;
    uchar		    my_buff[32];

    my_lwl_fifo = Lwl_fifo;
		/*
		** Note: The following loop runs at a rate of about 570 nsec
		**	 per cycle. Since it takes 2 executions of the loop to
		**	 read 1 packet in Hist Mode and this corresponds to
		**	 6 bytes, this loop should manage to empty the FIFO
		**	 for neutron rates below about 875 kHz. This
		**	 corresponds to a data rate over the fibre-optic link
		**	 of 5.2 Mbyte/sec. Since the link can theoretically
		**	 go faster than this, the code sets a finite limit
		**	 for itself and, if the limit is hit, flushes to the
		**	 end of a packet.
		*/
    for (i = 0; i < 10000000; i++) {
      lwl_hdr.ui4 = *my_lwl_fifo;
      if (lwl_hdr.ui4 == LWL_FIFO_EMPTY) return;
    }
		/*
		** We did not succeed in emptying the FIFO. We are therefore
		** likely to be in trouble!! However, we shall try our best
		** to please by finding a header marker and then flushing to
		** the end of that packet to leave things tidy.
		*/
    for (i = 0; i < 100; i++) {
      lwl_hdr.ui4 = *my_lwl_fifo;
      if (lwl_hdr.ui4 == LWL_FIFO_EMPTY) return;
      if (lwl_hdr.byte[0] != 0) {		    /* Packet header? */
	lwl_Packet_Read (lwl_hdr.ui4, my_buff);	    /* Yes! Flush and .. */
	break;					    /*	    .. quit */
      }
    }
    return;
  }
/*
**--------------------------------------------------------------------------*/
  int  lwl_Packet_Read (uint hdr, uchar *buff) {
/*     ===============
**			    Read current packet from the fibre-optic FIFO.
**			    <hdr> is the packet header and is used to calculate
**			    the amount of reading required. The data (including
**			    the header) is copied into *buff, which must be at
**			    least 22 bytes long.
**		Return value: Number of bytes read (including 4 bytes for hdr).
*/
    register uint   *my_lwl_fifo;
    register union {
      uint	ui4;
      usint	ui2[2];
      uchar	byte[4];
    } lwl_data;

    int		    i, do_print, bytes_read = 4;
    ULONG	    tick_now;
    static ULONG    lPF_tick[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    static int	    lPF_indx = 0;
    static int	    lPF_clockRate = 0;
    static int	    lPF_skipped = 0;

    if (lPF_clockRate == 0) lPF_clockRate = sysClkRateGet (); /* Ticks/second */
    my_lwl_fifo = Lwl_fifo;

    lwl_data.ui4 = hdr;
    buff[0] = lwl_data.byte[0];
    buff[1] = lwl_data.byte[1];
    buff[2] = lwl_data.byte[2];
    buff[3] = lwl_data.byte[3];
	/*
	** Switch according to header type ...
	*/
    switch (hdr & LWL_HDR_TYPE_MASK) {
     case LWL_HM_NC_C9:		    /* Cases with 18 more bytes ..
				    ** .. Also includes	LWL_HM_CO_C9
				    ** ..		LWL_SM_NC_C9
				    ** ..		LWL_SM_CO_C9
				    */
      lwl_data.ui4 = *my_lwl_fifo;	    /* Read remaining bytes */
      buff[bytes_read++] = lwl_data.byte[2];
      buff[bytes_read++] = lwl_data.byte[3];

     case LWL_HM_NC_C8:		    /* Cases with 16 more bytes ..
				    ** .. Also includes	LWL_HM_CO_C8
				    ** ..		LWL_SM_NC_C8
				    ** ..		LWL_SM_CO_C8
				    */
      lwl_data.ui4 = *my_lwl_fifo;	    /* Read remaining bytes */
      buff[bytes_read++] = lwl_data.byte[2];
      buff[bytes_read++] = lwl_data.byte[3];

     case LWL_HM_NC_C7:		    /* Cases with 14 more bytes ..
				    ** .. Also includes	LWL_HM_CO_C7
				    ** ..		LWL_SM_NC_C7
				    ** ..		LWL_SM_CO_C7
				    */
      lwl_data.ui4 = *my_lwl_fifo;	    /* Read remaining bytes */
      buff[bytes_read++] = lwl_data.byte[2];
      buff[bytes_read++] = lwl_data.byte[3];

     case LWL_HM_NC_C6:		    /* Cases with 12 more bytes ..
				    ** .. Also includes	LWL_HM_CO_C6
				    ** ..		LWL_SM_NC_C6
				    ** ..		LWL_SM_CO_C6
				    */
      lwl_data.ui4 = *my_lwl_fifo;	    /* Read remaining bytes */
      buff[bytes_read++] = lwl_data.byte[2];
      buff[bytes_read++] = lwl_data.byte[3];

     case LWL_HM_NC_C5:		    /* Cases with 10 more bytes ..
				    ** .. Also includes	LWL_HM_CO_C5
				    ** ..		LWL_SM_NC_C5
				    ** ..		LWL_SM_CO_C5
				    */
      lwl_data.ui4 = *my_lwl_fifo;	    /* Read remaining bytes */
      buff[bytes_read++] = lwl_data.byte[2];
      buff[bytes_read++] = lwl_data.byte[3];

     case LWL_HM_NC_C4:		    /* Cases with 8 more bytes ..
				    ** .. Also includes	LWL_HM_CO_C4
				    ** ..		LWL_SM_NC_C4
				    ** ..		LWL_SM_CO_C4
				    */
      lwl_data.ui4 = *my_lwl_fifo;	    /* Read remaining bytes */
      buff[bytes_read++] = lwl_data.byte[2];
      buff[bytes_read++] = lwl_data.byte[3];

     case LWL_HM_NC_C3:		    /* Cases with 6 more bytes ..
				    ** .. Also includes	LWL_HM_CO_C3
				    ** ..		LWL_SM_NC_C3
				    ** ..		LWL_SM_CO_C3
				    */
     case LWL_TSI_HM_C:		    /* Other cases with 6 more bytes ..
				    ** .. Also includes	LWL_TSI_SM_C
				    */
      lwl_data.ui4 = *my_lwl_fifo;	    /* Read remaining bytes */
      buff[bytes_read++] = lwl_data.byte[2];
      buff[bytes_read++] = lwl_data.byte[3];

     case LWL_HM_NC_C2:		    /* Cases with 4 more bytes ..
				    ** .. Also includes	LWL_HM_CO_C2
				    ** ..		LWL_SM_NC_C2
				    ** ..		LWL_SM_CO_C2
				    */
      lwl_data.ui4 = *my_lwl_fifo;	    /* Read remaining bytes */
      buff[bytes_read++] = lwl_data.byte[2];
      buff[bytes_read++] = lwl_data.byte[3];

     case LWL_HM_NC_C1:		    /* Cases with 2 more bytes ..
				    ** .. Also includes	LWL_HM_NC_C1
				    */
     case LWL_TR_C1:		    /* Other cases with 2 more bytes */
     case LWL_TR_C2:		    /*  Also includes LWL_TOF_C1 - LWL_TOF_C9 */
     case LWL_TR_C3:
     case LWL_TR_C4:
     case LWL_TR_C5:
     case LWL_TR_C6:
     case LWL_TR_C7:
     case LWL_TR_C8:
     case LWL_TR_C9:

     case LWL_TSI_TR:		    /* Yet more cases with 2 more bytes ..
				    ** .. Also includes	LWL_TSI_HM_NC
				    ** ..		LWL_TSI_TOF
				    ** ..		LWL_TSI_SM_NC
				    */
      lwl_data.ui4 = *my_lwl_fifo;	    /* Read remaining bytes */
      buff[bytes_read++] = lwl_data.byte[2];
      buff[bytes_read++] = lwl_data.byte[3];

     case LWL_FIFO_EMPTY:	    /* FIFO empty - no more bytes */
      break;

     default:
		    /*
		    ** Suppress messages if too many! Record times of last
		    ** 10 messages to see if this one should be printed.
		    */
      tick_now = tickGet ();

      if (lPF_indx == 9) {	    /* Only suppress after 10th message */
        if ((tick_now - lPF_tick[0]) > (5 * 60 * lPF_clockRate)) {
	  do_print = True;	    /* No more than 10 message per 5 mins */
	  for (i = 0; i < 9; i++) lPF_tick[i] = lPF_tick[i+1];
	  lPF_tick[9] = tick_now;
        }else if ((tick_now - lPF_tick[9]) > (60 * lPF_clockRate)) {
	  do_print = True;	    /* No more than 1 message per min */
	  for (i = 0; i < 9; i++) lPF_tick[i] = lPF_tick[i+1];
	  lPF_tick[9] = tick_now;
	}else {
	  do_print = False;	/* Suppress this message */
	  lPF_skipped++;
	}
      }else {
	do_print = True;
        lPF_tick[lPF_indx] = tick_now;
	lPF_indx++;
      }

      if (do_print) {
	printf ("lwl_Packet_Read -- unrecognised packet header 0x%08x\n", hdr);
	if (lPF_skipped > 0) {
	  printf ("lwl_Packet_Read -- %d packets skipped\n", lPF_skipped);
	}
	lPF_skipped = 0;
      }
    }
    return bytes_read;
  }
/*
**--------------------------------------------------------------------------*/
  int make_child (int (* proc) (), int flag, int pkt_size) {
/*    ==========
**		    Find a free child index, create a child process and
**		    invoke procedure proc in the child procedure.
**		    Return value >  0 if child successfully created;
**				 =  0 if this is the child which is executing;
**				 = -1 if error returned by fork;
**				 = -2 if there are too many children already;
**				 = -3 if time-out waiting for child to signal.
**				 = -4 the child indicated a start-up error.
*/
    int	    i, status, tmo;
    pid_t   created_pid;
    char    tsknam[20];
/*
**	    Find a free PID index. Zero is not a permitted value.
*/
    for (i = 1; i <= MAX_CLIENTS; i++) {
      if (Child_pid[i] == 0) break;
    }

    if (i <= MAX_CLIENTS) {			    /* Free index found? */
      Cnt_SIGUSR1 = 0;
      semTake (Sem_Server, NO_WAIT);   /* Ensure that Sem_Server is claimed. ..
				       ** .. Child will release it when ready */
      Child_exit_status[i] = 0;		/* Zero child's status indicator */
      sprintf (tsknam, "hmSrv%02d", i);
      created_pid = taskSpawn (		    /* Make a child */
			tsknam,		    /* Name */
			100,		    /* Priority */
			VX_FP_TASK,	    /* Options - fl.pt. usage assumed */
			20000,		    /* Stack size */
			proc,		    /* The entry point */
			flag,
			i,
			pkt_size, 0,0,0,0,0,0,0);
      if (created_pid == ERROR) {	    /* Error? */
        return -1;			    /* Yes. */
      }else {				    /* Parent */
	Child_pid[i] = created_pid;
	tmo = 1000;		    /* Normally give child 1000 ticks to ..
				    ** .. get going */
	if (flag != 0) {
	  tmo = WAIT_FOREVER;	    /* But in debug mode, wait forever! */
	}
	status = semTake (Sem_Server, tmo); /* Wait for child to get going */
	if (status == ERROR) {			/* Timeout? */
	  taskDelete (Child_pid[i]);		/* Yes, kill child. */
	  Child_pid[i] = 0;
	  return -3;				    /* Return with error. */
	}else {				/* No timeout so child is ready. */
	  if (Child_exit_status[i] == 0) {  /* Did the child have startup a ..
					    ** .. problem */
	    return i;			/* No, so return its index */
	  }else {
	    return -4;			/* Yes, so return error */
	  }
	}
      }
    }
    return -2;	    /* There are already too many children. */
  }
/*
**--------------------------------------------------------------------------*/
  int make_filler (int suspendMode) {
/*    ===========
**		    Create a child process to execute the FILLER procedure.
**		    Return value =  1 if FILLER successfully created;
**				 =  0 if this is FILLER which is executing;
**				 = -1 if error returned by fork;
**				 = -2 if FILLER already running;
**				 = -3 if time-out waiting for FILLER to signal.
*/
    int	    i, status, tmo;
    int	    created_pid;

    if (Filler_pid == 0) {
      Cnt_SIGUSR1 = 0;
      semTake (Sem_Filler, NO_WAIT); /* Ensure that Sem_Filler is claimed. ..
				     ** .. FILLER will release it when set up */

      sprintf (Filler_name, "hmFill%04d", Port_base);
      created_pid = taskSpawn (		 /* Make a child */
			Filler_name,	 /* Name */
			250,		 /* Priority (0=highest, 255=lowest ) */
			VX_FP_TASK,	 /* Options - fl.pt. usage assumed */
			20000,		 /* Stack size */
			SinqHM_filler,	 /* The entry point */
			suspendMode,
			0,0,0,0,0,0,0,0,0);
      if (created_pid == ERROR) {	    /* Error? */
        return -1;			    /* Yes. */
      }else {				    /* No */
        Filler_pid = created_pid;
	tmo = 10000;		    /* Normally give FILLER 1000 ticks to ..
				    ** .. get going */
	if (suspendMode != 0) {
	  tmo = WAIT_FOREVER;	    /* But in debug mode, wait forever! */
	}
	if (Dbg_lev0) printf ("make_filler: waiting for %s to get going ..\n",
				    Filler_name);
	status = semTake (Sem_Filler, tmo); /* Wait for FILLER to get going */
        if (status == ERROR) {			  /* Timeout? */
	  taskDelete (Filler_pid);		  /* Yes, kill FILLER. */
	  Filler_pid = 0;
	  return -3;				  /* Return with error. */
        }else {				/* No timeout so FILLER is ready. */
	  if (Dbg_lev0)
	    printf ("make_filler: %s is up and running.\n", Filler_name);
	  semGive (Sem_Filler);		/* Release Sem_Filler */
          return 1;
        }
      }
    }
    return -2;	    /* FILLER already active. A configure has been repeated. */
  }
/*
**--------------------------------------------------------------------------*/
  int net_flush (int skt, int nbytes) {
/*    =========
*/
    int	    is, bytes_to_come, nget;
    char    buff[1024];

    bytes_to_come = nbytes;
    while (bytes_to_come > 0) {
      nget = (bytes_to_come > sizeof (buff)) ? sizeof (buff) : bytes_to_come;
      is = recv (skt, buff, nget, 0);
      if (is > 0) {
        bytes_to_come -= is;
      }else {
        return ERROR;
      }
    }
    return OK;
  }
/*
**--------------------------------------------------------------------------*/
  void	process_coinc_tsi (
/*	=================
*/			    uint hdr) {

/*		    Routine to process a "coincidence" Timing-Status-Info
**		    Packet. These packets have 10 bytes altogether. The first
**		    4 bytes are in hdr.
*/
    int	    i, j, is;
    register union {
      uint	ui4;
      usint	ui2[2];
      uchar	ui1[4];
	} lwl_data;

    usint	words[3];

    for (j=0; j<3; j++) {		/* Get the remaining 6 bytes */
      for (i=0; i<1000; i++) {
	lwl_data.ui4 = *Lwl_fifo;		/* Get the last 16 bits */
	if (lwl_data.ui4 != LWL_FIFO_EMPTY) {
           break;
        }
	taskDelay (0);			/* But wait if FIFO is slow! */
      }
      if (lwl_data.ui4 == LWL_FIFO_EMPTY) {
	printf ("Time-out getting last 6 bytes of a \"coincidence\" "
		    "TSI packet!\n");
	return;
      }
      words[j] = lwl_data.ui2[1];
    }

    N_coin_tsi++;
    Dt_or_dts.both = hdr & LWL_TSI_DT_MSK;
    Nrl_active = ((hdr & LWL_HDR_NRL_MASK) != 0) ? True : False;
    Daq_active = ((hdr & Lwl_hdr_daq_mask) == Lwl_hdr_daq_soll) ? True : False;
    Tsi_status_info = words[0];

    Tsi_flags = (Nrl_active) ? STATUS_FLAGS__NRL : 0;
    if ((hdr & LWL_HDR_PF_MASK)	   != 0) Tsi_flags |= STATUS_FLAGS__PF;
    if ((hdr & LWL_HDR_SWC_MASK)   != 0) Tsi_flags |= STATUS_FLAGS__SWC;
    if (Daq_active) Tsi_flags |= STATUS_FLAGS__DAQ;
    if ((hdr & LWL_HDR_SYNC0_MASK) != 0) Tsi_flags |= STATUS_FLAGS__SYNC0;
    if ((hdr & LWL_HDR_SYNC1_MASK) != 0) Tsi_flags |= STATUS_FLAGS__SYNC1;
    if ((hdr & LWL_HDR_SYNC2_MASK) != 0) Tsi_flags |= STATUS_FLAGS__SYNC2;
    if ((hdr & LWL_HDR_SYNC3_MASK) != 0) Tsi_flags |= STATUS_FLAGS__SYNC3;
    if ((hdr & LWL_HDR_UD_MASK)	   != 0) Tsi_flags |= STATUS_FLAGS__UD;
    if ((hdr & LWL_HDR_GU_MASK)	   != 0) Tsi_flags |= STATUS_FLAGS__GU;

    lwl_data.ui2[0] = words[1];
    lwl_data.ui2[1] = words[2];
    Num_bad_events = lwl_data.ui4;
  }
/*--------------------------------------------------------------------------
  process_gummi_monitor processes special monitor datagrams as emitted by
  SANS. In gummi mode a sample environment is cycled and data continously
  collected during various steps of the cycle. Naturally, monitor values are
  needed at each step in order to be able to scale the data measured 
  appropriatetly. The monitors are sent in a special datagram consisting of.
  7 packets.  The first is the header and handed down as a function
  call parameter. This header also holds the gummi cycle number to which this
  monitor belongs. The following six packets are the monitor values, separate
  as low byte, high byte.
  
  The monitors are then stored into the last three counters of the first 
  detector (and only) detector bank. The looser is supposed to give three
  additional detectors additional to the normal ones. 

  Look at this again when one of the following conditions is violated:
  - More then one detector bank.

  --------------------------------------------------------------------------*/
void process_gummi_monitor(uint hdr){
  uint gummiBin, readbuf[6], mon[3];
  int i, imon;
  struct tof_histog  *my_tof_descr;

    union {
      uint	ui4;
      usint	ui2[2];
      uchar	ui1[4];
	} lwl_data, monitor;

    /*
      collect those monitor values
    */
    for(imon = 0; imon < 6; imon++){
      readbuf[imon] = LWL_FIFO_EMPTY;
      for (i=0; i<1000; i++) {
	  readbuf[imon] = *Lwl_fifo;		
	  if (readbuf[imon] != LWL_FIFO_EMPTY) break;
	  taskDelay (0);			/* But wait if FIFO is slow! */
      }
      if(readbuf[imon] == LWL_FIFO_EMPTY){
	printf("Timeout reading monitor %d in SANS GUMMI mode\n", imon);
	return;
      }
    }
     
    /*
      put them together again
    */
    for(imon = 0; imon < 3; imon++){
      lwl_data.ui4 = readbuf[imon*2];
      monitor.ui2[0] = lwl_data.ui2[1];
      lwl_data.ui4 = readbuf[imon*2+1];
      monitor.ui2[1] = lwl_data.ui2[1];
      mon[imon] = monitor.ui4;
    }

    gummiBin = hdr & LWL_HDR_TS_MASK;
    if(gummiBin < 0 || gummiBin >= N_bins){
      printf("Invalid gummiBin %d detected \n", gummiBin);
      return;
    }  
    
    if(Dbg_lev1){
    	printf(" Gummi monitors: %d, %d, %d registered for gummi bin %d\n",
    	        mon[0],mon[1],mon[2],gummiBin);
   }

    for(imon = 0; imon < 3; imon++){
      my_tof_descr=Tof_descr[N_hists-3+imon];
      /*
      printf(" detector %d receives %d\n", N_hists-3+imon, mon[imon]);
      */
      switch (my_tof_descr->bytes_per_bin) {
      case 1:
	my_tof_descr->u.b_bin_data[gummiBin] += mon[imon];
        break;
      case 2:
	my_tof_descr->u.w_bin_data[gummiBin] += mon[imon]; 
	break;
      default:
	my_tof_descr->u.l_bin_data[gummiBin] += mon[imon];
	break;
      }
    }
}
/*
**--------------------------------------------------------------------------*/
  void	process_psd_tsi (
/*	=================
*/			    uint hdr) {

/*		    Routine to process a PSD Timing-Status-Info
**		    Packet. These packets have 10 bytes altogether. The first
**		    4 bytes are in hdr.
*/
    int	    i, j, is;
    register union {
      uint	ui4;
      usint	ui2[2];
      uchar	ui1[4];
	} lwl_data;

    usint	words[3];

    for (j=0; j<3; j++) {		/* Get the remaining 6 bytes */
      for (i=0; i<1000; i++) {
	lwl_data.ui4 = *Lwl_fifo;		/* Get the last 16 bits */
	if (lwl_data.ui4 != LWL_FIFO_EMPTY) break;
	taskDelay (0);			/* But wait if FIFO is slow! */
      }
      if (lwl_data.ui4 == LWL_FIFO_EMPTY) {
	printf ("Time-out getting last 6 bytes of a PSD "
		    "TSI packet!\n");
	return;
      }
      words[j] = lwl_data.ui2[1];
    }
/*    printf(" %X %X %X\n", words[0], words[1], words[2]); */

    N_coin_tsi++;
    Dt_or_dts.both = hdr & LWL_TSI_DT_MSK;
    Nrl_active = ((hdr & LWL_HDR_NRL_MASK) != 0) ? True : False;
    Daq_active = ((hdr & Lwl_hdr_daq_mask) == Lwl_hdr_daq_soll) ? True : False;
    Tsi_status_info = words[0];

    Tsi_flags = (Nrl_active) ? STATUS_FLAGS__NRL : 0;
    if ((hdr & LWL_PSD_PWF)	   != 0) Tsi_flags |= STATUS_FLAGS__PF;
    if ((hdr & LWL_HDR_SWC_MASK)   != 0) Tsi_flags |= STATUS_FLAGS__SWC;
    if (Daq_active) Tsi_flags |= STATUS_FLAGS__DAQ;
    if ((hdr & LWL_HDR_SYNC0_MASK) != 0) Tsi_flags |= STATUS_FLAGS__SYNC0;
    if ((hdr & LWL_HDR_SYNC1_MASK) != 0) Tsi_flags |= STATUS_FLAGS__SYNC1;
    if ((hdr & LWL_HDR_SYNC2_MASK) != 0) Tsi_flags |= STATUS_FLAGS__SYNC2;
    if ((hdr & LWL_HDR_SYNC3_MASK) != 0) Tsi_flags |= STATUS_FLAGS__SYNC3;
    /*
    if ((hdr & LWL_HDR_UD_MASK)	   != 0) Tsi_flags |= STATUS_FLAGS__UD;
    if ((hdr & LWL_HDR_GU_MASK)	   != 0) Tsi_flags |= STATUS_FLAGS__GU;
    */
    psdHitCount += words[1];
    psdFlashCount += words[2] & LWL_PSD_FLASH_MASK;    
    if((words[2] & LWL_PSD_XORF) != 0) {
      psdXORF = 1;
    }else {
      psdXORF = 0;
    }
    if((words[2] & LWL_PSD_CONF) != 0) {
      psdConf = 0;
    }else {
      psdConf = 1;
    }

  }
/*
**--------------------------------------------------------------------------*/
  void	process_no_coinc_tsi (
/*	====================
*/			    uint hdr) {

/*		    Routine to process a "normal" Timing-Status-Info Packet.
**		    These packets have 6 bytes altogether. The first 4 bytes are
**		    in hdr.
*/
    int			i;
    register union {
      uint	ui4;
      usint	ui2[2];
      uchar	ui1[4];
	} lwl_data;

    for (i=0; i<1000; i++) {
      lwl_data.ui4 = *Lwl_fifo;		/* Get the last 16 bits */
      if (lwl_data.ui4 != LWL_FIFO_EMPTY) {
         break;
      }
      taskDelay (0);			/* But wait if FIFO is slow! */
    }
    if (lwl_data.ui4 == LWL_FIFO_EMPTY) {
      printf ("Time-out getting last 16 bits of a \"normal\" TSI packet!\n");
      return;
    }
    N_no_coin_tsi++;
    Dt_or_dts.both = hdr & LWL_TSI_DT_MSK;
    Nrl_active = ((hdr & LWL_HDR_NRL_MASK) != 0) ? True : False;
    Daq_active = ((hdr & Lwl_hdr_daq_mask) == Lwl_hdr_daq_soll) ? True : False;
    Tsi_status_info = lwl_data.ui2[1];

    Tsi_flags = (Nrl_active) ? STATUS_FLAGS__NRL : 0;
    if ((hdr & LWL_HDR_PF_MASK)	   != 0) Tsi_flags |= STATUS_FLAGS__PF;
    if ((hdr & LWL_HDR_SWC_MASK)   != 0) Tsi_flags |= STATUS_FLAGS__SWC;
    if (Daq_active) Tsi_flags |= STATUS_FLAGS__DAQ;
    if ((hdr & LWL_HDR_SYNC0_MASK) != 0) Tsi_flags |= STATUS_FLAGS__SYNC0;
    if ((hdr & LWL_HDR_SYNC1_MASK) != 0) Tsi_flags |= STATUS_FLAGS__SYNC1;
    if ((hdr & LWL_HDR_SYNC2_MASK) != 0) Tsi_flags |= STATUS_FLAGS__SYNC2;
    if ((hdr & LWL_HDR_SYNC3_MASK) != 0) Tsi_flags |= STATUS_FLAGS__SYNC3;
    if ((hdr & LWL_HDR_UD_MASK)	   != 0) Tsi_flags |= STATUS_FLAGS__UD;
    if ((hdr & LWL_HDR_GU_MASK)	   != 0) Tsi_flags |= STATUS_FLAGS__GU;
  }
/*
**--------------------------------------------------------------------------*/
  int rply_status_send (
/*    ================
*/		int			skt,
		struct rply_buff_struct	*rply_bf) {

    int	    is;

    is = send (skt, (char *) rply_bf, sizeof (*rply_bf), 0);
    if (is == sizeof (*rply_bf)) {
      Rw_bytes_put += is;
      return OK;
    }else {
      return ERROR;
    }
  }
/*
**--------------------------------------------------------------------------
**	    rply_status_setup:	Routine to set up a Status-response to client.
**				If <msg> is not NULL, <msg> will be copied
**				to the message field of the response. Otherwise,
**				only the status and sub_status fields will be
**				set up.
*/
  void	rply_status_setup (
/*	=================
*/			struct rply_buff_struct	*rply_bf,
			int			status,
			int			sub_status,
			char			*msg) {

    rply_bf->bigend	= htonl (0x12345678);
    rply_bf->status	= htonl (status);
    rply_bf->sub_status = htonl (sub_status);
    if (msg != NULL) {
      if (strlen (msg) < sizeof (rply_bf->u.message)) {
	strcpy (rply_bf->u.message, msg);
      }else {
	strcpy (rply_bf->u.message, "Message overflow!");
      }
    }
  }
/*
**--------------------------------------------------------------------------*/
  int rply_status_setup_and_send (
/*    ==========================
*/		int			skt,
		struct rply_buff_struct	*rply_bf,
		int			status,
		int			sub_status,
		char			*msg) {

    int	    is;

    rply_status_setup (rply_bf, status, sub_status, msg);
    is = rply_status_send (skt, rply_bf);

    return is;
  }
/*
**--------------------------------------------------------------------------*/
  uchar	*selectNewBuffer (uchar *nxt) {
/*	 ===============
**
**                  Move to new buffer in SQHM_TRANS mode.
**
**	    *nxt = next free byte in current buffer.
**	    Return value is first free byte in next buffer.
*/
    int	    i;
		/*
		** Close off the current buffer
		*/
    *nxt = 0;
    i = nxt - Tran_buff_base;	  /* Get number of bytes used in this buffer */
    memcpy (Tran_buff_base, &i, sizeof (i));	/* Put at front of buffer */
		/*
		** Move to next buffer
		*/
    Curr_hist++;
    if (Curr_hist > N_hists) Curr_hist = 0;
    Tran_buff_base = ((uchar *) Hist_base_addr) + (Curr_hist * N_bins);
    Next_char = Tran_buff_base + 4;
    return Next_char;
  }
/*
**--------------------------------------------------------------------------*/
  void setupLevelGenerator (int use_level_gen, char *base_addr) {
/*     ===================
**                  Set up VME access to a VMIO10 module at address 0x1900
**		    to be used for generating timing signals.
**
**		    If (use_level_gen == 0), the level generator will not
**			    be used. The VME address will point to a memory
**			    location.
*/
    STATUS	status;
    char	aux;
    void	(* sig_status) (int);

    if (use_level_gen == 0) {
      VmioBase = Vmio_Dummy;
      printf ("Timing signal generation via VMIO10 module disabled.\n");
      return;
    }
    if (base_addr == NULL) {
      status = sysBusToLocalAdrs (VME_AM_USR_SHORT_IO, (char *) VMIO_BASE_ADDR,
					(char **) &VmioBase);
    }else {
      status = sysBusToLocalAdrs (VME_AM_USR_SHORT_IO, base_addr,
					(char **) &VmioBase);
    }
    if (status != OK) {
      printf ("Error status from sysBusToLocalAdrs -- VMIO10 disabled.\n");
      VmioBase = Vmio_Dummy;
      return;
    }
	    /*
	    ** The "setjmp" and "signal" stuff it to trap a possible machine
	    ** check if the VMIO10 module is absent. This is rather obscure
	    ** code -- sorry about that but blame Unix thinking, not me, if
	    ** you don't like it!
	    */
    sig_status = signal (SIGBUS, catch_machine_check);
    if (setjmp (Vmio_trap_env) != 0) {
		    /*
		    ** We get to this code only if the VMIO10 module is absent.
		    */
      printf ("\007Bus error detected on trying to access the VMIO10 module!\n"
	      "Timing signals will not be generated via the VMIO10.\n");
      VmioBase = Vmio_Dummy;
      return;
    }
	/*
	** Now set up Ports A & B of the VMIO10, i.e. the first Z8536-CIO.
	** If the module is absent, the first access will trap and exit via
	** the "setjmp" condition block above.
	**
	** Start with a "reset" ..
	*/
    aux = VmioBase[VMIO_AB_CNTL];   /* Read Cntrl to ensure not State 1 */
    VmioBase[VMIO_AB_CNTL] = 0x00;  /* Write zero to Cntrl to ensure not in ..
				    ** .. "Reset State" */
    aux = VmioBase[VMIO_AB_CNTL];   /* Read Cntrl to ensure State 0 */
    VmioBase[VMIO_AB_CNTL] = Z8536_MICR;    /* Select the Mstr Int Ctrl Reg */
    VmioBase[VMIO_AB_CNTL] = 0x01;	    /* Set the reset bit */
    VmioBase[VMIO_AB_CNTL] = 0x00;	    /* Then clr it to complete reset */
	/*
	** Now set polarity and direction ..
	*/
    VmioBase[VMIO_AB_CNTL] = Z8536_DPPR_A;  /* Port A Data Path Pol */
    VmioBase[VMIO_AB_CNTL] = 0x00;	    /* Non-inverting */
    VmioBase[VMIO_AB_CNTL] = Z8536_DPPR_B;  /* Port B Data Path Pol */
    VmioBase[VMIO_AB_CNTL] = 0x00;	    /* Non-inverting */

    VmioBase[VMIO_AB_CNTL] = Z8536_DDR_A;   /* Port A Data Direction */
    VmioBase[VMIO_AB_CNTL] = 0x00;	    /* All bits output */
    VmioBase[VMIO_AB_CNTL] = Z8536_DDR_B;   /* Port B Data Direction */
    VmioBase[VMIO_AB_CNTL] = 0x00;	    /* All bits output */
	/*
	** Now enable Ports A & B ..
	*/
    VmioBase[VMIO_AB_CNTL] = Z8536_MCCR;    /* Select Master Config Ctrl Reg */
    VmioBase[VMIO_AB_CNTL] = 0x84;
	/*
	** Finally zero Ports A & B ..
	*/
    VmioBase[VMIO_PORT_A] = 0x00;
    VmioBase[VMIO_PORT_B] = 0x00;

    sig_status = signal (SIGBUS, SIG_DFL);   /* Reset trap handler to default */

    printf ("Timing signal generation via VMIO10 module enabled.\n");
    return;
  }
/*
**--------------------------------------------------------------------------
**	    setup_inet_info:	Get Internet Nodename and Address from System.
*/
  void setup_inet_info (
/*     ===============
*/			char	*host,
			int	 host_size,
			char	*addr,
			int	 addr_size) {

    int			    status;
    struct in_addr	    my_addr;
    char		    my_addr_c[INET_ADDR_LEN];

    status = gethostname (host, host_size);
    if (status != 0) StrJoin (host, host_size, "Undefined", "");

    my_addr.s_addr = hostGetByName (host);
    inet_ntoa_b (my_addr, my_addr_c);
    StrJoin (addr, addr_size, my_addr_c, "");
  }
/*--------------------------------------------------------------------------*/
  int sleep (int secs) {
/*    =====
**                  Go to sleep for secs seconds.
*/
    int	    ticks;

    ticks = secs * sysClkRateGet ();
    taskDelay (ticks);
    return 0;
  }
/*
**---------------------------------------------------------------------------
**		StrJoin	- join 2 strings.
**
**		    The routine joins 2 strings, checking for total string
**		    length and ensuring the result will be zero terminated.
**		    The "result" arg may be the same as "str_a" or "str_b".
**
**			    Note: strncat is used exclusively rather than
**				  strncpy to be sure result is always
**				  null terminated.
*/
  char	*StrJoin (
/*	 =======
*/		    char    *result,
		    int	    result_size,
		    char    *str_a,
		    char    *str_b) {

    int	    i, size, size_a, size_b;

    size = result_size - 1;

    if (size < 0) return result;

    if (result == str_a) {	    /* Are the result and str_a the same? */
      size_a = strlen (str_a);	    /* Yes */
      if (size_a > size) {	    /* Check sizes anyway. */
	result[size] = NIL;	    /* Truncate str_a. No room for str_b! */
      }else {
	size = size - strlen (result);	/* And append str_b */
	if (size > 0) {
	  strncat (result, str_b, size);
	}
      }
    }else if (result == str_b) {    /* Are the result and str_b the same? */
      size_a = strlen (str_a);	    /* Yes, this is a bit complicated! */
      size_b = strlen (str_b);
      if (size_a >= size) {	    /* If str_a completely fills result, .. */
	result[0] = NIL;	    /* .. then just copy in str_a */
	strncat (result, str_a, size);
      }else {
			    /*
			    ** Otherwise, str_b must first be moved to
			    ** make room for str_a and then str_a must
			    ** be put at the front of the result.
			    */
	if ((size_a + size_b) > size) size_b = size - size_a;
	result[size_a+size_b] = NIL;
	for (i = (size_b-1); i >= 0; i--) result[size_a+i] = str_b[i];
	memcpy (result, str_a, size_a);
      }
    }else {			   /* Result is neither str_a nor str_b so .. */
      result[0] = NIL;		   /* .. str_a needs to be copied */
      strncat (result, str_a, size);
      size = size - strlen (result);		    /* And str_a appended */
      if (size > 0) strncat (result, str_b, size);
    }
    return result;
  }
/*===================================== End of SinqHM_srv_routines.c ========*/
