/*
 * *************************************************************************
 *
 * Trimble Navigation, Ltd.
 * OEM Products Development Group
 * P.O. Box 3642
 * 645 North Mary Avenue
 * Sunnyvale, California 94088-3642
 *
 * Corporate Headquarter:
 *    Telephone:  (408) 481-8000
 *    Fax:        (408) 481-6005
 *
 * Technical Support Center:
 *    Telephone:  (800) 767-4822	(U.S. and Canada)
 *                (408) 481-6940    (outside U.S. and Canada)
 *    Fax:        (408) 481-6020
 *    BBS:        (408) 481-7800
 *    e-mail:     trimble_support@trimble.com
 *
 * *************************************************************************
 *
 * Vers	Date		   Changes									  Author
 * ----	---------   ----------------------------------------     ----------
 * v1.40
 * 5a10				matched 5.10 manual 						pvwl
 * *************************************************************************
 *
 * TSIP_CMD.C carries the function help_screen() displays the Keystroke
 * Command List in the format (key packet Id description).  For example,
 * (t 0x21 show time) means the keystroke 't' must be pressed in order to
 * request the time the receiver carries whether it is from an upload from
 * the user/computer or from the GPS constellation.  The TSIP commands are
 * displayed in the Keystroke Command List in ascending hexadecimal order.
 *
 * A large case statement in proc_kbd() parses the keyboard inputs and
 * directs processing to the mid-level function specific to the keyboard
 * stroke.  The called function then queries for user parameters and passes
 * them to the appropriate command string generator cmd_0x?? in TSIP_IFC.C.
 * The suffix convention for the command string generator follows:
 *
 *                   cmd_0x??q   -  query
 * 	               cmd_0x??s   -  set
 * 	               cmd_0x??c   -  clear/set to default
 * 	               cmd_0x??e   -  enable
 * 	               cmd_0x??d   -  disable
 *
 * In general, one command code corresponds to one or more keystrokes.
 * There are two exceptions to this single-command model:  Two functions
 * called by proc_kbd(), almgetb() and almputb(), begin a series of tasks
 * that get and load a full set of binary data from and into the receiver.
 * When either functions get invoked, several commands and reports are
 * generated before an exit to the main() function is performed.
 *
 * *************************************************************************
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <dos.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include "tsip_ifc.h"
#include "tsipincl.h"

/* Generate Control-letter character */
#define cntrl(x) ((x)-'A'+0x01)
#define ask_int(x) ask_byte(x)

/* Utility to check on sv_prn values */
short prn_valid (unsigned char sv_prn)
{
	if ((sv_prn > 0) && (sv_prn < 33)) {
      return TRUE;
   }
	xprintf ("SV number must be between 1 and 32 inclusive");
	return FALSE;
}

/**/
/* ***************  USER-PROMPTING ROUTINES FOR COMMANDS ************** */
/* 0x1D */
static void set_osc_offset (void)
{
	float
		offset;

	xprintf ("Input oscillator offset value?");
	if (!ask_verify ()) {
		set_cmd_esc (TRUE);
		return;
	}
	offset = ask_dbl ("Set oscillator offset (Hz) to: ");
	if (cmd_esc ()) return;
	xprintf ("Reset offset to %g Hz?", offset);
	if (!ask_verify_nocmdcrlf ()) {
		set_cmd_esc (TRUE);
		return;
	}
	cmd_0x1Ds (offset);
}

/**/
/* 0x20 */
static void request_almanac_data_page (void)
{
	unsigned char
		sv_prn;

	sv_prn = ask_byte ("Enter SV number: ");
	if (!prn_valid (sv_prn)) set_cmd_esc (TRUE);
	if (cmd_esc ()) return;
	cmd_0x20 (sv_prn);
	return;
}

/* 0x22 */
static void set_nav_mode (void)
{
	unsigned char
		nav_code;
	static char
		*nav_text [7] = {
			"set auto 2-D/3-D ",
			"Time Only Mode   ",
			"",
			"set manual 2-D   ",
			"set manual 3-D   ",
			"auto 2d->2dchg   ",
			"auto 3d->2d->2dch"};

	nav_code = pick_one ("Enter nav mode: ", nav_text, 7);
	if (cmd_esc ()) return;
	cmd_0x22 (nav_code);
}

/* 0x23 */
static void set_initial_ECEF_position (void)
{
	float
		pos_ECEF[3];

	pos_ECEF[0] = ask_dbl ("Enter ECEF x: ");
	if (cmd_esc ()) return;
	pos_ECEF[1] = ask_dbl ("Enter ECEF y: ");
	if (cmd_esc ()) return;
	pos_ECEF[2] = ask_dbl ("Enter ECEF z: ");
	if (cmd_esc ()) return;

	xprintf ("Set new position to %g, %g, %g m ECEF?",
		pos_ECEF[0], pos_ECEF[1], pos_ECEF[2]);
	if (!ask_verify_nocmdcrlf ()) {
		set_cmd_esc (TRUE);
		return;
	}
	cmd_0x23 (pos_ECEF);
	return;
}

/* 0x2A */
static void set_altitude (void)
{
	float
		alt;
	unsigned char
		op_mode;
	char *op_mode_text[2] = {"Disable", "Set"};

	op_mode = pick_one ("Enter mode: ", op_mode_text, 2);
	switch (op_mode)
	{
	case 0:
		cmd_0x2Ad ();
		break;
	case 1:
		alt = ask_dbl ("Enter reference altitude: ");
		if (!cmd_esc ())
		{
			cmd_0x2A (alt);
		}
		break;
	}
	return;
}

/* 0x2B */
static void set_initial_lla_position (void)
{
	float 
		lat, lon, alt;

	lat = ask_dbl ("Enter lat (ø): ");
	if (cmd_esc ()) return;
	lon = ask_dbl ("Enter lon (ø): ");
	if (cmd_esc ()) return;
	alt = ask_dbl ("Enter alt (m): ");
	if (cmd_esc ()) return;

	xprintf("Set new position to %gølat, %gølon, %gm alt?",
		lat, lon, alt);
	if (!ask_verify_nocmdcrlf ()) {
		set_cmd_esc (TRUE);
		return;
	}
	lat *= D2R;
	lon *= D2R;
	cmd_0x2B (lat, lon, alt);
	return;
}

/* 0x2C */
static void set_op_parms (void)
{
	unsigned char
		dyn_code;
	float
		elev_mask, snr, dop_mask, dop_switch;
	static char
		*dyn_text [5] = {"leave unchanged", "land", "sea", "air", "static"};

	dyn_code = pick_one ("Enter dynamics code: ", dyn_text, 5);
	if (cmd_esc ()) return;
	elev_mask = ask_dbl ("Enter elev angle mask, -1 for no change: ");
	if (cmd_esc ()) return;
	snr = ask_dbl ("Enter SNR mask, -1 for no change: ");
	if (cmd_esc ()) return;
	dop_mask = ask_dbl ("Enter DOP mask, -1 for no change: ");
	if (cmd_esc ()) return;
	dop_switch = ask_dbl ("Enter DOP switch, -1 for no change: ");
	if (cmd_esc ()) return;
		xprintf ("Set new masks to %d, %g, %g, %g, %g?",
		dyn_code, elev_mask, snr, dop_mask, dop_switch);
	if (!ask_verify ()) {
		set_cmd_esc (TRUE);
		return;
	}
	/* Convert elevation mask to radians */
	elev_mask *= D2R;
	cmd_0x2Cs (dyn_code, elev_mask, snr, dop_mask, dop_switch);
	return;
}

/* 0x2E */
static void set_time (void)
{
	short
		week_num;
	double
		gpstime;
	float
		time_of_week;
	short	days, hours, minutes;
	float seconds;
	const char
		*dname[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};


	/* set time from PC */
	GPS_time_from_PC (&gpstime);
	if (cmd_esc ()) return;
	week_num = (short) (gpstime/604800.);
	time_of_week = (gpstime - 604800.*week_num);
	xprintf ("GPS week %3d", week_num);
	days = (short)(time_of_week / 86400.0);
	hours = (short)fmod(time_of_week / 3600., 24.);
	minutes =  (short) fmod(time_of_week/60., 60.);
	seconds = fmod(time_of_week, 60.);
	xprintf (" %s %02d:%02d:%05.2f   ", dname[days], hours, minutes, seconds);
	show_crlf ();
	xprintf ("Set receiver time?");
	if (!ask_verify ()) {
		set_cmd_esc (TRUE);
		return;
	}
	cmd_0x2E (time_of_week, week_num);
	return;
}


/**/
/* 0x31 */
static void set_accurate_ECEF_position (void)
{
	float
		pos_ECEF[3];

	xprintf ("CAUTION: Position should be accurate to 50 km");
	show_crlf ();
	pos_ECEF[0] = ask_dbl ("Enter ECEF x: ");
	if (cmd_esc ()) return;
	pos_ECEF[1] = ask_dbl ("Enter ECEF y: ");
	if (cmd_esc ()) return;
	pos_ECEF[2] = ask_dbl ("Enter ECEF z: ");
	if (cmd_esc ()) return;
	xprintf ("Set new position to %g, %g, %g m?",
		pos_ECEF[0], pos_ECEF[1], pos_ECEF[2]);
	if (!ask_verify_nocmdcrlf ()) {
		set_cmd_esc (TRUE);
		return;
	}
	cmd_0x31 (pos_ECEF);
	return;
}

/* 0x32 */
static void set_accurate_LLA_position (void)
{
	float 
		lat, lon, alt;

	xprintf ("CAUTION: Position should be accurate to 50 km");
	show_crlf ();
	lat = ask_dbl ("Enter lat (ø): ");
	if (cmd_esc ()) return;
	lon = ask_dbl ("Enter lon (ø): ");
	if (cmd_esc ()) return;
	alt = ask_dbl ("Enter alt (ø): ");
	if (cmd_esc ()) return;
	xprintf("Set new position to %gølat, %gølon, %gm alt?",
		lat, lon, alt);
	if (!ask_verify_nocmdcrlf ()) {
		set_cmd_esc (TRUE);
		return;
	}
	/* Convert lat and lon to radians */
	lat *= D2R;
	lon *= D2R;
	cmd_0x32 (lat, lon, alt);
	return;
}

/* 0x34 */
static void set_SV_for_1SV_mode (void)
{
	unsigned char
		sv_prn;
	
	sv_prn = ask_byte ("Enter SV PRN number Time Only mode (0 for Auto Mode): ");
	if (sv_prn != 0) {
		if (!prn_valid (sv_prn)) {
			set_cmd_esc (TRUE);
	  }
   }
	if (cmd_esc ()) return;
	cmd_0x34 (sv_prn);
	return;
}

/* 0x35 */
static void set_IO_options (void)
{
	unsigned char
		hexnum, hexbyte[5];
	static short
		last_spkt_type;
	static char
		*spkt_text[4] = {"none",
			"8F-20 (fixed-point)",
			"UTM (single precision)",
			"UTM (double precision)"},
		*toggle_text[2] = {"off", "on"},
		*alt_text[2] = {"WGS-84", "MSL   "},
		*prec_text[2] = {"single", "double"},
		*time_text[2] = {"GPS", "UTC"},
		*latent_text[2] = {"ASAP               ", "next integer second"},
		*query_text[2] = {"when computed  ", "only on request"},
		*raw_text[2] = {"raw (unfiltered)", "Doppler-smoothed"};

	short
		bit0, bit1, bit2, bit3, bit4, bit5,
		pos_code, vel_code, time_code, aux_code,
		spkt_type;

	xprintf ("Enter full menu instead of hex codes?");
	if (!ask_verify ())
	{
		if (cmd_esc ()) return;
		hexnum = ask_hex_string ("Default is 1 1 0 0: ", hexbyte);
		if (hexnum != 4)
		{
			set_cmd_esc (TRUE);
		}
		else
		{
			pos_code = hexbyte[0];
			vel_code = hexbyte[1];
			time_code = hexbyte[2];
			aux_code = hexbyte[3];
		}
		if (cmd_esc ()) return;
	}
	else
	{ /* position code */
		bit0 = pick_one ("ECEF position output: ", toggle_text, 2);
		if (cmd_esc ()) return;
		bit1 = pick_one ("LLA position output: ", toggle_text, 2);
		if (cmd_esc ()) return;
		if (bit1 == 1)
		{
			bit2 = pick_one ("altitude output: ", alt_text, 2);
			if (cmd_esc ()) return;
		}
		else
		{
			bit2 = 0;
		}
		bit3 = pick_one ("altitude input: ", alt_text, 2);
		if (cmd_esc ()) return;
		bit4 = pick_one ("output precision: ", prec_text, 2);
		if (cmd_esc ()) return;
		bit5 = pick_one ("Superpacket output: ", toggle_text, 2);
		if (cmd_esc ()) return;
		pos_code = bit0+(2*bit1)+(4*bit2)+(8*bit3)+(16*bit4)+(32*bit5);

		/* velocity code */
		bit0  = pick_one ("ECEF velocity output: ", toggle_text, 2);
		if (cmd_esc ()) return;
		bit1  = pick_one ("ENU velocity output: ", toggle_text, 2);
		if (cmd_esc ()) return;
		vel_code = bit0 + (2 * bit1);

		/* time code */
		bit0 = pick_one ("Time tags in: ", time_text, 2);
		if (cmd_esc ()) return;
      bit1 = pick_one ("Fix computation time: ", latent_text, 2);
		if (cmd_esc ()) return;
		bit2 = pick_one ("Output time: ", query_text, 2);
		if (cmd_esc ()) return;
		bit3 = pick_one ("Synchronized measmts: ", toggle_text, 2);
		if (cmd_esc ()) return;
		bit4 = pick_one ("Min measmt propagate: ", toggle_text, 2);
		if (cmd_esc ()) return;
		time_code = bit0 + (2 * bit1) + (4 * bit2) + (8 * bit3) + (16 * bit4);

		/* auxiliary code */
		bit0 = pick_one ("Pseudorange output: ", toggle_text, 2);
		if (cmd_esc ()) return;
		if (bit0 == 1) {
			bit1  = pick_one ("Pseudorange quality: ", raw_text, 2);
			if (cmd_esc ()) return;
		} else {
		 bit1 = 0;
	  }
		bit2 = pick_one ("Additional fix status: ", toggle_text, 2);
		if (cmd_esc ()) return;
		aux_code = bit0 + (2 * bit1) + (4 * bit2);
	}
	show_crlf ();
	xprintf ("Set new I/O options to %2X%2X%2X%2X?",
		pos_code, vel_code, time_code, aux_code);
	if (!ask_verify ()) {
		set_cmd_esc (TRUE);
		return;
	}
	if (pos_code & 0x20)
	{
		spkt_type = pick_one ("Superpacket_type: ", spkt_text, 4);
		if (cmd_esc ()) return;
		if (last_spkt_type != spkt_type)
		{
			/* disable old choice */
			switch (last_spkt_type)
			{
			case 1: cmd_0x8E20d(); break;
			case 2: cmd_0x8E17d(); break;
			case 3: cmd_0x8E18d(); break;
			}
		}
		/* enable new choice */
		switch (spkt_type)
		{
		case 1: cmd_0x8E20e(); break;
		case 2: cmd_0x8E17e(); break;
		case 3: cmd_0x8E18e(); break;
		}
		last_spkt_type = spkt_type;
	}
	cmd_0x35s (pos_code, vel_code, time_code, aux_code);
}

/* 0x36 */
static void initial_velocity (void)
{
	unsigned char
		frame, enable;
	static char
		*frame_text[2] = {"XYZ", "ENU"};
	static char
		*enable_text[2] = {"Enable", "Disable"};
	float
		vel [3];

	enable = pick_one ("Mode: ", enable_text, 2);
	if (cmd_esc ()) return;

	frame = pick_one ("Enter coordinate frame: ", frame_text, 2);
	if (cmd_esc ()) return;

	vel[0] = ask_dbl ("Enter first vel coord: ");
	if (cmd_esc ()) return;
	vel[1] = ask_dbl ("Enter second vel coord: ");
	if (cmd_esc ()) return;
	vel[2] = ask_dbl ("Enter third vel coord: ");
	if (cmd_esc ()) return;
	xprintf ("Send %s velocity as %g, %g, %g m/s?",
		frame ? "ENU" : "XYZ", vel[0], vel[1], vel[2]);
	if (!ask_verify_nocmdcrlf ()) {
		set_cmd_esc (TRUE);
		return;
	}
	cmd_0x36 (frame, enable, vel);
	return;
}

/* 0x38 */
static void request_SV_system_data (void)
{
	unsigned char
		type_of_data,
		sv_prn;
	static char
		*type_text[7] = {"", "", "almanac", "health page, t_oa, wn_oa",
		"ionosphere", "UTC", "ephemeris"};

   /*
	* For loading, a data buffer must be supplied from somewhere
	* with the information to be loaded.  Because misloading of
	* data can cause the receiver to act erratic, the load
	* feature is not implemented here.
	* cmd_0x38s (type_of_data, sv_prn, nbytes, databuf);
	*/
	type_of_data = pick_one ("Type of data: ", type_text, 7);
	if (cmd_esc ()) return;

	if ((type_of_data == 2) || (type_of_data == 6)) {
		sv_prn = ask_byte ("Enter SV number: ");
		if (!prn_valid(sv_prn)) set_cmd_esc (TRUE);
		if (cmd_esc ()) return;
	} else {
	  sv_prn = 0;
   }
	cmd_0x38q (type_of_data, sv_prn);
}


/* 0x39 */
static void request_disable_or_health_override_list (void)
{
	unsigned char
		op_code, sv_prn;
	static char
		*op_text[7] = {"", "enable SV", "disable SV", 
		"list enabled/disabled", "heed SV health", 
		"ignore SV health", "list heed/ignore health"};

	op_code = pick_one ("Enter operation code: ", op_text, 7);
	if (cmd_esc ()) return;

	sv_prn = 0;
	if ((op_code != 3) && (op_code != 6)) {
		sv_prn = ask_byte ("Enter SV PRN number or 0 for all:  ");
		if (cmd_esc ()) return;
		if (sv_prn == 0) {
			xprintf ("Do %s for all SVs?", op_text[op_code]);
			if (!ask_verify ()) set_cmd_esc (TRUE);
		} else if (!prn_valid(sv_prn)) {
			set_cmd_esc (TRUE);
		} else {
			xprintf ("Do %s for for SV%2.2d?", op_text[op_code], sv_prn);
			if (!ask_verify ()) set_cmd_esc (TRUE);
		}
		if (cmd_esc ()) return;
		xprintf ("No reply will be sent.");
	}
	cmd_0x39 (op_code, sv_prn);
	return;
}

/* 0x3A */
static void request_raw_msmt_data (void)
{
	unsigned char
		sv_prn;

	sv_prn = ask_byte ("Enter SV PRN number or 0 for all: ");
	if (sv_prn) if (!prn_valid (sv_prn)) set_cmd_esc (TRUE);
	if (cmd_esc ()) return;
	cmd_0x3A (sv_prn);
	return;
}

/* 0x3B */
static void request_ephemeris_status (void)
{
	unsigned char
		sv_prn;

	sv_prn = ask_byte ("Enter SV PRN number or 0 for all: ");
	if (sv_prn) {
      if (!prn_valid (sv_prn)) {
         set_cmd_esc (TRUE);
      }
   }
	if (cmd_esc ()) return;
	cmd_0x3B (sv_prn);
	return;
}

/* 0x3C */
static void request_track_info (void)
{
	unsigned char
		sv_prn;
	
	sv_prn = ask_byte ("Enter SV PRN number or 0 for all: ");
	if (sv_prn != 0) {
      if (!prn_valid (sv_prn)) {
         set_cmd_esc (TRUE);
      }
   }
	if (cmd_esc ()) return;
	cmd_0x3C (sv_prn);
	return;
}

/* 0x3D */
static void set_channel_a_config (short *reply)
{
	short
		i, j;

	unsigned char
		baud_out,         /* XMT baud rate */
		baud_inp,         /* RCV baud rate */
		char_code,        /* parity and #bits per unsigned char */
		stopbitcode,      /* number of stop bits code */
		output_mode,      /* Ch. A transmission mode */
		input_mode;       /* Ch. A reception mode */
	char
		prompt[40];
	static unsigned char
		baudnum[MAX_BAUD]       =  {0, 1, 4, 5, 6, 8, 9, 11, 12, 28};
	static char
		*databit_text[4]        =  {"", "", "7", "8"},
		*parity_text[5]         =  {"even", "odd", "", "", "no"},
		*baud_text[MAX_BAUD]    =  {"50 bps", "110 bps", "300 bps", "600 bps",
											"1200 bps", "2400 bps", "4800 bps",
											"9600 bps", "38.4k bps", "19.2k bps"},
		*stop_bit_text[3]       =  {"", "1", "2"},
		*tx_mode_text[6]        =  {"Packets", "No output",
											"", "",
											"", "NMEA 0183"},
		*rx_mode_text[2]        =  {"Packets", "Raw RTCM data"};

	i = pick_one ("Enter XMT Baud Rate: ", baud_text, MAX_BAUD);
	if (cmd_esc ()) return;
	baud_out = baudnum[i];

	i = pick_one ("Enter RCV Baud Rate: ", baud_text, MAX_BAUD);
	if (cmd_esc ()) return;
	baud_inp = baudnum[i];

	i = pick_one ("Enter bits/char: ", databit_text, 4);
	if (cmd_esc ()) return;
	sprintf (prompt, "Enter parity: %s-", databit_text[i]);

	j = pick_one (prompt, parity_text, 5);
	if (cmd_esc ()) return;
	char_code = i + (j << 2);

	sprintf (prompt, "Enter stop bits: %s-%s-", databit_text[i], parity_text[j]);
	i = pick_one (prompt, stop_bit_text, 3);
	if (cmd_esc ()) return;
	if (i == 1)             /* 0x07 */
		stopbitcode = 0x07;
	else if (i == 2)        /* 2 stop bits code */
		stopbitcode = 0x0F;

	i = pick_one ("Enter XMT language: ", tx_mode_text, 6);
	if (cmd_esc ()) return;
	output_mode = i;
	i = pick_one ("Enter RCV language: ", rx_mode_text, 2);
	if (cmd_esc ()) return;
	input_mode = i;

	xprintf ("CAUTION: This command may hang a single-port receiver");
	show_crlf ();
	xprintf ("Change settings?");
	if (!ask_verify ()) {
		set_cmd_esc (TRUE);
		return;
	}
   cmd_0x3Ds (baud_out, baud_inp, char_code,
      stopbitcode, output_mode, input_mode);
   reply [0x3D] = 1;
   return;
}

/* 0x3E */
static void request_aux_fix_parms (void)
{
	cmd_0x3E ();
	return;
}

/**/
/* 0x62 */
static void set_or_request_DGPS_mode (void)
{
	unsigned char
		dgps_mode;
	static char
		*dgps_mode_text[5] = {
		"Manual GPS (DGPS off)",
		"Manual GPD (DGPS Req'd)",
		"Auto DGPS/GPS",
		"",
		"Query receiver for current mode"};

	dgps_mode = pick_one ("Enter DGPS mode: ", dgps_mode_text, 5);
	/* dgps_mode other than 0, 1, 2, or 3 results in query */
	/* this subroutine sets dgps_mode to 4 for query */
	if (cmd_esc ()) return;
	if (dgps_mode < 4) {
		xprintf ("Set DGPS mode to %s?", dgps_mode_text[dgps_mode]);
		if (!ask_verify ()) {
			set_cmd_esc (TRUE);
			return;
		}
		cmd_0x62s (dgps_mode);
	} else {
		cmd_0x62q ();
	}
	return;
}

/* 0x65 */
static void request_DGPS_corrections (void)
{
	unsigned char
		sv_prn;

	sv_prn = ask_byte ("Enter SV PRN number (0 for all): ");
	if (sv_prn) if (!prn_valid (sv_prn)) set_cmd_esc (TRUE);
	if (cmd_esc ()) return;
	cmd_0x65 (sv_prn);
	return;
}

/**/
/* 0x71 */
void set_pos_filter_parms (void)
{
   /* mode is set to default at program onset; otherwise, mode
	  remembers the last setting (receiver setting at program
	  startup is not known)
   */
	unsigned char
		temp_pf;
	TSIP_POS_FILT_PARMS
		temp_params;
	static unsigned char
		pf;
	const TSIP_POS_FILT_PARMS
		default_params =  {
			.0625, 1, 1, 0, 6, .1, 100., 1.21, 1000000., 2};
	static TSIP_POS_FILT_PARMS
		current_params = {
			.0625, 1, 1, 0, 6, .1, 100., 1.21, 1000000., 2};
	short
		mode;
	static char
		*able_text[5] = {"DISABLE", "DISABLE STATIC ONLY",
			"ENABLE ", "RESET", "CHANGE"};

	mode = pick_one ("Position filter: ", able_text, 5);
	temp_params = current_params;
	temp_pf = pf;
	if (cmd_esc ()) return;
	switch (mode) {
	case 0:  /* do not change parameters */
		temp_pf = 0;
		break;

	case 1:  /* do not change parameters */
		temp_pf = 1;
		temp_params.chr5 = 0xFF;
		break;

	case 2:  /* do not change parameters */
		temp_pf = 1;
		break;

	case 3:  /* go back to orig */
		temp_pf = 1;
		temp_params = default_params;
		break;

	case 4:
		temp_pf = 1;
		temp_params.flt1 = ask_dbl ("flt1: ");
		if (cmd_esc ()) return;
		temp_params.chr1 = ask_byte ("chr1: ");
		if (cmd_esc ()) return;
		temp_params.chr2 = ask_byte ("chr2: ");
		if (cmd_esc ()) return;
		temp_params.chr3 = ask_byte ("chr3: ");
		if (cmd_esc ()) return;
		temp_params.chr4 = ask_byte ("chr4: ");
		if (cmd_esc ()) return;
		temp_params.flt2 = ask_dbl ("flt2: ");
		if (cmd_esc ()) return;
		temp_params.flt3 = ask_dbl ("flt3: ");
		if (cmd_esc ()) return;
		temp_params.flt4 = ask_dbl ("flt4: ");
		if (cmd_esc ()) return;
		temp_params.flt5 = ask_dbl ("flt5: ");
		if (cmd_esc ()) return;
		temp_params.chr5 = ask_byte ("chr5 (255 = static filter disabled): ");
		if (cmd_esc ()) return;
	  break;
	}
	xprintf ("Reset filter settings to: ");
	xprintf("%s", pf ? "ENABLED" : "DISABLED");
	show_crlf ();
	xprintf("flt1:%.5f chr1:%.1d chr2:%1d chr3:%1d chr4:%2d",
		temp_params.flt1, temp_params.chr1, temp_params.chr2,
		temp_params.chr3, temp_params.chr4);
	show_crlf ();
	xprintf("flt2:%.3f flt3:%.0f flt4:%.3f flt5:%.0f chr5:%d?",
		temp_params.flt2, temp_params.flt3, temp_params.flt4,
		temp_params.flt5, temp_params.chr5);

   if (!ask_verify ()) {
		set_cmd_esc (TRUE);
		return;
	}
	pf = temp_pf;
	current_params = temp_params;
	cmd_0x71s (pf, &current_params);
}

/* 0x73 */
static void set_altitude_filter_parms (void)
{
	float
		time_constant;
	static char
		*mode_text[4] = {"DISABLE", "CHANGE ", "CLEAR  ", "QUERY  "};
	short
		mode;

	mode = pick_one ("Altitude filter: ", mode_text, 4);
	if (cmd_esc ()) return;
	switch (mode) {
	case 0:
		cmd_0x73d ();
		break;

	case 1:
		time_constant = ask_dbl(
			"Enter altitude time constant (# fixes) (0=default): ");
		if (cmd_esc ()) return;
		xprintf("num fixes: %.2f?", time_constant);
		if (!ask_verify ()) {
			set_cmd_esc (TRUE);
			return;
		}
		cmd_0x73s (time_constant);
		break;

	case 2:
		cmd_0x73c ();
		break;

	case 3:
		cmd_0x73q ();
		break;
	}
}

/* 0x75 */
static void set_track_mode (void)
{
	static char
		*trackmode_text[3] = {"Track high 8, best-4 fix",
		"Track high 6, over-determined fix", "Track high 8, over-determined fix"};
	unsigned char
		trackmode;

	/*  set track and fix mode */
	trackmode = pick_one ("Tracking mode: ", trackmode_text, 3);
   if (cmd_esc ()) return;
	xprintf ("Set tracking mode to: %s", trackmode_text[trackmode]);
	if (!ask_verify ()) {
		set_cmd_esc (TRUE);
		return;
	}
	cmd_0x75s (trackmode);
}

/* 0x77 */
static void set_DGPS_maxage (void)
{
	short maxage;

   maxage = ask_int("Enter Maximum age for differential corrections: ");
	if (cmd_esc ()) return;
   xprintf ("Set new maxage to %2d secs?", maxage);
   if (!ask_verify_nocmdcrlf ()) {
		set_cmd_esc (TRUE);
	   return;
	}
   cmd_0x77s (maxage);
   return;
}

/* 0x8E03 */
static void set_channel_b_config (void)
{
	short
		i, j;

	unsigned char
		baud_out,         /* XMT baud rate */
		baud_inp,         /* RCV baud rate */
		char_code,        /* parity and #bits per unsigned char */
		stopbitcode,      /* number of stop bits code */
		output_mode,      /* Ch. B transmission mode */
		input_mode;       /* Ch. B reception mode */
	char
		prompt[40];
	static unsigned char
		baudnum[MAX_BAUD]       =  {0, 1, 4, 5, 6, 8, 9, 11, 12, 28};
	static char
		*databit_text[4]        =  {"", "", "7", "8"},
		*parity_text[5]         =  {"even", "odd", "", "", "no"},
		*baud_text[MAX_BAUD]    =  {"50 bps", "110 bps", "300 bps", "600 bps",
											"1200 bps", "2400 bps", "4800 bps",
											"9600 bps", "38.4k bps", "19.2k bps"},
		*stop_bit_text[3]       =  {"", "1", "2"},
		*tx_mode_text[6]        =  {"Packets", "No output",
											"", "",
											"", "NMEA 0183"},
		*rx_mode_text[2]        =  {"Packets", "Raw RTCM data"};

	i = pick_one ("Enter XMT Baud Rate: ", baud_text, MAX_BAUD);
	if (cmd_esc ()) return;
	baud_out = baudnum[i];

	i = pick_one ("Enter RCV Baud Rate: ", baud_text, MAX_BAUD);
	if (cmd_esc ()) return;
	baud_inp = baudnum[i];

	i = pick_one ("Enter bits/char: ", databit_text, 4);
	if (cmd_esc ()) return;
	sprintf (prompt, "Enter parity: %s-", databit_text[i]);

	j = pick_one (prompt, parity_text, 5);
	if (cmd_esc ()) return;
	char_code = i + (j << 2);

	sprintf (prompt, "Enter stop bits: %s-%s-", databit_text[i], parity_text[j]);
	i = pick_one (prompt, stop_bit_text, 3);
	if (cmd_esc ()) return;
	if (i == 1)             /* 0x07 */
		stopbitcode = 0x07;
	else if (i == 2)        /* 2 stop bits code */
		stopbitcode = 0x0F;

	i = pick_one ("Enter XMT language: ", tx_mode_text, 6);
	if (cmd_esc ()) return;
	output_mode = i;
	i = pick_one ("Enter RCV language: ", rx_mode_text, 2);
	if (cmd_esc ()) return;
	input_mode = i;

	xprintf ("CAUTION: This command may hang a single-port receiver");
	show_crlf ();
	xprintf ("Change settings?");
	if (!ask_verify ()) {
		set_cmd_esc (TRUE);
		return;
	}
	cmd_0x8E03s (baud_out, baud_inp, char_code,
		stopbitcode, output_mode, input_mode);
	return;
}

static void set_std_datum (void)
{
	unsigned char
		datum_index;

	datum_index = ask_byte ("TSIP datum code:  ");
	if (datum_index > 179)
	{
		show_crlf();
		xprintf ("Incorrect datum value, %d", datum_index);
		set_cmd_esc (TRUE);
	}
	if (cmd_esc ()) return;
	xprintf ("Setting datum index to %d", datum_index);
	cmd_0x8E14s (datum_index);
	return;
}

/* 0x8E-17, -18, -20 */
static void superpacket_control (unsigned char spkt_type)
{
	unsigned char
		mode, cmdbuflen, cmdbuf[3];
	static char
		*superpacket_enable[3] = {"off", "on", "query"};


	mode = pick_one ("Superpacket output:  ", superpacket_enable, 3);
	if (mode > 1) {
		cmdbuflen = 1;
		cmdbuf[0] = spkt_type;
	} else {
		cmdbuflen = 2;
		cmdbuf[0] = spkt_type;
		cmdbuf[1] = mode;
	}
	cmd_0x8E (cmdbuf, cmdbuflen);
}

/* 0x8E19 */
static void set_or_request_UTM_status (void)	/* obslete; use 8E-17 or -18 */
{
	short query;
   static char *status_string[] = {"Enable", "Disable", "No Change"};

	query = pick_one ("Select UTM position state: ", status_string, 3);
	if (cmd_esc ()) return;
	switch (query) {
	case 0:
		xprintf ("Enable UTM position output messages? ");
		if (!ask_verify_nocmdcrlf ()) {
			set_cmd_esc (TRUE);
			return;
		}
		cmd_0x8E19s (0x45);
		break;

	case 1:
		xprintf ("Disable UTM position output messages? ");
		if (!ask_verify_nocmdcrlf ()) {
			set_cmd_esc (TRUE);
			return;
		}
		cmd_0x8E19s (0x44);
		break;

	case 2:		/* current UTM message enable/disable */
		cmd_0x8E19q ();
		break;

	default:
		break;
	}
}

/**/
/* list of keyboard strokes and command each invokes */
#define NUM_ALL_CMDS 48
static KB_CMD kb_all_cmd[NUM_ALL_CMDS] = {
	{" f",  'f', 0x1D, 0x00, "clear osc offset "},
	{" F",  'F', 0x1D, 0x00, "set osc offset   "},
	{"^K", 0x0B, 0x1E, 0x45, "clear battery RAM"},
	{" v",  'v', 0x1F, 0x45, "show S/W version "},
	{" A",  'A', 0x20, 0x40, "almanac data     "},
	{" t",  't', 0x21, 0x41, "show time        "},
	{" z",  'z', 0x21, 0x41, "sync PC to UTC   "},
	{" n",  'n', 0x22, 0x6D, "set set nav mode "},
	{" i",  'i', 0x23, 0x00, "input XYZ pos    "},
	{" M",  'M', 0x24, 0x6D, "show nav mode    "},
	{"^R", 0x12, 0x25, 0x45, "reset receiver   "},
	{" h",  'h', 0x26, 0x46, "receiver health  "},
	{" s",  's', 0x27, 0x47, "show sig levels  "},
	{" m",  'm', 0x28, 0x48, "GPS sys message  "},
	{" a",  'a', 0x29, 0x49, "almanac health   "},
	{"^A", 0x01, 0x2A, 0x4A, "altitude for 2-D "},
	{" I",  'I', 0x2B, 0x00, "input LLA pos    "},
	{" p",  'p', 0x2C, 0x4C, "show mask parms  "},
	{" P",  'P', 0x2C, 0x4C, "set mask parms   "},
	{" o",  'o', 0x2D, 0x4D, "show osc offset  "},
	{" T",  'T', 0x2E, 0x4E, "set time from PC "},
	{" u",  'u', 0x2F, 0x4F, "show UTC info    "},
	{" b",  'b', 0x31, 0x00, "set acc ECEF pos "},
	{" B",  'B', 0x32, 0x00, "set acc LLA pos  "},
	{" S",  'S', 0x34, 0x00, "set SV Time Mode "},
	{" O",  'O', 0x35, 0x55, "show I/O options "},
	{"^O", 0x0F, 0x35, 0x55, "set I/O options  "},
	{"^V", 0x16, 0x36, 0x00, "velocity input   "},
	{" w",  'w', 0x37, 0x57, "show last fix    "},
	{" $",  '$', 0x38, 0x58, "set/recv SV data "},
	{" d",  'd', 0x39, 0x59, "disable/ign hlth "},
	{" <",  '<', 0x3A, 0x5A, "show raw meas    "},
	{" e",  'e', 0x3B, 0x5B, "ephemeris info   "},
	{" >",  '>', 0x3C, 0x5C, "show track status"},
	{" U",  'U', 0x3D, 0x3D, "show Ch A format "},
	{"^U", 0x15, 0x3D, 0x3D, "set Ch A format  "},
	{" Z",  'Z', 0x3E, 0x5E, "show aux fix prms"},
	{" D",  'D', 0x62, 0x82, "set DGPS mode    "},
	{" /",  '/', 0x65, 0x85, "show DGPS info   "},
	{" l",  'l', 0x71, 0x72, "show pos flt pms "},
	{" L",  'L', 0x71, 0x72, "set pos flt prms "},
	{" H",  'H', 0x73, 0x74, "height filter    "},
	{" j",  'j', 0x75, 0x76, "show track mode  "},
	{" J",  'J', 0x75, 0x76, "set track mode   "},
	{" G",  'G', 0x77, 0x78, "set DGPS max age "},
	{" g",  'g', 0x77, 0x78, "show DGPS max age"},
	{" =",  '=', 0x8E, 0x8F, "extended cmds    "},
	{" %",  '%', 0x13, 0x13, "generic cmds     "}

};

#define NUM_8E_CMDS 9
static KB_CMD kb_8e_cmd[NUM_8E_CMDS] = {
	{" b",  'b', 0x03, 0x100 + 0x03, "show Ch B format "},
	{" B",  'B', 0x03, 0x100 + 0x03, "set Ch B format  "},
	{" d",  'd', 0x14, 0x100 + 0x14, "show datum index "},
	{" D",  'D', 0x14, 0x100 + 0x14, "set  datum index "},
	{" e",  'e', 0x17, 0x100 + 0x17, "UTM SglPrec spkt "},
	{" E",  'E', 0x18, 0x100 + 0x18, "UTM DblPrec spkt "},
	{" f",  'f', 0x19, 0x100 + 0x19, "UTM set (obs)    "},
	{" g",  'g', 0x20, 0x100 + 0x20, "Std PosVel spkt  "},
	{" =",  '=', 0x00,         0x00, "generic 8E pkt   "}
};

#define NUM_REPEAT_CMDS 6
static KB_CMD kb_repeat_cmd[NUM_REPEAT_CMDS] = {
	{" t",  't', 0x21, 0x41, "show time        "},
	{" o",  'o', 0x2D, 0x4D, "show osc offset  "},
	{" <",  '<', 0x3A, 0x5A, "show raw meas    "},
	{" s",  's', 0x27, 0x47, "show sig levels  "},
	{" >",  '>', 0x3C, 0x5C, "show track status"},
	{" /",  '/', 0x65, 0x85, "show DGPS info   "}
};

short get_menu (short code, KB_CMD **kb_cmd_list, short *num_kb_cmds)
{
	switch (code) {
	case REPEAT_MENU:
		*kb_cmd_list = kb_repeat_cmd;
		*num_kb_cmds = NUM_REPEAT_CMDS;
		break;

	case ALL_MENU:
		*kb_cmd_list = kb_all_cmd;
		*num_kb_cmds = NUM_ALL_CMDS;
		break;
	case x8E_MENU:
		*kb_cmd_list = kb_8e_cmd;
		*num_kb_cmds = NUM_8E_CMDS;
		break;

	default:
		return 1;
	}
	return 0;
}

/* When '?' is pressed, a command list is displayed and a FALSE is   */
/* returned. When unrecognized keystroke is entered, error message   */
/* appears and a FALSE is returned. Otherwise, the command code gets */
/* loaded and a TRUE is returned.                                    */
void display_cmds (short code)
{
	short
		icmd, icol, irow, col_len,
		num_kb_cmds;
	KB_CMD
		*kb_cmd_list;

	get_menu (code, &kb_cmd_list, &num_kb_cmds);
   highvideo ();
	xprintf ("Keystroke Command List (Key Pkt-ID Description):");
   normvideo ();
   textcolor (LIGHTGRAY);
   textbackground (BLUE);
	clreol ();
	col_len = (num_kb_cmds + 2) / 3;
	for (irow = 0; irow < col_len; irow++) {
		show_crlf ();
		for (icol = 0; icol < 3; icol++) {
			icmd = irow + (col_len * icol);
			if (icmd >= num_kb_cmds) break;
			xprintf (" %s 0x%2.2X %s", kb_cmd_list[icmd].kb_stroke,
				kb_cmd_list[icmd].cmdcode, kb_cmd_list[icmd].cmdtext);
		}
	}
	show_crlf ();
}

void confirm_keystroke (short code, KB_CMD *kb_cmd)
{
	KB_CMD
		*kb_cmd_list;
	unsigned char
		kbch;
	short
		num_kb_cmds, ikb;

	kbch = kb_cmd->kbch;
	get_menu (code, &kb_cmd_list, &num_kb_cmds);
	for (ikb = 0; ikb < num_kb_cmds; ikb++) {
		if (kbch == kb_cmd_list[ikb].kbch) {
			clreol ();
			*kb_cmd = kb_cmd_list[ikb];
			xprintf (" '%s'   0x%2.2X    %s", kb_cmd->kb_stroke,
				kb_cmd->cmdcode, kb_cmd->cmdtext);
			show_crlf ();
			return;
		}
	}
	if (isprint (kbch) || ((kbch >= cntrl('A')) && (kbch <= cntrl('Z')))) {
		xprintf ("Keystroke Unknown");
	}
	clreol ();
	kb_cmd->kbch = 0x1B;
	kb_cmd->cmdcode = 0;
	kb_cmd->replycode = 0;
}

short menu_cmd_prompt (short code, KB_CMD *kb_cmd)
{
	static char* bottom_line =
{"^W=Repeat ;  <Esc>=Exit;  ^F,^G=log, log hour;  !,@=down,upload alm;  ^I=RS232"};
	start_menu_window ();
	display_cmds (code);
	if (code == ALL_MENU) {
	  xprintf (bottom_line);
	  show_crlf ();
   }
   highvideo ();
	xprintf ("Enter Keystroke: ");
   normvideo ();
   textcolor (LIGHTGRAY);
   textbackground (BLUE);
	kb_cmd->kbch = read_rpts_wait_for_kbhit ();
	confirm_keystroke (code, kb_cmd);
	end_menu_window ();
	return (kb_cmd->kbch == 0x1B);
}

short subcode_8E_command (KB_CMD *kb_cmd)
{
	unsigned char
		cmdbuflen, cmdbuf[20];

	menu_cmd_prompt (x8E_MENU, kb_cmd);
	switch (kb_cmd->kbch) {
	case 0x1B:
		return 1;

	case 'b':
		cmd_0x8E03q();
		break;

	case 'B':
		set_channel_b_config ();
		break;

	case 'd':
		/* not available in 5.02 or earlier; use 8e15q() instead */
		cmd_0x8E14q ();
		break;

	case 'D':
		set_std_datum();
		break;

	case 'e':	/* UTM Sgl Prec Spkt */
		/* not available in 5.02 or earlier;
		 * use set_or_request_UTM_status() instead */
		superpacket_control (0x17);
		break;

	case 'E':	/* UTM Dbl Prec Spkt */
		/* not available in 5.02 or earlier;
		 * use set_or_request_UTM_status() instead */
		superpacket_control (0x18);
		break;

	case 'f':
		set_or_request_UTM_status ();
		break;

	case 'g':	/* Std Superpacket */
		superpacket_control (0x20);
		break;

	case '=':	/* unsigned char string */
		cmdbuflen = ask_hex_string ("8E command string (9 bytes): ", cmdbuf);
		cmd_0x8E (cmdbuf, cmdbuflen);
		kb_cmd->replycode = 0x100 + cmdbuf[0];
		kb_cmd->cmdcode = 0x100 + cmdbuf[0];
		break;
	}
	return 0;
}

/* returns TRUE if a command is to be sent to the receiver; otherwise   */
/* a FALSE is returned                                                  */
void proc_kbd (unsigned char kbch, short *reply)
{
	short
      num_replies = 1;
	KB_CMD
		kb_cmd;

	set_cmd_esc (FALSE);
	kb_cmd.kbch = kbch;
	confirm_keystroke (ALL_MENU, &kb_cmd);
	if (kb_cmd.kbch == 0x1B) {
		return;
	}
	switch (kb_cmd.kbch) {  /* TSIP commands */
	case 'f':
		xprintf ("Clear oscillator offset?");
		if (!ask_verify_nocmdcrlf()) {
			set_cmd_esc (TRUE);
		}
		cmd_0x1Dc ();
		break;

	case 'F':
		set_osc_offset ();
		break;

	case 0x0B:	/* cntrl k */
		xprintf ("Do you really wish to clear battery backed-up RAM?");
		if (!ask_verify_nocmdcrlf ()) {
			set_cmd_esc (TRUE);
		} else {
			cmd_0x1E ('K');
		}
		break;

	case 'v':   /* request SW version */
		cmd_0x1F ();
		break;

	case 'A':
		request_almanac_data_page ();
		break;

	case 't':   /* request time */
		cmd_0x21 ();
		break;

	case 'z':   /* sets a flag in TSIP_UTL that watches for time report */
		request_PC_time_set ();
		cmd_0x21 ();
		break;

	case 'n':   /* set nav mode to 2-D */
		set_nav_mode ();
		break;

	case 'i':
		set_initial_ECEF_position ();
		break;

	case 'M':   /* request nav mode */
		cmd_0x24 ();
		break;

	case 0x12:	/* cntrl r */
		xprintf ("Resetting the GPS receiver");
		cmd_0x25 ();
		break;

	case 'h':   /* request receiver health */
		cmd_0x26 ();
		break;

	case 's':   /* request SNRs from all birds tracked */
		cmd_0x27 ();
		break;

	case 'm':   /* request GPS system message */
		cmd_0x28 ();
		break;

	case 'a':   /* request almanac health page */
		cmd_0x29 ();
		break;

	case 0x01:	/* cntrl a */
		set_altitude ();
		break;

	case 'I':
		set_initial_lla_position ();
		break;

	case 'p':
		cmd_0x2Cq ();
		break;

	case 'P':
		set_op_parms ();
		break;

	case 'o':   /* request oscillator offset */
		cmd_0x2D ();
		break;

	case 'T':
		set_time ();
		break;

	case 'u':   /* request_UTC_data () */
		cmd_0x2F ();
		break;

	case 'b':
		set_accurate_ECEF_position ();
		break;

	case 'B':
		set_accurate_LLA_position ();
		break;

	case 'S':
		set_SV_for_1SV_mode ();
		break;

	case 'O':   /* request I/O options */
		cmd_0x35q ();
		break;

	case 0x0F:	/* cntrl o */
		set_IO_options ();
		break;

	case 0x16:	/* cntrl v */
		initial_velocity ();
		break;

	case 'w':   /* request last position */
		cmd_0x37 ();
		break;

	case '$':
		request_SV_system_data ();
		break;

	case 'd':
		request_disable_or_health_override_list ();
		break;

	case '<':
		request_raw_msmt_data ();
		num_replies = 8;
		break;

	case 'e':
		request_ephemeris_status ();
		num_replies = 32;
		break;

	case '>':
		request_track_info ();
		num_replies = 8;
		break;

	case 'U':   /* request channel A configuration */
		cmd_0x3Dq ();
		break;

	case 0x15:	/* cntrl u */
		set_channel_a_config (reply);
		break;

	case 'Z':
		request_aux_fix_parms ();
		break;

	case 'D':
		set_or_request_DGPS_mode ();
		break;

	case '/':
		request_DGPS_corrections ();
		num_replies = 12;
		break;

	case 'l':   /* request position filter parms */
		cmd_0x71q ();
		break;

	case 'L':
		set_pos_filter_parms ();
		break;

	case 'H':
		set_altitude_filter_parms ();
		break;

	case 'j':
		xprintf("Request track mode status");
		cmd_0x75q ();
		break;

	case 'J':
		set_track_mode ();
		break;

	case 'g':
		xprintf("Request DC max age");
		cmd_0x77q ();
		break;

   case 'G':
		set_DGPS_maxage ();
		break;

	case '=':
		if (subcode_8E_command (&kb_cmd)) {
			set_cmd_esc (TRUE);
		}
		break;

	case '%':	/* unsigned char string */
		{
			unsigned char cmdbuflen, cmdbuf[9];

			cmdbuflen = ask_hex_string ("command string (9 bytes): ", cmdbuf);
			cmd_0xxx (cmdbuf[0], &cmdbuf[1], cmdbuflen-1);
			kb_cmd.replycode = cmdbuf[0];
			kb_cmd.cmdcode = cmdbuf[0];
		}
		break;

	default:
		break;
	}
	if (cmd_esc ()) {
		show_crlf ();
		xprintf ("-- aborted --");
	} else {
		clreol ();
		/* general case; display the message if a report has been requested */
		if (kb_cmd.replycode) {
			reply[kb_cmd.replycode] = num_replies;
			switch (kb_cmd.replycode) {
			case 0x6D:
				reply [0x44] = 1;
				break;

			case 0x46:
				reply [0x4B] = 1;
				break;

			case 0x57:
				reply [0x42] = reply [0x83] = reply [0x4A] =
				reply [0x84] = reply [0x43] = reply [0x56] =
				reply [0x120] = reply [0x117] = reply [0x118] = 1;
				break;
			}
			if (kb_cmd.replycode > 0x100)
			{
				xprintf ("...waiting for reply (0x8F-%X)\r",
					kb_cmd.replycode - 0x100);
			}
			else
			{
				xprintf ("...waiting for reply (0x%X)\r",
					kb_cmd.replycode);
			}
		}
	}
}
