Add-on portable CAT/CIV and DTMF

Slightly larger than a fist mike this project adds a direct numeric pad & menus to any radio with CAT/CIV. I'm testing it on an FT817ND.
The PIC based "speaker-Mic" is inspired by  Ham Radio Delux
[B]NOTE: This is still a "work in progress"!


The code examples here are considerably out of date.

The current design uses a 18F67J50 PIC, 60 pins, external I2C EEPROM data, 1Mbyte code Flash and USB.

Actual Initial Prototype

1000118_catBox
MKII Prototype
MkII Catpad

The sub-modules (SW & HW) are useful on many projects.

[B]Features[/B]
128x64 Graphic LCD with SW controlled backlight.
Microphone
Speaker
4x4 keypad for direct Frequency input and DTMF
Easier menus for various radio functions.
Vox PTT (for radio with no built-in VOX).
Easy ASCII input to label Memories etc.
Maybe PSK31, CW and RTTY on MkII version.
Graphical bandscan and return loss

Powered from Radio. but 2x AA or 4x AA possible.

Schematic to share keys and GLCD (KS0108 128x64 type)

1000117_sharedglcdkey

Software is in JAL on microchip PIC family.

There is a simulation in VB6 that uses PC serial port for CAT. I may port it to Java. Or not :)

Here is Simulation running. I have real USB<-> Serial <->Cat port to real FT817ND running to the VB6 simulation which uses a 128x 64 array of "vbShapes" as pixels and identical routines and font table to JAL 

1000119_simCat1

 Reduced by 50%, showing S-Meter. 50% is S9, each division is 2x S points.

Once the "GUI" and menu structure designed and all CAT commands working with the real radio the VB6 code will be ported to the PIC. Actually the Serial transfer of Binary data is EASIER on PIC than VB6/WindowsXP, or Java/Linux!

Here is VB6 test code, I have it working with the simulated CATpad and the real radio

Obviously this is not "finished production code" and only for test purposes. I will be translating it to JAL for the PIC micro.

Yes.. it's pretty horrible. Especially handling variable number of bytes from serial port. Some commands vary number of bytes returned depending on Radio Mode.

Next is logic of how to use the commands!

[code]
'Demo test for FT817 Cat control
'needs a timer and comm control on the Form.

Option Explicit
Const lampOffColour = &H808080
Const lampGreenColour = 65280
Const lampRedColour = &HC0&
Const lampYellowColour = &HFFFF&
Const lampOrangeColour = &H80FF&

Dim CATOpen As Boolean

Dim strInput As String

Private waitRadio As Boolean
Private waitConsole As Boolean

'tested on real Com1 and on USB based Com8 Unless you hack mscomm32 the VB6 only allows 1st 16 ports
'Need good Ferrite Choke on Serial/USB cable or TX data is corrupt

'stick these in a separate Module / file
Declare Function QueryPerformanceCounter Lib "kernel32" _
(X As Currency) As Boolean
Declare Function QueryPerformanceFrequency Lib "kernel32" _
(X As Currency) As Boolean

' used in polling loop to timeout if we lost serial comms
Public Sub WaitDelay(ticks As Long)
'At 115k2 baud 011 or 001 is cycle of 38.4Khz
'An on or off is 34 cycles
'Start, | Data,| SPACE | Stop x 2 = 0|01 011 001| 0|11
'same number of ones and zeros
'note that we get four cycles per byte
Dim count As Currency '90 Ticks at 1/2 cycle of 37kHz
Dim initial As Currency
Dim now As Currency
Dim tog As Currency
count = CCur(ticks)
QueryPerformanceCounter initial
QueryPerformanceFrequency tog
tog = count / tog
Do While (now - initial) < tog
QueryPerformanceCounter now
Loop

End Sub

'CAT opcodes FT817, Not all are implemented
' Command Returned Bytes
Const CMD_lockOn = 0 '1
Const CMD_lockOff = &H80& '1
Const CMD_FreqWr = 1 '0
Const CMD_FreqRd = 3 '5
Const CMD_VFOtoggle = &H81& '0
Const CMD_SplitOn = 2 '1
Const CMD_SplitOff = &H82& '1
Const CMD_ClarOn = 5 '1
Const CMD_ClarOff = &H85& '1
Const CMD_ClarFreq = &HF5& '0 RIT
Const CMD_ModMode = 7 '0
Const CMD_PTTon = 8 '1
Const CMD_PTToff = &H88& '1
Const CMD_RepOffDir = 9 '0
Const CMD_RepOffFreq = &HF9& '0 0 .. 99MHz
Const CMD_SqlMode = &HA& '0
Const CMD_CTSSfreq = &HB& '0
Const CMD_DCScode = &HC& '0
Const CMD_PwrOn = &HF& '0
Const CMD_PwrOff = &H8F& '0
Const CMD_RXstats = &HE7& '1
Const CMD_TXstats = &HF7& '1
Const CMD_TXmeter = &HBD& '2 unofficial but only 1 byte = 0 if in RX mode
Const CMD_TXkeyState = &H10& '1 unofficial
Const CMD_ConfigRd = &HA7& '9 unofficial
Const CMD_ConfigRes = &HBE& '0 unofficial But DO NOT do this!
Const CMD_EEPROM_Rd = &HBB& '2 unofficial
Const CMD_EEPROM_Wr = &HBC& '0 unofficial
'
' so far
' CAT_FreqRd
'Not all are implemented
'
' comms error timeout
Const TimeCommShort = 50
Const TimeOutInitial = 1000
' Normal comms is about 300 for 2 bytes @ 38400baud
Private lastTX As Boolean

'
'******* FT817 CAT control Functions tested **************
'
Public Function CAT_FreqRd(ByRef ModMode As String) As String
Dim Buffer(4) As Byte
Dim freqText As String
Dim inBuff As Variant
Dim RXstatus As String
Dim TimeOut As Integer
Dim modeText As String
Buffer(0) = 0
Buffer(1) = 0
Buffer(2) = 0
Buffer(3) = 0
Buffer(4) = CMD_FreqRd 'Read Freq
TimeOut = TimeOutInitial
strInput = ""
If CATOpen And Not waitRadio Then
waitRadio = True
CATport.Output = Buffer
Do While (CATport.InBufferCount < 5) And (TimeOut > 0)
WaitDelay 3
TimeOut = TimeOut - 1
Loop
LogText "FreqRd: " & Str(TimeOut) & vbCrLf

If TimeOut > 0 Then
RXstatus = CATport.Input
RXstatus = StrConv(RXstatus, vbUnicode)
freqText = ""
freqText = freqText + Chr(NibbleHi(Mid(RXstatus, 1, 1)) + Asc("0"))
freqText = freqText + Chr(NibbleLo(Mid(RXstatus, 1, 1)) + Asc("0"))
freqText = freqText + Chr(NibbleHi(Mid(RXstatus, 2, 1)) + Asc("0")) + "."
freqText = freqText + Chr(NibbleLo(Mid(RXstatus, 2, 1)) + Asc("0"))
freqText = freqText + Chr(NibbleHi(Mid(RXstatus, 3, 1)) + Asc("0"))
freqText = freqText + Chr(NibbleLo(Mid(RXstatus, 3, 1)) + Asc("0")) + ","
freqText = freqText + Chr(NibbleHi(Mid(RXstatus, 4, 1)) + Asc("0"))
freqText = freqText + Chr(NibbleLo(Mid(RXstatus, 4, 1)) + Asc("0")) + "0"
Select Case byteVal(Mid(RXstatus, 5, 1))
Case 0
modeText = "LSB"
Case 1
modeText = "USB"
Case 2
modeText = " CW"
Case 3
modeText = "CWR"
Case &H82&
modeText = "CWN"
Case &H83&
modeText = "CRN"
Case 4
modeText = " AM"
Case 5
modeText = "MO4"
Case 6
modeText = "WFM"
Case 7
modeText = "MO7"
Case 8
modeText = "FM"
Case &H88&
modeText = "FM"
Case 9
modeText = "MO9"
Case 10
modeText = "DIG"
Case &H8A&
modeText = "DGN"
Case 11
modeText = "M11"
Case 12
modeText = "PKT"
End Select
freqText = StripLeadingZeros(freqText)
CAT_FreqRd = freqText
ModMode = modeText
Else
ModMode = "Err"
CAT_FreqRd = "0.010,000"
End If
waitRadio = False
End If
End Function
'

Public Sub CAT_FreqWr(freqText As String)
'we assume n.nnn,nnn to nnn.nnn,nnn format, i.e. pretty MHz with last 1Hz digit radio ignores

Dim Buffer(4) As Byte
On Error GoTo BAD
freqText = LTrim(freqText)
Do While Len(freqText) < 11
freqText = "0" + freqText

Loop
Buffer(0) = Val(Mid(freqText, 1, 1)) * 16 + Val(Mid(freqText, 2, 1))
Buffer(1) = Val(Mid(freqText, 3, 1)) * 16 + Val(Mid(freqText, 5, 1))
Buffer(2) = Val(Mid(freqText, 6, 1)) * 16 + Val(Mid(freqText, 7, 1))
Buffer(3) = Val(Mid(freqText, 9, 1)) * 16 + Val(Mid(freqText, 10, 1))
Buffer(4) = CMD_FreqWr 'Write Freq

If CATOpen And Not waitRadio Then
waitRadio = True
CATport.Output = Buffer
waitRadio = False
End If
BAD:
End Sub

Public Function CAT_PTT(KeyOn As Boolean) As Boolean
'This command returns lastKey state, not same as PTT state
Dim Buffer(4) As Byte
Dim inBuff As String
Dim keyState As String
Dim TimeOut As Integer
Dim temp As Integer
CAT_PTT = False
TimeOut = TimeOutInitial
On Error GoTo BAD
Buffer(0) = 0
Buffer(1) = 0
Buffer(2) = 0
Buffer(3) = 0
If KeyOn Then
Buffer(4) = CMD_PTTon '00 if the '817 WAS unkeyed, and F0 if already keyed
Else
Buffer(4) = CMD_PTToff 'returns 00 if the '817 was keyed, and F0 if already unkeyed.
End If
' returns one byte
If CATOpen And Not waitRadio Then
waitRadio = True
inBuff = CATport.Input 'clear buffer!
CATport.Output = Buffer
WaitDelay TimeOutInitial
Do While (CATport.InBufferCount < 1) And (TimeOut > 0)
WaitDelay 3
TimeOut = TimeOut - 1
Loop
If (TimeOut > 0) Then
inBuff = CATport.Input
inBuff = StrConv(inBuff, vbUnicode)
If Len(inBuff) > 0 Then
CAT_PTT = (Asc(Mid(inBuff, 1, 1)) = &HF0&)
Else
CAT_PTT = False
End If
End If
waitRadio = False
End If
BAD:
End Function

Public Function CAT_PTTstate() As Boolean
'This command supposed to return current PTT Key state of Radio. ACTUAL PTT, not if Radio is in TX or RX!
Dim Buffer(4) As Byte
Dim inBuff As String
Dim keyState As String
Dim TimeOut As Integer
Dim temp As Integer
CAT_KeyState = False
TimeOut = TimeOutInitial
On Error GoTo BAD
Buffer(0) = 0
Buffer(1) = 0
Buffer(2) = 0
Buffer(3) = 0
Buffer(4) = CMD_TXkeyState '00 if the '817 is unkeyed, and F0 if keyed
' returns one byte
If CATOpen And Not waitRadio Then
waitRadio = True
inBuff = CATport.Input 'clear buffer!
CATport.Output = Buffer
WaitDelay 10
Do While (CATport.InBufferCount < 1) And (TimeOut > 0)
WaitDelay 3
TimeOut = TimeOut - 1
Loop
LogText "KeyState: " & Str(TimeOut) & vbCrLf

If (TimeOut > 0) Then
inBuff = CATport.Input
inBuff = StrConv(inBuff, vbUnicode)
If Len(inBuff) > 0 Then
If Me.Visible Then
lblResult.Caption = ValToHex(Val(Mid(inBuff, 0, 1)))
End If
CAT_KeyState = (Asc(Mid(inBuff, 0, 1)) = &HF0&)
Else
If Me.Visible Then
lblResult.Caption = "??"
End If
CAT_KeyState = False
End If
End If
waitRadio = False
End If
BAD:
End Function

Public Function CAT_RXstats(ByRef squelch As Boolean, ByRef toneSql As Boolean, ByRef discrim As Boolean) As Integer
'returns S meter
Dim temp As Integer
Dim Buffer(4) As Byte
Dim meter As Integer
Dim TimeOut As Integer
Dim inBuff As String
Dim RXstatus As Integer
On Error GoTo BAD
'must set to default for TX or no connection
meter = 0
squelch = False
toneSql = False
discrim = False

Buffer(0) = 0
Buffer(1) = 0
Buffer(2) = 0
Buffer(3) = 0
Buffer(4) = CMD_RXstats 'Read RX status & sigmeter
strInput = ""
TimeOut = TimeOutInitial
If CATOpen And Not waitRadio Then
waitRadio = True
inBuff = CATport.Input 'clear buffer!
CATport.Output = Buffer
Do While (CATport.InBufferCount < 1) And (TimeOut > 0)
WaitDelay 3
TimeOut = TimeOut - 1
Loop
LogText "RXStats: " & Str(TimeOut) & vbCrLf
If (TimeOut > 0) Then
Debug.Print TimeOut
inBuff = CATport.Input
inBuff = StrConv(inBuff, vbUnicode)

If Len(inBuff) > 0 Then
RXstatus = Asc(Mid(inBuff, 1, 1))
If RXstatus = 255 Then
meter = -1
Else
meter = RXstatus And 15
temp = RXstatus And 128
squelch = (temp > 0)
temp = RXstatus And 64
toneSql = (temp > 0)
temp = RXstatus And 32
discrim = (temp > 0)
If Me.Visible Then
lblResult.Caption = ValToHex(RXstatus)
End If
End If
End If
End If
End If

BAD:
CAT_RXstats = meter
waitRadio = False
End Function

Public Function CAT_TXstatus(ByRef PTTon As Boolean, ByRef SWRhi As Boolean, ByRef SplitOn As Boolean) As Integer
'returns Power meter
Dim temp As Integer
Dim Buffer(4) As Byte
Dim meter As Integer
Dim TimeOut As Integer
Dim inBuff As String
Dim TXstatus As Integer
On Error GoTo BAD
'must set to default for TX or no connection
meter = 0
PTTon = False
SWRhi = False
SplitOn = False

Buffer(0) = 0
Buffer(1) = 0
Buffer(2) = 0
Buffer(3) = 0
Buffer(4) = CMD_TXstats 'Read TX status & Pwrmeter
strInput = ""
TimeOut = TimeOutInitial
If CATOpen And Not waitRadio Then
waitRadio = True
inBuff = CATport.Input 'clear buffer!
CATport.Output = Buffer
Do While (CATport.InBufferCount < 1) And (TimeOut > 0)
WaitDelay 3
TimeOut = TimeOut - 1
Loop
LogText "TXStatus: " & Str(TimeOut) & vbCrLf
If (TimeOut > 0) Then
inBuff = CATport.Input
inBuff = StrConv(inBuff, vbUnicode)
If Len(inBuff) > 0 Then
TXstatus = Asc(Mid(inBuff, 1, 1))
If TXstatus = 255 Then
meter = -1
Else
meter = TXstatus And 15
temp = TXstatus And 128
PTTon = (temp > 0)
temp = TXstatus And 64
SWRhi = (temp > 0)
temp = TXstatus And 32
SplitOn = (temp > 0)
If Me.Visible Then
lblResult.Caption = ValToHex(TXstatus)
End If
End If
End If
End If
End If

BAD:
CAT_TXstatus = meter
waitRadio = False

End Function

Public Function CAT_TXmeters(ByRef PWRmeter As Integer, _
ByRef ALCmeter As Integer, ByRef ModMeter As Integer) As Integer
'returns SWRmeter
Dim temp As Integer
Dim Buffer(4) As Byte
Dim meter As Integer
Dim TimeOut As Integer
Dim inBuff As String
Dim TXstatus As Integer
Dim RxMode As Boolean
On Error GoTo BAD
'must set to default for TX or no connection
RxMode = True
meter = 0
PWRmeter = 0
ALCmeter = 0
ModMeter = 0
Buffer(0) = 0
Buffer(1) = 0
Buffer(2) = 0
Buffer(3) = 0
Buffer(4) = CMD_TXmeter 'Read TX status & pwr 1 byte
TimeOut = TimeOutInitial
If CATOpen And Not waitRadio Then
waitRadio = True
inBuff = CATport.Input 'clear buffer!
CATport.Output = Buffer
Do While (CATport.InBufferCount < 2) And (TimeOut > 0)
WaitDelay 3
TimeOut = TimeOut - 1
If (TimeOut < TimeCommShort) Then
'must be in RX mode
RxMode = True
Exit Do
Else
RxMode = False
End If
Loop
LogText "TXmeters: " & Str(TimeOut)
If (TimeOut > 0) Then
inBuff = CATport.Input
If (Len(inBuff) > 0) Then
inBuff = StrConv(inBuff, vbUnicode)
LogText " Returned: " & Str(Len(inBuff)) & vbCrLf

If RxMode Then
meter = -1
Else
TXstatus = Asc(Mid(inBuff, 1, 1)) 'vswr, Power
meter = TXstatus And 15 'power
PWRmeter = TXstatus \ 16
'Alc, Mod
If Len(inBuff) > 1 Then
TXstatus = Asc(Mid(inBuff, 2, 1))
ALCmeter = TXstatus \ 16
ModMeter = TXstatus And 15
End If
End If
End If
End If
End If

BAD:
CAT_TXmeters = meter
waitRadio = False

End Function

' ********** END OF FT817 CAT control functions & Subs ************

Private Sub LogText(someResults As String)
If Me.Visible Then
txtConsole.SelLength = 0
txtConsole.SelStart = Len(txtConsole.text)
txtConsole.SelText = someResults
End If
End Sub

Private Sub cmdCheck_Click()
Dim pttState As Boolean
pttState = CAT_KeyState()
If pttState Then
Shape1.BackColor = lampRedColour
Else
Shape1.BackColor = lampGreenColour
End If
End Sub

Private Sub cmdConsole_Click()
Dim newMode As String
Dim tsqlch As Boolean
Dim sqlch As Boolean
Dim disc As Boolean
Dim pwr As Integer
Dim isPTT As Boolean
Dim isSWRhi As Boolean
Dim isSplit As Boolean
Dim v_meter As Integer
Dim p_meter As Integer
Dim a_meter As Integer
Dim m_meter As Integer
barVmeter.Value = 0
barAmeter.Value = 0
barMmeter.Value = 0
barSmeter.Value = 0
barPmeter.Value = 0
Shape2.BackColor = lampOffColour
lblResult.Caption = ""
' Me.Refresh
On Error GoTo BAD
lblFrequency.Caption = CAT_FreqRd(newMode)
lblMode.Caption = newMode
'Try RX then try TX
If Not lastTX Then
pwr = CAT_RXstats(sqlch, tsqlch, disc)
If pwr > -1 Then
pwr = (pwr + 1) * 4 - 1
If pwr < 64 Then
barSmeter.Value = pwr
End If
Shape2.BackColor = lampGreenColour
Else
lastTX = True
End If
End If
If lastTX Then
pwr = CAT_TXstatus(isPTT, isSWRhi, isSplit)
If pwr = -1 Then
lastTX = False
Shape2.BackColor = lampGreenColour
Else
pwr = (pwr + 1) * 4 - 1
If pwr > -1 And pwr < 64 Then
barPmeter.Value = pwr
End If
Shape2.BackColor = lampRedColour
End If
v_meter = CAT_TXmeters(p_meter, a_meter, m_meter)
If v_meter > -1 Then
v_meter = (v_meter + 1) * 4 - 1
If v_meter < 64 Then
barVmeter.Value = v_meter
End If
a_meter = (a_meter + 1) * 4 - 1
If a_meter < 64 Then
barAmeter.Value = a_meter
End If
m_meter = (m_meter + 1) * 4 - 1
If m_meter < 64 Then
barMmeter.Value = m_meter
End If
End If
End If
Exit Sub

BAD:
barVmeter.Value = 0
barAmeter.Value = 0
barMmeter.Value = 0
barSmeter.Value = 0
barPmeter.Value = 0
Shape2.BackColor = lampOffColour
lblResult.Caption = ""
lastTX = False
End Sub

Private Sub cmdPTT_Click()
Dim lastKey As Boolean
Do While waitConsole
DoEvents
Loop
waitConsole = True
lblResult.Caption = ""
lastKey = CAT_PTT(True)
lastTX = True
Shape2.BackColor = lampRedColour
waitConsole = False
End Sub

Private Sub cmdPTToff_Click()
Dim lastKey As Boolean
Do While waitConsole
DoEvents
Loop
waitConsole = True
lblResult.Caption = ""
lastKey = CAT_PTT(False)
Shape2.BackColor = lampGreenColour
lastTX = False
waitConsole = False
End Sub

'stuff for Windows
Private Sub Form_Load()
CATOpen = False
RigState = RigOff
waitRadio = False
waitConsole = False

cmbBaud.ListIndex = 3
lastTX = False
' Me.Height = 3750
Me.Top = CInt(GetMySetting("WindowPositions", CStr(Me.Name) + ".Top", Me.Top))
Me.Left = CInt(GetMySetting("WindowPositions", CStr(Me.Name) + ".Left", Me.Left))
End Sub

Public Function Connected() As Boolean
Connected = CATOpen
End Function

Private Sub Form_Unload(Cancel As Integer)
SaveMySetting "WindowPositions", CStr(Me.Name) + ".Top", CStr(Me.Top)
SaveMySetting "WindowPositions", CStr(Me.Name) + ".Left", CStr(Me.Left)
SaveMySetting "WindowPositions", CStr(Me.Name) + ".Width", CStr(Me.Width)
SaveMySetting "WindowPositions", CStr(Me.Name) + ".Height", CStr(Me.Height)

If CATOpen Then
CATport.PortOpen = False
CATOpen = False
End If
End Sub

Private Function StripLeadingZeros(ByVal freqText As String) As String
Dim lngCounter As Long
Dim lngLength As Long
Dim strReturn As String

strReturn = ""

If (freqText <> "") Then
lngLength = Len(freqText)
lngCounter = 1
Do While (Mid(freqText, lngCounter, 1) = "0")
lngCounter = lngCounter + 1
Loop
strReturn = Mid(freqText, lngCounter)
End If

StripLeadingZeros = strReturn
End Function
'
'Returns 0 .. 15 from high nibble
Private Function NibbleHi(byteInChr As String) As Integer
Dim nh As Integer
On Error GoTo BAD
nh = 0
If LenB(byteInChr) > 0 Then
nh = Asc(Mid(byteInChr, 1, 1)) \ 16
End If
BAD:
NibbleHi = nh
End Function
'
'Returns 0 .. 15 from low nibble
Private Function NibbleLo(byteInChr As String) As Integer
Dim NL As Integer
On Error GoTo BAD
NL = 0
If LenB(byteInChr) > 0 Then
NL = Asc(Mid(byteInChr, 1, 1)) And &HF&
End If
BAD:
NibbleLo = NL
End Function
'
'Returns 0 .. 255
Private Function byteVal(byteInChr As String) As Integer
Dim bv As Integer
On Error GoTo BAD
bv = 0
If LenB(byteInChr) > 0 Then
bv = Asc(Mid(byteInChr, 1, 1)) And &HFFFF&
End If
BAD:
byteVal = bv
End Function
'
'Returns true if bit 0 .. 7 defined by bitSel is Set

Private Function BitVal(byteInChr As String, bitSel As Integer) As Boolean
Dim bv As Integer
On Error GoTo BAD
bv = 0
If LenB(byteInChr) > 0 Then
Select Case bitSel
Case 0
bv = Asc(Mid(byteInChr, 1, 1)) And 1
Case 1
bv = Asc(Mid(byteInChr, 1, 1)) And 2
Case 2
bv = Asc(Mid(byteInChr, 1, 1)) And 4
Case 3
bv = Asc(Mid(byteInChr, 1, 1)) And 8
Case 4
bv = Asc(Mid(byteInChr, 1, 1)) And 16
Case 5
bv = Asc(Mid(byteInChr, 1, 1)) And 32
Case 6
bv = Asc(Mid(byteInChr, 1, 1)) And 64
Case 7
bv = Asc(Mid(byteInChr, 1, 1)) And 128
End Select
End If
BAD:
BitVal = (bv > 0)
End Function

Private Function ValToHex(byteVal As Integer) As String
Dim temp As Integer
Dim temp2 As Integer
Dim myHex As String
temp = byteVal And &HFF&
temp2 = (temp And &HF&)
temp = temp \ 16
If temp < 10 Then
myHex = Chr(temp + Asc("0"))
ElseIf temp = 10 Then
myHex = "A"
ElseIf temp = 11 Then
myHex = "B"
ElseIf temp = 12 Then
myHex = "C"
ElseIf temp = 13 Then
myHex = "D"
ElseIf temp = 14 Then
myHex = "E"
ElseIf temp = 15 Then
myHex = "F"
End If
If temp2 < 10 Then
myHex = myHex & Chr(temp2 + Asc("0"))
ElseIf temp2 = 10 Then
myHex = myHex & "A"
ElseIf temp2 = 11 Then
myHex = myHex & "B"
ElseIf temp2 = 12 Then
myHex = myHex & "C"
ElseIf temp2 = 13 Then
myHex = myHex & "D"
ElseIf temp2 = 14 Then
myHex = myHex & "E"
ElseIf temp2 = 15 Then
myHex = myHex & "F"
End If
ValToHex = myHex
End Function

Private Sub Timer1_Timer()
If Me.Visible Then
If CATOpen Then
Do While waitConsole
DoEvents
Loop
waitConsole = True
cmdConsole_Click
waitConsole = False
DoEvents
Else
barVmeter.Value = 0
barAmeter.Value = 0
barMmeter.Value = 0
barSmeter.Value = 0
barPmeter.Value = 0
Shape2.BackColor = lampOffColour
lblResult.Caption = ""
End If
End If
End Sub
[/code]

A real micro controller usually has a "timer tick" interupt and main program is a Do-Forever...

This fragment is the VB6 simulation (using scanned image of real prototype as form) and a 128 x64 array of small square VB6 "shapes" turned on/off to do the screen.

Thus the LCD_xxxxx calls are similar to microcontroller (I even used SAME font table to do the text!)

I haven't written the UI to enter a new Mode, Frequency, Squelch settings etc but the press "4" key does change radio to correct new Frequency.
The S meter, TX power meter (not power settings) and SWR/VSWR meters are working on simulated panel as vertical bars.
[code]
Private Sub TimerSystem_Timer()
'every 100th of second i.e. 10ms
Dim temp As String
Dim newFreq As String
Dim newMode As String
Dim sqlch As Boolean
Dim tsqlch As Boolean
Dim disc As Boolean
Dim s_meter As Integer
Dim v_meter As Integer
Dim p_meter As Integer
Dim a_meter As Integer
Dim m_meter As Integer
Dim is_SWRhigh As Boolean
Dim is_Spliton As Boolean
Dim is_PTT As Boolean
Dim plotidx As Integer
Dim bar As Boolean
Dim oldLineSpace As Integer
Dim rigStatus As String
ticks = ticks + 1
If ticks > 99 Then
ticks = 0
End If

If TimerPress > 0 Then
TimerPress = TimerPress - 10
If TimerPress < 0 Then
TimerPress = 0
End If
End If
If timerClickEnabled Then
If timerClickValue > 0 Then
timerClickValue = timerClickValue - 1
End If
If timerClickValue < 1 Then
timerClickValue = timerClickInterval
timerClickEnabled = False
SmsText
End If
End If
' every 1/4th second

If ((ticks Mod 25) = 0) And (Not busy) And (Me.Visible) Then
busy = True
'
' Check if Rig is Receiving or Transmitting
rigStatus = ""
If RigState = RigRX Then
If RigLastState <> RigRX Then
frmCATport.CAT_PTT False
DrawRXScreen
RigLastState = RigRX
End If
s_meter = frmCATport.CAT_RXstats(sqlch, tsqlch, disc)
If s_meter = -1 Then
RigLastState = RigRX
RigState = RigTX
rigStatus = " "
Else
s_meter = s_meter + 1
If sqlch Then
rigStatus = rigStatus + "SQ "
Else
rigStatus = rigStatus + " "
End If
If tsqlch Then
rigStatus = rigStatus + "TS "
Else
rigStatus = rigStatus + " "
End If
End If

End If

If RigState = RigTX Then ' we might have decided it is in TX during RXcheck
If RigLastState <> RigTX Then
frmCATport.CAT_PTT True
RigLastState = RigTX
DrawTXScreen
End If
p_meter = frmCATport.CAT_TXstatus(is_PTT, is_SWRhigh, is_Spliton)
If p_meter = -1 Then
RigLastState = RigTX
RigState = RigRX
Else
p_meter = p_meter + 1
If is_SWRhigh Then
rigStatus = rigStatus + "SWR! "
Else
rigStatus = rigStatus + " "
End If
If is_Spliton Then
rigStatus = rigStatus + "Split"
Else
rigStatus = rigStatus + " "
End If
End If
End If
If (RigState = RigTX) Or (RigState = RigRX) Then
newFreq = frmCATport.CAT_FreqRd(newMode)
If Len(newFreq) < 12 Then
temp = Space$(12 - Len(newFreq)) + newFreq
End If
FreqLast = temp
Modelast = newMode
temp = newFreq + "MHz"
LCD_GoToXY 7, 1
LCD_WriteStr temp
LCD_GoToXY 5, 7
LCD_WriteStr rigStatus
LCD_GoToXY 5, 8
LCD_WriteStr newMode
LCD_GoToXY 15, 8
LCD_WriteStr "Band"
End If
'
' Enter Setup ************************
If (keypress = 15) And ((RigState = RigOff) Or RigState = RigRX) Then 'Star
keypress = 255
RigLastState = RigState
RigState = RigSet
lampOn = True
LCD_Lamp lampOn
oldLineSpace = LCD_LineSpace
LCD_LineSpace = 5
LCD_Fill False
LCD_GoToXY 2, 1
LCD_WriteStr "Redo Lamp Tune Sets" + vbCr
LCD_WriteStr " CTCS DCS Sql Mems" + vbCr
LCD_WriteStr " Ant PreA Pwr Tran" + vbCr
LCD_WriteStr " Tone Msg Save Macr" + vbCr
LCD_WriteStr " Exit Spli B/S R/T"
For plotidx = 1 To 4 'columns
LCD_DrawButton 5, plotidx * 13 - 2, 27, 11, True
LCD_DrawButton 35, plotidx * 13 - 2, 27, 11, True
LCD_DrawButton 65, plotidx * 13 - 2, 27, 11, True
LCD_DrawButton 95, plotidx * 13 - 2, 27, 11, True
Next
Me.Refresh
keypress = 255
LCD_LineSpace = oldLineSpace
'
' Setup actions ************************
ElseIf (RigState = RigSet) Then
If (keypress = 15) Then
RigState = RigLastState
RigLastState = RigSet
keypress = 255
ElseIf (keypress = 17) Then
lampOn = Not lampOn
LCD_Lamp lampOn
keypress = 255
Else
If (pressType = pressSMS) Then 'And bindex < K_RED
lastKeypress = keypress
'keypress = bindex
'bindex = 255
If (keypress = lastKeypress) Then
If (timerClickEnabled) Then
clickCount = clickCount + 1
timerClickEnabled = False
timerClickValue = timerClickInterval
timerClickEnabled = True
End If
End If
If Not (timerClickEnabled) Then
timerClickValue = timerClickInterval
timerClickEnabled = True
End If
DoEvents
Else
lastKeypress = keypress
CheckMode keypress
End If
End If
'
' Exit TX ************************
ElseIf Not (RigState = RigTX) And (RigLastState = RigTX) Then
frmCATport.CAT_PTT (False) ' Then
DrawRXScreen
RigLastState = RigState

' Turn Off ************************
ElseIf (RigState = RigOff) And (Not (RigLastState = RigOff)) Then
LCD_Fill False
LCD_Lamp False
RigLastState = RigState
'
' TX Actions ************************
ElseIf (RigState = RigTX) Then
If (RigLastState <> RigTX) Then
End If
p_meter = 0
s_meter = 0
a_meter = 0
m_meter = 0
s_meter = frmCATport.CAT_TXmeters(p_meter, a_meter, m_meter)
'p_meter = frmCATport.CAT_TXstatus(is_PTT, is_SWRhigh, is_Spliton)

If p_meter > -1 Then
p_meter = 48 - (4 * p_meter)
If p_meter < 0 Then
p_meter = 0
End If
If s_meter < 0 Then
s_meter = 0
End If
s_meter = 48 - (3 * (s_meter))
For plotidx = 0 To 48
bar = plotidx > p_meter
LCD_Plot 0, plotidx, bar
LCD_Plot 1, plotidx, bar
LCD_Plot 2, plotidx, bar
LCD_Plot 3, plotidx, bar
bar = plotidx > s_meter
LCD_Plot 7, plotidx, bar
LCD_Plot 8, plotidx, bar
LCD_Plot 9, plotidx, bar
LCD_Plot 10, plotidx, bar
Me.Refresh
Next
End If
If Not is_PTT Then
'RigState = RigRX
End If
'
' RX Actions ************************
ElseIf (RigState = RigRX) Then
If Not (RigLastState = RigRX) Then
End If
's_meter = frmCATport.CAT_RXstats(sqlch, tsqlch, disc) + 1
s_meter = 64 - (4 * s_meter)
For plotidx = 0 To 63
bar = plotidx > s_meter
LCD_Plot 0, plotidx, bar
LCD_Plot 1, plotidx, bar
LCD_Plot 2, plotidx, bar
LCD_Plot 3, plotidx, bar
Next
If (keypress = 4) Then
frmCATport.CAT_FreqWr " 14.123,456"
keypress = 255
End If
End If
If flipFlop And cursorVisible Then
CursorFlash
End If
flipFlop = Not flipFlop
busy = False
End If
If (ticks = 0) Then
ClockUpdate (RigState = RigOff), 3, 1, 2
End If

End Sub
[/code]

If you are in Receive Mode on the Radio pressing * brings up the Menu

[CENTER][ATTACH]121[/ATTACH][/CENTER]
Each of the 20 menu items is mapped to either one of the 4x 4 keypad buttons or the 4 under screen menu buttons

Proposed UI structure
[code]
' RX options
'Listen
'Change ModMode :r and g buttons cycle
'Change frequency :press any numeric key to start
'Change Split : * 0
'Change Aerial : * 4
'Change CTCSS tone : * 1
'Change DCS code : * 2
'Change squelch : * 3
'change Preamp gain : * 5
'Change TX power : * 6
'Change ToneBurst/Roger : * 7
'Recall Memory, R/T Band or B/S :A= memory00, B = memory01 (VFO A or B), Cnn=Memory, Dnn=R/T
' #nn = B/S band
'Prior/Next memory/band etc.. : y & b buttons
'Save as Memory, : * 9
'R/T band or B/S band -> Exit to Setup | Setup Memory/Band
'Enter Message : * 8
'Send Message in Msg : r goes to Transmit
'Save Message : y
'Cancel Message : g
'Send last msg : * 8 r or * r
'Exit to Transmit : PTT
'Exit to Setup : * b
'Exit to Off

' TX options
'Exit to Receive : msg sent or PTT clicked/ released / Vox off
'Send DTMF
'Send data message
'change TXpower

'Setup options
'Setup Memory * A
'Setup Transvertors * B
'Setup Macros * C
'Setup R/T Bands * D
'Setup B/S Bands * #
'Change Split * 0
'Change CTCSS tone * 1
'Change DCS code * 2
'Change squelch * 3
'Change Aerial * 4
'change Preamp gain * 5
'Change TX power * 6
'Change ToneBurst/Roger * 7
'Setup New Message * 8
'Save as Memory, * 9
'Send last msg * r
'Toggle lamp on/off * g
'Tune PTT/TX * y
'Setup * b

' Redo | Lamp|Tune |Setup
' _____ _____ _____ _____
' |CTCSS| DCS |Sqlch| MEM |
' |__1__|__2__|__3__|__A__|
' | Ant | Pre | Pwr | TRAN|
' |__4__|__5__|__6__|__B__|
' |Tone | Msg | Save|Macro|
' |_____|_____|_____|__C__|
' |Exit |Split| B/S | R/T |
' |__*__|__0__|__#__|__D__|
[/code]

Any suggestions are welcome.

[B]Revised 8th Feb 2010[/B]
Normal Receive Operation:
0 .. 9 starts entry new frequency
r and g menu keys cycle mode
y & g menu keys cycle band/channel

Recall Memory, R/T Band or B/S :
An= [B]A[/B]nalyse /Spectrum Graph TX return loss or RX signal level
Bnn = [B]B[/B]ands. First 27 (00 to 26) are R/T, other 83 are RX only (28 to 99)
Cnn= Channel Memory R/T (100 channels as 00 to 99),
Dnn= ??
#nn = 100 More Memory Channels (00 to 99)

[B]This Wrong![/B]
[code]

'Internal EEPROM
'Frequency stored as 9876.54321MHz etc, i.e. 10s of Hz as BCD
' 21 43 56 78 54 76 98 Flags = 8 bytes
'Flags
' MSB
' BandType=Mem (100 channels), R/T (32 bands), Broadcast/Scanner (25 bands)
'
'R/T Band has per band:
' TX, RX, (16 bytes) _
' TX hi, TX low, RXhi, Rx low to nearest 1kHz is 7 bytes x4 = (28 bytes)
' TX display Offset, RX Display Offset(nearest kHz or MHz +/- 899.999 = 3bytes, MHz or GHz) 6Bytes
' Mode 4 bits 0= LSB, 1=USB, CW, CWR, AM, NAM, WFM, RES1, _
' 8=NFM, 9=RES2, A=DIG, B=RES3, C=PKT, D=DRM, E=DAB, F=Res4
' Tone settings 4 bits: CTSS on/off TX, CTSS on/off RX, DCS on/off TX, DCS on/off RX. (1 byte)
' TxTimeout 0..15 x 20secs = 0 to 5min 4 bits, TX Roger Beep, TX 1720 open, Aerial 0 ..3 = 2 bits (1 byte)
' DCS code 2 bytes BCD
' CTSS code 1 byte (lookup table)
' RX gain 0..15, TX power 0..7, MHz=0 or GHz=1 band
' band name 6
' 16 + 28 + 6 + 1 + 1 + 2 +1 +8 (2 spare) = 64 bytes x 32bands = 2K
'
' Broad/Scan Band has per band:
' last RX, (8 bytes) _
' RXhi, Rx low to nearest 1kHz is 7 bytes x2 = (14)
' RX Display Offset(nearest kHz or MHz +/- 899.999 = 3bytes, MHz or GHz) 3Bytes
' Mode 4 bits 0= LSB, 1=USB, CW, CWR, AM, NAM, WFM, RES1, _
' 8=NFM, 9=RES2, A=DIG, B=RES3, C=PKT, D=DRM, E=DAB, F=Res4
' Att/Preamp 0..15 4bit, Aerial 0 ..3 2 bits, spare flag, MHz=0 or GHz band=1 (1 byte)
' band name 6
'
' 8 + 14 + 3 + 1+6 (0 spare) = 32 bytes x 25bands = 800
'
'Mem has per Channel:
' TX, RX, (16 bytes) _
' use R/T band for display offset band, band = 5 bits (1 byte
' Mode 4 bits 0= LSB, 1=USB, CW, CWR, AM, NAM, WFM, RES1, _
' 8=NFM, 9=RES2, A=DIG, B=RES3, C=PKT, D=DRM, E=DAB, F=Res4
' Tone settings 4 bits: CTSS on/off TX, CTSS on/off RX, DCS on/off TX, DCS on/off RX. (1 byte)
' TxTimeout 0..15 x 20secs = 0 to 5min 4 bits, TX Roger Beep, TX 1720 open, Aerial 0 ..3 = 2 bits (1 byte)
' DCS code 2 bytes BCD
' CTSS code 1 byte (lookup table)
' RX gain 0..15, TX power 0..15 (1 byte)
' Channel Name 8
' spare for Squelch level?
' 16 + 1 + 1 + 1 + 2 +1 +1 + 4 (1 spare) = 32 bytes x 100 = 3200
'
' total = 6K

'External 24LC512 = 512 x 1024 / 8 = 64Ki byte
'Memories and Bands are in a separate I2C eeprom
[/code]

OK did some more work on Bands/Channels stuff. It doesn't use the memories in the Radio, nor the bands. So in theory plug into any Radio and you have the Memories & Bands.

The revisions

A Key enters "Analyse" Mode which can scan band like scanner but does graph. Or it can scan in Transmit at low power calculating and ploting Return Loss vs Frequency (filter/aerial Analyser). It will use SSB and lowest power setting adjusting drive to keep a reference forward power as it measures reverse volts using the "SWR" meter (which simply measures reflected signal, not actual VSWR reading).

B Key is Bands: 00 to 26 are RX & TX, withe per band setting of everything. band 27 to 99 are RX only so only settings to do with RX and no squelch settings are stored. All band limits for RX & TX can be edited. Of course it can't actually receive or Transmit where the radio doesn't. Each band can use one of 32 transverter settings. The Transverter settings have a separate RX and TX offset, and + or - action. There may be a physical port to control a Transverter controller.

C key with 00 to 99 is 100 named channels.
# key with 00 to 99 can be 100 more named channels or for numbered
C & # have all settings for R&T as per the 1st 26 bands and Transverters.
so 200 memory channels.
The bands are essentially 27 optionally split Rx/Tx VFOs and 73 RX only VFO.

Discussion on Electronics/Software here:

Discussion on Features and UI here:

Today, the signal level scan works (real radio FT817ND on 87.5 to 107.4 MHz)

1000121_setupMenu

1000122_scan1

There is a Graticule routine for X and Y axis but no labels yet ...
Mid Y scale is about S9, top is about +50dB. X axis can be various steps, if there are more than 100 they are averaged on display.
[CENTER]

[B]Main CPU board 1 of 2 [/B](Preliminary)

1000124_cpu

Errors in schematic: vUSB needs 220nF to ground and not connect to USB socket.
Two 1N4148 diodes, 10 K resistor and 100nF missing from GND, MCLR and +5V circuit.
Two resistors for I2c bus missing.

[B]Main CPU board 2 of 2 [/B](Preliminary)

1000125_audio

[B]Main CPU board [/B] (Vero / strip layout)

1000123_cpumain

[LIST]
[*]Top centre jack controls T1 Aerial Matchbox, or other remote autotuner, Tip is Memory_Recall and Ring is Tune_Init.
[*]Top right is TX/RX LED
[*]19 pin connector in middle of 40pin CPU is under board and allows board to clip on to to the keypad/ Graphics board.
[*]4 Pin Mid Bottom Right is rotary encoder + push for VFO etc.
[*]Bottom Centre is Volume and Balance.
[*]Internal speaker wires across Bottom Left headphone socket.
[*]Top Left is Electret Mic
[*]Top Left Inset is cable 8way "Y" cable to CAT and Data ports.
[*] Bottom right is USB mini B slave to PC
[/LIST]

18F4550 CPU (PIC)
24LC512 EEPROM (64K Bytes memories and bands.)
TDA 7040 Stereo Decoder (Only 76MHz to 108MHz band)*
NE567/LM567 tone Decoder for Sel Call and CW decoder
DTMF via software in PIC
TDA7330 RDS decoder (Only 76MHz to 108MHz band)*

(* Optional parts that require changing a Chip capacitor on the FT817 main board from 22nF to 2nF on the dedicated 76MHz to 108MHz band Discriminator FM IF out, normal audio via FT817ND speaker on WBFM not affected.)