diff --git a/sinqhm/SinqHM_srv_routines.c b/sinqhm/SinqHM_srv_routines.c new file mode 100755 index 00000000..3ffaed88 --- /dev/null +++ b/sinqhm/SinqHM_srv_routines.c @@ -0,0 +1,3320 @@ +#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. +**--------------------------------------------------------------------------- +** 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* +**==================== 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__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: + printf ("\nchk_config_alloc: " + "histogramming mode SQHM__HM_PSD is not yet supported.\n"); + rply_status_setup (reply, KER__BAD_VALUE, 0, "Unsupported hist mem mode"); + 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_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], status); + 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); + } + } +/* +**--------------------------------------------------------------------------*/ + 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, offs; + 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. +*/ + 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__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; + /*-----------------------------------------------------------*/ + 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. + */ + 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; + + 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 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 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; istatus = 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 */ + + 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; + + getErrno (&my_errno); + printf ("### Internet Error ###\n"); + printf (" ### errno = %d.\n", my_errno); + perror (text); + 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 + */ + free (Hist_base_addr); + 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. +** 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 = 1000; /* 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; + } +/* +**--------------------------------------------------------------------------*/ + 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 is not NULL, 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 ========*/