#define	    ident	    "1A07"
#define	    Active_Server   1
#define	    Blink_On	    0

#ifdef __DECC
#pragma	    module	    EL734	ident
#endif
/*
** +--------------------------------------------------------------+
** |                  Paul Scherrer Institute                     |
** |                     SINQ Project				  |
** |                                                              |
** | 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.|
** +--------------------------------------------------------------+
**
** Link_options - Here is the Linker Option File
**!$!
**!$! To build on LNSA09 ...
**!$!   $  build_cc_select :== decc
**!$!	$  import tasmad
**!$!	$  def/job deltat_c_tlb sinq_c_tlb
**!$!   $  bui ud0:[maden.motor]el734 debug
**!$!
**!$! To build on PSICL0 ...
**!$!	$ build_cc_select :== decc
**!$!	$ set default usr_scroot:[maden]
**!$!	$ copy lnsa09::ud0:[maden.motor]el734.c     []
**!$!	$ copy lnsa09::tasmad_disk:[mad.lib]sinq_dbg.olb []
**!$!	$ copy lnsa09::tasmad_disk:[mad.lib]sinq_c.tlb []
**!$!	$ def/job sinq_olb   usr_scroot:[maden]sinq_dbg.olb
**!$!	$ def/job sinq_c_tlb usr_scroot:[maden]sinq_c.tlb
**!$!	$ def/job deltat_c_tlb sinq_c_tlb
**!$!	$ bui el734 debug
**!$!
**!$	if p1 .eqs. "DEBUG" then dbg1 := /debug
**!$	if p1 .eqs. "DEBUG" then dbg2 := _dbg
**!$	link 'dbg1'/exe=cpt:[exe]el734'dbg2'.exe sys$input/options
**!	    el734
**!	    sinq_olb/lib
**!	    sys$share:decw$xmlibshr12.exe/share
**!	    sys$share:decw$xtlibshrr5.exe/share
**!$	purge/nolog cpt:[exe]el734'dbg2'.exe
**!$	exit
**!$!
** Link_options_end
**
**	Building on Alpha Digital Unix:
**
**	    setenv TAS_BASE ~maden/tasmad
**	    source $TAS_BASE/tasmad.setup
**	    rcp -p "lnsa09:tas_src:[utils]el734.c" \
**			$TAS_SRC/utils/el734.c
**	    cc -std -g -o $TAS_BIN/el734	    \
**			-I$TAS_INC		    \
**			$TAS_SRC/utils/el734.c	    \
**			-L$TAS_LIB -lsinq -lXm -lXt -lX11
**+
** Resource File:	decw$user_defaults:SinQ_rc.dat
** -------------     or $HOME/SinQ_rc
**
**	*el734Host:		Undefined     <-- the name of the server
**	*el734Port:		4000	      <-- the port of the server
**	*el734Chan:		0	      <-- the RS232C channel of EL734
**	*el734Motor:		1	      <-- the motor number (1..12)
**  plus
**	EL734.msecPoll:	       1000	<-- 1.0 sec updates
**	EL734.scaleWidth:	800	<-- scale width
**---------------------------------------------------------------------------
** Module Name  . . . . . . . . : [...MOTOR]EL734.C
**
** Author   . . . . . . . . . . : D. Maden
** Date of creation . . . . . . : Nov 1994
**
** Purpose
** =======
**    EL734 is a test program for using with the SINQ VME/RS-232-C
**    Motor Controller, EL734.
**
** Use:
** ===
**   1)	Ensure that EL734_SRV is running on the appropriate computer.
**
**   2)	Define a foreign command and the workstation where the display
**	is to appear via the commands:
**
**	    $ motor :== $cpt:[exe]el734
**	    $ set display /create /transport=tcpip /node=pswxxx
**
**   3) Check the resource file DECW$USER_DEFAULTS:SinQ_rc.dat on VMS or
**			        $HOME/SinQ_rc on Digital-UNIX for the
**	required resources (or specify them as flags - see below).
**
**   4)	Ensure that the Session Manager security is set up to allow windows
**	to be created on one's workstation.
**
**   5)	Issue the command:	$ motor [-options]
**
**	Options are:			Equivalent Resource Name    Default
**	-------				------------------------    -------
**	    -host  <server-name>	 *el734Host		    None
**	    -port  <port-number>	 *el734Port		    4000
**	    -chan  <chan-number>	 *el734Chan		    None
**	    -poll  <poll-delay-in-msec>	 EL734.msecPoll		    1000
**	    -m     <motor-number>	 EL734.el734Motor	    None
**	    -scale <width>		 EL734.scaleWidth:	     800
**	where
**	    <motor-number> must be in the range 1 to 12. It is the motor which
**			    will be controlled.
**	    <width> specifies the width of the displayed scale in pixels.
**
**	If specified, a flag takes precedence over the resource file.
**
** Updates:
**  1A01 20-Dec-1994 DM.	Initial version.
**-
**====================================================================
*/
#include    <stdlib.h>
#include    <stdio.h>
#include    <stdarg.h>
#include    <netdb.h>
#include    <errno.h>

#ifdef	__VMS
#include    <signal.h>
#include    <unixio.h>
#else
#include    <unistd.h>
#endif

#include    <netinet/in.h>
#include    <arpa/inet.h>
#include    <math.h>
#include    <sys/socket.h>

#include <X11/Intrinsic.h>
#include <Xm/Xm.h>
#include <Xm/ArrowB.h>
#include <Xm/CascadeB.h>
#include <Xm/DrawnB.h>
#include <Xm/Form.h>
#include <Xm/Frame.h>
#include <Xm/Label.h>
#include <Xm/MainW.h>
#include <Xm/PushB.h>
#include <Xm/RowColumn.h>
#include <Xm/PanedW.h>
#include <Xm/Scale.h>
#include <Xm/ScrolledW.h>
#include <Xm/Separator.h>
/*
**--------------------------------------------------------------------------
**			Define global structures and constants.
*/
#include    <sinq_prototypes.h>
#include    <el734_def.h>
#include    <rs232c_def.h>

#define TMO	        50	/* Units are 0.1 secs */
#define MAX_ARGS	20

  enum	Menu_Type {CASCADE, PULL_DOWN, SEPARATOR};

  enum CmndFmts   {ONE_INT, ONE_HEX, ONE_STRING, TWO_INT, TWO_STRING, NO_MORE};

  typedef struct {
    int   msec_timer;		    /* Poll rate in msec */
    char* vme_motor_host;	    /* Name         of Motor Server */
    int   vme_motor_port;	    /* Port  Number of Motor Server */
    int   vme_motor_number;	    /* Motor Number of Interest */
    int   v24_chan;		    /* Motor Number of Interest */
    int   scale_width;		    /* Scale width */
  } ApplicationData;
/*
**-------------------------------------------------------------
**	Global Variables
*/
  ApplicationData AppData;

  XtAppContext App_context;	/* application context;	*/

  static XtResource	Resources[] = {
       {"el734Host", "El734Host", XmRString, sizeof(String),
			XtOffsetOf (ApplicationData, vme_motor_host),
			XmRString, "Undefined"},
       {"el734Port", "El734Port", XmRInt, sizeof(int),
			XtOffsetOf (ApplicationData, vme_motor_port),
			XmRImmediate, (XtPointer) 0},
       {"el734Chan", "El734Chan", XmRInt, sizeof(int),
			XtOffsetOf (ApplicationData, v24_chan),
			XmRImmediate, (XtPointer) 0xffff},
       {"el734Motor", "El734Motor", XmRInt, sizeof(int),
			XtOffsetOf (ApplicationData, vme_motor_number),
			XmRImmediate, (XtPointer) 0},
       {"scaleWidth", "ScaleWidth", XmRInt, sizeof(int),
			XtOffsetOf (ApplicationData, scale_width),
			XmRImmediate, (XtPointer) 800},
       {"msecPoll", "MsecPoll", XmRInt, sizeof(int),
			XtOffsetOf (ApplicationData, msec_timer),
			XmRImmediate, (XtPointer) 1000},
  };
  static XrmOptionDescRec	OpTable[] = {
       {"-host",  ".el734Host",	    XrmoptionSepArg, (XPointer) NULL},
       {"-port",  ".el734Port",	    XrmoptionSepArg, (XPointer) NULL},
       {"-chan",  ".el734Chan",	    XrmoptionSepArg, (XPointer) NULL},
       {"-m",	  ".el734Motor",    XrmoptionSepArg, (XPointer) NULL},
       {"-motor", ".el734Motor",    XrmoptionSepArg, (XPointer) NULL},
       {"-poll",  ".msecPoll",      XrmoptionSepArg, (XPointer) NULL},
       {"-scale", ".scaleWidth",    XrmoptionSepArg, (XPointer) NULL},
    };

  static int		Motor;
  static int		Scale_width;
  static int		Msg_seq = 1234;

  struct Motor_State	    Old_Mot_state;
  struct Motor_State	    Mot_state;
  struct RS__RespStruct	    Respon_buff;

  int			Mot_factor;
  float			Mot_pos_ist;
  float			Mot_pos_soll;
  float			Mot_inertia_tol;
  float			Mot_ref_param;
  float			Mot_null_pt;
  float			Mot_lo_lim;
  float			Mot_hi_lim;

  float			Mot_scale_middle;
  int			Mot_is_on_left;

  int			Cnct_skt = 0;
  char			Err_text[80];

  Widget    Wtop_level;		/*  Top window	*/

  Widget    Wquit_cascade;	/*  Quit   CascadeButton	*/
  Widget    Wslct_cascade;	/*  Select CascadeButton	*/
  Widget    Whelp_cascade;	/*  Help   CascadeButton	*/

  Widget    Wupdt_button;	/*  Update   Push Button */
  Widget    Wgo_button;		/*  Go	     Push Button */
  Widget    Wstop_button;	/*  Stop     Push Button */

  Widget    Wmot_cascade;	/*  Motor Selection CascadeButton */

  Widget    Wlbl_state;		/*  Status Label */

  Widget    Label_name;
  Widget    Label_lo_lim;
  Widget    Label_hi_lim;
  Widget    Label_ist;
  Widget    Label_soll;
  Widget    Scale_soll;
  Widget    Scale_ist;
  Widget    Label_msr;
  Widget    Label_ss;
  Widget    Label_stats;
  Widget    Label_fd;
  Widget    Label_fm;
  Widget    Label_d;
  Widget    Label_e;
  Widget    Label_f;
  Widget    Label_g;
  Widget    Label_j;
  Widget    Label_k;
  Widget    Label_l;
  Widget    Label_m;
  Widget    Label_q;
  Widget    Label_t;
  Widget    Label_w;
  Widget    Label_v;
  Widget    Label_out;
  Widget    Label_in;
  Widget    Label_z;
  Widget    DrawnBut, DrawnButFrame;

  int	    Scale_is_khz;
  int	    Scale_max;
  float	    Thresh_cntr_thresh;
  float	    Thresh_cntr_rate;

  int	    Nargs;		/* Argument list variables - these must ..  */
  Arg	    Args[MAX_ARGS];	/* .. only be used as temporary variables.  */

  enum CmndFmts   Cmnd_fmt[] = {
			ONE_STRING, ONE_INT,    TWO_INT,    TWO_INT,
			ONE_STRING, ONE_INT,    ONE_INT,    ONE_INT,
			TWO_STRING, ONE_INT,	ONE_INT,    ONE_INT,
			ONE_INT,    ONE_STRING,	ONE_INT,    ONE_STRING,
			ONE_INT,    ONE_INT,	ONE_STRING, ONE_INT,
			ONE_INT,    ONE_INT,	NO_MORE};

  size_t    Offsets[] = {
		    OffsetOf (struct Motor_State, name[0]),
		    OffsetOf (struct Motor_State, dec_pt),
		    OffsetOf (struct Motor_State, enc_factor[0]),
		    OffsetOf (struct Motor_State, enc_factor[1]),
		    OffsetOf (struct Motor_State, mot_factor[0]),
		    OffsetOf (struct Motor_State, mot_factor[1]),
		    OffsetOf (struct Motor_State, inertia_tol[0]),
		    OffsetOf (struct Motor_State, ramp),
		    OffsetOf (struct Motor_State, loop_mode),
		    OffsetOf (struct Motor_State, slow_hz),
		    OffsetOf (struct Motor_State, lims[0][0]),
		    OffsetOf (struct Motor_State, lims[1][0]),
		    OffsetOf (struct Motor_State, fast_hz),
		    OffsetOf (struct Motor_State, ref_mode),
		    OffsetOf (struct Motor_State, backlash),
		    OffsetOf (struct Motor_State, pos_tol),
		    OffsetOf (struct Motor_State, ref_param[0]),
		    OffsetOf (struct Motor_State, is_sided),
		    OffsetOf (struct Motor_State, null_pt[0]),
		    OffsetOf (struct Motor_State, ac_par),
		    OffsetOf (struct Motor_State, enc_circ),
		    OffsetOf (struct Motor_State, set_real[0]),
		    OffsetOf (struct Motor_State, ac_state),
		    OffsetOf (struct Motor_State, out),
		    OffsetOf (struct Motor_State, in)
		    };
/*
**---------------------------------------------------------------------------
**			DecodeFloats	- decode the fl. pt. strings.
*/
  int	DecodeFloats () {
/*	=============
*/
    int		status, i;
    static int	do_warn_dec_pt	 = True;
    static int	do_warn_pos_real = True;
    static int	do_warn_pos_set  = True;

    status = True;	/* Assume all will be OK    */

    if (sscanf (Mot_state.pos_real, "%f", &Mot_pos_ist) != 1)
					status = False;
    if (sscanf (Mot_state.inertia_tol, "%f", &Mot_inertia_tol) != 1)
					status = False;
    if (sscanf (Mot_state.lims[0], "%f", &Mot_lo_lim) != 1)
					status = False;
    if (sscanf (Mot_state.lims[1], "%f", &Mot_hi_lim) != 1)
					status = False;
    if (sscanf (Mot_state.ref_param, "%f", &Mot_ref_param) != 1)
					status = False;
    if (sscanf (Mot_state.null_pt, "%f", &Mot_null_pt) != 1)
					status = False;
    if (sscanf (Mot_state.set_real, "%f", &Mot_pos_soll) != 1)
					status = False;
    if (Mot_lo_lim > Mot_hi_lim) {
      sscanf (Mot_state.lims[1], "%f", &Mot_lo_lim);
      sscanf (Mot_state.lims[0], "%f", &Mot_hi_lim);
    }
    if ((Mot_pos_ist < Mot_lo_lim) || (Mot_hi_lim < Mot_pos_ist)) {
      if (do_warn_pos_real) {
        printf ("\007Warning -- actual position is outside low/high limits\n");
        printf ("         Low/actual/high are %f, %f, %f.\n",
			Mot_lo_lim, Mot_pos_ist, Mot_hi_lim);
	Mot_pos_ist = (Mot_lo_lim + Mot_hi_lim)/2.0;
        printf ("         Actual position will be displayed as %f.\n",
			Mot_pos_ist);
        do_warn_pos_real = False;
      }
    }else {
      do_warn_pos_real = True;
    }
    if ((Mot_pos_soll < Mot_lo_lim) || (Mot_hi_lim < Mot_pos_soll)) {
      if (do_warn_pos_set) {
        printf ("\007Warning -- set position is outside low/high limits\n");
        printf ("         Low/set/high are %f, %f, %f.\n",
			Mot_lo_lim, Mot_pos_soll, Mot_hi_lim);
	Mot_pos_soll = (Mot_lo_lim + Mot_hi_lim)/2.0;
        printf ("         Set position will be displayed as %f.\n",
			Mot_pos_soll);
	do_warn_pos_set = False;
      }
    }else {
      do_warn_pos_set = True;
    }
    if ((Mot_state.dec_pt < 0) || (6 < Mot_state.dec_pt)) {
      if (do_warn_dec_pt) {
        printf ("\007Warning -- number of decimal digits is invalid.\n");
        printf ("         Low/value/high are %d, %d, %d.\n",
			0, Mot_state.dec_pt, 6);
	Mot_state.dec_pt = 2;
        printf ("         A value of %d will be assumed.\n", Mot_state.dec_pt);
	do_warn_dec_pt = False;
      }
    }else {
      do_warn_dec_pt = True;
    }
    Mot_factor = 1;
    for (i = 0; i < Mot_state.dec_pt; i++) Mot_factor = Mot_factor * 10;

    return status;
  }
/*
**---------------------------------------------------------------------------
**			EncodeSS	- encode the SS flags into text.
*/
  void	EncodeSS (char *text, int ss) {
/*	========
*/
    int	    len;

    if (ss == 0) {
      sprintf (text, "Flags, SS = 0");
    }else if ((ss & ~(0x3f)) != 0) {
      sprintf (text, "Flags, SS = ??");
    }else {
      sprintf (text, "Flags, SS = %#x ", ss);
      if ((ss & 0x20) != 0) strcat (text, "LSX/");
      if ((ss & 0x10) != 0) strcat (text, "LS2/");
      if ((ss & 0x08) != 0) strcat (text, "LS1/");
      if ((ss & 0x04) != 0) strcat (text, "STP/");
      if ((ss & 0x02) != 0) strcat (text, "CCW/");
      if ((ss & 0x01) != 0) strcat (text, "HLT/");
      len = strlen (text);
      text[len-1] = '\0';
    }
    return;
  }
/*
**---------------------------------------------------------------------------
**			EncodeMSR	- encode the MSR flags into text.
*/
  void	EncodeMSR (char *text,	int text_len,
/*	=========
*/				int msr,
				int ored_msr,
				int fp_cntr,
				int fr_cntr) {
    int	    len;
    char    my_text[132];
    char    my_text_0[32];

    if (msr == 0) {
      ored_msr = ored_msr & ~(MSR__BUSY);	    /* Zero "Busy" bit */
      if (ored_msr == MSR__OK) {
        StrJoin (text, text_len, "Status, MSR = Idle. Positioned OK.", "");
      }else {
        if ((ored_msr & MSR__OK) != 0) {
          StrJoin (text, text_len, "Status, MSR = Idle. Positioned OK. ", "");
        }else {
          StrJoin (text, text_len, "Status, MSR = Idle. ", "");
	}
	if ((ored_msr & MSR__REF_OK) != 0) {
	  StrJoin (my_text, sizeof (my_text), text, "");
	  StrJoin (text, text_len, my_text, "Ref. Pos'n OK. ");
	}
	if ((ored_msr & MSR__LIM_ERR) != 0) {
	  StrJoin (my_text, sizeof (my_text), text, "");
	  StrJoin (text, text_len, my_text, "Limit Switch Problem. ");
	}
	if ((ored_msr & MSR__AC_FAIL) != 0) {
	  StrJoin (my_text, sizeof (my_text), text, "");
	  StrJoin (text, text_len, my_text, "Air-Cushion Error. ");
	}
	if ((ored_msr & MSR__REF_FAIL) != 0) {
	  StrJoin (my_text, sizeof (my_text), text, "");
	  StrJoin (text, text_len, my_text, "Ref. Pos'n Fail. ");
	}
	if ((ored_msr & MSR__POS_FAIL) != 0) {
	  StrJoin (my_text, sizeof (my_text), text, "");
	  StrJoin (text, text_len, my_text, "Pos'n Fail. ");
	}
	if ((ored_msr & MSR__POS_FAULT) != 0) {
	  StrJoin (my_text, sizeof (my_text), text, "");
	  if (fp_cntr == 1) {
	    StrJoin (text, text_len, my_text, "1 Pos'n Fault. ");
	  }else {
	    sprintf (my_text_0, "%d Pos'n Faults. ", fp_cntr);
	    StrJoin (text, text_len, my_text, my_text_0);
	  }
	}
	if ((ored_msr & MSR__RUN_FAIL) != 0) {
	  StrJoin (my_text, sizeof (my_text), text, "");
	  StrJoin (text, text_len, my_text, "Run Fail. ");
	}
	if ((ored_msr & MSR__RUN_FAULT) != 0) {
	  StrJoin (my_text, sizeof (my_text), text, "");
	  if (fr_cntr == 1) {
	    StrJoin (text, text_len, my_text, "1 Run Fault. ");
	  }else {
	    sprintf (my_text_0, "%d Run Faults. ", fr_cntr);
	    StrJoin (text, text_len, my_text, my_text_0);
	  }
	}
	if ((ored_msr & MSR__HALT) != 0) {
	  StrJoin (my_text, sizeof (my_text), text, "");
	  StrJoin (text, text_len, my_text, "Halt. ");
	}
	if ((ored_msr & MSR__HI_LIM) != 0) {
	  StrJoin (my_text, sizeof (my_text), text, "");
	  StrJoin (text, text_len, my_text, "Hit HiLim. ");
	}
	if ((ored_msr & MSR__LO_LIM) != 0) {
	  StrJoin (my_text, sizeof (my_text), text, "");
	  StrJoin (text, text_len, my_text, "Hit LoLim. ");
	}
	if ((ored_msr & MSR__STOPPED) != 0) {
	  StrJoin (my_text, sizeof (my_text), text, "");
	  StrJoin (text, text_len, my_text, "Stopped. ");
	}
      }
    }else if ((msr & ~(0x2fff)) != 0) {
      StrJoin (text, text_len, "Status, MSR = ??", "");
    }else {
      sprintf (my_text, "%#x ", msr);
      StrJoin (text, text_len, "Status, MSR = ", my_text);
      if ((msr & MSR__LIM_ERR) != 0) {
	StrJoin (my_text, sizeof (my_text), text, "");
        StrJoin (text, text_len, my_text, "Limit Switch Problem/");
      }
      if ((msr & MSR__AC_FAIL) != 0) {
	StrJoin (my_text, sizeof (my_text), text, "");
        StrJoin (text, text_len, my_text, "Air-Cushion Error/");
      }
      if ((msr & MSR__REF_FAIL) != 0) {
	StrJoin (my_text, sizeof (my_text), text, "");
        StrJoin (text, text_len, my_text, "Ref. Pos'n Fail/");
      }
      if ((msr & MSR__POS_FAIL) != 0) {
	StrJoin (my_text, sizeof (my_text), text, "");
        StrJoin (text, text_len, my_text, "Pos'n Fail/");
      }
      if ((msr & MSR__POS_FAULT) != 0) {
	StrJoin (my_text, sizeof (my_text), text, "");
        StrJoin (text, text_len, my_text, "Pos'n Fault/");
      }
      if ((msr & MSR__RUN_FAIL)	!= 0) {
	StrJoin (my_text, sizeof (my_text), text, "");
        StrJoin (text, text_len, my_text, "Run Fail/");
      }
      if ((msr & MSR__RUN_FAULT) != 0) {
	StrJoin (my_text, sizeof (my_text), text, "");
        StrJoin (text, text_len, my_text, "Run Fault/");
      }
      if ((msr & MSR__HALT) != 0) {
	StrJoin (my_text, sizeof (my_text), text, "");
        StrJoin (text, text_len, my_text, "Halt/");
      }
      if ((msr & MSR__HI_LIM) != 0) {
	StrJoin (my_text, sizeof (my_text), text, "");
        StrJoin (text, text_len, my_text, "Hit HiLim/");
      }
      if ((msr & MSR__LO_LIM) != 0) {
	StrJoin (my_text, sizeof (my_text), text, "");
        StrJoin (text, text_len, my_text, "Hit LoLim/");
      }
      if ((msr & MSR__STOPPED) != 0) {
	StrJoin (my_text, sizeof (my_text), text, "");
        StrJoin (text, text_len, my_text, "Stopped/");
      }
      if ((msr & MSR__REF_OK) != 0) {
	StrJoin (my_text, sizeof (my_text), text, "");
        StrJoin (text, text_len, my_text, "Ref. Pos'n OK/");
      }
      if ((msr & MSR__OK) != 0) {
	StrJoin (my_text, sizeof (my_text), text, "");
        StrJoin (text, text_len, my_text, "OK/");
      }
      if ((msr & MSR__BUSY) != 0) {
	StrJoin (my_text, sizeof (my_text), text, "");
        StrJoin (text, text_len, my_text, "Busy/");
      }
      len = strlen (text);
      text[len-1] = '\0';
    }
    return;
  }
/*
**---------------------------------------------------------------------------
**			ConnectToSrvr	- make connection to Motor Server
*/
  int	ConnectToSrvr (char *host, int port) {
/*	=============
*/
    int	    status;
    int	    my_cnct_skt;    /* Socket for connecting to Motor Srv */
    struct sockaddr_in	lcl_sockname;
    struct sockaddr_in	rmt_sockname;
    int			rmt_inet_addr;
    struct in_addr	*rmt_inet_addr_pntr;
    int			rmt_port;
    int			rmt_sockname_len;
    int			i;
    struct hostent	*rmt_hostent;

#if Active_Server
    rmt_hostent = gethostbyname (host);
    if (rmt_hostent == NULL) FailInet ("Gethostbyname error.\n");
    rmt_inet_addr_pntr = (struct in_addr *) rmt_hostent->h_addr_list[0];

    rmt_port = port;
/*
**  	    Create a TCP/IP socket for connecting to root and bind it.
*/
    my_cnct_skt = socket (AF_INET, SOCK_STREAM, 0);
    if (my_cnct_skt == -1) FailInet ("Socket error.\n");

    lcl_sockname.sin_family = AF_INET;
    lcl_sockname.sin_port   = htons (0);
    lcl_sockname.sin_addr.s_addr = 0;
    status = bind (my_cnct_skt, (struct sockaddr *) &lcl_sockname,
					sizeof (lcl_sockname));
    if (status == -1) FailInet ("Bind error.\n");
/*
**		Connect to Motor Server.
*/
    rmt_sockname_len = sizeof (rmt_sockname);
    rmt_sockname.sin_family	 = AF_INET;
    rmt_sockname.sin_port	 = htons (rmt_port);
    rmt_sockname.sin_addr.s_addr = rmt_inet_addr_pntr->s_addr;
    status = connect (my_cnct_skt, (struct sockaddr *) &rmt_sockname,
				    sizeof (rmt_sockname));
    if (status == -1) {
      FailInet ("Connect error.\n");
    }
    return my_cnct_skt;
#else	/* Active_Server */
    return 0;	/* "No server" mode - don't connect to server */
#endif	/* Active_Server */
  }
/*
**---------------------------------------------------------------------------
**			ModifyLabel		- modify text of a simple label
*/
  void	 ModifyLabel (
/*	 ===========
*/		Widget		labl,	    /*  widget id of label */
		char		*text) {    /*  The text for the label */

    XmString	my_compString;

    my_compString = XmStringCreateLtoR (text, XmSTRING_DEFAULT_CHARSET);
    XtVaSetValues (labl,
			XmNlabelString, my_compString,
			NULL);
    XmStringFree (my_compString);

    return;
  }
/*
**---------------------------------------------------------------------------
**		    SetStateInWindows - update State fields in Windows to
**					match state_ptr->msr, etc.
*/
  void	SetStateInWindows (
/*	=================
*/	    struct Motor_State	*old_state_ptr,	/* Motor status of display */
	    struct Motor_State	*state_ptr) {	/* current motor status */

    XmString	    tmp_cmpStr;
    int		    i_left, i_right, i_ist, i_soll;
    float	    flt;
    char	    text[80];
    static int	    state_len;
	/*
	** First time in, ensure that state_len is set to the length of
	** the Motor_State structure which must be checked for changes.
	*/
    if (state_len == 0) state_len = sizeof (struct Motor_State);
    if (memcmp (old_state_ptr, state_ptr, state_len) == 0) return;

    if (strcmp (state_ptr->pos_real, old_state_ptr->pos_real) != 0) {
      sscanf (state_ptr->pos_real, "%f", &flt);
      i_left  = (int) (Mot_lo_lim * Mot_factor);
      i_right = (int) (Mot_hi_lim * Mot_factor);
      i_ist   = (int) (flt        * Mot_factor);
		/*    
		**      Update "Ist" scale slider
		*/
      if (i_ist < i_left)  i_ist = i_left;
      if (i_ist > i_right) i_ist = i_right;
      XmScaleSetValue (Scale_ist, i_ist);
		/*    
		**      Update "Ist" label
		*/
      sprintf (text, "%.*f", state_ptr->dec_pt, Mot_pos_ist);
      ModifyLabel (Label_ist, text);
      if (Mot_is_on_left) {
	XtVaSetValues (Label_ist,
	    XmNleftPosition, (i_ist - i_left), NULL);
      }else {
	XtVaSetValues (Label_ist,
	    XmNrightPosition, (i_ist - i_left), NULL);
      }
    }

    if (strcmp (state_ptr->set_real, old_state_ptr->set_real) != 0) {
      sscanf (state_ptr->set_real, "%f", &flt);
      i_left  = (int) (Mot_lo_lim * Mot_factor);
      i_right = (int) (Mot_hi_lim * Mot_factor);
      i_soll  = (int) (flt        * Mot_factor);
		/*    
		**      Update "Soll" scale slider
		*/
      if (i_soll < i_left)  i_soll = i_left;
      if (i_soll > i_right) i_soll = i_right;
      XmScaleSetValue (Scale_soll, i_soll);
		/*    
		**      Update "Soll" label
		*/
      sprintf (text, "%.*f", state_ptr->dec_pt, Mot_pos_soll);
      ModifyLabel (Label_soll, text);
      if (Mot_is_on_left) {
	XtVaSetValues (Label_soll,
	    XmNleftPosition, (i_soll - i_left), NULL);
      }else {
	XtVaSetValues (Label_soll,
	    XmNrightPosition, (i_soll - i_left), NULL);
      }
    }
		/*    
		**      Update MSR label if necessary
		*/
    if (state_ptr->msr != old_state_ptr->msr) {
      EncodeMSR (text, sizeof (text),	state_ptr->msr,
					state_ptr->ored_msr,
					state_ptr->fp_cntr,
					state_ptr->fr_cntr);
      ModifyLabel (Label_msr, text);
    }
		/*    
		**      Update SS label if necessary
		*/
    if (state_ptr->ss != old_state_ptr->ss) {
      EncodeSS (text, state_ptr->ss);
      ModifyLabel (Label_ss, text);
    }
		/*    
		**      Update Statistics label if necessary
		*/
    if ((state_ptr->stat_pos != old_state_ptr->stat_pos) ||
	(state_ptr->stat_pos_flt != old_state_ptr->stat_pos_flt) ||
	(state_ptr->stat_pos_fail != old_state_ptr->stat_pos_fail) ||
	(state_ptr->stat_cush_fail != old_state_ptr->stat_cush_fail)) {
      sprintf (text, "Statistics: Total/Faults/Fails/Cush-fails = %d/%d/%d/%d",
			state_ptr->stat_pos,	 state_ptr->stat_pos_flt,
			state_ptr->stat_pos_fail, state_ptr->stat_cush_fail);
      ModifyLabel (Label_stats, text);
    }
		/*    
		**      Update FD label if necessary
		*/
    if ((state_ptr->enc_factor[0] != old_state_ptr->enc_factor[0]) ||
	(state_ptr->enc_factor[1] != old_state_ptr->enc_factor[1])) {
      sprintf (text, "Encoder Ratio, FD = %d:%d", state_ptr->enc_factor[0],
						  state_ptr->enc_factor[1]);
      ModifyLabel (Label_fd, text);
    }
		/*    
		**      Update FM label if necessary
		*/
    if ((state_ptr->mot_factor[0] != old_state_ptr->mot_factor[0]) ||
	(state_ptr->mot_factor[1] != old_state_ptr->mot_factor[1])) {
      sprintf (text, "Motor   Ratio, FM = %d:%d", state_ptr->mot_factor[0],
						  state_ptr->mot_factor[1]);
      ModifyLabel (Label_fm, text);
    }
		/*    
		**      Update D label if necessary
		*/
    if (strcmp (state_ptr->inertia_tol, old_state_ptr->inertia_tol) != 0) {
      sprintf (text, "Inertia tol'nce, D = %s", state_ptr->inertia_tol);
      ModifyLabel (Label_d, text);
    }
		/*    
		**      Update E label if necessary
		*/
    if (state_ptr->ramp != old_state_ptr->ramp) {
      sprintf (text, "Start/stop ramp, E = %d", state_ptr->ramp);
      ModifyLabel (Label_e, text);
    }
		/*    
		**      Update F label if necessary
		*/
    if (state_ptr->loop_mode != old_state_ptr->loop_mode) {
      switch (state_ptr->loop_mode) {
       case 0:  sprintf (text, "Open loop mode, F = 0");	    break;
       case 1:  sprintf (text, "Closed loop mode, F = 1");    break;
       default: sprintf (text, "Bad loop mode, F = %d", state_ptr->loop_mode);
      }
      ModifyLabel (Label_f, text);
    }
		/*    
		**      Update G label if necessary
		*/
    if (state_ptr->slow_hz != old_state_ptr->slow_hz) {
      sprintf (text, "Start/stop  Hz, G = %d", state_ptr->slow_hz);
      ModifyLabel (Label_g, text);
    }
		/*    
		**      Update J label if necessary
		*/
    if (state_ptr->fast_hz != old_state_ptr->fast_hz) {
      sprintf (text, "Positioning Hz, J = %d", state_ptr->fast_hz);
      ModifyLabel (Label_j, text);
    }
		/*    
		**      Update K label if necessary
		*/
    if (state_ptr->ref_mode != old_state_ptr->ref_mode) {
      switch (state_ptr->ref_mode) {
       case   0: sprintf (text, "Absolute encoder, K = 0"); break;
       case   1: sprintf (text, "HiLimit is RefPt, K = 1"); break;
       case  -1: sprintf (text, "LoLimit is RefPt, K = -1"); break;
       case   2: sprintf (text, "Sep RefPt, K = 2"); break;
       case  11: sprintf (text, "HiLimit is RefPt + Indx, K = 11"); break;
       case -11: sprintf (text, "LoLimit is RefPt + Indx, K = -11"); break;
       case  12: sprintf (text, "Sep RefPt + Indx, K = 12"); break;
       default:  sprintf (text, "RefMode unknown, K = %d", state_ptr->ref_mode);
      }
      ModifyLabel (Label_k, text);
    }
		/*    
		**      Update L label if necessary
		*/
    if (state_ptr->backlash != old_state_ptr->backlash) {
      sprintf (text, "Backlash, L = %d", state_ptr->backlash);
      ModifyLabel (Label_l, text);
    }
		/*    
		**      Update M label if necessary
		*/
    if (state_ptr->pos_tol != old_state_ptr->pos_tol) {
      sprintf (text, "Position Tol'nce, M = %d", state_ptr->pos_tol);
      ModifyLabel (Label_m, text);
    }
		/*    
		**      Update Q label if necessary
		*/
    if (strcmp (state_ptr->ref_param, old_state_ptr->ref_param) != 0) {
      sprintf (text, "RefPt Width, Q = %s", state_ptr->ref_param);
      ModifyLabel (Label_q, text);
    }
		/*    
		**      Update T label if necessary
		*/
    if (state_ptr->is_sided != old_state_ptr->is_sided) {
      if (state_ptr->is_sided == 0) {
        sprintf (text, "No dir'n dependency, T = 0");
      }else if (state_ptr->is_sided > 0) {
        sprintf (text, "Position from above, T = %d", state_ptr->is_sided);
      }else {
        sprintf (text, "Position from below, T = %d", state_ptr->is_sided);
      }
      ModifyLabel (Label_t, text);
    }
		/*    
		**      Update V label if necessary
		*/
    if (strcmp (state_ptr->null_pt, old_state_ptr->null_pt) != 0) {
      sprintf (text, "NullPt, V = %s", state_ptr->null_pt);
      ModifyLabel (Label_v, text);
    }
		/*    
		**      Update W label if necessary
		*/
    if ((state_ptr->ac_par   != old_state_ptr->ac_par) ||
	(state_ptr->ac_state != old_state_ptr->ac_state)) {
      if (state_ptr->ac_par == 0) {
        sprintf (text, "No air-cushion present, W = 0");
      }else if (state_ptr->ac_par == Motor) {
        if (state_ptr->ac_state == 0) {
	  sprintf (text, "Air-cushion down");
        }else {
	  sprintf (text, "Air-cushion up");
        }
      }else {
        if (state_ptr->ac_state == 0) {
	  sprintf (text, "Air-cushion up (chained to %d)", state_ptr->ac_par);
        }else {
	  sprintf (text, "Air-cushion down (chained to %d)", state_ptr->ac_par);
        }
      }
      ModifyLabel (Label_w, text);
    }
		/*    
		**      Update Output label if necessary
		*/
    if (state_ptr->out != old_state_ptr->out) {
      if (state_ptr->out == 0) {
        sprintf (text, "Output signal not active", state_ptr->null_pt);
      }else {
        sprintf (text, "Output signal active", state_ptr->null_pt);
      }
      ModifyLabel (Label_out, text);
    }
		/*    
		**      Update Input label if necessary
		*/
    if (state_ptr->in != old_state_ptr->in) {
      if (state_ptr->in == 0) {
        sprintf (text, "Input signal not present");
      }else {
        sprintf (text, "Input signal present");
      }
      ModifyLabel (Label_in, text);
    }
		/*    
		**      Update Z label if necessary
		*/
    if (state_ptr->enc_circ != old_state_ptr->enc_circ) {
      sprintf (text, "Enc Circum, Z = %d", state_ptr->enc_circ);
      ModifyLabel (Label_z, text);
    }
		/*
		*/
    memcpy (old_state_ptr, state_ptr, state_len);
  }
/*
**---------------------------------------------------------------------------
**			SendCmndToServer   - send command to RS232C server
*/
  int	SendCmndToServer (
/*	=================
*/	    int			    v24_chan,	 /* RS232C port number	*/
	    int			    tmo,	 /* Time-out (0.1 secs) */
	    struct RS__RespStruct  *respon_ptr, /* Buffer for response */
	    int			    respon_size, /* Size of resp'se buff */
	    ...) {			/* Now we have parameter pairs -
					**   char *fmt   = pntr to format strng
					**   char *param = pntr to param
					** Terminate list with *fmt = NULL.
					*/
    struct RS__MsgStruct    msg_buff;
    int			    status, c_len, size, max_size, ncmnds;
    char		    text[20];
    va_list		    ap;		/* Pointer to variable args */
    char		    *fmt_ptr;
    char		    *param_ptr;
    char		    *cmnd_lst_ptr;

    if (Cnct_skt == 0) return True;	/* Do nothing if no connection - this
					** allows testing in "client-only" mode.
					*/

    Msg_seq++;				/* Set up an incrementing message id */
    if (Msg_seq > 9999) Msg_seq = 1;
    sprintf (msg_buff.msg_id,	   "%04.4d", Msg_seq);

    memcpy (msg_buff.c_pcol_lvl, RS__PROTOCOL_ID,
					sizeof (msg_buff.c_pcol_lvl));
    sprintf (msg_buff.serial_port, "%04.4d", v24_chan);
    sprintf (msg_buff.tmo,	   "%04.4d", tmo);

    memcpy (msg_buff.terms, "1\r\0\0", sizeof (msg_buff.terms));

    memcpy (msg_buff.n_cmnds, "0000", sizeof (msg_buff.n_cmnds));

    va_start (ap, respon_size);		/* Set up var arg machinery */

    fmt_ptr = va_arg (ap, char *);	/* Get pntr to next format string */
    ncmnds = 0;
    cmnd_lst_ptr = &msg_buff.cmnds[0];

    while (fmt_ptr != NULL) {
      param_ptr = va_arg (ap, char *);	/* Get pntr to next param */
      c_len = sprintf (cmnd_lst_ptr+2, fmt_ptr, param_ptr);
      sprintf (text, "%02.2d", c_len);
      memcpy (cmnd_lst_ptr, text, 2);
      cmnd_lst_ptr = cmnd_lst_ptr + c_len + 2;
      ncmnds++;
      fmt_ptr = va_arg (ap, char *);
    }
    sprintf (text, "%04.4d", ncmnds);
    memcpy (msg_buff.n_cmnds, text, sizeof (msg_buff.n_cmnds));

    size = cmnd_lst_ptr - msg_buff.msg_id;
    size = (size + 3) & (~3);	/* Round up to multiple of 4 */
    sprintf (text, "%04.4d", size);
    memcpy (msg_buff.msg_size, text, 4);

    status = send (Cnct_skt, (char *) &msg_buff, size+4, 0);
    if (status != (size+4)) {
      sprintf (Err_text, "send: did not send all of buffer: %d %d.\n",
			size+4, status);
      FailInet (Err_text);
    }

    size = sizeof (respon_ptr->msg_size);
    status = recv (Cnct_skt, respon_ptr->msg_size, size, 0);
    if (status != size) {
      sprintf (Err_text, "recv: did not get full byte count: %d %d.\n",
					size, status);
      FailInet (Err_text);
      }
    if (sscanf (respon_ptr->msg_size, "%4d", &size) != 1) {
      sprintf (Err_text, "recv: byte count is not ASCII decimal: %4s\n",
			respon_ptr->msg_size);
      FailInet (Err_text);
    }
    max_size = respon_size - sizeof (respon_ptr->msg_size);
    if (size > max_size) {
      sprintf (Err_text, "recv: message length is too big: %d, %d.\n",
		    max_size, size);
      FailInet (Err_text);
    }
    status = recv (Cnct_skt, (char *) respon_ptr->msg_id, size, 0);
    if (status != size) {
      sprintf (Err_text, "recv: did not get all of expected data: %d %d.\n",
			size, status);
      FailInet (Err_text);
    }
    return status;
  }
/*
**---------------------------------------------------------------------------
**			GetReply    - get next reply from a reply buffer
*/
  struct RS__RplyStruct *GetReply (
/*		         ========
*/	    struct RS__RespStruct  *respon_ptr,  /* Structure to pull apart */
	    struct RS__RplyStruct  *last_rply) { /* Starting point */

    int			    rply_len;
    struct RS__RplyStruct   *ptr;

    static int		n_replies, max_replies;

    ptr = NULL;
    if (last_rply == NULL) {	/* Start with first reply? */
      if (sscanf (respon_ptr->n_rply, "%4d", &max_replies) != 1)
	    max_replies = 0;
      if (max_replies > 0) ptr = (struct RS__RplyStruct *) respon_ptr->u.rplys;
      n_replies = 1;
    }else {
      n_replies++;
      if (n_replies <= max_replies) {
        if (sscanf (last_rply->rply_len, "%2d", &rply_len) == 1) {
	  ptr = (struct RS__RplyStruct *) ((char *) last_rply + rply_len + 2);
	}
      }
    }
    return ptr;
  }
/*
**---------------------------------------------------------------------------
**			GetMotorStatus	- get Motor status from srvr
*/
  int	GetMotorStatus (
/*	================
*/	    int type,			    /* FULL__STATUS or SHORT__STATUS */
	    struct Motor_State  *state) {   /* Structure to hold status */

    struct RS__MsgStruct    msg_buff;
    int			    status, size, max_size;
    int			    i, indx;
    int			    j0, j1;
    char		    txt0[16], txt1[16], mot_txt[10];
    struct RS__RplyStruct   *rply_ptr;
	/*
	** Start by getting "short" status of motor.
	*/
#if Active_Server
    sprintf (mot_txt, "%d", state->motor);
    status = SendCmndToServer (AppData.v24_chan, TMO,
				&Respon_buff, sizeof (Respon_buff),
				"msr %s\r", mot_txt,
				"ss %s\r",  mot_txt,
				"u %s\r",   mot_txt,
				"p %s\r",   mot_txt,
				"sp %s\r",  mot_txt,
				"st %s\r",  mot_txt,
				"sr %s\r",  mot_txt,
				"sa %s\r",  mot_txt,
				NULL);
    rply_ptr = GetReply (&Respon_buff, NULL);
    if (rply_ptr != NULL) {
      if (sscanf (rply_ptr->rply, "%x", &state->msr) == 1) {
	state->exists = True;
	state->ored_msr = state->ored_msr | state->msr;
	if ((state->msr & MSR__POS_FAULT) != 0) state->fp_cntr++;
	if ((state->msr & MSR__RUN_FAULT) != 0) state->fr_cntr++;
	rply_ptr = GetReply (&Respon_buff, rply_ptr);
	if (rply_ptr != NULL) {
	  if (sscanf (rply_ptr->rply, "%x", &state->ss) != 1) state->ss = -1;
	  rply_ptr = GetReply (&Respon_buff, rply_ptr);
	  if (rply_ptr != NULL) {
	    strncpy (state->pos_real, rply_ptr->rply,
			    sizeof (state->pos_real) - 1);
	    sscanf (state->pos_real, "%f", &Mot_pos_ist);
	    rply_ptr = GetReply (&Respon_buff, rply_ptr);
	    if (rply_ptr != NULL) {
	      strncpy (state->set_real, rply_ptr->rply,
			      sizeof (state->set_real) - 1);
	      sscanf (state->set_real, "%f", &Mot_pos_soll);
	      rply_ptr = GetReply (&Respon_buff, rply_ptr);
	      if (rply_ptr != NULL) {
		sscanf (rply_ptr->rply, "%d", &state->stat_pos);
		rply_ptr = GetReply (&Respon_buff, rply_ptr);
		if (rply_ptr != NULL) {
		  sscanf (rply_ptr->rply, "%d", &state->stat_pos_flt);
		  rply_ptr = GetReply (&Respon_buff, rply_ptr);
		  if (rply_ptr != NULL) {
		    sscanf (rply_ptr->rply, "%d", &state->stat_pos_fail);
		    rply_ptr = GetReply (&Respon_buff, rply_ptr);
		    if (rply_ptr != NULL) {
		      sscanf (rply_ptr->rply, "%d", &state->stat_cush_fail);
		      rply_ptr = GetReply (&Respon_buff, rply_ptr);
	            }
	          }
	        }
	      }
	    }
	  }
	}
      }else {
	state->exists = False;
      }
    }
    if ((type == FULL__STATUS) && state->exists) {
      status = SendCmndToServer (AppData.v24_chan, TMO,
				&Respon_buff, sizeof (Respon_buff),
				"mn %s\r", mot_txt,
				"a %s\r",  mot_txt,
				"fd %s\r", mot_txt,
				"fm %s\r", mot_txt,
				"d %s\r",  mot_txt,
				"e %s\r",  mot_txt,
				"f %s\r",  mot_txt,
				"g %s\r",  mot_txt,
				"h %s\r",  mot_txt,
				"j %s\r",  mot_txt,
				"k %s\r",  mot_txt,
				"l %s\r",  mot_txt,
				"m %s\r",  mot_txt,
				"q %s\r",  mot_txt,
				"t %s\r",  mot_txt,
				"v %s\r",  mot_txt,
				"w %s\r",  mot_txt,
				"z %s\r",  mot_txt,
				"p %s\r",  mot_txt,
				"ac %s\r", mot_txt,
				"so %s\r", mot_txt,
				"ri %s\r", mot_txt,
				NULL);

      rply_ptr = GetReply (&Respon_buff, NULL);
      indx = 0;
      for (i = 0; Cmnd_fmt[i] != NO_MORE; i++) {
        if (rply_ptr != NULL) {
	  switch (Cmnd_fmt[i]) {
	   case ONE_INT:
	    sscanf (rply_ptr->rply, "%d",
			(int *)(((char *) state) + Offsets[indx]));
	    indx++;
	    break;
	   case TWO_INT:
	    sscanf (rply_ptr->rply, "%d %d",
			(int *)(((char *) state) + Offsets[indx]),
			(int *)(((char *) state) + Offsets[indx+1]));
	    indx++; indx++;
	    break;
	   case ONE_STRING:
	    sscanf (rply_ptr->rply, "%15s",
			((char *) state) + Offsets[indx]);
	    indx++;
	    break;
	   case TWO_STRING:
	    sscanf (rply_ptr->rply, "%15s %15s",
			((char *) state) + Offsets[indx],
			((char *) state) + Offsets[indx+1]);
	    indx++; indx++;
	    break;
	  }
          rply_ptr = GetReply (&Respon_buff, rply_ptr);
	}
      }
      DecodeFloats ();	    /* Convert all strings in state to binary	*/
    }
#else
    state->exists = True;
    state->msr = 1;
    state->ss = 2;
    strcpy (state->pos_real, "12.2");
    state->pos_hex = 0x1234;
    strcpy (state->name, "DELTA");
    state->dec_pt = 3;
    state->enc_factor[0] = 400;
    state->enc_factor[1] = 2;
    state->mot_factor[0] = -300;
    state->mot_factor[1] = 3;
    strcpy (state->inertia_tol, "0.1");
    state->ramp = 20;
    state->loop_mode = 1;
    state->slow_hz = 300;
    strcpy (&state->lims[0][0], "-50.0");
    strcpy (&state->lims[1][0], "200.0");
    state->fast_hz = 1000;
    state->ref_mode = 2;
    state->backlash = 0;
    state->pos_tol = 1;
    strcpy (state->ref_param, "10.0");
    state->is_sided = 0;
    strcpy (state->null_pt, "-15.0");
    state->ac_par = state->motor;
    state->enc_circ = 0;
    state->stat_pos = 1234;
    state->stat_pos_flt = 2345;
    state->stat_pos_fail = 3456;
    state->stat_cush_fail = 4567;
    strcpy (state->set_real, "70.5");
    state->set_hex = 0x4321;
    state->ac_state = 0;
    state->out = 0;
    state->in = 0;
#endif	/* Active_Server */
    return True;
  }
/*

**---------------------------------------------------------------------------
**			ActivateCB		- callback for button
*/
  void	ActivateCB (
/*	==========
*/		Widget	    w,			/*  widget id	*/
		XtPointer    client_data,	/*  data from application   */
		XtPointer    call_data) {	/*  data from widget class  */

    Widget	w_tmp;
    char	*button_name, *parent_name;
	    /*
	    **	print message to prove we got activated
	    */
    w_tmp = XtParent (w);
    button_name = XtName (w);
    parent_name = XtName (w_tmp);

    printf ("Push button \"%s\" of Parent \"%s\" selected.\n",
		button_name, parent_name);
  }
/*
**---------------------------------------------------------------------------
**		MotorSelectCB	- callback for Select .../Motor .../Number
*/
  void	MotorSelectCB (
/*	=============
*/		Widget	    w,			/*  widget id	*/
		XtPointer    client_data,	/*  data from application   */
		XtPointer    call_data) {	/*  data from widget class  */

    int		 motor = 0, i_left, i_right, i_soll, i_ist;
    char	*button_name, text[80];
    XmString	 tmp_cmpStr;
	    /*
	    **	print message to prove we got activated
	    */
    button_name = XtName (w);
    printf ("Push button \"%s\" selected.\n", button_name);
    if ((sscanf (button_name, "%i", &motor) != 1) ||
	(motor <= 0) ||
	(motor > 12)) {
      printf ("Invalid push button label or motor number!\n");
      return;
    }
    if (motor != Motor) {
      Motor = motor;
      Mot_state.motor = Motor;
      printf ("Getting full status of Motor %d ...\n", Motor);
      GetMotorStatus (FULL__STATUS, &Mot_state);

      sprintf (text, "%.*f", Mot_state.dec_pt, Mot_lo_lim);
      tmp_cmpStr = XmStringCreateLtoR (text, XmSTRING_DEFAULT_CHARSET);
      XtVaSetValues (Label_lo_lim,
			XmNlabelString, tmp_cmpStr,
			NULL);
      XmStringFree (tmp_cmpStr);

      sprintf (text, "Motor %d \"%s\"", Motor, Mot_state.name);
      tmp_cmpStr = XmStringCreateLtoR (text, XmSTRING_DEFAULT_CHARSET);
      XtVaSetValues (Label_name,
			XmNlabelString, tmp_cmpStr,
			NULL);
      XmStringFree (tmp_cmpStr);

      sprintf (text, "%.*f", Mot_state.dec_pt, Mot_hi_lim);
      tmp_cmpStr = XmStringCreateLtoR (text, XmSTRING_DEFAULT_CHARSET);
      XtVaSetValues (Label_hi_lim,
			XmNlabelString, tmp_cmpStr,
			NULL);
      XmStringFree (tmp_cmpStr);

      i_left  = (int) (Mot_lo_lim   * Mot_factor);
      i_right = (int) (Mot_hi_lim   * Mot_factor);
      i_soll  = (int) (Mot_pos_soll * Mot_factor);
      i_ist   = (int) (Mot_pos_ist  * Mot_factor);
      if (i_ist  < i_left)  i_ist  = i_left;
      if (i_ist  > i_right) i_ist  = i_right;
      if (i_soll < i_left)  i_soll = i_left;
      if (i_soll > i_right) i_soll = i_right;
      XtVaSetValues (Scale_ist,
			XmNminimum, i_left,
			XmNmaximum, i_right,
			XmNvalue,   i_ist,
			NULL);
      XtVaSetValues (Scale_soll,
			XmNminimum, i_left,
			XmNmaximum, i_right,
			XmNvalue,   i_soll,
			NULL);

      SetStateInWindows (&Old_Mot_state, &Mot_state); /* Update window display. */
    }
  }
/*
**---------------------------------------------------------------------------
**			AddMenuItem		- add item into menu
*/
  Widget AddMenuItem (
/*	 ===========
*/		Widget		parent,		/* The parent menu	    */
		char		*name,		/* Name of menu item	    */
		char		accelerator,	/* Accelerator character    */
		int		menu_type,	/* Menu type		    */
		Widget		casc_pane,    /* Pane to link to button ..
					      ** .. (menu_type = CASCADE only */
		XtCallbackProc	callback) {	/* Callback procedure	    */

    Widget	my_menu_item;

    Nargs = 0;
    if (accelerator != 0)
      XtSetArg (Args[Nargs], XmNmnemonic, accelerator);  Nargs++;
    XtSetArg (Args[Nargs], XmNnavigationType, XmTAB_GROUP);  Nargs++;

    switch (menu_type) {
      case CASCADE:
	XtSetArg (Args[Nargs], XmNsubMenuId, casc_pane);  Nargs++;
        my_menu_item = XmCreateCascadeButton (parent, name, Args, Nargs);
        break;
      case PULL_DOWN:
	my_menu_item = XmCreatePushButton (parent, name, Args, Nargs);
        break;
      case SEPARATOR:
	my_menu_item = XmCreateSeparator (parent, NULL, Args, Nargs);
        break;
      default:
        printf ("\007Illegal menu_type in call to AddMenuItem\n");
    }
    XtManageChild (my_menu_item);

    if (callback != NULL)
      XtAddCallback (my_menu_item, XmNactivateCallback, callback, NULL);

    return my_menu_item;
  }
/*
**---------------------------------------------------------------------------
**			MakeLabel		- make a simple label
*/
  Widget MakeLabel (
/*	 =========
*/		Widget		w,	    /*  widget id of parent of label */
		char		*text,	    /*  The text for the label */
		unsigned char	align) {    /*  The alignment for the label */

    Widget	my_label;
    XmString	my_compString;

    my_compString = XmStringCreateLtoR (text, XmSTRING_DEFAULT_CHARSET);
    Nargs = 0;
    XtSetArg (Args[Nargs], XmNlabelString, my_compString); Nargs++;
    XtSetArg (Args[Nargs], XmNentryAlignment, align); Nargs++;
    XtSetArg (Args[Nargs], XmNrecomputeSize, False); Nargs++;
    my_label = XmCreateLabel (w, NULL, Args, Nargs);
    XtManageChild (my_label);
    XmStringFree (my_compString);

    return my_label;
  }
/*
**---------------------------------------------------------------------------
**			QuitCB		- callback for quit button
*/
  void	QuitCB (
/*	======
*/		Widget	    w,			/*  widget id	*/
		XtPointer    client_data,	/*  data from application   */
		XtPointer    call_data) {	/*  data from widget class  */

    char	buff[4];

    if (Cnct_skt != 0) {
      send (Cnct_skt, "-001", 4, 0);	/* Tell our TCP/IP server that ..
					** .. we are about to quit.
					*/
      recv (Cnct_skt, buff, sizeof (buff), 0);	/* And wait for his ack */
      close (Cnct_skt);
    }
    exit (True);	    /* Terminate the application. */
  }
/*
**---------------------------------------------------------------------------
**			SollCB		- callback for Soll-position Scale
*/
  void	SollCB (
/*	======
*/	    Widget		  w,		 /*  widget id	*/
	    XtPointer		  client_data, 	 /*  data from application   */
	    XmScaleCallbackStruct *call_data) {	 /*  data from widget class  */

    int		status;
    int		i_tmp;
    float	f_tmp;
    char	fmt[80];
    char	text[80];
    XmString	tmp_cmpStr;

    f_tmp = ((float) call_data->value)/((float) Mot_factor);
    sprintf (text, "%.*f", Mot_state.dec_pt, f_tmp);
    tmp_cmpStr = XmStringCreateLtoR (text, XmSTRING_DEFAULT_CHARSET);
    XtVaSetValues (Label_soll,
			XmNlabelString, tmp_cmpStr,
			NULL);
    XmStringFree (tmp_cmpStr);

    if (call_data->reason != XmCR_VALUE_CHANGED) {
      XmUpdateDisplay (Wtop_level);
      return;
    }
	    /*
	    **	Adjust position of label to be near pointer. There is a
	    **	complication if the position goes over the mid-point.
	    */
    i_tmp = call_data->value - (int) (Mot_lo_lim * Mot_factor);
    if (((f_tmp < Mot_scale_middle) &&  Mot_is_on_left)  ||
	((f_tmp > Mot_scale_middle) && !Mot_is_on_left)) {
		    /*
		    **	Get here if side has not changed.
		    */
      if (Mot_is_on_left) {
	XtVaSetValues (Label_soll,
			XmNleftPosition, i_tmp,
			NULL);
	XtVaSetValues (Label_ist,
			XmNleftPosition, i_tmp,
			NULL);
      }else {
	XtVaSetValues (Label_soll,
			XmNrightPosition, i_tmp,
			NULL);
	XtVaSetValues (Label_ist,
			XmNrightPosition, i_tmp,
			NULL);
      }
    }else if (Mot_is_on_left) {
		    /*
		    **	Get here if side has changed from left to right.
		    */
      Mot_is_on_left = False;
      XtVaSetValues (Label_soll,
			XmNleftAttachment, XmATTACH_NONE,
			XmNleftPosition, 0,
			XmNrightAttachment, XmATTACH_POSITION,
			XmNrightPosition, i_tmp,
			NULL);
      XtVaSetValues (Label_ist,
			XmNleftAttachment, XmATTACH_NONE,
			XmNleftPosition, 0,
			XmNrightAttachment, XmATTACH_POSITION,
			XmNrightPosition, i_tmp,
			NULL);
    }else {
		    /*
		    **	Get here if side has changed from right to left.
		    */
      Mot_is_on_left = True;
      XtVaSetValues (Label_soll,
			XmNleftAttachment, XmATTACH_POSITION,
			XmNleftPosition, i_tmp,
			XmNrightAttachment, XmATTACH_NONE,
			XmNrightPosition, 0,
			NULL);
      XtVaSetValues (Label_ist,
			XmNleftAttachment, XmATTACH_POSITION,
			XmNleftPosition, i_tmp,
			XmNrightAttachment, XmATTACH_NONE,
			XmNrightPosition, 0,
			NULL);
    }
    XmUpdateDisplay (Wtop_level);

    Mot_state.ored_msr = 0;
    Mot_state.fp_cntr  = 0;
    Mot_state.fr_cntr  = 0;
    sprintf (fmt, "p %d %%s\r", Motor);
    status = SendCmndToServer (AppData.v24_chan, TMO,
				&Respon_buff, sizeof (Respon_buff),
				fmt, text,
				NULL);
  }
/*
**---------------------------------------------------------------------------
**			TimerCB		- callback for timer
*/
  void	TimerCB (
/*	=======
*/		XtPointer	client_data,	/*  data from application   */
		XtIntervalId	*id) {		/*  data from widget class  */

    static int	    first = True;
    static int	    blink = True;
    static Display  *disp;
    static Window   wind;
    static GC	    gc;

    GetMotorStatus (SHORT__STATUS, &Mot_state);
    SetStateInWindows (&Old_Mot_state, &Mot_state); /* Update window display. */

    if (AppData.msec_timer > 0) {
      XtAppAddTimeOut (App_context, AppData.msec_timer, TimerCB, NULL);
    }else {
      printf ("\007EL734 -- status polling disabled.\n");
    }
#if  Blink_On	    /* This is just an exercise to do a bit of graphics!! */
    if (first) {
      first = False;
      disp = XtDisplay (DrawnBut);
      wind = XtWindow (DrawnBut);
      gc   = DefaultGCOfScreen (XtScreen (DrawnBut));
    }
    if (blink) {
      XFillArc (disp, wind, gc,
		    10, 10, 50, 50, 0, 360*64);
    }else {
      XClearArea (disp, wind, 10, 10, 50, 50, False);
    }
    blink = !blink;
#endif	/* Blink_On */
  }
/*
**---------------------------------------------------------------------------
**			CreateMenuBar - Create menu bar for main window.
*/
  Widget CreateMenuBar (Widget window) {
/* 	 =============
*/
    Widget my_menu_bar;		/*  MenuBar		*/

    Widget quit_menu_pane;	/*  Quit    MenuPane	*/
    Widget slct_menu_pane;	/*  Select  MenuPane	*/
    Widget help_menu_pane;	/*  Help    MenuPane	*/

    Widget mot_menu_pane;	/*  Motor MenuPane	*/

    Widget my_button;
	    /*-------------------------------------------------------------
	    **	Create MenuBar in MainWindow.
	    */
    Nargs = 0;
    XtSetArg (Args[Nargs], XmNadjustLast, True);  Nargs++;
    my_menu_bar = XmCreateMenuBar (window, "menu_bar", Args, Nargs); 
    XtManageChild (my_menu_bar);
		/*---------------------------------------------------------
		**    Create panes for the Menu Bar Pulldown Menus.
		*/
    Nargs = 0;
    quit_menu_pane = XmCreatePulldownMenu (my_menu_bar, "Quit_Menu",
								Args, Nargs);
    slct_menu_pane = XmCreatePulldownMenu (my_menu_bar, "Select_Menu",
								Args, Nargs);
    help_menu_pane = XmCreatePulldownMenu (my_menu_bar, "Help_Menu",
								Args, Nargs);

    mot_menu_pane  = XmCreatePulldownMenu (slct_menu_pane, "Motor_Menu",
						    Args, Nargs);
		/*-------------------------------------------------------------
		**	    Create buttons on menu bar and specify afterwards
		**	    which one is the Help item.
		*/
    Wquit_cascade = AddMenuItem (my_menu_bar, "File",  'F',
						CASCADE, quit_menu_pane, NULL);
    Wslct_cascade = AddMenuItem (my_menu_bar, "Select", 'S',
						CASCADE, slct_menu_pane, NULL);
    Whelp_cascade = AddMenuItem (my_menu_bar, "Help",  'H',
						CASCADE, help_menu_pane, NULL);

    XtSetArg (Args[0], XmNmenuHelpWidget, Whelp_cascade);
    XtSetValues (my_menu_bar, Args, 1);
		/*---------------------------------------------------------
		**    Put items into the menu bar menu panes. Start with Exit.
		*/
    AddMenuItem (quit_menu_pane,  "Quit/Finish", 'F', PULL_DOWN, NULL, QuitCB);
		/*---------------------------------------------------------
		**    Now do Select.
		*/
    Wmot_cascade = AddMenuItem (slct_menu_pane,
			"Motor", 'M', CASCADE, mot_menu_pane, NULL);
		/*---------------------------------------------------------
		**    Now do Help.
		*/
    AddMenuItem (help_menu_pane, "Context-sensitive Help", 'C',
						PULL_DOWN, NULL, ActivateCB);
    AddMenuItem (help_menu_pane, NULL, '\0', SEPARATOR, NULL, NULL);
    AddMenuItem (help_menu_pane, "Overview", 'O',
						PULL_DOWN, NULL, ActivateCB);
		/*---------------------------------------------------------
		**    Now do Motor.
		*/
    AddMenuItem (mot_menu_pane, "1", '1', PULL_DOWN, NULL, MotorSelectCB);
    AddMenuItem (mot_menu_pane, "2", '2', PULL_DOWN, NULL, MotorSelectCB);
    AddMenuItem (mot_menu_pane, "3", '3', PULL_DOWN, NULL, MotorSelectCB);
    AddMenuItem (mot_menu_pane, "4", '4', PULL_DOWN, NULL, MotorSelectCB);
    AddMenuItem (mot_menu_pane, "5", '5', PULL_DOWN, NULL, MotorSelectCB);
    AddMenuItem (mot_menu_pane, "6", '6', PULL_DOWN, NULL, MotorSelectCB);
    AddMenuItem (mot_menu_pane, "7", '7', PULL_DOWN, NULL, MotorSelectCB);
    AddMenuItem (mot_menu_pane, "8", '8', PULL_DOWN, NULL, MotorSelectCB);
    AddMenuItem (mot_menu_pane, "9", '9', PULL_DOWN, NULL, MotorSelectCB);
    AddMenuItem (mot_menu_pane, "10 (0x0a)", 'a', PULL_DOWN, NULL, MotorSelectCB);
    AddMenuItem (mot_menu_pane, "11 (0x0b)", 'b', PULL_DOWN, NULL, MotorSelectCB);
    AddMenuItem (mot_menu_pane, "12 (0x0c)", 'c', PULL_DOWN, NULL, MotorSelectCB);

    return my_menu_bar;
  }
/*
**---------------------------------------------------------------------------
**			CreateApplication - set up main window. Return value
**					    is main window widget.
*/
  Widget CreateApplication (Widget parent) {
/*	 =================
*/
    Widget  main_window;	/*  MainWindow		*/
    Widget  form_0;		/*  Form Widget		*/
    Widget  rc_00;		/*  RowColumn Widget	*/
    Widget  rc_01;		/*  RowColumn Widget	*/

    XmString	    tmp_cmpStr;
    char	    text[80];
    int		    i_left, i_right, i_soll, i_ist;
	    /*-------------------------------------------------------------*/
    i_left	    = (int) (Mot_lo_lim   * Mot_factor);
    i_right	    = (int) (Mot_hi_lim   * Mot_factor);
    i_soll	    = (int) (Mot_pos_soll * Mot_factor);
    i_ist	    = (int) (Mot_pos_ist  * Mot_factor);
    Mot_scale_middle = (Mot_lo_lim + Mot_hi_lim)/2.0;
    if (Mot_pos_soll < Mot_scale_middle) {
      Mot_is_on_left = True;
    }else {
      Mot_is_on_left = False;
    }
	    /*-------------------------------------------------------------
	    **	Create MainWindow.
	    */
    Nargs = 0;
    main_window = XmCreateMainWindow (parent, "main_window", Args, Nargs);
    XtManageChild (main_window);

    CreateMenuBar (main_window);
	    /*    
	    **      Create Form Widget to hold the various items
	    **	    in the Main Window
	    */
    Nargs = 0;
    form_0 = XmCreateForm (main_window, "form_0", Args, Nargs);
    XtVaSetValues (form_0,
			XmNfractionBase, (i_right - i_left),
			NULL);
    XtManageChild (form_0);
		/*    
		**      Create label to show lower limit
		*/
    sprintf (text, "%.*f", Mot_state.dec_pt, Mot_lo_lim);
    tmp_cmpStr = XmStringCreateLtoR (text, XmSTRING_DEFAULT_CHARSET);
    Nargs = 0;
    XtSetArg (Args[Nargs], XmNentryAlignment, XmALIGNMENT_BEGINNING); Nargs++;
    XtSetArg (Args[Nargs], XmNlabelString, tmp_cmpStr); Nargs++;
    XtSetArg (Args[Nargs], XmNrecomputeSize, True); Nargs++;
    Label_lo_lim = XmCreateLabel (form_0, "Lo_Lim_Label", Args, Nargs);
    XtManageChild (Label_lo_lim);
    XmStringFree (tmp_cmpStr);
		/*    
		**      Create label to show motor number and name
		*/
    sprintf (text, "Motor %d \"%s\"", Motor, Mot_state.name);
    tmp_cmpStr = XmStringCreateLtoR (text, XmSTRING_DEFAULT_CHARSET);
    Nargs = 0;
    XtSetArg (Args[Nargs], XmNentryAlignment, XmALIGNMENT_CENTER); Nargs++;
    XtSetArg (Args[Nargs], XmNlabelString, tmp_cmpStr); Nargs++;
    XtSetArg (Args[Nargs], XmNrecomputeSize, True); Nargs++;
    Label_name = XmCreateLabel (form_0, "Name_Label", Args, Nargs);
    XtManageChild (Label_name);
    XmStringFree (tmp_cmpStr);
		/*    
		**      Create label to show upper limit
		*/
    sprintf (text, "%.*f", Mot_state.dec_pt, Mot_hi_lim);
    tmp_cmpStr = XmStringCreateLtoR (text, XmSTRING_DEFAULT_CHARSET);
    Nargs = 0;
    XtSetArg (Args[Nargs], XmNentryAlignment, XmALIGNMENT_END); Nargs++;
    XtSetArg (Args[Nargs], XmNlabelString, tmp_cmpStr); Nargs++;
    XtSetArg (Args[Nargs], XmNrecomputeSize, True); Nargs++;
    Label_hi_lim = XmCreateLabel (form_0, "Hi_Lim_Label", Args, Nargs);
    XtManageChild (Label_hi_lim);
    XmStringFree (tmp_cmpStr);
	    /*    
	    **      Create scales -- use resource value as dimension.
	    */
		/*    
		**      Create label to show "Soll" position
		*/
    sprintf (text, "%.*f", Mot_state.dec_pt, Mot_pos_soll);
    tmp_cmpStr = XmStringCreateLtoR (text, XmSTRING_DEFAULT_CHARSET);
    Nargs = 0;
    XtSetArg (Args[Nargs], XmNlabelString, tmp_cmpStr); Nargs++;
    Label_soll = XmCreateLabel (form_0, "Soll_Label", Args, Nargs);
    XtManageChild (Label_soll);
    XmStringFree (tmp_cmpStr);
		/*    
		**      Create scales to show "Soll" and "Ist" positions
		*/
    Nargs = 0;
    XtSetArg (Args[Nargs], XmNdecimalPoints, Mot_state.dec_pt);  Nargs++;
    XtSetArg (Args[Nargs], XmNminimum, i_left); Nargs++;
    XtSetArg (Args[Nargs], XmNmaximum, i_right); Nargs++;
    XtSetArg (Args[Nargs], XmNorientation, XmHORIZONTAL);  Nargs++;
    XtSetArg (Args[Nargs], XmNscaleWidth, Scale_width);  Nargs++;

    Scale_soll = XmCreateScale (form_0, "Soll_Scale", Args, Nargs);
    XtManageChild (Scale_soll);

    Scale_ist  = XmCreateScale (form_0, "Ist_Scale", Args, Nargs);
    XtManageChild (Scale_ist);

    XtVaSetValues (Scale_soll,
			XmNvalue, i_soll,
			XmNsensitive, True,
			NULL);

    XtVaSetValues (Scale_ist,
			XmNvalue, i_ist,
			XmNsensitive, False,
			NULL);

    XtAddCallback (Scale_soll, XmNdragCallback,
				    (XtCallbackProc) SollCB, NULL);
    XtAddCallback (Scale_soll, XmNvalueChangedCallback,
				    (XtCallbackProc) SollCB, NULL);
		/*    
		**      Create label to show "Ist" position
		*/
    sprintf (text, "%.*f", Mot_state.dec_pt, Mot_pos_ist);
    tmp_cmpStr = XmStringCreateLtoR (text, XmSTRING_DEFAULT_CHARSET);
    Nargs = 0;
    XtSetArg (Args[Nargs], XmNlabelString, tmp_cmpStr); Nargs++;
    Label_ist = XmCreateLabel (form_0, "Ist_Label", Args, Nargs);
    XtManageChild (Label_ist);
    XmStringFree (tmp_cmpStr);
	    /*    
	    **      Create RowColumn widgets for status displays
	    */
    Nargs = 0;
    XtSetArg (Args[Nargs], XmNnumColumns, 1);  Nargs++;
    XtSetArg (Args[Nargs], XmNpacking, XmPACK_COLUMN);  Nargs++;
    XtSetArg (Args[Nargs], XmNorientation, XmVERTICAL);  Nargs++;
    XtSetArg (Args[Nargs], XmNentryAlignment, XmALIGNMENT_BEGINNING); Nargs++;
    rc_00 = XmCreateRowColumn (form_0, "RowCol_00", Args, Nargs);
    XtManageChild (rc_00);

    Nargs = 0;
    XtSetArg (Args[Nargs], XmNnumColumns, 3);  Nargs++;
    XtSetArg (Args[Nargs], XmNpacking, XmPACK_COLUMN);  Nargs++;
    XtSetArg (Args[Nargs], XmNorientation, XmVERTICAL);  Nargs++;
    XtSetArg (Args[Nargs], XmNentryAlignment, XmALIGNMENT_BEGINNING); Nargs++;
    rc_01 = XmCreateRowColumn (form_0, "RowCol_01", Args, Nargs);
    XtManageChild (rc_01);
	    /*
	    **    create labels for RowColumn widgets
	    */
    EncodeMSR (text, sizeof (text), Mot_state.msr,
				    Mot_state.ored_msr,
				    Mot_state.fp_cntr,
				    Mot_state.fr_cntr);
    Label_msr = MakeLabel (rc_00, text, XmALIGNMENT_BEGINNING);

    EncodeSS (text, Mot_state.ss);
    Label_ss = MakeLabel (rc_00, text, XmALIGNMENT_BEGINNING);

    sprintf (text, "Statistics: Total/Faults/Fails/Cush-fails = %d/%d/%d/%d",
			Mot_state.stat_pos,	 Mot_state.stat_pos_flt,
			Mot_state.stat_pos_fail, Mot_state.stat_cush_fail);
    Label_stats = MakeLabel (rc_00, text, XmALIGNMENT_BEGINNING);

    sprintf (text, "Encoder Ratio, FD = %d:%d", Mot_state.enc_factor[0],
						Mot_state.enc_factor[1]);
    Label_fd = MakeLabel (rc_01, text, XmALIGNMENT_BEGINNING);
    sprintf (text, "Motor   Ratio, FM = %d:%d", Mot_state.mot_factor[0],
						Mot_state.mot_factor[1]);
    Label_fm = MakeLabel (rc_01, text, XmALIGNMENT_BEGINNING);
    sprintf (text, "Inertia tol'nce, D = %s", Mot_state.inertia_tol);
    Label_d = MakeLabel (rc_01, text, XmALIGNMENT_BEGINNING);
    sprintf (text, "Start/stop ramp, E = %d", Mot_state.ramp);
    Label_e = MakeLabel (rc_01, text, XmALIGNMENT_BEGINNING);
    switch (Mot_state.loop_mode) {
     case 0:  sprintf (text, "Open loop mode, F = 0");	    break;
     case 1:  sprintf (text, "Closed loop mode, F = 1");    break;
     default: sprintf (text, "Bad loop mode, F = %d", Mot_state.loop_mode);
    }
    Label_f = MakeLabel (rc_01, text, XmALIGNMENT_BEGINNING);
    sprintf (text, "Start/stop  Hz, G = %d", Mot_state.slow_hz);
    Label_g = MakeLabel (rc_01, text, XmALIGNMENT_BEGINNING);
    sprintf (text, "Positioning Hz, J = %d", Mot_state.fast_hz);
    Label_j = MakeLabel (rc_01, text, XmALIGNMENT_BEGINNING);
    switch (Mot_state.ref_mode) {
     case   0: sprintf (text, "Absolute encoder, K = 0"); break;
     case   1: sprintf (text, "HiLimit is RefPt, K = 1"); break;
     case  -1: sprintf (text, "LoLimit is RefPt, K = -1"); break;
     case   2: sprintf (text, "Sep RefPt, K = 2"); break;
     case  11: sprintf (text, "HiLimit is RefPt + Indx, K = 11"); break;
     case -11: sprintf (text, "LoLimit is RefPt + Indx, K = -11"); break;
     case  12: sprintf (text, "Sep RefPt + Indx, K = 12"); break;
     default:  sprintf (text, "RefMode unknown, K = %d", Mot_state.ref_mode);
    }
    Label_k = MakeLabel (rc_01, text, XmALIGNMENT_BEGINNING);
    sprintf (text, "Backlash, L = %d", Mot_state.backlash);
    Label_l = MakeLabel (rc_01, text, XmALIGNMENT_BEGINNING);
    sprintf (text, "Position Tol'nce, M = %d", Mot_state.pos_tol);
    Label_m = MakeLabel (rc_01, text, XmALIGNMENT_BEGINNING);
    sprintf (text, "RefPt Width, Q = %s", Mot_state.ref_param);
    Label_q = MakeLabel (rc_01, text, XmALIGNMENT_BEGINNING);
    if (Mot_state.is_sided == 0) {
      sprintf (text, "No dir'n dependency, T = 0");
    }else if (Mot_state.is_sided > 0) {
      sprintf (text, "Position from above, T = %d", Mot_state.is_sided);
    }else {
      sprintf (text, "Position from below, T = %d", Mot_state.is_sided);
    }
    Label_t = MakeLabel (rc_01, text, XmALIGNMENT_BEGINNING);
    sprintf (text, "NullPt, V = %s", Mot_state.null_pt);
    Label_v = MakeLabel (rc_01, text, XmALIGNMENT_BEGINNING);
    if (Mot_state.ac_par == 0) {
      sprintf (text, "No air-cushion present, W = 0");
    }else if (Mot_state.ac_par == Motor) {
      if (Mot_state.ac_state == 0) {
	sprintf (text, "Air-cushion down");
      }else {
	sprintf (text, "Air-cushion up");
      }
    }else {
      if (Mot_state.ac_state == 0) {
	sprintf (text, "Air-cushion up (chained to %d)", Mot_state.ac_par);
      }else {
	sprintf (text, "Air-cushion down (chained to %d)", Mot_state.ac_par);
      }
    }
    Label_w = MakeLabel (rc_01, text, XmALIGNMENT_BEGINNING);
    if (Mot_state.out == 0) {
      sprintf (text, "Output signal not active", Mot_state.null_pt);
    }else {
      sprintf (text, "Output signal active", Mot_state.null_pt);
    }
    Label_out = MakeLabel (rc_01, text, XmALIGNMENT_BEGINNING);
    if (Mot_state.in == 0) {
      sprintf (text, "Input signal not present");
    }else {
      sprintf (text, "Input signal present");
    }
    Label_in = MakeLabel (rc_01, text, XmALIGNMENT_BEGINNING);
    sprintf (text, "Enc Circum, Z = %d", Mot_state.enc_circ);
    Label_z = MakeLabel (rc_01, text, XmALIGNMENT_BEGINNING);
		/*    
		**      Create DrawnButton in Frame for a bit of research
		*/
#if Blink_On
    Nargs = 0;
    DrawnButFrame = XmCreateFrame (form_0, "Button_Frame", Args, Nargs);
    XtManageChild (DrawnButFrame);

    Nargs = 0;
    XtSetArg (Args[Nargs], XmNminimum, i_left); Nargs++;
    XtSetArg (Args[Nargs], XmNmaximum, i_right); Nargs++;
    XtSetArg (Args[Nargs], XmNwidth, Scale_width/2);  Nargs++;
    XtSetArg (Args[Nargs], XmNheight, 100);  Nargs++;
    DrawnBut = XmCreateDrawnButton (DrawnButFrame, "Drawn_Button", Args, Nargs);
    XtManageChild (DrawnBut);
#endif	/* Blink_On */
	    /*-------------------------------------------------------------
	    **      Organise the components of the Main Form
	    */
    XtVaSetValues (Label_lo_lim,
			XmNtopAttachment, XmATTACH_FORM,
			XmNleftAttachment, XmATTACH_FORM,
			NULL);

    XtVaSetValues (Label_name,
			XmNtopAttachment, XmATTACH_FORM,
			XmNleftAttachment, XmATTACH_WIDGET,
			XmNleftWidget, Label_lo_lim,
			XmNrightAttachment, XmATTACH_WIDGET,
			XmNrightWidget, Label_hi_lim,
			NULL);

    XtVaSetValues (Label_hi_lim,
			XmNtopAttachment, XmATTACH_FORM,
			XmNrightAttachment, XmATTACH_FORM,
			NULL);

    XtVaSetValues (Label_soll,
			XmNtopAttachment, XmATTACH_WIDGET,
			XmNtopWidget, Label_name,
			NULL);
    if (Mot_is_on_left) {
      XtVaSetValues (Label_soll,
			XmNleftAttachment, XmATTACH_POSITION,
			XmNleftPosition, (i_soll - i_left),
			NULL);
    }else {
      XtVaSetValues (Label_soll,
			XmNrightAttachment, XmATTACH_POSITION,
			XmNrightPosition, (i_soll - i_left),
			NULL);
    }

    XtVaSetValues (Scale_soll,
			XmNleftAttachment, XmATTACH_FORM,
			XmNtopAttachment, XmATTACH_WIDGET,
			XmNtopWidget, Label_soll,
			NULL);

    XtVaSetValues (Scale_ist,
			XmNleftAttachment, XmATTACH_FORM,
			XmNtopAttachment, XmATTACH_WIDGET,
			XmNtopWidget, Scale_soll,
			NULL);

    XtVaSetValues (Label_ist,
			XmNtopAttachment, XmATTACH_WIDGET,
			XmNtopWidget, Scale_ist,
			NULL);
    if (Mot_is_on_left) {
      XtVaSetValues (Label_ist,
			XmNleftAttachment, XmATTACH_POSITION,
			XmNleftPosition, (i_ist - i_left),
			NULL);
    }else {
      XtVaSetValues (Label_ist,
			XmNrightAttachment, XmATTACH_POSITION,
			XmNrightPosition, (i_ist - i_left),
			NULL);
    }
    XtVaSetValues (rc_00,
			XmNleftAttachment, XmATTACH_FORM,
			XmNtopAttachment, XmATTACH_WIDGET,
			XmNtopWidget, Label_ist,
			NULL);
    XtVaSetValues (rc_01,
			XmNleftAttachment, XmATTACH_FORM,
			XmNtopAttachment, XmATTACH_WIDGET,
			XmNtopWidget, rc_00,
			NULL);
#if Blink_On
    XtVaSetValues (DrawnButFrame,
			XmNleftAttachment, XmATTACH_FORM,
			XmNtopAttachment, XmATTACH_WIDGET,
			XmNtopWidget, Label_stats,
			NULL);
#endif	/* Blink_On */
    return main_window;
  }
/*
**==========================================================================
**			Main line program
**			------------------
*/
  int   main (int argc, char **argv) {
/*      ============================
*/
    Widget		main_window;	/* MainWindow		*/
    int			status, i;
	/*-------------------------------------------------
	**	Initialize Mot_state to rubbish.
	*/
    memset (&Mot_state, '%', sizeof (Mot_state));
    Mot_state.motor		= Motor;
    Mot_state.exists		= False;
    Mot_state.ored_msr		= 0;
    Mot_state.fp_cntr		= 0;
    Mot_state.fr_cntr		= 0;
    Mot_state.pos_real[15]	= '\0';
    Mot_state.name[15]		= '\0';
    Mot_state.inertia_tol[15]	= '\0';
    Mot_state.lims[0][15]	= '\0';
    Mot_state.lims[1][15]	= '\0';
    Mot_state.ref_param[15]	= '\0';
    Mot_state.null_pt[15]	= '\0';
    Mot_state.set_real[15]	= '\0';
    memcpy (&Old_Mot_state, &Mot_state, sizeof (Mot_state));
	/*
	**	Initialize toolkit and open the display.
	*/
    Wtop_level = XtAppInitialize (&App_context, "SinQ_rc",
			    OpTable, XtNumber(OpTable),
			    &argc, argv, NULL, NULL, 0);

    XtGetApplicationResources (Wtop_level, (XtPointer) &AppData,
                              Resources, XtNumber(Resources), NULL, 0);

    printf ("Motor Client, Version %s\n\n", ident);

    if (strcmp (AppData.vme_motor_host, "Undefined") == 0) {
      printf ("   \"-host\" not specified!\n\n");
      return EXIT_FAILURE;
    }

    if (AppData.v24_chan == 0xffff) {
      printf ("   \"-chan\" not specified!\n\n");
      return EXIT_FAILURE;
    }else if ((AppData.v24_chan < 0) || (AppData.v24_chan > 15)) {
      printf ("   \"-chan\" is illegal!\n\n");
      return EXIT_FAILURE;
    }

    if ((AppData.vme_motor_number <= 0) || (AppData.vme_motor_number > 12)) {
      printf ("   \"-motor\" not specified or illegal!\n\n");
      return EXIT_FAILURE;
    }

    printf ("Motor Server        = \"%s\"\n",
			AppData.vme_motor_host);

    if (AppData.vme_motor_port == 0) {
      AppData.vme_motor_port = 4000;
      printf ("Default TCP/IP Port = %d\n", AppData.vme_motor_port);
    }else {
      printf ("TCP/IP Port         = %d\n", AppData.vme_motor_port);
    }

    printf ("RS-232-C channel    = %d\n", AppData.v24_chan);
    printf ("Polling delay       = %d msec.\n", AppData.msec_timer);
    Scale_width = AppData.scale_width;
    printf ("Scale width         = %d pixels.\n\n", Scale_width);

    Motor = AppData.vme_motor_number;
    printf ("Motor number        = %d.\n\n", Motor);

    printf ("Opening connection to Motor Server ...\n");
    Cnct_skt = ConnectToSrvr (AppData.vme_motor_host,
		     AppData.vme_motor_port);

    Mot_state.motor = Motor;

    printf ("Ensuring EL734 is in \"rmt 1\" mode ...\n");
    status = SendCmndToServer (AppData.v24_chan, TMO,
				&Respon_buff, sizeof (Respon_buff),
				"rmt 1\r", NULL,
				"rmt 1\r", NULL,
				NULL);

    printf ("Ensuring EL734 is in \"echo 0\" mode ...\n");
    status = SendCmndToServer (AppData.v24_chan, TMO,
				&Respon_buff, sizeof (Respon_buff),
				"echo 0\r", NULL,
				NULL);

    printf ("Getting full status of Motor ...\n");
    GetMotorStatus (FULL__STATUS, &Mot_state);
    if (!Mot_state.exists) {
      printf ("\007Selected motor is off-line.\n");
      exit (False);
    }
    memcpy (&Old_Mot_state, &Mot_state, sizeof (Mot_state));
    
    main_window = CreateApplication (Wtop_level);
	/*
	**	Realize Widgets
	*/
    XtRealizeWidget (Wtop_level);
	/*
	**	Make a timer so that the display gets updated regularly.
	*/
    if (AppData.msec_timer > 0) {
      XtAppAddTimeOut (App_context, AppData.msec_timer, TimerCB, NULL);
    } else {
      printf ("msecTimer = 0. Continuous status update disabled.\n");
    }
	/*
	**	process events
	*/
    XtAppMainLoop (App_context);
  }
/*------------------------------------------------------ End of EL734.C */
