###################################################################
# This file is part of tk75, a control program for the
# ICOM IC-R75 receiver.
# 
#    Copyright (C) 2001, 2002, Bob Parnass
# 
# 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
###################################################################

set Mode(AM) "02"
set Mode(CW) "03"
set Mode(CWR) "07"
set Mode(FM) "05"
set Mode(LSB) "00"
set Mode(USB) "01"
set Mode(SAM) "11"
set Mode(RTTY) "04"
set Mode(RTTYR) "08"

set RMode(02) "AM"
set RMode(03) "CW"
set RMode(07) "CWR"
set RMode(05) "FM"
set RMode(00) "LSB"
set RMode(01) "USB"
set RMode(11) "SAM"
set RMode(04) "RTTY"
set RMode(08) "RTTYR"


# Tuning step in Hz
set RTs(0) 10
set RTs(1) 50
set RTs(2) 100
set RTs(3) 1000
set RTs(4) 2500
set RTs(5) 5000
set RTs(6) 9000
set RTs(7) 10000
set RTs(8) 12500
set RTs(9) 20000
set RTs(10) 25000
set RTs(11) 100000
set RTs(12) 1000000

set Bw(NARROW) "03"
set Bw(MEDIUM) "02"
set Bw(WIDE) "01"

set RBw(03) NARROW
set RBw(02) MEDIUM
set RBw(01) 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


# 9 MHz IF Filters

set Filter9(15kHz)	"00"
set Filter9(2.8kHz)	"01"
set Filter9(2.4kHz)	"02"
set Filter9(1.9kHz)	"03"
set Filter9(500Hz)	"04"
set Filter9(350Hz)	"05"
set Filter9(250Hz)	"06"
set Filter9(OFF)	"07"

set RFilter9(00)	"15kHz"
set RFilter9(01)	"2.8kHz"
set RFilter9(02)	"2.4kHz"
set RFilter9(03)	"1.9kHz"
set RFilter9(04)	"500Hz"
set RFilter9(05)	"350Hz"
set RFilter9(06)	"250Hz"
set RFilter9(07)	"OFF"


# 455 kHz IF Filters

set Filter4(15kHz)	"00"
set Filter4(6kHz)	"01"
set Filter4(3.3kHz)	"02"
set Filter4(2.8kHz)	"03"
set Filter4(2.4kHz)	"04"
set Filter4(1.8kHz)	"05"
set Filter4(500Hz)	"06"
set Filter4(250Hz)	"07"

set RFilter4(00)	"15kHz"
set RFilter4(01)	"6kHz"
set RFilter4(02)	"3.3kHz"
set RFilter4(03)	"2.8kHz"
set RFilter4(04)	"2.4kHz"
set RFilter4(05)	"1.8kHz"
set RFilter4(06)	"500Hz"
set RFilter4(07)	"250Hz"


set FilterMode(SSB)	"00"
set FilterMode(CW)	"01"
set FilterMode(RTTY)	"02"
set FilterMode(AM)	"03"
set FilterMode(SAM)	"04"
set FilterMode(FM)	"05"

##########################################################
# 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 \
		-buffering full \
		-translation binary \
		-mode 19200,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.
#
# Return the pathname to a configuration file in the user's
# HOME directory
#
# 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/.tk75rc" $Home]
			set labelfile [format "%s/.tk75la" $Home]

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

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

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

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

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

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

			set Home $env(tk75)
			regsub -all {\\} $Home "/" Home
			set rcfile [format "%s/tk75.ini" $Home]
			set labelfile [format "%s/tk75.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
}

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

	after 500

	close $Sid
	return
}

###################################################################
# Return the preamble for messages sent from computer to radio.
###################################################################
proc MsgPreamble { } \
{
	# byte 0 = FE
	# byte 1 = FE
	# byte 2 = 5A (radio's unique address)
	# byte 3 = e0 (computer's address)

	set preamble [ binary format "H2H2H2H2" fe fe 5a e0]

	return $preamble
}


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

	set bch [Ch2BCD $ch]

	set cmd [ binary format "H2" 08 ]
	append cmd [binary format "H*" $bch ]

	SendCmd $Sid $cmd

	return
}


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

	global Sid

	set bval [Ch2BCD $val]

	set cmd [ binary format "H2H2" 14 03 ]
	append cmd [binary format "H4" $bval ]

	SendCmd $Sid $cmd


	# Read ok/ng status to clean off the bus.
	ReadRx 0

	return
}

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

	set bval [Ch2BCD $val]

	set cmd [ binary format "H2H2" 14 01]
	append cmd [binary format "H4" $bval]
	SendCmd $Sid $cmd

	# Read ok/ng status to clean off the bus.
	ReadRx 0

	set GlobalParam(VolumeCurrent) $val

	return
}


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

	set bval [Ch2BCD $val]

	set cmd [ binary format "H2H2" 14 02]
	append cmd [binary format "H4" $bval ]
	SendCmd $Sid $cmd

	# Read ok/ng status to clean off the bus.
	ReadRx 0

	set GlobalParam(RFGain) $val

	return
}


###################################################################
# Set CW pitch.
#	Inputs:
#		val	- 300 to 900
###################################################################
proc SetCWPitch { val } \
{
	global GlobalParam
	global Sid


	set val [ PadLeft0 4 $val ]

	SetTweak2 10 $val 2

	# set GlobalParam(CWPitch) $val

	return
}



###################################################################
# Read CW pitch.
#	Inputs: none
#
#	Returns: 1-4 digit string
###################################################################
proc ReadCWPitch { } \
{
	global GlobalParam
	global Sid



	set val [ReadTweak2 10 2]

	regsub  {^0*} $val "" val

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

	return $val
}



###################################################################
# Set LCD backlight level.
#	Inputs:
#		val	- 0 to 100
###################################################################
proc SetBacklight { val } \
{
	global GlobalParam
	global Sid


	set val [expr {$val * 255 / 100}]
	set val [expr {int($val)}]
	set val [ PadLeft0 4 $val ]

	SetTweak2 21 $val 2

	return
}


###################################################################
# Set NR level.
#	Inputs:
#		val	- 0 to 255
###################################################################
proc SetNRLevel { val } \
{
	global GlobalParam
	global Sid

	set bval [Ch2BCD $val]

	set cmd [binary format "H2H2" 14 06 ]
	append cmd [binary format "H4" $bval ]
	SendCmd $Sid $cmd

	# Read ok/ng status to clean off the bus.
	ReadRx 0

	set GlobalParam(NRLevel) $val

	return
}


###################################################################
# Set AGC off/slow/fast/sfast
###################################################################
proc SetAGC { val } \
{
	global Sid


	set cmd [ binary format "H2H2" 16 12 ]

	if { $val == "fast" } \
		{
		set cmd [ append cmd [binary format "H2" 02 ]]
		} \
	elseif { $val == "sfast" } \
		{
		set cmd [ append cmd [binary format "H2" 01 ]]
		} \
	elseif { $val == "slow" } \
		{
		set cmd [ append cmd [binary format "H2" 03 ]]
		} \
	elseif { $val == "off" } \
		{
		set cmd [ append cmd [binary format "H2" 00 ]]
		}

	SendCmd $Sid $cmd

	# Read ok/ng status to clean off the bus.
	ReadRx 0

	return
}


###################################################################
# MW - Memory write
###################################################################
proc SetMW { } \
{
	global Sid


	set cmd [ binary format "H2" 09 ]

	SendCmd $Sid $cmd

	# Read ok/ng status to clean off the bus.
	ReadRx 0

	return
}


###################################################################
# Set Audio Peak Filter off/on.
###################################################################
proc SetAPF { offon } \
{
	global Sid


	set cmd [ binary format "H2" 16 ]

	if { $offon == "on" } \
		{
		append cmd [binary format "H2" 31 ]
		} \
	else \
		{
		append cmd [binary format "H2" 30 ]
		}

	SendCmd $Sid $cmd

	# Read ok/ng status to clean off the bus.
	ReadRx 0


	return
}

###################################################################
# Adjust APF (audio peak filter) control.
#	Inputs:
#		val	- 0 to 255
###################################################################
proc AdjAPF { val } \
{
	global Sid

	set bval [Ch2BCD $val]

	set cmd [ binary format "H2H2" 14 05]
	append cmd [binary format "H4" $bval ]
	SendCmd $Sid $cmd

	# Read ok/ng status to clean off the bus.
	ReadRx 0

	return
}

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

	set val [expr {$val / 10}]
	set val [expr {$val + 128}]

	set bval [Ch2BCD $val]


	set cmd [ binary format "H2H2" 14 04]
	append cmd [binary format "H4" $bval ]

	SendCmd $Sid $cmd

	# Read ok/ng status to clean off the bus.
	ReadRx 0

	return
}


###################################################################
# Set Pass Band Shift 9 MHz.
#	Inputs:
#		val	-   -1280 to 1280
###################################################################
proc SetPBS9 { val } \
{
	global Sid

	set val [expr {$val / 10}]
	set val [expr {$val + 128}]

	set bval [Ch2BCD $val]


	set cmd [ binary format "H2H2" 14 07]
	append cmd [binary format "H4" $bval ]

	SendCmd $Sid $cmd

	# Read ok/ng status to clean off the bus.
	ReadRx 0

	return
}


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

	set val [expr {$val / 2}]
	set val [expr {$val + 128}]

	set bval [Ch2BCD $val]


	set cmd [binary format "H2H2" 14 08]
	append cmd [binary format "H4" $bval ]

	SendCmd $Sid $cmd

	# Read ok/ng status to clean off the bus.
	ReadRx 0

	return
}


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



	# Translate alphabetic mode to numeric equivalent.
	set m $GlobalParam(Mode)
	set m $Mode($m)

	# Translate alphabetic bandwidth to numeric equivalent.
	set w $GlobalParam(Bw)
	set w [format "%02d" $Bw($w)]

	set cmd [ binary format "H2H2H2" 06 $m $w]

	SendCmd $Sid $cmd

	# Read ok/ng status to clean off the bus.
	ReadRx 0

	return
}


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


	set cmd [MsgPreamble]
	append cmd $command
	append cmd [binary format "H2" fd]


	if { $GlobalParam(Debug) > 0 } \
		{
		binary scan $cmd "H*" s

		# Insert a space between each pair of hex digits
		# to improve readability.

		regsub -all ".." $s { \0} s
		set msg ""
		set msg [ append msg "---> " $s]
		Tattle $msg
		}

	# Write data to serial port.

	puts -nonewline $Sid $cmd
	flush $Sid
	return
}

###################################################################
# Set frequency.
#	Inputs:
#		freq	-frequency in Hz
#
# Note:
#	Radio sends back an ack after executing this
#	command.
###################################################################
proc SetFreq { freq } \
{
	global Sid

	set f [Freq2BCD $freq]

	set cmd [ binary format "H2" 05 ]
	append cmd $f

	SendCmd $Sid $cmd


	# Read the ok ack.
	ReadRx 0

	return
}


###################################################################
# Set speech synthesizer.
###################################################################
proc Speak { } \
{
	global Sid

	set cmd [ binary format "H2H2" 13 00]

	SendCmd $Sid $cmd

	# Read the ok ack.
	ReadRx 0

	return
}


###################################################################
# Start limit scan (i.e., search) 
###################################################################
proc StartLimitScan { } \
{
	global Sid

	set cmd [ binary format "H2H2" 0E 02 ]

	SendCmd $Sid $cmd

	# Read the ok ack.
	ReadRx 0

	return
}


###################################################################
# Start auto write search 
###################################################################
proc StartAutoWriteScan { } \
{
	global Sid

	set cmd [ binary format "H2H2" 0E 04]

	SendCmd $Sid $cmd

	# Read the ok ack.
	ReadRx 0

	return
}


###################################################################
# Start memory bank scan 
#
# Returns:
#	0	-ok
#	1	-error
###################################################################
proc StartMemoryScan { } \
{
	global Sid

	set cmd [ binary format "H2H2" 0E 22]

	SendCmd $Sid $cmd

	# Read the ok ack.
	ReadRx 0

	return
}


###################################################################
# Start select memory scan 
#
# Returns:
#	0	-ok
#	1	-error
###################################################################
proc StartSelectMemoryScan { } \
{
	global Sid

	set cmd ""
	append cmd [binary format "H2H2" 0E 23 ]

	SendCmd $Sid $cmd

	# Read the ack.
	set line [ReadRx 0]

	set len [string length $line]

	if { $len == 1} \
		{
		# Examine the status byte.

		if { [string compare -nocase -length 1 $line \xfb] == 0} \
			{
			# This ack message is ok.
			set status 0
			} \
		else \
			{
			# The command failed.

			# puts stderr "StartSelectMemoryScan: FAILED"
			set status 1
			}
		}
	
	return $status
}

###################################################################
# Start mode scan 
###################################################################
proc StartModeScan { } \
{
	global Sid


	set cmd ""
	append cmd [binary format "H2H2" 0E 24 ]

	SendCmd $Sid $cmd

	# Read the ack.
	set line [ReadRx 0]

	set len [string length $line]

	if { $len == 1} \
		{
		# Examine the status byte.

		if { [string compare -nocase -length 1 $line \xfb] == 0} \
			{
			# This ack message is ok.
			set status 0
			} \
		else \
			{
			# The command failed.

			# puts stderr "StartModeScan: FAILED"
			set status 1
			}
		}
	
	return $status
}


###################################################################
# Start priority scan 
###################################################################
proc StartPriorityScan { } \
{
	global Sid

	set cmd ""
	append cmd [binary format "H2H2" 0E 42 ]

	SendCmd $Sid $cmd

	# Read the ack.

	set line [ReadRx 0]

	set len [string length $line]

	if { $len == 1} \
		{
		# Examine the status byte.

		if { [string compare -nocase -length 1 $line \xfb] == 0} \
			{
			# This ack message is ok.
			set status 0
			} \
		else \
			{
			# The command failed.

			# puts stderr "StartPriorityScan: FAILED"
			set status 1
			}
		}

	
	return $status
}


###################################################################
# Stop scan 
###################################################################
proc StopScan { } \
{
	StopSearch
	return
}

###################################################################
# Stop search 
###################################################################
proc StopSearch { } \
{
	global Sid

	set cmd ""
	append cmd [binary format "H2H2" 0E 00]

	SendCmd $Sid $cmd

	# Read ok/ng status to clean off the bus.
	ReadRx 0

	return
}


###################################################################
# Set the rescan resume condition 
###################################################################
proc SetResume { val } \
{
	global Sid

	set cmd [ binary format "H2" 0E ]

	if {$val == "on" } \
		{
		append cmd [binary format "H2" D3 ]
		} \
	elseif {$val == "off" } \
		{
		append cmd [binary format "H2" D0 ]
		} \
	else {return}
	

	SendCmd $Sid $cmd

	# Read ok/ng status to clean off the bus.
	ReadRx 0

	return
}


###################################################################
# Set the VSC  (voice scan control)
###################################################################
proc SetVSC { offon } \
{
	global Sid

	set cmd ""
	set cmd [ append cmd [binary format "H2" 0E ]]

	if {$offon == "off" } \
		{
		set cmd [ append cmd [binary format "H2" C0 ]]
		} \
	elseif {$offon == "on" } \
		{
		set cmd [ append cmd [binary format "H2" C1 ]]
		}
	
	SendCmd $Sid $cmd


	# Read ok/ng status to clean off the bus.
	ReadRx 0

	return
}


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

	set cmd [binary format "H2" 03 ]

	set error 1

	while {$error} \
		{
		SendCmd $Sid $cmd

		set error 0

		while {1} \
			{

			# Read messages until we find the
			# one which matches this request.
	
			set line [ReadRx]
			set len [string length $line]
			if {$len == 0} \
				{
				# Got an error while reading.
				puts stderr "ReadFreq: read error."
				set error 1
				break
				} \
			elseif {[Check4Meter $line]} \
				{
				# Radio sent an S meter value.
				# continue
				} \
			elseif {$len == 6} \
				{
				set cn [string range $line 0 0]
				binary scan $cn "H*" cn
				if {$cn == 3} {break}
				}
			}
		}

	set f [BCD2Freq $line 1]
	set f [ format "%.6f" $f ]

	return $f
}



###################################################################
# Read mode.
#
#	Inputs:
#		none
#	Returns:
#		numeric mode
###################################################################
proc ReadMode { } \
{
	global Sid

	set cmd [binary format "H2" 04 ]

	set error 1

	while {$error} \
		{
		SendCmd $Sid $cmd

		set error 0

		while {1} \
			{

			# Read messages until we find the
			# one which matches this request.
	
			set line [ReadRx]
			set len [string length $line]
			if {$len == 0} \
				{
				# Got an error while reading.
				puts stderr "ReadFreq: read error."
				set error 1
				break
				} \
			elseif {[Check4Meter $line]} \
				{
				# Radio sent an S meter value.
				# continue
				} \
			elseif {$len == 3} \
				{
				set cn [string range $line 0 0]
				binary scan $cn "H*" cn
				if {$cn == 4} {break}
				}
			}
		}

	set b1 [string range $line 1 1]
	binary scan $b1 "H*" b1

	set b2 [string range $line 2 2]
	binary scan $b2 "H*" b2

	set m [ format "%s%s" $b1 $b2]
	# set m [string trimleft $m 0]

	return $m
}




###################################################################
# Read Set Mode code setting from radio.
#
# Inputs:
#
#	code	- set mode code
#	n	- number of bytes to expect in response
#
# Returns:
#	on or off
###################################################################
proc ReadTweak { code } \
{
	global Sid

	set line [ReadTweak2 $code 1]

	if {$line == "00"} \
		{
		return off
		} \
	else \
		{
		return on
		}
}


###################################################################
# Read Set Mode code setting from radio.
#
# Inputs:
#
#	code	- set mode code
#	n	- number of bytes to expect in response
#
# Returns:
#	string
###################################################################
proc ReadTweak2 { code n } \
{
	global Sid

	set n [ PadLeft0 2 $n ]

	set keystring [format "1A02%2s" $code]

	set cmd [binary format "H2H2H2" 1A 02 $code ]

	set error 1

	while {$error} \
		{
		SendCmd $Sid $cmd

		set error 0

		while {1} \
			{

			# Read messages until we find the
			# one which matches this request.
	
			set line [ReadRx]
			set len [string length $line]
			if {$len == 0} \
				{
				# Got an error while reading.
				puts stderr "ReadFreq: read error."
				set error 1
				break
				} \
			elseif {[Check4Meter $line]} \
				{
				# Radio sent an S meter value.
				# continue
				} \
			elseif { $len == [expr { $n + 3}]} \
				{
				# Response length looks like a match.
				set cn [string range $line 0 2]
				binary scan $cn "H*" cn
				set cn [string toupper $cn]

#				puts stderr "keystring: $keystring,"
#				puts stderr " len: $len, cn: $cn"

				# If response code matches.
				if {$cn == $keystring} {break}
				}
			}
		}

	set p 2
	set m ""

	for {set i 0} {$i < $n} {incr i} \
		{
		incr p
		set b [string range $line $p $p]
		binary scan $b "H*" b
		append m $b
		}

	# puts stderr "m= $m"
	return $m
}


###################################################################
# Set noise blanker off/on.
###################################################################
proc SetNB { offon } \
{
	global Sid

	set cmd [binary format "H2H2" 16 22 ]

	if { $offon == "on" } \
		{
		append cmd [binary format "H2" 01 ]
		} \
	else \
		{
		append cmd [binary format "H2" 00 ]
		}

	SendCmd $Sid $cmd

	# Read ok/ng status to clean off the bus.
	ReadRx 0

	return
}



###################################################################
# Set tweak in the R-75's Set Menu on or off.
###################################################################
proc SetTweak { code offon } \
{
	global Sid


	if { $offon == "on" } \
		{
		SetTweak2 $code 01 1
		} \
	else \
		{
		SetTweak2 $code 00 1
		}

	return
}



###################################################################
# Set the R-75's clock
###################################################################
proc SetClock { hhmmss } \
{
	global Sid

	set cmd [binary format "H2H2H2H6" 1A 02 27 $hhmmss ]

	SendCmd $Sid $cmd

	# Read ok/ng status to clean off the bus.
	ReadRx 0

	return
}


###################################################################
# Set tweak <code> in the R-75's Set Menu with an n byte value <val>
###################################################################
proc SetTweak2 { code val n} \
{
	global Sid

	incr n $n

	set cmd [binary format "H2H2H2" 1A 02 $code ]
	append cmd [binary format "H$n" $val ]

	SendCmd $Sid $cmd

	# Read ok/ng status to clean off the bus.
	ReadRx 0

	return
}


###################################################################
# Set radio to use the VFO.
###################################################################
proc SetVFO { } \
{
	global Sid

	set cmd [binary format "H2" 07 ]

	SendCmd $Sid $cmd

	# Read ok/ng status to clean off the bus.
	ReadRx 0

	return
}


###################################################################
# Set noise reduction off/on.
###################################################################
proc SetNR { offon } \
{
	global Sid


	set cmd [binary format "H2H2" 16 40 ]

	if { $offon == "on" } \
		{
		append cmd [binary format "H2" 01 ]
		} \
	else \
		{
		append cmd [binary format "H2" 00 ]
		}

	SendCmd $Sid $cmd

	# Read ok/ng status to clean off the bus.
	ReadRx 0

	return
}


###################################################################
# Set automatic notch filter off/on.
###################################################################
proc SetNotch { offon } \
{
	global Sid


	set cmd [binary format "H2H2" 16 41 ]

	if { $offon == "on" } \
		{
		append cmd [binary format "H2" 01 ]
		} \
	else \
		{
		append cmd [binary format "H2" 00 ]
		}

	SendCmd $Sid $cmd

	# Read ok/ng status to clean off the bus.
	ReadRx 0

	return
}


###################################################################
# Set tuning step size (in Hz).
#	Inputs:
#		step	- tuning step in kHz
###################################################################
proc SetTS { step } \
{
	global Sid
	global Tstep

#	puts stderr "SetTS: step $step"
	set val [EncodeTS $step]

	set cmd [binary format "H2" 10 ]
	append cmd $val

	SendCmd $Sid $cmd

	return
}

###################################################################
# Set attenuator
#	Inputs:
#		val	- 0
#			- != 0
###################################################################
proc SetAttenuator { val } \
{
	global Sid

	if {$val == 0} \
		{
		set val 0
		} \
	else \
		{
		set val 20
		}
	
	set val [ PadLeft0 2 $val ]

	set cmd [binary format "H2H2" 11 $val]
	SendCmd $Sid $cmd

	# Read ok/ng status to clean off the bus.
	ReadRx 0

	return
}


###################################################################
# Set antenna selection
#	Inputs:
#		val	- ANT1 or ANT2
###################################################################
proc SetAntenna { val } \
{
	global Sid

	if {$val == "ANT1"} \
		{
		set val 0
		} \
	else \
		{
		set val 1
		}
	
	set val [ PadLeft0 2 $val ]

	set cmd [binary format "H2H2" 12 $val ]
	SendCmd $Sid $cmd

	# Read ok/ng status to clean off the bus.
	ReadRx 0

	return
}


###################################################################
# Set preamplifier
#	Inputs:
#		val	- 0, 1, 2
###################################################################
proc SetPreamp { val } \
{
	global Sid

	if { ($val != 0) && ($val != 1) && ($val != 2) } \
		{
		return
		}
	
	set val [ PadLeft0 2 $val ]

	set cmd [ binary format "H2H2H2" 16 02 $val ]
	SendCmd $Sid $cmd

	# Read ok/ng status to clean off the bus.
	ReadRx 0

	return
}


###################################################################
# Convert channel number (0 - 999) to BCD.
# Return a string of bytes.
###################################################################

proc Ch2BCD { ch } \
{

	set s [PadLeft0 4 $ch ]

	return $s
}

###################################################################
# Convert channel number (0 - 999) to BCD.
# Return a string of 4 bytes.
###################################################################

proc xCh2BCD { ch } \
{
	set ch [ PadLeft0 4 $ch ]


	# Channel digit pairs are reversed.

	set bch ""

#	puts stderr "from Ch2BCD, ch = $ch"

	set dpair0 [string range $ch 0 1]
	set dpair0 [binary format "H2" $dpair0]

	set dpair1 [string range $ch 2 3]
	set dpair1 [binary format "H2" $dpair1]

	if {$ch <= 100} \
		{
		append bch $dpair0 $dpair1
		} \
	else \
		{
		append bch $dpair1 $dpair0
		}


	return $bch
}

###################################################################
# Read one memory channel.
#	Inputs:
#		ch	-channel
#
#	Returns a message.
#
# Notes:
#	1) If you ask to read an empty channel, the radio
#	responds with a shorter packet in which the frequency
#	contains only a single byte, ff.
#
#	e.g., if you asked for channel 0, and it was
#	empty, the radio responds:
#
#		fe fe e0 5a 1a 01 00 00 00 ff fd
###################################################################
proc ReadAChannel { ch } \
{
	global Sid

	set bch [Ch2BCD $ch]

	set cmd [ binary format "H2H2" 1A 00 ]
	set cmd [ append cmd [binary format "H*" $bch ]]

	SendCmd $Sid $cmd

	while {1} \
		{
		# Read messages until we find the
		# one which matches this request.

		set line [ReadRx]

		if {[Check4Meter $line]} \
			{
			# Radio sent an S meter value.
			continue
			}

		set len [string length $line]
		set cn [string range $line 0 0]
		binary scan $cn "H*" cn

		# If this is a response to our request.
		if {$cn == "1a"} {break}

		# If we got an NG message from the radio.
		if {$cn == "fa"} {break}
		}

	set status "ok"
	set len [string length $line]

	# Check if channel is empty.
	if {$len == 5}  \
		{
		set line ""
		set status "empty"
		}

	# Check if radio sent NG msg. 
	if {$len == 1}  \
		{
		set line ""
		set status "invalid"
		}

	set lst [list $status $line]

	return $lst
}

###################################################################
# Write one memory channel to the radio.
#	Inputs:
#		s	- encoded data string
###################################################################
proc WriteAChannel { s } \
{
	global Sid

	set cmd [ binary format "H2H2" 1A 00 ]
	set cmd [ append cmd $s ]

	set nretries 5
	set status error

	for { set i 0 } {$i < $nretries} {incr i } \
		{
		SendCmd $Sid $cmd

		# Read ok/ng status to clean off the bus.
		ReadRx 0

return


		# Read the response
		set line [ReadRx]
		set len [string length $line]

		if { $len == 0} \
			{
			# Got a read error.
			puts stderr "WriteAChannel: got a read error from radio."
			set status error
			} \
		elseif { $len == 1} \
			{
			# Examine the byte.
			if { [string compare -nocase -length 1 $line \xfb] == 0} \
				{
				# This ack message is ok.
				set status ok
				break
				} \
			else \
				{
				# This ack message is ng.
				puts stderr "WriteAChannel: got NG ack from radio. Will retry."
				set status error
				continue
				}
			} \
		else \
			{
			# Got a strange response.
			puts stderr "WriteAChannel: got strange response from radio."
			set status error
			exit
			}

		}
	if {$status == "error" } \
		{
		puts stderr "WriteAChannel: Retried $nretries times and failed."
		exit
		}

	return
}

###################################################################
# Read a CI-V message from the serial port.
#
# Inputs:
#	any	- 0 means ignore messages with a "from address"
#		field which indicates the message is from
#		this computer.
#		- 1 means return any message
#
# Strip off the 2 address bytes.
#
# Returns: the message without the address fields.
###################################################################
proc ReadRx { {any 0} } \
{
	global GlobalParam

	set ignored "ignoring previous echo msg from the radio."

	set line {} 

	while { 1 } \
		{
		# Read message from the bus.

		set line [ReadCIV]

		if { [string length $line] == 0} \
			{
			# Got a read error.
			break
			}

		# Examine the address bytes.
		set to [string range $line 0 0]
		set from [string range $line 1 1]

		if { ([string compare -nocase -length 1 $to \xe0] != 0) \
			&& ([string compare -nocase -length 1 $to \x5a] != 0)} \
			{
			puts stderr "ReadRx: UNKNOWN MESSAGE"
			continue;
			}

		if { $any == 0 } \
			{
			if { [string compare -nocase -length 1 $from \xe0] == 0} \
				{
				# This message is from us,

				# so ignore it and read again.
				continue
				} \
			} 

		# Strip of the address bytes.
		set line [string range $line 2 end]
		set len [string length $line]

		if { [Check4Meter $line] } \
			{
			# Radio sent an S meter value.
			#  continue
			}


		# Ignore fa and fb ack messages. (caution!)

		break
		}
	return $line
}


###################################################################
# Read a CI-V message from the serial port.
#
# Returns:
#		The message unless there was an error.
#		The empty string if there was an error.
###################################################################
proc ReadCIV { } \
{
	global GlobalParam
	global Sid


	set collision_error false

	# Skip the 2 byte "fe fe" preamble
	read $Sid 1
	read $Sid 1

	set line ""


	while { 1 } \
		{
		set b [read $Sid 1]

		# A byte of hexadecimal fc means there was an
		# error, usually a collision.

		# Note: I have observered that the radio
		# usually sends 3 consecutive fc bytes after
		# a CIV collision.   Because fc should never appear
		# in the IC-R75 data stream, we consider it 
		# an error whenever we see even a single fc byte.
		#        - Bob Parnass, 2/12/2002

		if { [string compare -nocase -length 1 $b \xfc] == 0} \
			{
			# Got an error, but continue reading bytes
			# until we get an end of message byte fe.

			set collision_error true
			set line [append line $b]
			} \
		elseif { [string compare -nocase -length 1 $b \xfd] == 0} \
			{
			# Got the end of message code byte.
			break
			} \
		elseif { [string compare -nocase -length 1 $b \xfe] == 0} \
			{
			; # Ignore leading preamble bytes.
			} \
		else \
			{
			set line [append line $b]
			}
		}

	if { $GlobalParam(Debug) > 0 } \
		{
		set msg "<--- "
		binary scan $line "H*" x

		regsub -all ".." $x { \0} x

		set msg [append msg $x]
		Tattle $msg
		}

	if { $collision_error == "true" } \
		{
		puts stderr "ReadCIV: collison error."
		set line ""
		}
	return $line
}

###################################################################
# Read S meter.
#
#	Inputs:
#		none
#	Returns:
#		nothing
#
# Notes
#	After calling this proc, the S-meter level
#	will be available in the variable GlobalParam(Smeter).
###################################################################
proc ReadSmeter { } \
{
	global Sid

	set cmd [ binary format "H2H2" 15 02 ]


	while { 1 } \
		{
		SendCmd $Sid $cmd

		# Read response from radio.
	
		set line [ReadRx]
		set len [string length $line]

		if {$len > 0} \
			{
			break
			}

		# Got an error while reading.
		puts stderr "ReadSmeter: read error."
		}

	return
}


###################################################################
# Encode a tuning step from kHz to the command string
# the radio understands.
#
# Input:	step in kHz
#
# Returns:	1-byte binary string
###################################################################
proc EncodeTS { step } \
{

	switch $step \
		{
		.01	{return [binary format H2 00 ]}
		.1	{return [binary format H2 01 ]}
		1	{return [binary format H2 02 ]}
		5	{return [binary format H2 03 ]}
		6.25	{return [binary format H2 04 ]}
		9	{return [binary format H2 05 ]}
		10	{return [binary format H2 06 ]}
		12.5	{return [binary format H2 07 ]}
		20	{return [binary format H2 08 ]}
		25	{return [binary format H2 09 ]}
		100	{return [binary format H2 10 ]}
		1000	{return [binary format H2 11 ]}
		default {return [binary format H2 01 ]}
		}
}

###################################################################
# Read squelch status.
#
#	Inputs:
#		none
#
#	Returns:
#	0	- squelch is closed.
#	!=0	- squelch is open.
###################################################################
proc ReadSquelchStatus { } \
{
	global Sid

	set cmd [ binary format "H2H2" 15 01]

	set error 1

	while {$error} \
		{
		SendCmd $Sid $cmd

		set error 0

		while {1} \
			{

			# Read messages until we find the
			# one which matches this request.
	
			set line [ReadRx]
			set len [string length $line]

			if {$len == 0} \
				{
				# Got an error while reading.
				puts stderr "ReadSquelchStatus: read error."
				set error 1
				break
				} \
			elseif {$len == 3} \
				{
				set cn [string range $line 0 0]
				binary scan $cn "H*" cn

				set sc [string range $line 1 1]
				binary scan $sc "H*" sc

				if {($cn == 15) && ($sc == 01)} \
					{
					set val [string range $line 2 3]
					binary scan $val "H*" val

					set val [string trimleft $val 0]
					break
					}
				}
			}
		}

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

	return $val
}
###################################################################
# Check the message in "line" to see
# if it is an S-meter value message.
# If so, save the value in a global variable.
###################################################################

proc Check4Meter { line } \
{
	global GlobalParam

	set ismeter 0

	set len [string length $line]

	if {$len == 4} \
		{
		set cn [string range $line 0 0]
		binary scan $cn "H*" cn

		set sc [string range $line 1 1]
		binary scan $sc "H*" sc

		if {($cn == 15) && ($sc == 02)} \
			{
			set val [string range $line 2 3]
			binary scan $val "H*" val

			set val [string trimleft $val 0]
			if {$val == ""} \
				{
				set val 0
				}
			set GlobalParam(Smeter) $val
			set ismeter 1
			}
		}
	return $ismeter
}


###################################################################
# Turn power off/on.
#
# Inputs:
#	off	-instruct radio to go into sleep mode
#	on	-instruct radio come back on from sleep mode
###################################################################
proc PowerSwitch { offon } \
{
	global Sid


	set cmd [ binary format "H2" 18 ]

	if { $offon == "on" } \
		{
		set cmd [ append cmd [binary format "H2" 01 ]]
		} \
	elseif { $offon == "off" } \
		{
		set cmd [ append cmd [binary format "H2" 00 ]]
		}

	SendCmd $Sid $cmd

	# Read ok/ng status to clean off the bus.
	ReadRx 0


	return
}

###################################################################
# Read filter.
#
#	Inputs:
#		AM, SAM SSB, CW, RTTY, FM
#	Returns:
#		a 12 character string which represents:
#			9 MHz medium filter
#			9 MHz narrow filter
#			9 MHz wide filter
#			455 kHz medium filter
#			455 kHz narrow filter
#			455 kHz wide filter
#
###################################################################
proc ReadFilter { mode } \
{
	global Sid
	global FilterMode

	set cmd [binary format "H2H2H2" 1A 01 $FilterMode($mode) ]

	set error 1

	while {$error} \
		{
		SendCmd $Sid $cmd

		set error 0

		while {1} \
			{

			# Read messages until we find the
			# one which matches this request.
	
			set line [ReadRx]
			set len [string length $line]
			if {$len == 0} \
				{
				# Got an error while reading.
				puts stderr "ReadFreq: read error."
				set error 1
				break
				} \
			elseif {[Check4Meter $line]} \
				{
				# Radio sent an S meter value.
				# continue
				} \
			elseif {$len == 9} \
				{
				set cn [string range $line 0 1]
				binary scan $cn "H4" cn
				set cn [string toupper $cn]
				if {$cn == "1A01"} {break}
				}
			}
		}

	set s [string range $line 3 8]
	binary scan $s "H12" s


	return $s
}


###################################################################
# Read 4 digit timer setting.
#
#	Inputs:
#		29	-means power-on time
#		31	-means power-off time
#		33	-means sleep time
#
#	Returns:
#		a 4 character string 0000 to 2359
#
###################################################################
proc ReadTimer { code } \
{
	global Sid

	set cmd [binary format "H2H2H2" 1A 02 $code ]

	set error 1

	while {$error} \
		{
		SendCmd $Sid $cmd

		set error 0

		while {1} \
			{

			# Read messages until we find the
			# one which matches this request.
	
			set line [ReadRx]
			set len [string length $line]
			if {$len == 0} \
				{
				# Got an error while reading.
				puts stderr "ReadFreq: read error."
				set error 1
				break
				} \
			elseif {[Check4Meter $line]} \
				{
				# Radio sent an S meter value.
				# continue
				} \
			elseif {$len == 5} \
				{
				set cn [string range $line 0 1]
				binary scan $cn "H4" cn
				set cn [string toupper $cn]
				if {$cn == "1A02"} {break}
				}
			}
		}

	set s [string range $line 3 6]
	binary scan $s "H4" s

	return $s
}


###################################################################
# Write filter configuration for a mode.
#	Inputs:
#		mode	-AM, SAM SSB, CW, RTTY, FM
#		s	-12 byte string
###################################################################
proc WriteFilter { mode s } \
{
	global FilterMode
	global Sid

	set cmd [binary format "H2H2H2" 1A 01 $FilterMode($mode) ]
	append cmd [binary format "H*" $s]

	SendCmd $Sid $cmd

	# Read ok/ng status to clean off the bus.
	ReadRx 0

	return
}

