Merge branch 'master' into kc4upr. Updating to quisk-4.1.53 in order to ensure that gpiokeyer etc is maintained current.
This commit is contained in:
commit
cf8aaa5ae0
@ -1,3 +1,15 @@
|
|||||||
|
Quisk Version 4.1.53 March 2020
|
||||||
|
================================
|
||||||
|
I changed the Afedri radio module to be compatible with Python3. The graph Zoom feature now is available
|
||||||
|
on the Bandscope screen. Vladimyr Burdeiny provided a patch to make dx cluster work with Python 3.
|
||||||
|
|
||||||
|
I extended the range of the Waterfall color controls Ys and Yz to accommodate hardware with a higher
|
||||||
|
noise floor such as PlutoSDR. You will have to readjust your waterfall colors.
|
||||||
|
|
||||||
|
I added a hardware setting for the LNA gain during transmit for the HL2. I made some changes to the CW
|
||||||
|
and PTT hardware interface for the HL2. These work great with the HL2, but test the new code if you have
|
||||||
|
diferent Hermes hardware such as Red Pitaya.
|
||||||
|
|
||||||
Quisk Version 4.1.52 December 2019
|
Quisk Version 4.1.52 December 2019
|
||||||
===================================
|
===================================
|
||||||
I added an On/Off button to Quisk. When Quisk starts the button is "On". When you turn it to "Off",
|
I added an On/Off button to Quisk. When Quisk starts the button is "On". When you turn it to "Off",
|
||||||
@ -7,8 +19,8 @@ and to re-start your hardware after a power down.
|
|||||||
|
|
||||||
Martin Schaller found and fixed a bug in the Alsa sound system that produced sporadic crashes. Thanks Martin!
|
Martin Schaller found and fixed a bug in the Alsa sound system that produced sporadic crashes. Thanks Martin!
|
||||||
Max, G7UOZ, found and fixed a bug in the Python3 SoftRock hardware_net.py code. Thanks Max!
|
Max, G7UOZ, found and fixed a bug in the Python3 SoftRock hardware_net.py code. Thanks Max!
|
||||||
This Quisk includes a more recent FreeDV library in both 32-bit and 64-bit versions. The SoapySDR interface
|
This Quisk includes a more recent FreeDV library in both 32-bit and 64-bit versions. The Windows
|
||||||
still requires 64-bit Quisk.
|
SoapySDR interface still requires 64-bit Quisk.
|
||||||
|
|
||||||
The Config/Status screen now shows the dB level of each open sound device. The maximum level is zero dB.
|
The Config/Status screen now shows the dB level of each open sound device. The maximum level is zero dB.
|
||||||
This is meant as an aid to configuring the sound devices.
|
This is meant as an aid to configuring the sound devices.
|
||||||
|
2
PKG-INFO
2
PKG-INFO
@ -1,6 +1,6 @@
|
|||||||
Metadata-Version: 1.1
|
Metadata-Version: 1.1
|
||||||
Name: quisk
|
Name: quisk
|
||||||
Version: 4.1.52
|
Version: 4.1.53
|
||||||
Summary: QUISK is a Software Defined Radio (SDR) transceiver that can control various radio hardware.
|
Summary: QUISK is a Software Defined Radio (SDR) transceiver that can control various radio hardware.
|
||||||
Home-page: http://james.ahlstrom.name/quisk/
|
Home-page: http://james.ahlstrom.name/quisk/
|
||||||
Author: James C. Ahlstrom
|
Author: James C. Ahlstrom
|
||||||
|
@ -1 +1 @@
|
|||||||
#Quisk version 4.1.52
|
#Quisk version 4.1.53
|
||||||
|
1
afedrinet/af_comp.bat.makeit
Executable file
1
afedrinet/af_comp.bat.makeit
Executable file
@ -0,0 +1 @@
|
|||||||
|
gcc -o afedrinet_io.pyd --shared afedrinet_io.c ../is_key_down.c ../import_quisk_api.c -O3 -I"../" -I"C:\Programs\Python27\include" -L"C:\Programs\Python27\libs" -lws2_32 -lpython27
|
@ -8,10 +8,15 @@ from __future__ import division
|
|||||||
# AFEDRI Class module
|
# AFEDRI Class module
|
||||||
# Title: afedri.py
|
# Title: afedri.py
|
||||||
# Author: k3it
|
# Author: k3it
|
||||||
|
|
||||||
# Adopted to work with Quisk
|
# Adopted to work with Quisk
|
||||||
# by 4Z5LV
|
# by 4Z5LV
|
||||||
# Last Changes: Sat Feb 02 2013
|
# Last Changes: Sat Feb 02 2013
|
||||||
# Version: 2.2
|
# Version: 2.2
|
||||||
|
|
||||||
|
# Adapted to work with Python3
|
||||||
|
# by N2ADR
|
||||||
|
# Last Changes: January 2020
|
||||||
##################################################
|
##################################################
|
||||||
|
|
||||||
from socket import *
|
from socket import *
|
||||||
@ -56,10 +61,10 @@ class afedri(object):
|
|||||||
if not self.s: return 1
|
if not self.s: return 1
|
||||||
__next_freq = target_freq
|
__next_freq = target_freq
|
||||||
__next_freq = struct.pack("<q",__next_freq)
|
__next_freq = struct.pack("<q",__next_freq)
|
||||||
__set_freq_cmd = "\x0a\x00\x20\x00\x00" + __next_freq[:5]
|
__set_freq_cmd = b"\x0a\x00\x20\x00\x00" + __next_freq[:5]
|
||||||
self.s.send(__set_freq_cmd)
|
self.s.send(__set_freq_cmd)
|
||||||
__data = self.s.recv(10)
|
__data = self.s.recv(10)
|
||||||
__freq = __data[5:] + "\0" * 3
|
__freq = __data[5:] + b"\x00\x00\x00"
|
||||||
__freq = struct.unpack("<q",__freq)[0]
|
__freq = struct.unpack("<q",__freq)[0]
|
||||||
return __freq
|
return __freq
|
||||||
|
|
||||||
@ -68,10 +73,10 @@ class afedri(object):
|
|||||||
if not self.s: return 1
|
if not self.s: return 1
|
||||||
#__samp_rate = target_samprate
|
#__samp_rate = target_samprate
|
||||||
__samp_rate = struct.pack("<L",target_samprate)
|
__samp_rate = struct.pack("<L",target_samprate)
|
||||||
__set_rate_cmd = "\x09\x00\xB8\x00\x00" + __samp_rate[:4]
|
__set_rate_cmd = b"\x09\x00\xB8\x00\x00" + __samp_rate[:4]
|
||||||
self.s.send(__set_rate_cmd)
|
self.s.send(__set_rate_cmd)
|
||||||
__data = self.s.recv(9)
|
__data = self.s.recv(9)
|
||||||
__samp = __data[5:] + "\0" * 4
|
__samp = __data[5:] + b"\x00\x00\x00\x00"
|
||||||
__samp = struct.unpack("<q",__samp)[0]
|
__samp = struct.unpack("<q",__samp)[0]
|
||||||
return __samp
|
return __samp
|
||||||
|
|
||||||
@ -81,7 +86,7 @@ class afedri(object):
|
|||||||
__gain = target_gain
|
__gain = target_gain
|
||||||
# special afedri calculation for the gain byte
|
# special afedri calculation for the gain byte
|
||||||
__gain = ((__gain+10)/3 << 3) + 1
|
__gain = ((__gain+10)/3 << 3) + 1
|
||||||
__set_gain_cmd = "\x06\x00\x38\x00\x00" + struct.pack("B",__gain)
|
__set_gain_cmd = b"\x06\x00\x38\x00\x00" + struct.pack("B",__gain)
|
||||||
self.s.send(__set_gain_cmd)
|
self.s.send(__set_gain_cmd)
|
||||||
__data = self.s.recv(6)
|
__data = self.s.recv(6)
|
||||||
__rf_gain = -10 + 3 * (struct.unpack("B",__data[5:6])[0]>>3)
|
__rf_gain = -10 + 3 * (struct.unpack("B",__data[5:6])[0]>>3)
|
||||||
@ -92,7 +97,7 @@ class afedri(object):
|
|||||||
__gain = (indx << 3) + 1
|
__gain = (indx << 3) + 1
|
||||||
# special afedri calculation for the gain byte
|
# special afedri calculation for the gain byte
|
||||||
#__gain = ((__gain+10)/3 << 3) + 1
|
#__gain = ((__gain+10)/3 << 3) + 1
|
||||||
__set_gain_cmd = "\x06\x00\x38\x00\x00" + struct.pack("B",__gain)
|
__set_gain_cmd = b"\x06\x00\x38\x00\x00" + struct.pack("B",__gain)
|
||||||
self.s.send(__set_gain_cmd)
|
self.s.send(__set_gain_cmd)
|
||||||
__data = self.s.recv(6)
|
__data = self.s.recv(6)
|
||||||
__rf_gain = -10 + 3 * (struct.unpack("B",__data[5:6])[0]>>3)
|
__rf_gain = -10 + 3 * (struct.unpack("B",__data[5:6])[0]>>3)
|
||||||
@ -103,7 +108,7 @@ class afedri(object):
|
|||||||
NOT IMPLEMENTED IN AFEDRI?. DON'T USE
|
NOT IMPLEMENTED IN AFEDRI?. DON'T USE
|
||||||
"""
|
"""
|
||||||
if not self.s: return 1
|
if not self.s: return 1
|
||||||
__get_gain_cmd = "\x05\x20\x38\x00\x00"
|
__get_gain_cmd = b"\x05\x20\x38\x00\x00"
|
||||||
self.s.send(__get_gain_cmd)
|
self.s.send(__get_gain_cmd)
|
||||||
__data = self.s.recv(6)
|
__data = self.s.recv(6)
|
||||||
__rf_gain = -10 + 3 * (struct.unpack("B",__data[5:])[0]>>3)
|
__rf_gain = -10 + 3 * (struct.unpack("B",__data[5:])[0]>>3)
|
||||||
@ -111,8 +116,8 @@ class afedri(object):
|
|||||||
|
|
||||||
def get_fe_clock(self):
|
def get_fe_clock(self):
|
||||||
if not self.s: return 1
|
if not self.s: return 1
|
||||||
__get_lword_cmd = "\x09\xE0\x02\x55\x00\x00\x00\x00\x00"
|
__get_lword_cmd = b"\x09\xE0\x02\x55\x00\x00\x00\x00\x00"
|
||||||
__get_hword_cmd = "\x09\xE0\x02\x55\x01\x00\x00\x00\x00"
|
__get_hword_cmd = b"\x09\xE0\x02\x55\x01\x00\x00\x00\x00"
|
||||||
self.s.send(__get_lword_cmd)
|
self.s.send(__get_lword_cmd)
|
||||||
__data_l = self.s.recv(9)
|
__data_l = self.s.recv(9)
|
||||||
self.s.send(__get_hword_cmd)
|
self.s.send(__get_hword_cmd)
|
||||||
@ -123,7 +128,7 @@ class afedri(object):
|
|||||||
def start_capture(self):
|
def start_capture(self):
|
||||||
#start 16-bit contiguous capture, complex numbers
|
#start 16-bit contiguous capture, complex numbers
|
||||||
if not self.s: return 1
|
if not self.s: return 1
|
||||||
__start_cmd="\x08\x00\x18\x00\x80\x02\x00\x00"
|
__start_cmd=b"\x08\x00\x18\x00\x80\x02\x00\x00"
|
||||||
self.s.send(__start_cmd)
|
self.s.send(__start_cmd)
|
||||||
__data = self.s.recv(8)
|
__data = self.s.recv(8)
|
||||||
return __data
|
return __data
|
||||||
@ -131,14 +136,15 @@ class afedri(object):
|
|||||||
def get_sdr_name(self):
|
def get_sdr_name(self):
|
||||||
#Request SDR's Name string command = array.array('B',[0x4, 0x20,1,0])
|
#Request SDR's Name string command = array.array('B',[0x4, 0x20,1,0])
|
||||||
if not self.s: return 1
|
if not self.s: return 1
|
||||||
__start_cmd="\x04\x20\x01\x00"
|
__start_cmd=b"\x04\x20\x01\x00"
|
||||||
self.s.send(__start_cmd)
|
self.s.send(__start_cmd)
|
||||||
__data = self.s.recv(16)
|
__data = self.s.recv(16)
|
||||||
|
__data = __data.decode('utf-8')
|
||||||
return __data
|
return __data
|
||||||
|
|
||||||
def stop_capture(self):
|
def stop_capture(self):
|
||||||
if not self.s: return 1
|
if not self.s: return 1
|
||||||
__stop_cmd="\x08\x00\x18\x00\x00\x01\x00\x00"
|
__stop_cmd=b"\x08\x00\x18\x00\x00\x01\x00\x00"
|
||||||
self.s.send(__stop_cmd)
|
self.s.send(__stop_cmd)
|
||||||
__data = self.s.recv(8)
|
__data = self.s.recv(8)
|
||||||
return __data
|
return __data
|
||||||
@ -150,8 +156,8 @@ class afedri(object):
|
|||||||
__DISCOVER_SERVER_PORT=48321 # PC client Tx port, SDR Server Rx Port
|
__DISCOVER_SERVER_PORT=48321 # PC client Tx port, SDR Server Rx Port
|
||||||
__DISCOVER_CLIENT_PORT=48322 # PC client Rx port, SDR Server Tx Port
|
__DISCOVER_CLIENT_PORT=48322 # PC client Rx port, SDR Server Tx Port
|
||||||
|
|
||||||
__data="\x38\x00\x5a\xa5" # magic discovery packet
|
__data=b"\x38\x00\x5a\xa5" # magic discovery packet
|
||||||
__data=__data.ljust(56,"\x00") # pad with zeroes
|
__data=__data.ljust(56,b"\x00") # pad with zeroes
|
||||||
|
|
||||||
self.s = socket(AF_INET, SOCK_DGRAM)
|
self.s = socket(AF_INET, SOCK_DGRAM)
|
||||||
self.s.bind(('', 0))
|
self.s.bind(('', 0))
|
||||||
@ -168,7 +174,9 @@ class afedri(object):
|
|||||||
try:
|
try:
|
||||||
__msg=self.sin.recv(256,0)
|
__msg=self.sin.recv(256,0)
|
||||||
__devname=__msg[5:20]
|
__devname=__msg[5:20]
|
||||||
|
__devname=__devname.decode('utf-8')
|
||||||
__sn=__msg[21:36]
|
__sn=__msg[21:36]
|
||||||
|
__sn=__sn.decode('utf-8')
|
||||||
__ip=inet_ntoa(__msg[40:36:-1])
|
__ip=inet_ntoa(__msg[40:36:-1])
|
||||||
__port=struct.unpack("<H",__msg[53:55])[0]
|
__port=struct.unpack("<H",__msg[53:55])[0]
|
||||||
self.s.close()
|
self.s.close()
|
||||||
|
@ -7,14 +7,12 @@ from __future__ import division
|
|||||||
import os,sys
|
import os,sys
|
||||||
os.environ['PATH'] = os.path.dirname(__file__) + ';' + os.environ['PATH']
|
os.environ['PATH'] = os.path.dirname(__file__) + ';' + os.environ['PATH']
|
||||||
|
|
||||||
#import array
|
import afedrinet
|
||||||
#import socket # Import socket module
|
import afedrinet.afedri
|
||||||
from afedri import *
|
|
||||||
#import afedri
|
|
||||||
|
|
||||||
class Control:
|
class Control:
|
||||||
def __init__(self, sdr_address="192.168.0.8", sdr_port=50000):
|
def __init__(self, sdr_address="192.168.0.8", sdr_port=50000):
|
||||||
self.hw = afedri(sdr_address, sdr_port)
|
self.hw = afedrinet.afedri.afedri(sdr_address, sdr_port)
|
||||||
if self.hw.s is None: # Failure to find the hardware
|
if self.hw.s is None: # Failure to find the hardware
|
||||||
self.hw = None
|
self.hw = None
|
||||||
def OpenHW(self):
|
def OpenHW(self):
|
||||||
|
@ -1106,7 +1106,9 @@ class BaseWindow(wx.ScrolledWindow):
|
|||||||
application.Hardware.SetLowPwrEnable(x)
|
application.Hardware.SetLowPwrEnable(x)
|
||||||
elif name == 'hermes_power_amp':
|
elif name == 'hermes_power_amp':
|
||||||
application.Hardware.EnablePowerAmp(x)
|
application.Hardware.EnablePowerAmp(x)
|
||||||
elif name == "hermes_bias_adjust":
|
elif name == 'hermes_TxLNA_dB':
|
||||||
|
application.Hardware.ChangeTxLNA(x)
|
||||||
|
elif name == "hermes_bias_adjust" and self.HermesBias0:
|
||||||
self.HermesBias0.Enable(x)
|
self.HermesBias0.Enable(x)
|
||||||
self.HermesBias1.Enable(x)
|
self.HermesBias1.Enable(x)
|
||||||
self.HermesWriteBiasButton.Enable(x)
|
self.HermesWriteBiasButton.Enable(x)
|
||||||
@ -1424,6 +1426,8 @@ class RadioHardware(RadioHardwareBase): # The Hardware page in the second-level
|
|||||||
def __init__(self, parent, radio_name):
|
def __init__(self, parent, radio_name):
|
||||||
RadioHardwareBase.__init__(self, parent, radio_name)
|
RadioHardwareBase.__init__(self, parent, radio_name)
|
||||||
self.AlwaysMakeControls()
|
self.AlwaysMakeControls()
|
||||||
|
self.HermesBias0 = None
|
||||||
|
self.HermesBias1 = None
|
||||||
radio_dict = local_conf.GetRadioDict(radio_name)
|
radio_dict = local_conf.GetRadioDict(radio_name)
|
||||||
radio_type = radio_dict['hardware_file_type']
|
radio_type = radio_dict['hardware_file_type']
|
||||||
data_names = local_conf.GetReceiverData(radio_type)
|
data_names = local_conf.GetReceiverData(radio_type)
|
||||||
@ -1435,7 +1439,7 @@ class RadioHardware(RadioHardwareBase): # The Hardware page in the second-level
|
|||||||
hermes_board_id = application.Hardware.hermes_board_id
|
hermes_board_id = application.Hardware.hermes_board_id
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
if hasattr(application.Hardware, "ProgramGateware"):
|
if radio_name == Settings[1] and hasattr(application.Hardware, "ProgramGateware"):
|
||||||
help_text = "Choose an RBF file and program the Gateware (FPGA software) over Ethernet."
|
help_text = "Choose an RBF file and program the Gateware (FPGA software) over Ethernet."
|
||||||
self.AddTextButtonHelp(1, "Gateware Update", "Program from RBF file..", application.Hardware.ProgramGateware, help_text)
|
self.AddTextButtonHelp(1, "Gateware Update", "Program from RBF file..", application.Hardware.ProgramGateware, help_text)
|
||||||
col = 1
|
col = 1
|
||||||
|
12
docs.html
12
docs.html
@ -257,8 +257,12 @@ sudo apt-get install portaudio19-dev
|
|||||||
<br>
|
<br>
|
||||||
sudo apt-get install libpulse-dev
|
sudo apt-get install libpulse-dev
|
||||||
<br>
|
<br>
|
||||||
|
sudo apt-get install python-dev
|
||||||
|
<br>
|
||||||
sudo apt-get install libpython2.7-dev
|
sudo apt-get install libpython2.7-dev
|
||||||
<br>
|
<br>
|
||||||
|
sudo apt-get install python3-dev
|
||||||
|
<br>
|
||||||
sudo apt-get install libpython3-dev
|
sudo apt-get install libpython3-dev
|
||||||
<br>
|
<br>
|
||||||
sudo apt-get install python-usb
|
sudo apt-get install python-usb
|
||||||
@ -838,14 +842,6 @@ just
|
|||||||
changing the sound card names.
|
changing the sound card names.
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<br>
|
|
||||||
For more information try these articles:<span style="text-decoration: underline;">
|
|
||||||
<br>
|
|
||||||
</span><a href="http://linuxplanet.com/linuxplanet/tutorials/6465/1/">http://linuxplanet.com/linuxplanet/tutorials/6465/1/</a>
|
|
||||||
<br>
|
|
||||||
<a href="http://linuxplanet.com/linuxplanet/tutorials/6466/1/">http://linuxplanet.com/linuxplanet/tutorials/6466/1/</a>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
<h3 id="g0.4.4">Windows Names</h3>
|
<h3 id="g0.4.4">Windows Names</h3>
|
||||||
To see what sound cards you have, use the Control Panel item Sound
|
To see what sound cards you have, use the Control Panel item Sound
|
||||||
|
10
dxcluster.py
10
dxcluster.py
@ -110,17 +110,17 @@ class DxCluster(threading.Thread):
|
|||||||
for i in range(10):
|
for i in range(10):
|
||||||
try:
|
try:
|
||||||
self.tn.open(conf.dxClHost, conf.dxClPort, 10)
|
self.tn.open(conf.dxClHost, conf.dxClPort, 10)
|
||||||
self.tn.read_until('login:', 10)
|
self.tn.read_until(b"login:", 10)
|
||||||
self.tn.write(str(conf.user_call_sign) + "\n") # user_call_sign may be Unicode
|
self.tn.write(conf.user_call_sign.encode('utf-8', errors='ignore') + b"\n") # user_call_sign may be Unicode
|
||||||
break
|
break
|
||||||
except:
|
except:
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
if conf.dxClPassword:
|
if conf.dxClPassword:
|
||||||
self.tn.read_until("Password: ")
|
self.tn.read_until(b"Password: ")
|
||||||
self.tn.write(str(conf.dxClPassword) + "\n")
|
self.tn.write(conf.dxClPassword.encode('utf-8', errors='ignore') + b"\n")
|
||||||
|
|
||||||
def telnetRead(self):
|
def telnetRead(self):
|
||||||
message = self.tn.read_until('\n', 60).decode(encoding='utf-8', errors='replace')
|
message = self.tn.read_until(b'\n', 60).decode(encoding='utf-8', errors='replace')
|
||||||
if self.doQuit.isSet() == False:
|
if self.doQuit.isSet() == False:
|
||||||
dxEntry = DxEntry();
|
dxEntry = DxEntry();
|
||||||
if dxEntry.parseMessage(message):
|
if dxEntry.parseMessage(message):
|
||||||
|
@ -71,6 +71,7 @@ class Hardware(BaseHardware):
|
|||||||
self.SetControlByte(0x10, 1, (value >> 2) & 0xFF) # cw_hang_time
|
self.SetControlByte(0x10, 1, (value >> 2) & 0xFF) # cw_hang_time
|
||||||
self.SetLowPwrEnable(conf.hermes_lowpwr_tr_enable)
|
self.SetLowPwrEnable(conf.hermes_lowpwr_tr_enable)
|
||||||
self.EnablePowerAmp(conf.hermes_power_amp)
|
self.EnablePowerAmp(conf.hermes_power_amp)
|
||||||
|
self.ChangeTxLNA(conf.hermes_TxLNA_dB)
|
||||||
self.MakePowerCalibration()
|
self.MakePowerCalibration()
|
||||||
def pre_open(self):
|
def pre_open(self):
|
||||||
# This socket is used for the Metis Discover protocol
|
# This socket is used for the Metis Discover protocol
|
||||||
@ -395,8 +396,10 @@ class Hardware(BaseHardware):
|
|||||||
btn = event.GetEventObject()
|
btn = event.GetEventObject()
|
||||||
if btn.GetValue():
|
if btn.GetValue():
|
||||||
QS.set_PTT(1)
|
QS.set_PTT(1)
|
||||||
|
QS.set_key_down(1)
|
||||||
else:
|
else:
|
||||||
QS.set_PTT(0)
|
QS.set_PTT(0)
|
||||||
|
QS.set_key_down(0)
|
||||||
def OnSpot(self, level):
|
def OnSpot(self, level):
|
||||||
# level is -1 for Spot button Off; else the Spot level 0 to 1000.
|
# level is -1 for Spot button Off; else the Spot level 0 to 1000.
|
||||||
pass
|
pass
|
||||||
@ -437,9 +440,9 @@ class Hardware(BaseHardware):
|
|||||||
QS.pc_to_hermes(self.pc2hermes)
|
QS.pc_to_hermes(self.pc2hermes)
|
||||||
if DEBUG: print ("Change AGC to", value)
|
if DEBUG: print ("Change AGC to", value)
|
||||||
## Simpler LNA setting for HL2 identifying as version >=40, see HL2 wiki for details
|
## Simpler LNA setting for HL2 identifying as version >=40, see HL2 wiki for details
|
||||||
def ChangeLNA(self, value):
|
def ChangeLNA(self, value): # LNA for Rx
|
||||||
# value is -12 to +48
|
# value is -12 to +48
|
||||||
if self.hermes_code_version < 40:
|
if self.hermes_code_version < 40: # Is this correct ??
|
||||||
if value < 20:
|
if value < 20:
|
||||||
self.pc2hermes[2] |= 0x08 # C0 index == 0, C3[3]: LNA +32 dB disable == 1
|
self.pc2hermes[2] |= 0x08 # C0 index == 0, C3[3]: LNA +32 dB disable == 1
|
||||||
value = 19 - value
|
value = 19 - value
|
||||||
@ -451,6 +454,12 @@ class Hardware(BaseHardware):
|
|||||||
self.pc2hermes[4 * 10 + 3] = value # C0 index == 0x1010, C4[4:0] LNA 0-32 dB gain
|
self.pc2hermes[4 * 10 + 3] = value # C0 index == 0x1010, C4[4:0] LNA 0-32 dB gain
|
||||||
QS.pc_to_hermes(self.pc2hermes)
|
QS.pc_to_hermes(self.pc2hermes)
|
||||||
if DEBUG: print ("Change LNA to", value)
|
if DEBUG: print ("Change LNA to", value)
|
||||||
|
def ChangeTxLNA(self, value): # LNA for Tx
|
||||||
|
# value is -12 to +48
|
||||||
|
value = ((value+12) & 0x3f) | 0x40 | 0x80
|
||||||
|
self.SetControlByte(0x0e, 3, value) # C0 index == 0x0e, C3
|
||||||
|
QS.pc_to_hermes(self.pc2hermes)
|
||||||
|
if DEBUG: print ("Change Tx LNA to", value)
|
||||||
def SetTxLevel(self):
|
def SetTxLevel(self):
|
||||||
try:
|
try:
|
||||||
tx_level = self.conf.tx_level[self.band]
|
tx_level = self.conf.tx_level[self.band]
|
||||||
|
40
quisk.c
40
quisk.c
@ -3365,17 +3365,15 @@ static int read_rx_udp10(complex double * samp) // Read samples from UDP using t
|
|||||||
unsigned int seq;
|
unsigned int seq;
|
||||||
unsigned int hlwp = 0;
|
unsigned int hlwp = 0;
|
||||||
static unsigned int seq0;
|
static unsigned int seq0;
|
||||||
static int key_state;
|
|
||||||
static int tx_records;
|
static int tx_records;
|
||||||
static int max_multirx_count=0;
|
static int max_multirx_count=0;
|
||||||
int i, j, nSamples, xr, xi, index, start, want_samples, dindex, state, num_records;
|
int i, j, nSamples, xr, xi, index, start, want_samples, dindex, num_records;
|
||||||
complex double c;
|
complex double c;
|
||||||
struct timeval tm_wait;
|
struct timeval tm_wait;
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
|
|
||||||
if ( ! quisk_hermes_is_ready(rx_udp_socket)) {
|
if ( ! quisk_hermes_is_ready(rx_udp_socket)) {
|
||||||
seq0 = 0;
|
seq0 = 0;
|
||||||
key_state = 0;
|
|
||||||
tx_records = 0;
|
tx_records = 0;
|
||||||
quisk_rx_udp_started = 0;
|
quisk_rx_udp_started = 0;
|
||||||
multirx_fft_next_index = 0;
|
multirx_fft_next_index = 0;
|
||||||
@ -3519,23 +3517,8 @@ static int read_rx_udp10(complex double * samp) // Read samples from UDP using t
|
|||||||
//code_version = quisk_hermes_to_pc[3];
|
//code_version = quisk_hermes_to_pc[3];
|
||||||
if ((quisk_hermes_to_pc[0] & 0x01) != 0) // C1
|
if ((quisk_hermes_to_pc[0] & 0x01) != 0) // C1
|
||||||
quisk_sound_state.overrange++;
|
quisk_sound_state.overrange++;
|
||||||
if (quisk_hermes_code_version >= 62) {
|
|
||||||
hardware_ptt = buf[start] & 0x01; // C0 bit zero is PTT
|
hardware_ptt = buf[start] & 0x01; // C0 bit zero is PTT
|
||||||
hardware_cwkey = (buf[start] & 0x02) >> 1; // C0 bit one is CW key state
|
hardware_cwkey = (buf[start] & 0x04) >> 2; // C0 bit two is CW key state
|
||||||
}
|
|
||||||
else {
|
|
||||||
hardware_cwkey = buf[start] & 0x01; // C0 bit zero is CW key state
|
|
||||||
}
|
|
||||||
if (rxMode == CWL || rxMode == CWU) {
|
|
||||||
state = hardware_cwkey | is_PTT_down;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
state = is_PTT_down;
|
|
||||||
}
|
|
||||||
if (state != key_state) {
|
|
||||||
key_state = state;
|
|
||||||
quisk_set_key_down(state);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if(dindex == 1) { // temperature and forward power
|
else if(dindex == 1) { // temperature and forward power
|
||||||
hermes_temperature += quisk_hermes_to_pc[4] << 8 | quisk_hermes_to_pc[5];
|
hermes_temperature += quisk_hermes_to_pc[4] << 8 | quisk_hermes_to_pc[5];
|
||||||
@ -4566,15 +4549,19 @@ static PyObject * get_multirx_graph(PyObject * self, PyObject * args) // Called
|
|||||||
return retrn;
|
return retrn;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject * get_bandscope(void) // Called by the GUI thread
|
static PyObject * get_bandscope(PyObject * self, PyObject * args) // Called by the GUI thread
|
||||||
{
|
{
|
||||||
int i, j, j1, j2, L;
|
int i, j, j1, j2, L, clock;
|
||||||
|
double zoom, deltaf, rate, f1;
|
||||||
static int fft_count = 0;
|
static int fft_count = 0;
|
||||||
static double the_max = 0;
|
static double the_max = 0;
|
||||||
static double time0=0; // time of last graph
|
static double time0=0; // time of last graph
|
||||||
double d1, d2, sample, frac, scale;
|
double d1, d2, sample, frac, scale;
|
||||||
PyObject * tuple2;
|
PyObject * tuple2;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple (args, "idd", &clock, &zoom, &deltaf))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (bandscopeState == 99 && bandscopePlan) { // bandscope samples are ready
|
if (bandscopeState == 99 && bandscopePlan) { // bandscope samples are ready
|
||||||
for (i = 0; i < bandscope_size; i++) {
|
for (i = 0; i < bandscope_size; i++) {
|
||||||
d1 = fabs(bandscopeSamples[i]);
|
d1 = fabs(bandscopeSamples[i]);
|
||||||
@ -4595,9 +4582,12 @@ static PyObject * get_bandscope(void) // Called by the GUI thread
|
|||||||
tuple2 = PyTuple_New(graph_width);
|
tuple2 = PyTuple_New(graph_width);
|
||||||
frac = (double)L / graph_width;
|
frac = (double)L / graph_width;
|
||||||
scale = 1.0 / frac / fft_count / bandscope_size;
|
scale = 1.0 / frac / fft_count / bandscope_size;
|
||||||
|
rate = clock / 2.0;
|
||||||
for (i = 0; i < graph_width; i++) { // for each pixel
|
for (i = 0; i < graph_width; i++) { // for each pixel
|
||||||
d1 = i * frac;
|
f1 = deltaf + rate / 2.0 * (1.0 - zoom); // frequency at left of graph
|
||||||
d2 = (i + 1) * frac;
|
// freq = f1 + pixel / graph_width + zoom * rate = rate * fft_index / L
|
||||||
|
d1 = L / rate * (f1 + (double)i / graph_width * zoom * rate);
|
||||||
|
d2 = L / rate * (f1 + (double)(i + 1) / graph_width * zoom * rate);
|
||||||
j1 = floor(d1);
|
j1 = floor(d1);
|
||||||
j2 = floor(d2);
|
j2 = floor(d2);
|
||||||
if (j1 == j2) {
|
if (j1 == j2) {
|
||||||
@ -4645,9 +4635,6 @@ static PyObject * get_graph(PyObject * self, PyObject * args) // Called by the G
|
|||||||
|
|
||||||
if (!PyArg_ParseTuple (args, "idd", &k, &zoom, &deltaf))
|
if (!PyArg_ParseTuple (args, "idd", &k, &zoom, &deltaf))
|
||||||
return NULL;
|
return NULL;
|
||||||
if (k == 2) {
|
|
||||||
return get_bandscope();
|
|
||||||
}
|
|
||||||
if (k != use_fft) { // change in data return type; re-initialize
|
if (k != use_fft) { // change in data return type; re-initialize
|
||||||
use_fft = k;
|
use_fft = k;
|
||||||
count_fft = 0;
|
count_fft = 0;
|
||||||
@ -5302,6 +5289,7 @@ static PyMethodDef QuiskMethods[] = {
|
|||||||
{"is_key_down", is_key_down, METH_VARARGS, "Check whether the key is down; return 0 or 1."},
|
{"is_key_down", is_key_down, METH_VARARGS, "Check whether the key is down; return 0 or 1."},
|
||||||
{"get_state", get_state, METH_VARARGS, "Return a count of read and write errors."},
|
{"get_state", get_state, METH_VARARGS, "Return a count of read and write errors."},
|
||||||
{"get_graph", get_graph, METH_VARARGS, "Return a tuple of graph data."},
|
{"get_graph", get_graph, METH_VARARGS, "Return a tuple of graph data."},
|
||||||
|
{"get_bandscope", get_bandscope, METH_VARARGS, "Return a tuple of bandscope data."},
|
||||||
{"set_multirx_mode", set_multirx_mode, METH_VARARGS, "Select demodulation mode for sub-receivers."},
|
{"set_multirx_mode", set_multirx_mode, METH_VARARGS, "Select demodulation mode for sub-receivers."},
|
||||||
{"set_multirx_freq", set_multirx_freq, METH_VARARGS, "Select how to play audio from sub-receivers."},
|
{"set_multirx_freq", set_multirx_freq, METH_VARARGS, "Select how to play audio from sub-receivers."},
|
||||||
{"set_multirx_play_method", set_multirx_play_method, METH_VARARGS, "Select how to play audio from sub-receivers."},
|
{"set_multirx_play_method", set_multirx_play_method, METH_VARARGS, "Select how to play audio from sub-receivers."},
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
Metadata-Version: 1.1
|
Metadata-Version: 1.1
|
||||||
Name: quisk
|
Name: quisk
|
||||||
Version: 4.1.52
|
Version: 4.1.53
|
||||||
Summary: QUISK is a Software Defined Radio (SDR) transceiver that can control various radio hardware.
|
Summary: QUISK is a Software Defined Radio (SDR) transceiver that can control various radio hardware.
|
||||||
Home-page: http://james.ahlstrom.name/quisk/
|
Home-page: http://james.ahlstrom.name/quisk/
|
||||||
Author: James C. Ahlstrom
|
Author: James C. Ahlstrom
|
||||||
|
@ -41,6 +41,7 @@ quisk.py
|
|||||||
quisk_conf_defaults.py
|
quisk_conf_defaults.py
|
||||||
quisk_conf_kx3.py
|
quisk_conf_kx3.py
|
||||||
quisk_conf_model.py
|
quisk_conf_model.py
|
||||||
|
quisk_conf_openradio.py
|
||||||
quisk_conf_peaberry.py
|
quisk_conf_peaberry.py
|
||||||
quisk_conf_sdr8600.py
|
quisk_conf_sdr8600.py
|
||||||
quisk_conf_sdriq.py
|
quisk_conf_sdriq.py
|
||||||
@ -50,10 +51,12 @@ quisk_hardware_hamlib.py
|
|||||||
quisk_hardware_model.py
|
quisk_hardware_model.py
|
||||||
quisk_hardware_sdr8600.py
|
quisk_hardware_sdr8600.py
|
||||||
quisk_hardware_sdriq.py
|
quisk_hardware_sdriq.py
|
||||||
|
quisk_hardware_sdrmicron.py
|
||||||
quisk_utils.py
|
quisk_utils.py
|
||||||
quisk_vna.py
|
quisk_vna.py
|
||||||
quisk_widgets.py
|
quisk_widgets.py
|
||||||
setup.py
|
setup.py
|
||||||
|
softrock_tune_vfo.py
|
||||||
sound.c
|
sound.c
|
||||||
sound_alsa.c
|
sound_alsa.c
|
||||||
sound_directx.c
|
sound_directx.c
|
||||||
@ -86,6 +89,7 @@ winsound.txt
|
|||||||
./quisk_conf_defaults.py
|
./quisk_conf_defaults.py
|
||||||
./quisk_conf_kx3.py
|
./quisk_conf_kx3.py
|
||||||
./quisk_conf_model.py
|
./quisk_conf_model.py
|
||||||
|
./quisk_conf_openradio.py
|
||||||
./quisk_conf_peaberry.py
|
./quisk_conf_peaberry.py
|
||||||
./quisk_conf_sdr8600.py
|
./quisk_conf_sdr8600.py
|
||||||
./quisk_conf_sdriq.py
|
./quisk_conf_sdriq.py
|
||||||
@ -95,9 +99,11 @@ winsound.txt
|
|||||||
./quisk_hardware_model.py
|
./quisk_hardware_model.py
|
||||||
./quisk_hardware_sdr8600.py
|
./quisk_hardware_sdr8600.py
|
||||||
./quisk_hardware_sdriq.py
|
./quisk_hardware_sdriq.py
|
||||||
|
./quisk_hardware_sdrmicron.py
|
||||||
./quisk_utils.py
|
./quisk_utils.py
|
||||||
./quisk_vna.py
|
./quisk_vna.py
|
||||||
./quisk_widgets.py
|
./quisk_widgets.py
|
||||||
|
./softrock_tune_vfo.py
|
||||||
./windows.txt
|
./windows.txt
|
||||||
./winsound.txt
|
./winsound.txt
|
||||||
./afedrinet/SOURCE.txt
|
./afedrinet/SOURCE.txt
|
||||||
@ -162,12 +168,11 @@ winsound.txt
|
|||||||
./softrock/widgets_tx.py
|
./softrock/widgets_tx.py
|
||||||
afedrinet/SOURCE.txt
|
afedrinet/SOURCE.txt
|
||||||
afedrinet/__init__.py
|
afedrinet/__init__.py
|
||||||
afedrinet/af_comp.bat
|
afedrinet/af_comp.bat.makeit
|
||||||
afedrinet/afe_library
|
afedrinet/afe_library
|
||||||
afedrinet/afe_library.mac
|
afedrinet/afe_library.mac
|
||||||
afedrinet/afedri.py
|
afedrinet/afedri.py
|
||||||
afedrinet/afedrinet_io.c
|
afedrinet/afedrinet_io.c
|
||||||
afedrinet/afedrinet_io.pyd
|
|
||||||
afedrinet/quisk_conf.py
|
afedrinet/quisk_conf.py
|
||||||
afedrinet/quisk_conf_linux.py
|
afedrinet/quisk_conf_linux.py
|
||||||
afedrinet/quisk_conf_mac.py
|
afedrinet/quisk_conf_mac.py
|
||||||
|
74
quisk.py
74
quisk.py
@ -857,6 +857,7 @@ class ConfigScreen(wx.Panel):
|
|||||||
def __init__(self, parent, width, fft_size):
|
def __init__(self, parent, width, fft_size):
|
||||||
self.y_scale = 0
|
self.y_scale = 0
|
||||||
self.y_zero = 0
|
self.y_zero = 0
|
||||||
|
self.zoom_control = 0
|
||||||
self.finish_pages = True
|
self.finish_pages = True
|
||||||
self.width = width
|
self.width = width
|
||||||
wx.Panel.__init__(self, parent)
|
wx.Panel.__init__(self, parent)
|
||||||
@ -920,6 +921,7 @@ class ConfigStatus(wx.ScrolledWindow):
|
|||||||
self.latencyPlay = -1
|
self.latencyPlay = -1
|
||||||
self.y_scale = 0
|
self.y_scale = 0
|
||||||
self.y_zero = 0
|
self.y_zero = 0
|
||||||
|
self.zoom_control = 0
|
||||||
self.rate_min = -1
|
self.rate_min = -1
|
||||||
self.rate_max = -1
|
self.rate_max = -1
|
||||||
self.chan_min = -1
|
self.chan_min = -1
|
||||||
@ -1779,6 +1781,7 @@ class GraphScreen(wx.Window):
|
|||||||
else:
|
else:
|
||||||
self.y_scale = conf.graph_y_scale
|
self.y_scale = conf.graph_y_scale
|
||||||
self.y_zero = conf.graph_y_zero
|
self.y_zero = conf.graph_y_zero
|
||||||
|
self.zoom_control = 0
|
||||||
self.y_ticks = []
|
self.y_ticks = []
|
||||||
self.VFO = 0
|
self.VFO = 0
|
||||||
self.filter_mode = 'AM'
|
self.filter_mode = 'AM'
|
||||||
@ -1879,9 +1882,10 @@ class GraphScreen(wx.Window):
|
|||||||
def ChangeYzero(self, y_zero):
|
def ChangeYzero(self, y_zero):
|
||||||
self.y_zero = y_zero
|
self.y_zero = y_zero
|
||||||
self.doResize = True
|
self.doResize = True
|
||||||
def ChangeZoom(self, zoom, deltaf):
|
def ChangeZoom(self, zoom, deltaf, zoom_control):
|
||||||
self.zoom = zoom
|
self.zoom = zoom
|
||||||
self.zoom_deltaf = deltaf
|
self.zoom_deltaf = deltaf
|
||||||
|
self.zoom_control = zoom_control
|
||||||
self.doResize = True
|
self.doResize = True
|
||||||
def MakeYScale(self):
|
def MakeYScale(self):
|
||||||
chary = self.chary
|
chary = self.chary
|
||||||
@ -2491,14 +2495,19 @@ class WaterfallDisplay(wx.Window):
|
|||||||
#T('graph start')
|
#T('graph start')
|
||||||
row = bytearray(0) # Make a new row of pixels for a one-line image
|
row = bytearray(0) # Make a new row of pixels for a one-line image
|
||||||
gain = self.rf_gain
|
gain = self.rf_gain
|
||||||
|
# y_scale and y_zero range from zero to 160.
|
||||||
|
# y_zero controls the center position of the colors. Set to a bit over the noise level.
|
||||||
|
# y_scale controls how much the colors change when the sample deviates from y_zero.
|
||||||
for x in data: # x is -130 to 0, or so (dB)
|
for x in data: # x is -130 to 0, or so (dB)
|
||||||
l = int((x - gain + y_zero // 3 + 100) * y_scale / 10)
|
yz = 40.0 + y_zero * 0.69 # -yz is the color center in dB
|
||||||
|
l = int((x - gain + yz) * (y_scale + 10) * 0.10 + 128)
|
||||||
l = max(l, 0)
|
l = max(l, 0)
|
||||||
l = min(l, 255)
|
l = min(l, 255)
|
||||||
row.append(self.red[l])
|
row.append(self.red[l])
|
||||||
row.append(self.green[l])
|
row.append(self.green[l])
|
||||||
row.append(self.blue[l])
|
row.append(self.blue[l])
|
||||||
row.append(255)
|
row.append(255)
|
||||||
|
#print ('OnGraphData yz %.0f, slope %.3f, l %4d' % (yz, (y_scale + 10) * 0.10, l))
|
||||||
#T('graph string')
|
#T('graph string')
|
||||||
if wxVersion in ('2', '3'):
|
if wxVersion in ('2', '3'):
|
||||||
bmp = wx.BitmapFromBufferRGBA(len(row) // 4, 1, row)
|
bmp = wx.BitmapFromBufferRGBA(len(row) // 4, 1, row)
|
||||||
@ -2523,15 +2532,17 @@ class WaterfallDisplay(wx.Window):
|
|||||||
dc.DrawLine(tune_tx, self.margin, tune_tx, self.height)
|
dc.DrawLine(tune_tx, self.margin, tune_tx, self.height)
|
||||||
self.tune_tx = tune_tx
|
self.tune_tx = tune_tx
|
||||||
self.tune_rx = tune_rx
|
self.tune_rx = tune_rx
|
||||||
def ChangeZoom(self, zoom, deltaf):
|
def ChangeZoom(self, zoom, deltaf, zoom_control):
|
||||||
self.zoom = zoom
|
self.zoom = zoom
|
||||||
self.zoom_deltaf = deltaf
|
self.zoom_deltaf = deltaf
|
||||||
|
self.zoom_control = zoom_control
|
||||||
|
|
||||||
class WaterfallScreen(wx.SplitterWindow):
|
class WaterfallScreen(wx.SplitterWindow):
|
||||||
"""Create a splitter window with a graph screen and a waterfall screen"""
|
"""Create a splitter window with a graph screen and a waterfall screen"""
|
||||||
def __init__(self, frame, width, data_width, graph_width):
|
def __init__(self, frame, width, data_width, graph_width):
|
||||||
self.y_scale = conf.waterfall_y_scale
|
self.y_scale = conf.waterfall_y_scale
|
||||||
self.y_zero = conf.waterfall_y_zero
|
self.y_zero = conf.waterfall_y_zero
|
||||||
|
self.zoom_control = 0
|
||||||
wx.SplitterWindow.__init__(self, frame)
|
wx.SplitterWindow.__init__(self, frame)
|
||||||
self.SetSizeHints(width, -1, width)
|
self.SetSizeHints(width, -1, width)
|
||||||
self.SetSashGravity(0.50)
|
self.SetSashGravity(0.50)
|
||||||
@ -2576,6 +2587,11 @@ class WaterfallScreen(wx.SplitterWindow):
|
|||||||
self.pane2.OnGraphData(data)
|
self.pane2.OnGraphData(data)
|
||||||
def ChangeRfGain(self, gain): # Set the correction for RF gain
|
def ChangeRfGain(self, gain): # Set the correction for RF gain
|
||||||
self.pane2.display.rf_gain = gain
|
self.pane2.display.rf_gain = gain
|
||||||
|
def ChangeZoom(self, zoom, deltaf, zoom_control):
|
||||||
|
self.zoom_control = zoom_control
|
||||||
|
self.pane1.ChangeZoom(zoom, deltaf, zoom_control)
|
||||||
|
self.pane2.ChangeZoom(zoom, deltaf, zoom_control)
|
||||||
|
self.pane2.display.ChangeZoom(zoom, deltaf, zoom_control)
|
||||||
|
|
||||||
class WaterfallPane(GraphScreen):
|
class WaterfallPane(GraphScreen):
|
||||||
"""Create a waterfall screen with an X axis and a waterfall display."""
|
"""Create a waterfall screen with an X axis and a waterfall display."""
|
||||||
@ -2583,6 +2599,7 @@ class WaterfallPane(GraphScreen):
|
|||||||
GraphScreen.__init__(self, frame, data_width, graph_width)
|
GraphScreen.__init__(self, frame, data_width, graph_width)
|
||||||
self.y_scale = conf.waterfall_y_scale
|
self.y_scale = conf.waterfall_y_scale
|
||||||
self.y_zero = conf.waterfall_y_zero
|
self.y_zero = conf.waterfall_y_zero
|
||||||
|
self.zoom_control = 0
|
||||||
self.oldVFO = self.VFO
|
self.oldVFO = self.VFO
|
||||||
self.filter_mode = 'AM'
|
self.filter_mode = 'AM'
|
||||||
self.filter_bandwidth = 0
|
self.filter_bandwidth = 0
|
||||||
@ -3004,6 +3021,7 @@ class ScopeScreen(wx.Window):
|
|||||||
self.horizPen = wx.Pen(conf.color_gl, 1, wx.SOLID)
|
self.horizPen = wx.Pen(conf.color_gl, 1, wx.SOLID)
|
||||||
self.y_scale = conf.scope_y_scale
|
self.y_scale = conf.scope_y_scale
|
||||||
self.y_zero = conf.scope_y_zero
|
self.y_zero = conf.scope_y_zero
|
||||||
|
self.zoom_control = 0
|
||||||
self.yscale = 1
|
self.yscale = 1
|
||||||
self.running = 1
|
self.running = 1
|
||||||
self.doResize = False
|
self.doResize = False
|
||||||
@ -3136,8 +3154,11 @@ class ScopeScreen(wx.Window):
|
|||||||
|
|
||||||
class BandscopeScreen(WaterfallScreen):
|
class BandscopeScreen(WaterfallScreen):
|
||||||
def __init__(self, frame, width, data_width, graph_width, clock):
|
def __init__(self, frame, width, data_width, graph_width, clock):
|
||||||
|
self.zoom = 1.0
|
||||||
|
self.zoom_deltaf = 0
|
||||||
|
self.zoom_control = 0
|
||||||
WaterfallScreen.__init__(self, frame, width, data_width, graph_width)
|
WaterfallScreen.__init__(self, frame, width, data_width, graph_width)
|
||||||
self.pane1.sample_rate = self.pane2.sample_rate = int(clock) // 2
|
self.sample_rate = self.pane1.sample_rate = self.pane2.sample_rate = int(clock) // 2
|
||||||
self.VFO = clock // 4
|
self.VFO = clock // 4
|
||||||
self.SetVFO(self.VFO)
|
self.SetVFO(self.VFO)
|
||||||
def SetTxFreq(self, tx_freq, rx_freq):
|
def SetTxFreq(self, tx_freq, rx_freq):
|
||||||
@ -3146,6 +3167,26 @@ class BandscopeScreen(WaterfallScreen):
|
|||||||
def SetFrequency(self, freq): # freq is 7000000, not the offset from VFO
|
def SetFrequency(self, freq): # freq is 7000000, not the offset from VFO
|
||||||
freq = freq - self.VFO
|
freq = freq - self.VFO
|
||||||
WaterfallScreen.SetTxFreq(self, freq, freq)
|
WaterfallScreen.SetTxFreq(self, freq, freq)
|
||||||
|
def ChangeZoom(self, zoom_control): # zoom_control is the slider value 0 to 1000
|
||||||
|
self.zoom_control = zoom_control
|
||||||
|
if zoom_control < 50:
|
||||||
|
zoom = 1.0
|
||||||
|
zoom_deltaf = 0
|
||||||
|
else:
|
||||||
|
zoom = 1.0 - zoom_control / 1000.0 * 0.95
|
||||||
|
freq = application.rxFreq + application.VFO
|
||||||
|
srate = int(self.sample_rate * zoom) # reduced (zoomed) sample rate
|
||||||
|
if freq - srate // 2 < 0:
|
||||||
|
zoom_deltaf = srate // 2 - self.VFO
|
||||||
|
elif freq + srate // 2 > self.sample_rate:
|
||||||
|
zoom_deltaf = self.VFO - srate // 2
|
||||||
|
else:
|
||||||
|
zoom_deltaf = freq - self.VFO
|
||||||
|
self.zoom = zoom
|
||||||
|
self.zoom_deltaf = zoom_deltaf
|
||||||
|
self.pane1.ChangeZoom(zoom, zoom_deltaf, zoom_control)
|
||||||
|
self.pane2.ChangeZoom(zoom, zoom_deltaf, zoom_control)
|
||||||
|
self.pane2.display.ChangeZoom(zoom, zoom_deltaf, zoom_control)
|
||||||
|
|
||||||
class FilterScreen(GraphScreen):
|
class FilterScreen(GraphScreen):
|
||||||
"""Create a graph of the receive filter response."""
|
"""Create a graph of the receive filter response."""
|
||||||
@ -3153,6 +3194,7 @@ class FilterScreen(GraphScreen):
|
|||||||
GraphScreen.__init__(self, parent, data_width, graph_width)
|
GraphScreen.__init__(self, parent, data_width, graph_width)
|
||||||
self.y_scale = conf.filter_y_scale
|
self.y_scale = conf.filter_y_scale
|
||||||
self.y_zero = conf.filter_y_zero
|
self.y_zero = conf.filter_y_zero
|
||||||
|
self.zoom_control = 0
|
||||||
self.VFO = 0
|
self.VFO = 0
|
||||||
self.txFreq = 0
|
self.txFreq = 0
|
||||||
self.data = []
|
self.data = []
|
||||||
@ -3199,6 +3241,7 @@ class AudioFFTScreen(GraphScreen):
|
|||||||
GraphScreen.__init__(self, parent, data_width, graph_width)
|
GraphScreen.__init__(self, parent, data_width, graph_width)
|
||||||
self.y_scale = conf.filter_y_scale
|
self.y_scale = conf.filter_y_scale
|
||||||
self.y_zero = conf.filter_y_zero
|
self.y_zero = conf.filter_y_zero
|
||||||
|
self.zoom_control = 0
|
||||||
self.VFO = 0
|
self.VFO = 0
|
||||||
self.txFreq = 0
|
self.txFreq = 0
|
||||||
self.sample_rate = sample_rate
|
self.sample_rate = sample_rate
|
||||||
@ -3216,6 +3259,7 @@ class HelpScreen(wx.html.HtmlWindow):
|
|||||||
wx.html.HtmlWindow.__init__(self, parent, -1, size=(width, height))
|
wx.html.HtmlWindow.__init__(self, parent, -1, size=(width, height))
|
||||||
self.y_scale = 0
|
self.y_scale = 0
|
||||||
self.y_zero = 0
|
self.y_zero = 0
|
||||||
|
self.zoom_control = 0
|
||||||
if "gtk2" in wx.PlatformInfo:
|
if "gtk2" in wx.PlatformInfo:
|
||||||
self.SetStandardFonts()
|
self.SetStandardFonts()
|
||||||
self.SetFonts("", "", [10, 12, 14, 16, 18, 20, 22])
|
self.SetFonts("", "", [10, 12, 14, 16, 18, 20, 22])
|
||||||
@ -4907,6 +4951,7 @@ The new code supports multiple corrections per band.""")
|
|||||||
self.vertBox.Layout() # This destroys the initialized sash position!
|
self.vertBox.Layout() # This destroys the initialized sash position!
|
||||||
self.sliderYs.SetValue(self.screen.y_scale)
|
self.sliderYs.SetValue(self.screen.y_scale)
|
||||||
self.sliderYz.SetValue(self.screen.y_zero)
|
self.sliderYz.SetValue(self.screen.y_zero)
|
||||||
|
self.sliderZo.SetValue(self.screen.zoom_control)
|
||||||
if name == 'WFall':
|
if name == 'WFall':
|
||||||
self.screen.SetSashPosition(sash)
|
self.screen.SetSashPosition(sash)
|
||||||
def OnBtnFileRecord(self, event):
|
def OnBtnFileRecord(self, event):
|
||||||
@ -4929,14 +4974,21 @@ The new code supports multiple corrections per band.""")
|
|||||||
elif self.multi_rx_screen.rx_zero == self.graph:
|
elif self.multi_rx_screen.rx_zero == self.graph:
|
||||||
self.graphScaleZ[self.lastBand] = (self.graph.y_scale, self.graph.y_zero)
|
self.graphScaleZ[self.lastBand] = (self.graph.y_scale, self.graph.y_zero)
|
||||||
def OnChangeZoom(self, event):
|
def OnChangeZoom(self, event):
|
||||||
x = self.sliderZo.GetValue()
|
zoom_control = self.sliderZo.GetValue()
|
||||||
if x < 50:
|
if self.screen == self.bandscope_screen:
|
||||||
|
self.bandscope_screen.ChangeZoom(zoom_control)
|
||||||
|
self.bandscope_screen.SetTxFreq(self.txFreq, self.rxFreq)
|
||||||
|
return
|
||||||
|
# The display runs from f1 to f2. The original sample rate is "rate".
|
||||||
|
# The new effective sample rate is rate * zoom.
|
||||||
|
# f1 = deltaf + rate * (1 - zoom) / 2
|
||||||
|
if zoom_control < 50:
|
||||||
self.zoom = 1.0 # change back to not-zoomed mode
|
self.zoom = 1.0 # change back to not-zoomed mode
|
||||||
self.zoom_deltaf = 0
|
self.zoom_deltaf = 0
|
||||||
self.zooming = False
|
self.zooming = False
|
||||||
else:
|
else:
|
||||||
a = 1000.0 * self.sample_rate / (self.sample_rate - 2500.0)
|
a = 1000.0 * self.sample_rate / (self.sample_rate - 2500.0)
|
||||||
self.zoom = 1.0 - x / a
|
self.zoom = 1.0 - zoom_control / a
|
||||||
if not self.zooming: # set deltaf when zoom mode starts
|
if not self.zooming: # set deltaf when zoom mode starts
|
||||||
center = self.multi_rx_screen.graph.filter_center
|
center = self.multi_rx_screen.graph.filter_center
|
||||||
freq = self.rxFreq + center
|
freq = self.rxFreq + center
|
||||||
@ -4944,10 +4996,8 @@ The new code supports multiple corrections per band.""")
|
|||||||
self.zooming = True
|
self.zooming = True
|
||||||
zoom = self.zoom
|
zoom = self.zoom
|
||||||
deltaf = self.zoom_deltaf
|
deltaf = self.zoom_deltaf
|
||||||
self.graph.ChangeZoom(zoom, deltaf)
|
self.graph.ChangeZoom(zoom, deltaf, zoom_control)
|
||||||
self.waterfall.pane1.ChangeZoom(zoom, deltaf)
|
self.waterfall.ChangeZoom(zoom, deltaf, zoom_control)
|
||||||
self.waterfall.pane2.ChangeZoom(zoom, deltaf)
|
|
||||||
self.waterfall.pane2.display.ChangeZoom(zoom, deltaf)
|
|
||||||
self.screen.SetTxFreq(self.txFreq, self.rxFreq)
|
self.screen.SetTxFreq(self.txFreq, self.rxFreq)
|
||||||
self.station_screen.Refresh()
|
self.station_screen.Refresh()
|
||||||
def OnLevelVOX(self, event):
|
def OnLevelVOX(self, event):
|
||||||
@ -5851,7 +5901,7 @@ The new code supports multiple corrections per band.""")
|
|||||||
self.SetPTT(False)
|
self.SetPTT(False)
|
||||||
self.timer = time.time()
|
self.timer = time.time()
|
||||||
if self.bandscope_clock: # Hermes UDP protocol
|
if self.bandscope_clock: # Hermes UDP protocol
|
||||||
data = QS.get_graph(2, 1.0, 0)
|
data = QS.get_bandscope(self.bandscope_clock, self.bandscope_screen.zoom, float(self.bandscope_screen.zoom_deltaf))
|
||||||
if data and self.screen == self.bandscope_screen:
|
if data and self.screen == self.bandscope_screen:
|
||||||
self.screen.OnGraphData(data)
|
self.screen.OnGraphData(data)
|
||||||
if self.screen == self.scope:
|
if self.screen == self.scope:
|
||||||
|
@ -429,6 +429,11 @@ Hware_Hl2_EepromMAC = '0xA1 0x6B'
|
|||||||
Hware_Hl2_EepromMACUse = 'Ignore'
|
Hware_Hl2_EepromMACUse = 'Ignore'
|
||||||
#Hware_Hl2_EepromMACUse = 'Set address'
|
#Hware_Hl2_EepromMACUse = 'Set address'
|
||||||
|
|
||||||
|
## hermes_TxLNA_dB LNA during Tx dB, integer
|
||||||
|
# During transmit the low noise Rx amplifier gain changes to this value (in dB) if the hardware supports it.
|
||||||
|
# Changes are immediate (no need to restart).
|
||||||
|
hermes_TxLNA_dB = 21
|
||||||
|
|
||||||
# These are known power meter calibration tables. This table is not present in the JSON settings file.
|
# These are known power meter calibration tables. This table is not present in the JSON settings file.
|
||||||
power_meter_std_calibrations = {}
|
power_meter_std_calibrations = {}
|
||||||
power_meter_std_calibrations['HL2FilterE3'] = [[ 0, 0.0 ], [ 25.865384615384617, 0.0025502539351328003 ], [ 101.02453987730061, 0.012752044999999998 ],
|
power_meter_std_calibrations['HL2FilterE3'] = [[ 0, 0.0 ], [ 25.865384615384617, 0.0025502539351328003 ], [ 101.02453987730061, 0.012752044999999998 ],
|
||||||
|
122
quisk_conf_openradio.py
Executable file
122
quisk_conf_openradio.py
Executable file
@ -0,0 +1,122 @@
|
|||||||
|
# OpenRadio v1.1 Quisk Configuration File
|
||||||
|
#
|
||||||
|
# IMPORTANT: To be able to control the OpenRadio board from within Quisk,
|
||||||
|
# you will need to compile and upload the 'openradio_quisk' firmware, which
|
||||||
|
# is available from: https://github.com/darksidelemm/open_radio_miniconf_2015
|
||||||
|
#
|
||||||
|
# You will also need to install the pyserial package for python.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
|
||||||
|
|
||||||
|
# SOUND CARD SETTINGS
|
||||||
|
#
|
||||||
|
# Uncomment these if you wish to use PortAudio directly
|
||||||
|
#name_of_sound_capt = "portaudio:(hw:2,0)"
|
||||||
|
#name_of_sound_play = "portaudio:(hw:1,0)"
|
||||||
|
|
||||||
|
# Uncomment these lines if you wish to use Pulseaudio
|
||||||
|
name_of_sound_capt = "pulse"
|
||||||
|
name_of_sound_play = "pulse"
|
||||||
|
|
||||||
|
# SERIAL PORT SETTINGS
|
||||||
|
# Set this as appropriate for your OS.
|
||||||
|
openradio_serial_port = "/dev/ttyUSB0"
|
||||||
|
openradio_serial_rate = 57600
|
||||||
|
|
||||||
|
|
||||||
|
# OpenRadio Frequency limits.
|
||||||
|
# These are just within the limits set in the openradio_quisk firmware.
|
||||||
|
openradio_lower = 100001
|
||||||
|
openradio_upper = 29999999
|
||||||
|
|
||||||
|
# OpenRadio Hardware Control Class
|
||||||
|
#
|
||||||
|
import serial,time
|
||||||
|
from quisk_hardware_model import Hardware as BaseHardware
|
||||||
|
|
||||||
|
class Hardware(BaseHardware):
|
||||||
|
def open(self):
|
||||||
|
# Called once to open the Hardware
|
||||||
|
# Open the serial port.
|
||||||
|
self.or_serial = serial.Serial(openradio_serial_port,openradio_serial_rate,timeout=3)
|
||||||
|
print("Opened Serial Port.")
|
||||||
|
# Wait for the Arduino Nano to restart and boot.
|
||||||
|
time.sleep(2)
|
||||||
|
# Poll for version. Should probably confirm the response on this.
|
||||||
|
version = str(self.get_parameter("VER"))
|
||||||
|
print(version)
|
||||||
|
# Return an informative message for the config screen
|
||||||
|
t = version + ". Capture from sound card %s." % self.conf.name_of_sound_capt
|
||||||
|
return t
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
# Called once to close the Hardware
|
||||||
|
self.or_serial.close()
|
||||||
|
|
||||||
|
def ChangeFrequency(self, tune, vfo, source='', band='', event=None):
|
||||||
|
# Called whenever quisk requests a frequency change.
|
||||||
|
# This sends the FREQ command to set the centre frequency of the OpenRadio,
|
||||||
|
# and will also move the 'tune' frequency (the section within the RX passband
|
||||||
|
# which is to be demodulated) if it falls outside the passband (+/- sample_rate/2).
|
||||||
|
print("Setting VFO to %d." % vfo)
|
||||||
|
if(vfo<openradio_lower):
|
||||||
|
vfo = openradio_lower
|
||||||
|
print("Outside range! Setting to %d" % openradio_lower)
|
||||||
|
|
||||||
|
if(vfo>openradio_upper):
|
||||||
|
vfo = openradio_upper
|
||||||
|
print("Outside range! Setting to %d" % openradio_upper)
|
||||||
|
|
||||||
|
success = self.set_parameter("FREQ",str(vfo))
|
||||||
|
|
||||||
|
# If the tune frequency is outside the RX bandwidth, set it to somewhere within that bandwidth.
|
||||||
|
if(tune>(vfo + sample_rate/2) or tune<(vfo - sample_rate/2)):
|
||||||
|
tune = vfo + 10000
|
||||||
|
print("Bringing tune frequency back into the RX bandwidth.")
|
||||||
|
|
||||||
|
if success:
|
||||||
|
print("Frequency change succeeded!")
|
||||||
|
else:
|
||||||
|
print("Frequency change failed.")
|
||||||
|
|
||||||
|
return tune, vfo
|
||||||
|
|
||||||
|
#
|
||||||
|
# Serial comms functions, to communicate with the OpenRadio board
|
||||||
|
#
|
||||||
|
|
||||||
|
def get_parameter(self,string):
|
||||||
|
self.or_serial.write(string+"\n")
|
||||||
|
return self.get_argument()
|
||||||
|
|
||||||
|
def set_parameter(self,string,arg):
|
||||||
|
self.or_serial.write(string+","+arg+"\n")
|
||||||
|
if self.get_argument() == arg:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_argument(self):
|
||||||
|
data1 = self.or_serial.readline()
|
||||||
|
# Do a couple of quick checks to see if there is useful data here
|
||||||
|
if len(data1) == 0:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
# Maybe we didn't catch an OK line?
|
||||||
|
if data1.startswith('OK'):
|
||||||
|
data1 = self.or_serial.readline()
|
||||||
|
|
||||||
|
# Check to see if we have a comma in the string. If not, there is no argument.
|
||||||
|
if data1.find(',') == -1:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
data1 = data1.split(',')[1].rstrip('\r\n')
|
||||||
|
|
||||||
|
# Check for the OK string
|
||||||
|
data2 = self.or_serial.readline()
|
||||||
|
if data2.startswith('OK'):
|
||||||
|
return data1
|
259
quisk_hardware_sdrmicron.py
Executable file
259
quisk_hardware_sdrmicron.py
Executable file
@ -0,0 +1,259 @@
|
|||||||
|
# -*- coding: cp1251 -*-
|
||||||
|
#
|
||||||
|
# It provides support for the SDR Micron
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
|
||||||
|
import sys, wx, traceback
|
||||||
|
|
||||||
|
import ftd2xx as d2xx
|
||||||
|
import time
|
||||||
|
|
||||||
|
from quisk_hardware_model import Hardware as BaseHardware
|
||||||
|
|
||||||
|
DEBUG = 0
|
||||||
|
|
||||||
|
# https://github.com/Dfinitski/SDR-Micron
|
||||||
|
#
|
||||||
|
# RX control, to device, 32 bytes total
|
||||||
|
# Preamble + 'RX0' + enable + rate + 4 bytes frequency + attenuation + 14 binary zeroes
|
||||||
|
#
|
||||||
|
# where:
|
||||||
|
# Preamble is 7*0x55, 0xd5
|
||||||
|
# bytes:
|
||||||
|
# enable - binary 0 or 1, for enable receiver
|
||||||
|
# rate:
|
||||||
|
# binary
|
||||||
|
# 0 for 48 kHz
|
||||||
|
# 1 for 96 kHz
|
||||||
|
# 2 for 192 kHz
|
||||||
|
# 3 for 240 kHz
|
||||||
|
# 4 for 384 kHz
|
||||||
|
# 5 for 480 kHz
|
||||||
|
# 6 for 640 kHz
|
||||||
|
# 7 for 768 kHz
|
||||||
|
# 8 for 960 kHz
|
||||||
|
# 9 for 1536 kHz
|
||||||
|
# 10 for 1920 kHz
|
||||||
|
#
|
||||||
|
# frequency - 32 bits of tuning frequency, MSB is first
|
||||||
|
# attenuation - binary 0, 10, 20, 30 for needed attenuation
|
||||||
|
#
|
||||||
|
# RX data, to PC, 508 bytes total
|
||||||
|
# Preamble + 'RX0' + FW1 + FW2 + CLIP + 2 zeroes + 492 bytes IQ data
|
||||||
|
#
|
||||||
|
# Where:
|
||||||
|
# FW1 and FW2 - char digits firmware version number
|
||||||
|
# CLIP - ADC overflow indicator, 0 or 1 binary
|
||||||
|
# IQ data for 0 - 7 rate:
|
||||||
|
# 82 IQ pairs formatted as "I2 I1 I0 Q2 Q1 Q0.... ", MSB is first, 24 bits per sample
|
||||||
|
# IQ data for 8 - 10 rate:
|
||||||
|
# 123 IQ pairs formatted as "I1 I0 Q1 Q0..... ", MSB is first, 16 bits per sample
|
||||||
|
#
|
||||||
|
# Band Scope control, to device, 32 bytes total
|
||||||
|
# Preamble + 'BS0' + enable + period + 19 binary zeroes
|
||||||
|
#
|
||||||
|
# Where period is the full frame period in ms, from 50 to 255ms, 100ms is recommended
|
||||||
|
# for 10Hz refresh rate window.
|
||||||
|
#
|
||||||
|
# Band Scope data, to PC, 16384 16bit samples, 32768 bytes by 492 in each packet
|
||||||
|
# Preamble + 'BS0' + FW1 + FW2 + CLIP + PN + 1 zero + 492 bytes BS data
|
||||||
|
#
|
||||||
|
# Where PN is packet number 0, 1, 2, ..., 66
|
||||||
|
# BS data in format "BS1, BS0, BS1, BS0, ...", MSB is first
|
||||||
|
#
|
||||||
|
# 66 packets with PN = 0 - 65 contain 492 bytes each, and 67-th packet with PN = 66 contains
|
||||||
|
# the remaining 296 bytes of data and junk data to full 492 bytes size
|
||||||
|
#
|
||||||
|
|
||||||
|
class Hardware(BaseHardware):
|
||||||
|
sample_rates = [48, 96, 192, 240, 384, 480, 640 ,768, 960, 1536, 1920]
|
||||||
|
def __init__(self, app, conf):
|
||||||
|
BaseHardware.__init__(self, app, conf)
|
||||||
|
self.device = None
|
||||||
|
self.usb = None
|
||||||
|
self.rf_gain_labels = ('RF +10', 'RF 0', 'RF -10', 'RF -20')
|
||||||
|
self.index = 1
|
||||||
|
self.enable = 0
|
||||||
|
self.rate = 0
|
||||||
|
self.att = 10
|
||||||
|
self.freq = 7220000
|
||||||
|
self.old_freq = 0
|
||||||
|
self.sdrmicron_clock = 76800000
|
||||||
|
self.sdrmicron_decim = 1600
|
||||||
|
self.bscope_data = bytearray(0)
|
||||||
|
self.fw_ver = None
|
||||||
|
self.frame_msg = ''
|
||||||
|
|
||||||
|
if conf.fft_size_multiplier == 0:
|
||||||
|
conf.fft_size_multiplier = 3 # Set size needed by VarDecim
|
||||||
|
|
||||||
|
rx_bytes = 3 # rx_bytes is the number of bytes in each I or Q sample: 1, 2, 3, or 4
|
||||||
|
rx_endian = 1 # rx_endian is the order of bytes in the sample array: 0 == little endian; 1 == big endian
|
||||||
|
self.InitSamples(rx_bytes, rx_endian) # Initialize: read samples from this hardware file and send them to Quisk
|
||||||
|
bs_bytes = 2
|
||||||
|
bs_endian = 1
|
||||||
|
self.InitBscope(bs_bytes, bs_endian, self.sdrmicron_clock, 16384) # Initialize bandscope
|
||||||
|
|
||||||
|
def open(self): # This method must return a string showing whether the open succeeded or failed.
|
||||||
|
enum = d2xx.createDeviceInfoList() # quantity of FTDI devices
|
||||||
|
if(enum==0):
|
||||||
|
return 'Device was not found'
|
||||||
|
for i in range(enum): # Searching and openinq needed device
|
||||||
|
a = d2xx.getDeviceInfoDetail(i)
|
||||||
|
if(a['description']==b'SDR-Micron'):
|
||||||
|
try: self.usb = d2xx.openEx(a['serial'])
|
||||||
|
except:
|
||||||
|
return 'Device was not found'
|
||||||
|
Mode = 64 # Configure FT2232H into 0x40 Sync FIFO Mode
|
||||||
|
self.usb.setBitMode(255, 0) # reset
|
||||||
|
time.sleep(0.1)
|
||||||
|
self.usb.setBitMode(255, Mode) #configure FT2232H into Sync FIFO mode
|
||||||
|
self.usb.setTimeouts(100, 100) # read, write
|
||||||
|
self.usb.setLatencyTimer(2)
|
||||||
|
self.usb.setUSBParameters(32, 32) # in_tx_size, out_tx_size
|
||||||
|
time.sleep(1.5) # waiting for initialisation device
|
||||||
|
data = self.usb.read(self.usb.getQueueStatus()) # clean the usb data buffer
|
||||||
|
self.device = 'Opened'
|
||||||
|
self.frame_msg = a['description'].decode('utf-8') + ' S/N - ' + a['serial'].decode('utf-8')
|
||||||
|
return self.frame_msg
|
||||||
|
return 'Device was not found'
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
if(self.usb):
|
||||||
|
if(self.device=='Opened'):
|
||||||
|
enable = 0
|
||||||
|
self.device = None
|
||||||
|
self.rx_control_upd()
|
||||||
|
time.sleep(0.5)
|
||||||
|
self.usb.setBitMode(255, 0) # reset
|
||||||
|
self.usb.close()
|
||||||
|
|
||||||
|
def OnButtonRfGain(self, event):
|
||||||
|
btn = event.GetEventObject()
|
||||||
|
n = btn.index
|
||||||
|
self.att = n * 10
|
||||||
|
self.rx_control_upd()
|
||||||
|
|
||||||
|
def ChangeFrequency(self, tune, vfo, source='', band='', event=None):
|
||||||
|
if vfo:
|
||||||
|
self.freq = (vfo - self.transverter_offset)
|
||||||
|
if(self.freq!=self.old_freq):
|
||||||
|
self.old_freq = self.freq
|
||||||
|
self.rx_control_upd()
|
||||||
|
return tune, vfo
|
||||||
|
|
||||||
|
def ChangeBand(self, band):
|
||||||
|
# band is a string: "60", "40", "WWV", etc.
|
||||||
|
BaseHardware.ChangeBand(self, band)
|
||||||
|
btn = self.application.BtnRfGain
|
||||||
|
if btn:
|
||||||
|
if band in ('160', '80', '60', '40'):
|
||||||
|
btn.SetLabel('RF -10', True)
|
||||||
|
elif band in ('20',):
|
||||||
|
btn.SetLabel('RF 0', True)
|
||||||
|
else:
|
||||||
|
btn.SetLabel('RF +10', True)
|
||||||
|
|
||||||
|
def VarDecimGetChoices(self): # Return a list/tuple of strings for the decimation control.
|
||||||
|
return list(map(str, self.sample_rates)) # convert integer to string
|
||||||
|
|
||||||
|
def VarDecimGetLabel(self): # return a text label for the control
|
||||||
|
return "Sample rate ksps"
|
||||||
|
|
||||||
|
def VarDecimGetIndex(self): # return the current index
|
||||||
|
return self.index
|
||||||
|
|
||||||
|
def VarDecimSet(self, index=None): # return sample rate
|
||||||
|
if index is None: # initial call to set the sample rate before the call to open()
|
||||||
|
rate = self.application.vardecim_set
|
||||||
|
try:
|
||||||
|
self.index = self.sample_rates.index(rate // 1000)
|
||||||
|
except:
|
||||||
|
self.index = 0
|
||||||
|
else:
|
||||||
|
self.index = index
|
||||||
|
rate = self.sample_rates[self.index] * 1000
|
||||||
|
self.rate = self.index
|
||||||
|
if(rate>=960000):
|
||||||
|
rx_bytes = 2
|
||||||
|
rx_endian = 1
|
||||||
|
self.InitSamples(rx_bytes, rx_endian)
|
||||||
|
else:
|
||||||
|
rx_bytes = 3
|
||||||
|
rx_endian = 1
|
||||||
|
self.InitSamples(rx_bytes, rx_endian)
|
||||||
|
self.rx_control_upd()
|
||||||
|
return rate
|
||||||
|
|
||||||
|
def VarDecimRange(self): # Return the lowest and highest sample rate.
|
||||||
|
return (48000, 1920000)
|
||||||
|
|
||||||
|
def StartSamples(self): # called by the sound thread
|
||||||
|
self.enable = 1
|
||||||
|
self.rx_control_upd()
|
||||||
|
self.bscope_control_upd()
|
||||||
|
|
||||||
|
def StopSamples(self): # called by the sound thread
|
||||||
|
self.enable = 0
|
||||||
|
self.rx_control_upd()
|
||||||
|
self.bscope_control_upd()
|
||||||
|
|
||||||
|
def rx_control_upd(self):
|
||||||
|
if(self.device=='Opened'):
|
||||||
|
work = self.freq
|
||||||
|
freq4 = work & 0xFF
|
||||||
|
work = work >> 8
|
||||||
|
freq3 = work & 0xFF
|
||||||
|
work = work >> 8
|
||||||
|
freq2 = work & 0xFF
|
||||||
|
work = work >> 8
|
||||||
|
freq1 = work & 0xFF
|
||||||
|
if sys.version_info.major <= 2:
|
||||||
|
MESSAGE = 7*chr(0x55) + chr(0xd5) + 'RX0' + chr(self.enable) + chr(self.rate)
|
||||||
|
MESSAGE += chr(freq1) + chr(freq2) + chr(freq3) + chr(freq4) + chr(self.att) + 14*chr(0)
|
||||||
|
else:
|
||||||
|
MESSAGE = b"\x55\x55\x55\x55\x55\x55\x55\xd5RX0"
|
||||||
|
MESSAGE += bytes((self.enable, self.rate, freq1, freq2, freq3, freq4, self.att))
|
||||||
|
MESSAGE += bytes(14)
|
||||||
|
try: self.usb.write(MESSAGE)
|
||||||
|
except: print('Error while rx_control_upd')
|
||||||
|
|
||||||
|
def bscope_control_upd(self):
|
||||||
|
if self.device == 'Opened':
|
||||||
|
if sys.version_info.major <= 2:
|
||||||
|
MESSAGE = 7*chr(0x55) + chr(0xd5) + 'BS0' + chr(self.enable) + chr(100) + 19 * chr(0)
|
||||||
|
else:
|
||||||
|
MESSAGE = b"\x55\x55\x55\x55\x55\x55\x55\xd5BS0"
|
||||||
|
MESSAGE += bytes((self.enable, 100))
|
||||||
|
MESSAGE += bytes(19)
|
||||||
|
try: self.usb.write(MESSAGE)
|
||||||
|
except: None
|
||||||
|
|
||||||
|
def GetRxSamples(self): # Read all data from the SDR Micron and process it.
|
||||||
|
if self.device == None:
|
||||||
|
return
|
||||||
|
while (self.usb.getQueueStatus() >= 508):
|
||||||
|
data = self.usb.read(508)
|
||||||
|
data = bytearray(data)
|
||||||
|
if data[8:11] == bytearray(b'RX0'): # Rx I/Q data
|
||||||
|
if data[13]:
|
||||||
|
self.GotClip()
|
||||||
|
if self.fw_ver is None:
|
||||||
|
self.fw_ver = chr(data[11]) + '.' + chr(data[12])
|
||||||
|
self.frame_msg += ' F/W version - ' + self.fw_ver
|
||||||
|
self.application.main_frame.SetConfigText(self.frame_msg)
|
||||||
|
self.AddRxSamples(data[16:])
|
||||||
|
elif data[8:11] == bytearray(b'BS0'): # bandscope data
|
||||||
|
packet_number = data[14]
|
||||||
|
if packet_number == 0: # start of a block of data
|
||||||
|
self.bscope_data = data[16:] # 492 bytes
|
||||||
|
elif packet_number < 66:
|
||||||
|
self.bscope_data += data[16:] # 492 bytes
|
||||||
|
else: # end of a block of data, 296 bytes
|
||||||
|
self.bscope_data += data[16:312]
|
||||||
|
self.AddBscopeSamples(self.bscope_data)
|
||||||
|
|
||||||
|
|
2
setup.py
2
setup.py
@ -8,7 +8,7 @@ import struct
|
|||||||
# 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.1.52'
|
Version = '4.1.53'
|
||||||
|
|
||||||
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)
|
||||||
|
Binary file not shown.
Binary file not shown.
19
softrock_tune_vfo.py
Executable file
19
softrock_tune_vfo.py
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
# This is a replacement hardware file for the Softrock and similar radios.
|
||||||
|
|
||||||
|
# Normally Quisk will change the VFO (center frequency) by large amounts, and perform
|
||||||
|
# fine tuning within the returned bandwidth. This hardware file does all tuning with the VFO.
|
||||||
|
# This creates a constant offset between the VFO and the tuning frequency. Specify this file
|
||||||
|
# as your hardware file on the Config/radio/Hardware screen.
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
|
||||||
|
import softrock
|
||||||
|
from softrock.hardware_usb import Hardware as BaseHardware
|
||||||
|
|
||||||
|
class Hardware(BaseHardware):
|
||||||
|
def ChangeFrequency(self, tx_freq, vfo_freq, source='', band='', event=None):
|
||||||
|
vfo_freq = tx_freq - 10000
|
||||||
|
tx, vfo = BaseHardware.ChangeFrequency(self, tx_freq, vfo_freq, source, band, event)
|
||||||
|
return tx, vfo
|
Loading…
Reference in New Issue
Block a user