#include "globals.h"
#include "lcd.h"
#include "i2c.h"
#include "error_utils.h"
#include "string_utils.h"
#include "device-functions.h"
#include "flash.h"
#include "nicutils.h"
#include "menus.h"
#include "gpib.h"
#include <glib.h>
#include <math.h>


/* define common strings */
#define Press_Change_Message "Push CHANGE to continue."

/* keypad hardware definitions */
#define Move_Button 1			/* mask for MOVE button */
#define Change_Button 2 		/* mask for CHANGE button */
#define Mult10_Button 4 		/* mask for x10 button */
#define Div10_Button 8 			/* mask for /10 button */
#define Plus_Minus_Button 16	/* mask for +/- button */
#define Extra_Fine_Button 32	/* mask for extra-fine button */


/* ----- HOW THE MENU SYSTEM WORKS -------------------------------------------------------------------------*/

/* To add a new menu:	1. add the menu name	directly below */
/*						2. add the menu mode list choices directly below */
/*						3. if it is to be shown on the main menu, update Show_Main_Menu(void); */
/*						4. update Submenu_Display(void), which builds the submenu */
/*						5. update Submenu_Implement_Changes(void), to do the actual functions */

/* KEY SUBROUTINES: */

/*			Show_Main_Menu(void);				- displays the main menu */
/*			Menu_Check_Buttons(void);				- determines what to show based on button status */
/*			 (void);				- clears any button presses */
/*			Menu_Move_Pointer(int move_amount);	- moves the pointer up and down the main menu */

/*			Submenu_Display(void);					- builds and displays submenus */
/*			Submenu_Move_Pointer(void);			- moves the pointer up and down submenu mode list */
/*			Submenu_Implement_Changes(void);		- once a mode in a submenu mode list has been chosen, */
/*															  this executes whatever is associated with that mode */
/*			Submenu_Mult_Value(float mult_by);	- this implements the x10, /10, +/- button functions */
/*			Submenu_Service_Encoder(void);		- this implements the adjust knob */

/*			Nonstd_menu_RS232(void);				- the RS232 menu is non-standard */
/*			Nonstd_menu_default_rs232(void);		- the default RS232 screen is non-standard */
/*			Nonstd_menu_model_info(void);			- the model info screen is non-standard */

/* MENU NAMES - these are menus with associated mode lists */
/*		  	  - Submenu1 are submenus linked from the main menu */
/*		  	  - Submenu2 are submenus linked from the other submenus */


/* MODE LIST CHOICES - if selected, these are fed into Submenu_Implement_Changes */

#define	mode_freq_int 0
#define	mode_freq_ext 100
#define	mode_freq_man 200
#define	mode_freq_hold 300
#define	mode_delay_norm 400
#define	mode_delay_dbl 500
#define	mode_pw_norm 600
#define	mode_pw_duty 700
#define	mode_pw_inout 800
#define	mode_pw_dc 900
#define	mode_output_on 1000
#define	mode_output_off 1100
#define	mode_inv_no 1200
#define	mode_inv_yes 1300
#define	mode_gate_losync 1400
#define	mode_gate_loasync 1500
#define	mode_gpib_address 1600
#define	mode_rs232_settings 1700
#define	mode_model_info 1800
#define	mode_exit_normal_submenu 1900
#define	mode_zout_max 2000
#define	mode_zout_min 2100
#define	mode_save_0 2200
#define	mode_save_1 2300
#define	mode_save_2 2400
#define	mode_save_3 2500
#define	mode_load_0 2600
#define	mode_load_1 2700
#define	mode_load_2 2800
#define	mode_load_3 2900
#define	mode_load 3000
#define	mode_save 3100
#define	mode_change_rs232 3200
#define	mode_default_rs232 3300
#define	mode_1200 3400
#define	mode_2400 3500
#define	mode_4800 3600
#define	mode_9600 3700
#define	mode_7bits 3800
#define	mode_8bits 3900
#define	mode_par_none 4000
#define	mode_par_even 4100
#define	mode_par_odd 4200
#define	mode_1bit 4300
#define	mode_2bits 4400
#define	mode_hand_hard 4500
#define	mode_hand_off 4600
#define	mode_echo_on 4700
#define	mode_echo_off 4800
#define	mode_amp_normal 4900
#define	mode_amp_ea 5000
#define	mode_gate_hisync 5100
#define	mode_gate_hiasync 5200
#define	mode_go_to_local 5500
#define	mode_exit_rs232 5600
#define	mode_logic_ttl 5700
#define	mode_logic_ecl 5800
#define	mode_os_normal 6300
#define	mode_os_eo 6400
#define	mode_amp_amplify 6500
#define mode_func_sin 6700
#define mode_func_tri 6800
#define mode_func_squ 6900
#define mode_func_pulse 7000
#define mode_func_amp 7100
#define	mode_network 7200
#define	mode_password 7300
#define	mode_selfcal 7400
#define mode_19200 7500
#define mode_38400 7600
#define mode_57600 7700
#define mode_115200 7800
#define mode_pw_ew 7900

#define mode_ampl_fixed_point0 8000
#define mode_ampl_fixed_point1 8100
#define mode_ampl_fixed_point2 8200
#define mode_ampl_fixed_point3 8300
#define mode_ampl_fixed_point4 8400
#define mode_ampl_fixed_point5 8500
#define mode_ampl_fixed_point6 8600
#define mode_ampl_fixed_point7 8700
#define mode_ampl_fixed_point8 8800
#define mode_ampl_fixed_point9 8900

#define mode_freq_ext2 9000
#define mode_route1 9100
#define mode_route2 9200

#define mode_rise_time_min 9300
#define mode_rise_time_max 9400

#define mode_load_exit 9500
#define mode_save_exit 9600

#define Submenu_maximum_entries 10

/* what parameter to adjust */
#define Show_frequency 0
#define Show_delay 100
#define Show_pw 200
#define Show_amplitude 300
#define Show_offset 400
#define Show_duty_cycle 500
#define Show_zout 600
#define Show_No_Number 700
#define Show_monitor 800
#define Show_Burst_Count 900
#define Show_Burst_Time 1000
#define Show_rise_time 1100
#define Show_gpib_address 1200
#define Show_soft_current_limit 1300
#define Show_route_primary 1500
#define Show_route_secondary 1600
#define Show_load_type 1700
#define Show_slew 1800


/* KEY MENU-JUGGLING VARIABLES - controlling what is actually shown on the display */

int menu_cursor_pos;

int last_button_state;	/* keeping track of button presses (software flip-flop) */
int last_encoder_adjust_error;
unsigned long long encoder_last_adjust;
unsigned long long encoder_timer_change[3];
int encoder_mult;

int base_entry;			/* for scrolling submenu mode lists */


/* KEY MAIN-MENU-RELATED VARIABLES */

/* 	- the main menu choices are indexed [0]-[Main_Menu_max_entry] */
/*	- the actual item at each choice is stored in Main_Menu_Structure[] */

int 	Main_Menu_Structure[LCD_max_entries+1];
int  	Main_Menu_max_entry;


/* KEY SUBMENU VARIABLES */

int 	Submenu_Structure[Submenu_maximum_entries];	/* this keeps track of the submenu mode-list */
int  	Submenu_Selected_Item; 		/* current submenu mode-list item selected */
int  	Submenu_Numeric_Parameter;	/* when the adjust knob is varied, this is what gets changed */

/* for example, Show_No_Number */
/*				Show_frequency */
/*				Show_delay */
/*				Show_pw */
/*				Show_amplitude */
/*				Show_offset */
/*				Show_duty_cycle */

int  	Submenu_max_entry;			/* highest mode-list menu item number */
float 	Submenu_Value;				/* actual value of the shown parameter (like frequency) */
int  	Submenu_extra_fine;			/* is the extra-fine mode on? */


static void update_remote_mode ();
static int Menu_Is_Item_Visible(int LCD_entry);
static void Menu_Move_Pointer(int move_amount);
static void Display_Number_on_LCD(int Is_Item_Visible,int LCD_row,int LCD_col,char *start_string,int Show_What, int significant_digits, int width_of_column);
static void Submenu_Display(int change_selection);
static void Submenu_Move_Pointer(void);
static int Submenu_Mult_Value(float mult_by);
static void Submenu_Service_Encoder(int encoder_change);
static void Nonstd_menu_default_rs232(void);
static void Nonstd_menu_model_info(void);
static int Submenu_Implement_Changes(void);
static void Nonstd_menu_network(void);
static void Read_Keypad(int *button_port_val, int *upper_encoder_val, int *lower_encoder_val);


#define VXI_OR_GPIB_LOCK_ACTIVE  ((globals.Remote.gpib_remote && globals.Remote.gpib_lock) || globals.Remote.vxi_panel_lock)


static void update_remote_mode ()
{
	GPIB_check_remote_status (&globals.Remote.gpib_remote, &globals.Remote.gpib_lock);
}


static int Menu_Is_Item_Visible(int LCD_entry)
{
	return ((LCD_entry/LCD_max_entries_per_page)==(menu_cursor_pos/LCD_max_entries_per_page));
}



void Update_Main_Menu_If_Visible(void)
{
	if (	(globals.MenuStatus.Type_Of_Menu == Main_Menu_On) &&
	                (globals.MenuStatus.Error_Screen == NO) &&
	                (globals.MenuStatus.Nonstd_Display == NO)) {
		Show_Main_Menu();
	}
}


void Show_Main_Menu(void)
{

	if (!globals.Sys.startup_complete) {
		return;
	}

	static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
	g_static_mutex_lock (&mutex);	// can be triggered simultaneously by local or remote users

	GString *menu_string = g_string_new ("");

	int LCD_entry, LCD_row, LCD_col;
	int sig_dig;	/* number of significant digits to display */
	int i;
	int chan;
	int show_item;
	int old_cursor_pos;


	// update remote/local info before starting screen writes, to avoid
	// odd-looking pauses
	update_remote_mode();
	GString *raw_str = g_string_new ("");

	if (!VXI_OR_GPIB_LOCK_ACTIVE) {
		raw_str = g_string_append (raw_str, "LOCAL+");
	}
	if (globals.Remote.gpib_remote) {
		raw_str = g_string_append (raw_str, "GPIB+");
	}
	if (globals.Remote.terminal_connections > 0) {
		g_string_append_printf (raw_str, "%dTER+", globals.Remote.terminal_connections);
	}
	if (globals.Remote.vxi_connections > 0) {
		g_string_append_printf (raw_str, "%dVXI", globals.Remote.vxi_connections);
	}
	gchar *step1 = g_strdup (raw_str->str);
	g_string_free (raw_str, TRUE);

	// remove semicolon at end
	gchar *step2 = conditional_regex_replace (TRUE, step1, "\\+$", "");
	g_free (step1);

	// shorten as required
	gchar *step3 = conditional_regex_replace (strlen(step2) > (LCD_col_width-1), step2, "LOCAL", "LO");
	g_free (step2);

	// shorten as required
	gchar *step4 = conditional_regex_replace (strlen(step3) > (LCD_col_width-1), step3, "TER", "T");
	g_free (step3);

	// shorten as required
	gchar *step5 = conditional_regex_replace (strlen(step4) > (LCD_col_width-1), step4, "GPIB", "GP");
	g_free (step4);

	// shorten as required
	gchar *step6 = conditional_regex_replace (strlen(step5) > (LCD_col_width-1), step5, "VXI", "V");
	g_free (step5);

	// finish
	gchar *ctrl_str = g_strdup (step6);
	g_free (step6);


	if (    (globals.MenuStatus.Type_Of_Menu != Main_Menu_On) ||
	                (globals.MenuStatus.Error_Screen == YES) ||
	                (globals.MenuStatus.Nonstd_Display == YES) ) {
		LCD_clear();
		LCD_initialize();
	}

	LCD_entry=-1;
	sig_dig = 4;
	Submenu_extra_fine=NO;

	globals.MenuStatus.Type_Of_Menu=Main_Menu_On;
	globals.MenuStatus.Error_Screen=NO;
	globals.MenuStatus.Nonstd_Display=NO;


	/* fill in unused cursor columns */
	for (i=0; i<(menu_cursor_pos % LCD_max_entries_per_page); ++i) {
		LCD_row=i % LCD_rows;
		LCD_col=(i / LCD_rows) * LCD_col_width;
		LCD_write(LCD_row,LCD_col," ");
	}

	/* Don't overwrite the cursor. This would generate needless LCD accesses */

	for (i=((menu_cursor_pos % LCD_max_entries_per_page)+1); i<15; ++i) {
		LCD_row=i % LCD_rows;
		LCD_col=(i / LCD_rows) * LCD_col_width;
		LCD_write(LCD_row,LCD_col," ");
	}

	old_cursor_pos=menu_cursor_pos;

	/*----- display freq, always (except func gen amplify mode) -----*/

	for (chan=0; chan<(globals.Flash.ChanKey_frequency?globals.Flash.channels:1); ++chan) {
		if (globals.ChannelState[chan].func_mode!=amp_mode_on) {
			++LCD_entry;
			Main_Menu_Structure[LCD_entry]=Submenu1_freq+chan;								/* keep track of what is displayed */
			LCD_row=LCD_entry % LCD_rows;								/* find next available row */
			LCD_col=((LCD_entry % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width + 1;	/* find next available column */

			show_item=Show_No_Number;

			if (globals.ChannelState[chan].trigger_source==source_internal) {
				menu_string = g_string_append (menu_string, "INT");
				show_item=Show_frequency+chan;
			} else if (globals.ChannelState[chan].trigger_source==source_external) {
				menu_string = g_string_append (menu_string, "EXT TRIG");
                       } else if (globals.ChannelState[chan].trigger_source==source_external2) {
                                menu_string = g_string_append (menu_string, "EXT DBL");
			} else if (globals.ChannelState[chan].trigger_source==source_manual) {
				menu_string = g_string_append (menu_string, "MAN TRIG");
			} else if (globals.ChannelState[chan].trigger_source==source_hold) {
				menu_string = g_string_append (menu_string, "HOLD TRIG");
			} else if (globals.ChannelState[chan].trigger_source==source_immediate) {
				menu_string = g_string_append (menu_string, "IMMED TRIG");
			}

			if (globals.Flash.ChanKey_frequency) {
				g_string_append_printf (menu_string, "%d", chan+1);
			}
			if (globals.ChannelState[chan].trigger_source==source_internal) {
				menu_string = g_string_append (menu_string, ":");
			}

			Display_Number_on_LCD(Menu_Is_Item_Visible(LCD_entry), LCD_row,LCD_col,menu_string->str,show_item,sig_dig,LCD_col_width-1);
			g_string_erase (menu_string, 0, -1);
		}
	}

	/*----- display shape, if appropriate -----*/

	for (chan=0; chan<(globals.Flash.ChanKey_func_mode?globals.Flash.channels:1); ++chan) {
		if (globals.Flash.is_func_gen[chan]) {
			++LCD_entry;
			Main_Menu_Structure[LCD_entry]=Submenu1_func+chan;								/* keep track of what is displayed */
			LCD_row=LCD_entry % LCD_rows;								/* find next available row */
			LCD_col=((LCD_entry % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width + 1;	/* find next available column */

			show_item=Show_No_Number;

			if (globals.ChannelState[chan].func_mode==pulse_mode_on) {
				menu_string = g_string_append (menu_string, "SHAPE:PULSE");
			} else if (globals.ChannelState[chan].func_mode==sin_mode_on) {
				menu_string = g_string_append (menu_string, "SHAPE:SINE");
			} else if (globals.ChannelState[chan].func_mode==tri_mode_on) {
				menu_string = g_string_append (menu_string, "SHAPE:TRI");
			} else if (globals.ChannelState[chan].func_mode==squ_mode_on) {
				menu_string = g_string_append (menu_string, "SHAPE:SQU");
			} else if (globals.ChannelState[chan].func_mode==amp_mode_on) {
				menu_string = g_string_append (menu_string, "SHAPE:AMP");
			}

			if (globals.Flash.ChanKey_func_mode) {
				g_string_append_printf (menu_string, "%d", chan+1);
			}

			Display_Number_on_LCD(Menu_Is_Item_Visible(LCD_entry), LCD_row,LCD_col,menu_string->str,show_item,sig_dig,LCD_col_width-1);
			g_string_erase (menu_string, 0, -1);
		}
	}

	/*----- display delay, except for pwin=pwout and ext amplify modes -----*/

	for (chan=0; chan<(globals.Flash.ChanKey_delay?globals.Flash.channels:1); ++chan)
		if (		(globals.ChannelState[chan].amp_mode!=amp_mode_amplify)
		                && (globals.ChannelState[chan].pw_ctrl_mode!=pw_in_out)
		                && ((globals.ChannelState[chan].func_mode==pulse_mode_on)
		                    || (globals.ChannelState[chan].func_mode==dc_mode_on))
				&& (globals.Flash.max_delay[chan]>0.0)
		   ) {
			++LCD_entry;
			Main_Menu_Structure[LCD_entry]=Submenu1_delay+chan;
			LCD_row=LCD_entry % LCD_rows;
			LCD_col=((LCD_entry % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width + 1;

			if (globals.ChannelState[chan].double_pulse==double_off) {
				menu_string = g_string_append (menu_string, "DLY");
			} else {
				menu_string = g_string_append (menu_string, "DBL");
			}
			if (globals.Flash.ChanKey_delay) {
				g_string_append_printf (menu_string, "%d", chan+1);
			}
			menu_string = g_string_append (menu_string, ":");

			Display_Number_on_LCD(Menu_Is_Item_Visible(LCD_entry), LCD_row,LCD_col,menu_string->str,Show_delay+chan,sig_dig,LCD_col_width-1);
			g_string_erase (menu_string, 0, -1);
		}


	/*----- display pw, as appropriate -----*/

	for (chan=0; chan<(globals.Flash.ChanKey_pw?globals.Flash.channels:1); ++chan) {
		if (	!globals.Flash.fixed_pw[chan]
		                && (globals.ChannelState[chan].amp_mode!=amp_mode_amplify)
		                && ((globals.ChannelState[chan].func_mode==pulse_mode_on)
		                    || (globals.ChannelState[chan].func_mode==dc_mode_on))
		   ) {

			++LCD_entry;
			Main_Menu_Structure[LCD_entry]=Submenu1_pw+chan;
			LCD_row=LCD_entry % LCD_rows;
			LCD_col=((LCD_entry % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width + 1;

			show_item=Show_No_Number;

			if (globals.ChannelState[chan].func_mode==pulse_mode_on) {
				switch (globals.ChannelState[chan].pw_ctrl_mode) {

				default:
				case pw_normal:
					if (globals.ChannelState[chan].hold_setting==hold_width) {
						show_item=Show_pw+chan;
						menu_string = g_string_append (menu_string, "PW");
						if (globals.Flash.ChanKey_pw) {
							g_string_append_printf (menu_string, "%d", chan+1);
						}
						menu_string = g_string_append (menu_string, ":");
					} else {
						show_item=Show_duty_cycle+chan;
						menu_string = g_string_append (menu_string, "DUTY");
						if (globals.Flash.ChanKey_pw) {
							g_string_append_printf (menu_string, "%d", chan+1);
						}
						menu_string = g_string_append (menu_string, ":");
					}
					break;

				case pw_in_out:
					menu_string = g_string_append (menu_string, "PW");
                                        if (globals.Flash.ChanKey_pw) {
                                                g_string_append_printf (menu_string, "%d", chan+1);
                                        }
                                        menu_string = g_string_append (menu_string, ":IN=OUT");
					break;

				case pw_ew_ext:
                                        menu_string = g_string_append (menu_string, "PW");
                                        if (globals.Flash.ChanKey_pw) {
                                                g_string_append_printf (menu_string, "%d", chan+1);
                                        }
                                        menu_string = g_string_append (menu_string, ":EXT");
                                        break;
				}
				
			} else {
				menu_string = g_string_append (menu_string, "PW");
				if (globals.Flash.ChanKey_pw) {
					g_string_append_printf (menu_string, "%d", chan+1);
				}
				menu_string = g_string_append (menu_string, ": DC");
			}
			Display_Number_on_LCD(Menu_Is_Item_Visible(LCD_entry), LCD_row,LCD_col,menu_string->str,show_item,sig_dig,LCD_col_width-1);
			g_string_erase (menu_string, 0, -1);
		}
	}


	/*----- display rise_time, as appropriate -----*/

	for (chan=0; chan<(globals.Flash.ChanKey_rise_time?globals.Flash.channels:1); ++chan) {
		if (	!globals.Flash.fixed_rise_time[chan]
		                && (globals.ChannelState[chan].amp_mode!=amp_mode_amplify)
		                && ((globals.ChannelState[chan].func_mode==pulse_mode_on)
		                    || (globals.ChannelState[chan].func_mode==dc_mode_on))
		   ) {

			++LCD_entry;
			Main_Menu_Structure[LCD_entry]=Submenu1_rise_time+chan;
			LCD_row=LCD_entry % LCD_rows;
			LCD_col=((LCD_entry % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width + 1;

			show_item=Show_rise_time+chan;
			menu_string = g_string_append (menu_string, "TR");
			if (globals.Flash.ChanKey_rise_time) {
				g_string_append_printf (menu_string, "%d", chan+1);
			}
			menu_string = g_string_append (menu_string, ":");
			Display_Number_on_LCD(Menu_Is_Item_Visible(LCD_entry), LCD_row,LCD_col,menu_string->str,show_item,sig_dig,LCD_col_width-1);
			g_string_erase (menu_string, 0, -1);
		}
	}


	/*----- display amplitude, as appropriate -----*/

	for (chan=0; chan<(globals.Flash.ChanKey_amplitude?globals.Flash.channels:1); ++chan) {
		if ((globals.Flash.voltage_enabled[chan] || globals.Flash.current_enabled[chan]) ) {
			++LCD_entry;
			Main_Menu_Structure[LCD_entry]=Submenu1_amp+chan;
			LCD_row=LCD_entry % LCD_rows;
			LCD_col=((LCD_entry % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width + 1;

			show_item=Show_No_Number;

			if (globals.ChannelState[chan].amp_mode==amp_mode_normal) {
				show_item=Show_amplitude+chan;
				menu_string = g_string_append (menu_string, "AMP");
				if (globals.Flash.ChanKey_amplitude) {
					g_string_append_printf (menu_string, "%d", chan+1);
				}
				menu_string = g_string_append (menu_string, ":");
			} else if (globals.ChannelState[chan].amp_mode==amp_mode_ea) {
				menu_string = g_string_append (menu_string, "AMP");
				if (globals.Flash.ChanKey_amplitude) {
					g_string_append_printf (menu_string, "%d", chan+1);
				}
				menu_string = g_string_append (menu_string, ":EXT");
			} else if (globals.ChannelState[chan].amp_mode==amp_mode_amplify) {
				menu_string = g_string_append (menu_string, "AMP");
				if (globals.Flash.ChanKey_amplitude) {
					g_string_append_printf (menu_string, "%d", chan+1);
				}
				menu_string = g_string_append (menu_string, ":AMPLFY");
			}
			Display_Number_on_LCD(Menu_Is_Item_Visible(LCD_entry), LCD_row,LCD_col,menu_string->str,show_item,sig_dig,LCD_col_width-1);
			g_string_erase (menu_string, 0, -1);
		}
	}


	/*----- display soft_current_limit, as appropriate -----*/

	for (chan=0; chan<(globals.Flash.ChanKey_current_limit?globals.Flash.channels:1); ++chan) {
		if (globals.Flash.soft_current_limit_enabled[chan]) {

			++LCD_entry;
			Main_Menu_Structure[LCD_entry]=Submenu1_soft_current_limit+chan;
			LCD_row=LCD_entry % LCD_rows;
			LCD_col=((LCD_entry % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width + 1;

			show_item=Show_soft_current_limit+chan;
			menu_string = g_string_append (menu_string, "LIM");
			if (globals.Flash.ChanKey_current_limit) {
				g_string_append_printf (menu_string, "%d", chan+1);
			}
			menu_string = g_string_append (menu_string, ":");
			Display_Number_on_LCD(Menu_Is_Item_Visible(LCD_entry), LCD_row,LCD_col,menu_string->str,show_item,sig_dig,LCD_col_width-1);
			g_string_erase (menu_string, 0, -1);
		}
	}



	/*----- display current slew, as appropriate -----*/

	for (chan=0; chan<(globals.Flash.ChanKey_slew?globals.Flash.channels:1); ++chan) {
		if ( globals.Flash.curr_slew[chan] ) {

			++LCD_entry;
			Main_Menu_Structure[LCD_entry]=Submenu1_slew+chan;
			LCD_row=LCD_entry % LCD_rows;
			LCD_col=((LCD_entry % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width + 1;

			show_item=Show_slew+chan;
			menu_string = g_string_append (menu_string, "SL");
			if (globals.Flash.ChanKey_slew) {
				g_string_append_printf (menu_string, "%d", chan+1);
			}
			menu_string = g_string_append (menu_string, ":");
			Display_Number_on_LCD(Menu_Is_Item_Visible(LCD_entry), LCD_row,LCD_col,menu_string->str,show_item,sig_dig,LCD_col_width-1);
			g_string_erase (menu_string, 0, -1);
		}
	}


	/*----- display burst count, as appropriate -----*/

	for (chan=0; chan<(globals.Flash.ChanKey_Burst_Count?globals.Flash.channels:1); ++chan) {
		if (globals.Flash.max_burst_count[chan]>1) {

			++LCD_entry;
			Main_Menu_Structure[LCD_entry]=Submenu1_burst_count+chan;
			LCD_row=LCD_entry % LCD_rows;
			LCD_col=((LCD_entry % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width + 1;

			show_item=Show_Burst_Count+chan;
			menu_string = g_string_append (menu_string, "N");
			if (globals.Flash.ChanKey_Burst_Count) {
				g_string_append_printf (menu_string, "%d", chan+1);
			}
			menu_string = g_string_append (menu_string, ":");
			Display_Number_on_LCD(Menu_Is_Item_Visible(LCD_entry), LCD_row,LCD_col,menu_string->str,show_item,0,LCD_col_width-1);
			g_string_erase (menu_string, 0, -1);
		}
	}



	/*----- display burst timing, as appropriate -----*/

	for (chan=0; chan<(globals.Flash.ChanKey_Burst_Time?globals.Flash.channels:1); ++chan) {
		if ((globals.Flash.max_burst_count[chan]>1) && !globals.Flash.burst_func[chan]) {

			++LCD_entry;
			Main_Menu_Structure[LCD_entry]=Submenu1_burst_time+chan;
			LCD_row=LCD_entry % LCD_rows;
			LCD_col=((LCD_entry % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width + 1;

			show_item=Show_Burst_Time+chan;
			menu_string = g_string_append (menu_string, "BUR");
			if (globals.Flash.ChanKey_Burst_Time) {
				g_string_append_printf (menu_string, "%d", chan+1);
			}
			menu_string = g_string_append (menu_string, ":");
			Display_Number_on_LCD(Menu_Is_Item_Visible(LCD_entry), LCD_row,LCD_col,menu_string->str,show_item,sig_dig,LCD_col_width-1);
			g_string_erase (menu_string, 0, -1);
		}
	}



	/*----- display offset, as appropriate -----*/

	for (chan=0; chan<(globals.Flash.ChanKey_offset?globals.Flash.channels:1); ++chan) {
		if ((globals.Flash.voltage_offset_enabled[chan] || globals.Flash.current_offset_enabled[chan])
		                && (globals.ChannelState[chan].amp_mode!=amp_mode_amplify)) {
			++LCD_entry;
			Main_Menu_Structure[LCD_entry]=Submenu1_offset+chan;
			LCD_row=LCD_entry % LCD_rows;
			LCD_col=((LCD_entry % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width + 1;

			show_item=Show_No_Number;

			if (globals.ChannelState[chan].os_mode==os_mode_normal) {
				show_item=Show_offset+chan;
				menu_string = g_string_append (menu_string, "OS");
				if (globals.Flash.ChanKey_offset) {
					g_string_append_printf (menu_string, "%d", chan+1);
				}
				menu_string = g_string_append (menu_string, ":");
			} else {
				menu_string = g_string_append (menu_string, "OS");
				if (globals.Flash.ChanKey_offset) {
					g_string_append_printf (menu_string, "%d", chan+1);
				}
				menu_string = g_string_append (menu_string, ":EXT");
			}
			Display_Number_on_LCD(Menu_Is_Item_Visible(LCD_entry), LCD_row,LCD_col,menu_string->str,show_item,sig_dig,LCD_col_width-1);
			g_string_erase (menu_string, 0, -1);
		}
	}

	/*----- displayed monitor, as appropriate -----*/

	for (chan=0; chan<(globals.Flash.ChanKey_Curr_Mon_value?globals.Flash.channels:1); ++chan) {
		if (globals.Flash.monitor_enabled[chan]) {
			++LCD_entry;
			Main_Menu_Structure[LCD_entry]=Submenu1_mon+chan;
			LCD_row=LCD_entry % LCD_rows;
			LCD_col=((LCD_entry % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width + 1;

			menu_string = g_string_append (menu_string, "Mon");
			if (globals.Flash.ChanKey_Curr_Mon_value) {
				g_string_append_printf (menu_string, "%d", chan+1);
			}
			menu_string = g_string_append (menu_string, ":");
			Display_Number_on_LCD(Menu_Is_Item_Visible(LCD_entry),LCD_row,LCD_col,menu_string->str,Show_monitor+chan,sig_dig,LCD_col_width-1);
			g_string_erase (menu_string, 0, -1);
			globals.ChannelState[chan].displayed_mon_val=globals.ChannelState[chan].Curr_Mon_value;
		}
	}

	/*----- display Zout, as appropriate -----*/

	/* The Zout hardware and software is controlled by PW commands in the AVPP */

	for (chan=0; chan<(globals.Flash.ChanKey_zout?globals.Flash.channels:1); ++chan) {
		if (globals.Flash.switchable_zout[chan] && !globals.Flash.volt_ctrl_pw[chan]) {
			++LCD_entry;
			Main_Menu_Structure[LCD_entry]=Submenu1_zout+chan;
			LCD_row=LCD_entry % LCD_rows;
			LCD_col=((LCD_entry % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width + 1;

			menu_string = g_string_append (menu_string, "Zout");
			if (globals.Flash.ChanKey_zout) {
				g_string_append_printf (menu_string, "%d", chan+1);
			}
			menu_string = g_string_append (menu_string, ":");

			if (globals.ChannelState[chan].zout==globals.Flash.zout_max[chan]) {
				g_string_append_printf (menu_string, "%d\xf4    ", globals.Flash.zout_max[chan]);
			} else {
				g_string_append_printf (menu_string, "%d\xf4    ", globals.Flash.zout_min[chan]);
			}

			Display_Number_on_LCD(Menu_Is_Item_Visible(LCD_entry), LCD_row,LCD_col,menu_string->str,Show_No_Number,sig_dig,LCD_col_width-1);
			g_string_erase (menu_string, 0, -1);
		}
	}


	/*----- display load type, as appropriate -----*/
	for (chan=0; chan<(globals.Flash.ChanKey_load_type?globals.Flash.channels:1); ++chan) {
		if (globals.Flash.switchable_load[chan]) {
			++LCD_entry;
			Main_Menu_Structure[LCD_entry]=Submenu1_loadtype+chan;
			LCD_row=LCD_entry % LCD_rows;
			LCD_col=((LCD_entry % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width + 1;

			show_item=Show_load_type+chan;
			menu_string = g_string_append (menu_string, "Load");
			if (globals.Flash.ChanKey_load_type) {
				g_string_append_printf (menu_string, "%d", chan+1);
			}
			menu_string = g_string_append (menu_string, ":");
			Display_Number_on_LCD(Menu_Is_Item_Visible(LCD_entry), LCD_row,LCD_col,menu_string->str,show_item,sig_dig,LCD_col_width-1);
			g_string_erase (menu_string, 0, -1);
		}
	}


	/*----- display output state, if used -----*/

	if (globals.Flash.on_off_used)
		for (chan=0; chan<(globals.Flash.ChanKey_output_state?globals.Flash.channels:1); ++chan) {
			++LCD_entry;
			Main_Menu_Structure[LCD_entry]=Submenu1_output_state+chan;
			LCD_row=LCD_entry % LCD_rows;
			LCD_col=((LCD_entry % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width + 1;


			menu_string = g_string_append (menu_string, "Output");
			if (globals.Flash.ChanKey_output_state) {
				g_string_append_printf (menu_string, "%d", chan+1);
			}
			menu_string = g_string_append (menu_string, ":");

			if (globals.ChannelState[chan].output_state==output_on) {
				menu_string = g_string_append (menu_string, "ON");
			} else {
				menu_string = g_string_append (menu_string, "OFF");
			}

			Display_Number_on_LCD(Menu_Is_Item_Visible(LCD_entry), LCD_row,LCD_col,menu_string->str,Show_No_Number,sig_dig,LCD_col_width-1);
			g_string_erase (menu_string, 0, -1);
		}

	/*----- display primary routing, as appropriate -----*/

	for (chan=0; chan<(globals.Flash.ChanKey_route?globals.Flash.channels:1); ++chan) {
		if (globals.Flash.routing_required[chan] > 0) {

			++LCD_entry;
			Main_Menu_Structure[LCD_entry]=Submenu1_route_primary+chan;
			LCD_row=LCD_entry % LCD_rows;
			LCD_col=((LCD_entry % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width + 1;

			show_item=Show_route_primary+chan;

			if (globals.Flash.routing_required[chan] == 1) {
				menu_string = g_string_append (menu_string, "Route");
			} else {
				menu_string = g_string_append (menu_string, "ANOD");
			}

			if (globals.Flash.ChanKey_route) {
				g_string_append_printf (menu_string, "%d", chan+1);
			}
			menu_string = g_string_append (menu_string, ":");
			Display_Number_on_LCD(Menu_Is_Item_Visible(LCD_entry), LCD_row,LCD_col,menu_string->str,show_item,0,LCD_col_width-1);
			g_string_erase (menu_string, 0, -1);
		}
	}


	/*----- display secondary routing, as appropriate -----*/

	for (chan=0; chan<(globals.Flash.ChanKey_route?globals.Flash.channels:1); ++chan) {
		if (globals.Flash.routing_required[chan] == 2) {

			++LCD_entry;
			Main_Menu_Structure[LCD_entry]=Submenu1_route_secondary+chan;
			LCD_row=LCD_entry % LCD_rows;
			LCD_col=((LCD_entry % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width + 1;

			show_item=Show_route_secondary+chan;

			menu_string = g_string_append (menu_string, "CATH");

			if (globals.Flash.ChanKey_route) {
				g_string_append_printf (menu_string, "%d", chan+1);
			}
			menu_string = g_string_append (menu_string, ":");
			Display_Number_on_LCD(Menu_Is_Item_Visible(LCD_entry), LCD_row,LCD_col,menu_string->str,show_item,0,LCD_col_width-1);
			g_string_erase (menu_string, 0, -1);
		}
	}


	/*----- display inverted state, if allowed -----*/

	for (chan=0; chan<(globals.Flash.ChanKey_inverted?globals.Flash.channels:1); ++chan) {
		if (globals.Flash.invert_allowed[chan]) {
			++LCD_entry;
			Main_Menu_Structure[LCD_entry]=Submenu1_invert+chan;
			LCD_row=LCD_entry % LCD_rows;
			LCD_col=((LCD_entry % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width + 1;

			menu_string = g_string_append (menu_string, "INVERT");
			if (globals.Flash.ChanKey_inverted) {
				g_string_append_printf (menu_string, "%d", chan+1);
			}
			menu_string = g_string_append (menu_string, ":");

			if (globals.ChannelState[chan].inverted==NO) {
				menu_string = g_string_append (menu_string, "NO");
			} else {
				menu_string = g_string_append (menu_string, "YES");
			}

			Display_Number_on_LCD(Menu_Is_Item_Visible(LCD_entry), LCD_row,LCD_col,menu_string->str,Show_No_Number,sig_dig,LCD_col_width-1);
			g_string_erase (menu_string, 0, -1);
		}
	}


	/*----- display logic level type, as appropriate -----*/
	if (globals.Flash.logic_level_enabled) {
		for (chan=0; chan<(globals.Flash.ChanKey_logic_level?globals.Flash.channels:1); ++chan) {
			++LCD_entry;
			Main_Menu_Structure[LCD_entry]=Submenu1_logic_level+chan;
			LCD_row=LCD_entry % LCD_rows;
			LCD_col=((LCD_entry % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width + 1;

			menu_string = g_string_append (menu_string, "Logic");
			if (globals.Flash.ChanKey_logic_level) {
				g_string_append_printf (menu_string, "%d", chan+1);
			}
			menu_string = g_string_append (menu_string, ":");
			if (globals.ChannelState[chan].logic_level==logic_ttl) {
				menu_string = g_string_append (menu_string, "TTL");
			} else {
				menu_string = g_string_append (menu_string, "ECL");
			}

			Display_Number_on_LCD(Menu_Is_Item_Visible(LCD_entry), LCD_row,LCD_col,menu_string->str,Show_No_Number,sig_dig,LCD_col_width-1);
			g_string_erase (menu_string, 0, -1);
		}
	}


	/*----- display gate type, except on func gens -----*/

	for (chan=0; chan<((globals.Flash.ChanKey_gate_level|globals.Flash.ChanKey_gate_type)?globals.Flash.channels:1); ++chan)
		if (!globals.Flash.is_func_gen[chan]) {
			{
				++LCD_entry;
				Main_Menu_Structure[LCD_entry]=Submenu1_gate+chan;
				LCD_row=LCD_entry % LCD_rows;
				LCD_col=((LCD_entry % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width + 1;

				menu_string = g_string_append (menu_string, "GAT");
				if (globals.Flash.ChanKey_gate_type || globals.Flash.ChanKey_gate_level) {
					g_string_append_printf (menu_string, "%d", chan+1);
				}
				menu_string = g_string_append (menu_string, ":");

				if (globals.ChannelState[chan].gate_type==gate_sync && globals.ChannelState[chan].gate_level==gate_low) {
					menu_string = g_string_append (menu_string, "SYN,LO");
				} else if (globals.ChannelState[chan].gate_type==gate_sync && globals.ChannelState[chan].gate_level==gate_high) {
					menu_string = g_string_append (menu_string, "SYN,HI");
				} else if (globals.ChannelState[chan].gate_type==gate_async && globals.ChannelState[chan].gate_level==gate_low) {
					menu_string = g_string_append (menu_string, "ASY,LO");
				} else {
					menu_string = g_string_append (menu_string, "ASY,HI");
				}

				Display_Number_on_LCD(Menu_Is_Item_Visible(LCD_entry), LCD_row,LCD_col,menu_string->str,Show_No_Number, sig_dig,LCD_col_width-1);
				g_string_erase (menu_string, 0, -1);
			}
		}

	/*----- display remote/local, always -----*/

	++LCD_entry;
	Main_Menu_Structure[LCD_entry]=Submenu1_rem_loc;
	LCD_row=LCD_entry % LCD_rows;
	LCD_col=((LCD_entry % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width + 1;

	if (Menu_Is_Item_Visible(LCD_entry)) {
		LCD_write_padded_spaces(LCD_row,LCD_col,ctrl_str,LCD_col_width-1);
	}

	g_free (ctrl_str);

	/*----- display memory, always -----*/

	++LCD_entry;
	Main_Menu_Structure[LCD_entry]=Submenu1_memory;
	LCD_row=LCD_entry % LCD_rows;
	LCD_col=((LCD_entry % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width + 1;

	if (Menu_Is_Item_Visible(LCD_entry)) {
		LCD_write_padded_spaces(LCD_row,LCD_col,"Memory menu",LCD_col_width-1);
	}


	/*----- display setup, always -----*/

	++LCD_entry;
	Main_Menu_Structure[LCD_entry]=Submenu1_setup;
	LCD_row=LCD_entry % LCD_rows;
	LCD_col=((LCD_entry % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width + 1;

	if (Menu_Is_Item_Visible(LCD_entry)) {
		LCD_write_padded_spaces(LCD_row,LCD_col,"Setup menu",LCD_col_width-1);
	}


	/*----- display the pointer -----*/

	Menu_Move_Pointer(0);	/* display pointer, but don't move it */

	if (old_cursor_pos!=menu_cursor_pos) {
		LCD_row=(old_cursor_pos % LCD_max_entries_per_page) % LCD_rows;
		LCD_col=((old_cursor_pos % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width;
		LCD_write(LCD_row,LCD_col," ");
	}

	/*----- finish up -----*/

	Main_Menu_max_entry=LCD_entry;	/* record number of menu items */

	if (Main_Menu_max_entry>=LCD_max_entries_per_page) {
		LCD_write(3,39,">");
	} else {
		LCD_write(3,39," ");
	}

	if ((Main_Menu_max_entry/LCD_max_entries_per_page)==(menu_cursor_pos/LCD_max_entries_per_page))
		for (i=(Main_Menu_max_entry%LCD_max_entries_per_page)+ 1; i<12; ++i) {
			LCD_row=i % LCD_rows;
			LCD_col=(i / LCD_rows) * LCD_col_width + 1;
			LCD_write_padded_spaces(LCD_row,LCD_col,"",LCD_col_width-1);
		}

	g_string_free (menu_string, TRUE);

	g_static_mutex_unlock (&mutex);
}


static void Menu_Move_Pointer(int move_amount)
{
	int LCD_row,LCD_col;
	int old_page,new_page;

	/* find the menu index where the selected item is */
	for (menu_cursor_pos=0;
	                ((globals.MenuStatus.Selected_Submenu!=Main_Menu_Structure[menu_cursor_pos]) &&
	                 (menu_cursor_pos < LCD_max_entries));
	                ++menu_cursor_pos) {
		;
	}

	if (menu_cursor_pos==LCD_max_entries) {
		menu_cursor_pos=0;
	}
	/* this occurs when submenus not listed on the main menu are selected, like load/save */

	old_page=menu_cursor_pos / LCD_max_entries_per_page;

	/* use the menu index to find where the cursor is currently pointing, and erase it */
	if (move_amount) {
		LCD_row=menu_cursor_pos % LCD_rows;
		LCD_col=((menu_cursor_pos % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width;
		LCD_write(LCD_row,LCD_col," ");										/* erase pointer */


		/* move the pointer, with wrap-around to zero */
		menu_cursor_pos += move_amount;

		if (menu_cursor_pos > Main_Menu_max_entry) {
			menu_cursor_pos=0;
		}
		if (menu_cursor_pos < 0) {
			menu_cursor_pos=Main_Menu_max_entry;
		}
	}

	/* update the selected menu item */
	globals.MenuStatus.Selected_Submenu=Main_Menu_Structure[menu_cursor_pos];

	/* draw the pointer at the new location */
	LCD_row=menu_cursor_pos % LCD_rows;
	LCD_col=((menu_cursor_pos % LCD_max_entries_per_page) / LCD_rows) * LCD_col_width;
	LCD_write(LCD_row,LCD_col,"~");										/* "~" equals "->" on LCD */

	new_page=menu_cursor_pos / LCD_max_entries_per_page;

	if (new_page!=old_page) {
		Show_Main_Menu();
	}
}


static void Display_Number_on_LCD(int Is_Item_Visible,int LCD_row,int LCD_col,char *start_string,int Show_What, int significant_digits, int width_of_column)
{
	if (!Is_Item_Visible) {
		return;
	}

	gchar *LCD_string = NULL;
	gchar *units = NULL;
	int channel;

	channel=Show_What%100;

	if (Show_What!=Show_No_Number) {
		int show_plus_sign;

		switch (Show_What-channel) {
		case Show_frequency:
			Submenu_Value=globals.ChannelState[channel].frequency;
			units = g_strdup("Hz");
			show_plus_sign=NO;
			break;

		case Show_delay:
			Submenu_Value=globals.ChannelState[channel].delay;
			units = g_strdup("s");
			if (globals.Flash.min_delay[channel] > 0.0) {
				show_plus_sign=NO;
			} else {
				show_plus_sign=YES;
			}
			break;

		case Show_pw:
			Submenu_Value=globals.ChannelState[channel].pw;
			units = g_strdup("s");
			show_plus_sign=NO;
			break;

		case Show_amplitude:
			Submenu_Value=globals.ChannelState[channel].amplitude;

			if (globals.Flash.ignore_ampl_polarity[channel]) {
				show_plus_sign=NO;
			} else {
				show_plus_sign=YES;
			}

			if (globals.Flash.voltage_enabled[channel]) {
				units = g_strdup("V");
			} else {
				units = g_strdup("A");
			}
			break;

		case Show_offset:
			Submenu_Value=globals.ChannelState[channel].offset;
			show_plus_sign=YES;
			if (globals.Flash.voltage_offset_enabled[channel]) {
				units = g_strdup("V");
			} else {
				units = g_strdup("A");
			}
			break;

		case Show_monitor:
			Submenu_Value=globals.ChannelState[channel].Curr_Mon_value;
			show_plus_sign=YES;
			if (globals.ChannelState[channel].pw<globals.Flash.mon_pw_threshold[channel]) {
				units = g_strdup("A*");
				--significant_digits;
			} else {
				units = g_strdup("A");
			}
			break;

		case Show_duty_cycle:
			Submenu_Value=100*globals.ChannelState[channel].pw*globals.ChannelState[channel].frequency;
			show_plus_sign=NO;
			units = g_strdup("%");
			break;

		case Show_route_primary:
			Submenu_Value=(float) globals.ChannelState[channel].route_primary;
			significant_digits=0;
			show_plus_sign=NO;
			units = g_strdup("");
			break;

		case Show_route_secondary:
			Submenu_Value=(float) globals.ChannelState[channel].route_secondary;
			significant_digits=0;
			show_plus_sign=NO;
			units = g_strdup("");
			break;

		case Show_Burst_Count:
			Submenu_Value=(float) globals.ChannelState[channel].burst_count;
			significant_digits=0;
			show_plus_sign=NO;
			units = g_strdup("");
			break;

		case Show_Burst_Time:
			Submenu_Value=globals.ChannelState[channel].burst_time;
			units = g_strdup("s");
			show_plus_sign=NO;
			break;

		case Show_rise_time:
			Submenu_Value=globals.ChannelState[channel].rise_time;
			units = g_strdup("s");
			show_plus_sign=NO;
			break;

		case Show_slew:
			Submenu_Value=globals.ChannelState[channel].slew;
			units = g_strdup("A/s");
			show_plus_sign=NO;
			break;

		case Show_load_type:
			Submenu_Value=globals.ChannelState[channel].load_type;
			units = g_strdup("\xf4");
			show_plus_sign=NO;
			break;

		case Show_soft_current_limit:
			Submenu_Value=globals.ChannelState[channel].soft_current_limit;
			units = g_strdup("A");
			show_plus_sign=YES;
			break;

		case Show_gpib_address:
			Submenu_Value=(float) globals.Flash.gpib_address;
			significant_digits=0;
			units = g_strdup("");
			show_plus_sign=NO;
			break;

		default:
			units = g_strdup("");
		}

		String_Parameter_To_Text(Submenu_Value,significant_digits,start_string,units,&LCD_string,show_plus_sign,width_of_column);
	} else {
		LCD_string = g_strdup(start_string);
	}

	LCD_write_padded_spaces(LCD_row, LCD_col, LCD_string, width_of_column);

	g_free (LCD_string);
	g_free (units);
}


static gchar* title_with_channel (const gchar* title, char chan_key, int channel)
{
	if (chan_key) {
		return g_strdup_printf ("%s %d:", title, channel+1);
	} else {
		return g_strdup_printf ("%s:", title);
	}
}

static void Submenu_Display(int change_selection)
{
	gchar *title = NULL;
	int i;
	int channel;

	if (    (globals.MenuStatus.Type_Of_Menu != Submenu_On) ||
	                (globals.MenuStatus.Error_Screen == YES) ||
	                (globals.MenuStatus.Nonstd_Display == YES) ||
	                (!change_selection)) {
		LCD_clear();
	}

	globals.MenuStatus.Type_Of_Menu=Submenu_On;
	globals.MenuStatus.Error_Screen=NO;
	globals.MenuStatus.Nonstd_Display=NO;

	Submenu_Numeric_Parameter=Show_No_Number;
	Submenu_max_entry=0;


	channel=globals.MenuStatus.Selected_Submenu%100;

	switch (globals.MenuStatus.Selected_Submenu-channel) {
	case Submenu1_freq:

		if (globals.ChannelState[channel].trigger_source==source_internal) {
			title = g_strdup ("Internal Clock:");
			Submenu_Numeric_Parameter=Show_frequency+channel;
		} else {
			title = g_strdup ("Trigger Menu");
		}

		if (globals.Flash.is_func_gen[channel]) {
			Submenu_max_entry=0;
		} else if (globals.Flash.ext2_enabled[channel]) {
			Submenu_max_entry=4;
			Submenu_Structure[0]=mode_freq_int;
			Submenu_Structure[1]=mode_freq_ext;
			Submenu_Structure[2]=mode_freq_ext2;
			Submenu_Structure[3]=mode_freq_man;
			Submenu_Structure[4]=mode_freq_hold;
		} else {
			Submenu_max_entry=3;
			Submenu_Structure[0]=mode_freq_int;
			Submenu_Structure[1]=mode_freq_ext;
			Submenu_Structure[2]=mode_freq_man;
			Submenu_Structure[3]=mode_freq_hold;
		}

		break;

	case Submenu1_func:

		title = g_strdup ("Shape Menu");
		Submenu_max_entry=4;
		Submenu_Structure[0]=mode_func_sin;
		Submenu_Structure[1]=mode_func_tri;
		Submenu_Structure[2]=mode_func_squ;
		Submenu_Structure[3]=mode_func_pulse;
		Submenu_Structure[4]=mode_func_amp;

		break;

	case Submenu1_delay:

		if (globals.ChannelState[channel].double_pulse==double_off) {
			title = title_with_channel("Delay",globals.Flash.ChanKey_delay,channel);
		} else {
			title = title_with_channel("Pulse Spacing",globals.Flash.ChanKey_delay,channel);
		}
		Submenu_Numeric_Parameter=Show_delay+channel;

		if (globals.Flash.double_pulse_allowed[channel]) {
			Submenu_max_entry=1;
			Submenu_Structure[0]=mode_delay_norm;
			Submenu_Structure[1]=mode_delay_dbl;
		} else {
			Submenu_max_entry=0;
		}


		break;

	case Submenu1_pw:
		if (globals.ChannelState[channel].pw_ctrl_mode==pw_normal) {
			if (globals.ChannelState[channel].hold_setting==hold_width) {
				title = title_with_channel("Pulse Width",globals.Flash.ChanKey_pw,channel);
				Submenu_Numeric_Parameter=Show_pw+channel;
			} else {
				title = title_with_channel("Duty Cycle",globals.Flash.ChanKey_pw,channel);
				Submenu_Numeric_Parameter=Show_duty_cycle+channel;
			}
		} else {
			title = title_with_channel("Pulse Width",globals.Flash.ChanKey_pw,channel);
		}

		Submenu_max_entry=0;
		Submenu_Structure[0]=mode_pw_norm;

		if (globals.ChannelState[channel].trigger_source==source_external && (globals.Flash.pw_ab_mode_enabled[channel])) {
			++Submenu_max_entry;
			Submenu_Structure[Submenu_max_entry]=mode_pw_inout;
		}

		if (globals.ChannelState[channel].trigger_source==source_internal) {

			if (globals.Flash.min_pw[channel]!=globals.Flash.max_pw[channel]) {
				++Submenu_max_entry;
	                        Submenu_Structure[Submenu_max_entry]=mode_pw_duty;
			}

			if (globals.Flash.dc_mode_allowed[channel]) {
				++Submenu_max_entry;
				Submenu_Structure[Submenu_max_entry]=mode_pw_dc;
			}
		}

		if (globals.Flash.ew_enabled[channel]) {
			++Submenu_max_entry;
			Submenu_Structure[Submenu_max_entry]=mode_pw_ew;
		}

		break;

	case Submenu1_amp:
		title = title_with_channel("Amplitude",globals.Flash.ChanKey_amplitude,channel);

		if (number_of_fixed_ampl_points(channel)>0) {
			int fixed_count;
			Submenu_max_entry = number_of_fixed_ampl_points(channel) - 1;
			for (fixed_count = 0; fixed_count < number_of_fixed_ampl_points(channel); ++fixed_count) {
				Submenu_Structure[fixed_count] = mode_ampl_fixed_point0 + (fixed_count*100);
			}
		} else if (globals.ChannelState[channel].amp_mode==amp_mode_normal) {
			Submenu_Numeric_Parameter=Show_amplitude+channel;
		}

		if (globals.Flash.ea_enabled[channel]) {
			++Submenu_max_entry;
			Submenu_Structure[0]=mode_amp_normal;
			Submenu_Structure[Submenu_max_entry]=mode_amp_ea;
		}
		if (globals.Flash.ext_amplify_enabled[channel]) {
			++Submenu_max_entry;
			Submenu_Structure[0]=mode_amp_normal;
			Submenu_Structure[Submenu_max_entry]=mode_amp_amplify;
		}

		if (globals.Flash.ignore_ampl_polarity[channel]) {
			LCD_write(2,2,"(+/- set by AMP1)");
		}
		break;

	case Submenu1_burst_count:
		title = title_with_channel("Pulses per burst",globals.Flash.ChanKey_Burst_Count,channel);
		Submenu_Numeric_Parameter=Show_Burst_Count+channel;
		Submenu_max_entry=0;
		break;

	case Submenu1_burst_time:
		title = title_with_channel("Burst Spacing",globals.Flash.ChanKey_Burst_Time,channel);
		Submenu_Numeric_Parameter=Show_Burst_Time+channel;
		Submenu_max_entry=0;
		break;

	case Submenu1_rise_time:
		title = title_with_channel("Rise time",globals.Flash.ChanKey_rise_time,channel);

		if (globals.Flash.rise_time_min_max_only[channel]) {
			Submenu_max_entry=1;
			Submenu_Structure[0]=mode_rise_time_min;
			Submenu_Structure[1]=mode_rise_time_max;
		} else {
			Submenu_Numeric_Parameter=Show_rise_time+channel;
                        Submenu_max_entry=0;
		}
		break;

	case Submenu1_slew:
		title = title_with_channel("Slew Rate",globals.Flash.ChanKey_slew,channel);
		Submenu_Numeric_Parameter=Show_slew+channel;
		Submenu_max_entry=0;
		break;

	case Submenu1_soft_current_limit:
		title = title_with_channel("Current Limit",globals.Flash.ChanKey_current_limit,channel);
		Submenu_Numeric_Parameter=Show_soft_current_limit+channel;
		Submenu_max_entry=0;
		break;

	case Submenu1_zout:
		title = title_with_channel("Output Impedance",globals.Flash.ChanKey_zout,channel);
		Submenu_max_entry=1;
		Submenu_Structure[0]=mode_zout_min;
		Submenu_Structure[1]=mode_zout_max;
		break;

	case Submenu1_loadtype:
		title = title_with_channel("Load Impedance",globals.Flash.ChanKey_load_type,channel);
		Submenu_Numeric_Parameter=Show_load_type+channel;
		Submenu_max_entry=0;
		break;

	case Submenu1_offset:
		title = title_with_channel("Offset",globals.Flash.ChanKey_offset,channel);

		if (globals.ChannelState[channel].os_mode==os_mode_normal) {
			Submenu_Numeric_Parameter=Show_offset+channel;
		}

		if (globals.Flash.eo_enabled[channel]) {
			Submenu_max_entry=1;
			Submenu_Structure[0]=mode_os_normal;
			Submenu_Structure[1]=mode_os_eo;
		} else {
			Submenu_max_entry=0;
		}

		break;

	case Submenu1_mon:
		Submenu_max_entry=0;
		title = title_with_channel("Monitor",globals.Flash.ChanKey_Curr_Mon_value,channel);
		if (globals.ChannelState[channel].pw<globals.Flash.mon_pw_threshold[channel]) {
			LCD_write(2,2,"*PW too narrow for accurate reading.");
		}
		Submenu_Numeric_Parameter=Show_monitor+channel;
		break;

	case Submenu1_output_state:
		title = title_with_channel("Output State",globals.Flash.ChanKey_output_state,channel);

		Submenu_max_entry=1;
		Submenu_Structure[0]=mode_output_on;
		Submenu_Structure[1]=mode_output_off;

		break;

	case Submenu1_invert:
		title = title_with_channel("Inverted Mode",globals.Flash.ChanKey_inverted,channel);

		Submenu_max_entry=1;
		Submenu_Structure[0]=mode_inv_no;
		Submenu_Structure[1]=mode_inv_yes;

		break;

	case Submenu1_logic_level:
		title = title_with_channel("Logic Output",globals.Flash.ChanKey_logic_level,channel);
		Submenu_max_entry=1;
		Submenu_Structure[0]=mode_logic_ttl;
		Submenu_Structure[1]=mode_logic_ecl;
		break;

	case Submenu1_gate:
		title = g_strdup ("Gate (trigger off) ");

		Submenu_max_entry=1;
		Submenu_Structure[0]=mode_gate_losync;
		Submenu_Structure[1]=mode_gate_hisync;

		/* async mode doesn't work properly in dual-channel units */
		if ((globals.Flash.channels<=1) && !globals.Flash.sync_only) {
			Submenu_max_entry=3;
			Submenu_Structure[2]=mode_gate_loasync;
			Submenu_Structure[3]=mode_gate_hiasync;
		}

		break;

	case Submenu1_rem_loc:

		if (globals.Remote.gpib_remote && !VXI_OR_GPIB_LOCK_ACTIVE) {
			Submenu_max_entry=1;
			title = g_strdup ("GPIB Remote:");
			Submenu_Structure[0]=mode_go_to_local;
			Submenu_Structure[1]=mode_exit_normal_submenu;
		} else {
			Submenu_max_entry=0;
			title = g_strdup ("GPIB interface already in local mode.");
			Submenu_Structure[0]=mode_exit_normal_submenu;
		}
		break;

	case Submenu1_setup:
		title = g_strdup ("Setup Menu:");

		Submenu_max_entry=5;
		if (globals.Flash.self_cal) {
			Submenu_max_entry=6;
			Submenu_Structure[5]=mode_selfcal;
		}

		Submenu_Structure[0]=mode_gpib_address;
		Submenu_Structure[1]=mode_rs232_settings;
		Submenu_Structure[2]=mode_model_info;
		Submenu_Structure[3]=mode_network;
		Submenu_Structure[4]=mode_password;
		Submenu_Structure[Submenu_max_entry]=mode_exit_normal_submenu;
		break;

	case Submenu2_save:
		title = g_strdup ("Save Settings:");
		Submenu_max_entry=4;

		Submenu_Structure[0]=mode_save_0;
		Submenu_Structure[1]=mode_save_1;
		Submenu_Structure[2]=mode_save_2;
		Submenu_Structure[3]=mode_save_3;
                Submenu_Structure[4]=mode_save_exit;
		break;

	case Submenu2_load:
		title = g_strdup ("Load Settings:");
		Submenu_max_entry=4;

		Submenu_Structure[0]=mode_load_0;
		Submenu_Structure[1]=mode_load_1;
		Submenu_Structure[2]=mode_load_2;
		Submenu_Structure[3]=mode_load_3;
                Submenu_Structure[4]=mode_load_exit;

		break;

	case Submenu1_memory:
		title = g_strdup ("Memory:");
		Submenu_max_entry=2;

		Submenu_Structure[0]=mode_load;
		Submenu_Structure[1]=mode_save;
		Submenu_Structure[2]=mode_exit_normal_submenu;
		break;

	case Submenu2_rs232:
		title = g_strdup ("Serial Port:");
		Submenu_max_entry=2;

		Submenu_Structure[0]=mode_change_rs232;
		Submenu_Structure[1]=mode_default_rs232;
		Submenu_Structure[2]=mode_exit_rs232;
		break;

	case Submenu2_rs232_baud:
		title = g_strdup ("Baud Rate:");
		Submenu_max_entry=7;

		Submenu_Structure[0]=mode_1200;
		Submenu_Structure[1]=mode_2400;
		Submenu_Structure[2]=mode_4800;
		Submenu_Structure[3]=mode_9600;
		Submenu_Structure[4]=mode_19200;
		Submenu_Structure[5]=mode_38400;
		Submenu_Structure[6]=mode_57600;
		Submenu_Structure[7]=mode_115200;

		break;

	case Submenu2_rs232_hardhand:
		title = g_strdup ("Handshaking:");
		Submenu_max_entry=1;

		Submenu_Structure[0]=mode_hand_hard;
		Submenu_Structure[1]=mode_hand_off;
		break;

	case Submenu2_gpib_address:
		title = g_strdup ("GPIB Address:");
		Submenu_Numeric_Parameter=Show_gpib_address+channel;
		break;

	case Submenu1_route_primary:
		if (globals.Flash.routing_required[channel] == 1) {
			title = g_strdup ("Output route:");
		} else {
			title = g_strdup ("Anode pin:");
		}

		// use modes for 2 outputs, adjust knob for 16 pins
		if (globals.Flash.routing_max_pins[channel] == 2) {
			Submenu_max_entry=1;
			Submenu_Structure[0]=mode_route1;
			Submenu_Structure[1]=mode_route2;
		} else {
			Submenu_Numeric_Parameter=Show_route_primary+channel;
			Submenu_max_entry=0;
		}
		break;

	case Submenu1_route_secondary:
		title = g_strdup ("Cathode pin:");
		Submenu_Numeric_Parameter=Show_route_secondary+channel;
		Submenu_max_entry=0;
		break;


	default:
		title = g_strdup ("error - not implemented");
	}

	for (i=0; i<=Submenu_max_entry; ++i) {
		Submenu_Structure[i]+=channel;
	}

	LCD_write(0,0,title);
	g_free (title);

	Display_Number_on_LCD(YES,1,2,"",Submenu_Numeric_Parameter,4,LCD_col_width);
	LCD_write(3,0,Press_Change_Message);

	if (Submenu_max_entry>0) {

		GPtrArray *gparray = g_ptr_array_new ();

		int current_operating_mode = 0;

		LCD_write(0,19,"Mode:");

		for (i=0; i<=Submenu_max_entry; ++i) {
			gchar *mode_name;
			gchar *fixed_ampl_units;
			float use_ampl;

			if (globals.Flash.voltage_enabled[channel]) {
				fixed_ampl_units = g_strdup("V");
			} else {
				fixed_ampl_units = g_strdup("A");
			}

			switch (Submenu_Structure[i]-channel) {
			case mode_freq_int:
				mode_name = g_strdup("Internal");
				if (globals.ChannelState[channel].trigger_source==source_internal) {
					current_operating_mode=i;
				}
				break;
			case mode_freq_ext:
				mode_name = g_strdup("External");
				if (globals.ChannelState[channel].trigger_source==source_external) {
					current_operating_mode=i;
				}
				break;
                        case mode_freq_ext2:
				mode_name = g_strdup("Ext Dbl");
				if (globals.ChannelState[channel].trigger_source==source_external2) {
					current_operating_mode=i;
				}
				break;
			case mode_freq_man:
				mode_name = g_strdup("Manual");
				if (globals.ChannelState[channel].trigger_source==source_manual) {
					current_operating_mode=i;
				}
				break;
			case mode_freq_hold:
				mode_name = g_strdup("Hold");
				if (globals.ChannelState[channel].trigger_source==source_hold) {
					current_operating_mode=i;
				}
				break;
			case mode_func_sin:
				mode_name = g_strdup("Sine");
				if (globals.ChannelState[channel].func_mode==sin_mode_on) {
					current_operating_mode=i;
				}
				break;
			case mode_func_tri:
				mode_name = g_strdup("Triangle");
				if (globals.ChannelState[channel].func_mode==tri_mode_on) {
					current_operating_mode=i;
				}
				break;
			case mode_func_squ:
				mode_name = g_strdup("Square");
				if (globals.ChannelState[channel].func_mode==squ_mode_on) {
					current_operating_mode=i;
				}
				break;
			case mode_func_pulse:
				mode_name = g_strdup("Pulse");
				if (globals.ChannelState[channel].func_mode==pulse_mode_on) {
					current_operating_mode=i;
				}
				break;
			case mode_func_amp:
				mode_name = g_strdup("Amplify");
				if (globals.ChannelState[channel].func_mode==amp_mode_on) {
					current_operating_mode=i;
				}
				break;
			case mode_delay_norm:
				mode_name = g_strdup("Normal");
				if (globals.ChannelState[channel].double_pulse==double_off) {
					current_operating_mode=i;
				}
				break;
			case mode_delay_dbl:
				mode_name = g_strdup("Double Pulse");
				if (globals.ChannelState[channel].double_pulse==double_on) {
					current_operating_mode=i;
				}
				break;
			case mode_pw_norm:
				mode_name = g_strdup("Normal");
				if (globals.ChannelState[channel].func_mode==pulse_mode_on
				                && globals.ChannelState[channel].hold_setting==hold_width && globals.ChannelState[channel].pw_ctrl_mode==pw_normal) {
					current_operating_mode=i;
				}
				break;
			case mode_pw_duty:
				mode_name = g_strdup("Duty Cycle");
				if (globals.ChannelState[channel].func_mode==pulse_mode_on
				                && globals.ChannelState[channel].hold_setting==hold_duty && globals.ChannelState[channel].pw_ctrl_mode==pw_normal) {
					current_operating_mode=i;
				}
				break;
			case mode_pw_inout:
				mode_name = g_strdup("PWin=PWout");
				if (globals.ChannelState[channel].func_mode==pulse_mode_on && globals.ChannelState[channel].pw_ctrl_mode==pw_in_out) {
					current_operating_mode=i;
				}
				break;
                        case mode_pw_ew:
                                mode_name = g_strdup("Ext Control");
                                if (globals.ChannelState[channel].func_mode==pulse_mode_on && globals.ChannelState[channel].pw_ctrl_mode==pw_ew_ext) {
                                        current_operating_mode=i;
                                }
                                break;
			case mode_pw_dc:
				mode_name = g_strdup("DC output");
				if (globals.ChannelState[channel].func_mode==dc_mode_on) {
					current_operating_mode=i;
				}
				break;
			case mode_output_on:
				mode_name = g_strdup("Output On");
				if (globals.ChannelState[channel].output_state==output_on) {
					current_operating_mode=i;
				}
				break;
			case mode_output_off:
				mode_name = g_strdup("Output Off");
				if (globals.ChannelState[channel].output_state==output_off) {
					current_operating_mode=i;
				}
				break;
			case mode_go_to_local:
				mode_name = g_strdup("Go To Local");
				break;
			case mode_inv_no:
				mode_name = g_strdup("NO (normal)");
				if (globals.ChannelState[channel].inverted==NO) {
					current_operating_mode=i;
				}
				break;
			case mode_inv_yes:
				mode_name = g_strdup("YES (inverted)");
				if (globals.ChannelState[channel].inverted==YES) {
					current_operating_mode=i;
				}
				break;
			case mode_gate_losync:
				mode_name = g_strdup("Sync,TTL-low");
				if (globals.ChannelState[channel].gate_type==gate_sync && globals.ChannelState[channel].gate_level==gate_low) {
					current_operating_mode=i;
				}
				break;
			case mode_gate_hisync:
				mode_name = g_strdup("Sync,TTL-hi");
				if (globals.ChannelState[channel].gate_type==gate_sync && globals.ChannelState[channel].gate_level==gate_high) {
					current_operating_mode=i;
				}
				break;
			case mode_gate_loasync:
				mode_name = g_strdup("Async,TTL-low");
				if (globals.ChannelState[channel].gate_type==gate_async && globals.ChannelState[channel].gate_level==gate_low) {
					current_operating_mode=i;
				}
				break;
			case mode_gate_hiasync:
				mode_name = g_strdup("Async,TTL-hi");
				if (globals.ChannelState[channel].gate_type==gate_async && globals.ChannelState[channel].gate_level==gate_high) {
					current_operating_mode=i;
				}
				break;
			case mode_gpib_address:
				mode_name = g_strdup("GPIB address");
				break;
			case mode_rs232_settings:
				mode_name = g_strdup("RS232 setup");
				break;
			case mode_model_info:
				mode_name = g_strdup("Model info");
				break;
			case mode_network:
				mode_name = g_strdup("Network info");
				break;
			case mode_password:
				mode_name = g_strdup("Pwd~default");
				break;
			case mode_selfcal:
				mode_name = g_strdup("Self Cal");
				break;
			case mode_exit_normal_submenu:
				mode_name = g_strdup("Exit");
				break;
			case mode_load:
				mode_name = g_strdup("Load Settings");
				break;
			case mode_save:
				mode_name = g_strdup("Save Settings");
				break;
			case mode_load_0:
			case mode_save_0:
				mode_name = g_strdup("Storage 0");
				break;
			case mode_load_1:
			case mode_save_1:
				mode_name = g_strdup("Storage 1");
				break;
			case mode_load_2:
			case mode_save_2:
				mode_name = g_strdup("Storage 2");
				break;
			case mode_load_3:
			case mode_save_3:
				mode_name = g_strdup("Storage 3");
				break;

                        case mode_load_exit:
                        case mode_save_exit:
                                mode_name = g_strdup("Exit");
                                break;

			case mode_change_rs232:
				mode_name = g_strdup("Change values");
				break;
			case mode_default_rs232:
				mode_name = g_strdup("Default");
				break;
			case mode_exit_rs232:
				mode_name = g_strdup("Exit");
				break;
			case mode_zout_max:
				mode_name = g_strdup_printf ("Zout = %d\xf4", globals.Flash.zout_max[channel]);
				if (globals.ChannelState[channel].zout==globals.Flash.zout_max[channel]) {
					current_operating_mode=i;
				}
				break;
			case mode_zout_min:
				mode_name = g_strdup_printf ("Zout = %d\xf4", globals.Flash.zout_min[channel]);
				if (globals.ChannelState[channel].zout==globals.Flash.zout_min[channel]) {
					current_operating_mode=i;
				}
				break;
			case mode_logic_ttl:
				mode_name = g_strdup("TTL levels");
				if (globals.ChannelState[channel].logic_level==logic_ttl) {
					current_operating_mode=i;
				}
				break;
			case mode_logic_ecl:
				mode_name = g_strdup("ECL levels");
				if (globals.ChannelState[channel].logic_level==logic_ecl) {
					current_operating_mode=i;
				}
				break;
			case mode_amp_normal:
				mode_name = g_strdup("Normal");
				if (globals.ChannelState[channel].amp_mode==amp_mode_normal) {
					current_operating_mode=i;
				}
				break;
			case mode_amp_ea:
				mode_name = g_strdup("Ext Control");
				if (globals.ChannelState[channel].amp_mode==amp_mode_ea) {
					current_operating_mode=i;
				}
				break;
			case mode_amp_amplify:
				mode_name = g_strdup("Ext Amplify");
				if (globals.ChannelState[channel].amp_mode==amp_mode_amplify) {
					current_operating_mode=i;
				}
				break;
			case mode_os_normal:
				mode_name = g_strdup("Normal");
				if (globals.ChannelState[channel].os_mode==os_mode_normal) {
					current_operating_mode=i;
				}
				break;
			case mode_os_eo:
				mode_name = g_strdup("Ext Control");
				if (globals.ChannelState[channel].os_mode==os_mode_eo) {
					current_operating_mode=i;
				}
				break;


			// hard-coded count of 10 - not ideal!
                        case (mode_ampl_fixed_point0):
				use_ampl = globals.Flash.fixed_ampl_points[channel][0];
                                String_Parameter_To_Text(use_ampl,3,"",fixed_ampl_units,&mode_name,YES,LCD_col_width);
                                if (fabs(globals.ChannelState[channel].amplitude-use_ampl)<globals.Flash.ampl_zero_equiv[channel]) {
                                        current_operating_mode=i;
                                }
                                break;
                        case (mode_ampl_fixed_point1):
                                use_ampl = globals.Flash.fixed_ampl_points[channel][1];
                                String_Parameter_To_Text(use_ampl,3,"",fixed_ampl_units,&mode_name,YES,LCD_col_width);
                                if (fabs(globals.ChannelState[channel].amplitude-use_ampl)<globals.Flash.ampl_zero_equiv[channel]) {
                                        current_operating_mode=i;
                                }
                                break;
                        case (mode_ampl_fixed_point2):
                                use_ampl = globals.Flash.fixed_ampl_points[channel][2];
                                String_Parameter_To_Text(use_ampl,3,"",fixed_ampl_units,&mode_name,YES,LCD_col_width);
                                if (fabs(globals.ChannelState[channel].amplitude-use_ampl)<globals.Flash.ampl_zero_equiv[channel]) {
                                        current_operating_mode=i;
                                }
                                break;

			case (mode_ampl_fixed_point3):
                                use_ampl = globals.Flash.fixed_ampl_points[channel][3];
				String_Parameter_To_Text(use_ampl,3,"",fixed_ampl_units,&mode_name,YES,LCD_col_width);
				if (fabs(globals.ChannelState[channel].amplitude-use_ampl)<globals.Flash.ampl_zero_equiv[channel]) {
					current_operating_mode=i;
				}
				break;

                        case (mode_ampl_fixed_point4):
                                use_ampl = globals.Flash.fixed_ampl_points[channel][4];
                                String_Parameter_To_Text(use_ampl,3,"",fixed_ampl_units,&mode_name,YES,LCD_col_width);
                                if (fabs(globals.ChannelState[channel].amplitude-use_ampl)<globals.Flash.ampl_zero_equiv[channel]) {
                                        current_operating_mode=i;
                                }
                                break;
                        case (mode_ampl_fixed_point5):
                                use_ampl = globals.Flash.fixed_ampl_points[channel][5];
                                String_Parameter_To_Text(use_ampl,3,"",fixed_ampl_units,&mode_name,YES,LCD_col_width);
                                if (fabs(globals.ChannelState[channel].amplitude-use_ampl)<globals.Flash.ampl_zero_equiv[channel]) {
                                        current_operating_mode=i;
                                }
                                break;
                        case (mode_ampl_fixed_point6):
                                use_ampl = globals.Flash.fixed_ampl_points[channel][6];
                                String_Parameter_To_Text(use_ampl,3,"",fixed_ampl_units,&mode_name,YES,LCD_col_width);
                                if (fabs(globals.ChannelState[channel].amplitude-use_ampl)<globals.Flash.ampl_zero_equiv[channel]) {
                                        current_operating_mode=i;
                                }
                                break;
                        case (mode_ampl_fixed_point7):
                                use_ampl = globals.Flash.fixed_ampl_points[channel][7];
                                String_Parameter_To_Text(use_ampl,3,"",fixed_ampl_units,&mode_name,YES,LCD_col_width);
                                if (fabs(globals.ChannelState[channel].amplitude-use_ampl)<globals.Flash.ampl_zero_equiv[channel]) {
                                        current_operating_mode=i;
                                }
                                break;
                        case (mode_ampl_fixed_point8):
                                use_ampl = globals.Flash.fixed_ampl_points[channel][8];
                                String_Parameter_To_Text(use_ampl,3,"",fixed_ampl_units,&mode_name,YES,LCD_col_width);
                                if (fabs(globals.ChannelState[channel].amplitude-use_ampl)<globals.Flash.ampl_zero_equiv[channel]) {
                                        current_operating_mode=i;
                                }
                                break;
                        case (mode_ampl_fixed_point9):
                                use_ampl = globals.Flash.fixed_ampl_points[channel][9];
                                String_Parameter_To_Text(use_ampl,3,"",fixed_ampl_units,&mode_name,YES,LCD_col_width);
                                if (fabs(globals.ChannelState[channel].amplitude-use_ampl)<globals.Flash.ampl_zero_equiv[channel]) {
                                        current_operating_mode=i;
                                }
                                break;

			case mode_route1:
				mode_name = g_strdup("1");
				if (globals.ChannelState[channel].route_primary == 1) {
					current_operating_mode=i;
				}
				break;

			case mode_route2:
				mode_name = g_strdup("2");
				if (globals.ChannelState[channel].route_primary == 2) {
					current_operating_mode=i;
				}
				break;

			case mode_1200:
				mode_name = g_strdup("1200 baud");
				if (globals.Flash.baud==1200) {
					current_operating_mode=i;
				}
				break;
			case mode_2400:
				mode_name = g_strdup("2400 baud");
				if (globals.Flash.baud==2400) {
					current_operating_mode=i;
				}
				break;
			case mode_4800:
				mode_name = g_strdup("4800 baud");
				if (globals.Flash.baud==4800) {
					current_operating_mode=i;
				}
				break;
			case mode_9600:
				mode_name = g_strdup("9600 baud");
				if (globals.Flash.baud==9600) {
					current_operating_mode=i;
				}
				break;
			case mode_19200:
				mode_name = g_strdup("19200 baud");
				if (globals.Flash.baud==19200) {
					current_operating_mode=i;
				}
				break;
			case mode_38400:
				mode_name = g_strdup("38400 baud");
				if (globals.Flash.baud==38400) {
					current_operating_mode=i;
				}
				break;
			case mode_57600:
				mode_name = g_strdup("57600 baud");
				if (globals.Flash.baud==57600) {
					current_operating_mode=i;
				}
				break;
			case mode_115200:
				mode_name = g_strdup("115200 baud");
				if (globals.Flash.baud==115200) {
					current_operating_mode=i;
				}
				break;

			case mode_hand_hard:
				mode_name = g_strdup("Hardware");
				if (globals.Flash.hardhand) {
					current_operating_mode=i;
				}
				break;
			case mode_hand_off:
				mode_name = g_strdup("None");
				if (!globals.Flash.hardhand) {
					current_operating_mode=i;
				}
				break;

			case mode_rise_time_min:
				String_Parameter_To_Text(globals.Flash.min_rise_time[channel],2,"","s",&mode_name,NO,LCD_col_width);
				if (fabs(globals.ChannelState[channel].rise_time-globals.Flash.min_rise_time[channel]) < smallest_allowed_number) {
					current_operating_mode=i;
				}
				break;
				
                        case mode_rise_time_max:
                                String_Parameter_To_Text(globals.Flash.max_rise_time[channel],2,"","s",&mode_name,NO,LCD_col_width);
                                if (fabs(globals.ChannelState[channel].rise_time-globals.Flash.max_rise_time[channel]) < smallest_allowed_number) {
                                        current_operating_mode=i;
                                }
				break;

			default:
				mode_name = g_strdup("??");
				break;
			}

			g_ptr_array_add (gparray, (gpointer) mode_name);

			g_free (fixed_ampl_units);
		}

		/* If change_selection==NO, the submenu is being drawn from scratch.
		   this case, the arrow pointer points at the current operating mode.
		   If change_selection=YES, the submenu is being redrawn to scroll
		   the mode list. In this case, the arrow pointer points at the current
		   selection. */

		if (change_selection==NO && current_operating_mode<4) {
			base_entry=0;
			Submenu_Selected_Item=current_operating_mode;
		} else if (change_selection==NO) {
			base_entry=current_operating_mode-3;
			Submenu_Selected_Item=current_operating_mode;
		} else if (change_selection==YES && Submenu_Selected_Item<4) {
			base_entry=0;
		} else if (change_selection==YES && Submenu_Selected_Item>=4) {
			base_entry=Submenu_Selected_Item-3;
		}

		for (i=base_entry; ( (i<=Submenu_max_entry) && (i< (base_entry+4)) ); ++i) {
			LCD_write_padded_to_end_of_line(i-base_entry, 26, g_ptr_array_index (gparray, i));
		}
		LCD_write(Submenu_Selected_Item-base_entry,25,"~");

		/* add scrolling indicators, if required */
		LCD_write(0,39," ");
		LCD_write(3,39," ");
		if (base_entry) {
			LCD_write(0,39,"\x2");
		}
		if ((base_entry+3) < Submenu_max_entry) {
			LCD_write(3,39,"\x3");
		}

		g_ptr_array_foreach (gparray, (GFunc) g_free, NULL);
		g_ptr_array_free (gparray, TRUE);
	}
}


static void Submenu_Move_Pointer(void)
{
	if (Submenu_max_entry>0) {

		LCD_write(Submenu_Selected_Item-base_entry,25," ");
		++Submenu_Selected_Item;

		if (Submenu_Selected_Item>Submenu_max_entry) {
			Submenu_Selected_Item=0;
		}

		Submenu_Display(YES);
	}
}


static int Submenu_Mult_Value(float mult_by)
{

	int error_num;
	int channel;

	float new_value;

	error_num=OK;

	/* return if the encoder is not useful for the displayed parameter */
	if (Submenu_Numeric_Parameter==Show_No_Number) {
		return OK;
	}

	channel=Submenu_Numeric_Parameter%100;

	new_value = Submenu_Value * mult_by;

	switch (Submenu_Numeric_Parameter-channel) {
	case Show_frequency:
		if (error_num=Set_frequency(0,0,0,channel,new_value)) {
			Submenu_Value=new_value;
		}
		break;

	case Show_delay:

		if (fabs(new_value)<zero_equiv_timing && mult_by>1.0) {
			if (new_value<0.0) {
				new_value=-zero_equiv_timing;
			} else {
				new_value=zero_equiv_timing;
			}
		}

		if (fabs(new_value) < zero_equiv_timing) {
			if (new_value<0.0) {
				new_value=-smallest_allowed_number;
			} else {
				new_value=smallest_allowed_number;
			}
		}

		if (error_num=Set_Delay(0,0,0,channel,new_value)) {
			Submenu_Value=new_value;
		}
		break;

	case Show_pw:

		if (fabs(new_value)<zero_equiv_timing && mult_by>1.0) {
			if (new_value<0.0) {
				new_value=-zero_equiv_timing;
			} else {
				new_value=zero_equiv_timing;
			}
		}

		if (fabs(new_value) < zero_equiv_timing) {
			if (new_value<0.0) {
				new_value=-smallest_allowed_number;
			} else {
				new_value=smallest_allowed_number;
			}
		}

		if (error_num=Set_Pw(0,0,0,channel,new_value,0)) {
			Submenu_Value=new_value;
		}
		break;

	case Show_amplitude:
		if (fabs(new_value)<globals.Flash.ampl_zero_equiv[channel] && mult_by>1.0) {
			if (new_value<0.0 || globals.Flash.max_ampl[channel]<globals.Flash.ampl_zero_equiv[channel]) {
				new_value=-globals.Flash.ampl_zero_equiv[channel];
			} else {
				new_value=globals.Flash.ampl_zero_equiv[channel];
			}
		}

		if (fabs(new_value) < globals.Flash.ampl_zero_equiv[channel]) {
			if (new_value<0.0) {
				new_value=-smallest_allowed_number;
			} else {
				new_value=smallest_allowed_number;
			}
		}

		if (error_num=Set_Amplitude(0,0,0,0,0,0,0,channel,new_value,0)) {
			Submenu_Value=new_value;
		}
		break;

	case Show_Burst_Time:
		if (error_num=Set_Burst_Time(0,0,0,channel,new_value)) {
			Submenu_Value=new_value;
		}
		break;

	case Show_rise_time:
		if (error_num=Set_rise_time(0,0,0,channel,new_value)) {
			Submenu_Value=new_value;
		}
		break;

	case Show_slew:
		if (error_num=Set_slew(0,0,0,channel,new_value)) {
			Submenu_Value=new_value;
		}
		break;

	case Show_load_type:
		if (error_num=Set_Load(channel,new_value)) {
			Submenu_Value=new_value;
		}
		break;

	case Show_soft_current_limit:
		if (error_num=Set_current_limit(0,channel,new_value)) {
			Submenu_Value=new_value;
		}
		break;

	case Show_offset:
		if (fabs(new_value)<globals.Flash.os_zero_equiv[channel] && mult_by>1.0) {
			if (new_value<0.0 || globals.Flash.max_offset[channel]<globals.Flash.os_zero_equiv[channel]) {
				new_value=-globals.Flash.os_zero_equiv[channel];
			} else {
				new_value=globals.Flash.os_zero_equiv[channel];
			}
		}

		if (fabs(new_value) < globals.Flash.os_zero_equiv[channel]) {
			if (new_value<0.0) {
				new_value=-smallest_allowed_number;
			} else {
				new_value=smallest_allowed_number;
			}
		}

		if (error_num=Set_Offset(0,0,0,0,channel,new_value)) {
			Submenu_Value=new_value;
		}
		break;

	case Show_duty_cycle:
		if (error_num=Set_Pw(0,0,0,channel,new_value/(100*globals.ChannelState[channel].frequency),0)) {
			Submenu_Value=new_value;
		}
		break;
	}

	Main_update_shift_registers();

	Display_Number_on_LCD(YES,1,2,"",Submenu_Numeric_Parameter,4,LCD_col_width);

	return error_num;
}


static void Submenu_Service_Encoder(int encoder_change)
{

	int error_num;
	int equivalent_integer;		/* non-exponent part stripped of its decimal point */
	float new_value;		/* new parameter value to be loaded */
	float abs_Submenu_Value;	/* absolute value of Submenu_Value */
	int increment_size;
	int new_int_value;
	int reset_encoder;
	int channel;

	reset_encoder=YES;

	/* quit if RWLS mode */
	update_remote_mode ();
	if (VXI_OR_GPIB_LOCK_ACTIVE) {
		return;
	}

	if (globals.MenuStatus.Type_Of_Menu==Main_Menu_On) {
		if (encoder_change>1) {
			Menu_Move_Pointer(1);
		} else if (encoder_change<-1) {
			Menu_Move_Pointer(-1);
		}

		g_usleep(2e5);
		return;
	}

	/* increase increments for rapid rotation */
	encoder_timer_change[2] = encoder_timer_change[1];
	encoder_timer_change[1] = encoder_timer_change[0];
	encoder_timer_change[0] = ms_timer() - encoder_last_adjust;
	encoder_last_adjust = ms_timer();

	if (encoder_timer_change[0]<0) {
		encoder_timer_change[0]=1000;
	}

	if (
	        (encoder_timer_change[0] < 50)
	        && (encoder_timer_change[1] < 50)
	        && (encoder_timer_change[2] < 50)
	        && (Submenu_extra_fine==NO) ) {
		++encoder_mult;
		if (encoder_mult>8) {
			encoder_mult=8;
		}
		encoder_change *= encoder_mult;
	} else {
		encoder_mult=1;
	}

	/* make changes minimal if last adjustment caused an error */
	if (last_encoder_adjust_error != OK) {
		if (encoder_change>0) {
			encoder_change=1;
		} else {
			encoder_change=-1;
		}
	}

	channel=Submenu_Numeric_Parameter%100;

	/* return if the encoder is not useful for the displayed parameter */
	if ((Submenu_Numeric_Parameter-channel)==Show_No_Number || (Submenu_Numeric_Parameter-channel)==Show_monitor) {
		return;
	}

	if (Submenu_Value<0) {
		abs_Submenu_Value=-Submenu_Value;
	} else {
		abs_Submenu_Value=Submenu_Value;
	}

	/* deal with special integer parameters first */
	if ((Submenu_Numeric_Parameter-channel) == Show_gpib_address)

	{
		g_usleep (2e5);
		reset_encoder=YES;	/* to avoid extra unwanted increments */
		if (encoder_change>0) {
			new_int_value=(int) (Submenu_Value + 1.0);
			if (new_int_value>30) {
				new_int_value=0;
			}
		} else {
			new_int_value=(int) (Submenu_Value - 1.0);
			if (new_int_value<0) {
				new_int_value=30;
			}
		}
	}

	if ((Submenu_Numeric_Parameter-channel) == Show_Burst_Count)

	{
		g_usleep (2e5);
		reset_encoder=YES;	/* to avoid extra unwanted increments */
		new_int_value=(int) (Submenu_Value);
	
#define LARGE_CHANGE 3
#define BURST_SMALL_INC 1
#define BURST_LARGE_INC 10

		if (encoder_change>0) {
			if (encoder_change>LARGE_CHANGE) {
				new_int_value += BURST_LARGE_INC;
			} else {
				new_int_value += BURST_SMALL_INC;
			}
		} else if (encoder_change<0) {
                       if (encoder_change<-LARGE_CHANGE) {
                                new_int_value -= BURST_LARGE_INC;
                        } else {
                                new_int_value -= BURST_SMALL_INC;
                        }
		}

		if (new_int_value>globals.Constraints.err_max_burst_count[channel]) {
			if (globals.Flash.burst_func[channel]) {
				new_int_value=0;
			} else {
				new_int_value=1;
			}
		} else if (	(new_int_value<1 && !globals.Flash.burst_func[channel])
		                || (new_int_value<0 && globals.Flash.burst_func[channel])) {
			new_int_value=globals.Constraints.err_max_burst_count[channel];
		}
	}

	else if ( ((Submenu_Numeric_Parameter-channel) == Show_route_primary) ||
	                ((Submenu_Numeric_Parameter-channel) == Show_route_secondary) ) {
		g_usleep (2e5);

		reset_encoder=YES;	/* to avoid extra unwanted increments */
		new_int_value=(int) (Submenu_Value);

		if (encoder_change>0) {
			++new_int_value;
		} else {
			--new_int_value;
		}

		if (new_int_value>globals.Flash.routing_max_pins[channel]) {
			new_int_value=1;
		}

		if (new_int_value<1) {
			new_int_value=globals.Flash.routing_max_pins[channel];
		}
	}

	else {	/* deal with normal floating point parameters */

		/* if the value is zero, substitute small value */
		if (abs_Submenu_Value<zero_equiv_timing
		                &&
		                (	((Submenu_Numeric_Parameter-channel)==Show_delay)
		                        ||	((Submenu_Numeric_Parameter-channel)==Show_pw)
		                        ||	((Submenu_Numeric_Parameter-channel)==Show_Burst_Time) )
		   ) {
			abs_Submenu_Value=zero_equiv_timing;
		}

		/* reverse direction for negative values if they are supposed
		   to smoothly transition through zero */
		if ( (Submenu_Value < 0.0)
		                &&    (((Submenu_Numeric_Parameter-channel)==Show_delay)
		                       ||	((Submenu_Numeric_Parameter-channel)==Show_pw)) ) {
			encoder_change = -encoder_change;
		}

		else if ((channel<max_channels) && abs_Submenu_Value<globals.Flash.ampl_zero_equiv[channel] && (Submenu_Numeric_Parameter-channel)==Show_amplitude) {
			abs_Submenu_Value=globals.Flash.ampl_zero_equiv[channel];
			if (globals.Flash.max_ampl[channel]<globals.Flash.ampl_zero_equiv[channel]) {
				Submenu_Value=-abs_Submenu_Value;
			}
		}

		else if ((channel<max_channels) && abs_Submenu_Value<globals.Flash.os_zero_equiv[channel] && (Submenu_Numeric_Parameter-channel)==Show_offset) {
			abs_Submenu_Value=globals.Flash.os_zero_equiv[channel];
			if (globals.Flash.max_offset[channel]<globals.Flash.os_zero_equiv[channel]) {
				Submenu_Value=-abs_Submenu_Value;
			}
		}

		gchar *num_string = NULL;	/* submenu_value in string form */

		/* get a string version of the floating value to be modified */
		Float_To_Text(3,abs_Submenu_Value,&num_string);

		/* isolate the exponent and non-exponent parts */
		gchar *expon = g_strdup (num_string+5);

		num_string[5]=0;

		/* remove the decimal */
		strcpy(num_string+1,num_string+2);
		num_string[4]=0;

		/* convert the non-exponent significant digits to an integer */
		if (Submenu_extra_fine==NO) {
			num_string[3]='0';	/* go in steps of 10 */

			/* now select encoder step size */
			if (num_string[0]=='1') {
				increment_size=10;
			} else if (num_string[0]<'5') {
				/* now make sure that we go in steps of 20 - odd numbers can arise after switching out */
				/* of the extra fine mode */
				if (num_string[2]=='1' || num_string[2]=='3' || num_string[2]=='5' || num_string[2]=='7' || num_string[2]=='9' ) {
					num_string[2]-=1;
				}
				increment_size=20;
			} else {
				/* now make sure that we go in steps of 50 */
				if (num_string[2]<'5') {
					num_string[2]='0';
				} else {
					num_string[2]='5';
				}
				increment_size=50;
			}

			equivalent_integer=atoi(num_string);

			/* new number is ... */
			equivalent_integer+=increment_size*encoder_change;
		} else {
			equivalent_integer=atoi(num_string);
			equivalent_integer+=encoder_change;
		}

		g_free (num_string);

		/* don't let it change too much */
		if (equivalent_integer<1000) {
			equivalent_integer=995;
		}
		if (equivalent_integer>10000) {
			equivalent_integer=10100;
		}

		/* get first digit of new number */
		gchar* int_string = g_strdup_printf ("%d", equivalent_integer);
		gchar* new_string = g_strdup_printf (" %c.%s%s", int_string[0], int_string+1, expon);
		g_free (expon);
		g_free (int_string);

		/* put in sign if required */
		if (Submenu_Value<0) {
			new_string[0]='-';
		}

		// "moves" fractional digits to rear, to make room for the decimal point

		new_value=atof(new_string);

		if (equivalent_integer>9999) {
			new_value*=10;
		}
		if (equivalent_integer<1000) {
			new_value/=10;
		}

		g_free (new_string);
	}

	/* update display - correct later if required */
	Display_Number_on_LCD(YES,1,2,"",Submenu_Numeric_Parameter,4,LCD_col_width);

	switch ((Submenu_Numeric_Parameter-channel)) {
	case Show_frequency:
		if (globals.Flash.min_freq[channel]==globals.Flash.max_freq[channel]) {
			return;
		}
		if (error_num=Set_frequency(0,0,0,channel,new_value)) {
			Submenu_Value=new_value;
		}
		break;

	case Show_delay:
		if (globals.Flash.min_delay[channel]==globals.Flash.max_delay[channel]) {
			return;
		}

		/* If the new value is less than the zero_equiv_value, but
		   the original was not, set the new value to the smallest
		   allowed number with the same polarity (zero, basically) */
		if (   (fabs(new_value) < zero_equiv_timing)
		                && (abs_Submenu_Value > zero_equiv_timing)) {
			if (Submenu_Value<0.0) {
				new_value=-smallest_allowed_number;
			} else {
				new_value=smallest_allowed_number;
			}
		}

		/* If the new value is less than the zero_equiv_value, and
		   so was the original, flip the polarity (i.e., cross zero) */
		if (   (fabs(new_value) < zero_equiv_timing)
		                && (abs_Submenu_Value = zero_equiv_timing)) {
			if (Submenu_Value<0.0) {
				new_value=zero_equiv_timing;
			} else {
				new_value=-zero_equiv_timing;
			}
		}

		if (error_num=Set_Delay(0,0,0,channel,new_value)) {
			Submenu_Value=new_value;
		}
		break;

	case Show_pw:
		if (globals.Flash.min_pw[channel]==globals.Flash.max_pw[channel]) {
			return;
		}

		/* If the new value is less than the zero_equiv_value, but
		   the original was not, set the new value to the smallest
		   allowed number with the same polarity (zero, basically) */
		if (   (fabs(new_value) < zero_equiv_timing)
		                && (abs_Submenu_Value > zero_equiv_timing)) {
			if (Submenu_Value<0.0) {
				new_value=-smallest_allowed_number;
			} else {
				new_value=smallest_allowed_number;
			}
		}

		/* If the new value is less than the zero_equiv_value, and
		   so was the original, flip the polarity (i.e., cross zero) */
		if (   (fabs(new_value) < zero_equiv_timing)
		                && (abs_Submenu_Value = zero_equiv_timing)) {
			if (Submenu_Value<0.0) {
				new_value=zero_equiv_timing;
			} else {
				new_value=-zero_equiv_timing;
			}
		}

		if (error_num=Set_Pw(0,0,0,channel,new_value,0)) {
			Submenu_Value=new_value;
		}
		break;

	case Show_Burst_Time:
		if (error_num=Set_Burst_Time(0,0,0,channel,new_value)) {
			Submenu_Value=new_value;
		}
		break;

	case Show_rise_time:
		if (error_num=Set_rise_time(0,0,0,channel,new_value)) {
			Submenu_Value=new_value;
		}
		break;

	case Show_slew:
		if (error_num=Set_slew(0,0,0,channel,new_value)) {
			Submenu_Value=new_value;
		}
		break;

	case Show_load_type:
		if (error_num=Set_Load(channel,new_value)) {
			Submenu_Value=new_value;
		}
		break;

	case Show_soft_current_limit:
		if (error_num=Set_current_limit(0,channel,new_value)) {
			Submenu_Value=new_value;
		}
		break;

	case Show_amplitude:
		if (globals.Flash.min_ampl[channel]==globals.Flash.max_ampl[channel]) {
			return;
		}

		if (fabs(new_value) < globals.Flash.ampl_zero_equiv[channel]) {
			if (Submenu_Value<0.0) {
				new_value=-smallest_allowed_number;
			} else {
				new_value=smallest_allowed_number;
			}
		}

		if (number_of_fixed_ampl_points(channel)>0) { /* not used for fixed point amplitudes */
			return;
		}

		/* For units with large amplitude step sizes (AVRQ-2-B-PN-EVE) */
		if (globals.Flash.ampl_step_size[channel] > 0.0) {
			if (new_value < globals.ChannelState[channel].amplitude) {
				new_value = globals.ChannelState[channel].amplitude - globals.Flash.ampl_step_size[channel];
			} else {
				new_value = globals.ChannelState[channel].amplitude + globals.Flash.ampl_step_size[channel];
			}

		}

		if (error_num=Set_Amplitude(0,0,0,0,0,0,0,channel,new_value,0)) {
			Submenu_Value=new_value;
		}
		break;

	case Show_offset:
		if (globals.Flash.min_offset[channel]==globals.Flash.max_offset[channel]) {
			return;
		}
		if (fabs(new_value) < globals.Flash.os_zero_equiv[channel]) {
			if (Submenu_Value<0.0) {
				new_value=-smallest_allowed_number;
			} else {
				new_value=smallest_allowed_number;
			}
		}

		if (error_num=Set_Offset(0,0,0,0,channel,new_value)) {
			Submenu_Value=new_value;
		}
		break;

	case Show_duty_cycle:
		if (error_num=Set_Pw(0,0,0,channel,new_value/(100*globals.ChannelState[channel].frequency),0)) {
			Submenu_Value=new_value;
		}
		break;

	case Show_gpib_address:
		GPIB_change_address(new_int_value);
		error_num=OK;
		break;

	case Show_Burst_Count:
		if (error_num=Set_Burst_Count(channel,new_int_value,globals.ChannelState[channel].burst_time)) {
			Submenu_Value=new_value;
		}
		break;

	case Show_route_primary:
		if (error_num=Set_Route(channel,ROUTE_PRIMARY,new_int_value)) {
			Submenu_Value=new_value;
		}
		break;

	case Show_route_secondary:
		if (error_num=Set_Route(channel,ROUTE_SECONDARY,new_int_value)) {
			Submenu_Value=new_value;
		}
		break;

	}

	Main_update_shift_registers();

	Display_Number_on_LCD(YES,1,2,"",Submenu_Numeric_Parameter,4,LCD_col_width);

	queue_error_and_display_on_LCD(error_num);

	last_encoder_adjust_error=error_num;

	if (reset_encoder) {
		Menu_Clear_Buttons();
	}

	return;
}


static void Nonstd_menu_default_rs232(void)
{
	Menu_Clear_Buttons();

	LCD_clear(); /*0123456789012345678901234567890123456789*/
	LCD_write(0,0,"The RS232 settings are now: 1200 baud,");
	LCD_write(1,0,"auto data bits / parity, 1 stop bit,");
	LCD_write(2,0,"hardware handshaking on, echo on.");
	LCD_write(3,0,Press_Change_Message);

	IO_Setup_RS232(1200, 1);

	Menu_Clear_Buttons();

	globals.MenuStatus.Nonstd_Display=YES;
}


static void Nonstd_menu_model_info(void)
{
        gchar *message = g_strdup_printf ("Avtech Electrosystems Ltd., since 1975. Model %s, S/N %s, FW v%s.",
                globals.Flash.model_num,
                globals.Flash.serial_num,
		globals.HWDetect.firmware);
        LCD_display_extended_message (message, TRUE, FALSE);
        g_free (message);

	globals.MenuStatus.Nonstd_Display=YES;
}


void Menu_Clear_Buttons(void)
{
	int dummy1,dummy2,dummy3;

	/* enable interrupt lines */
	Read_Keypad(&dummy1,&dummy2,&dummy3);
}


static void Read_Keypad(int *button_port_val, int *upper_encoder_val, int *lower_encoder_val)
{
#define Overload_Input 64		/* mask for main overload input */
#define Over_Temp 0x10			/* over-temperature */
#define Over_Volt 0x20			/* over-voltage */
#define Over_Other 0x40			/* over-other */

	int new_button_state;

	/* read the button data */
	new_button_state = I2C_Read(PCF8574A+Button_Press_Port);

	/* invert bit 6 (of 0-7) = overload */
	if ( (new_button_state & 0x40) == 0x40) {
		/* if high, set low */
		new_button_state = new_button_state & (0xff - 0x40);
	} else {
		/* if low, set high */
		new_button_state = new_button_state | 0x40;
	}

	/* ignore bit 7 (of 0-7) */
	new_button_state = new_button_state & 0x7f;

	/* a button_port_val bit goes low if:
			The corresponding last_button_state was low (inactive)
			and
			The corresponding new_button_state is high (pressed) */

	*button_port_val =  ~ ((~last_button_state) & (new_button_state));

	last_button_state = new_button_state;

	/* read the encoder data */
	*upper_encoder_val = I2C_Read(PCF8574A+Upper_Encoder_Port);

	/* lowering the button clear line disables encoder counting */
	I2C_Write(PCF8574A+Button_Press_Port,127);
	*lower_encoder_val = I2C_Read(PCF8574A+Lower_Encoder_Port);

	/* reenable encoder */
	I2C_Write(PCF8574A+Button_Press_Port,255);

	/* reset encoder-monitoring by presetting counters to mid range */
	I2C_Write(PCF8574A+Upper_Encoder_Port,127);
	I2C_Write(PCF8574A+Upper_Encoder_Port,255);


	/* alarm condition */
	/* valid for both local and remote modes */
	if ( 		!(*upper_encoder_val & Over_Temp)
	                || !(*upper_encoder_val & Over_Volt)
	                || !(*upper_encoder_val & Over_Other)
	                || !(*button_port_val & Overload_Input)	) {

		/* disable all outputs immediately */
		int outputs_turned_off = 0;
		if (globals.Flash.on_off_used) {
			int chan;
			for (chan=0; chan<(globals.Flash.ChanKey_output_state?globals.Flash.channels:1); ++chan) {
				if (globals.ChannelState[chan].output_state == output_on) {
					++outputs_turned_off;
					Set_Output_State(chan,output_off);
				}
			}
		}

		/* Report the problem if outputs had to be turned off. */
		if ((outputs_turned_off > 0) || globals.Flash.warn_even_if_output_off) {
			/* flag the problem */
			if (!(*upper_encoder_val & Over_Temp)) {
				queue_and_broadcast_sensor_alarm(Overtemp_Detected);
			} else if (!(*upper_encoder_val & Over_Volt)) {
				queue_and_broadcast_sensor_alarm(Overvolt_Detected);
			} else if (!(*upper_encoder_val & Over_Other)) {
				queue_and_broadcast_sensor_alarm(Device_Specific_Aux_Error_Detected);
			} else if (!(*button_port_val & Overload_Input)) {
				queue_and_broadcast_sensor_alarm(Overload_Detected);
			}
		}
	}
}


void Menu_Check_Buttons(void)
{
	int button_port_val;
	int upper_encoder_val;
	int lower_encoder_val;
	int encoder_change;

	// abort if not running on the target board with the I2C bus
	if (!globals.HWDetect.has_i2c) {
		return;
	}

	/* get keypad state */
	Read_Keypad(&button_port_val,&upper_encoder_val,&lower_encoder_val);

	encoder_change=lower_encoder_val;

	/* handle negative changes */
	if (encoder_change & 0x80) {
		encoder_change = encoder_change - 0x100;
	}

	update_remote_mode();

	if (!(button_port_val & Change_Button)) {		/* ----- CHANGE BUTTON --------- */
		if (VXI_OR_GPIB_LOCK_ACTIVE) {
			// front panel is locked out
			Show_Main_Menu();
		} else {
			if ((globals.MenuStatus.Type_Of_Menu==Main_Menu_On && globals.MenuStatus.Error_Screen==YES) || globals.MenuStatus.Nonstd_Display==YES) {
				Show_Main_Menu();
			} else if (globals.MenuStatus.Type_Of_Menu==Submenu_On && globals.MenuStatus.Error_Screen==YES) {
				Submenu_Display(NO);
			} else if (globals.MenuStatus.Type_Of_Menu==Main_Menu_On && globals.MenuStatus.Error_Screen==NO) {
				Submenu_Display(NO);
			} else if (globals.MenuStatus.Type_Of_Menu==Submenu_On && globals.MenuStatus.Error_Screen==NO) {
				int error_num;
				if (error_num=Submenu_Implement_Changes()) {
					queue_error_and_display_on_LCD(error_num);
				}
			}
		}
	} else if (!(button_port_val & Move_Button)) {				/* ----- MOVE BUTTON ----------- */
		/* MOVE button hit, move pointer */
		if (globals.MenuStatus.Type_Of_Menu==Main_Menu_On && globals.MenuStatus.Nonstd_Display==NO && globals.MenuStatus.Error_Screen==NO) {
			Menu_Move_Pointer(1);
		} else if (globals.MenuStatus.Type_Of_Menu==Submenu_On && globals.MenuStatus.Nonstd_Display==NO && globals.MenuStatus.Error_Screen==NO) {
			Submenu_Move_Pointer();
		}
	} else if (!(button_port_val & Mult10_Button)) {		/* ----- X10 BUTTON ------------ */
		if (globals.MenuStatus.Type_Of_Menu==Submenu_On && !VXI_OR_GPIB_LOCK_ACTIVE) {
			if (globals.MenuStatus.Error_Screen==YES) {
				Submenu_Display(NO);
			}
			queue_error_and_display_on_LCD(Submenu_Mult_Value(10.0));
		}
	} else if (!(button_port_val & Div10_Button)) {		/* ----- /10 BUTTON ------------ */
		if (globals.MenuStatus.Type_Of_Menu==Submenu_On && !VXI_OR_GPIB_LOCK_ACTIVE) {
			if (globals.MenuStatus.Error_Screen==YES) {
				Submenu_Display(NO);
			}
			queue_error_and_display_on_LCD(Submenu_Mult_Value(0.1));
		}
	} else if (!(button_port_val & Plus_Minus_Button)) {	/* ----- +/- BUTTON ------------ */
		if (globals.MenuStatus.Type_Of_Menu==Submenu_On && !VXI_OR_GPIB_LOCK_ACTIVE) {
			if (globals.MenuStatus.Error_Screen==YES) {
				Submenu_Display(NO);
			}
			queue_error_and_display_on_LCD(Submenu_Mult_Value(-1.0));
		}
	} else if (!(button_port_val & Extra_Fine_Button)) {	/* ----- EXTRA FINE BUTTON ----- */
		if (globals.MenuStatus.Type_Of_Menu==Submenu_On && globals.MenuStatus.Nonstd_Display==NO && globals.MenuStatus.Error_Screen==NO && !VXI_OR_GPIB_LOCK_ACTIVE) {
			if (Submenu_extra_fine==YES) {
				g_usleep (250e3);
				Submenu_extra_fine=NO;
				LCD_write(2,2,"                   ");
			} else {
				g_usleep (250e3);
				Submenu_extra_fine=YES;
				LCD_write(2,2,"(extra fine adjust)");
			}
		}
	}
	/* if none of the buttons are pressed, it must be the encoder */
	else if (encoder_change) {								/* ----- ENCODER --------------- */
		/* ignore if the overload error screen is displayed */
		if (!(globals.MenuStatus.Error_Screen==YES && globals.MenuStatus.Type_Of_Menu==Main_Menu_On)) {
			if (globals.MenuStatus.Error_Screen==YES && globals.MenuStatus.Type_Of_Menu==Submenu_On) {
				Submenu_Display(NO);
			}
			Submenu_Service_Encoder(encoder_change);
		}
	}
}


static int Submenu_Implement_Changes(void)
{
	int error_num;
	int call_new_submenu;
	int channel;

	call_new_submenu=NO;

	/* this routine changes the pulse generator parameters, as chosen by the submenu settings */

	if (Submenu_max_entry==0) {
		Show_Main_Menu();
		return OK;
	}

	/* Cases that involve third-level and greater menu must indicate what menu to return to, e.g */
	/* globals.MenuStatus.Selected_Submenu=Submenu1_setup after finishing the default RS232 case. */

	channel=Submenu_Structure[Submenu_Selected_Item]%100;

	switch (Submenu_Structure[Submenu_Selected_Item]-channel) {
	case mode_freq_int:
		if (globals.ChannelState[channel].trigger_source!=source_internal) {
			if (error_num=Set_Trig_Source(channel,source_internal)) {
				return error_num;
			}
		}
		break;
	case mode_freq_ext:
		if (error_num=Set_Trig_Source(channel,source_external)) {
			return error_num;
		}
		break;
        case mode_freq_ext2:
		if (error_num=Set_Trig_Source(channel,source_external2)) {
			return error_num;
		}
                break;
	case mode_freq_man:
		if (error_num=Set_Trig_Source(channel,source_manual)) {
			return error_num;
		}
		break;
	case mode_freq_hold:
		if (error_num=Set_Trig_Source(channel,source_hold)) {
			return error_num;
		}
		break;
	case mode_func_sin:
		if (error_num=Set_Func(channel,sin_mode_on)) {
			return error_num;
		}
		break;
	case mode_func_tri:
		if (error_num=Set_Func(channel,tri_mode_on)) {
			return error_num;
		}
		break;
	case mode_func_squ:
		if (error_num=Set_Func(channel,squ_mode_on)) {
			return error_num;
		}
		break;
	case mode_func_pulse:
		if (error_num=Set_Func(channel,pulse_mode_on)) {
			return error_num;
		}
		break;
	case mode_func_amp:
		if (error_num=Set_Func(channel,amp_mode_on)) {
			return error_num;
		}
		break;
	case mode_delay_norm:
		if (error_num=Set_Double(channel,double_off)) {
			return error_num;
		}
		break;
	case mode_delay_dbl:
		if (error_num=Set_Double(channel,double_on)) {
			return error_num;
		}
		break;
	case mode_pw_norm:
		globals.ChannelState[channel].hold_setting=hold_width;
		if ( (globals.ChannelState[channel].pw_ctrl_mode!=pw_normal) || (globals.ChannelState[channel].func_mode!=pulse_mode_on)) {
			if (error_num=Set_Func(channel,pulse_mode_on)) {
				return error_num;
			}
			if (error_num=Set_Pwmode(channel,pw_normal)) {
				return error_num;
			}
			if (Set_Pw(0,0,0,channel,globals.ChannelState[channel].pw,0)!=OK) {
				Set_Pw(0,0,0,channel,globals.Flash.min_pw[channel],0);
			}
		}
		break;
	case mode_pw_duty:
		globals.ChannelState[channel].hold_setting=hold_duty;
		if ( (globals.ChannelState[channel].pw_ctrl_mode!=pw_normal) || (globals.ChannelState[channel].func_mode!=pulse_mode_on)) {
			if (error_num=Set_Func(channel,pulse_mode_on)) {
				return error_num;
			}
			if (error_num=Set_Pwmode(channel,pw_normal)) {
				return error_num;
			}
			if (Set_Pw(0,0,0,channel,globals.ChannelState[channel].pw,0)!=OK) {
				Set_Pw(0,0,0,channel,globals.Flash.min_pw[channel],0);
			}
		}
		break;
	case mode_pw_inout:
		if (error_num=Set_Func(channel,pulse_mode_on)) {
			return error_num;
		}
		if (error_num=Set_Pwmode(channel,pw_in_out)) {
			return error_num;
		}
		break;
        case mode_pw_ew:
                if (error_num=Set_Func(channel,pulse_mode_on)) {
                        return error_num;
                }
                if (error_num=Set_Pwmode(channel,pw_ew_ext)) {
                        return error_num;
                }
                break;
	case mode_pw_dc:
		if (error_num=Set_Func(channel,dc_mode_on)) {
			return error_num;
		}
		break;
	case mode_output_on:
		if (error_num=Set_Output_State(channel,output_on)) {
			return error_num;
		}
		break;
	case mode_output_off:
		if (error_num=Set_Output_State(channel,output_off)) {
			return error_num;
		}
		break;
	case mode_go_to_local:
		GPIB_go_to_local();
		break;
	case mode_inv_no:
		if (error_num=Set_Inverted(channel,NO)) {
			return error_num;
		}
		break;
	case mode_inv_yes:
		if (error_num=Set_Inverted(channel,YES)) {
			return error_num;
		}
		break;
	case mode_gate_losync:
		Set_Gate_Sync(channel,gate_sync);
		Set_Gate_Level(channel,gate_low);
		break;
	case mode_gate_hisync:
		Set_Gate_Sync(channel,gate_sync);
		Set_Gate_Level(channel,gate_high);
		break;
	case mode_gate_loasync:
		Set_Gate_Sync(channel,gate_async);
		Set_Gate_Level(channel,gate_low);
		break;
	case mode_gate_hiasync:
		Set_Gate_Sync(channel,gate_async);
		Set_Gate_Level(channel,gate_high);
		break;
	case mode_gpib_address:
		globals.MenuStatus.Selected_Submenu=Submenu2_gpib_address;
		call_new_submenu=YES;
		Submenu_Display(NO);
		/* return cursor to setup submenu afterwards */
		globals.MenuStatus.Selected_Submenu=Submenu1_setup;
		break;
	case mode_zout_max:
		if (error_num=Set_zout(channel,globals.Flash.zout_max[channel],1)) {
			return error_num;
		}
		break;
	case mode_zout_min:
		if (error_num=Set_zout(channel,globals.Flash.zout_min[channel],1)) {
			return error_num;
		}
		break;
	case mode_logic_ttl:
		if (error_num=Set_Logic_Level(channel,logic_ttl)) {
			return error_num;
		}
		break;
	case mode_logic_ecl:
		if (error_num=Set_Logic_Level(channel,logic_ecl)) {
			return error_num;
		}
		break;

	case mode_rise_time_min:
		if (error_num=Set_rise_time(0,0,0,channel,globals.Flash.min_rise_time[channel])) {
			return error_num;
		}
		break;

        case mode_rise_time_max:
                if (error_num=Set_rise_time(0,0,0,channel,globals.Flash.max_rise_time[channel])) {
                        return error_num;
                }
                break;

	// hard-coded count of 10 - not ideal!
	case (mode_ampl_fixed_point0):
		if (error_num=Set_Amplitude(0,0,0,0,0,0,0,channel,globals.Flash.fixed_ampl_points[channel][0],0)) {
			return error_num;
		}
		break;
        case (mode_ampl_fixed_point1):
                if (error_num=Set_Amplitude(0,0,0,0,0,0,0,channel,globals.Flash.fixed_ampl_points[channel][1],0)) {
                        return error_num;
                }
                break;
        case (mode_ampl_fixed_point2):
                if (error_num=Set_Amplitude(0,0,0,0,0,0,0,channel,globals.Flash.fixed_ampl_points[channel][2],0)) {
                        return error_num;
                }
                break;
        case (mode_ampl_fixed_point3):
                if (error_num=Set_Amplitude(0,0,0,0,0,0,0,channel,globals.Flash.fixed_ampl_points[channel][3],0)) {
                        return error_num;
                }
                break;
        case (mode_ampl_fixed_point4):
                if (error_num=Set_Amplitude(0,0,0,0,0,0,0,channel,globals.Flash.fixed_ampl_points[channel][4],0)) {
                        return error_num;
                }
                break;
        case (mode_ampl_fixed_point5):
                if (error_num=Set_Amplitude(0,0,0,0,0,0,0,channel,globals.Flash.fixed_ampl_points[channel][5],0)) {
                        return error_num;
                }
                break;
        case (mode_ampl_fixed_point6):
                if (error_num=Set_Amplitude(0,0,0,0,0,0,0,channel,globals.Flash.fixed_ampl_points[channel][6],0)) {
                        return error_num;
                }
                break;
        case (mode_ampl_fixed_point7):
                if (error_num=Set_Amplitude(0,0,0,0,0,0,0,channel,globals.Flash.fixed_ampl_points[channel][7],0)) {
                        return error_num;
                }
                break;
        case (mode_ampl_fixed_point8):
                if (error_num=Set_Amplitude(0,0,0,0,0,0,0,channel,globals.Flash.fixed_ampl_points[channel][8],0)) {
                        return error_num;
                }
                break;
        case (mode_ampl_fixed_point9):
                if (error_num=Set_Amplitude(0,0,0,0,0,0,0,channel,globals.Flash.fixed_ampl_points[channel][9],0)) {
                        return error_num;
                }
                break;


	case mode_amp_normal:
		if (error_num=Set_EA(channel,amp_mode_normal)) {
			return error_num;
		}
		break;
	case mode_amp_ea:
		if (error_num=Set_EA(channel,amp_mode_ea)) {
			return error_num;
		}
		break;
	case mode_amp_amplify:
		if (error_num=Set_EA(channel,amp_mode_amplify)) {
			return error_num;
		}
		break;
	case mode_os_normal:
		if (error_num=Set_EO(channel,os_mode_normal)) {
			return error_num;
		}
		break;
	case mode_os_eo:
		if (error_num=Set_EO(channel,os_mode_eo)) {
			return error_num;
		}
		break;

	case mode_route1:
		if (error_num=Set_Route(channel,ROUTE_PRIMARY,1)) {
                        return error_num;
                }
		break;
        case mode_route2:
                if (error_num=Set_Route(channel,ROUTE_PRIMARY,2)) {
                        return error_num;
                }
                break;

	case mode_load:
		globals.MenuStatus.Selected_Submenu=Submenu2_load;
		call_new_submenu=YES;
		Submenu_Display(NO);
		break;
	case mode_load_0:
		Set_Rcl(0);
		globals.MenuStatus.Selected_Submenu=Submenu1_memory;
		break;
	case mode_load_1:
		Set_Rcl(1);
		globals.MenuStatus.Selected_Submenu=Submenu1_memory;
		break;
	case mode_load_2:
		Set_Rcl(2);
		globals.MenuStatus.Selected_Submenu=Submenu1_memory;
		break;
	case mode_load_3:
		Set_Rcl(3);
		globals.MenuStatus.Selected_Submenu=Submenu1_memory;
		break;

        case mode_load_exit:
        case mode_save_exit:
                globals.MenuStatus.Selected_Submenu=Submenu1_memory;
                break;

	case mode_save:
		globals.MenuStatus.Selected_Submenu=Submenu2_save;
		call_new_submenu=YES;
		Submenu_Display(NO);
		break;
	case mode_save_0:
		Set_Sav(0);
		globals.MenuStatus.Selected_Submenu=Submenu1_memory;
		break;
	case mode_save_1:
		Set_Sav(1);
		globals.MenuStatus.Selected_Submenu=Submenu1_memory;
		break;
	case mode_save_2:
		Set_Sav(2);
		globals.MenuStatus.Selected_Submenu=Submenu1_memory;
		break;
	case mode_save_3:
		Set_Sav(3);
		globals.MenuStatus.Selected_Submenu=Submenu1_memory;
		break;
	case mode_rs232_settings:
		globals.MenuStatus.Selected_Submenu=Submenu2_rs232;
		call_new_submenu=YES;
		Submenu_Display(NO);
		break;
	case mode_default_rs232:
		call_new_submenu=YES;
		Nonstd_menu_default_rs232();
		break;
	case mode_model_info:
		call_new_submenu=YES;
		Nonstd_menu_model_info();
		break;
	case mode_network:
		call_new_submenu=YES;
		Nonstd_menu_network();
		break;
	case mode_password:
		change_password (NULL, "default");
		break;
	case mode_selfcal:
		if (error_num=self_cal()) {
			return error_num;
		}
		break;
	case mode_change_rs232:
		globals.MenuStatus.Selected_Submenu=Submenu2_rs232_baud;
		call_new_submenu=YES;
		Submenu_Display(NO);
		break;
	case mode_exit_rs232:
		globals.MenuStatus.Selected_Submenu=Submenu1_setup;
		break;
	case mode_1200:
		IO_Setup_RS232(1200, globals.Flash.hardhand);
		globals.MenuStatus.Selected_Submenu=Submenu2_rs232_hardhand;
		call_new_submenu=YES;
		Submenu_Display(NO);
		break;
	case mode_2400:
		IO_Setup_RS232(2400, globals.Flash.hardhand);
		globals.MenuStatus.Selected_Submenu=Submenu2_rs232_hardhand;
		call_new_submenu=YES;
		Submenu_Display(NO);
		break;
	case mode_4800:
		IO_Setup_RS232(4800, globals.Flash.hardhand);
		globals.MenuStatus.Selected_Submenu=Submenu2_rs232_hardhand;
		call_new_submenu=YES;
		Submenu_Display(NO);
		break;
	case mode_9600:
		IO_Setup_RS232(9600, globals.Flash.hardhand);
		globals.MenuStatus.Selected_Submenu=Submenu2_rs232_hardhand;
		call_new_submenu=YES;
		Submenu_Display(NO);
		break;
	case mode_19200:
		IO_Setup_RS232(19200, globals.Flash.hardhand);
		globals.MenuStatus.Selected_Submenu=Submenu2_rs232_hardhand;
		call_new_submenu=YES;
		Submenu_Display(NO);
		break;
	case mode_38400:
		IO_Setup_RS232(38400, globals.Flash.hardhand);
		globals.MenuStatus.Selected_Submenu=Submenu2_rs232_hardhand;
		call_new_submenu=YES;
		Submenu_Display(NO);
		break;
	case mode_57600:
		IO_Setup_RS232(57600, globals.Flash.hardhand);
		globals.MenuStatus.Selected_Submenu=Submenu2_rs232_hardhand;
		call_new_submenu=YES;
		Submenu_Display(NO);
		break;
	case mode_115200:
		IO_Setup_RS232(115200, globals.Flash.hardhand);
		globals.MenuStatus.Selected_Submenu=Submenu2_rs232_hardhand;
		call_new_submenu=YES;
		Submenu_Display(NO);
		break;

	case mode_hand_hard:
		IO_Setup_RS232(globals.Flash.baud, 1);
		globals.MenuStatus.Selected_Submenu=Submenu1_setup;
		break;
	case mode_hand_off:
		IO_Setup_RS232(globals.Flash.baud, 0);
		globals.MenuStatus.Selected_Submenu=Submenu1_setup;
		break;
	}

	Main_update_shift_registers();	 /* update values in pulse generator circuit */

	if (call_new_submenu==NO) {
		Show_Main_Menu();
	}

	/* re-run error_check to update min/max values based on actual settings, not proposed settings */
	Error_check(globals.ChannelState);

	return OK;
}


static void Nonstd_menu_network(void)
{
	LCD_clear();

	nicinfo info;
	if (nicutils_infofordefaultroute(&info)) {
		gchar *response = g_strdup_printf ("MAC address: %s", info.mac);
		LCD_write(0,0,response);
		g_free (response);

		response = g_strdup_printf ("IP address: %s", info.ip);
		LCD_write(1,0,response);
		g_free (response);

		LCD_write(3,0,"Press CHANGE to continue.");
	} else {
		LCD_display_extended_message("No network found.", TRUE, FALSE);
	}

	globals.MenuStatus.Nonstd_Display=YES;
}