###################################################################
# This file is part of tk545, a control program for the
# Japan Radio Corp. NRD-545 receiver.
# 
#    Copyright (C) 2001, 2002, Bob Parnass
# 
# tk545 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.
# 
# tk545 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 tk545; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
# 02111-1307  USA
###################################################################


set NBanks		10
set NChanPerBank	100
set VNChanPerBank	100
set ChanNumberRepeat	no
set HasLabels		yes

set Mode(rtty) "0"
set Mode(cw) "1"
set Mode(usb) "2"
set Mode(lsb) "3"
set Mode(am) "4"
set Mode(fm) "5"
set Mode(ams) "6"
set Mode(eccs/u) "7"
set Mode(eccs/l) "8"
set Mode(wfm) "9"

set RMode(0) rtty
set RMode(1) cw
set RMode(2) usb
set RMode(3) lsb
set RMode(4) am
set RMode(5) fm
set RMode(6) ams
set RMode(7) "eccs/u"
set RMode(8) "eccs/l"
set RMode(9) wfm

set Bw(narr) "2"
set Bw(inter) "1"
set Bw(wide) "0"

set RBw(2) narr
set RBw(1) inter
set RBw(0) wide

set Sunits2Db(1) 1
set Sunits2Db(2) 3
set Sunits2Db(3) 5
set Sunits2Db(4) 7
set Sunits2Db(5) 9
set Sunits2Db(7) {+25}
set Sunits2Db(8) {+40}
set Sunits2Db(9) {+55}

# Tuning step sizes
set Tstep(1) V0
set Tstep(10) V1
set Tstep(100) V2
set Tstep(1000) V3
set Tstep(10000) V4
set Tstep(100000) V5

##########################################################
# Open the serial port.
# Notes:
#	This procedure sets the global variable Sid.
#
# Returns:
#	"" -ok
#	else -error message
##########################################################

proc OpenDevice {} \
{
	global Pgm
	global GlobalParam
	global Sid
	global tcl_platform


	 set platform $tcl_platform(platform) 
	 switch -glob $platform \
		{
		{unix} \
			{
			set Sid [open $GlobalParam(Device) "r+"]
			}
		{macintosh} \
			{
			set Sid [open $GlobalParam(Device) "r+"]
			}
		{windows} \
			{
			set Sid [open $GlobalParam(Device) RDWR]
			}
		default \
			{
			set msg "$Pgm error: Platform $platform not supported."
			Tattle $msg
			return $msg
			}
		}


	# Set up the serial port parameters (similar to stty)
	if [catch {fconfigure $Sid -mode 4800,n,8,1 -blocking 1}] \
		{
		set msg "$Pgm error: "
		set msg [append msg "Cannot configure serial port\n"]
		set msg [append msg "$GlobalParam(Device)"]
		Tattle $msg
		return $msg
		}
	return "" 
}
##########################################################
#
# Initialize a few global variables.
#
# Inputs: basename of configuration file
#
#
# Returns:
#	list of 2 elements:
#		-name of configuration file
#		-name of label file
#
##########################################################
proc InitStuff { } \
{
	global argv0
	global DisplayFontSize
	global env
	global Home
	global Pgm
	global RootDir
	global tcl_platform


	set platform $tcl_platform(platform) 
	switch -glob $platform \
		{
		{unix} \
			{
			set Home $env(HOME)
			set rcfile [format "%s/.tk545rc" $Home]
			set labelfile [format "%s/.tk545la" $Home]

			set DisplayFontSize "Courier 56 bold"
			}
		{macintosh} \
			{

			# Configuration file should be
			# named $HOME/.tk545rc

			# Use forward slashes within Tcl/Tk
			# instead of colons.

			set Home $env(HOME)
			regsub -all {:} $Home "/" Home
			set rcfile [format "%s/.tk545rc" $Home]
			 set labelfile [format "%s/.tk545la" $Home]

			# The following font line may need changing.
			set DisplayFontSize "Courier 56 bold"
			}
		{windows} \
			{

			# Configuration file should be
			# named $tk545/tk545.ini
			# Use forward slashes within Tcl/Tk
			# instead of backslashes.

			set Home $env(tk545)
			regsub -all {\\} $Home "/" Home
			set rcfile [format "%s/tk545.ini" $Home]
			set labelfile [format "%s/tk8500.lab" $Home]

			set DisplayFontSize "Courier 28 bold"
			}
		default \
			{
			puts "Operating System $platform not supported."
			exit 1
			}
		}
	set Home $env(HOME)
	# set Pgm [string last "/" $argv0]

	set lst [list $rcfile $labelfile]
        return $lst
}

###################################################################
# Enable computer control of radio.
###################################################################
proc EnableCControl { } \
{

	global Sid

	SendCmd $Sid "H1"
	after 1000
	return
}

###################################################################
# Disable computer control of radio.
###################################################################
proc DisableCControl { } \
{
	global Sid

	SendCmd $Sid "H0"
	after 500

	close $Sid
	return
}

###################################################################
# Read radio memories.
###################################################################
proc ReadMem { g } \
{
	global GlobalParam
	global Sid

	set data ""

	SendCmd $Sid "L000999"

	after 1000

	set n 1000
	set pc 0
	set line ""
	for {set i 0} {$i < $n} {incr i} \
		{
		gets $Sid line
		append data $line "\n"

		set pc [ expr $i * 100 / $n ]
		gauge_value $g $pc

		if { $GlobalParam(Debug) > 0 } \
			{
			Tattle "<--- $line"
			}
		}
	flush $Sid
	return $data
}


###################################################################
# Read radio computer control status.
###################################################################
proc ReadCCStatus { } \
{

	global Sid

	SendCmd $Sid "H"

	global Sid

	gets $Sid line

	return $line
}


###################################################################
# Set memory channel.
#	Inputs:
#		ch	-channel
###################################################################
proc SetChannel { ch } \
{

	global Sid

	set command [ append command "C" [ PadLeft0 3 $ch ] ]

	SendCmd $Sid $command

	# gets $Sid line
	set line [ReadRx]

	return $line
}



###################################################################
# Set squelch.
#	Inputs:
#		val	- 0 to 255
###################################################################
proc SetSquelch { val } \
{

	global Sid

	set command [ append command "LL" [ PadLeft0 3 $val ] ]

	SendCmd $Sid $command

	return
}

###################################################################
# Set Bandwidth from 10 - 9990 Hz
#	Inputs:
#		val	- 0 to 9990 Hz
###################################################################
proc SetBW { val } \
{
	global Sid

	set val [ expr $val / 10 ]

	set command [ append command "W" [ PadLeft0 3 $val ] ]

	SendCmd $Sid $command

	return
}



###################################################################
# Read the bandwidth.
#
#	Inputs:
#		none
#	Returns:
#		0 to 9900 (frequency in Hz)
###################################################################
proc GetBW { } \
{
	global Sid

	set command "OO"
	SendCmd $Sid $command
	set line [ReadRx]

	# Strip the leading pair of O (letter) characters
	# from the response.
	regsub "^OO" $line "" bw

	# Strip any leading 0 (zero) characters.
	set line $bw
	# regsub "^0*" $line "" bw
	set bw [string trimleft $line 0]
	set bw [ expr $bw * 10 ]

	return $bw
}


###################################################################
# Set Bandwidth to narr, inter, or wide
#	Inputs:
#		val	- narr, inter, or wide
###################################################################
proc SetBWm { val } \
{
	global Bw
	global Sid

	if {[ info exists Bw($val) ] == 0 } then {return}

	set command [ append command "B" $Bw($val) ]
	SendCmd $Sid $command
	return
}

###################################################################
# Set AF gain (volume).
#	Inputs:
#		val	- 0 to 255
###################################################################
proc SetAF { val } \
{
	global Sid

	set command [ append command "JJ" [ PadLeft0 3 $val ] ]

	SendCmd $Sid $command

	return
}


###################################################################
# Set AGC decay time 0 - 5.1 seconds (0 - 255).
#	Inputs:
#		val	- 0 to 5100
###################################################################
proc SetAGC { val } \
{
	global GlobalParam
	global Sid

	set val $GlobalParam(AGCms)

	# Scale the time.
	set val [ expr ($val * 255) / 5100 ]

	set command [ append command "G3" [ PadLeft0 3 $val ] ]

	SendCmd $Sid $command

	return
}


###################################################################
# Set RF gain.
#	Inputs:
#		val	- 0 to 255
###################################################################
proc SetRF { val } \
{
	global Sid

	set command [ append command "HH" [ PadLeft0 3 $val ] ]

	SendCmd $Sid $command

	return
}


###################################################################
# Set audio tone.
#	Inputs:
#		val	- 0 to 255
###################################################################
proc SetTone { val } \
{
	global Sid

	set command [ append command "KK" [ PadLeft0 3 $val ] ]

	SendCmd $Sid $command

	return
}

###################################################################
# Set Pass Band Shift.
#	Inputs:
#		val	-   -255 to 255
###################################################################
proc SetPBS { val } \
{
	global Sid

	if { $val < 0 } then \
		{
		set val [ expr 0 - $val ]
		set s "-"
		}  \
	else \
		{
		set s "+"
		} 

	# Scale val to be within -255 to 255.

	set val [ expr ($val * 255) / 2200 ]

	set val [ PadLeft0 3 $val ]

	# Insert plus or minus sign in front of value.
	set command [ append command "P" $s $val ]

	SendCmd $Sid $command

	return
}


###################################################################
# Set emission mode.
###################################################################
proc SetMode { } \
{
	global Sid
	global GlobalParam

	set command [ append command "D" $GlobalParam(Mode)]

	SendCmd $Sid $command

	after 100

	return
}

###################################################################
# Set noise reduction/beat canceler mode.
#
###################################################################
proc SetNRBC { } \
{
	global Sid
	global WhichNR

	set command [ append command "BB" $WhichNR ]

	SendCmd $Sid $command

	return
}


###################################################################
# Set DSP Noise Reduction level.
#	Inputs:
#		val	- 0 to 255
###################################################################
proc SetNRLevel { val } \
{
	global Sid

	set command [ append command "U29" [ PadLeft0 3 $val ] ]

	SendCmd $Sid $command

	return
}


###################################################################
# Set DSP Noise Reduction Line Enhance/Invalidate.
#	Inputs:
#		val	- 0 (Line Enhance) or 1 (Invalidate)
###################################################################
proc SetLE { val } \
{
	global Sid

	if {$val == 0} then \
		{
		# Line enhance.
		set command "U270"
		} \
	else \
		{
		# Invalidate.
		set command "U271"
		}

	SendCmd $Sid $command

	return
}

###################################################################
#
# Send "command" to radio.
# Write command to error stream if Debug flag is set.
#
###################################################################
proc SendCmd { Sid command } \
{
	global GlobalParam

	if { $GlobalParam(Debug) > 0 } \
		{
		Tattle "$command --->"
		}
	puts $Sid $command
	flush $Sid
	return
}

###################################################################
# Set frequency.
#	Inputs:
#		freq	-frequency
###################################################################
proc SetFreq { freq } \
{
	global Sid

	set command [ append command "F" [ PadLeft0 10 $freq ] ]
	SendCmd $Sid $command

	return
}


###################################################################
# Read frequency.
#
#	Inputs:
#		none
#	Returns:
#		frequency in MHz
###################################################################
proc ReadFreq { } \
{
	global Sid

	SendCmd $Sid F

	set line [ReadRx]

	regsub "^F" $line "" freq
	set line $freq

	if { [regexp {^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]$} \
		$freq] == 0 } { set freq 0.0 }
	
	regsub "^0*" $line "" freq
	set freq [ format "%11.6f" $freq ]
	set freq [ expr ($freq / 1000000) ]

	return $freq
}


###################################################################
# Set Noise Blanker level.
#	Inputs:
#		val	- 0 to 255
###################################################################
proc SetNBlevel { val } \
{
	global Sid

	set command [ append command "FF" [ PadLeft0 3 $val ] ]

	SendCmd $Sid $command

	return
}


###################################################################
# Set noise blanker mode.
#
###################################################################
proc SetNB { } \
{
	global Sid
	global WhichNB

	set command [ append command "N" $WhichNB ]

	SendCmd $Sid $command

	return
}


###################################################################
# Set notch mode.
#
# Input:
#	global variable WhichNotch:
#		0 notch/notch tracking OFF
#		1 notch ON
#		2 notch tracking ON
#
###################################################################
proc SetNotch { } \
{
	global Sid
	global WhichNotch

	set command [ append command "EE" $WhichNotch ]

	SendCmd $Sid $command

	return
}


###################################################################
# Set Notch frequency.
#	Inputs:
#		val	-   -2500 to 2500
###################################################################
proc SetNotchFreq { val } \
{
	global Sid

	if { $val < 0 } then \
		{
		set val [ expr 0 - $val ]
		set s "-"
		}  \
	else \
		{
		set s "+"
		} 

	# Scale val to be within -1023 to +1023.

	set val [ expr ($val * 1023) / 2500 ]

	set val [ PadLeft0 4 $val ]

	# Insert plus or minus sign in front of value.
	set command [ append command "GG" $s $val ]

	SendCmd $Sid $command

	return
}

###################################################################
# Set beat canceler level.
#	Inputs:
#		val	- 0 to 255
###################################################################
proc SetBC { val } \
{
	global Sid

	set command [ append command "U30" [ PadLeft0 3 $val ] ]

	SendCmd $Sid $command

	return
}


###################################################################
# Enable/disable front end band pass filter.
#	Inputs:
#		flag	- off or on
#			off means disable
#			on means enable (better selectivity)
###################################################################
proc SetBPF { flag } \
{
	global Sid

	if { $flag == "off" } \
		{
		# Disable
		set command "U240"
		} \
	else \
		{
		# Enable
		set command "U241"
		}

	SendCmd $Sid $command
	waiter 500

	return
}



###################################################################
# Set IF filter shape.
#	Inputs:
#		flag	- off or on
#			off means loose
#			on means sharp (better selectivity)
###################################################################
proc SetFilterShape { flag } \
{
	global Sid

	if { $flag == "off" } \
		{
		# Loose
		set command "U321"
		} \
	else \
		{
		# Sharp
		set command "U320"
		}

	SendCmd $Sid $command

	return
}


###################################################################
# Skip empty channels during memory scan.
#	Inputs:
#		val	- off or on
#			off - include empty channels while scanning
#			on - means skip empty channels while scanning
###################################################################
proc SetSkipEmptyCh { offon } \
{
	global Sid

	if { $offon == "off" } \
		{
		set command "U120"
		} \
	elseif { $offon == "on" } \
		{
		set command "U121"
		}

	SendCmd $Sid $command

	return
}


###################################################################
# Set scan auto stop
#	Inputs:
#		offon	- off or on
###################################################################
proc SetScanAutoStop { offon } \
{
	global Sid

	if { $offon == "off" } \
		{
		# Scan auto stop off.
		set command "U110"
		} \
	elseif { $offon == "on" } \
		{
		# Scan auto stop on.
		set command "U111"
		}

	SendCmd $Sid $command

	return
}


###################################################################
# Set tuning step size (in Hz).
#	Inputs:
#		val	- 1, 10, 100, 1000, 10000, 100000
###################################################################
proc SetTS { val } \
{
	global Sid
	global Tstep

	set val [ expr {round($val)}]

	if {[ info exists Tstep($val) ] == 0 } then {return}

	set command [ format "%s" $Tstep($val) ]
	SendCmd $Sid $command

	return
}

###################################################################
# Increment or decrement frequency.
#	Inputs:
#		val	- 0, <0, >0
#
# Note: upon command, radio starts to tune up or down by itself.
###################################################################
proc IncFreq { val } \
{
	global Sid

	if {$val == 0 }\
		{
		set command Y0
		} \
	elseif {$val > 0 }\
		{
		set command Y+
		} \
	elseif {$val < 0 }\
		{
		set command Y-
		}

	SendCmd $Sid $command
	return
}



###################################################################
# Read radio status.
###################################################################
proc ReadRadioStatus { } \
{
	global GlobalParam
	global Sid

	SendCmd $Sid "I"

	close $Sid
	set Sid [open $GlobalParam(Device) "r+"]
	set line [ReadRx]

	return $line
}



###################################################################
# Read squelch open/close status.
#
# Returns:
#	0	- squelch is closed.
#	1	- squelch is open.
###################################################################
proc ReadSquelchStatus { } \
{
	global Sid

	SendCmd $Sid "Q"

	set line [ReadRx]

	if {$line == "Q0" } {return 1} \
	else {return 0}
}

###################################################################
# Set attenuator
#	Inputs:
#		flag	- off or on
###################################################################
proc SetAttenuator { flag } \
{
	global Sid

	if {$flag == "off"} \
		{
		SendCmd $Sid "A0"
		} \
	elseif {$flag == "on"} \
		{
		SendCmd $Sid "A1"
		} \
	return
}


###################################################################
# Get S-meter reading.
###################################################################
proc GetSmeter { } \
{
	global GlobalParam
	global Sid

	# Write to serial port directly because
	# the amount of debugging output is overwhelming.

	# SendCmd $Sid "M"
	puts $Sid M
	flush $Sid

	gets $Sid line
	if { [regexp {^M} $line ] == 0 } \
		{
		# Oops.  We read data which was not S-meter data.
		puts stderr "ERROR _Rx responded: $line"
		return "0"
		}

	if { $GlobalParam(Debug) > 0 } \
		{
		Tattle "<--- $line"
		}
	# Delete leading Ms.
	set line [string trimleft $line "M"]


	# Delete leading zeroes.
	set line [string trimleft $line 0]

	if {$line == ""} then {set line "0"}
	return $line
}
###################################################################
# Read from the serial port until the radio responds
# with a line which does not begin with the first
# character M.
#
# Note: Responses starting with M are S-meter readings.
###################################################################
proc ReadRx { } \
{
	global GlobalParam
	global Sid


	while { 1 } \
		{
		gets $Sid line
		if { $GlobalParam(Debug) > 0 } \
			{
			Tattle "<--- $line"
			}
		if { [regexp {^M} $line ] } \
			{
			set sflag 1
			waiter 50
			} \
		else \
			{
			return $line
			}
		}
}

###################################################################
# Clear all memory channels.
###################################################################
proc ClearAllMem { } \
{
	global Sid
	SendCmd $Sid "Z1"
	return
}

###################################################################
# Send arrow key to radio.
# Simulates a single press of an arrow key.
#	Inputs:
#		updown	- up or down
###################################################################
proc SendArrow { updown } \
{
	global Sid

	if {$updown == "up"} \
		{
		SendCmd $Sid "MM25"
		} \
	elseif {$updown == "down"} \
		{
		SendCmd $Sid "MM24"
		} \
	return
}

###################################################################
# Enable/disable the sending of RTTY data stream on the radio's
# RS-232 port.
#
#	Inputs:
#		offon	- on or off
#
# Note: This is termed "Demodulation code output" in the
# NRD-545 user manual.
###################################################################
proc DecodeRtty { offon } \
{
	global Sid

	if {$offon == "off"} \
		{
		SendCmd $Sid "U230"
		} \
	elseif {$updown == "on"} \
		{
		SendCmd $Sid "U231"
		}
	return
}


###################################################################
# Configure timer relay operation
#
#	Inputs:
#		val
#			- off means off
#			- on means on
#			- squelch means controlled by squelch
#
###################################################################
proc ConfigureTimerRelay { val } \
{
	global Sid

	if {$val == "off"} \
		{
		SendCmd $Sid "U130"
		} \
	elseif {$val == "on"} \
		{
		SendCmd $Sid "U131"
		} \
	elseif {$val == "squelch"} \
		{
		SendCmd $Sid "U132"
		}
	return
}


###################################################################
# Activate/deactivate power supply.
#
#	Inputs:
#		offon	- on or off
#
###################################################################
proc SetPower { offon } \
{
	global Sid

	if {$offon == "off"} \
		{
		SendCmd $Sid "T0"
		} \
	elseif {$offon == "on"} \
		{
		SendCmd $Sid "T1"
		}
	return
}


###################################################################
# Activate/deactivate colon blinking on front panel time display.
#
#	Inputs:
#		offon	- on or off
#
###################################################################
proc SetBlinkingColon { offon } \
{
	global Sid

	if {$offon == "off"} \
		{
		SendCmd $Sid "U190"
		} \
	elseif {$offon == "on"} \
		{
		SendCmd $Sid "U191"
		}
	return
}


###################################################################
# Set front panel display lighting.
#
#	Inputs:
#		level	- dim or bright
#
###################################################################
proc SetLighting { level } \
{
	global Sid

	if {$level == "dim"} \
		{
		SendCmd $Sid "AA1"
		} \
	elseif {$level == "bright"} \
		{
		SendCmd $Sid "AA0"
		}
	return
}


###################################################################
# Set RTTY unshift on space.
#
#	Inputs:
#		offon	- off or on
#
###################################################################
proc SetUnshiftOnSpace { offon } \
{
	global Sid

	if {$offon == "on"} \
		{
		SendCmd $Sid "U251"
		} \
	elseif {$offon == "off"} \
		{
		SendCmd $Sid "U250"
		}
	return
}


###################################################################
# Set RTTY space upon error.
#
#	Inputs:
#		val	- space or asterisk
#
###################################################################
proc SetSpaceOnError { val } \
{
	global Sid

	if {$val == "space"} \
		{
		SendCmd $Sid "U260"
		} \
	elseif {$val == "asterisk"} \
		{
		SendCmd $Sid "U261"
		}
	return
}


###################################################################
# Set RTTY polarity.
#
#	Inputs:
#		polarity	- normal or reverse
#
###################################################################
proc SetRttyPolarity { polarity } \
{
	global Sid

	if {$polarity == "normal"} \
		{
		SendCmd $Sid "U171"
		} \
	elseif {$polarity == "reverse"} \
		{
		SendCmd $Sid "U170"
		}
	return
}


###################################################################
# Set PanelLock
#	Inputs:
#	flag	- off or on
#
# Contributed by: Steve Walker 12/30/2001
###################################################################
proc SetPanelLock { flag } \
{
	global Sid

	if {$flag == "off"} \
		{
		SendCmd $Sid "DD0"
		} \
	elseif {$flag == "on"} \
		{
		SendCmd $Sid "DD1"
		UpdDisplay
		}
	return
}

###################################################################
# Set the clock in the radio.
#
# Input:
#	val	-HHMM
###################################################################
proc SetClock { val } \
{
	global Sid

	set command [ append command "R1" [ PadLeft0 4 $val ] ]

	SendCmd $Sid $command
	return
}


###################################################################
# Set defalt steps in the radio.
#
###################################################################
proc SetDefaultSteps { } \
{
	global Sid

	# 1 Hz step permitted
	set command U011
	SendCmd $Sid $command

	# 10 Hz step permitted
	set command U021
	SendCmd $Sid $command

	# 100 Hz step permitted (over 30 MHz, AM, FM)
	set command U041
	SendCmd $Sid $command

	# 1 kHz step permitted
	set command U030
	SendCmd $Sid $command

	# 5 kHz step permitted (over 30 MHz)
	set command U050
	SendCmd $Sid $command

	# 10 kHz step permitted
	set command U060
	SendCmd $Sid $command

	return
}

###################################################################
# Read AM lock status.
#
# Returns:
#	UnLocked	- ECSS is unlocked.
#	Locked		- ECSS is locked (Sync).
#
# Contributed by: Steve Walker 1/4/2002
###################################################################
proc ReadAMdetection { } \
{
	global Sid
	SendCmd $Sid "TT"

	set line [ReadRx]

	if {$line == "TT1" } {return Locked} \
	else {return UnLocked}
}


###################################################################
# Read stereo status.
#
# Returns:
#	stereo		- signal is stereo
#	monaural	- signal is monaural
#
###################################################################
proc ReadStereoDetect { } \
{
	global Sid
	SendCmd $Sid "SS"

	set line [ReadRx]

	if {$line == "SS0" } {return monaural} \
	else {return stereo}
}

