3 Commits
Author SHA1 Message Date
James C. Ahlstrom 7e8a0846f7 Quisk version 4.2.40 2024-11-15 16:39:47 -05:00
James C. Ahlstrom fb888a2e08 Quisk version 4.2.39 2024-10-01 14:22:23 -04:00
James C. Ahlstrom 78a1ca3d60 Quisk version 4.2.38 2024-09-01 13:57:53 -04:00
9 changed files with 175 additions and 82 deletions
+21
View File
@@ -1,3 +1,24 @@
Quisk Version 4.2.40 November 2024
===================================
Python 3.13 eliminated the telnetlib module, so I wrote a replacement. I fixed a bug in window sizing.
If you use the Dx Cluster feature, please report any problems. Dx Cluster used to use the telnetlib module
but is now new code.
I updated the install to Python 3.13. Please report any problems with Python 3.13.
Quisk Version 4.2.39 October 2024
==================================
I added an optional Hardware method PollGuiControl(self). If you define this in your Hardware file,
the GUI thread will call it frequently. It can be used to set PTT from your hardware.
I am trying to work around a wxPython quirk that causes mouse wheel tuning to fail. Please test.
Quisk Version 4.2.38 September 2024
====================================
This is a bugfix release. I fixed a bug in the Hamlib serial port when using a physical TTY instead
of a pseudo-tty. The Hamlib ZZFA command now changes the receive frequency instead of the transmit
frequency. I fixed some window sizing issues.
Quisk Version 4.2.37 August 2024 Quisk Version 4.2.37 August 2024
================================= =================================
Quisk now has a new option "Fixed tune offset" on the Config/radio/Options screen. This is meant for Quisk now has a new option "Fixed tune offset" on the Config/radio/Options screen. This is meant for
+1 -1
View File
@@ -1,2 +1,2 @@
#Quisk version 4.2.37 #Quisk version 4.2.40
from .quisk import main from .quisk import main
+80 -32
View File
@@ -1,9 +1,9 @@
from __future__ import absolute_import
# This code was contributed by Christof, DJ4CM. Many Thanks!! # This code was contributed by Christof, DJ4CM. Many Thanks!!
# Modified November 2024 by N2ADR to remove deprecated telnetlib module.
import threading import threading
import socket
import time import time
import telnetlib
import quisk_conf_defaults as conf import quisk_conf_defaults as conf
class DxEntry: class DxEntry:
@@ -81,61 +81,109 @@ class DxEntry:
class DxCluster(threading.Thread): class DxCluster(threading.Thread):
def __init__(self): def __init__(self):
self.do_init = 1 self.error = 'Starting'
self.dxSpots = []
threading.Thread.__init__(self) threading.Thread.__init__(self)
self.doQuit = threading.Event() self.doQuit = threading.Event()
self.dxSpots = []
self.doQuit.clear() self.doQuit.clear()
self.dxLock = threading.Lock()
self.addr = conf.dxClHost + ':' + str(conf.dxClPort)
self.msg_no_spots = "No DX Cluster data from " + self.addr
self.msg_one_spot = '1 DX spot received from ' + self.addr
self.msg_spots = ' DX spots received from ' + self.addr
def run(self): def run(self):
self.telnetInit()
self.telnetConnect() self.telnetConnect()
if self.error:
self.sock.close()
return
while not self.doQuit.isSet(): while not self.doQuit.isSet():
try: try:
self.telnetRead() by = self.sock.recv(1024)
except TimeoutError:
continue
except: except:
self.tn.close() by = b''
time.sleep(20) if by:
with self.dxLock:
self.bytes += by
else:
self.sock.close()
self.error = "Restarting " + self.addr
time.sleep(2)
if not self.doQuit.isSet(): if not self.doQuit.isSet():
self.telnetConnect() self.telnetConnect()
self.tn.close() if self.error:
self.sock.close()
def setListener (self, listener): return
self.listener = listener self.sock.close()
def telnetInit(self):
self.tn = telnetlib.Telnet()
def telnetConnect(self): def telnetConnect(self):
self.bytes = bytearray(0)
self.error = 'Starting'
self.sock = socket.socket()
self.sock.settimeout(20)
try:
self.sock.connect( (conf.dxClHost, conf.dxClPort) )
except:
self.error = "Failed to connect to " + self.addr
return
self.sock.settimeout(1)
for i in range(10): for i in range(10):
try: try:
self.tn.open(conf.dxClHost, conf.dxClPort, 10) self.bytes += self.sock.recv(1024)
self.tn.read_until(b"login:", 10)
self.tn.write(conf.user_call_sign.encode('utf-8', errors='ignore') + b"\n") # user_call_sign may be Unicode
break
except: except:
time.sleep(0.5) pass
if b"login:" in self.bytes:
break
else:
self.error = 'No "login:" prompt from ' + self.addr
return
self.sock.sendall(conf.user_call_sign.encode('utf-8', errors='ignore') + b"\r\n")
if conf.dxClPassword: if conf.dxClPassword:
self.tn.read_until(b"Password: ") for i in range(10):
self.tn.write(conf.dxClPassword.encode('utf-8', errors='ignore') + b"\n") try:
self.bytes += self.sock.recv(1024)
except:
pass
if b"Password:" in self.bytes:
break
else:
self.error = 'No "Password:" prompt from ' + self.addr
return
self.sock.sendall(conf.dxClPassword.encode('utf-8', errors='ignore') + b"\r\n")
self.error = ''
self.bytes = bytearray(0)
def telnetRead(self): def Poll(self):
message = self.tn.read_until(b'\n', 60).decode(encoding='utf-8', errors='replace') with self.dxLock:
if self.doQuit.isSet() == False: index = self.bytes.find(b"\n")
dxEntry = DxEntry(); if index >= 0:
message = self.bytes[0:index + 1]
self.bytes = self.bytes[index + 1:]
else:
return
message = message.decode(encoding='utf-8', errors='replace')
dxEntry = DxEntry()
if dxEntry.parseMessage(message): if dxEntry.parseMessage(message):
for i, listElement in enumerate(self.dxSpots): for i, listElement in enumerate(self.dxSpots):
if (listElement.equal(dxEntry)): if (listElement.equal(dxEntry)):
listElement.join (dxEntry) listElement.join (dxEntry)
return return True
if listElement.isExpired(): if listElement.isExpired():
del (self.dxSpots[i]) del (self.dxSpots[i])
self.dxSpots.append(dxEntry) self.dxSpots.append(dxEntry)
if self.listener: return True
self.listener()
def getHost(self):
return self.tn.host + ':' + str(self.tn.port)
def stop(self): def stop(self):
self.doQuit.set() self.doQuit.set()
def dxStatus(self):
if self.error:
return self.error
nSpots = len(self.dxSpots)
if nSpots == 0:
return self.msg_no_spots
elif nSpots == 1:
return self.msg_one_spot
return str(nSpots) + self.msg_spots
+2
View File
@@ -402,6 +402,8 @@ class Hardware(BaseHardware):
if do_tx: if do_tx:
try: try:
self.rx_udp_socket.send(s) self.rx_udp_socket.send(s)
if DEBUG:
self.PrintStatus(' Send', self.want_udp_status)
except: except:
pass pass
def SetVNA(self, key_down=None, vna_start=None, vna_stop=None, vna_count=None, do_tx=False): def SetVNA(self, key_down=None, vna_start=None, vna_stop=None, vna_count=None, do_tx=False):
+22 -1
View File
@@ -91,6 +91,8 @@ class Hardware(BaseHardware):
conf.si570_direct_control = False conf.si570_direct_control = False
conf.si570_xtal_freq = 114285000 conf.si570_xtal_freq = 114285000
conf.repeater_delay = 0.25 conf.repeater_delay = 0.25
self.ptt_count = 200
self.ptt_on = 0
BaseHardware.__init__(self, app, conf) BaseHardware.__init__(self, app, conf)
QS.set_sparams(multus_cw_samples=1) QS.set_sparams(multus_cw_samples=1)
self.use_softrock = True self.use_softrock = True
@@ -104,6 +106,13 @@ class Hardware(BaseHardware):
self.usb_dev.ctrl_transfer(OUT, address, self.si570_i2c_address + 0x700, 0, message) self.usb_dev.ctrl_transfer(OUT, address, self.si570_i2c_address + 0x700, 0, message)
if DEBUG: if DEBUG:
print ("USB send to 0x%X" % address, message) print ("USB send to 0x%X" % address, message)
def TransferIn(self, address, length):
if self.usb_dev:
recv = self.usb_dev.ctrl_transfer(IN, address, self.si570_i2c_address + 0x700, 0, length)
if DEBUG:
print ("USB receive from 0x%X" % address, recv)
return recv
return None
def open(self): def open(self):
text = BaseHardware.open(self) text = BaseHardware.open(self)
self.InitKeyer() self.InitKeyer()
@@ -120,8 +129,20 @@ class Hardware(BaseHardware):
print ("Mode is not CW") print ("Mode is not CW")
self.TransferOut(0x70, cw_mode) self.TransferOut(0x70, cw_mode)
return ret return ret
def PollCwKey(self): # Called frequently by Quisk to check the CW key status def PollCwKey(self): # Called frequently from the sound thread to check the CW key status
return # Quisk is always in Rx return # Quisk is always in Rx
def PollGuiControl(self): # Called frequently from the GUI thread
self.ptt_count -= 1
if self.ptt_count <= 0:
self.ptt_count = 200
reply = self.TransferIn(0xA5, 1)
if DEBUG:
print ("PollGuiControl got", reply)
if reply:
ptt = reply[0] # This is 255 for error
if ptt in (0, 1) and ptt != self.ptt_on:
self.ptt_on = ptt
self.application.pttButton.SetValue(ptt, True)
def InitKeyer(self): def InitKeyer(self):
# Initialize the keyer parameters # Initialize the keyer parameters
conf = self.conf conf = self.conf
+37 -39
View File
@@ -334,6 +334,7 @@ class HamlibHandlerSerial:
self.public_name = public_name # the public name for the serial port self.public_name = public_name # the public name for the serial port
self.tune_step = 1000 self.tune_step = 1000
if sys.platform == 'win32' or public_name.startswith("/dev/"): if sys.platform == 'win32' or public_name.startswith("/dev/"):
self.port_is_mod_serial = True # self.port is from the serial module
try: try:
import serial import serial
except: except:
@@ -346,6 +347,7 @@ class HamlibHandlerSerial:
print ("The serial port %s could not be opened." % public_name) print ("The serial port %s could not be opened." % public_name)
else: else:
import tty import tty
self.port_is_mod_serial = False # self.port is a file descriptor
if os.path.lexists(public_name): if os.path.lexists(public_name):
try: try:
os.remove(public_name) os.remove(public_name)
@@ -369,7 +371,7 @@ class HamlibHandlerSerial:
def open(self): def open(self):
return return
def close(self): def close(self):
if sys.platform == 'win32': if self.port_is_mod_serial:
if self.port: if self.port:
self.port.close() self.port.close()
self.port = None self.port = None
@@ -382,7 +384,7 @@ class HamlibHandlerSerial:
def Read(self): def Read(self):
if self.port is None: if self.port is None:
return return
if sys.platform == 'win32': if self.port_is_mod_serial:
text = self.port.read(99) text = self.port.read(99)
if not isinstance(text, Q3StringTypes): if not isinstance(text, Q3StringTypes):
text = text.decode('utf-8') text = text.decode('utf-8')
@@ -433,22 +435,14 @@ class HamlibHandlerSerial:
return return
if isinstance(data, Q3StringTypes): if isinstance(data, Q3StringTypes):
data = data.encode('utf-8', errors='ignore') data = data.encode('utf-8', errors='ignore')
if sys.platform == 'win32': if self.port_is_mod_serial:
self.port.write(data) self.port.write(data)
else: else:
r, w, x = select.select((), (self.port,), (), 0) r, w, x = select.select((), (self.port,), (), 0)
if w: if w:
os.write(self.port, data) os.write(self.port, data)
def set_frequency(self, freq): def set_frequency(self, freq): # This changes the Rx frequency
tune = freq - self.app.VFO self.app.ChangeRxTxFrequency(freq, None)
d = self.app.sample_rate * 45 // 100
if -d <= tune <= d: # Frequency is on-screen
vfo = self.app.VFO
else: # Change the VFO
vfo = (freq // 5000) * 5000 - 5000
tune = freq - vfo
self.app.BandFromFreq(freq)
self.app.ChangeHwFrequency(tune, vfo, 'FreqEntry')
if HAMLIB_DEBUG: print("New Freq rx,tx", self.app.txFreq + self.app.VFO, self.app.rxFreq + self.app.VFO) if HAMLIB_DEBUG: print("New Freq rx,tx", self.app.txFreq + self.app.VFO, self.app.rxFreq + self.app.VFO)
def ZZAC(self, cmd, data, length): # Set or read tune steps def ZZAC(self, cmd, data, length): # Set or read tune steps
if length == 0: if length == 0:
@@ -1440,12 +1434,8 @@ class ConfigStatus(wx.ScrolledCanvas):
self.MakeRow2("Sample interrupts", self.interrupts, cfile) self.MakeRow2("Sample interrupts", self.interrupts, cfile)
self.MakeRow2("Microphone or DGT level dB", level, qfile) self.MakeRow2("Microphone or DGT level dB", level, qfile)
self.MakeRow2("FFT number of points", self.fft_size, err_msg) self.MakeRow2("FFT number of points", self.fft_size, err_msg)
if conf.dxClHost: # connection to dx cluster if application.dxCluster:
nSpots = len(application.dxCluster.dxSpots) msg = application.dxCluster.dxStatus()
if nSpots > 0:
msg = str(nSpots) + ' DX spot' + ('' if nSpots==1 else 's') + ' received from ' + application.dxCluster.getHost()
else:
msg = "No DX Cluster data from %s" % conf.dxClHost
self.MakeRow2("FFT number of errors", self.fft_error, msg) self.MakeRow2("FFT number of errors", self.fft_error, msg)
else: else:
self.MakeRow2("FFT number of errors", self.fft_error) self.MakeRow2("FFT number of errors", self.fft_error)
@@ -2129,7 +2119,7 @@ class GraphScreen(wx.Window):
"""For mouse clicks in our display, translate to our screen coordinates.""" """For mouse clicks in our display, translate to our screen coordinates."""
mouse_x, mouse_y = event.GetPosition() mouse_x, mouse_y = event.GetPosition()
win = event.GetEventObject() win = event.GetEventObject()
if win is not self: if win and win is not self:
x, y = win.GetPosition().Get() x, y = win.GetPosition().Get()
mouse_x += x mouse_x += x
mouse_y += y mouse_y += y
@@ -2643,7 +2633,7 @@ class WaterfallScreen(wx.SplitterWindow):
self.y_zero = conf.waterfall_y_zero self.y_zero = conf.waterfall_y_zero
self.zoom_control = 0 self.zoom_control = 0
wx.SplitterWindow.__init__(self, frame) wx.SplitterWindow.__init__(self, frame)
self.SetSizeHints(width, -1, width) self.SetSizeHints(width, -1)
self.SetSashGravity(0.50) self.SetSashGravity(0.50)
self.SetMinimumPaneSize(1) self.SetMinimumPaneSize(1)
self.SetSize((width, conf.waterfall_graph_size + 100)) # be able to set sash size self.SetSize((width, conf.waterfall_graph_size + 100)) # be able to set sash size
@@ -2997,7 +2987,7 @@ class MultiReceiverScreen(wx.SplitterWindow):
self.rx_zero = self.graph self.rx_zero = self.graph
self.Initialize(self.rx_zero) self.Initialize(self.rx_zero)
self.waterfall.Hide() self.waterfall.Hide()
self.SetSizeHints(self.width, -1, self.width) self.SetSizeHints(self.width, -1)
# Calculate control width # Calculate control width
rx_btn = QuiskPushbutton(self, None, "Rx 8....", style=wx.BU_EXACTFIT) rx_btn = QuiskPushbutton(self, None, "Rx 8....", style=wx.BU_EXACTFIT)
self.rx_btn_width, self.rx_btn_height = rx_btn.GetSize().Get() self.rx_btn_width, self.rx_btn_height = rx_btn.GetSize().Get()
@@ -3530,6 +3520,7 @@ class App(wx.App):
if not os.path.isdir(self.QuiskFilesDir): if not os.path.isdir(self.QuiskFilesDir):
self.QuiskFilesDir = DefaultConfigDir self.QuiskFilesDir = DefaultConfigDir
self.std_out_err = StdOutput(self) self.std_out_err = StdOutput(self)
self.std_out_err.Logfile("WxPython " + wx.version())
QS.set_params(quisk_is_vna=0) # We are not the VNA program QS.set_params(quisk_is_vna=0) # We are not the VNA program
# Read in configuration from the selected radio # Read in configuration from the selected radio
self.BandPlan = [] self.BandPlan = []
@@ -3620,6 +3611,7 @@ class App(wx.App):
setattr(conf, 'widgets_file_name', '') setattr(conf, 'widgets_file_name', '')
Hardware = self.Hardware Hardware = self.Hardware
self.use_fast_heart_beat = hasattr(Hardware, "FastHeartBeat") self.use_fast_heart_beat = hasattr(Hardware, "FastHeartBeat")
self.poll_gui_control = hasattr(Hardware, "PollGuiControl")
# Initialization - may be over-written by persistent state # Initialization - may be over-written by persistent state
self.local_conf.Initialize() self.local_conf.Initialize()
self.clip_time0 = 0 # timer to display a CLIP message on ADC overflow self.clip_time0 = 0 # timer to display a CLIP message on ADC overflow
@@ -3830,9 +3822,10 @@ class App(wx.App):
self.std_out_err.Show(False) self.std_out_err.Show(False)
else: else:
self.std_out_err.Show(True) self.std_out_err.Show(True)
wClient, hClient = frame.GetClientSize() wClient, hClient = self.main_frame.GetClientSize()
#w, h = frame.GetSize().Get() wFrame, hFrame = self.main_frame.GetSize()
#print ('Main frame: size', w, h, 'client', wClient, hClient) main_border_w = wFrame - wClient
#print ('Main frame: size', wFrame, hFrame, 'client', wClient, hClient, 'border', main_border_w)
# Find the data width from a list of preferred sizes; it is the width of returned graph data. # Find the data width from a list of preferred sizes; it is the width of returned graph data.
# The graph_width is the width of data_width that is displayed. # The graph_width is the width of data_width that is displayed.
# The total width of the graph is graph_width + self.graph_borders # The total width of the graph is graph_width + self.graph_borders
@@ -3963,14 +3956,14 @@ class App(wx.App):
frame.SetSizer(vertBox) frame.SetSizer(vertBox)
# Add the screens # Add the screens
vertBox.Add(self.config_screen, 1, wx.EXPAND) vertBox.Add(self.config_screen, 1, wx.EXPAND)
vertBox.Add(self.multi_rx_screen, 1) vertBox.Add(self.multi_rx_screen, 1, wx.EXPAND)
vertBox.Add(self.scope, 1) vertBox.Add(self.scope, 1, wx.EXPAND)
vertBox.Add(self.bandscope_screen, 1) vertBox.Add(self.bandscope_screen, 1, wx.EXPAND)
vertBox.Add(self.filter_screen, 1) vertBox.Add(self.filter_screen, 1, wx.EXPAND)
if self.rate_audio_fft: if self.rate_audio_fft:
vertBox.Add(self.audio_fft_screen, 1) vertBox.Add(self.audio_fft_screen, 1, wx.EXPAND)
vertBox.Add(self.help_screen, 1) vertBox.Add(self.help_screen, 1, wx.EXPAND)
vertBox.Add(self.station_screen) vertBox.Add(self.station_screen, 0, wx.EXPAND)
# Add the spacer # Add the spacer
vertBox.Add(Spacer(frame), 0, wx.EXPAND) vertBox.Add(Spacer(frame), 0, wx.EXPAND)
# Add the sizer for the controls # Add the sizer for the controls
@@ -3983,13 +3976,16 @@ class App(wx.App):
vertBox.AddSpacer(5) # Thanks to Christof, DJ4CM vertBox.AddSpacer(5) # Thanks to Christof, DJ4CM
# End of vertical box. # End of vertical box.
self.MakeButtons(frame, gbs) self.MakeButtons(frame, gbs)
minw = width = self.graph.width
maxw = maxh = -1
minh = 100
if conf.window_width > 0: if conf.window_width > 0:
minw = width = maxw = conf.window_width minw = maxw = conf.window_width
else:
minw = self.graph.width + main_border_w
maxw = -1
if conf.window_height > 0: if conf.window_height > 0:
minh = maxh = self.height = conf.window_height minh = maxh = self.height = conf.window_height
else:
minh = 100
maxh = -1
self.main_frame.SetSizeHints(minw, minh, maxw, maxh) self.main_frame.SetSizeHints(minw, minh, maxw, maxh)
self.main_frame.SetClientSize(wx.Size(width, self.height)) self.main_frame.SetClientSize(wx.Size(width, self.height))
if hasattr(Hardware, 'pre_open'): # pre_open() is called before open() if hasattr(Hardware, 'pre_open'): # pre_open() is called before open()
@@ -4031,7 +4027,6 @@ class App(wx.App):
if conf.dxClHost: if conf.dxClHost:
# create DX Cluster and register listener for change notification # create DX Cluster and register listener for change notification
self.dxCluster = dxcluster.DxCluster() self.dxCluster = dxcluster.DxCluster()
self.dxCluster.setListener(self.OnDxClChange)
self.dxCluster.start() self.dxCluster.start()
# Create shortcut keys for buttons # Create shortcut keys for buttons
if conf.button_layout == 'Large screen': if conf.button_layout == 'Large screen':
@@ -4382,8 +4377,6 @@ class App(wx.App):
conf.tx_ip, conf.tx_audio_port, conf.tx_ip, conf.tx_audio_port,
conf.mic_sample_rate, conf.mic_channel_I, conf.mic_channel_Q, conf.mic_sample_rate, conf.mic_channel_I, conf.mic_channel_Q,
0.7, conf.mic_playback_rate) 0.7, conf.mic_playback_rate)
def OnDxClChange(self):
self.station_screen.Refresh()
def OnIdle(self, event): def OnIdle(self, event):
if self.screen: if self.screen:
self.screen.OnIdle(event) self.screen.OnIdle(event)
@@ -6458,6 +6451,8 @@ class App(wx.App):
self.hamlib_com2_handler.Process() self.hamlib_com2_handler.Process()
if self.use_fast_heart_beat: if self.use_fast_heart_beat:
Hardware.FastHeartBeat() Hardware.FastHeartBeat()
if self.poll_gui_control:
Hardware.PollGuiControl()
if conf.do_repeater_offset: if conf.do_repeater_offset:
hold = QS.tx_hold_state(-1) hold = QS.tx_hold_state(-1)
if hold == 2: # Tx is being held for an FM repeater TX frequency shift if hold == 2: # Tx is being held for an FM repeater TX frequency shift
@@ -6638,6 +6633,9 @@ class App(wx.App):
self.ChangeDisplayFrequency(tune - vfo, vfo) self.ChangeDisplayFrequency(tune - vfo, vfo)
self.FldigiPoll() self.FldigiPoll()
self.HamlibPoll() self.HamlibPoll()
if self.dxCluster:
if self.dxCluster.Poll():
self.station_screen.Refresh()
if self.timer - self.slowheart_time0 > 0.5: if self.timer - self.slowheart_time0 > 0.5:
self.slowheart_time0 = self.timer self.slowheart_time0 = self.timer
if self.w_phase: if self.w_phase:
+2 -1
View File
@@ -29,9 +29,10 @@ class Hardware(BaseHardware):
# self.hamlib_rigctld_port = 4532 # Standard rigctld control port # self.hamlib_rigctld_port = 4532 # Standard rigctld control port
# self.hamlib_poll_seconds = 0.2 # Time interval to poll for changes # self.hamlib_poll_seconds = 0.2 # Time interval to poll for changes
def open(self): def open(self):
# Thanks to Peter, DC6AR, Rig ID changed from 229 to 2045.
ret = BaseHardware.open(self) ret = BaseHardware.open(self)
if not self.hamlib_connected: # rigctld is not started. Try to start it. if not self.hamlib_connected: # rigctld is not started. Try to start it.
os.system("rigctld -m 229 -r /dev/ttyUSB0 -s 4800 & ") # Check the baud rate menu setting os.system("rigctld -m 2045 -r /dev/ttyUSB0 -s 4800 & ") # Check the baud rate menu setting
# If this fails, start rigctld by hand. # If this fails, start rigctld by hand.
return ret return ret
+2
View File
@@ -120,6 +120,8 @@ class Hardware:
self.application.bandscope_clock = clock self.application.bandscope_clock = clock
#def PollCwKey(self): # Optional. Called frequently by the sound thread to check the CW key status. #def PollCwKey(self): # Optional. Called frequently by the sound thread to check the CW key status.
# pass # Do not define if not needed. # pass # Do not define if not needed.
#def PollGuiControl(self): # Optional. Called frequently by the GUI thread to change GUI settings (PTT etc.)
# pass # Do not define if not needed.
def StartSamples(self): # Quisk calls this from the sound thread to start sending samples. def StartSamples(self): # Quisk calls this from the sound thread to start sending samples.
# If you return a string, it replaces the string returned from hardware open() # If you return a string, it replaces the string returned from hardware open()
pass pass
+1 -1
View File
@@ -7,7 +7,7 @@ import os
# You must define the version here. A title string including # You must define the version here. A title string including
# the version will be written to __init__.py and read by quisk.py. # the version will be written to __init__.py and read by quisk.py.
Version = '4.2.37' Version = '4.2.40'
fp = open("__init__.py", "w") # write title string fp = open("__init__.py", "w") # write title string
fp.write("#Quisk version %s\n" % Version) fp.write("#Quisk version %s\n" % Version)