
###################################################################
# This file is part of tk75, a control program for the
# ICOM IC-R75 receiver.
# 
#    Copyright (C) 2001, 2002, Bob Parnass
#					AJ9S
# 
# tk75 is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published
# by the Free Software Foundation; either version 2 of the License,
# or (at your option) any later version.
# 
# tk75 is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with tk75; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
# 02111-1307  USA
###################################################################


proc MakeGui { } \
{
	global Cht
	global Chvector
	global GlobalParam
	global HistVector
	global RMode

	# Set custom font and colors.

	SetAppearance

	set msg [OpenDevice]
	
	if { $msg != ""} \
		{
		tk_dialog .opnerror "tk75 error" \
			$msg error 0 OK
		exit
		}


	# Read current mode from radio.
	set m [ReadMode]
	set m [string range $m 0 1]
	set m $RMode($m)
	set GlobalParam(Mode) $m

	
	###############################################################
	# Menu bar along the top edge.
	###############################################################
	set fr_menubar [MakeMenuBar .mb]
	set mf [frame .mainframe]
	frame $mf.chtable
	set Cht $mf.chtable
	
	###############################################################
	# Freq Display and tuning buttons.
	###############################################################
	set fr_freqdisplay [FreqDisplay .freqdisplay]
	
	set fr_sliderule [MakeSlideRule .dial]
	set fr_buttons [frame .fbuttons]
	
	set fr_vet [frame $fr_buttons.vertbar -borderwidth 6 \
		-relief groove]
	
	set fr_slew [MakeSlewFrame $fr_buttons.slew]
	balloonhelp_for $fr_slew \
		"Press once to start slew (autotune).\nPress again to stop."
	

	set fr_updown [MakeUpDownFrame $fr_buttons.updown]
	balloonhelp_for $fr_updown \
		"Click and release a button\nto change the frequency."

	pack $fr_slew -side top -fill x -expand y -padx 3
	pack $fr_updown -side top -fill x -expand y -padx 3
	
	###############################################################
	# Potentiometer (scale) controls
	###############################################################
	frame $mf.row2 -relief groove -borderwidth 3
	set row2 $mf.row2
	
	set fr_pots [ MakePots $row2.potentiometers]
	set fr_kp [MakeKeyPad $row2.kp ]
	
	pack $fr_pots -side left -fill x -expand y -padx 3 -pady 3
	pack $fr_kp -side left -fill x -expand n -padx 1 -pady 1
	
	###############################################################
	# Secondary controls window
	###############################################################
	toplevel .controls
	set ctls .controls.ctls
	frame $ctls -relief groove
	
	MakeModeSwitch $ctls.mode
	MakePushButtons $ctls.pushb
	MakeDSPFrame $ctls.dsp
	MakeFrontEnd $ctls.frontend
	
	toplevel .mc
	set Cht .mc
	
	# Prevent user from closing the channel list window unless
	# he elects to exit the entire program.
	
	wm protocol $Cht WM_DELETE_WINDOW {ExitApplication; exit}
	wm title $Cht "tk75 Memory Channels"
	wm iconify $Cht
	
	
	set $ctls.scan [ MakeMemScanFrame $ctls.scan]
	set $ctls.search [ MakeSearchFrame $ctls.search]
	
	
	set Chvector ""
	
	pack $fr_menubar -side top -fill x -pady 3
	pack $fr_freqdisplay -side top -fill x
	pack $fr_sliderule -side top -fill x -expand y
	pack $fr_buttons -side top -fill x -expand y
	
	
	pack $mf.row2 -side top -fill x -expand y -padx 3 -pady 3
	
	pack \
		$ctls.mode \
		$ctls.pushb \
		$ctls.dsp \
		$ctls.frontend \
		$ctls.scan \
		$ctls.search \
		-side left -anchor n -padx 3 -pady 3 -expand y -fill y
	
	
	pack $ctls -side top -fill both -expand true -padx 3 -pady 3
	pack .mainframe -side top -fill both -expand true
	
	# Zap the session history.
	set HistVector ""
	
	update idletasks
	
	###############################################################
	#  Ask the window manager to catch the delete window
	#  event.
	###############################################################
	wm protocol . WM_DELETE_WINDOW {ExitApplication; exit}
	
	# Prevent user from shrinking or expanding main window.
	wm minsize . [winfo width .] [winfo height .]
	wm maxsize . [winfo width .] [winfo height .]
	
	wm protocol .controls WM_DELETE_WINDOW {ExitApplication; exit}
	wm title .controls "tk75 Secondary Controls"
	
	# set x [winfo width $ctls.mode]
	# set x [expr $x + 14]
	
	# Prevent user from overshrinking or expanding controls window.
	wm minsize .controls [winfo width .controls] [winfo height .controls]
	wm maxsize .controls [winfo width .controls] [winfo height .controls]
	
	# Update the frequency display widget with the radio's frequency.
	
	UpdDisplay
	SetSlideRuleDial
	
	return
}


###################################################################
# Alter color and font appearance based on user preferences.
###################################################################
proc SetAppearance { } \
{
	global GlobalParam

	if {$GlobalParam(Font) != "" } \
		{
		# Designate a custom font for most widgets.
		option add *font $GlobalParam(Font)
		}

	if {$GlobalParam(BackGroundColor) != "" } \
		{
		# Designate a custom background color for most widgets.
		option add *background $GlobalParam(BackGroundColor)
		}

	if {$GlobalParam(ForeGroundColor) != "" } \
		{
		# Designate a custom foreground color for most widgets.
		option add *foreground $GlobalParam(ForeGroundColor)
		}

	if {$GlobalParam(TroughColor) != "" } \
		{
		# Designate a custom slider trough color
		# for most scale widgets.
		option add *troughColor $GlobalParam(TroughColor)
		}

	return
}



##########################################################
# Check if the configuration file exists.
# If it exits, return 1.
#
# Otherwise, prompt the user to select the
# serial port.
##########################################################

proc FirstTimeCheck { Rcfile } \
{
	global AboutMsg
	global GlobalParam
	global Libdir
	global tcl_platform

	if { [file readable $Rcfile] == 1 } \
		{
		return 0
		}

	tk_dialog .about "About tk75" \
		$AboutMsg info 0 OK

	# No readable config file found.
	# Treat this as the first time the user has run the program.

	# Create a new window with radio buttions and
	# an entry field so user can designate the proper
	# serial port.

	set msg "Please identify the serial port to which\n"
	set msg [append msg "your IC-R75 receiver is connected."]

	toplevel .serialport
	set sp .serialport

	label $sp.intro -text $msg

	frame $sp.rbframe
	set fr $sp.rbframe

	if { $tcl_platform(platform) == "windows" } \
		{
		# For Windows.
		radiobutton $fr.com1 -text COM1: -variable port \
			-value {COM1:}
		radiobutton $fr.com2 -text COM2: -variable port \
			-value {COM2:} 
		radiobutton $fr.com3 -text COM3: -variable port \
			-value {COM3:} 
		radiobutton $fr.com4 -text COM4: -variable port \
			-value {COM4:} 

		pack $fr.com1 $fr.com2 $fr.com3 $fr.com4 \
			-side top -padx 3 -pady 3 -anchor w

		} \
	else \
		{
		# For unix, mac, etc..
		radiobutton $fr.s0 -text /dev/ttyS0 -variable port \
			-value {/dev/ttyS0} 
		radiobutton $fr.s1 -text /dev/ttyS1 -variable port \
			-value {/dev/ttyS1} 
		radiobutton $fr.s2 -text /dev/ttyS2 -variable port \
			-value {/dev/ttyS2} 
		radiobutton $fr.s3 -text /dev/ttyS3 -variable port \
			-value {/dev/ttyS3} 
		radiobutton $fr.s4 -text /dev/ttyS4 -variable port \
			-value {/dev/ttyS4} 
		radiobutton $fr.s5 -text /dev/ttyS5 -variable port \
			-value {/dev/ttyS5} 

		pack \
			$fr.s0 $fr.s1 $fr.s2 \
			$fr.s3 $fr.s4 $fr.s5 \
			-side top -padx 3 -pady 3 -anchor w

		}

	radiobutton $fr.other -text "other (enter below)" \
		-variable port \
		-value other

	entry $fr.ent -width 30 -textvariable otherport

	pack $fr.other $fr.ent \
		-side top -padx 3 -pady 3 -anchor w

	button $sp.ok -text "OK" \
		-command \
			{ \
			global GlobalParam

			if {$port == "other"} \
				{
				set GlobalParam(Device) $otherport
				} \
			else \
				{
				set GlobalParam(Device) $port
				}
			}

	button $sp.exit -text "Exit" \
		-command { exit }

	pack $sp.intro -side top -padx 3 -pady 3
	pack $fr -side top -padx 3 -pady 3
	pack $sp.ok $sp.exit -side left -padx 3 -pady 3 -expand true



	bind $fr.ent <Key-Return> \
		{
		global GlobalParam
		set GlobalParam(Device) $otherport
		}

	wm title $sp "Select serial port"
	wm protocol $sp WM_DELETE_WINDOW {exit}

	set errorflag true

	while { $errorflag == "true" } \
		{
		tkwait variable GlobalParam(Device)

		if { $tcl_platform(platform) != "unix" } \
			{
			set errorflag false
			break
			}

		# The following tests do not work properly
		# in Windows. That is why we won't perform
		# the serial port tests when running Windows version.

		if { ([file readable $GlobalParam(Device)] != 1) \
			|| ([file writable $GlobalParam(Device)] != 1)
			|| ([file type $GlobalParam(Device)] != "characterSpecial") } \
			{
			# Device must be readable, writable,
			# and legit.

			bell
			tk_dialog .badport "Serial port problem" \
				"Serial port problem" error 0 OK
			} \
		else \
			{
			set errorflag false
			}
		}

	destroy $sp
	return 1
}

##########################################################
# ExitApplication
#
# This procedure can do any cleanup necessary before
# exiting the program.
#
# Disable computer control of the radio, then quit.
##########################################################
proc ExitApplication { } \
{
	global Lid
	global Lfilename

	SaveSetup
	SaveLabel
	DisableCControl

	if { [info exists Lfilename] } \
		{
		if { $Lfilename != "" } \
			{
			# Close log file.
			close $Lid
			}
		}
	exit
}


##########################################################
# NoExitApplication
#
# This procedure prevents the user from
# killing the window.
##########################################################
proc NoExitApplication { } \
{

	set response [tk_dialog .quitit "Exit?" \
		"Do not close this window." \
		warning 0 OK ]

	return
}
##########################################################
#
# Scroll_Set manages optional scrollbars.
#
# From "Practical Programming in Tcl and Tk,"
# second edition, by Brent B. Welch.
# Example 27-2
#
##########################################################

proc Scroll_Set {scrollbar geoCmd offset size} {
	if {$offset != 0.0 || $size != 1.0} {
		eval $geoCmd;# Make sure it is visible
		$scrollbar set $offset $size
	} else {
		set manager [lindex $geoCmd 0]
		$manager forget $scrollbar								;# hide it
	}
}


##########################################################
#
# Listbox with optional scrollbars.
#
#
# Inputs: basename of configuration file
#
# From "Practical Programming in Tcl and Tk,"
# second edition, by Brent B. Welch.
# Example 27-3
#
##########################################################

proc Scrolled_Listbox { f args } {
	frame $f
	listbox $f.list \
		-font {courier 12} \
		-xscrollcommand [list Scroll_Set $f.xscroll \
			[list grid $f.xscroll -row 1 -column 0 -sticky we]] \
		-yscrollcommand [list Scroll_Set $f.yscroll \
			[list grid $f.yscroll -row 0 -column 1 -sticky ns]]
	eval {$f.list configure} $args
	scrollbar $f.xscroll -orient horizontal \
		-command [list $f.list xview]
	scrollbar $f.yscroll -orient vertical \
		-command [list $f.list yview]
	grid $f.list $f.yscroll -sticky news
	grid $f.xscroll -sticky news

	grid rowconfigure $f 0 -weight 1
	grid columnconfigure $f 0 -weight 1

	return $f.list
}


###################################################################
# Change the detector mode.
#
# Notes:
#	This proc determines the mode from the variable
#	GlobalParam(Mode), so make sure it is set before
#	calling this proc.
###################################################################
proc ChangeMode { } \
{
	global GlobalParam

	SetMode

	Add2History

	return
}

##########################################################
#
# Create a scrollable frame.
#
#
# From "Effective Tcl/Tk Programming,"
# by Mark Harrison and Michael McLennan.
# Page 121.
#
##########################################################

proc ScrollformCreate { win } \
{

	frame $win -class Scrollform -relief groove -borderwidth 3
	scrollbar $win.sbar -command "$win.vport yview"
	pack $win.sbar -side right -fill y

	canvas $win.vport -yscrollcommand "$win.sbar set"
	pack $win.vport -side left -fill both -expand true

	frame $win.vport.form
	$win.vport create window 0 0 -anchor nw \
		-window $win.vport.form

	bind $win.vport.form <Configure> "ScrollFormResize $win"
	return $win
}

proc ScrollFormResize { win } \
{
	set bbox [ $win.vport bbox all ]
	set wid [ winfo width $win.vport.form ]
	$win.vport configure -width $wid \
		-scrollregion $bbox -yscrollincrement 0.1i
}

proc ScrollFormInterior { win } \
{
	return "$win.vport.form"
}

##########################################################
#
# Read .csv input file.
# Massage contents of each line.
# Insert the info into the channel selector listbox.
#
##########################################################

proc ReadMemFile { } \
{
	global AntennaArray
	global AttenArray
	global CancelXfer
	global ChArray
	global Cht
	global Chvector
	global CommentArray
	global FilterArray
	global FreqArray
	global GlobalParam
	global LabelArray
	global ModeArray
	global PreampArray
	global SelectArray
	global SkipArray

	for {set ch 0} {$ch < 100} {incr ch} \
		{
		set key $ch
		set ChArray($key) 0
		}
	set sid [open $GlobalParam(Ifilename) "r"]

	set line ""
	set i 0

	# Read entire .csv file at one time.
	set allchannels [read $sid]

	# For each line in the .csv file.
	foreach line [split $allchannels "\n" ] \
		{
		update

		incr i
		if { $i > 1 } then\
			{
			# Delete double quote characters.
			regsub -all "\"" $line "" bline
			set line $bline

			if {$line == ""} then {continue}
		
			set flag [ParseCsvLine $line]

			if { $flag == "error" } \
				{
				set msg [GenErrMsg $line]
				set response [tk_dialog .badcsv \
					"Error in file" \
					$msg error 0 OK Exit]
				if {$response == 0} then {continue} \
				else {DisableCControl; exit}
				} \
			elseif { $flag == "ignore" } {continue}
		

			set mlist [split $bline ","]
			set ch [lindex $mlist 0]

			if { $ch != "" } then \
				{
				set key $ch

				set pre ""
				if { [regexp {1} $PreampArray($key)] } \
					{
					set pre PREAMP1
					} \
				elseif { [regexp {2} $PreampArray($key)] } \
					{
					set pre PREAMP2
					}

				if {$AttenArray($key) == "ATTEN"} \
					{
					set atten ATTEN
					} \
				else \
					{
					set atten ""
					}

				set s [format "%2d %11.6f %-6s %-6s %-8s %-6s %-7s %-5s %1s %s" \
					$ch $FreqArray($key) \
					$ModeArray($key) \
					$FilterArray($key) \
					$LabelArray($key) \
					$SelectArray($key) \
					$pre \
					$atten \
					$AntennaArray($key) \
					$CommentArray($key)
					]
				lappend Chvector $s

				# Add frequency and label
				# to a cache

				Add2LabelCache \
					$FreqArray($key) \
					$LabelArray($key)
				}
			}
		}
	close $sid

	wm title $Cht [ Basename $GlobalParam(Ifilename) ]
	return
}


##########################################################
#
# Return the channel selected from the channel selector listbox
#
##########################################################

proc ChSelected { w } \
{
	set line [ ListSelected $w ]
	set line [string trimleft $line " "]

	regsub " .*" $line "" ch
	return "$ch"
}


##########################################################
#
# Return the index selected from the history selector listbox
#
##########################################################

proc HistSelected { w } \
{
	set line [ ListSelected $w ]
	set line [string trimleft $line " "]

	regsub " .*" $line "" i
	return "$i"
}


###################################################################
# Parse one line of a .csv file and extract the fields.
#
# Returns:
#	0	-line passes parsing tests
#	error	-line contains an error
###################################################################

proc ParseCsvLine { s } \
{
	global Bw
	global Mode
	global RBw
	global AntennaArray
	global CommentArray
	global ChArray FreqArray StepArray ModeArray \
		SkipArray SelectArray AttenArray LabelArray \
		PreampArray FilterArray

	set mlist [split $s ","]

	# Skip empty lines.
	if { $s == "" } then {return error}

	if { [llength $mlist] < 8 } then {return error}

	set frq [lindex $mlist 1]
	if { [string compare $frq ""] == 0 } then {return error}
	if { $frq <= 0 } then {return error}


	set ch [lindex $mlist 0]
	if {$ch == ""} {return error}
	set ch [string trimleft $ch 0]

	if {$ch == ""} \
		{
		set ch 0
		}

	set key $ch

	if { $ch < 0 || $ch > 99 } then {return error}

	set FreqArray($key) $frq

	set mode [lindex $mlist 2]
	set mode [string toupper $mode]
	if {[ info exists Mode($mode) ] == 0 } {return error}
	set ModeArray($key) $mode


	set filter [lindex $mlist 3]
	set filter [string toupper $filter]
	if {[ info exists Bw($filter) ] == 0 } {return error}
	set FilterArray($key) $filter

	set select [lindex $mlist 5]
	if { ($select != "") && ($select != "select") } {return error}
	set SelectArray($key) $select

	set preamp [lindex $mlist 6]
	set preamp [string toupper $preamp]

	if { [regexp {1} $preamp] } \
		{
		set preamp 1
		} \
	elseif { [regexp {2} $preamp] } \
		{
		set preamp 2
		} \
	else \
		{
		set preamp 0
		}

	set PreampArray($key) $preamp

	set atten [lindex $mlist 7]
	set atten [string toupper $atten]
	if {$atten != ""} \
		{
		set AttenArray($key) ATTEN
		} \
	else \
		{
		set AttenArray($key) 0
		}

	set LabelArray($key) [lindex $mlist 4]

	set antenna [lindex $mlist 8]
	if {$antenna == ""} \
		{
		set AntennaArray($key) ANT1
		} \
	elseif { [regexp {0} $antenna] || [regexp {1} $antenna] } \
		{
		set AntennaArray($key) ANT1
		} \
	elseif { [regexp {2} $antenna] } \
		{
		set AntennaArray($key) ANT2
		} \
	else {return error}


	# Truncate comment to 30 characters max.
	set cmt [lindex $mlist 9]
	set cmt [string range $cmt 0 29]
	set CommentArray($key) $cmt

	set ChArray($key) 1
	return ok
}

proc GenErrMsg {s} \
{
	global GlobalParam

	set msg ""
	append msg "The following line in file\n"
	append msg "$GlobalParam(Ifilename) "
	append msg "contains an error:\n\n"
	append msg "$s\n\n"
	append msg "Continue or exit the program?"

	return $msg
}


##########################################################
# Contruct the top row of pulldown menus
##########################################################
proc MakeMenuBar { f } \
{
	global AboutMsg
	global Device
	global FileTypes
	global GlobalParam
	global Pgm
	global Version

	# File pull down menu
	frame $f -relief groove -borderwidth 3

	menubutton $f.file -text "File" -menu $f.file.m \
		-underline 0
	menubutton $f.view -text "View" -menu $f.view.m \
		-underline 0
	menubutton $f.tweaks -text "Tweaks" -menu $f.tweaks.m \
		-underline 0
	menubutton $f.filters -text "Filters" -menu $f.filters.m \
		-underline 0
	menubutton $f.options -text "Scan Options" -menu $f.options.m \
		-underline 0
	menubutton $f.log -text "Log" -menu $f.log.m \
		-underline 0
	menubutton $f.presets -text "Presets" -menu $f.presets.m \
		-underline 0
	menubutton $f.radio -text "Radio" -menu $f.radio.m \
		-underline 0
	menubutton $f.help -text "Help" -menu $f.help.m \
		-underline 0
	
	
	menu $f.view.m
	AddView $f.view.m

	menu $f.tweaks.m
	AddTweaks $f.tweaks.m

	menu $f.filters.m
	AddFilters $f.filters.m

	menu $f.options.m
	AddOptions $f.options.m

	menu $f.log.m
	AddLog $f.log.m




	set hint ""
	set hint [append hint "The Tweaks menu lets you "]
	set hint [append hint "configure the IC-R75 Set Mode options "]
	set hint [append hint "To tear off the Tweaks menu, "]
	set hint [append hint "click on Tweaks, "]
	set hint [append hint "then click on the dotted line."]
	balloonhelp_for $f.tweaks $hint


	set hint ""
	set hint [append hint "The Filters menu lets you "]
	set hint [append hint "install optional filters and "]
	set hint [append hint "associate filters with "]
	set hint [append hint "wide, medium, and narrow selectivity "]
	set hint [append hint "settings for each mode. "]
	set hint [append hint "To tear off the Filters menu, "]
	set hint [append hint "click on Filters, "]
	set hint [append hint "then click on the dotted line."]
	balloonhelp_for $f.filters $hint


	set hint ""
	set hint [append hint "To tear off the Scan Options menu, "]
	set hint [append hint "click on Scan Options, "]
	set hint [append hint "then click on the dotted line."]
	balloonhelp_for $f.options $hint

	set hint ""
	set hint [append hint "To tear off the Log menu, "]
	set hint [append hint "click on Log, "]
	set hint [append hint "then click on the dotted line."]
	balloonhelp_for $f.log $hint


	set hint ""
	set hint [append hint "The Radio menu lets you "]
	set hint [append hint "read memory channels from and "]
	set hint [append hint "write them to the IC-R75."]
	balloonhelp_for $f.radio $hint

	menu $f.help.m
	$f.help.m add command -label "Tcl info" \
		-underline 0 \
		-command { \
			tk_dialog .about "Tcl info" \
				[HelpTclInfo] info 0 OK
			}

	$f.help.m add command -label "License" \
		-underline 0 \
		-command { \
			set helpfile [format "%s/COPYING" $Libdir ]
			set win [textdisplay_create "Notice"]
			textdisplay_file $win $helpfile
			}
	
	$f.help.m add command -label "About tk75" \
		-underline 0 \
		-command { \
			tk_dialog .about "About tk75" \
				$AboutMsg info 0 OK
			}
	
	menu $f.file.m -tearoff no

	$f.file.m add command -label "Open ..." \
		-underline 0 \
		-command {global Cht
			global GlobalParam
			# wm deiconify $Cht;
			set fr_table [MakeChannelListFrame $Cht]; \
			if { $GlobalParam(Ifilename) != ""} \
				{
				pack $fr_table
				}
			}
	
	$f.file.m add command -label "Save setup" \
		-underline 0 \
		-command {SaveSetup; SaveLabel}

	$f.file.m add command -label "Exit" \
		-underline 1 \
		-command { ExitApplication; exit }
	
	menu $f.radio.m -tearoff no
	AddRadio $f.radio.m

	menu $f.presets.m
	AddPresets $f.presets.m

	set hint ""
	set hint [append hint "Quickly tune the radio "]
	set hint [append hint "to preset frequencies."]
	balloonhelp_for $f.presets $hint

	pack $f.file $f.view $f.tweaks $f.filters $f.options $f.log \
		$f.presets $f.radio -side left -padx 10
	pack $f.help -side right
	
	update
	return $f
}


####################################################################
# Freq Display
####################################################################
proc FreqDisplay { f } \
{
	global ChanLabel
	global CurrentFreq
	global DisplayFontSize
	global GlobalParam
	global LabelLabel
	global MeterFrame
	global Readout
	global SignalLabel


	frame $f -relief flat -background black -borderwidth 0
	set lf [frame $f.lf -relief flat -background black \
		-borderwidth 0]

#	set Power on
#	checkbutton $f.power -text "POWER" \
#		-variable Power \
#		-onvalue "on" \
#		-offvalue "off" \
#		-command { PowerSwitch $Power }
	

	set MeterFrame $f.meter
	MakeMeter


	set lw 15


	set LabelLabel $lf.label
	label $LabelLabel -text " " -borderwidth 3 \
		-width $lw \
		-justify left \
		-background black -foreground white

	set ChanLabel $lf.chan
	label $ChanLabel -text "VFO" -borderwidth 3 \
		-width $lw \
		-justify left \
		-background black -foreground yellow


	MkModeLabel $lf.mode $lw
	MkBwLabel $lf.bw $lw

	pack \
		$LabelLabel \
		$ChanLabel \
		$lf.mode \
		$lf.bw \
		-anchor w -side top

		# -font {Courier $DisplayFontSize bold} 

	entry $f.display -width 11 \
		-font $DisplayFontSize \
		-textvariable CurrentFreq \
		-relief flat \
		-borderwidth 0 \
		-background black \
		-foreground yellow


	set Readout $f.display
	
	set rf [frame $f.rf -relief flat -background black \
		-borderwidth 0]

	set rw 6
	label $rf.units -text "MHz" -borderwidth 3

	set SignalLabel $rf.signal
	label $SignalLabel -text "    " -borderwidth 3 \
		-justify left \
		-width $rw \
		-background black -foreground red

	pack \
		$rf.units \
		$SignalLabel \
		-anchor w -side top

	set CurrentFreq [FormatFreq "0"]
	pack $f.meter -pady 3 -padx 10 -side left
	pack $lf -padx 4 -side left -expand y
	pack $f.display -padx 10 -side left -expand y
	pack $rf -padx 4 -side left
	
	bind $f.display <Key-Return> \
		{
		# If we are scanning, stop scanning. 
		set GlobalParam(ScanFlag) 0

		# Trim leading spaces or zeros.
		set tmp $CurrentFreq
		regsub {^[ 0]*} $tmp "" CurrentFreq

		set units mhz

		if { [regexp {[mM]$} $CurrentFreq] } \
			{
			# Ends in m or M so number is MHz
			set units mhz 
			regsub {[mM]$} $CurrentFreq {} CurrentFreq
			} \
		elseif { [regexp {[kK]$} $CurrentFreq] } \
			{
			# Ends in k or K so number is kHz
			set units khz
			regsub {[kK]$} $CurrentFreq "" CurrentFreq
			}

		if { [CheckFreqValid $CurrentFreq $units] } then \
			{
			if { $units == "khz" } \
				{
				set CurrentFreq [ expr { double($CurrentFreq) \
					/ double(1000) } ]
				}
			set CurrentFreq [FormatFreq $CurrentFreq ]

			SetSlideRuleDial
			set hz [expr {$CurrentFreq * 1000000}]
			set hz [expr {round($hz)}]
			SetFreq $hz
			set GlobalParam(PreviousFreq) $CurrentFreq

			Add2History
			} \
		else \
			{
			# Invalid frequency.
			bell
			set CurrentFreq $GlobalParam(PreviousFreq)
			set CurrentFreq [FormatFreq $CurrentFreq ]
			}
		}
	return $f
}

####################################################################
# Make frame for pushbuttons
####################################################################
proc MakePushButtons { f } \
{

	frame $f

	MakeBwSwitch $f.bw
	# MakeNoiseBlanker $f
	MakeAGC $f.agc

	pack	$f.bw \
		$f.agc \
		-side top -expand y -fill x \
		-pady 3

	return $f
}


####################################################################
# Make frame for DSP controls
####################################################################
proc MakeDSPFrame { f } \
{
	global GlobalParam

	frame $f -relief sunk -borderwidth 3

	checkbutton $f.notch -text "Automatic notch" \
		-variable GlobalParam(Notch) \
		-onvalue on \
		-offvalue off \
		-command { SetNotch $GlobalParam(Notch) }
	SetNotch $GlobalParam(Notch)

	checkbutton $f.nb -text "Noise Blanker" \
		-variable GlobalParam(NB) \
		-onvalue on \
		-offvalue off \
		-command { SetNB $GlobalParam(NB) }
	SetNB $GlobalParam(NB)

	checkbutton $f.nr -text "Noise reduction" \
		-variable GlobalParam(NR) \
		-onvalue on \
		-offvalue off \
		-command { SetNR $GlobalParam(NR) }
	 SetNR $GlobalParam(NR)


	scale $f.nrlevel -from 0 -to 255 \
		-label "NR Level" \
		-resolution 25 \
		-variable GlobalParam(NRLevel) \
		-command SetNRLevel \
		-orient horizontal 
	SetNRLevel $GlobalParam(NRLevel)
	
	pack	\
		$f.notch \
		$f.nb \
		$f.nr \
		$f.nrlevel \
		-side top -anchor w -expand y -pady 3

	return $f
}


####################################################################
# Make frame for font end widgets, e.g., preamp. atten, antenna
####################################################################
proc MakeFrontEnd { f } \
{

	frame $f -relief sunken -borderwidth 3

	MakeAntenna $f.ant
	MakePreamp $f.preamp
	MakeAttenuator $f.attenuator

	pack \
		$f.ant \
		$f.preamp \
		$f.attenuator \
		-side top -expand y -fill x \
		-pady 3

	return $f
}


####################################################################
# Noise Noise Blanker controls
####################################################################

proc MakeNoiseBlanker { f }\
{
	global GlobalParam


	checkbutton $f.nb -text "Noise Blanker" \
		-variable GlobalParam(NB) \
		-onvalue on \
		-offvalue off \
		-command { SetNB $GlobalParam(NB) }

	pack $f.nb -padx 3 -anchor w

	return $f
}


####################################################################
# Attenuator controls
####################################################################

proc MakeAttenuator { f }\
{
	global GlobalParam

	frame $f -relief flat -borderwidth 3

	checkbutton $f.atten -text "Attenuator" \
		-variable GlobalParam(Attenuator) \
		-onvalue ATTEN \
		-offvalue 0 \
		-command { SetAttenuator $GlobalParam(Attenuator) }
	SetAttenuator $GlobalParam(Attenuator)

	pack $f.atten -padx 3 -anchor w

	return $f
}


####################################################################
# AGC controls
####################################################################

proc MakeAGC { f }\
{
	global GlobalParam

	frame $f -relief groove -borderwidth 3
	label $f.lab -text AGC

	SetAGC $GlobalParam(AGC)

	radiobutton $f.agcs -text "Slow" \
		-variable GlobalParam(AGC) \
		-value slow \
		-command {SetAGC slow}

	radiobutton $f.agcf -text "Fast" \
		-variable GlobalParam(AGC) \
		-value fast \
		-command {SetAGC fast}

	radiobutton $f.agcsf -text "S-Fast" \
		-variable GlobalParam(AGC) \
		-value sfast \
		-command {SetAGC sfast}

	radiobutton $f.agco -text "Off" \
		-variable GlobalParam(AGC) \
		-value off \
		-command {SetAGC off}

	pack $f.lab $f.agcs $f.agcf $f.agcsf $f.agco \
		-side top -padx 3 -anchor w

	return $f
}


####################################################################
# Preamp controls
####################################################################

proc MakePreamp { f }\
{
	global GlobalParam

	frame $f -relief groove -borderwidth 3

	radiobutton $f.preamp0 -text "Preamp off" \
		-variable GlobalParam(Preamp) \
		-value 0 \
		-command {SetPreamp 0}

	radiobutton $f.preamp1 -text "Preamp 1" \
		-variable GlobalParam(Preamp) \
		-value 1 \
		-command {SetPreamp 1}

	radiobutton $f.preamp2 -text "Preamp 2" \
		-variable GlobalParam(Preamp) \
		-value 2 \
		-command {SetPreamp 2}

	SetPreamp $GlobalParam(Preamp)

	pack $f.preamp0 $f.preamp1 $f.preamp2 \
		-side top -padx 3 -anchor w

	return $f
}


####################################################################
# Antenna selection controls
####################################################################

proc MakeAntenna { f }\
{
	global GlobalParam

	frame $f -relief groove -borderwidth 3


	radiobutton $f.ant1 -text "Antenna 1" \
		-variable GlobalParam(Antenna) \
		-value ANT1 \
		-command {SetAntenna ANT1}

	radiobutton $f.ant2 -text "Antenna 2" \
		-variable GlobalParam(Antenna) \
		-value ANT2 \
		-command {SetAntenna ANT2}

	SetAntenna $GlobalParam(Antenna)

	pack $f.ant1 $f.ant2 \
		-side top -padx 3 -anchor w

	return $f
}


####################################################################
# Make two rows of potentiometers
####################################################################

proc MakePots { f } \
{
	global Bwpot
	global GlobalParam

	frame $f -relief flat -borderwidth 3
	frame $f.basic -relief flat -borderwidth 3
	frame $f.adv -relief flat -borderwidth 3
	set p1 $f.basic
	set p2 $f.adv

	
	scale $p1.af -from 0 -to 250 -label "Volume" \
		-variable GlobalParam(Volume1) \
		-resolution 5 \
		-orient horizontal  -command SetVolume \
		-troughcolor green 

	$p1.af set $GlobalParam(Volume1)
	

	
	scale $p1.pbs455 -from -255 -to 255 \
		-label "PBT 455 kHz" \
		-resolution 25 \
		-variable GlobalParam(PassBandShift4) \
		-orient horizontal  -command SetPBS455



	scale $p1.squelch -from 0 -to 250 -label "Squelch" \
		-variable GlobalParam(Squelch) \
		-orient horizontal  -command SetSquelch \
		-troughcolor yellow
	$p1.squelch set $GlobalParam(Squelch)
	
	set GlobalParam(CWPitch) [ReadCWPitch]
	scale $p1.cwpitch -from 300 -to 900 -label "CW Pitch (Hz)" \
		-variable GlobalParam(CWPitch) \
		-resolution 10 \
		-orient horizontal  -command SetCWPitch

	# $p1.cwpitch set $GlobalParam(CWPitch)
	
	
	scale $p2.rf -from 0 -to 250 -label "RF Gain" \
		-variable GlobalParam(RFGain) \
		-command SetRFGain \
		-resolution 5 \
		-orient horizontal

	$p2.rf set $GlobalParam(RFGain)
	
	scale $p2.pbs9 -from -1250 -to 1250 \
		-label "PBT 9 MHz" \
		-resolution 25 \
		-variable GlobalParam(PassBandShift9) \
		-orient horizontal  -command SetPBS9

	scale $p2.backlight -from 0 -to 100 \
		-label "LCD Backlight" \
		-resolution 1 \
		-variable GlobalParam(Backlight) \
		-orient horizontal -command SetBacklight
	SetBacklight $GlobalParam(Backlight)
	
	scale $p2.interval -from 300 -to 1000 \
		-label "Display Interval" \
		-resolution 25 \
		-variable GlobalParam(DisplayUpdateInterval) \
		-orient horizontal 
	

	pack $p1.af $p1.pbs455 $p1.squelch $p1.cwpitch -side left \
		-fill x -expand y -padx 3
	pack $p2.rf $p2.pbs9 $p2.backlight $p2.interval -side left \
		-fill x -expand y -padx 3
	pack $p1 -side top -fill x
	pack $p2 -side top -fill x

	return $f
}


proc MakeScrollPane {w x y} {
   frame $w -class ScrollPane -width $x -height $y
   canvas $w.c -xscrollcommand [list $w.x set] -yscrollcommand [list $w.y set]
   scrollbar $w.x -orient horizontal -command [list $w.c xview]
   scrollbar $w.y -orient vertical   -command [list $w.c yview]
   set f [frame $w.c.content -borderwidth 0 -highlightthickness 0]
   $w.c create window 0 0 -anchor nw -window $f
   grid $w.c $w.y -sticky nsew
   grid $w.x      -sticky nsew
   grid rowconfigure    $w 0 -weight 1
   grid columnconfigure $w 0 -weight 1
   # This binding makes the scroll-region of the canvas behave correctly as
   # you place more things in the content frame.
   bind $f <Configure> [list Scrollpane_cfg $w %w %h]
   $w.c configure -borderwidth 0 -highlightthickness 0
   return $f
}
proc Scrollpane_cfg {w wide high} {
   set newSR [list 0 0 $wide $high]
	return
   if {![string equals [$w cget -scrollregion] $newSR]} {
      $w configure -scrollregion $newSR
   }
}


###################################################################
# Check to see if someone is running another
# copy of  this program.
#
# Code Snippit by DJ Eaton.
# Ben Mesander helped with Mac OS X compatibility.
#
# Warning: works in Linux and Mac OS X only, not Solaris
#
###################################################################
proc CheckForDup { } \
{
	global argv0
	global Pgm

	set filename [lindex [split $argv0 "/"] end]
	set ppid [lindex \
		[exec ps xwww \| grep -i wish \| grep $filename] 0]

	if {$ppid != [pid] } \
		{
		puts stderr "$Pgm: A copy of this program is already running.\n"
		exit 1
		}
	unset ppid filename
	return;
}


###################################################################
# Change the current frequency by adding 'delta' MHz.
###################################################################
proc Qsy { delta } \
{
	global ChanLabel
	global CurrentFreq
	global GlobalParam

	# We are deviating off a channel so wipe out the
	# channel number label.

	if { $GlobalParam(ScanFlag) == 0 } \
		{
		$ChanLabel configure -text "VFO"
		}

	set CurrentFreq [expr {$CurrentFreq + $delta}]
	if { [CheckFreqValid $CurrentFreq mhz] } then \
		{
		set CurrentFreq [FormatFreq $CurrentFreq ]
		set newfreq [expr {$CurrentFreq * 1000000}]
		set newfreq [expr {round($newfreq)}]
		SetFreq $newfreq
		set GlobalParam(PreviousFreq) $CurrentFreq
		SetSlideRuleDial
		update
		} \
	else \
		{
		# Invalid frequency.
		bell
		set CurrentFreq [FormatFreq $GlobalParam(PreviousFreq)]
		}
	return

}

###################################################################
# Search between lower and upper frequency limits
###################################################################
proc Search { l u type } \
{
	global BlinkToggle
	global CurrentFreq
	global GlobalParam
	global PreviousFreq

	SetVFO
	SetTS $GlobalParam(SearchStep)

	# We must program the frequency limits,
	# etc., into channels 100 and 101.

	set s [EncodeAChannel \
		100 $l \
		$GlobalParam(Mode) \
		$GlobalParam(Bw) \
		"        " \
		"" \
		$GlobalParam(Preamp) \
		$GlobalParam(Attenuator) \
		$GlobalParam(Antenna) ]

	# Write the limit a few times to overcome a flake in the
	# IC-R75 which sometimes doesn't store the limit
	# despite is sending a positive ack when I write it.

	WriteAChannel $s
	WriteAChannel $s
	WriteAChannel $s

	set s [EncodeAChannel \
		101 $u \
		$GlobalParam(Mode) \
		$GlobalParam(Bw) \
		"        " \
		"" \
		$GlobalParam(Preamp) \
		$GlobalParam(Attenuator) \
		$GlobalParam(Antenna) ]

	# Write the limit a few times to overcome a flake in the
	# IC-R75 which sometimes doesn't store the limit
	# despite is sending a positive ack when I write it.

	WriteAChannel $s
	WriteAChannel $s
	WriteAChannel $s


	if {$type == "autowritescan"} \
		{
		StartAutoWriteScan
		} \
	elseif {$type == "limitscan"} \
		{
		StartLimitScan
		}

	return
}

###################################################################
# Create memory scan widgets. 
###################################################################
proc MakeMemScanFrame { f }\
{
	global BlinkToggle
	global ChArray
	global ChanLabel
	global GlobalParam

	frame $f -relief sunken -borderwidth 3
	label $f.labmemscan -text "Memory Scan" -borderwidth 3

	set l $f.l
	set r $f.r

	# Create memory scan widgets.
	MakeMemScanTypes  $l

	pack $f.labmemscan -side top -padx 3 -pady 3
	pack $l -side left -anchor n -padx 3 -pady 3
	return
}

###################################################################
# Create button widgets for the various flavors of
# memory scanning.
###################################################################

proc MakeMemScanTypes { f }\
{
	global BlinkToggle
	global ChArray
	global ChanLabel
	global GlobalParam
	global ModeScanLabel

	frame $f -relief flat -borderwidth 3

	button $f.memscanstart -text "Memory Scan" \
		-command {\
			global GlobalParam

			DisableModeScan
			set GlobalParam(ScanType) "Memory Scan"

			PreScan
			StartMemoryScan
			}


	button $f.selscanstart -text "Select Scan" \
		-command { SelectScanCB }


	checkbutton $f.prioscan -text "Priority Scan" \
		-variable GlobalParam(PriorityScan) \
		-onvalue 1 -offvalue 0 \
		-command {\
			global GlobalParam

			if { $GlobalParam(PriorityScan) } \
				{
				# set GlobalParam(ScanType) "Memory Scan"
				set BlinkToggle 1	
				# set GlobalParam(ScanFlag) 1	
				if {[StartPriorityScan]} \
					{
					tk_dialog .error "tk75" \
						"Priority scan error" \
						error 0 OK
					set GlobalParam(PriorityScan) 0
					}
				}
			}

	MakeModeScanMenu  $f.modescanstart 


	button $f.scanstop -text "Stop" \
		-command {\
			StopScan
			$ChanLabel configure -text "VFO"
			set GlobalParam(ScanFlag) 0
			DisableModeScan
			}

	pack \
		$f.memscanstart \
		$f.selscanstart \
		$f.modescanstart \
		$f.scanstop \
		-side top -padx 3 -fill x -anchor w

	return $f
}

###################################################################
# Select Memory Scan callback
###################################################################

proc SelectScanCB { } \
{
	global ChanLabel
	global GlobalParam
	global ModeScan
	global ModeScanLabel

	if {$GlobalParam(ScanFlag) } \
		{
		# We are already scanning so stop scanning first.
		StopScan
		$ChanLabel configure -text "VFO"
		set GlobalParam(ScanFlag) 0
		DisableModeScan
		}

	set GlobalParam(ScanType) "Select Scan"

	PreScan

	if { [StartSelectMemoryScan] } \
		{

		# The radio responded with an error.
		# Cannot do Select Memory Scan 
		# probably because there are no
		# memory channels with the
		# Select tag enabled.

		StopScan
		$ChanLabel configure -text "VFO"
		set GlobalParam(ScanFlag) 0
		DisableModeScan

		# Cannot start select mem scan.
		tk_dialog .noscan "Select Scan error" \
			"Cannot start Select Scan" \
			error 0 OK
		}
	return
}
###################################################################
# Validate frequency search limits
#
# Returns:
#	0	- limits invalid
#	1	- limits valid
###################################################################
proc CheckLimitsValid { l u } \
{
	if { [CheckFreqValid  $l mhz] == 0 } \
		{
		return 0
		} \
	elseif { [CheckFreqValid  $u mhz] == 0 } \
		{
		return 0
		} \
	elseif { $l >= $u } \
		{
		return 0
		} \
	else \
		{
		return 1
		}
}

###################################################################
# Create search widgets. 
###################################################################
proc MakeSearchFrame { f }\
{
	global ChanLabel
	global GlobalParam
	global LowerFreq
	global ModeScanLabel
	global UpperFreq

	frame $f -relief sunken -borderwidth 3
	label $f.limitscan -text "Limit Scan" -borderwidth 3


	label $f.lowerl -text "Lower freq MHz" -borderwidth 3

	entry $f.lower -width 12 \
		-textvariable GlobalParam(LowerLimit) \
		-background white 


	label $f.upperl -text "Upper freq MHz" -borderwidth 3

	entry $f.upper -width 12 \
		-textvariable GlobalParam(UpperLimit) \
		-background white 


	label $f.stepl -text "Step size kHz" -borderwidth 3


	tk_optionMenu $f.stepmenu GlobalParam(SearchStep) \
		.01 .1 1 5 6.25 9 10 12.5 20 25 100


	button $f.limitscanstart -text "Limit Scan" \
		-command { LimitScanCB }


	button $f.autowritescanstart -text "Auto Write Scan" \
		-command {\
			if { [CheckLimitsValid \
				$GlobalParam(LowerLimit) \
				$GlobalParam(UpperLimit)]} \
				{

				set GlobalParam(ScanType) \
					"Auto Write Scan"
				PreScan

				Search $GlobalParam(LowerLimit) \
					 $GlobalParam(UpperLimit) \
					"autowritescan"
				} \
			else \
				{
				tk_dialog .error "tk75" \
					"Search limit error" error 0 OK
				}
			}

	button $f.searchstop -text "Stop" \
		-command {\
			StopScan
			$ChanLabel configure -text "VFO"
			set GlobalParam(ScanFlag) 0
			DisableModeScan
			}


	pack \
		$f.limitscan \
		$f.lowerl \
		$f.lower \
		$f.upperl \
		$f.upper \
		-side top -padx 3 -fill x
	pack \
		$f.stepl \
		$f.stepmenu \
		-side top -padx 3 -pady 3

	pack \
		$f.limitscanstart \
		$f.autowritescanstart \
		$f.searchstop \
		-side top -padx 3 -fill x
	return $f
}

###################################################################
# Limit Scan callback
###################################################################

proc LimitScanCB {} \
{
	global ChanLabel
	global GlobalParam
	global ModeScanLabel

	if { $GlobalParam(ScanFlag) } \
		{
		# We are already scanning so stop scanning first.
		StopScan
		$ChanLabel configure -text "VFO"
		set GlobalParam(ScanFlag) 0
		DisableModeScan
		}

	if { [CheckLimitsValid \
		$GlobalParam(LowerLimit) \
		$GlobalParam(UpperLimit)] } \
		{
		set GlobalParam(ScanType) "Limit Scan"

		DisableModeScan

		PreScan

		Search $GlobalParam(LowerLimit) \
			$GlobalParam(UpperLimit) \
			"limitscan"
		} \
	else \
		{
		tk_dialog .error "tk75" \
			"Search limit error" error 0 OK
		}
	return
}

###################################################################
# Set radio to logical channel.
#
# The proc send commands to the radio to set
# the frequency, mode, bandwidth, and AGC decay time
# according to the settings for channel "ch" in
# our global arrays.
#
# We will drive the radio with these logical channel
# settings from our software arrays instead of relying
# on the contents of what is actually programmed
# in the radio's memory channels.
###################################################################

proc SetLChannel { ch } \
{
	global AgcArray
	global AntennaArray
	global AttenArray
	global ChanLabel
	global ChArray
	global CurrentFreq
	global FreqArray
	global GlobalParam
	global Mode
	global FilterArray
	global ModeArray
	global PreampArray
	global RMode

	set key $ch

	set freq $FreqArray($key)

	# Trim leading spaces and zeroes.
	regsub {^[0 ]*} $freq "" tmp
	set freq $tmp

	if { [CheckFreqValid $freq mhz] } then \
		{
		# Update the frequency display.
		set CurrentFreq [FormatFreq $freq ]
		set hz [expr {$freq * 1000000}]
		set hz [expr {round($hz)}]
		SetFreq $hz

		set GlobalParam(PreviousFreq) $tmp
		SetSlideRuleDial

		# Update the channel label display.
		set tmp [FormatChan $ch]
		if {$GlobalParam(Debug) > 0 }\
			{
			;# puts stderr "chann $chann , tmp $tmp"
			}

		$ChanLabel configure -text $tmp


		set GlobalParam(Mode) $ModeArray($key)
		set GlobalParam(Bw) $FilterArray($key)
		set GlobalParam(Antenna) $AntennaArray($key)
		set GlobalParam(Attenuator) $AttenArray($key)
		set GlobalParam(Preamp) $PreampArray($key)

		ChangeMode
		SetAntenna $GlobalParam(Antenna)
		SetPreamp $GlobalParam(Preamp)
		SetAttenuator $GlobalParam(Attenuator)
		} \
	else \
		{
		# Invalid frequency.
		bell
		set CurrentFreq $GlobalParam(PreviousFreq)
		set CurrentFreq [FormatFreq $CurrentFreq ]
		}

	return
}


##########################################################
# Make channel list frame
##########################################################

proc MakeChannelListFrame { f }\
{
	global Bwpot
	global ChanLabel
	global Chb
	global CurrentFreq
	global FreqArray
	global GlobalParam
	global Chvector
	global FileTypes
	global Home

	set GlobalParam(Ifilename) [Mytk_getOpenFile $f \
		$GlobalParam(MemoryFileDir) \
		"tk75" $FileTypes]

	if {$GlobalParam(Ifilename) == ""} then {return ""}
	set Chvector ""
	ReadMemFile
	
	set GlobalParam(MemoryFileDir) \
		[ Dirname $GlobalParam(Ifilename) ]

	catch {destroy $f.lch}
	set Chb [ List_channels $f.lch $Chvector 30 ]
	wm deiconify $f
	$Chb activate 1
	pack $f.lch -side top
	# pack $f -side top
	
	# Tune radio to given memory channel when user clicks
	# mouse on channel selector listbox entry.
	
	bind $Chb <ButtonRelease-1> \
		{

		# If we are scanning, stop scanning. 
		set GlobalParam(ScanFlag) 0

		set ch [ global Chb; ChSelected $Chb ]

		set key $ch

		# Tune radio to the channel.
		SetLChannel $ch

		SetVolume

		update
		}

	return $f.lch
}

###################################################################
# Create a new history window and populate it with
# frequencies we've visited, mode and timestamp.
###################################################################

proc RefreshHistory {} \
{
	global GlobalParam
	global HistoryFreq
	global HistoryMode
	global HistoryTime
	global HistVector

	set HistVector ""
	for {set i 0} {$i < 1000} {incr i} \
		{
		if {[info exists HistoryTime($i)] == 0} {break}
		if {$HistoryTime($i) <= 0} {break}

		set s [format "%3d %11.6f %-6s %s" \
			$i \
			$HistoryFreq($i) \
			$HistoryMode($i) \
			$HistoryTime($i)]
		lappend HistVector $s
		}

	set f .hist
	catch {destroy $f}
	toplevel $f
	wm title $f "tk75 Session History"

	if {$GlobalParam(ViewHistory) == "off"} \
		{
		# Hide window because user does not want to view it.
		wm iconify $f
		}

	MakeHistoryListFrame $f
	return
}

##########################################################
# Make session history list frame
##########################################################

proc MakeHistoryListFrame { f }\
{
	global Bwpot
	global ChanLabel
	global Histb
	global CurrentFreq
	global FreqArray
	global GlobalParam
	global HistVector

	
	# RefreshHistory

	set Histb [ List_channels $f.hch $HistVector 10 ]
	$Histb activate 1
	pack $f.hch -side top
	
	# Tune radio to given history freq entry
	# and set the mode when user clicks
	# the mouse button on history selector listbox entry.
	
	bind $Histb <ButtonRelease-1> \
		{

		# If we are scanning, stop scanning. 
		set GlobalParam(ScanFlag) 0

		set idx [ global Histb; HistSelected $Histb ]

		$ChanLabel configure -text VFO

		# Update the frequency display.
		set CurrentFreq $HistoryFreq($idx)
		set GlobalParam(PreviousFreq) $CurrentFreq

		SetSlideRuleDial

		# Tune radio to the channel.
                set hz [expr {$CurrentFreq * 1000000}]
                set hz [expr {round($hz)}]
                SetFreq $hz

		set GlobalParam(Mode) $HistoryMode($idx)
		SetMode

		SetVolume
		update
		}

	return $f.hch
}

##########################################################
# Make frame for the Up and Down single step freq buttons.
##########################################################

proc MakeUpDownFrame { g } \
{
	global GlobalParam

	frame $g -borderwidth 0 -relief flat
	frame $g.but -borderwidth 3 -relief sunken
	set f $g.but

	foreach inc { 50000 25000 15000 12500 10000 5000 1000 100 10 1 } \
		{
		frame $f.f$inc -borderwidth 3 -relief flat
		}

	button $f.f50000.down50000 -text "-50" -command {Qsy -0.050} -width 5
	button $f.f25000.down25000 -text "-25" -command {Qsy -0.025} -width 5
	button $f.f15000.down15000 -text "-15" -command {Qsy -0.015} -width 5
	button $f.f12500.down12500 -text "-12.5" -command {Qsy -0.0125} -width 5
	button $f.f10000.down10000 -text "-10" -command {Qsy -0.01} -width 5
	button $f.f5000.down5000 -text "-5" -command {Qsy -0.005} -width 5
	button $f.f1000.down1000 -text "-1" -command {Qsy -0.001} -width 5
	button $f.f100.down100 -text "-.1" -command {Qsy -0.0001} -width 5
	button $f.f10.down10 -text "-.01" -command {Qsy -0.00001} -width 5
	button $f.f1.down1 -text "-.001" -command {Qsy -0.000001} -width 5
	button $f.f1.up1 -text "+.001" -command {Qsy 0.000001} -width 5
	button $f.f10.up10 -text "+.01" -command {Qsy 0.00001} -width 5
	button $f.f100.up100 -text "+.1" -command {Qsy 0.0001} -width 5
	button $f.f1000.up1000 -text "+1" -command {Qsy 0.001} -width 5
	button $f.f5000.up5000 -text "+5" -command {Qsy 0.005} -width 5
	button $f.f10000.up10000 -text "+10" -command {Qsy 0.01} -width 5
	button $f.f12500.up12500 -text "+12.5" -command {Qsy 0.0125} -width 5
	button $f.f15000.up15000 -text "+15" -command {Qsy 0.015} -width 5
	button $f.f25000.up25000 -text "+25" -command {Qsy 0.025} -width 5
	button $f.f50000.up50000 -text "+50" -command {Qsy 0.050} -width 5


	foreach inc {50000 25000 15000 12500 10000 5000 1000 100 10 1} \
		{
		foreach direction { up down } \
			{
			# Pack each pair of up/down buttons.
			pack $f.f$inc.$direction$inc \
				-side top -fill x -expand y
			}
		}

	foreach inc {1 10 100 1000 5000 10000 12500 15000 25000 50000} \
		{
		pack $f.f$inc -side right -fill x -expand y
		}

	label $g.lab -text "Single Step"

	if { $GlobalParam(ViewUpDownButtons) == "on" } \
		{
		pack $f -side top -fill x -expand y
		}
	return $g
}

##########################################################
# Make the frequency display impossible to read.
##########################################################
proc BlankDisplay { } \
{
	global ChanLabel

	.freqdisplay.display config -foreground black
	return
}


##########################################################
# Make the frequency display possible to read.
##########################################################
proc RestoreDisplay { } \
{
	.freqdisplay.display config -foreground yellow
	return
}

###################################################################
# Start and stop frequency slewing (autotune).
###################################################################

proc SlewCB { w amt updown } \
{
	global GlobalParam

	if { $GlobalParam(Slewing) == 1 } \
		{
		# We are currently slewing. User wants to stop.

		set GlobalParam(Slewing) 0

		return
		}

	# We are not slewing and the user
	# wants to start slewing.


	set GlobalParam(Slewing) 1
	StartSlew $amt $updown

	return
}

###################################################################
# Make a frame for the freq slew (autotune) buttons.
###################################################################

proc MakeSlewFrame { g } \
{
	global GlobalParam

	frame $g -borderwidth 0 -relief flat
	frame $g.but -borderwidth 3 -relief sunken 
	set f $g.but

	set slew_text(down50000)  "<-50"
	set slew_text(down25000)  "<-25"
	set slew_text(down15000)  "<-15"
	set slew_text(down12500)  "<-12.5"
	set slew_text(down10000)  "<-10"
	set slew_text(down5000)  "<-5"
	set slew_text(down1000)  "<-1"
	set slew_text(down100)	"<-.1"
	set slew_text(down10)	"<-.01"
	set slew_text(down1)	"<-.001"

	set slew_text(up50000)  "->50"
	set slew_text(up25000)  "->25"
	set slew_text(up15000)  "->15"
	set slew_text(up10000)  "->10"
	set slew_text(up12500)  "->12.5"
	set slew_text(up5000)  "->5"
	set slew_text(up1000)  "->1"
	set slew_text(up100) "->.1"
	set slew_text(up10) "->.01"
	set slew_text(up1) "->.001"


	foreach inc {1 10 100 1000 5000 10000 12500 15000 25000 50000 } \
		{
		# Create one frame for each pair of slew buttons.

		frame $f.f$inc -borderwidth 3

		# label $f.f$inc.lab -text $slew_text($inc)


		foreach updown { up down }\
			{
			set w $f.f$inc.$updown
			button $w \
				-width 5 \
				-text $slew_text($updown$inc) \
				-command \
					"
					global inc
					global updown
					SlewCB $w $inc $updown
					"

			pack $f.f$inc.$updown -side top -fill x \
				-expand y
			}

		pack $f.f$inc -side right -fill x -expand y
		}


	if { $GlobalParam(ViewSlewButtons) == "on" } \
		{
		pack $f -side top -fill x -expand y
		}
	return $g
}


###################################################################
# Read the frequency from the receiver and update the
# display widget to reflect the receiver's true frequency.
###################################################################
proc UpdDisplay {} \
{
	global CurrentFreq
	global GlobalParam
	global LabelLabel
	global Label

	set CurrentFreq [ReadFreq]

	if { [CheckFreqValid $CurrentFreq mhz] } then \
		{
		set hz [expr {$CurrentFreq * 1000000}]
		set hz [expr {round($hz)}]
		# puts "$CurrentFreq $hz"
		set CurrentFreq [FormatFreq $CurrentFreq ]
		set GlobalParam(PreviousFreq) $CurrentFreq


		# Get and display frequency alpha label
		# from label cache.

		set f [string trimleft $CurrentFreq " "]
		if { [info exists Label($f)] } \
			{
			$LabelLabel configure \
				-text $Label($f)
			} \
		else \
			{
			$LabelLabel configure -text " "
			}

		} \
	else \
		{
		# Invalid frequency.
		bell
		set CurrentFreq $GlobalParam(PreviousFreq)
		set CurrentFreq [FormatFreq $CurrentFreq ]
		puts stderr "UpdDisplay: BAD FREQ"
		}

	# RestoreDisplay
	return
}


proc AlterDisplay { deltahz } \
{
	global CurrentFreq

	set ad [ expr {abs($deltahz)} ]

	# Force the least significant display digits to zero,
	# depending on the step size.

	if { $ad == 1000 }\
		{
		regsub "...$" $CurrentFreq "000" CurrentFreq
		} \
	elseif { $ad == 100 }\
		{
		regsub "..$" $CurrentFreq "00" CurrentFreq
		} \
	elseif { $ad == 10 }\
		{
		regsub ".$" $CurrentFreq "0" CurrentFreq
		}

	set hz [expr {$CurrentFreq * 1000000}]
	set hz [expr {$hz + $deltahz}]
	set CurrentFreq [expr {$hz / 1000000}]

	if { [CheckFreqValid $CurrentFreq mhz] } then \
		{
		set CurrentFreq [FormatFreq $CurrentFreq ]
		set GlobalParam(PreviousFreq) $CurrentFreq

		# Update the slide rule dial every 1 kHz
		if { [regexp {000$} $CurrentFreq] } \
			{
			SetSlideRuleDial
			}
		} \
	else \
		{
		# Invalid frequency.
		bell
		set CurrentFreq $GlobalParam(PreviousFreq)
		set CurrentFreq [FormatFreq $CurrentFreq ]
		}

	# RestoreDisplay
	return
}


##########################################################
# Add widgets to the view menu
##########################################################
proc AddView { m } \
{
	global GlobalParam
	global HistoryFreq
	global HistoryIdx
	global HistoryMode
	global HistoryTime
	global MeterFrame
	global SlideRule


	# Change font.

	if {$GlobalParam(Font) == ""} \
		{
		set msg "Change Font"
		} \
	else \
		{
		set msg [format "Change Font (%s)" $GlobalParam(Font)]
		}

	$m add command -label $msg -command \
		{
		set ft [font_select]
		if {$ft != ""} \
			{
			set GlobalParam(Font) $ft

			set msg "The change will take effect next "
			set msg [append msg "time you start tk545."]

			tk_dialog .wcf "Change Appearance" \
				$msg info 0 OK
			}
		}

	$m add command -label "Restore Original Font" -command \
		{
		set GlobalParam(Font) ""
		set msg "The change will take effect next "
		set msg [append msg "time you start tk545."]

		tk_dialog .wcf "Change Appearance" $msg info 0 OK
		}

	$m add separator

	$m add command -label "Change Panel Color" -command \
		{
		set col [tk_chooseColor -initialcolor #d9d9d9]
		if {$col != ""} \
			{
			set GlobalParam(BackGroundColor) $col

			set msg "The change will take effect next "
			set msg [append msg "time you start tk545."]

			tk_dialog .wcf "Change Appearance" \
				$msg info 0 OK
			}
		}

	$m add command -label "Change Lettering Color" -command \
		{
		set col [tk_chooseColor -initialcolor black]
		if {$col != ""} \
			{
			set GlobalParam(ForeGroundColor) $col

			set msg "The change will take effect next "
			set msg [append msg "time you start tk545."]

			tk_dialog .wcf "Change Appearance" \
				$msg info 0 OK
			}
		}

	$m add command -label "Change Slider Trough Color" -command \
		{
		set col [tk_chooseColor -initialcolor #c3c3c3]
		if {$col != ""} \
			{
			set GlobalParam(TroughColor) $col

			set msg "The change will take effect next "
			set msg [append msg "time you start tk545."]

			tk_dialog .wcf "Change Appearance" \
				$msg info 0 OK
			}
		}

	$m add separator


	# Helpful tips balloons

	$m add  checkbutton \
		-label "Balloon Help Windows" \
                -variable GlobalParam(BalloonHelpWindows) \
                -onvalue on \
                -offvalue off 

	$m add  checkbutton \
		-label "Slide Rule Dial" \
                -variable GlobalParam(ViewSlideRule) \
                -onvalue on \
                -offvalue off \
		-command \
			{
			set msg "The change will take effect next "
			set msg [append msg "time you start tk75."]

			tk_dialog .wslew "Change appearance" \
				$msg info 0 OK
			}

	$m add  checkbutton \
		-label "Frequency Slew Buttons" \
                -variable GlobalParam(ViewSlewButtons) \
                -onvalue on \
                -offvalue off \
		-command \
			{
			set msg "The change will take effect next "
			set msg [append msg "time you start tk75."]

			tk_dialog .wslew "Change appearance" \
				$msg info 0 OK
			}


	$m add  checkbutton \
		-label "Frequency Step Buttons" \
                -variable GlobalParam(ViewUpDownButtons) \
                -onvalue on \
                -offvalue off \
		-command \
			{
			set msg "The change will take effect next "
			set msg [append msg "time you start tk75."]

			tk_dialog .wud "Change appearance" \
				$msg info 0 OK
			}


	$m add separator

	$m add  checkbutton \
		-label "Session History Window" \
                -variable GlobalParam(ViewHistory) \
                -onvalue on \
                -offvalue off \
                -command \
			{
			if {$GlobalParam(ViewHistory) == "on"} \
				{
				catch {wm deiconify .hist}
				} \
			else \
				{
				catch {wm iconify .hist}
				}
			}

	$m add  command \
		-label "Clear Session History" \
                -command \
			{
			unset HistoryIdx
			unset HistoryTime
			unset HistoryFreq
			unset HistoryMode
			catch {destroy .hist}
			}

	return
}

##########################################################
# Add widgets to the Options menu
##########################################################
proc AddOptions { m } \
{
	global GlobalParam


	$m add  radiobutton \
		-label "Slew speed slow" \
		-variable GlobalParam(SlewSpeed) \
		-value 1000


	$m add  radiobutton \
		-label "Slew speed fast" \
		-variable GlobalParam(SlewSpeed) \
		-value 500

	$m add separator

	$m add  checkbutton \
		-label "Scan fast" \
		-variable GlobalParam(FastScan) \
		-onvalue on \
		-offvalue off \
		-command {SetTweak 07 $GlobalParam(FastScan)}

	SetTweak 07 $GlobalParam(FastScan)

	$m add separator

	$m add  checkbutton \
		-label "Scan resume" \
		-variable GlobalParam(Resume) \
		-onvalue on \
		-offvalue off \
		-command {SetResume $GlobalParam(Resume)}



	SetResume $GlobalParam(Resume)

	$m add separator


	return $m
}


##########################################################
# Add widgets to the Filters menu
##########################################################
proc AddFilters { m } \
{
	global GlobalParam


	$m add  checkbutton \
		-label "Expanded filter selection" \
		-variable GlobalParam(ExpandedFilters) \
		-onvalue on \
		-offvalue off \
		-command {SetTweak 23 $GlobalParam(ExpandedFilters)}
	SetTweak 23 $GlobalParam(ExpandedFilters)

	$m add separator

	$m add command -label "Optional 9 MHz IF filter installed"

	$m add radiobutton -label "None" \
		-variable GlobalParam(Opt9Filter) \
		-value 00 -command { SetTweak2 24 00 1 }

	$m add radiobutton -label "250Hz, FL-101" \
		-variable GlobalParam(Opt9Filter) \
		-value 02 -command { SetTweak2 24 02 1 }

	$m add radiobutton -label "350Hz, FL-232" \
		-variable GlobalParam(Opt9Filter) \
		-value 05 -command { SetTweak2 24 05 1 }

	$m add radiobutton -label "500Hz, FL-100" \
		-variable GlobalParam(Opt9Filter) \
		-value 01 -command { SetTweak2 24 01 1 }

	$m add radiobutton -label "1.9kHz, FL-223" \
		-variable GlobalParam(Opt9Filter) \
		-value 04 -command { SetTweak2 24 04 1 }

	$m add radiobutton -label "2.8kHz, FL-103" \
		-variable GlobalParam(Opt9Filter) \
		-value 03 -command { SetTweak2 24 03 1 }

	$m add separator

	$m add command -label "Optional 455 kHz IF filter installed"

	$m add radiobutton -label "None" \
		-variable GlobalParam(Opt4Filter) \
		-value 00 -command { SetTweak2 25 00 1 }

	$m add radiobutton -label "250Hz, FL-53A" \
		-variable GlobalParam(Opt4Filter) \
		-value 02 -command { SetTweak2 25 02 1 }

	$m add radiobutton -label "500Hz, FL-52A" \
		-variable GlobalParam(Opt4Filter) \
		-value 01 -command { SetTweak2 25 01 1 }

	$m add radiobutton -label "1.8kHz, FL-222" \
		-variable GlobalParam(Opt4Filter) \
		-value 04 -command { SetTweak2 25 04 1 }

	$m add radiobutton -label "2.8kHz, FL-96" \
		-variable GlobalParam(Opt4Filter) \
		-value 03 -command { SetTweak2 25 03 1 }

	$m add radiobutton -label "3.3kHz, FL-257" \
		-variable GlobalParam(Opt4Filter) \
		-value 05 -command { SetTweak2 25 05 1 }

	$m add separator

	$m add command -label "Wide/Medium/Narrow filter settings ..." \
		-command { \
			catch {destroy .filters}
			toplevel .filters
			wm title .filters "Wide/medium/narrow filter settings"
			MakeFilterSelectFrame .filters
			update
			}
	
	return
}

##########################################################
# Add widgets to the Tweaks menu
##########################################################
proc AddTweaks { m } \
{
	global GlobalParam


	set GlobalParam(RFSquelch) [ReadTweak2 01 1]
	$m add radiobutton  \
		-label "RF/Squelch control = Squelch" \
		-variable GlobalParam(RFSquelch) \
		-value 00 -command {SetTweak2 01 00 1}

	$m add radiobutton \
		-label "RF/Squelch control = Auto" \
		-variable GlobalParam(RFSquelch) \
		-value 01 -command {SetTweak2 01 01 1}

	$m add radiobutton \
		-label "RF/Squelch control = RF gain + squelch" \
		-variable GlobalParam(RFSquelch) \
		-value 02 -command {SetTweak2 01 02 1}


	$m add separator


	set GlobalParam(ShowLabel) [ReadTweak 26]
	$m add  checkbutton \
		-label "Show memory label instead of frequency" \
		-variable GlobalParam(ShowLabel) \
		-onvalue on \
		-offvalue off \
		-command {SetTweak 26 $GlobalParam(ShowLabel)}


	set GlobalParam(SmeterPeakHold) [ReadTweak 05]
	$m add  checkbutton \
		-label "S Meter peak hold" \
		-variable GlobalParam(SmeterPeakHold) \
		-onvalue on \
		-offvalue off \
		-command {SetTweak 05 $GlobalParam(SmeterPeakHold)}


	set GlobalParam(AutoTuningStep) [ReadTweak 22]
	$m add  checkbutton \
		-label "Auto tuning step" \
		-variable GlobalParam(AutoTuningStep) \
		-onvalue on \
		-offvalue off \
		-command {SetTweak 22 $GlobalParam(AutoTuningStep)}

	set GlobalParam(AMNB) [ReadTweak 08]
	$m add  checkbutton \
		-label "AM mode noise blanker" \
		-variable GlobalParam(AMNB) \
		-onvalue on \
		-offvalue off -command {SetTweak 08 $GlobalParam(AMNB)}


	set GlobalParam(WeakAM) [ReadTweak 09]
	$m add  checkbutton \
		-label "Downgrade from S-AM to AM on weak signal" \
		-variable GlobalParam(WeakAM) \
		-onvalue on \
		-offvalue off \
		-command {SetTweak 09 $GlobalParam(WeakAM)}

	set GlobalParam(BlankChannelInd) [ReadTweak 11]
	$m add  checkbutton \
		-label "Skip blank channels" \
		-variable GlobalParam(BlankChannelInd) \
		-onvalue on \
		-offvalue off \
		-command {SetTweak 11 $GlobalParam(BlankChannelInd)}

	set GlobalParam(RecorderRelay) [ReadTweak 12]
	$m add  checkbutton \
		-label "Recorder remote relay" \
		-variable GlobalParam(RecorderRelay) \
		-onvalue on \
		-offvalue off \
		-command {SetTweak 12 $GlobalParam(RecorderRelay)}

	$m add separator

	set GlobalParam(Beep) [ReadTweak 02]
	$m add  checkbutton \
		-label "Keypad confirmation beep" \
		-variable GlobalParam(Beep) \
		-onvalue on \
		-offvalue off \
		-command {SetTweak 02 $GlobalParam(Beep)}


	set GlobalParam(BeepLevelLimit) [ReadTweak 04]
	$m add  checkbutton \
		-label "Beep level limit" \
		-variable GlobalParam(BeepLevelLimit) \
		-onvalue on \
		-offvalue off \
		-command {SetTweak 04 $GlobalParam(BeepLevelLimit)}

	$m add separator

	set GlobalParam(SpeakFast) [ReadTweak 16]
	$m add  checkbutton \
		-label "Speak fast" \
		-variable GlobalParam(SpeakFast) \
		-onvalue on \
		-offvalue off \
		-command {SetTweak 16 $GlobalParam(SpeakFast)}

	set GlobalParam(SpeakJapanese) [ReadTweak 15]
	$m add  checkbutton \
		-label "Speak Japanese" \
		-variable GlobalParam(SpeakJapanese) \
		-onvalue on \
		-offvalue off \
		-command {SetTweak 15 $GlobalParam(SpeakJapanese)}

	set GlobalParam(SpeakSmeter) [ReadTweak 17]
	$m add  checkbutton \
		-label "Announce S Meter level" \
		-variable GlobalParam(SpeakSmeter) \
		-onvalue on \
		-offvalue off \
		-command {SetTweak 17 $GlobalParam(SpeakSmeter)}

	set GlobalParam(SpeakTime) [ReadTweak 18]
	$m add  checkbutton \
		-label "Announce current time" \
		-variable GlobalParam(SpeakTime) \
		-onvalue on \
		-offvalue off \
		-command {SetTweak 18 $GlobalParam(SpeakTime)}

	$m add separator


	set GlobalParam(PowerOnTimerArm) [ReadTweak 28]
	$m add  checkbutton \
		-label "Arm power on timer" \
		-variable GlobalParam(PowerOnTimerArm) \
		-onvalue on \
		-offvalue off \
		-command {SetTweak 28 $GlobalParam(PowerOnTimerArm)}

	$m add command -label "Configure power on timer ..." \
		-command \
			{
			catch {destroy .ctimer}
			toplevel .ctimer
			set t "Power on time"
			wm title .ctimer $t

			MakeConfigureTimerFrame \
				.ctimer $t PowerOnTimer 29
			update
			}

	set GlobalParam(PowerOffTimerArm) [ReadTweak 30]
	$m add  checkbutton \
		-label "Arm power off timer" \
		-variable GlobalParam(PowerOffTimerArm) \
		-onvalue on \
		-offvalue off \
		-command {SetTweak 30 $GlobalParam(PowerOffTimerArm)}

	$m add command -label "Configure power off timer ..." \
		-command \
			{
			catch {destroy .ctimer}
			toplevel .ctimer
			set t "Power off time"
			wm title .ctimer $t

			MakeConfigureTimerFrame \
				.ctimer $t PowerOffTimer 31
			update
			}

	set GlobalParam(SleepTimerArm) [ReadTweak 32]
	$m add  checkbutton \
		-label "Arm sleep timer" \
		-variable GlobalParam(SleepTimerArm) \
		-onvalue on \
		-offvalue off \
		-command {SetTweak 32 $GlobalParam(SleepTimerArm)}

	$m add command -label "Configure sleep timer ..." \
		-command \
			{
			catch {destroy .ctimer}
			toplevel .ctimer
			set t "Sleep time"
			wm title .ctimer $t

			MakeConfigureTimerFrame \
				.ctimer $t SleepTime 33
			update
			}
	$m add separator

	$m add command -label "Set radio clock using GMT" \
		-command { SyncClock 1 }

	$m add command -label "Set radio clock using local time zone" \
		-command { SyncClock 0 }

	$m add separator


	set GlobalParam(RTTYmark) [ReadTweak2 19 1]

	$m add radiobutton  \
		-label "RTTY mark frequency = 1275 Hz" \
		-variable GlobalParam(RTTYmark) \
		-value 00 -command {SetTweak2 19 00 1}

	$m add radiobutton  \
		-label "RTTY mark frequency = 1615 Hz" \
		-variable GlobalParam(RTTYmark) \
		-value 01 -command {SetTweak2 19 01 1}

	$m add radiobutton  \
		-label "RTTY mark frequency = 2125 Hz" \
		-variable GlobalParam(RTTYmark) \
		-value 02 -command {SetTweak2 19 02 1}

	$m add separator


	set GlobalParam(RTTYshift) [ReadTweak2 20 1]
	$m add radiobutton  \
		-label "RTTY shift width = 170 Hz" \
		-variable GlobalParam(RTTYshift) \
		-value 00 -command {SetTweak2 20 00 1}

	$m add radiobutton  \
		-label "RTTY shift width = 200 Hz" \
		-variable GlobalParam(RTTYshift) \
		-value 01 -command {SetTweak2 20 01 1}

	$m add radiobutton  \
		-label "RTTY shift width = 425 Hz" \
		-variable GlobalParam(RTTYshift) \
		-value 02 -command {SetTweak2 20 02 1}


	return $m
}


##########################################################
# Add widgets to the Log menu
##########################################################
proc AddLog { m } \
{
	global GlobalParam
	global Lid
	global Lfilename


	set msg "Log active frequencies in a file automatically"

	$m add checkbutton \
		-label $msg \
                -variable GlobalParam(AutoLogging) \
                -onvalue on \
                -offvalue off \
                -command \
			{
			if {$Lfilename == ""} \
				{
				InitLogFile
				}
			}

	$m add command -label "Log the current frequency and time." \
		-command \
			{
			if { $Lfilename == "" } \
				{
				InitLogFile
				}
			LogTransmission
			}

	return $m
}

###################################################################
# Prompt user for the name of a file to create for logging
# active frequencies.
# Open the file.
###################################################################

proc InitLogFile { } \
{
	global FileTypes
	global GlobalParam
	global Lfilename
	global Lid

	set Lfilename [Mytk_getSaveFile \
		.mainframe \
		$GlobalParam(LogFileDir) \
		.csv \
		"Create a log file" \
		$FileTypes]

	if { [string length $Lfilename] != 0 } \
		{
		set GlobalParam(LogFileDir) \
			[ Dirname $Lfilename ]

		if { [catch {open $Lfilename {WRONLY APPEND CREAT} } \
			Lid] } \
			{
			bell
			tk_dialog .logfilerror "Log file error" \
				"Cannot create log file." error 0 OK
			}
		}
	return
}

##########################################################
# Add option widgets to the Presets menu
##########################################################
proc AddPresets { m } \
{
	global CurrentFreq
	global GlobalParam
	global PreviousFreq
	global PresetFreq PresetLabel PresetMode
	global Psi

	set n [array size PresetFreq]

	# For each preset frequency.

	for { set Psi 0 } { $Psi < $n } { incr Psi } \
		{

		set cmd [format "$m add command "]
		set cmd [append cmd "\-label {$PresetLabel($Psi)} "]
		set cmd [append cmd "\-command {GoToPreset $Psi}"]
		eval $cmd
		}
	return $m
}

proc GoToPreset { i } \
{
	global Bwpot
	global CurrentFreq
	global GlobalParam
	global Mode
	global RMode
	global PreviousFreq
	global PresetFreq PresetLabel PresetMode

	set CurrentFreq [FormatFreq $PresetFreq($i) ]
	set hz [expr {$CurrentFreq * 1000000}]
	set hz [expr {round($hz)}]
	SetFreq $hz
	set GlobalParam(PreviousFreq) $CurrentFreq

	set m $PresetMode($i)
	set m [string toupper $m]
	set GlobalParam(Mode) $m
	SetMode

	SetSlideRuleDial

	return
}


##########################################################
# Add choices to the Radio menu
##########################################################
proc AddRadio { m } \
{
	global GlobalParam
	global Libdir

	$m add command -label "Speech" \
		-command { Speak }
	
	$m add separator

	$m add command -label "Read from radio ..." \
		-command { \
			Radio2File .mainframe
			update
			}
	
	$m add command -label "Write memories to radio ..." \
		-command { \
			File2Radio .mainframe
			update
			}
	
	$m add separator


	$m add  checkbutton \
		-label "Debug" \
                -variable GlobalParam(Debug) \
                -onvalue "1" \
                -offvalue "0"

	return $m
}


##########################################################
#
# Create a progress gauge widget.
#
#
# From "Effective Tcl/Tk Programming,"
# by Mark Harrison and Michael McLennan.
# Page 125.
#
##########################################################
proc gauge_create {win {color ""}} \
{
	frame $win -class Gauge

	# set len [option get $win length Length]
	set len 300

	canvas $win.display -borderwidth 0 -background white \
		-highlightthickness 0 -width $len -height 20
	pack $win.display -expand yes -padx 10
	if {$color == ""} \
		{
		set color [option get $win color Color]
		}


	$win.display create rectangle 0 0 0 20 \
		-outline "" -fill $color -tags bar
	$win.display create text [expr {0.5 * $len}] 10 \
		-anchor c -text "0%" -tags value
	return $win
}

proc gauge_value {win val} \
{
	if {$val < 0 || $val > 100} \
		{
		error "bad value \"$val\": should be 0-100"
		}
	set msg [format "%.0f%%" $val]
	$win.display itemconfigure value -text $msg

	set w [expr {0.01 * $val * [winfo width $win.display]}]
	set h [winfo height $win.display]
	$win.display coords bar 0 0 $w $h

	update
}

proc MakeWaitWindow {f cnflag color} \
{
	global CancelXfer

	set CancelXfer 0

	frame $f
	button $f.cancel -text Cancel -command {\
		global CancelXfer; set CancelXfer 1; puts "Canceled"}

	gauge_create $f.g PaleGreen
	option add *Gauge.borderWidth 2 widgetDefault
	option add *Gauge.relief sunken widgetDefault
	option add *Gauge.length 300 widgetDefault
	option add *Gauge.color gray widgetDefault

	pack $f.g -expand yes -fill both \
		-padx 10 -pady 10

	if {$cnflag} \
		{
		pack $f.cancel -side top -padx 3 -pady 3
		}

	

	pack $f
	return $f.g
}

##########################################################
# Copy from radio to .csv file
##########################################################
proc Radio2File { f }\
{
	global FileTypes
	global GlobalParam
	global Home
	global Ofilename


	set Ofilename [Mytk_getSaveFile $f \
		$GlobalParam(MemoryFileDir) \
		.csv \
		"Copy from IC-R75 to file" \
		$FileTypes]


	if {$Ofilename != ""} \
		{
		# puts "going to read from radio into $Ofilename"
	
		set GlobalParam(MemoryFileDir) \
			[ Dirname $GlobalParam(Ifilename) ]

		# Create and display progress bar.
		toplevel .pbw
		wm title .pbw "Reading IC-R75"
		grab set .pbw
		set p [MakeWaitWindow .pbw.g 0 PaleGreen]
		set pc 0
		gauge_value $p $pc
		update
	
		# set memorydata [ReadMem $p]

		set fid [open $Ofilename "w"]

		# Write first line as the field names.
		puts $fid [format "Ch,MHz,Mode,Selectivity,Label,Select,Preamp,Atten,Antenna"]

		# We don't know whether a channel exists
		# until we try to read it.

		# Set the highest channel number so we
		# won't waste time trying to read many non-existent
		# channels.

		set hi $GlobalParam(HighestChannel)


		# For each memory channel.
		for {set ch 1} {$ch <= $hi} {incr ch} \
			{
			set lst [ReadAChannel $ch]
			set status [lindex $lst 0]
			set line [lindex $lst 1]

			# Check for empty channel.
			# Check for invalid channel.

			if { ($status == "invalid")
				|| ($status == "empty")} \
				{
				continue
				}

			set memorydata [DecodeAChannel \
				$line $ch ]

			set f [lindex $memorydata 0]
			set mode [lindex $memorydata 1]
			set filter [lindex $memorydata 2]
			set lab [lindex $memorydata 3]
			set select [lindex $memorydata 4]
			set preamp [lindex $memorydata 5]
			set atten [lindex $memorydata 6]
			set antenna [lindex $memorydata 7]

			if { $f == 0 } {continue}

			set lab [string trimright $lab " "]
			set lab [string trimleft $lab " "]
			if {[string length $lab] > 0} \
				{
				set lab [format "\"%s\"" $lab]
				}
			if {$atten == 0} {set atten ""}
			set s [format "%d,%.6f,%s,%s,%s,%s,%s,%s,%s" \
				$ch $f \
				$mode \
				$filter \
				$lab \
				$select $preamp $atten $antenna]
			puts $fid $s
			# puts stderr $s

			# Update progress bar widget.
			set pc $ch
			gauge_value $p $pc
			}

		close $fid

		# Zap the progress bar.
		grab release .pbw
		destroy .pbw

		tk_dialog .belch "Read IC-R75" \
			"Transfer Complete" info 0 OK

		return
		}
}

proc FileExistsDialog { file } \
{
	set result [tk_dialog .fed "Warning" \
		"File $file already exists. Overwrite file?" \
		warning 0 Cancel Overwrite ]

	puts "result is $result"
	return $result
}


##########################################################
# Copy from a .csv file containing memory channels to radio
##########################################################
proc File2Radio { f }\
{
	global FileTypes
	global GlobalParam
	global Cht;


	if {$GlobalParam(Ifilename) == ""} \
		{
		# Prompt for file name and read the file.
		# wm deiconify $Cht;
		set fr_table [MakeChannelListFrame $Cht]
		if {$GlobalParam(Ifilename) == ""} then {return}
		pack $fr_table
		}


	if {$GlobalParam(Ifilename) != ""} \
		{

		# Create a new window with a progress gauge
		# and prevent user from accessing main window
		# during the data transfer.

		toplevel .pbw
		wm title .pbw "Writing to IC-R75"
		grab set .pbw

		set p [MakeWaitWindow .pbw.g 1 PaleGreen]
	
		Memories2Radio $p

		# Zap the progress bar window.
		grab release .pbw
		destroy .pbw

			# warning: Font is ugly
			# tk_messageBox -icon info \
				# -message "Transfer Complete"

		tk_dialog .wpbr "Write to IC-R75" \
			"Transfer Complete" info 0 OK

		return
		}
}
##########################################################
# Format and write memory data to the radio.
# Data has previously been stored in global arrays.
##########################################################
proc Memories2Radio { g } \
{
	global AntennaArray
	global AttenArray
	global Bw
	global CancelXfer
	global ChArray
	global FilterArray
	global FreqArray
	global LabelArray
	global Mode
	global ModeArray
	global PreampArray
	global SelectArray
	global Sid
	global StepArray


	set keylist [ array names ChArray ]
	set keylist [ lsort -dictionary $keylist ]

	set n [ llength $keylist ]
	set i 0

	foreach key $keylist \
		{
		update
		if {$CancelXfer} then {break}
		if {$key == "" } then {continue}
		if {$ChArray($key) != 1 } then {continue}

		set lst [split $key ","]
		set ch [lindex $lst 0]

		set s [EncodeAChannel $ch \
			$FreqArray($key) \
			$ModeArray($key) \
			$FilterArray($key) \
			$LabelArray($key) \
			$SelectArray($key) \
			$PreampArray($key) \
			$AttenArray($key) \
			$AntennaArray($key) ]


		# Write memory channel info to radio.
		WriteAChannel $s
 
		incr i
		set pc [ expr $i * 100 / $n ]
		gauge_value $g $pc
		}

	return
}


###################################################################
# Read S meter value from radio and update the S meter widget.
#
# This sequence repeats continuously whenever a callback
# is not running.
###################################################################
proc PollSmeter {} \
{
	global BlinkToggle
	global ChanLabel
	global CurrentFreq
	global GlobalParam
	global Label
	global LabelLabel
	global RBw
	global RMode
	global ScanCounter
	global SignalLabel

	waiter 100

	set ScanCounter 0

	while {1} \
		{

		# Let events happen for a while.
		after $GlobalParam(DisplayUpdateInterval) [list set imdone 1]
		vwait imdone

		set signal [ReadSquelchStatus]

		# If signal present

		if {$signal} \
			{
			# SetVolume

			# Read the radio freq and
			# update the display widget.

			UpdDisplay

			# Read the S-meter
			ReadSmeter
			set m [ReadMode]

			set bw [string range $m 2 3]
			set GlobalParam(Bw) $RBw($bw)

			set m [string range $m 0 1]

			updateMeter $GlobalParam(Smeter)

			SetSlideRuleDial
			RestoreDisplay
			RestoreSlideRuleDial

			set m $RMode($m)
			set GlobalParam(Mode) $m

			# Illuminate signal lamp.
			$SignalLabel configure -text "SIGNAL"

			# If we are scanning and are supposed to stop
			# forever when we find a signal, and we
			# have found a signal ...

			# Note: The VSC takes precedence
			# over the Resume setting sometimes.
			# so the radio
			# will resume scanning after if hears a
			# signal even if the Resume is set to infinite
			# if VSC is enabled.
			# Since the radio's behavior is not consistent,
			# we will force consistency and make the
			# scan halt if the resume setting is
			# infinite.

			if { $GlobalParam(ScanFlag) \
				&& ($GlobalParam(Resume) == "infinite")}\
				{
				# Stop the scan.
				StopScan
				set GlobalParam(ScanFlag) 0
				$ChanLabel configure -text "VFO"
				}
			} \
		else \
			{
			# No signal.
			set GlobalParam(LastHit) 0

			if {$GlobalParam(ScanFlag)} \
				{
				# We are scanning and there is
				# no signal so blank out the
				# frequency display because
				# we don't know the frequency
				# the radio is tuned to a this
				# instant.

				BlankDisplay
				BlankSlideRuleDial
				$LabelLabel configure -text " "
				} \
			else \
				{
				# Not scanning.
				# Read the radio freq and
				# update the display widget.

				UpdDisplay
				SetSlideRuleDial
				RestoreDisplay
				RestoreSlideRuleDial
				}
			# Extinguish signal lamp.
			$SignalLabel configure -text " "

			# Zero the S meter
			set GlobalParam(Smeter) 0
			updateMeter $GlobalParam(Smeter)

			}

		if {$GlobalParam(ScanFlag) && ($signal == 0)} \
			{
			# Don't bother to poll the S meter
			# if there is no
			# signal while we are scanning.

			# Zero the S meter
			set GlobalParam(Smeter) 0
			updateMeter $GlobalParam(Smeter)

			set ty $GlobalParam(ScanType)
			} \
		else \
			{
			# Signal present or not scanning.
			# ReadSmeter
			# updateMeter $GlobalParam(Smeter)
			}

		if {$GlobalParam(ScanFlag) && $signal} \
			{
			# Signal present and scanning.


			if {$GlobalParam(LastHit) != $CurrentFreq} \
				{
				# Xmsn started on a new freq.

				if { $GlobalParam(AutoLogging) == "on"} \
					{
					LogTransmission  
					}
				set GlobalParam(LastHit) $CurrentFreq
				}
			}

		if {$GlobalParam(ScanFlag)} \
			{

			incr ScanCounter
			set ScanCounter \
				[expr {fmod ($ScanCounter, 3)}]
			set ScanCounter \
				[expr {round ($ScanCounter)}]
#			puts stderr "$ScanCounter"
			if { [info exists BlinkToggle] == 0} \
				{
				set BlinkToggle 0
				}
			if {$BlinkToggle} \
				{
				set BlinkToggle 0
				$ChanLabel configure -text $GlobalParam(ScanType)
				} \
			else \
				{
				set BlinkToggle 1
				$ChanLabel configure -text " "
				}
			}
		}
}


###################################################################
# Adjust the volume based on the designated volume control.
#
# Note:
#	To save time, we will not send a volume command to
#	be sent to the radio if the volume is already at the
#	desired level.
###################################################################

proc SetVolume { {val 0} } \
{
	global GlobalParam

	SetAF $GlobalParam(Volume1)


	return
}

###################################################################
# Meter widget adapted from
# Bob Techentin's code.
###################################################################
proc updateMeter {v} \
{
	global MeterFrame

	# set meterht 75
	set meterht 50
	set min 0
	set max 255.0
 
	set pos [expr {$v / $max}]
	set x [expr {$meterht - $meterht * .9*(cos($pos*3.14))}]
	set y [expr {$meterht - $meterht * .9*(sin($pos*3.14))}]
	$MeterFrame.c coords meter $meterht $meterht $x $y
}
###################################################################
# Create a meter widget
#
# Variables:
#	max 	-the highest amplitude of what we will measure
#	meterht	-meter height in pixels
###################################################################
proc MakeMeter { } \
{
	global MeterFrame
	global Sunits2Db

	set max 255.0
	set meterht 50
	# set meterht 75
	set meterwidth [expr {$meterht * 2.0}]

	set f $MeterFrame
	frame $f -relief sunken -borderwidth 10 

	set meterhtplus [expr {$meterht * 1.1}]
	grid [canvas $f.c -width $meterwidth -height $meterhtplus \
		-borderwidth 1 -relief sunken -background white]

	# Calculate endpoints for the arc.

	set m10 [expr {$meterht * .1}]
	set m190 [expr {$meterwidth - $m10}]

	$f.c create arc $m10 $m10 $m190 $m190 \
		-extent 160 \
		-start 10 -style arc -outline black -width 2

	$f.c create line $meterht $meterht $m10 $meterht \
		-tag meter -width 2 \
		-fill red

	# Draw meter calibrations.
	set ndivs [ expr {$max / 24} ]
	for {set i 0} {$i <= $ndivs} {incr i}\
		{
		if {$i == 0} {continue}
		set pos [expr {$i * 24 / $max}]

		set x [expr {$meterht - $meterht \
			* .75 *(cos($pos*3.14))}]
		set y [expr {$meterht - $meterht \
			* .75 *(sin($pos*3.14))}]

		# Scale is 0 - 10 units.

		$f.c create text $x $y -text $i \
			-justify center \
			-fill black \
			-font {Courier 10 normal}
		}
	set ylogo [expr {.7 * $meterht}]
	$f.c create text $meterht $ylogo -text "tk75" \
		-justify center \
		-fill blue \
		-font {Courier 10 bold}
	return $f
}

###################################################################
# Create a Keypad.
# This is based on a calculator program by Richard Suchenwirth.
###################################################################
proc MakeKeyPad {f} \
{
	global Enw

	frame $f -relief raised -borderwidth 10
	set Enw [entry $f.e -width 12 -textvar e \
		-just right -background white]
	grid $Enw -columnspan 3 
	bind $f.e <Return> {Ekey mhz}


	set hint ""
	set hint [append hint "You can enter a new frequency\n"]
	set hint [append hint "(in kHz or MHz) by using\n"]
	set hint [append hint "the simulated keypad."]
	balloonhelp_for $f $hint


	set n 0
	foreach row {
		{7 8 9 }
		{4 5 6 }
		{1 2 3 }
		{C 0 . }
		{ MHz kHz Spc }
		} {
		foreach key $row {
			switch -- $key {
				MHz   {set cmd {Ekey mhz}}
				kHz   {set cmd {Ekey khz}}
				C       {set cmd {set clear 1; set e ""}}
				Spc    {set cmd {Speak}}
				default {set cmd "Hit $f $key"}
				}
			lappend keys [button $f.[incr n] \
				-text $key \
				-width 3 \
				-command $cmd]
			}
		eval grid $keys -sticky we -padx 1 -pady 1
		set keys [list]
		}

	# grid $f.$n -columnspan 3 ;# make last key (E) triple wide
	return $f
}

proc Ekey { units }\
{
	global Enw
	global Bwpot
	global CurrentFreq
	global GlobalParam
	global Readout

	# Calculate the length of string entered.
	set elen [ string length $::e ]
	set tmp $::e


	# Trim leading spaces or zeros.
	regsub {^[ 0]*} $::e "" $tmp
	set CurrentFreq $tmp



	if { [CheckFreqValid $CurrentFreq $units] } then \
		{
		if { $units == "khz" } \
			{
			set CurrentFreq [ expr { double($CurrentFreq) \
				/ double(1000) } ]
			}
		set CurrentFreq [FormatFreq $CurrentFreq ]
		set hz [expr {$CurrentFreq * 1000000}]
		set hz [expr {round($hz)}]
		SetFreq $hz
		set GlobalParam(PreviousFreq) $CurrentFreq

		SetSlideRuleDial
		Add2History

		} \
	else \
		{
		# Invalid frequency.
		bell
		set CurrentFreq $GlobalParam(PreviousFreq)
		set CurrentFreq [FormatFreq $CurrentFreq ]
		}

	# Clear the string entered in the local entry box.
	$Enw delete 0 $elen
	return
 }
 
proc Hit {f key} \
{
	if $::clear {
		set ::e ""
		if ![regexp {[0-9().]} $key] {set ::e $::res}
		$f.e config -fg black
		$f.e icursor end
		set ::clear 0
		}
	$f.e insert end $key
}
set clear 0

###################################################################
# Return 1 if frequency is in range 0 - 2000 exclusive.
###################################################################
proc FreqInRange { f units } \
{
	if {$units == "mhz" } \
		{
		if { $f > 0 && $f < 2000.0 } \
			{
			return 1
			}
		} \
	elseif {$units == "khz" } \
		{
		if { $f > 0 && $f < 2000000.0 } \
			{
			return 1
			}
		}
	return 0
}

###################################################################
# Return 1 if string 's' is a valid frequency.
# Return 0 otherwise.
#
# Units should be khz or mhz
###################################################################
proc CheckFreqValid { s units }\
{
	if {$s == ""} then {return 0}

	# Check for non-digit and non decimal point chars.
	set rc [regexp {^[0-9.]*$} $s]
	if {$rc == 0} then {return 0}


	# All digits.
	set rc [regexp {^[0-9]*$} $s]
	if {$rc == 1} \
		{
		return [FreqInRange $s $units]
		}

	if {$s == "."} then {return 0}

	# Check for Two or more decimal points
	set tmp $s
	set tmp [split $s "."]
	set n [llength $tmp]
	if { $n >= 3 } then {return 0}
	
	return [FreqInRange $s $units]
}


###################################################################
# Format a channel label
###################################################################
proc FormatChan { ch } \
{
	set tmp [format "Ch %3d" $ch ]
	return $tmp
}

###################################################################
# Format a frequency into the proper
# floating point representation for display, i.e.,
#	4 digits . 6 digits
###################################################################
proc FormatFreq { freq } \
{
	set tmp [format "%11.6f" $freq ]
	return $tmp
}


###################################################################
# Set default receiver parameters
###################################################################
proc SetUp { } \
{
	global env
	global GlobalParam
	global RootDir
	global tcl_platform


	if { [regexp "Darwin" $tcl_platform(os) ] } \
		{
		# For Mac OS X.
		set RootDir ":"
		} \
	else \
		{
		set RootDir "/"
		}

	set GlobalParam(Debug) 0
	# set GlobalParam(Device) /dev/ttyS1
	set GlobalParam(Ifilename) {}
	set GlobalParam(MemoryFileDir) $RootDir
	set GlobalParam(PreviousFreq) 0.0

	return
}



###################################################################
# Read frequencies/labels from the label file.
#
# Strip off comments.
# Strip out blank and empty lines.
#
# Remaining lines should be of the form:
#
# freq=label
###################################################################

proc ReadLabel { } \
{
	global env
	global Label
	global LabelFile
	global Mode
	global RootDir


	if [ catch { open $LabelFile "r"} fid] \
		{
		# error
		# Tattle "Cannot open $LabelFile for reading."
		return
		} 


	# For each line in the file.

	while { [gets $fid rline] >= 0 } \
		{
		set line $rline

		# Discard comments.
		regsub {#.*} $line "" line

		# Skip blank line.
		if { [regexp {^ *$} $line] } \
			{
			continue
			}

		set line [string trimleft $line " "]

		# Valid parameter line must be of the form:
		# Fieldname=value

		set plist [ split $line "=" ]
		set n [llength $plist]

		set msg [format "Error in label file %s,\n" $LabelFile]
		set msg [append msg [format "in this line:\n%s" $rline]]

		if {$n != 2} \
			{
			tk_dialog .error "tk75" \
				$msg error 0 OK

			exit 1
			}
		set field [ lindex $plist 0 ]
		set value [ lindex $plist 1 ]
		set Label($field) $value
		}


	close $fid
	return
}

###################################################################
# Save freq/label correspondence in the label file.
###################################################################

proc SaveLabel { } \
{
	global env
	global GlobalParam
	global LabelFile
	global Label
	global Version

	if [ catch { open $LabelFile "w"} fid] \
		{
		# error
		tk_dialog .error "tk75" \
			"Cannot save labels in file $LabelFile" \
			error 0 OK

		return
		} 

	puts $fid "# tk75 label file, Version $Version"

	set a [array names Label]
	set a [ lsort -dictionary $a ]

	foreach x $a \
		{
		puts $fid "$x=$Label($x)"
		}

	close $fid
	return
}


###################################################################
# Start or stop frequency slewing (autotune).
#
# Inputs:
#	ts	-frequency increment in kHz
#	updown	-direction up or down
###################################################################
proc StartSlew { ts updown }\
{
	global GlobalParam

	set GlobalParam(Slewing) 1;
	SetTS $ts
 
	if { $updown == "down" } \
		{
		set amount [ expr { -1 * $ts / 1000000.0 } ]
		} \
	else \
		{
		set amount [ expr { $ts / 1000000.0 } ]
		}

	while { $GlobalParam(Slewing) } \
		{
		Qsy $amount
		waiter $GlobalParam(SlewSpeed)
		}

	return
}


###################################################################
# Explain to user that he cannot scan memory channels
# until he opens a memory data file.
###################################################################
proc CannotScan {} \
{
	set msg ""
	set msg [append msg "You must open a memory data "]
	set msg [append msg "file before scanning."]

	tk_dialog .noscan "Memory scan" $msg warning 0 OK

	return
}

###################################################################
# Add a frequency and mode to the history list and
# timestamp the entry.
#
# Each entry is assigned a unique, sequential number, starting
# at 0.  Once the history list is full, we discard the oldest
# entry and move the remaining entries down one slot.
###################################################################

proc Add2History { } \
{
	global CurrentFreq
	global GlobalParam
	global HistoryTime
	global HistoryFreq
	global HistoryMode
	global HistoryIdx
	global RMode


	# Maximum number of history entries - 1
	set n 99

	if {[ info exists HistoryIdx ] == 0 } \
		{
		set HistoryIdx -1
		}

	incr HistoryIdx

	# If list is full...

	if { $HistoryIdx > $n} \
		{
		# Overlay the oldest entry and move each
		# remaining entry down one slot.

		for {set i 0} { $i < $n} {incr i} \
			{
			set ip1 [expr {$i + 1}]
			set HistoryTime($i) $HistoryTime($ip1)
			set HistoryFreq($i) $HistoryFreq($ip1)
			set HistoryMode($i) $HistoryMode($ip1)
			}
		set HistoryIdx $n
		}
	set seconds [clock seconds]
	set HistoryTime($HistoryIdx) [clock format $seconds \
		-format {%T}]
	set HistoryFreq($HistoryIdx) $CurrentFreq

	set mode $GlobalParam(Mode)
	set HistoryMode($HistoryIdx) $mode

	RefreshHistory

	return
}
###################################################################
# Create an analog style slide rule dial using a scale widget.
# The scale and reading is adjusted by the SetSlideRuleDial
# procedure as the user tunes the radio.
###################################################################

proc MakeSlideRule { f }\
{
	global CurrentFreq
	global DialFreq
	global GlobalParam

	global SlideRule
	frame $f -background ""


	scale $f.d -from 0 -to 30 -showvalue yes \
		-orient horizontal \
		-width 6 \
		-sliderlength 6 -resolution 1 \
		-tickinterval 10 \
		-troughcolor white \
		-background black -foreground white \
		-activebackground red \
		-variable DialFreq \
		-state disabled

	set SlideRule $f.d

	if {$GlobalParam(ViewSlideRule) == "on"} \
		{
		pack $f.d -padx 0 -pady 0 -expand yes -fill x
		}

	return $f
}
###################################################################
# Update the slide rule tuning dial widget to show the
# frequency according to the global variable CurrentFreq.
###################################################################

proc SetSlideRuleDial {} \
{
	global CurrentFreq
	global DialFreq
	global SlideRule

	set lowlim [expr {floor($CurrentFreq)}]
	set hilim  [expr {ceil($CurrentFreq)}]


	if {$hilim == $lowlim} \
		{
		# We are tuned to a band edge.
		set hilim [ expr {$lowlim + 1.0}]
		}


	$SlideRule configure -from $lowlim -to $hilim \
		-showvalue yes -tickinterval .1 \
		-state disabled \
		-resolution .001 

	$SlideRule set $CurrentFreq
	set DialFreq $CurrentFreq

	update

	return
}

###################################################################
# This proc is not used currently.
###################################################################
proc TuneBySlideRule {f} \
{
	set CurrentFreq [FormatFreq $f ]
	set hz [expr {$CurrentFreq * 1000000}]
	set hz [expr {round($hz)}]
	SetFreq $hz
	set GlobalParam(PreviousFreq) $CurrentFreq

	UpdDisplay
	update
	return
}


proc DecodeAChannel {line ch} \
{
	global RBw
	global RMode
	global RTs

	if { [string length $line] == 0 } \
		{
		# Empty channel
		set lst [list 0 am empty 0]
		return $lst
		}

	# Extract frequency digit pairs. They are BCD in reversed order.
	set f [BCD2Freq $line 5]

	set alabel [string range $line 15 22]

	set mode [string range $line 10 10]
	binary scan $mode "H*" mode
#	puts "DecodeAChanel: mode is $mode"


	if {[info exists RMode($mode)]} \
		{
		set amode $RMode($mode)
		} \
	else \
		{
		set amode "?"
		}

	set filter [string range $line 11 11]
	binary scan $filter "H*" filter
	# regsub {^0} $filter "" filter
	if {[ info exists RBw($filter) ] == 0 } \
		{
		set filter ?
		} \
	else \
		{
		set filter $RBw($filter)
		}

	

	set scn [string range $line 4 4]
	binary scan $scn "H*" scn

	set select ""

	if { $scn == "00" } \
		{
		set select ""
		} \
	elseif { $scn == "01" } \
		{
		set select "select"
		}

	set atten [string range $line 12 12]
	binary scan $atten "H*" atten
	regsub {^0} $atten "" atten

	set preamp [string range $line 13 13]
	binary scan $preamp "H*" preamp
	regsub {^0} $preamp "" preamp

	# Translate antenna from 0,1 to 1,2.

	set ant [string range $line 14 14]
	binary scan $ant "H*" ant
	regsub {^0} $ant "" ant
	incr ant


	# puts stderr [format "%s %s %s %s" $f $alabel $amode $scn]
	set lst [list $f $amode $filter $alabel $select $preamp \
		$atten $ant]
	return $lst
}

###################################################################
# Decode a BCD frequency.
#
# Returns:	frequency in MHz
###################################################################

proc BCD2Freq { line start } \
{
	# Frequency digit pairs are reversed.

	set i $start

	set f5 [string index $line $i]
	binary scan $f5 "H*" f5
	incr i

	set f4 [string index $line $i]
	binary scan $f4 "H*" f4
	incr i

	set f3 [string index $line $i]
	binary scan $f3 "H*" f3
	incr i

	set f2 [string index $line $i]
	binary scan $f2 "H*" f2
	incr i

	set f1 [string index $line $i]
	binary scan $f1 "H*" f1
	incr i

	set f [format "%s%s%s%s%s" $f1 $f2 $f3 $f4 $f5]
	set f [string trimleft $f 0]

	if { $f == ""} \
		{
		set f 0.0
		}

	set f [expr {$f/1000000.0}]
	return $f
}

###################################################################
# Encode frequency into BCD format.
#
# Inputs:	frequency in Hz
# Returns:	frequency in BCD format with digit bytes reversed.
###################################################################

proc Freq2BCD { f } \
{
	# Convert frequency to a 10 digit integer in Hz.

	set f [expr {int($f)}]
	set f [ PadLeft0 10 $f ]

	# Frequency digit pairs are reversed.

	set bf ""

#	puts stderr "from Freq2BCD, f = $f"

	set dpair [string range $f 8 9]
	set bf [ append bf [binary format "H2" $dpair] ]

	set dpair [string range $f 6 7]
	set bf [ append bf [binary format "H2" $dpair] ]

	set dpair [string range $f 4 5]
	set bf [ append bf [binary format "H2" $dpair] ]

	set dpair [string range $f 2 3]
	set bf [ append bf [binary format "H2" $dpair] ]

	set dpair [string range $f 0 1]
	set bf [ append bf [binary format "H2" $dpair] ]

	return $bf
}


###################################################################
# Encode memory channel parameters into a single binary string.
#
# Notes:
#	mode argument must be alphabetic, e.g, FM
###################################################################
proc EncodeAChannel { ch mhz mode filter lab sel preamp atten antenna} \
{
	global Bw
	global Mode

	set ich [ PadLeft0 4 $ch ]
	# set ich [ xCh2BCD $ch ]

	set freq [ expr 1000000 * $mhz ]
	set freq [ expr round($freq) ]
	set bcdfreq [ Freq2BCD $freq ]


	# Get numeric mode and pad it with zeroes.
	set mode $Mode($mode)
	set mode [ PadLeft0 2 $mode ]

	set atten [PadLeft0 2 $atten]

	if {$sel == ""} \
		{
		set select 00
		} \
	else \
		{
		set select 01
		}

	set label [string range $lab 0 7]
	set label [string toupper $label]

	if { [string length $label] == 7 } \
		{
		if { [regexp {[0-9 ]$} $label] == 0 } \
			{
			set label [string range $label 0 5]
			}
		} \
	elseif { [string length $label] == 8 } \
		{
		if { [regexp {[0-9 ][0-9 ]$} $label] == 0 } \
			{
			set label [string range $label 0 5]
			}
		}
	set label [format "%-8s" $label]

#	puts stderr "EncodeAChannel: lab $lab ==>  $label"



	set filter $Bw($filter)

	if { $antenna == "ANT2" } \
		{
		set antenna 01
		} \
	else \
		{
		set antenna 00
		}

	if {$atten == "ATTEN"} \
		{
		set atten 20
		} \
	else \
		{
		set atten 00
		}
	set preamp [PadLeft0 2 $preamp]

	set s ""
	append s [binary format "H4" $ich]
	# append s $ich
	append s [binary format "H2" $select]
	append s $bcdfreq
	append s [binary format "H2" $mode]
	append s [binary format "H2" $filter]
	append s [binary format "H2" $atten]
	append s [binary format "H2" $preamp]
	append s [binary format "H2" $antenna]
	append s $label

	return $s
}

proc BlankSlideRuleDial {} \
{
	global SlideRule

	$SlideRule configure \
		-state disabled \
		-activebackground black \
		-foreground black \
		-troughcolor black
}

proc RestoreSlideRuleDial {} \
{
	global SlideRule

	$SlideRule configure \
		-state disabled \
		-activebackground red \
		-foreground white \
		-troughcolor white
}

###################################################################
# Setup before scanning
###################################################################
proc PreScan {} \
{
	global ChanLabel
	global BlinkToggle
	global GlobalParam

	set BlinkToggle 1	
	set GlobalParam(ScanFlag) 1	
	$ChanLabel configure -text $GlobalParam(ScanType)

	set ty $GlobalParam(ScanType)

	set GlobalParam(Attenuator) 0
	return
}
###################################################################
# Add a frequency and label to a global cache.
###################################################################
proc Add2LabelCache { f label } \
{
	global Label

	# puts stderr "from Add2LabelCache, f= $f"

	set f [string trimleft $f " "]

	if { ($label != "") && ($f != "") && ($f > 0) } \
		{
		set f [format "%.6f" $f]
		set Label($f) $label
		}
	return
}

###################################################################
# Append a line in csv format to the log file.
#
# Note:
#	The current value of the S-meter will be used,
#	so be sure to read the S-meter from the radio
#	while on the current frequency before calling this
#	procedure.
###################################################################

proc LogTransmission { } \
{
	global CurrentFreq
	global GlobalParam
	global Label
	global Lid
	global Lfilename
	global RMode

	# puts stderr "LogTransmission: entered"

	if { $Lfilename == "" } {return}


	set f [string trimleft $CurrentFreq " "]
	if { [info exists Label($f)] } \
		{
		set label $Label($f)
		} \
	else \
		{
		set label ""
		}

	set seconds [clock seconds]
	set time [clock format $seconds -format {%T}]
	set date [clock format $seconds -format {%Y/%m/%d}]

	regsub -all " " $label "_" label

	# Scale the signal strength reading from 0 - 256
	# to 0 - 10.

	set smeter [expr { $GlobalParam(Smeter) / 25.6 } ]

	set s [format "%s,%s,%s,%s,%.2f,\"%s\"" \
		$date $time $f \
		$GlobalParam(Mode) $smeter $label]

	if { [catch {puts $Lid $s}] } \
		{
		bell
		tk_dialog .logfilerror "Log file error" \
			"Cannot write to log file." error 0 OK
		} \
	else \
		{
		catch {flush $Lid}
		}
	return
}


###################################################################
# Create a Mode label 
#
# The text displayed on the menu button will be changed
# as the mode changes to it reflects the current reception mode.
#
# Inputs:
#	f	-name of frame to create
#	lw	-width of frame to create
###################################################################
proc MkModeLabel { f lw } \
{
	global GlobalParam
	global Mode;
	global RBw;
	global RMode;

	frame $f -relief flat -borderwidth 0


	label $f.labmode -textvariable GlobalParam(Mode) \
		-background black -foreground orange \
		-width $lw

	pack $f.labmode -side top

	return $f
}


###################################################################
# Create a BandWidth pulldown menu 
# and radiobutton widgets for all reception modes.
#
# The text displayed on the menu button will be changed
# as the bw changes to it reflects the current reception bandwidth.
#
# Inputs:
#	f	-name of frame to create
#	lw	-width of frame to create
###################################################################
proc MkBwLabel { f lw } \
{
	global GlobalParam
	global Mode;
	global RBw;
	global RMode;

	frame $f -relief flat -borderwidth 0

	label $f.labbw -textvariable GlobalParam(Bw) \
		-background black -foreground white \
		-width $lw

	pack $f.labbw -side top


	return $f
}

###################################################################
# Make pulldown menu for mode scan
#
# Cannot start a mode scan if we are already scanning apparently.
# (But it would work ok using the radio front panel.)
###################################################################
proc MakeModeScanMenu { f } \
{	
	global GlobalParam
	global ModeScanLabel

	frame $f -relief raised -borderwidth 2

	set ModeScanLabel $f.modescan

	menubutton $f.modescan -text "Mode Scan ..." \
		-menu $f.modescan.m 
	menu $f.modescan.m

	foreach mode {AM SAM USB LSB CW CWR FM RTTY RTTYR} \
		{

		$f.modescan.m add radiobutton \
			-label $mode \
			-variable GlobalParam(ModeScan) \
			-value $mode -command \
				{
				ModeScanCB
				}
		}

	# pack $f.modescan -side top -fill x -expand y
	return $f
}

###################################################################
# Mode Scan Callback
###################################################################
proc ModeScanCB {} \
{
	global ChanLabel
	global GlobalParam
	global ModeScanLabel

	if { ($GlobalParam(ModeScan) != "off")
		&& ( ($GlobalParam(ScanFlag) == 0) \
		|| ($GlobalParam(ScanType) == "Limit Scan") \
		|| ($GlobalParam(ScanType) == "Auto Write Scan") ) } \
		{
		# We are not scanning so do not honor user request.
		DisableModeScan

		set msg "The IC-R75 must be scanning "
		set msg [append msg "in Memory Scan or "]
		set msg [append msg "Select Scan before choosing "]
		set msg [append msg "a Memory Scan mode. "]

		tk_dialog .noscan "Mode Scan info" \
			$msg info 0 OK
		return
		} 

	if {$GlobalParam(ModeScan) != "off"} \
		{
		set GlobalParam(Mode) \
			$GlobalParam(ModeScan)
		SetMode
		set GlobalParam(ScanFlag) 1

		if { [StartModeScan] } \
			{
			# Cannot start mode scan.

			# The radio responded with an error.
			# Cannot do Mode Scan
			# probably because there are not enough
			# memory channels in this mode with the
			# designated mode.


			}
		$ModeScanLabel configure -foreground red
		} \
	else \
		{
		# User turned off mode scan.
		$ChanLabel configure -text "VFO"
		DisableModeScan
		}


	return
}

###################################################################
# Disable Mode Scan within the software,
# though no commands are actually sent to the radio.
###################################################################

proc DisableModeScan { } \
{
	global GlobalParam
	global ModeScanLabel

	set GlobalParam(ModeScan) off
	$ModeScanLabel configure -foreground black

	return
}



###################################################################
# 
# Define receiver parameters before we read the
# global parameter configuration file in case they are missing
# from the configuration file.
# This avoids a tcl error if we tried to refer to an
# undefined variable.
#
# These initial definitions will be overridden with
# definitions from the configuration file.
#
###################################################################

proc PresetGlobals { } \
{
	global GlobalParam
	global Mode
	global Rcfile
	global RootDir
	global tcl_platform

	set GlobalParam(AGC) slow
	set GlobalParam(AMNB) off
	set GlobalParam(Antenna) ANT1
	set GlobalParam(Attenuator) 0
	set GlobalParam(AutoTuningStep) off
	set GlobalParam(BalloonHelpWindows) on
	set GlobalParam(BackGroundColor) ""
	set GlobalParam(Backlight) 66
	set GlobalParam(BClevel) 128
	set GlobalParam(Beep) on
	set GlobalParam(BeepLevelLimit) on
	set GlobalParam(BlankChannelInd) on
	set GlobalParam(BPFenable) on
	set GlobalParam(Bw) MEDIUM
	set GlobalParam(CWPitch) 600
	set GlobalParam(Debug) 0
	set GlobalParam(DisplayUpdateInterval) 500
	set GlobalParam(ExpandedFilters) off
	set GlobalParam(FastScan) on
	set GlobalParam(Font) ""
	set GlobalParam(ForeGroundColor) ""
	set GlobalParam(HighestChannel) 99
	set GlobalParam(LastHit) 0
	set GlobalParam(LogFileDir) $RootDir
	set GlobalParam(LowerLimit) 0
	set GlobalParam(MemoryFileDir) $RootDir
	set GlobalParam(Mode) AM
	set GlobalParam(NB) off
	set GlobalParam(Notch) off
	set GlobalParam(NR) off
	set GlobalParam(NRLevel) 50
	set GlobalParam(Opt4Filter) 00
	set GlobalParam(Opt9Filter) 00
	set GlobalParam(PassBandShift9) 0
	set GlobalParam(PassBandShift4) 0
	set GlobalParam(PowerOffTime) 0000
	set GlobalParam(PowerOffTimerArm) off
	set GlobalParam(PowerOnTime) 0000
	set GlobalParam(PowerOnTimerArm) off
	set GlobalParam(Preamp) 0
	set GlobalParam(PreviousFreq) 10
	set GlobalParam(RecorderRelay) off
	set GlobalParam(Resume) on
	set GlobalParam(RFGain) 255
	set GlobalParam(RFSquelch) 02
	set GlobalParam(RTTYmark) 00
	set GlobalParam(RTTYshift) 00
	set GlobalParam(ScanFlag) 0
	set GlobalParam(ScanType) {}
	set GlobalParam(SearchStep) 1
	set GlobalParam(ShowLabel) off
	set GlobalParam(SleepTime) 0000
	set GlobalParam(SleepTimerArm) off
	set GlobalParam(Slewing) 0
	set GlobalParam(SlewSpeed) 500
	set GlobalParam(Smeter) 0
	set GlobalParam(SmeterPeakHold) on
	set GlobalParam(SpeakFast) on
	set GlobalParam(SpeakJapanese) off
	set GlobalParam(SpeakSmeter) off
	set GlobalParam(SpeakTime) off
	set GlobalParam(Squelch) 0
	set GlobalParam(TroughColor) ""
	set GlobalParam(UpperLimit) 0
	set GlobalParam(ViewHistory) off
	set GlobalParam(ViewSlewButtons) on
	set GlobalParam(ViewSlideRule) on
	set GlobalParam(ViewUpDownButtons) on
	set GlobalParam(Volume1) 50
	set GlobalParam(WeakAM) on

	return
}


###################################################################
# Set global variables after reading the global
# configuration file so these settings override
# whatever values were in the configuration file.
###################################################################

proc OverrideGlobals { } \
{
	global env
	global GlobalParam
	global RootDir
	global tcl_platform


	set GlobalParam(AutoLogging) off
	set GlobalParam(Ifilename) {}
	set GlobalParam(LastHit) ""
	set GlobalParam(ScanFlag) 0
	set GlobalParam(ModeScan) off
	set GlobalParam(PriorityScan) 0
	set GlobalParam(VolumeCurrent) -1

	# Note on MacOS X:
	# The initial directory passed to the file chooser widget.
	# The problem here is that osx's tcl is utterly busted.
	# The _only_ pathname it accepts is ':' - no other ones work.
	# Now this isn't as bad as you might think because
	# the native macos file selector widget persistantly
	# remembers the last place you opened/saved a file
	# for a particular application. So the logic to
	# remember this is simply redundant on macos anyway...
	# Presumably they'll fix this someday and we can take
	# out the hack.
	# - Ben Mesander

	if { [regexp "Darwin" $tcl_platform(os) ] } \
		{
		# kluge for MacOS X.

		set GlobalParam(LogFileDir) $RootDir
		set GlobalParam(MemoryFileDir) $RootDir

		if {$GlobalParam(Ifilename) != ""} \
			{
			set GlobalParam(Ifilename) $RootDir
			}
		}

	return
}


###################################################################
# Create a radiobutton widget for each reception bandwidth.
###################################################################
proc MakeBwSwitch { f } \
{
	global Bw
	global RMode

	frame $f -relief groove -borderwidth 3

	label $f.lab -text Selectivity


	MkBwSel $f.wide  "Wide" WIDE
	MkBwSel $f.inter "Medium" MEDIUM
	MkBwSel $f.narr  "Narrow" NARROW

	SetMode

	pack $f.lab $f.wide $f.inter $f.narr -side top -anchor w

	return $f
}

###################################################################
#
# Create one bandwidth selection radiobutton widget
# named 'w', with text label 't' and value 'val'.
#
###################################################################
proc MkBwSel { w t val } \
{
	global GlobalParam

	radiobutton $w -text $t -variable GlobalParam(Bw) \
		-value $val -command {\
			SetMode
			Add2History
			}
	return
}


###################################################################
# Create a radiobutton widget for each reception mode.
###################################################################
proc MakeModeSwitch { f } \
{
	global Bw
	global RMode

	frame $f -relief groove -borderwidth 3
	label $f.lab -text Mode

	MkModeSel $f.am		"AM"	AM
	MkModeSel $f.sam	"S-AM"	SAM
	MkModeSel $f.usb	"USB"	USB
	MkModeSel $f.lsb	"LSB"	LSB
	MkModeSel $f.cw		"CW"	CW
	MkModeSel $f.cwr	"CW-R"	CWR
	MkModeSel $f.fm		"FM"	FM
	MkModeSel $f.rtty	"RTTY"	RTTY
	MkModeSel $f.rttyr	"RTTY-R"	RTTYR


	pack	\
		$f.lab \
		$f.am \
		$f.sam \
		$f.usb \
		$f.lsb \
		$f.cw \
		$f.cwr \
		$f.fm \
		$f.rtty \
		$f.rttyr \
		-side top -anchor w

	return $f
}

###################################################################
#
# Create one mode selection radiobutton widget
# named 'w', with text label 't' and value 'val'.
#
###################################################################
proc MkModeSel { w t val } \
{
	global GlobalParam

	radiobutton $w -text $t -variable GlobalParam(Mode) \
		-value $val -command {\
			ChangeMode
			Add2History
			}
	return
}


###################################################################
# SyncClock
#
# Set the radio's clock using the computer's time.
#
# Inputs:
#	gmtflag:
#
#	0 - use local time
#	1 - use Greenwich Mean Time 
#
###################################################################
proc SyncClock { gmtflag } \
{
	set nsec [clock seconds]

	set time_now [clock format $nsec -format {%H%M%S} -gmt $gmtflag]

	# puts stderr "SyncClock: PC time now: $time_now"
	SetClock $time_now
	return
}


###################################################################
# Create widgets for Filter selection. 
###################################################################
proc MakeFilterSelectFrame { f }\
{
	global GlobalParam

	ReadFilterConfig

	label $f.lab -text "Filter Selection" -borderwidth 3
	pack $f.lab -side top

	ScrollformCreate $f.s

	set w [ScrollFormInterior $f.s]

	foreach mode { AM SAM SSB CW FM RTTY } \
		{
		label $w.labblank$mode -text "" -borderwidth 3
		label $w.lab$mode -text $mode -borderwidth 3
		label $w.lab9$mode -text "9 MHz IF" -borderwidth 3
		label $w.lab4$mode -text "455 kHz IF" -borderwidth 3

		foreach width { WIDE MEDIUM NARROW } \
			{
			label $w.lab$mode$width -text $width \
				-borderwidth 3
			}
		}

	set row 1
	set incrow 3

	foreach mode { AM SAM SSB CW FM RTTY } \
		{
		grid $w.labblank$mode -row $row -column 0 -sticky w
		incr row 1

		grid $w.lab$mode -row $row -column 0 -sticky w
		grid $w.lab9$mode -row $row -column 2 -sticky w
		grid $w.lab4$mode -row $row -column 3 -sticky w

		incr row 1

		foreach width { WIDE MEDIUM NARROW } \
			{
			MkFilterMenu9 $w.menu9$mode$width $mode $width
			MkFilterMenu4 $w.menu4$mode$width $mode $width

			grid $w.lab$mode$width -row $row -column 1 \
				-sticky w

			grid $w.menu9$mode$width -row $row -column 2 \
				-sticky ew

			grid $w.menu4$mode$width -row $row -column 3 \
				-sticky ew

			incr row 1
			}
		}

	pack $f.s -expand yes -fill both -padx 3 -pady 3

	frame $f.b -relief flat -borderwidth 3
	set b $f.b

	button $b.apply -text "Apply" \
		-command { WriteFilterConfig; catch {destroy .filters} }

	button $b.cancel -text "Cancel" \
		-command { catch {destroy .filters} }

	pack $b.apply $b.cancel -side left -padx 3 -pady 3

	pack $b -side top -padx 3 -pady 3

	return $f
}

proc MkFilterMenu4 { f mode width } \
{
	tk_optionMenu $f GlobalParam(Filter4,$mode,$width) \
		15kHz 6kHz "3.3kHz" "2.8kHz" "2.4kHz" "1.8kHz" \
		500Hz 250Hz	

	return
}

proc MkFilterMenu9 { f mode width } \
{
	tk_optionMenu $f GlobalParam(Filter9,$mode,$width) \
		15kHz "2.8kHz" "2.4kHz" "1.9kHz" 500Hz \
		350Hz 250Hz OFF	

	return
}
###################################################################
# Write the user's filter choices for each mode to the radio.
###################################################################
proc WriteFilterConfig { } \
{
	global Filter4
	global Filter9
	global GlobalParam

	# puts stderr "WriteFilterConfig: going to validate filters"
	if {[ValidateFilters]} \
		{
		# Trying to configure non installed filter.
		return
		}
	foreach mode { AM SAM SSB CW FM RTTY } \
		{
		set s ""

		set t $GlobalParam(Filter9,$mode,MEDIUM)
		set t $Filter9($t)
		# append s [binary format "H2" $t]
		append s $t

		set t $GlobalParam(Filter4,$mode,MEDIUM)
		set t $Filter4($t)
		append s $t

		set t $GlobalParam(Filter9,$mode,NARROW)
		set t $Filter9($t)
		append s $t

		set t $GlobalParam(Filter4,$mode,NARROW)
		set t $Filter4($t)
		append s $t

		set t $GlobalParam(Filter9,$mode,WIDE)
		set t $Filter9($t)
		append s $t

		set t $GlobalParam(Filter4,$mode,WIDE)
		set t $Filter4($t)
		append s $t

#		puts stderr "WriteFilterConfig: mode $mode , s $s"
		WriteFilter $mode $s
		}
	return
}

###################################################################
# Read the current filter choices for each mode from the radio.
###################################################################
proc ReadFilterConfig { } \
{
	global GlobalParam
	global RFilter4
	global RFilter9

	foreach mode { AM SAM SSB CW FM RTTY } \
		{
		set s [ReadFilter $mode]

		set t [string range $s 0 1]
		set t $RFilter9($t)
		set GlobalParam(Filter9,$mode,MEDIUM) $t
			
		set t [string range $s 2 3]
		set t $RFilter4($t)
		set GlobalParam(Filter4,$mode,MEDIUM) $t
			
		set t [string range $s 4 5]
		set t $RFilter9($t)
		set GlobalParam(Filter9,$mode,NARROW) $t
			
		set t [string range $s 6 7]
		set t $RFilter4($t)
		set GlobalParam(Filter4,$mode,NARROW) $t
			
		set t [string range $s 8 9]
		set t $RFilter9($t)
		set GlobalParam(Filter9,$mode,WIDE) $t
			
		set t [string range $s 10 11]
		set t $RFilter4($t)
		set GlobalParam(Filter4,$mode,WIDE) $t
			
		}
	return
}

###################################################################
# Check of the user has chosen to configure optional filters
# but has not specified that they are installed.
#
# Returns:
#	0 -on
#	1 -error, trying to configure filters not installed
#
###################################################################
proc ValidateFilters { } \
{
	global GlobalParam

	foreach m { AM SAM SSB CW FM RTTY } \
		{
		foreach w { MEDIUM NARROW WIDE } \
			{
			set f9 $GlobalParam(Filter9,$m,$w)
			if {$f9 == "OFF"} \
				{
				continue
				}
			if {$GlobalParam(Opt9Filter) == "00"} \
				{
				if {($f9 != "15kHz") \
					&& ($f9 != "2.4kHz")} \
					{

					# No 9 MHz IF opt filter is
					# installed, but user trying
					# to configure one.

					set msg "You cannot configure "
					append msg "the optional $f9 "
					append msg "9 MHz IF filter "
					append msg "until you mark the "
					append msg "checkbox that it "
					append msg "is installed in "
					append msg "the radio."

					tk_dialog .error \
						"tk75 missing filter" \
						"$msg" \
						error 0 OK

					return 1
					}
				}

			set f4 $GlobalParam(Filter4,$m,$w)
			if {$f4 == "OFF"} \
				{
				continue
				}

			if {$GlobalParam(Opt4Filter) == "00"} \
				{
				if {($f4 == "15kHz") \
					|| ($f4 == "6kHz") \
					|| ($f4 == "2.4kHz")} \
					{
					continue
					}

				# No 455 kHz IF opt filter is installed,
				# but user trying to configure one.

				set msg "You cannot configure the "
				append msg "optional $f4 455 kHz "
				append msg "IF filter until you mark "
				append msg "the checkbox that it is "
				append msg "installed in the radio."

				tk_dialog .error "tk75 missing filter" \
					"$msg" \
					error 0 OK
				return 1

				}
			}
		}
	
	return 0
}
###################################################################
# Set a timer value.
#
# NOTE:
#	The IC-R75 will not change the value of a sleep timer
#	once it has been armed even though it will issue
#	a positive ack to a command to set the timer value.
###################################################################

proc MakeConfigureTimerFrame { f lbl which code } \
{
	global GlobalParam
	global TimerCode
	global WhichVar

	set WhichVar $which
	set TimerCode $code

	# Read timer value from radio.
	set GlobalParam($which) [ReadTimer $code]

	append lbl " (HHMM)"
	label $f.lab -text $lbl -borderwidth 3

	if { ($which == "SleepTime") \
		&& ($GlobalParam(SleepTimerArm) == "on") } \
		{
		# Do not let user change sleep time value
		# if Sleep Timer is armed.

		label $f.ent -text $GlobalParam($which) -borderwidth 3
		} \
	else \
		{
		entry $f.ent -width 8 \
			-textvariable GlobalParam($which) \
			-background white 
		}

	pack $f.lab $f.ent -side top

	frame $f.b -relief flat -borderwidth 3
	set b $f.b

	button $b.apply -text "Apply" -command \
		{
		global TimerCode
		global WhichVar

		SetTweak2 $TimerCode $GlobalParam($WhichVar) 2

		catch {destroy .ctimer}
		}

	button $b.cancel -text "Cancel" -command \
		{
		catch {destroy .ctimer}
		}

	pack $b.apply $b.cancel -side left -padx 3 -pady 3

	pack $b -side top -padx 3 -pady 3

	return $f
}
