#define	    IDENT	"1C05"
/*
** +--------------------------------------------------------------+
** |                  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_filler.c
**
** Author   . . . . . . . . . . : D. Maden
** Date of creation . . . . . . : Oct 1996
**
** Updates:
**  1A01  2-Oct-1996 DM	    Initial version.
**  1B01 10-Jun-1998 DM	    Add code for SQMH__TOF mode.
**  1C01 11-Jun-1999 DM	    Add code for SQMH__HRPT mode.
**  1C03 10-Aug-1999 DM	    Make Lwl_hdr_daq_mask/Lwl_hdr_daq_soll dependent
**				on the instrument.
**
**  SinqHM_srv_filler.c forms a child process of the SINQ Histogram Memory
**  process. It reads data from the detector via the PCI bus and fills the
**  histogram(s).
**
**  To compile this module for VxWorks on PSS123, use:
**
	    ccvx SinqHM_srv_filler.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    <sysLib.h>
#include    <msgQLib.h>

#include    <stdlib.h>
#include    <stdio.h>
#include    <signal.h>
#include    <timers.h>
#include    <errno.h>
#include    <setjmp.h>

/*
**====================	Global Definitions =====================================
*/
#define ESC 27

#include    "SinqHM_def.h"
#include    "SinqHM_gbl.h"
#include    "vmio10_def.h"
/*==============================================================================
		Global Routines
**
**   SinqHM_filler_setup_id  - copy some ident information to global variables.
**
**		Local Routines
**
**   SinqHM_filler_timer_handler - routine to handle timer interrupts.
**
**   SinqHM_filler_daq_hm_dig	- routine called by SinqHM_filler_daq for
**				    performing data acquisition in
**				    SQHM__HM_DIG mode, i.e. for data from
**				    detectors with digitised read-out
**				    electronics.
**   SinqHM_filler_daq_hrpt	- routine called by SinqHM_filler_daq for
**				    performing data acquisition in
**				    SQHM__HRPT mode, i.e. for data from
**				    detectors connected to a CERCA interface
**				    as in the HRPT instrument.
**   SinqHM_filler_daq_tof	- routine called by SinqHM_filler_daq for
**				    performing data acquisition in
**				    SQHM__TOF mode, i.e. for data from
**				    time-of-flight detectors.
**   SinqHM_filler_daq_psd	- routine called by SinqHM_filler_daq for
**				    performing data acquisition in
**				    SQHM__HM_PSD mode, i.e. for data from
**				    EMBL detectors.
**
**   SinqHM_filler_daq		- routine called by SinqHM_filler for
**				    performing data acquisition.
**
**   SinqHM_filler		- the main entry point for the FILLER child
**				    process.
**------------------------------------------------------------------------------
**
*/
/*==============================================================================
**		Global Routines for Filler
*/
  void	SinqHM_filler_setup_id () {
/*	======================
**		Simply copy some ident information to global variables
**		for use by the SQHM_IDENT request.
*/
    StrJoin (Sqhm_fill_ident, sizeof (Sqhm_fill_ident), IDENT, "");
    StrJoin (Sqhm_fill_date,  sizeof (Sqhm_fill_date),  __DATE__, ", ");
    StrJoin (Sqhm_fill_date,  sizeof (Sqhm_fill_date),  Sqhm_fill_date, __TIME__);
  }
/*==============================================================================
**		Local Routines for Filler
*/
  void	SinqHM_filler_timer_handler (int arg) {
/*	===========================
**				Routine to handle timer interrupts.
*/
    FillTimer_expired = True;
  }
/*
**------------------------------------------------------------------------------
**
*/
  void	SinqHM_filler_daq_hm_dig () {
/*	========================
**				Routine to handle Histogram Mode for
**				detectors with single channel digitised
**				read-out.
**	Note:
**	    Lwl_fifo could, in principle, be accessed via a register for better
**	    efficiency. However, this can cause trouble with the GDB debugger
**	    when single stepping. I think this is probably connected with
**	    instruction pipe-lining.
**	    For the time being, the register copy of Lwl_fifo will NOT be used.
*/
    register uint	*my_lwl_fifo;
    register uint	 my_lo_bin, my_hi_bin;
    register union {
      uint	ui4;
      usint	ui2[2];
      uchar	ui1[4];
    } lwl_hdr, lwl_data;
    uchar		    my_buff[32];
    int			    i, is;
    char    er_eol[] = {ESC, '[', '0', 'J'};	/* Erase to End-of-Line */

    register uchar  *my_char_base;
    register usint  *my_word_base;
    register uint   *my_long_base;

			/*-----------------------------------------------
			** Make register copies of some items for speed.
			*/
    my_lwl_fifo  = Lwl_fifo;
    my_lo_bin    = Lo_bin;
    my_hi_bin    = Hi_bin;
    switch (Bytes_per_bin) {
     case 1:  my_char_base = (uchar *) Hist_base_addr; break;
     case 2:  my_word_base = (usint *) Hist_base_addr; break;
     default: my_long_base = (uint  *) Hist_base_addr;
    }
			/*-----------------------------------------------*/
    while (Filler_flag == 0) {	       /* Loop till flag gets set */
      lwl_hdr.ui4 = *Lwl_fifo;	       /* Read a header from the FIFO */

      if (lwl_hdr.ui4 == LWL_FIFO_EMPTY) {
	taskDelay (0);	/* If FIFO is empty, we can take a breather! */
      }else if ((lwl_hdr.ui4 & LWL_HDR_TYPE_MASK) == LWL_HM_NC_C1) {
	VmioBase[VMIO_PORT_A] = 0xff;   /* Set timer level (if present) */
	 
	
	for (i=0; i<1000000; i++) {
	  lwl_data.ui4 = *Lwl_fifo;		/* Get the 16 bits of data */
	  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 histogram data word! Event # = %d\n",
		    N_events);
	}else if ((lwl_hdr.ui4 & Lwl_hdr_daq_mask) != Lwl_hdr_daq_soll) {
	    /* Some header bits are not what they should be (e.g. NRL may
	    ** be set) so skip the event.
	    */
	  N_skipped++;
	  if (Dbg_lev1) {
	    printf("Skipped header: 0x%08x\n"
		   "          Mask: 0x%08x\n"
		   "          Soll: 0x%08x\n", 
                 lwl_hdr.ui4, Lwl_hdr_daq_mask, Lwl_hdr_daq_soll);
	  }
	}else if (lwl_data.ui4 < my_lo_bin)	{   /* Check "out-of-rnge" */
	  if (Cnts_lo != 0xffffffff) Cnts_lo++;
	}else if (lwl_data.ui4 > my_hi_bin)	{   /* Check "out-of-rnge" */
	  if (Cnts_hi != 0xffffffff) Cnts_hi++;
	}else {
	  if (Hm_mode_REFLECT == 0) {	    /* Calculate bin number */
	    lwl_data.ui4 -= my_lo_bin;	    /* No reflection */
	  }else {
	    lwl_data.ui4 = my_hi_bin - lwl_data.ui4; /* Histogram must be reflected */
	  }
	  switch (Bytes_per_bin) {
	   case 1:
	    if (my_char_base[lwl_data.ui4] != 0xff) {	/* Check bin ovfl */
	      my_char_base[lwl_data.ui4]++;		/* Incr the bin */
	    }else {
	      switch (Hm_mode_BO) {		/* Bin overflow */
	       case SQHM__BO_SMAX: break;		/* Stop-at-max */
	       case SQHM__BO_CNT:  break;		/* Not programmed yet */
	       default:
		my_char_base[lwl_data.ui4] = 0;	 /* By default, wrap-to-zero */
	      }
	    }
	    break;
	   case 2:
	    if (my_word_base[lwl_data.ui4] != 0xffff) {	/* Check bin ovfl */
	      my_word_base[lwl_data.ui4]++;		/* Incr the bin */
	    }else {
	      switch (Hm_mode_BO) {		/* Bin overflow */
	       case SQHM__BO_SMAX: break;		/* Stop-at-max */
	       case SQHM__BO_CNT:  break;		/* Not programmed yet */
	       default:
		my_word_base[lwl_data.ui4] = 0;	 /* By default, wrap-to-zero */
	      }
	    }
	    break;
	   default:
	    if (my_long_base[lwl_data.ui4] != 0xffffffff) { /* Check bin ovfl */
	      my_long_base[lwl_data.ui4]++;		    /* Incr the bin */
	    }else {
	      switch (Hm_mode_BO) {		/* Bin overflow */
	       case SQHM__BO_SMAX: break;		/* Stop-at-max */
	       case SQHM__BO_CNT:  break;		/* Not programmed yet */
	       default:
		my_long_base[lwl_data.ui4] = 0;	 /* By default, wrap-to-zero */
	      }
	    }
	  }
	}
	VmioBase[VMIO_PORT_A] = 0x00;  /* Reset timer level (if present) */
	N_events++;
      }else if ((lwl_hdr.ui4 & LWL_HDR_TYPE_MASK) == LWL_TSI_HM_NC) {

	process_no_coinc_tsi (lwl_hdr.ui4);	/* We have found a "normal"
				** TSI (Timing-Status-Info) header. Process
				** it.
				*/
      }else if ((lwl_hdr.ui4 & LWL_HDR_TYPE_MASK) == LWL_TSI_HM_C) {

	process_coinc_tsi (lwl_hdr.ui4);	/* We have found a "coincidence"
				** type TSI header. The packet has 10 bytes
				** altogether. Process it.
				*/
      }else {					/* Anything else gets flushed */
	lwl_Packet_Read (lwl_hdr.ui4, my_buff);
      }

/*      if (FillTimer_expired) { */
      if (0) {
	if (Print_hdr) printf ("\nTaking data in Digitised Histogramming Mode\n"
		  "  #-Events     #-Skip      #-TSI  Dead-Time Sync-Status\n");
	Print_hdr = False;
	FillTimer_expired = False;
	printf ("\r%10u %10u %10u %10u %s", N_events, N_skipped,
	   (N_no_coin_tsi + N_coin_tsi), Dt_or_dts.dead_time, er_eol);
	if (Daq_active) printf (" DAQ");
	if ((Tsi_flags & STATUS_FLAGS__PF)    != 0) printf (" PF");
	if ((Tsi_flags & STATUS_FLAGS__SWC)   != 0) printf (" SWC");
	if (Nrl_active) printf (" NRL");
	if ((Tsi_flags & STATUS_FLAGS__SYNC3) != 0) printf (" SYNC3");
	if ((Tsi_flags & STATUS_FLAGS__SYNC2) != 0) printf (" SYNC2");
	if ((Tsi_flags & STATUS_FLAGS__SYNC1) != 0) printf (" SYNC1");
	if ((Tsi_flags & STATUS_FLAGS__SYNC0) != 0) printf (" SYNC0");
	if ((Tsi_flags & STATUS_FLAGS__UD)    != 0) printf (" UD");
	if ((Tsi_flags & STATUS_FLAGS__GU)    != 0) printf (" GU");

	is = timer_settime (FillTimerId, ~TIMER_ABSTIME, &FillerTime, NULL);
	if (is != 0) {
	  printf ("%s -- failed to set timer\n", Filler_name);
	}
      }
    }
		/* Our flag has been set. There should be ..
		** .. a message waiting for us. Return to process it.
		*/
  }
/*
**------------------------------------------------------------------------------
**
*/
  void	SinqHM_filler_daq_hrpt () {
/*	======================
**				Routine to handle Histogram Mode for
**				detectors connected to a CERCA interface
**				as in the HRPT instrument.
**
**	The wires of the detector are read out frame by frame.
**	Each wire comes as a 3-word packet (i.e. Hist Mode mit 3 Kanaele).
**	The first  word is 15-bit Wire Address (0 .. 1601) + Error Bit
**	The second word is 10-bit Count
**	The third  word is 16-bit Frame Number
**
**	To avoid skewing the histograms, the data is read out frame by frame
**	and the frame is merged with the overall histogram only when it is
**	complete and the LWL header information was OK for Wire 0 of the frame.
**
**	Note:
**	    Lwl_fifo could, in principle, be accessed via a register for better
**	    efficiency. However, this can cause trouble with the GDB debugger
**	    when single stepping. I think this is probably connected with
**	    instruction pipe-lining.
**	    For the time being, the register copy of Lwl_fifo will NOT be used.
**
**	Another Note:
**	    The HRPT detector has 1600 wires numbered 0 to 1599. The physicists
**	    want these numbers reflected for reasons of their own.
**	    The CERCA readout also uses wire numbers 1600 and 1601 to present
**	    time information about the frame. This information is discarded.
*/
    register uint	*my_lwl_fifo;
    register uint	 my_lo_bin, my_hi_bin;
    register union {
      uint	ui4;
      usint	ui2[2];
      uchar	ui1[4];
    } lwl_hdr, lwl_data_0, lwl_data_1, lwl_data_2;
    uchar		my_buff[32];
    uint		wire;
    int			i, j, k, is, my_state;
    int			n_errors = 0;
    char		err_txt[128];

    char    er_eol[] = {ESC, '[', '0', 'J'};	/* Erase to End-of-Line */

    register uchar  *my_char_base;
    register usint  *my_word_base;
    register uint   *my_long_base;

    register uchar  *my_char_frame;
    register usint  *my_word_frame;
    register uint   *my_long_frame;

			/*-----------------------------------------------
			** Make register copies of some items for speed.
			*/
    my_lwl_fifo  = Lwl_fifo;
    my_lo_bin    = Lo_bin;
    my_hi_bin    = Hi_bin;
    switch (Bytes_per_bin) {
     case 1:  my_char_base = (uchar *) Hist_base_addr; break;
     case 2:  my_word_base = (usint *) Hist_base_addr; break;
     default: my_long_base = (uint  *) Hist_base_addr;
    }
    switch (Bytes_per_bin) {
     case 1:  my_char_frame = (uchar *) Frame_base_addr; break;
     case 2:  my_word_frame = (usint *) Frame_base_addr; break;
     default: my_long_frame = (uint  *) Frame_base_addr;
    }
    my_state = HRPT__SRCH_FRAME;
			/*-----------------------------------------------*/
    while (Filler_flag == 0) {	       /* Loop till flag gets set */
      lwl_hdr.ui4 = *Lwl_fifo;	       /* Read a header from the FIFO */

      if (lwl_hdr.ui4 == LWL_FIFO_EMPTY) {
	taskDelay (0);	/* If FIFO is empty, we can take a breather! */

      }else if ((lwl_hdr.ui4 & LWL_HDR_TYPE_MASK) == LWL_HM_NC_C3) {
			/* Histo data, three channel -- this is what we are
			** interested in in HRPT mode. Start by reading out
			** the 3 data words which should follow the header.
			*/
	VmioBase[VMIO_PORT_A] = 0xff;	    /* Set timer level (if present) */
	for (i=0; i<1000; i++) {
	  lwl_data_0.ui4 = *Lwl_fifo;		/* Get first 16 bits of data */
	  if (lwl_data_0.ui4 != LWL_FIFO_EMPTY) break;
	  taskDelay (0);			/* But wait if FIFO is slow! */
	}
	if (lwl_data_0.ui4 != LWL_FIFO_EMPTY) {
	  for (i=0; i<1000; i++) {
	    lwl_data_1.ui4 = *Lwl_fifo;	       /* Get second 16 bits of data */
	    if (lwl_data_1.ui4 != LWL_FIFO_EMPTY) break;
	    taskDelay (0);			/* But wait if FIFO is slow! */
	  }
	  if (lwl_data_1.ui4 != LWL_FIFO_EMPTY) {
	    for (i=0; i<1000; i++) {
	      lwl_data_2.ui4 = *Lwl_fifo;	/* Get third 16 bits of data */
	      if (lwl_data_2.ui4 != LWL_FIFO_EMPTY) break;
	      taskDelay (0);			/* But wait if FIFO is slow! */
	    }
            if (Dbg_lev1 && (lwl_data_1.ui4 > 0)) {
                printf ("Got address = %d, shifted = %d, counts = %d\n", 
                     lwl_data_0.ui4, (lwl_data_0.ui4 >> 1), lwl_data_1.ui4);
	    }
	  }
	}
	if ((lwl_data_0.ui4 == LWL_FIFO_EMPTY) ||
	    (lwl_data_1.ui4 == LWL_FIFO_EMPTY) ||
	    (lwl_data_2.ui4 == LWL_FIFO_EMPTY)) {
	  if (n_errors == 0) {
	    sprintf (err_txt, "Time-out getting the three data words! "
			"Event # = %d\n", N_events);
	  }
	  n_errors++;
	}else {
	  wire = lwl_data_0.ui4 >> 1;		   /* Shift out error bit */
	  if (wire < my_lo_bin) {		   /* Out-of-rnge? */
	    if (Cnts_lo != 0xffffffff) Cnts_lo++;
	  }else if (wire == my_lo_bin) {	   /* Start of new frame? */
	    my_state = HRPT__READ_FRAME;	   /* Yes. Note our new state */
	    Frame_hdr = lwl_hdr.ui4;		   /* Remember hdr for frame */
	    Frame_num = lwl_data_2.ui4;
	    switch (Bytes_per_bin) {
	     case 1:  my_char_frame[0] = lwl_data_1.ui4; break;
	     case 2:  my_word_frame[0] = lwl_data_1.ui4; break;
	     default: my_long_frame[0] = lwl_data_1.ui4;
	    }
	  }else if (wire <= my_hi_bin) {	    /* In range? */
	    if (my_state == HRPT__READ_FRAME) {	    /* Yes. Check state */
	      if (lwl_data_2.ui4 == Frame_num) {    /* And check frame # */
		switch (Bytes_per_bin) {
		 case 1:  my_char_frame[wire-my_lo_bin] = lwl_data_1.ui4; break;
		 case 2:  my_word_frame[wire-my_lo_bin] = lwl_data_1.ui4; break;
		 default: my_long_frame[wire-my_lo_bin] = lwl_data_1.ui4;
		}
	      }else {
		if (n_errors == 0) {
		  sprintf (err_txt, "Frame sequence error: Frame 0x%04x\n"
			"      Packet: 0x%08x 0x%04x 0x%04x 0x%04x\n",
		   lwl_hdr.ui4, lwl_data_0.ui4, lwl_data_1.ui4, lwl_data_2.ui4);
		}
		n_errors++;
	      }
	      if (wire == my_hi_bin) {			/* End of frame? */
						/* Yes, merge it in if the
						** header bits are OK
						*/
		if ((Frame_hdr & Lwl_hdr_daq_mask) != Lwl_hdr_daq_soll) {
		  N_skipped++;
		  if (Dbg_lev1) {
		    printf("Skipped frame %d\n"
			   "       Hdr:  0x%08x\n"
			   "       Mask: 0x%08x\n"
			   "       Soll: 0x%08x\n", Frame_num,
			    Frame_hdr, Lwl_hdr_daq_mask, Lwl_hdr_daq_soll);
		  }
		}else {
		  N_events++;
		  k = 0;
		  for (i = my_lo_bin; i <= my_hi_bin; i++) {
		    if (Hm_mode_REFLECT == 0) {	    /* Reflect if necessary */
		      j = i - my_lo_bin;
		    }else {
		      j = my_hi_bin - i;
		    }
		    switch (Bytes_per_bin) {
		     case 1:  my_char_base[j] += my_char_frame[k]; break;
		     case 2:  my_word_base[j] += my_word_frame[k]; break;
		     default: my_long_base[j] += my_long_frame[k];
		    }
		    k++;
		  }
		}
		my_state == HRPT__SRCH_FRAME;
	      }
	    }
	  }else if (wire == (my_hi_bin + 1)) {	    /* Frame timing #1? */
	    continue;				    /* Yes, ignore */
	  }else if (wire == (my_hi_bin + 2)) {	    /* Frame timing #2? */
	    continue;				    /* Yes, ignore */
	  }else if (wire > (my_hi_bin + 2))	{   /* Out-of-rnge? */
	    if (Cnts_hi != 0xffffffff) Cnts_hi++;
	  }
	}
	VmioBase[VMIO_PORT_A] = 0x00;  /* Reset timer level (if present) */
      }else if ((lwl_hdr.ui4 & LWL_HDR_TYPE_MASK) == LWL_TSI_HM_NC) {
	process_no_coinc_tsi (lwl_hdr.ui4);	/* We have found a "normal"
				** TSI (Timing-Status-Info) header. Process
				** it.
				*/
      }else if ((lwl_hdr.ui4 & LWL_HDR_TYPE_MASK) == LWL_TSI_HM_C) {
	process_coinc_tsi (lwl_hdr.ui4);	/* We have found a "coincidence"
				** type TSI header. The packet has 10 bytes
				** altogether. Process it.
				*/
      }else {					/* Anything else gets flushed */
	lwl_Packet_Read (lwl_hdr.ui4, my_buff);
      }

      if (FillTimer_expired) {
	if (Print_hdr) printf ("\nTaking data in HRPT Mode\n"
		  "  #-Events     #-Skip      #-TSI  #-Frame  Sync-Status\n");
	Print_hdr = False;
	FillTimer_expired = False;
	printf ("\r%10u %10u %10u %10u %s", N_events, N_skipped,
	   (N_no_coin_tsi + N_coin_tsi), Frame_num, er_eol);
	if (Daq_active) printf (" DAQ");
	if ((Tsi_flags & STATUS_FLAGS__PF)    != 0) printf (" PF");
	if ((Tsi_flags & STATUS_FLAGS__SWC)   != 0) printf (" SWC");
	if (Nrl_active) printf (" NRL");
	if ((Tsi_flags & STATUS_FLAGS__SYNC3) != 0) printf (" SYNC3");
	if ((Tsi_flags & STATUS_FLAGS__SYNC2) != 0) printf (" SYNC2");
	if ((Tsi_flags & STATUS_FLAGS__SYNC1) != 0) printf (" SYNC1");
	if ((Tsi_flags & STATUS_FLAGS__SYNC0) != 0) printf (" SYNC0");
	if ((Tsi_flags & STATUS_FLAGS__UD)    != 0) printf (" UD");
	if ((Tsi_flags & STATUS_FLAGS__GU)    != 0) printf (" GU");

	if (n_errors != 0) {
	  printf ("\n%d errors occurred in the last time period\n", n_errors);
	  printf ("The first one was:\n%s\n", err_txt);
	  n_errors = 0;
	}
	is = timer_settime (FillTimerId, ~TIMER_ABSTIME, &FillerTime, NULL);
	if (is != 0) {
	  printf ("%s -- failed to set timer\n", Filler_name);
	}
      }
    }
		/* Our flag has been set. There should be ..
		** .. a message waiting for us. Return to process it.
		*/
  }
/*
**-----------------------------------------------------------------------------
*/
  void	SinqHM_filler_daq_tof () {
/*	=====================
**				Routine to handle Time-of-flight Mode
**	Note:
**	    Lwl_fifo could, in principle, be accessed via a register for better
**	    efficiency. However, this can cause trouble with the GDB debugger
**	    when single stepping. I think this is probably connected with
**	    instruction pipe-lining.
**	    For the time being, the register copy of Lwl_fifo will NOT be used.
*/
    register uint   *my_lwl_fifo;
    register union {
      uint	ui4;
      usint	ui2[2];
      uchar	ui1[4];
    } lwl_hdr, lwl_data;

    int				 i, j, is, ts, left, right, middl, not_finished;
    uchar			 my_buff[32];
    register struct tof_histog  *my_tof_descr;
    uint			*edge_pntr;
    char    er_eol[] = {ESC, '[', '0', 'J'};	/* Erase to End-of-Line */
			/*-----------------------------------------------
			** Make register copies of some items for speed.
			*/
    my_lwl_fifo  = Lwl_fifo;
			/*-----------------------------------------------*/
    while (Filler_flag == 0) {	       /* Loop till flag gets set */

      lwl_hdr.ui4 = *Lwl_fifo;	       /* Read a header from the FIFO */

      if (lwl_hdr.ui4 == LWL_FIFO_EMPTY) {
	taskDelay (0);	/* If FIFO is empty, we can take a breather! */

      }else if (((lwl_hdr.ui4 & LWL_HDR_TYPE_MASK) == LWL_TOF_C1) ||
		((lwl_hdr.ui4 & LWL_HDR_TYPE_MASK) == LWL_TOF_C2) ||
		((lwl_hdr.ui4 & LWL_HDR_TYPE_MASK) == LWL_TOF_C3) ||
		((lwl_hdr.ui4 & LWL_HDR_TYPE_MASK) == LWL_TOF_C4) ||
		((lwl_hdr.ui4 & LWL_HDR_TYPE_MASK) == LWL_TOF_C5) ||
		((lwl_hdr.ui4 & LWL_HDR_TYPE_MASK) == LWL_TOF_C6) ||
		((lwl_hdr.ui4 & LWL_HDR_TYPE_MASK) == LWL_TOF_C7) ||
		((lwl_hdr.ui4 & LWL_HDR_TYPE_MASK) == LWL_TOF_C8) ||
		((lwl_hdr.ui4 & LWL_HDR_TYPE_MASK) == LWL_TOF_C9)) {
				/* We have found a header of the type we are
				** interested in, i.e. a TOF packet. So
				** process it. We must first get the 16 bits
				** of data which give the counter number.
				*/
	VmioBase[VMIO_PORT_A] = 0xff;   /* Set timer level (if present) */
	for (i=0; i<1000; i++) {
	  lwl_data.ui4 = *Lwl_fifo;		/* Get the counter number */
	  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 counter number!\n");
	}else if ((lwl_hdr.ui4 & Lwl_hdr_daq_mask) != Lwl_hdr_daq_soll) {
	    /* Some header bits are not what they should be (e.g. NRL may
	    ** be set) so skip the event.
	    */
	  N_skipped++;
	  if (Dbg_lev1) {
	    printf("Skipped header: 0x%08x\n"
		   "          Mask: 0x%08x\n"
		   "          Soll: 0x%08x\n", 
                 lwl_hdr.ui4, Lwl_hdr_daq_mask, Lwl_hdr_daq_soll);
	  }
	}else {
			/* We have a valid TOF packet. Validate it
			** thoroughly and process it. First check
			** that the counter number is valid.
			*/
	  if (lwl_data.ui4 >= MAX_TOF_CNTR) {
	    Tof_count_bad_counter_number++;	    /* It isn't */
	  }else {
	    my_tof_descr = Tof_descr[lwl_data.ui4];
	    if (my_tof_descr == NULL) {
	      Tof_count_bad_counter_number++;	    /* It isn't */
	    }else {
			/* The counter number is valid. Process the time-stamp
			** (20-bit quantity) to find which bin to increment.
			*/
	      ts = lwl_hdr.ui4 & LWL_HDR_TS_MASK;
	      if (ts < my_tof_descr->lo_edge) {
		if ((Hm_mode_UD != 0) &&
		    (lwl_hdr.ui4 & LWL_HDR_UD_MASK) == 0) {
		  my_tof_descr->cnt_early_down++;
		}else {
		  my_tof_descr->cnt_early_up++;
		}
	      }else {
		if (ts > my_tof_descr->hi_edge) {
		  if ((Hm_mode_UD != 0) &&
		      (lwl_hdr.ui4 & LWL_HDR_UD_MASK) == 0) {
		    my_tof_descr->cnt_late_down++;
		  }else {
		    my_tof_descr->cnt_late_up++;
		  }
		}else {
			    /* Now search the bin boundary list to find the
			    ** bin to which this event belongs.
			    */
		  edge_pntr = my_tof_descr->bin_edge;
		  left = 0;
		  right = my_tof_descr->n_bins;
		  middl = (left + right)/2;
		  not_finished = True;
		  while (not_finished) {
		    switch (right - left) {
		     case 0:
		      not_finished = False;
		      break;
		     case 1:
		      middl = (ts >= edge_pntr[right]) ? right : left;
		      not_finished = False;
		      break;
		     default:
		      middl = (left + right)/2;
		      if (ts == edge_pntr[middl]) {
		        not_finished = False;
		      }else if (ts > edge_pntr[middl]) {
			left = middl;
		      }else {
			right = middl;
		      }
		    }
		  }
		  if ((Hm_mode_UD != 0) &&
		      ((lwl_hdr.ui4 & LWL_HDR_UD_MASK) != 0)) {
		    middl += my_tof_descr->n_bins;
		  }
		  switch (my_tof_descr->bytes_per_bin) {
		   case 1:
		    my_tof_descr->u.b_bin_data[middl]++; break;
		   case 2:
		    my_tof_descr->u.w_bin_data[middl]++; break;
		   default:
		    my_tof_descr->u.l_bin_data[middl]++; break;
		  }
		}
	      }
	    }
	  }
	}
	VmioBase[VMIO_PORT_A] = 0x00;  /* Reset timer level (if present) */
	N_events++;
      }else if ((lwl_hdr.ui4 & LWL_HDR_TYPE_MASK) == LWL_TSI_HM_NC) {
	process_no_coinc_tsi (lwl_hdr.ui4);	/* We have found a "normal"
				** TSI (Timing-Status-Info) header. Process
				** it.
				*/
      }else if ((lwl_hdr.ui4 & LWL_HDR_TYPE_MASK) == LWL_TSI_HM_C) {
	process_coinc_tsi (lwl_hdr.ui4);	/* We have found a "coincidence"
				** type TSI header. The packet has 10 bytes
				** altogether. Process it.
				*/
      }else if ((lwl_hdr.ui4 & LWL_HDR_TYPE_MASK) == LWL_GUMMI_MON) {
	/*
	  process a SANS gummi mode monitor datagram
	*/
	process_gummi_monitor(lwl_hdr.ui4);
      }else {					/* Anything else gets flushed */
	lwl_Packet_Read (lwl_hdr.ui4, my_buff);
      }

      if (FillTimer_expired) {
	if (Print_hdr) printf ("\nTaking data in TOF Mode\n"
		  "  #-Events     #-Skip      #-TSI Delay-Time Sync-Status\n");
	Print_hdr = False;
	FillTimer_expired = False;
	printf ("\r%10u %10u %10u %10u %s", N_events, N_skipped,
	   (N_no_coin_tsi + N_coin_tsi), Dt_or_dts.dts, er_eol);
	if (Daq_active) printf (" DAQ");
	if ((Tsi_flags & STATUS_FLAGS__PF)    != 0) printf (" PF");
	if ((Tsi_flags & STATUS_FLAGS__SWC)   != 0) printf (" SWC");
	if (Nrl_active) printf (" NRL");
	if ((Tsi_flags & STATUS_FLAGS__SYNC3) != 0) printf (" SYNC3");
	if ((Tsi_flags & STATUS_FLAGS__SYNC2) != 0) printf (" SYNC2");
	if ((Tsi_flags & STATUS_FLAGS__SYNC1) != 0) printf (" SYNC1");
	if ((Tsi_flags & STATUS_FLAGS__SYNC0) != 0) printf (" SYNC0");
	if ((Tsi_flags & STATUS_FLAGS__UD)    != 0) printf (" UD");
	if ((Tsi_flags & STATUS_FLAGS__GU)    != 0) printf (" GU");

	is = timer_settime (FillTimerId, ~TIMER_ABSTIME, &FillerTime, NULL);
	if (is != 0) {
	  printf ("%s -- failed to set timer\n", Filler_name);
	}
      }
    }
		/* Our flag has been set. There should be ..
		** .. a message waiting for us. Return to process it.
		*/
  }
/*
**-----------------------------------------------------------------------------
*/
  void	SinqHM_filler_daq_psd () {
/*	=====================
**				Routine to handle PSD-TOF Mode
**	Note:
**	    Lwl_fifo could, in principle, be accessed via a register for better
**	    efficiency. However, this can cause trouble with the GDB debugger
**	    when single stepping. I think this is probably connected with
**	    instruction pipe-lining.
**	    For the time being, the register copy of Lwl_fifo will NOT be used.
*/
    register uint   *my_lwl_fifo;
    register union {
      uint	ui4;
      usint	ui2[2];
      uchar	ui1[4];
    } lwl_hdr, xData, yData, edData;

    int xPos, yPos, iTime, dataPos, edNum, xOff, yOff;
    signed int  sPosx, sPosy;
    int		     i, j, is, ts, left, right, middl, not_finished;
    uint			*edge_pntr;
    char    er_eol[] = {ESC, '[', '0', 'J'};	/* Erase to End-of-Line */
    uchar			 my_buff[32];
    uint *histlPtr = (uint *)Hist_base_addr;
    usint *histsPtr = (usint *)Hist_base_addr;
    uchar *histcPtr = (uchar *)Hist_base_addr;
    

    /*
      precalculate some offsets
    */
    xOff = psdXOffset*psdXFactor;
    yOff = psdYOffset*psdYFactor;

			/*-----------------------------------------------
			** Make register copies of some items for speed.
			*/
    my_lwl_fifo  = Lwl_fifo;
			/*-----------------------------------------------*/
    while (Filler_flag == 0) {	       /* Loop till flag gets set */

      lwl_hdr.ui4 = *Lwl_fifo;	       /* Read a header from the FIFO */

      if (lwl_hdr.ui4 == LWL_FIFO_EMPTY) {
	taskDelay (0);	/* If FIFO is empty, we can take a breather! */

      }else if ( (lwl_hdr.ui4 & LWL_HDR_TYPE_MASK) == LWL_PSD_DATA) {
        /*
           we have located a PSD data packet. Let us read the xPos and
           yPos packes.
	*/
	VmioBase[VMIO_PORT_A] = 0xff;   /* Set timer level (if present) */

	for (i=0; i<1000; i++) {
	  xData.ui4 = *Lwl_fifo;		/* Get the x Position */
	  if (xData.ui4 != LWL_FIFO_EMPTY) break;
	  taskDelay (0);			/* But wait if FIFO is slow! */
	}
	if (xData.ui4 == LWL_FIFO_EMPTY) {
	  printf ("Time-out getting X position !\n");
          continue;
	}

	for (i=0; i<1000; i++) {
	  yData.ui4 = *Lwl_fifo;		/* Get the y Position */
	  if (yData.ui4 != LWL_FIFO_EMPTY) break;
	  taskDelay (0);			/* But wait if FIFO is slow! */
	}
	if (yData.ui4 == LWL_FIFO_EMPTY) {
	  printf ("Time-out getting Y position!\n");
          continue;
	}

        /*
          check if data aquisition is active
	*/
        if ((lwl_hdr.ui4 & Lwl_hdr_daq_mask) != Lwl_hdr_daq_soll) {
	    /* Some header bits are not what they should be (e.g. NRL 
	    ** ow PWF may be set) so skip the event.
	    */
	  N_skipped++;
	  if (Dbg_lev1) {
	    printf("Skipped header: 0x%08x\n"
		   "          Mask: 0x%08x\n"
		   "          Soll: 0x%08x\n", 
                 lwl_hdr.ui4, Lwl_hdr_daq_mask, Lwl_hdr_daq_soll);
  	  }
          continue;
	}
          /*
            We have a valid PSD packet. Find and check positions.
	  */


	/*
	  This is the new version where all values are offset by 4096
          in order to give positive values at all times. This relates
          to a zero point in the middle of the detector. As we want a
          zero point in the lower left corner, we subtract 2048.
	*/
	  xPos = xData.ui2[1];
	  xPos = (xPos - 2048)/psdXFactor;
	  yPos = yData.ui2[1];
	  yPos = (yPos - 2048)/psdYFactor;


          if(xPos < 0 || xPos >= psdXSize)
	  {
	    printf("X position out of range: %d, alllowed 0 - %d\n",
                   xPos, psdXSize);
	    continue;
          }
          if(yPos < 0 || yPos >= psdYSize)
	  {
	    printf("Y position out of range: %d, alllowed 0 - %d\n",
                   yPos, psdYSize);
            continue;
          }

          /*
            Extract time stamp and match to the appropriate time bin.
	  */
          iTime = lwl_hdr.ui4 & LWL_PSD_TIME;
          if(Dbg_lev1){
	    printf("Received detector hit at x,y, time: %d, %d, %d\n",
		   xPos, yPos, iTime);
          }

	  edge_pntr = Tof_edges[0]->edges;
	  left = 0;
	  right = Tof_edges[0]->n_bins;
	  middl = (left + right)/2;
	  not_finished = True;
          iTime -= Tof_dts_soll;
	  while (not_finished) {
		    switch (right - left) {
		     case 0:
		      not_finished = False;
		      break;
		     case 1:
		      middl = (iTime >= edge_pntr[right]) ? right : left;
		      not_finished = False;
		      break;
		     default:
		      middl = (left + right)/2;
		      if (iTime == edge_pntr[middl]) {
		        not_finished = False;
		      }else if (iTime > edge_pntr[middl]) {
			left = middl;
		      }else {
			right = middl;
		      }
		    }
	 }
	 if(Dbg_lev1){
	   printf("Matched time stamp %d into bin %d\n", iTime,middl);
         }
         
	 if(middl >= Tof_edges[0]->n_bins){
	   if(Tof_edges[0]->n_bins < 5){
	     /*
	       fix for PSD without TOF
	     */
	     middl = Tof_edges[0]->n_bins-1;
	   } else {
	     /* 
		skip it, out of range
	     */
	     continue;
	   }
	 }

         /* 
	    calculate histogram position to update 
	 */
         dataPos = yPos*psdXSize*Tof_edges[0]->n_bins + 
	   xPos*Tof_edges[0]->n_bins + middl;

         /* UD must come but the bit is not yet defined
	 if ((Hm_mode_UD != 0) &&
	     ((lwl_hdr.ui4 & LWL_HDR_UD_MASK) != 0)) {
		    dataPos += 
		      (psdXSize*psdYSize+MAX_PSD_ED)*Tof_edges[0]->n_bins ;
	 }
         */
         switch(Bytes_per_bin)
	 {
	   case 1:
	     histcPtr[dataPos]++;
	     break;
	   case 2:
	     histsPtr[dataPos]++;
	     break;
	   case 4:
	     histlPtr[dataPos]++;
	     break;
         }         

          VmioBase[VMIO_PORT_A] = 0x00;  /* Reset timer level (if present) */
	  N_events++;
      }else if ( (lwl_hdr.ui4 & LWL_HDR_ED_MASK) == 0) {
        /*
	  we have located a single detector packet from AMOR. We need to
          read the detector number
	*/
	VmioBase[VMIO_PORT_A] = 0xff;   /* Set timer level (if present) */

	for (i=0; i<1000; i++) {
	  edData.ui4 = *Lwl_fifo;		/* Get the detector number */
	  if (edData.ui4 != LWL_FIFO_EMPTY) break;
	  taskDelay (0);			/* But wait if FIFO is slow! */
	}
	if (xData.ui4 == LWL_FIFO_EMPTY) {
	  printf ("Time-out getting  detector number !\n");
          continue;
	}
        /*
          check if data aquisition is active
	*/
        if ((lwl_hdr.ui4 & Lwl_hdr_daq_mask) != Lwl_hdr_daq_soll) {
	    /* Some header bits are not what they should be (e.g. NRL 
	    ** ow PWF may be set) so skip the event.
	    */
	  N_skipped++;
	  if (Dbg_lev1) {
	    printf("Skipped header: 0x%08x\n"
		   "          Mask: 0x%08x\n"
		   "          Soll: 0x%08x\n", 
                 lwl_hdr.ui4, Lwl_hdr_daq_mask, Lwl_hdr_daq_soll);
  	  }
          continue;
	}
          /*
            We have a valid single detector packet. 
	    Subtract one from the number because Urs Greuter starts 
	    counting at 1, and ANSI-C at 0
	  */
	  edNum = edData.ui2[1] - 1;
          if(edNum < 0 || edNum >= MAX_PSD_ED){
	    printf("Got invalid single detector number %d\n",edNum);
	    continue;
          }

          /*
            Extract time stamp and match to the appropriate time bin.
	  */
          iTime = lwl_hdr.ui4 & LWL_PSD_TIME;
          if(Dbg_lev1){
	    printf("Received single detector hit at no, time: %d, %d\n",
		   edNum, iTime);
          }

	  edge_pntr = Tof_edges[0]->edges;
	  left = 0;
	  right = Tof_edges[0]->n_bins;
	  middl = (left + right)/2;
	  not_finished = True;
          iTime -= Tof_dts_soll;
	  while (not_finished) {
		    switch (right - left) {
		     case 0:
		      not_finished = False;
		      break;
		     case 1:
		      middl = (iTime >= edge_pntr[right]) ? right : left;
		      not_finished = False;
		      break;
		     default:
		      middl = (left + right)/2;
		      if (iTime == edge_pntr[middl]) {
		        not_finished = False;
		      }else if (iTime > edge_pntr[middl]) {
			left = middl;
		      }else {
			right = middl;
		      }
		    }
	 }
	 if(Dbg_lev1){
	   printf("Matched time stamp %d into bin %d\n", iTime,middl);
         }
         
	 if(middl >= Tof_edges[0]->n_bins){
	   middl = Tof_edges[0]->n_bins-1;
           if(Dbg_lev1){
	     printf("WARNING: Fixed bad time bin for single detector!\n");
	   }
	   continue;
	 }

         /* 
	    calculate histogram position to update 
	 */
         dataPos = (psdYSize*psdXSize)*Tof_edges[0]->n_bins  
	           + edNum*Tof_edges[0]->n_bins + middl - 1;

	 if(Dbg_lev1){
	   printf("dataPos = %d\n", dataPos);
         }


         /* UD must come but the UD bit is not defined......
	 if ((Hm_mode_UD != 0) &&
	     ((lwl_hdr.ui4 & LWL_HDR_UD_MASK) != 0)) {
		    dataPos += 
		      (psdXSize*psdYSize+MAX_PSD_ED)*Tof_edges[0]->n_bins ;
	 }
         */

         switch(Bytes_per_bin)
	 {
	   case 1:
	     histcPtr[dataPos]++;
	     break;
	   case 2:
	     histsPtr[dataPos]++;
	     break;
	   case 4:
	     histlPtr[dataPos]++;
	     break;
         }         

          VmioBase[VMIO_PORT_A] = 0x00;  /* Reset timer level (if present) */
	  N_events++;
      }else if ((lwl_hdr.ui4 & LWL_HDR_TYPE_MASK) == LWL_PSD_TSI) {
        /* 
          we have located a PSD style TSI telegram
	*/
        process_psd_tsi(lwl_hdr.ui4);
      }else {	    
        /* Anything else gets flushed */
	lwl_Packet_Read (lwl_hdr.ui4, my_buff);
      }

      if (FillTimer_expired) {
	if (Print_hdr) printf ("\nTaking data in PSD Mode\n"
            "  #-Events     #-Skip      #-TSI     #-Hits   %s",
            "#-Flash Delay-Time Sync-Status\n");
	Print_hdr = False;
	FillTimer_expired = False;
	printf ("\r%10u %10u %10u %10u %10u %10u %s", N_events, N_skipped,
	   (N_no_coin_tsi + N_coin_tsi), psdHitCount, 
                    psdFlashCount, Dt_or_dts.dts, er_eol);
	if (Daq_active) printf (" DAQ");
	if ((Tsi_flags & STATUS_FLAGS__PF)    != 0) printf (" PF");
	if ((Tsi_flags & STATUS_FLAGS__SWC)   != 0) printf (" SWC");
	if (Nrl_active) printf (" NRL");
	if ((Tsi_flags & STATUS_FLAGS__SYNC3) != 0) printf (" SYNC3");
	if ((Tsi_flags & STATUS_FLAGS__SYNC2) != 0) printf (" SYNC2");
	if ((Tsi_flags & STATUS_FLAGS__SYNC1) != 0) printf (" SYNC1");
	if ((Tsi_flags & STATUS_FLAGS__SYNC0) != 0) printf (" SYNC0");
	if ((Tsi_flags & STATUS_FLAGS__UD)    != 0) printf (" UD");
	if ((Tsi_flags & STATUS_FLAGS__GU)    != 0) printf (" GU");
        if(psdXORF) printf(" XORF");
        if(psdConf) printf(" CONF");
	 
	is = timer_settime (FillTimerId, ~TIMER_ABSTIME, &FillerTime, NULL);
	if (is != 0) {
	  printf ("%s -- failed to set timer\n", Filler_name);
	}
      }
    }
		/* Our flag has been set. There should be ..
		** .. a message waiting for us. Return to process it.
		*/
  }
/*
**-----------------------------------------------------------------------------
*/
  void	SinqHM_filler_daq_trans () {
/*	=======================
**			Routine to handle Transparent Mode. Data is simply read
**			and packed into the buffers. The buffers are used
**			cyclically.
**			The routine attempts to read packets of data from the
**			fibre-optic channel. This code, however, assumes that
**			the packets obey the LWL protocol specification.
**	Note:
**	    Lwl_fifo could, in principle, be accessed via a register for better
**	    efficiency. However, this can cause trouble with the GDB debugger
**	    when single stepping. I think this is probably connected with
**	    instruction pipe-lining.
**	    For the time being, the register copy of Lwl_fifo will NOT be used.
*/
    register uint   *my_lwl_fifo;
    register union {
      uint	ui4;
      usint	ui2[2];
      uchar	ui1[4];
    } lwl_hdr, lwl_data;

    uint	     status_info;
    int		     i, j;
    register uchar  *my_char_nxt;

			/*-----------------------------------------------
			** Make register copies of some items for speed.
			*/
    my_lwl_fifo = Lwl_fifo;
    my_char_nxt = Next_char;

    while (Filler_flag == 0) {	       /* Loop till flag gets set */
      lwl_hdr.ui4 = *Lwl_fifo;	       /* Read a header from the FIFO */

      if (lwl_hdr.ui4 == LWL_FIFO_EMPTY) {
	taskDelay (0);	/* If FIFO is empty, we can take a breather! */
      }else {
#ifdef TRANNY	
	VmioBase[VMIO_PORT_A] = 0xff;	    /* Set timer level (if present) */
	*my_char_nxt = lwl_Packet_Read (lwl_hdr.ui4, &my_char_nxt[1]);
	Bytes_free = Bytes_free - *my_char_nxt - 1;
	my_char_nxt = my_char_nxt + *my_char_nxt + 1;
	if (Bytes_free < 24) my_char_nxt = selectNewBuffer (my_char_nxt);
	VmioBase[VMIO_PORT_A] = 0x00;	/* Reset timer level (if present) */
#else
        printf("%#8.8x\n",lwl_hdr.ui4);
#endif
      }
    }
		/* Our flag has been set. There should be ..
		** .. a message waiting for us. Return to process it.
		*/
  }
/*
**-----------------------------------------------------------------------------
*/
  void	SinqHM_filler_daq () {
/*	=================
*/
    int	    is;

    switch (Hm_mode & (~SQHM__SUB_MODE_MSK)) {
     case SQHM__TRANS:
      SinqHM_filler_daq_trans ();	/* Do Transparent mode */
      break;
     case SQHM__HM_DIG:
      SinqHM_filler_daq_hm_dig ();	/* Do Digitised-type detectors */
      break;
     case SQHM__HRPT:
      SinqHM_filler_daq_hrpt ();	/* Do HRPT (CERCA) type detectors */
      break;
     case SQHM__HM_PSD:
      SinqHM_filler_daq_psd ();		/* Do PSD readout  */
      break;
     case SQHM__TOF:
      SinqHM_filler_daq_tof ();		/* Do time-of-flight read-out */
      break;
    }
  }
/*
**=============================================================================
**			Here beginneth the main code for FILLER ...
*/
  int SinqHM_filler (int suspend_flag) {
/*    =============
**		    FILLER - Scaler Overflow Handler for SinqHM sub-system.
*/
    int		status, i, is, j, k, wait_result, indx;
    int		keep_cycling;
    int		shm_size;
    char		recd[80];

    struct msg_to_filler_struct msg_buff;

    sigset_t		proc_sigmask;
    struct sigaction	sig_action;
/*============================================================================
*/
    if (suspend_flag != 0) {
      printf ("%s: Suspending ...", Filler_name);
      taskSuspend (0);		/* We've been told to suspend ourself, ..
				**  .. presumably for debug reasons.
				*/
      printf (" suspension ended!\n");
    }
/*============================================================================
**	    Create message queue for receiving requests from clients.
*/
    if (MsgQ_to_filler == NULL) {
      MsgQ_to_filler = msgQCreate (8, sizeof (msg_buff), MSG_Q_FIFO);
      if (MsgQ_to_filler == NULL) {
	printf ("%s -- failed to create MsgQ_to_filler message queue.\n",
			    Filler_name);
	exit (KER__BAD_VALUE);
      }
      if (Dbg_lev1) {
	printf ("%s -- created MsgQ_to_filler message queue.\n", Filler_name);
      }
    }
    while (msgQNumMsgs (MsgQ_to_filler) > 0) {	/* Ensure Q is empty */
      msgQReceive (MsgQ_to_filler, (char *) &msg_buff, sizeof (msg_buff),
		    WAIT_FOREVER);
    }
/*============================================================================
**	    Create message queues for sending replies to servers.
**	    Note: MsgQ_to_server[0] is used for messages to SinqHM-master.
*/
    for (i = 0; i <= MAX_CLIENTS; i++) {
      if (MsgQ_to_server[i] == NULL) {
	MsgQ_to_server[i] = msgQCreate (8, sizeof (msg_buff), MSG_Q_FIFO);
	if (MsgQ_to_server[i] == NULL) {
	  printf ("%s -- failed to create MsgQ_to_server[%d] message queue.\n",
					Filler_name, i);
	  exit (KER__BAD_VALUE);
	}
	if (Dbg_lev1) {
	  printf ("%s -- created MsgQ_to_server[%d] message queue.\n",
					Filler_name, i);
	}
      }
      while (msgQNumMsgs (MsgQ_to_server[i]) > 0) {	/* Ensure Q is empty */
	msgQReceive (MsgQ_to_server[i], (char *) &msg_buff, sizeof (msg_buff),
		    WAIT_FOREVER);
      }
    }
/*============================================================================*/
    Filler_flag = 0;		/* Ensure the communication flag is zero */

    Server_masks[0] = 0x8000;   /* This is our bit in SinqHM_Dsbl_Mask */
    for (i = 1; i <= MAX_CLIENTS; i++) Server_masks[i] = 1 << (i - 1);

    SinqHM_Dsbl_Mask = 0;	/* Start up with DAQ enabled */

    /*
      set up address of fibre optic. This is very board specific!
      The last 3 bytes of this address are set in the programmable logic
      of the mezzanine card. The first byte is the offset of the PCI memory
      space in the processor memory map. Together the address must result 
      in a valid address lying in the region reserved for PCI I/O. The 
      program on the mezzanine card may need updating in order to ensure just
      that.

      Mark Koennecke, February 2002
    */
#ifdef MV2600
    Lwl_fifo = (uint *) 0x80008080;
#else
    Lwl_fifo = (uint *) 0x80810080; /* for MVME1603 boards */ 
#endif
 
    /*
      For the MEN board the pci-to-pci bridge to the mezzanine card
      has to be configured........... 
    */
#ifdef MEN_A012
    printf("Configuring for MEN....\n");
    Lwl_fifo = (uint *) 0x8a200000;
    pciConfigOutWord(0,0x1d,0,0x04,0x0007);
    pciConfigOutWord(0,0x1d,0,0x20,0x8a20);
    pciConfigOutWord(0,0x1d,0,0x22,0x8a20);
#endif

    printf("Value at lwl_fifo = %x, address = %x\n", *Lwl_fifo, Lwl_fifo);

    Lwl_csr  = &Lwl_dummy_csr;		/* Set up address of dummy CSR */
/*============================================================================
**	Define our signal mask first and define an action routine to catch
**	the SIGINT signal our parent will send us when he wants us to exit.
*/
    status = sigemptyset (&proc_sigmask);
    status = sigprocmask (SIG_SETMASK, &proc_sigmask, NULL);

    status = sigemptyset (&sig_action.sa_mask);
    sig_action.sa_handler = catch_int_signal;
    sig_action.sa_flags   = 0;
    if (sigaction (SIGINT, &sig_action, NULL) == -1) {
      getErrno (&My_errno);
      perror ("sigaction error:");
      exit (KER__BAD_VALUE);
    }
/*============================================================================
**	When we can do it, ensure the detector read-out is inhibited and
**	flush out any data in the fibre-optic FIFO.
*/
    *Lwl_csr = 0x0001;	/* This will (maybe) initialise the fibre-optic FIFO. */
    printf("vxWorks thinks it still has %d bytes of memory\n",memFindMax());
	   
    printf("Flushing lwl.....\n");
    lwl_Fifo_Flush ();	/* Flush the fibre-optic FIFO. */

/*============================================================================
**	Initialisation done, release semaphore so that our parent can continue.
*/
    if (Dbg_lev1) printf ("%s -- releasing Sem_Filler semaphore\n",
				    Filler_name);
    is = semGive (Sem_Filler);
    if (Dbg_lev1)
      printf ("%s -- returned from sem release: %d\n", Filler_name, is);
    if (is != OK) {
      printf ("%s -- sem release error\n", Filler_name);
      exit (KER__BAD_VALUE);
    }
    taskDelay ((sysClkRateGet())/2); /* Give parent time to display a message */
/*============================================================================
**		    Make a timer to give occasional status on console
*/
    FillTimer_active = False;
    FillTimer_expired = False;
    if (Hm_mode_NO_STAT != 0) {
      printf ("%s -- display of TSI information suppressed\n", Filler_name);
    }else {
      is = timer_create (CLOCK_REALTIME, NULL, &FillTimerId);
      if (is != 0) {
	printf ("%s -- timer creation failed\n", Filler_name);
      }else {
	is = timer_connect (FillTimerId, SinqHM_filler_timer_handler, 0);
	if (is != 0) {
	  printf ("%s -- failed to connect to timer\n", Filler_name);
	}else {
	  FillerTime.it_value.tv_sec = 2;	    /* Set a 2 second timer */
	  FillerTime.it_value.tv_nsec = 0;
	  FillerTime.it_interval.tv_sec = 0;
	  FillerTime.it_interval.tv_nsec = 0;
	  is = timer_settime (FillTimerId, ~TIMER_ABSTIME, &FillerTime, NULL);
	  if (is != 0) {
	    printf ("%s -- failed to set timer\n", Filler_name);
	  }
	  FillTimer_active  = True;
	}
      }
    }
/*============================================================================
**		    Loop taking data and waiting for requests from clients.
*/
    for (keep_cycling = True; keep_cycling;) {
      if (SinqHM_Dsbl_Mask == 0) {
	SinqHM_filler_daq ();	/* Start data acquisition ..
				** .. We return here whenever Filler_flag ..
				** .. indicates that a message is waiting ..
				** .. to be processed.
				*/
      }
      is = msgQReceive (MsgQ_to_filler, (char *) &msg_buff, sizeof (msg_buff),
			    WAIT_FOREVER);
      if (is <= 0) {
	printf ("%s -- error status from msgQReceive: %d\n", Filler_name, is);
	exit (KER__BAD_VALUE);
      }
      if (Dbg_lev1) printf ("%s -- received a message of %d bytes!\n",
					Filler_name, is);
      Filler_flag = 0;
      indx = msg_buff.u.uu.index;
      switch (msg_buff.u.uu.cmnd) {
       case DAQ__EXIT:
	keep_cycling = False;	    /* Break out of the loop */
	break;
       case DAQ__CLR:
	SinqHM_Dsbl_Mask &= (~Server_masks[indx]);  /* Clear user's mask bit. */
	break;
       case DAQ__GO:
	SinqHM_Dsbl_Mask &= (~Server_masks[0]);	    /* Clear our mask bit */
	break;
       case DAQ__INH:
	SinqHM_Dsbl_Mask |= Server_masks[indx];	    /* Set user's mask bit */
	break;
       case DAQ__STOP:
	SinqHM_Dsbl_Mask |= Server_masks[0];	    /* Set our mask bit. */
	break;
      }
      msg_buff.u.uu.new_mask = SinqHM_Dsbl_Mask;    /* Put new mask in reply */
      is = msgQSend (MsgQ_to_server[indx],	    /* Tell user to continue */
			(char *) &msg_buff,
			sizeof (msg_buff),
			WAIT_FOREVER, MSG_PRI_NORMAL);
      if (is != OK) {
	printf ("%s -- error status from msgQSend: %d\n", Filler_name, is);
	exit (KER__BAD_VALUE);
      }
    }
    exit (KER__SUCCESS);
  }
/*======================================= End of SinqHM_srv_filler.c ========*/




