Quisk version 4.2.42

This commit is contained in:
James C. Ahlstrom
2025-04-11 15:33:20 -04:00
parent 1c209457dc
commit f5c4732eba
6 changed files with 473 additions and 70 deletions
+6
View File
@@ -1,3 +1,9 @@
Quisk Version 4.2.42 April 2025
================================
I fixed a bug in the Kenwood IF CAT command. Thanks Nick! I moved the Pulse server IP address to the Sound screen.
I added a CAT method to imitate the Elecraft K4 command set over a TCP port. Quisk now has four CAT controls. To
make this clearer I added more documentation to the Remote screen.
Quisk Version 4.2.41 January 2025
==================================
I made some improvements to the top-level Config/Radios screen. There is now an option to
+1 -1
View File
@@ -1,2 +1,2 @@
#Quisk version 4.2.41
#Quisk version 4.2.42
from .quisk import main
+104 -20
View File
@@ -1338,7 +1338,16 @@ class RadioNotebook(wx.Notebook): # The second-level notebook for each radio nam
self.AddPage(page, "Sound")
self.pages.append(page)
for section, names in local_conf.sections:
if section in ('Sound', 'Bands', 'Filters'): # There is a special page for these sections
if section == 'Sound': # There is a special page for these sections
continue
if section == 'Bands':
continue
if section == 'Filters':
continue
if section == 'Remote':
page = RadioRemote(self, radio_name, section, names)
self.AddPage(page, section)
self.pages.append(page)
continue
page = RadioSection(self, radio_name, section, names)
self.AddPage(page, section)
@@ -1979,6 +1988,16 @@ class ControlMixin:
btn.SetSizeHints(h, h, h, h)
self.gbs.Add(btn, (self.row, col), flag=wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, border=self.charx*border)
return sld, btn
def AddTextHeading(self, key, text, help_text):
if key in text: # Start of heading
self.NextRow()
self.SetFont(self.heading_font)
self.AddTextL(1, help_text, span=7)
self.SetFont(self.font)
self.NextRow()
self.col = 2
return key
return None
def AddPopupMenuHelp(self, Qclass, col, text, btn_text, help_text, span1=1, span2=1, border=1):
if text:
txt = wx.StaticText(self, -1, text)
@@ -2890,16 +2909,7 @@ class RadioSection(BaseWindow): # The pages for each section in the second-leve
radio_dict = local_conf.GetRadioDict(self.radio_name)
radio_type = radio_dict['hardware_file_type']
for name, text, fmt, help_text, values in self.names:
if name == 'remote_radio_password':
self.AddTextButtonHelp(col, text, "Change", self.OnChangePassword, help_text)
if col == 1:
col = 4
else:
col = 1
self.NextRow()
elif name == 'remote_radio_ip' and radio_type != "Control Head":
continue
elif name == 'favorites_file_path':
if name == 'favorites_file_path':
self.favorites_path = radio_dict.get('favorites_file_path', '')
row = self.row
self.row = 1
@@ -3087,14 +3097,6 @@ class RadioSection(BaseWindow): # The pages for each section in the second-leve
index = self.list_ctrl.GetFirstSelected()
if index >= 0:
self.list_ctrl.Select(index, 0)
def OnChangePassword(self, event):
text = local_conf.globals.get('remote_radio_password', '')
dlg = wx.TextEntryDialog(self, "Please enter a password for remote access",
"Password Entry", text)
if dlg.ShowModal() == wx.ID_OK:
local_conf.globals["remote_radio_password"] = dlg.GetValue()
local_conf.settings_changed = True
local_conf.SaveState()
class RadioHardwareBase(BaseWindow): # The Hardware page in the second-level notebook for each radio
def __init__(self, parent, radio_name):
@@ -3747,7 +3749,7 @@ class RadioSound(BaseWindow): # The Sound page in the second-level notebook for
self.radio_dict = local_conf.GetRadioDict(self.radio_name)
self.num_cols = 8
for name, text, fmt, help_text, values in local_conf.GetSectionData('Sound'):
if name in ('digital_output_level', 'file_play_level'):
if name in ('digital_output_level', 'file_play_level', 'IQ_Server_IP'):
value = self.GetValue(name, self.radio_dict)
no_edit = "choice" in fmt or fmt == 'boolean'
txt, cb, btn = self.AddTextComboHelp(1, text, value, values, help_text, no_edit)
@@ -4182,6 +4184,88 @@ The Tx bits are sent as the "Alex" filters and are sent to the J16 interface.'
if hasattr(application.Hardware, "ImmediateChange"):
application.Hardware.ImmediateChange(name)
class RadioRemote(BaseWindow): # The Remote page in the second-level notebook for each radio
def __init__(self, parent, radio_name, section, names):
BaseWindow.__init__(self, parent)
self.radio_name = radio_name
self.section = section
self.names = names
self.heading_font = wx.Font(conf.config_font_size, wx.FONTFAMILY_SWISS, wx.ITALIC,
wx.FONTWEIGHT_NORMAL, False, conf.quisk_typeface)
self.MakeControls()
def MakeControls(self):
self.num_cols = 8
#self.MarkCols()
self.AddColSpacer(1, 3)
self.NextRow()
self.col = 2
radio_dict = local_conf.GetRadioDict(self.radio_name)
radio_type = radio_dict['hardware_file_type']
heading = None
for name, text, fmt, help_text, values in self.names:
if heading:
if heading not in text: # End of heading
heading = None
self.NextRow()
self.col = 2
if not heading:
heading = self.AddTextHeading("Hamlib Rig 2", text,
'Rig control commands using "Hamlib Rig 2" are sent to a Quisk TCP port from multiple clients.')
if not heading:
heading = self.AddTextHeading("XML-RPC", text,
'XML-RPC is a protocol that allows clients to call methods on a remote server using XML passed via HTTP')
if not heading:
heading = self.AddTextHeading("CAT serial", text,
'"CAT serial" supports the FlexRadio PowerSDR 2.x command set sent over a serial port. Some Kenwood commands are included.')
if not heading:
heading = self.AddTextHeading("remote radio", text,
'Quisk can be used as a control head to control a real radio located remotely. This feature is due to AC2YD.')
if not heading:
heading = self.AddTextHeading("K4 TCP", text,
'Rig control commands using "K4 TCP" use the Elecraft K4 command set, and are sent to a Quisk TCP port from multiple clients.')
if not heading:
heading = self.AddTextHeading("Dx cluster", text,
'"Dx Cluster" is a telnet service used to announce Dx spots in real time.')
if name == 'remote_radio_password':
self.AddTextButtonHelp(self.col, text, "Change", self.OnChangePassword, help_text)
if self.col == 2:
self.col = 5
else:
self.col = 2
self.NextRow()
elif name == 'remote_radio_ip' and radio_type != "Control Head":
continue
else:
if fmt[0:4] in ('dict', 'list'):
continue
if name[0:4] == platform_ignore:
continue
value = self.GetValue(name, radio_dict)
no_edit = "choice" in fmt or fmt == 'boolean'
txt, cb, btn = self.AddTextComboHelp(self.col, text, value, values, help_text, no_edit)
cb.handler = self.OnChange
cb.quisk_data_name = name
if self.col == 2:
self.col = 5
else:
self.col = 2
self.NextRow()
self.NextRow()
self.AddTextL(1, "End of list", span=7)
self.AddColSpacer(3, 20)
self.AddColSpacer(6, 20)
self.FitInside()
self.SetScrollRate(1, 1)
def OnChangePassword(self, event):
text = local_conf.globals.get('remote_radio_password', '')
dlg = wx.TextEntryDialog(self, "Please enter a password for remote access",
"Password Entry", text)
if dlg.ShowModal() == wx.ID_OK:
local_conf.globals["remote_radio_password"] = dlg.GetValue()
local_conf.settings_changed = True
local_conf.SaveState()
class xxRadioFilters(BaseWindow): # The Filters page in the second-level notebook for each radio
def __init__(self, parent, radio_name):
BaseWindow.__init__(self, parent)
+306 -7
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# All QUISK software is Copyright (C) 2006-2024 by James C. Ahlstrom.
# All QUISK software is Copyright (C) 2006-2025 by James C. Ahlstrom.
# This free software is licensed for use under the GNU General Public
# License (GPL), see http://www.opensource.org.
# Note that there is NO WARRANTY AT ALL. USE AT YOUR OWN RISK!!
@@ -585,11 +585,18 @@ class HamlibHandlerSerial:
mode = self.app.mode
info = cmd
info += "%011d" % (self.app.rxFreq + self.app.VFO) # frequency, ZZFA
info += '0000'
if ritFreq < 0: # RIT freq
info += "-%05d" % -ritFreq
else:
info += "+%05d" % ritFreq
if len(cmd) == 4: # Flex ZZIF
info += '0000'
if ritFreq < 0: # RIT freq
info += "-%05d" % -ritFreq
else:
info += "+%05d" % ritFreq
else: # Kenwood IF
info += '00000'
if ritFreq < 0: # RIT freq
info += "-%04d" % -ritFreq
else:
info += "+%04d" % ritFreq
info += "%d" % rit # RIT status
info += '0000'
if QS.is_key_down(): # MOX, key down
@@ -933,6 +940,8 @@ class HamlibHandlerRig2: # Test with telnet localhost 4532
if not isinstance(text, Q3StringTypes):
text = text.decode('utf-8')
self.received += text
if HAMLIB_DEBUG and text:
print ("Raw rig2 received:", text)
if '\n' in self.received: # A complete command ending with newline is available
self.input, self.received = self.received.split('\n', 1) # Split off the command, save any further characters
else:
@@ -1218,6 +1227,267 @@ class HamlibHandlerRig2: # Test with telnet localhost 4532
else:
self.ErrParam()
class CatControl:
def GetFreqVfo(self, vfoB=False):
if vfoB: # The Tx Frequency
return self.app.txFreq + self.app.VFO
else: # The Rx Frequency
rx = self.app.multi_rx_screen.receiver_list
if rx:
rx = rx[0]
return rx.txFreq + rx.VFO
else:
return self.app.rxFreq + self.app.VFO
def SetFreqVfo(self, freq, vfoB=False):
if vfoB: # The Tx Frequency
self.app.ChangeRxTxFrequency(None, freq)
else: # The Rx Frequency
# For multiple receivers this controls the first added receiver frequency; else it controls split Rx/Tx frequency.
rx = self.app.multi_rx_screen.receiver_list
if rx:
rx[0].ChangeRxTxFrequency(freq)
else:
self.app.ChangeRxTxFrequency(freq, None)
def GetFilterBW(self):
return self.app.filter_bandwidth
def SetFilterBW(self, bw):
# Choose button closest to requested bandwidth
buttons = self.app.filterButns.GetButtons()
Lab = buttons[0].GetLabel()
diff = abs(int(Lab) - bw)
for i in range(1, len(buttons) - 1):
label = buttons[i].GetLabel()
df = abs(int(label) - bw)
if df < diff:
Lab = label
diff = df
self.app.filterButns.SetLabel(Lab, True)
class ElecraftK4Handler(CatControl): # Test with telnet localhost 9200
Mo2CoElecraft = {'LSB':1, 'USB':2, 'CWU':3, 'FM':4, 'AM':5, 'DGT-U':6, 'CWL':7, 'DGT-L':9, 'DGT-FM':4, 'DGT-IQ':6}
Co2MoElecraft = {1:'LSB', 2:'USB', 3:'CWU', 4:'FM', 5:'AM', 6:'DGT-U', 7:'CWL', 9:'DGT-L'}
def __init__(self, app, conf, sock, address):
self.app = app
self.conf = conf
self.sock = sock
sock.settimeout(0.0)
self.address = address
self.params = '' # params is the string following the command
self.received = ''
self.cmds = []
self.K31Elecraft = False # K31 mode
h = self.Handlers = {} # Branch on the first two letters of the command
h['AI'] = self.AiAutoInfo
h['CW'] = self.CwCWPitch
h['DT'] = self.DtDataMode
h['FA'] = self.FaFbVfoFreq
h['FB'] = self.FaFbVfoFreq
h['FT'] = self.FtTxVfo
h['FW'] = self.FwFilterBW
h['ID'] = self.IdIdent
h['IF'] = self.IfInfo
h['IS'] = self.IsCenterPitch
h['KS'] = self.KsKeyerSpeed
h['K3'] = self.K3Elecraft
h['LN'] = self.LnLinkVfo
h['MD'] = self.MdMode
h['OM'] = self.OmOptionModules
h['RV'] = self.RvFirmware
h['RX'] = self.RxReceive
h['SB'] = self.SbSubReceiver
h['SM'] = self.SmSmeter
h['TX'] = self.TxTransmit
def Send(self, text):
"""Send text back to the client."""
if HAMLIB_DEBUG:
for cmd in self.cmds[0:-1]:
print ("CatTcp received: %-10s" % cmd)
print ("CatTcp received: %-10s ; sent %s" % (self.cmds[-1], text))
del self.cmds[:]
text = text.encode('utf-8', errors='ignore')
try:
self.sock.sendall(text)
except socket.error:
self.sock.close()
self.sock = None
def Process(self):
"""This is the main processing loop, and is called frequently. It reads and satisfies requests."""
if not self.sock:
return 0
try: # Read any data from the socket
text = self.sock.recv(1024)
except socket.timeout: # This does not work
pass
except socket.error: # Nothing to read
pass
else: # We got some characters
text = text.decode('utf-8', errors='ignore')
self.received += text
if HAMLIB_DEBUG and text:
pass #print ("Raw CatTcp received:", text)
if ';' in self.received: # A complete command ending with semicolon is available
cmd, self.received = self.received.split(';', 1) # Split off the command, save any further characters
else:
return 1
cmd = cmd.strip() # Here is our command line
if len(cmd) < 2:
return 1
if HAMLIB_DEBUG:
self.cmds.append(cmd)
base = cmd[0:2].upper()
try:
handler = self.Handlers[base]
except KeyError:
self.Send(cmd[0:2] + "?;")
#print ("Unknown command", cmd)
return 1
if len(cmd) == 2:
args = ''
elif cmd[2] == '$': # base is the first two letters upper case and any following "$"
base += '$'
args = cmd[3:]
else:
args = cmd[2:]
handler(base, args) # args is the remainder
return 1
def AiAutoInfo(self, base, args):
if not args:
self.Send("AI0;")
elif args != '0':
self.Send("AI0;")
def CwCWPitch(self, base, args):
pitch = self.conf.cwTone
pitch = (pitch + 5) // 10
if pitch < 25:
pitch = 25
elif pitch > 95:
pitch = 95
self.Send("CW%d;" % pitch)
def DtDataMode(self, base, args):
self.Send("%s0;" % base)
def IdIdent(self, base, args):
if args:
self.Send("ID?;")
else:
self.Send("ID017;")
#self.Send("IDQuisk;")
def IfInfo(self, base, args):
rxfreq = self.GetFreqVfo()
info = "%011d " % rxfreq # Rx frequency, five blanks
ritFreq = self.app.ritScale.GetValue()
if ritFreq < 0: # +/- RIT freq
info += "-%04d" % -ritFreq
else:
info += "+%04d" % ritFreq
if self.app.ritButton.GetValue(): # RIT status, XIT status, blank "00"
info += "10 00"
else:
info += "00 00"
if QS.is_key_down(): # MOX, key down
info += '1'
else:
info += '0'
mode = self.Mo2CoElecraft.get(self.app.mode, 2)
info += "%d" % mode # Mode 1-9
info += '00' # Rx on VFOA, no scan
if self.app.split_rxtx: # VFO split status
info += '1'
else:
info += '0'
info += '001 ;'
self.Send(info)
def FaFbVfoFreq(self, base, args):
if base[1] in ('B', 'b'):
vfoB = True
else:
vfoB = False
if not args: # Get command
freq = "%06d" % self.GetFreqVfo(vfoB)
self.Send(base + freq + ';')
else: # Put command
try:
freq = int(args)
except:
self.Send(base + "?;")
else:
l = len(args)
if l <= 2:
freq *= 1000000
elif l <= 5:
freq *= 1000
self.SetFreqVfo(freq, vfoB)
def FtTxVfo(self, base, args):
if not args:
if self.app.split_rxtx:
self.Send("FT1;")
else:
self.Send("FT0;")
else:
# Set split Rx/Tx mode.
is_split = self.app.splitButton.GetValue()
split = int(args)
if split and not is_split:
self.app.splitButton.SetValue(split, True)
elif is_split and not split:
self.app.splitButton.SetValue(split, True)
def FwFilterBW(self, base, args):
if not args:
code = self.GetFilterBW()
self.Send("%s%04d;" % (base, (code + 5) // 10))
else:
self.SetFilterBW(int(args) * 10)
def IsCenterPitch(self, base, args):
if not args:
code = self.GetFilterBW() // 2
if self.K31Elecraft:
self.Send("%s %04d;" % (base, code))
else:
code = (code + 5) // 10
self.Send("%s%04d;" % (base, code))
else:
if self.K31Elecraft:
self.SetFilterBW(int(args) * 2)
else:
self.SetFilterBW(int(args) * 2 * 10)
def K3Elecraft(self, base, args):
if args == '1':
self.K31Elecraft = True
else:
self.K31Elecraft = False
def KsKeyerSpeed(self, base, args):
if len(base) == 2:
self.Send("KS013;")
def LnLinkVfo(self, base, args):
if args != '0':
self.Send("LN0;")
def MdMode(self, base, args):
if args: # set the mode
code = int(args)
mode = self.Co2MoElecraft[code]
self.app.modeButns.SetLabel(mode, True)
else: # return the mode
code = self.Mo2CoElecraft.get(self.app.mode, 2)
self.Send("%s%d;" % (base, code))
def OmOptionModules(self, base, args):
self.Send("OM ------------;")
def RvFirmware(self, base, args):
self.Send("%s99.99;" % base)
def RxReceive(self, base, args):
self.app.pttButton.SetValue(0, True)
def SbSubReceiver(self, base, args):
self.Send("SB0;")
def SmSmeter(self, base, args):
if base[0:3].upper() == "SMH":
self.Send(base + "?;")
elif args:
self.Send(base + "?;")
elif self.K31Elecraft:
self.Send("SM0000;")
else:
self.Send("SM00;")
def TxTransmit(self, base, args):
self.app.pttButton.SetValue(1, True)
class SoundThread(threading.Thread):
"""Create a second (non-GUI) thread to read, process and play sound."""
def __init__(self, samples_from_python):
@@ -3698,6 +3968,19 @@ class App(wx.App):
# traceback.print_exc()
else:
self.hamlib_socket = None
# Quisk control by K4 commands through a TCP port
self.k4_tcp_clients = [] # list of TCP connections to handle
if conf.k4_tcp_port:
try:
self.k4_tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.k4_tcp_socket.bind((conf.k4_tcp_ip, conf.k4_tcp_port))
self.k4_tcp_socket.settimeout(0.0)
self.k4_tcp_socket.listen(5) # listen for TCP connections from multiple clients
except:
self.k4_tcp_socket = None
# traceback.print_exc()
else:
self.k4_tcp_socket = None
# Quisk control by fldigi
self.fldigi_new_freq = None
self.fldigi_freq = None
@@ -4406,6 +4689,9 @@ class App(wx.App):
if self.hamlib_socket:
self.hamlib_socket.close()
self.hamlib_socket = None
if self.k4_tcp_socket:
self.k4_tcp_socket.close()
self.k4_tcp_socket = None
if self.dxCluster:
self.dxCluster.stop()
if self.hamlib_com1_handler:
@@ -6383,7 +6669,7 @@ class App(wx.App):
if rxtx != 'rx':
self.fldigi_server.main.rx()
self.fldigi_timer = time.time()
def HamlibPoll(self): # Poll for Hamlib commands
def HamlibPoll(self): # Poll for Hamlib and K4 TCP commands
if self.hamlib_socket:
try: # Poll for new client connections.
conn, address = self.hamlib_socket.accept()
@@ -6397,6 +6683,19 @@ class App(wx.App):
self.hamlib_clients.remove(client)
# print ('Remove', client.address)
break
if self.k4_tcp_socket:
try: # Poll for new client connections.
conn, address = self.k4_tcp_socket.accept()
except socket.error:
pass
else:
# print ('Connection from', address)
self.k4_tcp_clients.append(ElecraftK4Handler(self, conf, conn, address))
for client in self.k4_tcp_clients: # Service existing clients
if not client.Process(): # False return indicates a closed connection; remove the handler for this client
self.k4_tcp_clients.remove(client)
# print ('Remove', client.address)
break
def OnKeyHook(self, event):
event.Skip()
if conf.hot_key_ptt_if_hidden: # Hot key PTT operates even if Quisk is hidden
+55 -41
View File
@@ -1094,6 +1094,11 @@ file_play_level = 1.000
#file_play_level = 0.500
#file_play_level = 0.100
## IQ_Server_IP Pulse server IP address, text
# IP Address for remote PulseAudio IQ server.
IQ_Server_IP = ""
#IQ_Server_IP = "192.168.230.102"
# Sound card names:
#
# In PortAudio, soundcards have an index number 0, 1, 2, ... and a name.
@@ -1303,51 +1308,15 @@ fixed_tune_offset = 0
################ Remote
# DX cluster telent login data, thanks to DJ4CM. Must have station_display_lines > 0.
## dxClHost Dx cluster host name, text
# The Dx cluster options log into a Dx cluster server, and put station information
# on the station window under the graph and waterfall screens.
# dxClHost is the telnet host name.
dxClHost = ''
#dxClHost = 'example.host.net'
## dxClPort Dx cluster port number, integer
# The Dx cluster options log into a Dx cluster server, and put station information
# on the station window under the graph and waterfall screens.
# dxClPort is the telnet port number.
dxClPort = 7373
## user_call_sign Call sign for Dx cluster, text
# The Dx cluster options log into a Dx cluster server, and put station information
# on the station window under the graph and waterfall screens.
# user_call_sign is your call sign which may be needed for login.
user_call_sign = ''
## dxClPassword Password for Dx cluster, text
# The Dx cluster options log into a Dx cluster server, and put station information
# on the station window under the graph and waterfall screens.
# dxClPassword is the telnet password for the server.
dxClPassword = ''
#dxClPassword = 'getsomedx'
## dxClExpireTime Dx cluster expire minutes, integer
# The Dx cluster options log into a Dx cluster server, and put station information
# on the station window under the graph and waterfall screens.
# dxClExpireTime is the time in minutes until DX Cluster entries are removed.
dxClExpireTime = 20
## IQ_Server_IP Pulse server IP address, text
#IP Address for remote PulseAudio IQ server.
IQ_Server_IP = ""
## hamlib_ip IP address for Hamlib Rig 2, text
# You can control Quisk from Hamlib. Set the Hamlib rig to 2 and the device for rig 2 to
# localhost:4575. Or choose a different name and port here. Set the same name and port
# in the controlling program.
# hamlib_ip is the IP name or address.
hamlib_ip = "localhost"
hamlib_ip = ""
#hamlib_ip = "localhost"
## hamlib_port IP port for Hamlib, integer
## hamlib_port IP port for Hamlib Rig 2, integer
# You can control Quisk from Hamlib. For direct control, set the external program to rig 2
# "Hamlib NET rigctl", and set the Quisk hamlib port to 4532. To use the rigctld program to control
# Quisk, set the Quisk hamlib port to 4575. To turn off Hamlib control, set the Quisk port to zero.
@@ -1398,19 +1367,64 @@ win_hamlib_com2_name = ""
#win_hamlib_com2_name = "COM15"
#win_hamlib_com2_name = "COM16"
## remote_radio_ip Remote radio IP or name, text
## remote_radio_ip IP or name of the remote radio, text
# Quisk can be used as a control head to control a real radio located remotely.
# This is the IP adddress or the host name of the remote radio.
remote_radio_ip = ""
#remote_radio_ip = "192.168.1.56"
## remote_radio_password Password for remote radio, text
## remote_radio_password Password for the remote radio, text
# Quisk can be used as a control head to control a real radio located remotely.
# For security it requires the same password to be entered on both computers.
# Enter a fairly long pass phrase of 20 or more characters.
# It is only necessary to enter it once on each computer.
remote_radio_password = ""
## k4_tcp_ip IP address for K4 TCP, text
# This is the Quisk IP address for the TCP server implementing K4 commands.
k4_tcp_ip = ""
#k4_tcp_ip = "localhost"
#k4_tcp_ip = "127.0.0.1"
## k4_tcp_port Port number for K4 TCP, integer
# This is the Quisk port for the TCP server implementing K4 commands.
k4_tcp_port = 0
#k4_tcp_port = 9200
#k4_tcp_port = 50004
# DX cluster telent login data, thanks to DJ4CM. Must have station_display_lines > 0.
## dxClHost Dx cluster host name, text
# The Dx cluster options log into a Dx cluster server, and put station information
# on the station window under the graph and waterfall screens.
# dxClHost is the telnet host name.
dxClHost = ''
#dxClHost = 'example.host.net'
## dxClPort Dx cluster port number, integer
# The Dx cluster options log into a Dx cluster server, and put station information
# on the station window under the graph and waterfall screens.
# dxClPort is the telnet port number.
dxClPort = 7373
## user_call_sign Call sign for Dx cluster, text
# The Dx cluster options log into a Dx cluster server, and put station information
# on the station window under the graph and waterfall screens.
# user_call_sign is your call sign which may be needed for login.
user_call_sign = ''
## dxClPassword Password for Dx cluster, text
# The Dx cluster options log into a Dx cluster server, and put station information
# on the station window under the graph and waterfall screens.
# dxClPassword is the telnet password for the server.
dxClPassword = ''
#dxClPassword = 'getsomedx'
## dxClExpireTime Dx cluster expire minutes, integer
# The Dx cluster options log into a Dx cluster server, and put station information
# on the station window under the graph and waterfall screens.
# dxClExpireTime is the time in minutes until DX Cluster entries are removed.
dxClExpireTime = 20
hamlib_com1_name = ""
+1 -1
View File
@@ -7,7 +7,7 @@ import os
# You must define the version here. A title string including
# the version will be written to __init__.py and read by quisk.py.
Version = '4.2.41'
Version = '4.2.42'
fp = open("__init__.py", "w") # write title string
fp.write("#Quisk version %s\n" % Version)