#define IDENT "1D02" /* ** +--------------------------------------------------------------+ ** | 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_main.c ** ** Author . . . . . . . . . . : D. Maden ** Date of creation . . . . . . : Oct 1996 ** ** Updates: ** 1A01 1-Oct-1996 DM Initial version. ** 1B01 16-Jul-1997 DM Flush fibre-optic FIFO on SQHM_ZERO and SQHM_WRITE. ** 1C01 24-Jun-1998 DM Add TOF support. ** 1C06 10-Aug-1999 DM Add instrument dependent conditional code. **--------------------------------------------------------------------------- ** SinqHM_srv_main.c is the main program of a SINQ Histogram Memory process ** which will run in a front-end processor and perform the necessary ** operations for a SINQ multi-detector. ** ** Communication between SinqHM_srv and the client is via TCP/IP protocol. ** ** To compile and link this program for VxWorks on PSS123, use: ** ccvx '-DINST=""' SinqHM_srv_main.c ccvx '-DINST=""' SinqHM_srv_routines.c ccvx '-DINST=""' SinqHM_srv_filler.c ccvx '-DINST=""' SinqHM_srv_server.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 ** and ** = DMC, SANS, FOCUS, HRPT, TRICS or POLDI ldppc -o SinqHM_srv.o -r SinqHM_srv_main.o \ SinqHM_srv_routines.o \ SinqHM_srv_filler.o \ SinqHM_srv_server.o ** and, on the target, ** ** -> ld < /home/pss123/aco/maden/wind/SinqHM/SinqHM_srv.o ** -> taskSpawn "SinqHM_srv", 100, 8, 20000, SinqHM_srv, ** ^ ** | ** default = 2400 ------+ ** **==================================================================== */ #include "vxWorks.h" #include "taskLib.h" #include "msgQLib.h" #include "sockLib.h" #include #include #include #include #include #include #include #include #include #include #include #include /* Get POSIX signal definitions. */ #include #include /* Get POSIX mem mgmnt definitions. */ #include /* Get POSIX wait definitions. */ /* **==================== Global Definitions ===================================== */ #include "SinqHM_def.h" #include "SinqHM_gbl.h" /* **============================================================================= ** Local routines. ** ** None */ /*============================================================================== ** Main line program ** ------------------ **============================================================================*/ int SinqHM_srv (int port, int use_level_gen, char *base_addr, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int suspend) { /*============================================================================*/ struct req_buff_struct req_buff; struct rply_buff_struct rply_buff; int i, j, is, status, cntr; int keep_going = OK; int bytes_to_come, n_bytes_got; char *p_addr; int cl_port; int do_send; int cnct_skt; /* Connection socket */ int rw_skt; /* Read/write socket */ struct sockaddr_in lcl_sockname; struct sockaddr_in rmt_sockname; int rmt_sockname_len; int pkt_size; time_t timer; sigset_t proc_sigmask; struct sigaction sig_action; /*============================================================================ */ if (suspend != 0) { printf ("\nSinqHM_srv: Suspending ...\n"); taskSuspend (0); /* We've been told to suspend ourself, .. ** .. presumably for debug reasons. */ printf ("\nSinqHM_srv: Suspension ended!\n"); } /*============================================================================ ** Perform the initialisation of global variables ... */ StrJoin (Instr_name, sizeof (Instr_name), INST, ""); /* Save the instr. ** name in a global */ StrJoin (Def_ident, sizeof (Def_ident), SINQHM_DEF_ID, ""); StrJoin (Sqhm_main_ident, sizeof (Sqhm_main_ident), IDENT, ""); StrJoin (Sqhm_main_date, sizeof (Sqhm_main_date), __DATE__, ", "); StrJoin (Sqhm_main_date, sizeof (Sqhm_main_date), Sqhm_main_date, __TIME__); SinqHM_server_setup_id (); SinqHM_filler_setup_id (); SinqHM_routines_setup_id (); time (&Sqhm_start_time); /* Initialise the start time */ StrJoin (Tsk_name[0], sizeof (Tsk_name[0]), taskName (get_pid ()), ""); Dbg_mask = 0; Dbg_lev0 = 0; Dbg_lev1 = 1; Dbg_lev2 = 0; Dbg_lev3 = 0; Cfgn_done = 0; /* Force a configuration before we can do anything. */ free_HM_memory (NULL); /* Release memory (possibly) in case .. ** .. of a restart of the program */ Parent_pid = get_pid (); Filler_pid = 0; for (i = 0; i <= MAX_CLIENTS; i++) { Child_pid[i] = 0; Child_exit_status[i] = 0; } if (Sem_Filler == NULL) { Sem_Filler = semBCreate (SEM_Q_FIFO, SEM_FULL); } if (Sem_Server == NULL) { Sem_Server = semBCreate (SEM_Q_FIFO,SEM_FULL); } /* ** Debug hint - set Use_sem_tmo to zero to disable semaphore time-outs ** during debug sessions. This will stop FILLER falling off. */ Sem_tmo = 10; /* 10 second time-out by default */ Use_sem_tmo = 0; setupLevelGenerator (use_level_gen, base_addr); /*============================================================================ ** Clear the process signal mask to let in all signals (actually, on ** PPC VxWorks this seems to cause all signals to get ignored!) and then ** declare action routine for SIGUSR1. Our children signal with SIGUSR1 ** just before they exit in a more or less controlled manner. If the ** child gets deleted from the shell, it will not signal. */ Cnt_SIGUSR1 = 0; status = sigemptyset (&proc_sigmask); status = sigprocmask (SIG_SETMASK, &proc_sigmask, NULL); status = sigemptyset (&sig_action.sa_mask); sig_action.sa_handler = catch_signal; sig_action.sa_flags = 0; if (sigaction (SIGUSR1, &sig_action, NULL) == -1) { getErrno (&My_errno); perror ("sigaction error:"); exit (0); } /*============================================================================ ** Get a port number to use. If the argument "port" is not ** a valid port number (not in range 128 to 32767), use PORT_BASE. */ Port_base = PORT_BASE; if ((port >= 128) && (port < 32768)) Port_base = port; /*============================================================================ ** Create a TCP/IP socket for receiving connection requests, bind it and ** set it to listen. */ cnct_skt = socket (AF_INET, SOCK_STREAM, 0); if (cnct_skt == -1) failInet_port ("\nhmRoot%d -- Cnct-Socket socket error", Port_base); status = 1; setsockopt(cnct_skt, SOL_SOCKET, SO_REUSEADDR, &status, sizeof(int)); lcl_sockname.sin_family = AF_INET; lcl_sockname.sin_port = htons (Port_base); lcl_sockname.sin_addr.s_addr = 0; status = bind (cnct_skt, (struct sockaddr *) &lcl_sockname, sizeof (lcl_sockname)); if (status != 0) failInet_port ("\nhmRoot%d -- Cnct-Socket bind error", Port_base); status = listen (cnct_skt, 5); if (status != 0) failInet_port ("\nhmRoot%d -- Cnct-Socket listen error", Port_base); /* ** Clients must now connect to the Connect-port and send either a ** connect, configure, deconfigure, status or exit request. A ** successful configure request must precede any connection request. ** ** When a configure request arrives, the histogram data structures are ** initialised, the histogram filler process (FILLER) is spawned and ** connection requests are enabled. A status reply is sent to the ** client and the connection closed. ** ** When a connection request arrives, a child will be spawned to ** handle the connection. The child will be told which port to use ** and he will release a semaphore when the port is ready. The parent ** then sends the client a reply to tell him which port to use. The ** connection is then closed to await further connections. */ setup_inet_info (Inet_host, sizeof (Inet_host), /* Find out who we are */ Inet_addr, sizeof (Inet_addr)); printf ("\n%s: Program Ident = \"%s\". Started on %s (%s).\n", Tsk_name[0], IDENT, Inet_host, Inet_addr); printf ("%s: Protocol Ident = \"%s\"\n", Tsk_name[0], SINQHM_DEF_ID); #ifndef INST #error Define the target instrument via the symbol "INST"! #endif if (strcmp (INST, "DMC") == 0) { printf ("%s: Instrument = \"%s\"\n", Tsk_name[0], "DMC"); Lwl_hdr_daq_mask = LWL_HDR_NRL_MASK; Lwl_hdr_daq_soll = 0; }else if (strcmp (INST, "SANS") == 0) { printf ("%s: Instrument = \"%s\"\n", Tsk_name[0], "SANS"); Lwl_hdr_daq_mask = LWL_HDR_NRL_MASK; Lwl_hdr_daq_soll = 0; }else if (strcmp (INST, "FOCUS") == 0) { /* Lwl_hdr_daq_mask = LWL_HDR_NRL_MASK | LWL_HDR_SYNC2_MASK; Lwl_hdr_daq_soll = 0; */ Lwl_hdr_daq_mask = 0x00f00000; Lwl_hdr_daq_soll = 0x00200000; printf ("%s: Instrument = \"%s\"\n", Tsk_name[0], "FOCUS"); }else if (strcmp (INST, "HRPT") == 0) { printf ("%s: Instrument = \"%s\"\n", Tsk_name[0], "HRPT"); Lwl_hdr_daq_mask = LWL_HDR_SYNC0_MASK | LWL_HDR_SYNC2_MASK; Lwl_hdr_daq_soll = LWL_HDR_SYNC2_MASK; }else if (strcmp (INST, "TRICS") == 0) { printf ("%s: Instrument = \"%s\"\n", Tsk_name[0], "TriCS"); /* Lwl_hdr_daq_mask = LWL_HDR_NRL_MASK | LWL_PSD_PWF; Lwl_hdr_daq_soll = 0; */ Lwl_hdr_daq_mask = 0x00f00000; Lwl_hdr_daq_soll = 0x00e00000; }else if (strcmp(INST,"AMOR") == 0) { printf ("%s: Instrument = \"%s\"\n", Tsk_name[0], "AMOR"); Lwl_hdr_daq_mask = LWL_HDR_NRL_MASK | LWL_PSD_PWF; Lwl_hdr_daq_soll = 0; /* Lwl_hdr_daq_mask = 0x00f00000; Lwl_hdr_daq_soll = 0x00600000; */ }else if (strcmp (INST, "POLDI") == 0) { printf ("%s: Instrument = \"%s\"\n", Tsk_name[0], "POLDI"); Lwl_hdr_daq_mask = LWL_HDR_NRL_MASK; Lwl_hdr_daq_soll = 0; printf ("%s: Warning -- Lwl_hdr_daq_mask and Lwl_hdr_daq_soll are " "provisional!\n", Tsk_name[0]); }else { printf ("%s: Instrument is not defined\n", Tsk_name[0]); Lwl_hdr_daq_mask = LWL_HDR_NRL_MASK; Lwl_hdr_daq_soll = 0; } printf ("%s: Lwl_hdr_daq_mask = 0x%08x", Tsk_name[0], Lwl_hdr_daq_mask); if ((Lwl_hdr_daq_mask & LWL_HDR_NRL_MASK) != 0) printf (" NRL"); if ((Lwl_hdr_daq_mask & LWL_HDR_SYNC3_MASK) != 0) printf (" SYNC3"); if ((Lwl_hdr_daq_mask & LWL_HDR_SYNC2_MASK) != 0) printf (" SYNC2"); if ((Lwl_hdr_daq_mask & LWL_HDR_SYNC1_MASK) != 0) printf (" SYNC1"); if ((Lwl_hdr_daq_mask & LWL_HDR_SYNC0_MASK) != 0) printf (" SYNC0"); printf ("\n%s: Lwl_hdr_daq_soll = 0x%08x", Tsk_name[0], Lwl_hdr_daq_soll); if ((Lwl_hdr_daq_soll & LWL_HDR_NRL_MASK) != 0) printf (" NRL"); if ((Lwl_hdr_daq_soll & LWL_HDR_SYNC3_MASK) != 0) printf (" SYNC3"); if ((Lwl_hdr_daq_soll & LWL_HDR_SYNC2_MASK) != 0) printf (" SYNC2"); if ((Lwl_hdr_daq_soll & LWL_HDR_SYNC1_MASK) != 0) printf (" SYNC1"); if ((Lwl_hdr_daq_soll & LWL_HDR_SYNC0_MASK) != 0) printf (" SYNC0"); printf ("\n"); while (keep_going == OK) { rmt_sockname_len = sizeof (rmt_sockname); rw_skt = accept (cnct_skt, (struct sockaddr *) &rmt_sockname, &rmt_sockname_len); if (rw_skt == -1) { getErrno (&My_errno); failInet_port ("\nhmRoot%d -- Cnct-Socket accept error", Port_base); /* No return */ } Rw_bytes_got = 0; Rw_bytes_put = 0; p_addr = inet_ntoa (rmt_sockname.sin_addr); cl_port = ntohs (rmt_sockname.sin_port); printf ("\n%s: Connected to Host %s, Port %d.\n", Tsk_name[0], p_addr, cl_port); bytes_to_come = sizeof (req_buff); /* Read a command */ p_addr = (char *) &req_buff; while (bytes_to_come > 0) { n_bytes_got = recv (rw_skt, p_addr, bytes_to_come, 0); if (n_bytes_got <= 0) break; Rw_bytes_got += n_bytes_got; bytes_to_come -= n_bytes_got; p_addr += n_bytes_got; } if (Cnt_SIGUSR1 > 0) { /* Have any children exited? */ if (Dbg_lev0) printf ("hmRoot%d: Cleaning up children ...", Port_base); cleanup_children (); /* Yes, update our database. */ if (Dbg_lev0) printf ("\n ... cleanup of children done.\n"); } if (n_bytes_got < 0) { printf ("\007" "%s -- R/W-Socket recv error\n", Tsk_name[0]); printf ("%s -- Connection to %s will be closed.\n", Tsk_name[0], inet_ntoa (rmt_sockname.sin_addr)); }else if (n_bytes_got == 0) { printf ("\007" "%s -- no command received!\n", Tsk_name[0]); printf ("%s -- Connection to %s will be closed.\n", Tsk_name[0], inet_ntoa (rmt_sockname.sin_addr)); }else if (n_bytes_got != sizeof (req_buff)) { printf ("\007" "%s -- command packet has wrong number of bytes:" " %d instead of %d\n", Tsk_name[0], n_bytes_got, sizeof (req_buff)); printf ("%s -- Connection to %s will be closed.\n", Tsk_name[0], inet_ntoa (rmt_sockname.sin_addr)); }else if (ntohl (req_buff.bigend) != 0x12345678) { printf ("\007" "%s -- big-endian/little-endian problem!\n" " Buffer received in non-network byte order!\n", Tsk_name[0]); }else { do_command (0, rw_skt, 4096, &req_buff, &rply_buff); } close (rw_skt); if (ntohl (req_buff.cmnd) == SQHM_EXIT) keep_going = !OK; } close (cnct_skt); exit (KER__SUCCESS); } /*========================================= End of SinqHM_srv_main.c ========*/