#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 ========*/