Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31ecbce146 | ||
|
|
a1343c1264 | ||
|
|
71146c9eaf | ||
|
|
814e4ce08c | ||
|
|
36d717636c |
@@ -1,3 +1,42 @@
|
|||||||
|
Quisk Version 4.2.34 May 2024
|
||||||
|
==============================
|
||||||
|
For the Hermes-Lite2 the inhibit Tx function (CN8) now releases the Spot button.
|
||||||
|
|
||||||
|
Quisk displays the band plan below the X-axis as colored bars, and there are eighteen possible colors.
|
||||||
|
If you hover the mouse over a bar, Quisk now displays the name of the mode. Recall that there is a dialog
|
||||||
|
box so you can set the band plan to what you want.
|
||||||
|
|
||||||
|
Quisk Version 4.2.33 May 2024
|
||||||
|
==============================
|
||||||
|
Added the get_level Hamlib command "l STRENGTH". It returns the S-meter reading. I finally found some Hamlib
|
||||||
|
documentation, often not an easy task. The return value of STRENGTH is in dB with zero dB equal to S9.
|
||||||
|
There are 6 dB per S-unit. So a STRENGTH of 4 is 4dB over S9, and -6, -12, -18 is S8, S7, S6. I also added
|
||||||
|
the corresponding FlexRadio command ZZSM.
|
||||||
|
|
||||||
|
Quisk Version 4.2.32 April 2024
|
||||||
|
================================
|
||||||
|
I found and fixed a bug in the microphone filters that can result in a buffer overrun. You should update Quisk.
|
||||||
|
|
||||||
|
Some Linux digital programs can not use the usual Quisk Pulse loopback device and must use an
|
||||||
|
Alsa loopback. I added more documentation for Alsa loopbacks, added more information on the Sound
|
||||||
|
screen and I changed the default Alsa sample size to 16 bit.
|
||||||
|
|
||||||
|
Quisk now responds to the Hermes Lite2 Tx inhibit input by displaying a message and extinguishing the "Tx" light.
|
||||||
|
There is a new item "Hermes Lite2 protocol" on the Hardware screen to control this behavior.
|
||||||
|
|
||||||
|
Quisk Version 4.2.31 March 2024
|
||||||
|
================================
|
||||||
|
The "Tune" item was missing from the Midi menus. I fixed it but I didn't test it because I did
|
||||||
|
not borrow Ben's Midi controller. Please test it yourself and let me know if it works. The Midi
|
||||||
|
speed can be set from the menu too.
|
||||||
|
|
||||||
|
Quisk Version 4.2.30 March 2024
|
||||||
|
================================
|
||||||
|
A new option "Tx-Rx silence msec" on the Timing configuration screen controls how long
|
||||||
|
to suppress Rx audio when switching from Tx to Rx. The previous fixed time was 50 msec.
|
||||||
|
|
||||||
|
The SSB squelch control now works on CW too. Please test.
|
||||||
|
|
||||||
Quisk Version 4.2.29 January 2024
|
Quisk Version 4.2.29 January 2024
|
||||||
==================================
|
==================================
|
||||||
This version updates the FreeDV library files and program logic. I added a "Monitor"
|
This version updates the FreeDV library files and program logic. I added a "Monitor"
|
||||||
|
|||||||
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
#Quisk version 4.2.29
|
#Quisk version 4.2.34
|
||||||
from .quisk import main
|
from .quisk import main
|
||||||
|
|||||||
+21
-27
@@ -170,12 +170,16 @@ class Configuration:
|
|||||||
radio_dict["Hermes_BandDictTx"] = {}
|
radio_dict["Hermes_BandDictTx"] = {}
|
||||||
def UpdateGlobals(self):
|
def UpdateGlobals(self):
|
||||||
self.RadioName = Settings[1]
|
self.RadioName = Settings[1]
|
||||||
|
application.BandPlanC2T = {}
|
||||||
if self.RadioName == "ConfigFileRadio":
|
if self.RadioName == "ConfigFileRadio":
|
||||||
application.BandPlan = conf.BandPlan
|
application.BandPlan = conf.BandPlan
|
||||||
|
for mode, color in conf.BandPlanColors:
|
||||||
|
application.BandPlanC2T[color] = mode
|
||||||
elif "BandPlanColors" in Settings[4] and "BandPlan" in Settings[4]:
|
elif "BandPlanColors" in Settings[4] and "BandPlan" in Settings[4]:
|
||||||
mode_dict = {"End":None}
|
mode_dict = {"End":None}
|
||||||
for mode, color in Settings[4]["BandPlanColors"]:
|
for mode, color in Settings[4]["BandPlanColors"]:
|
||||||
mode_dict[mode] = color
|
mode_dict[mode] = color
|
||||||
|
application.BandPlanC2T[color] = mode
|
||||||
plan = []
|
plan = []
|
||||||
for freq, mode in Settings[4]["BandPlan"]:
|
for freq, mode in Settings[4]["BandPlan"]:
|
||||||
freq = int(float(freq) * 1E6 + 0.1)
|
freq = int(float(freq) * 1E6 + 0.1)
|
||||||
@@ -188,6 +192,8 @@ class Configuration:
|
|||||||
application.BandPlan = plan
|
application.BandPlan = plan
|
||||||
else:
|
else:
|
||||||
application.BandPlan = conf.BandPlan
|
application.BandPlan = conf.BandPlan
|
||||||
|
for mode, color in conf.BandPlanColors:
|
||||||
|
application.BandPlanC2T[color] = mode
|
||||||
if "MidiNoteDict" not in Settings[4]:
|
if "MidiNoteDict" not in Settings[4]:
|
||||||
Settings[4]["MidiNoteDict"] = {}
|
Settings[4]["MidiNoteDict"] = {}
|
||||||
self.settings_changed = True
|
self.settings_changed = True
|
||||||
@@ -1484,7 +1490,7 @@ class MidiKnob(QuiskControl):
|
|||||||
self.menu = wx.Menu()
|
self.menu = wx.Menu()
|
||||||
for name in application.midiControls:
|
for name in application.midiControls:
|
||||||
ctrl, func = application.midiControls[name]
|
ctrl, func = application.midiControls[name]
|
||||||
if not ctrl or not func:
|
if name != "Tune" and (not ctrl or not func):
|
||||||
continue
|
continue
|
||||||
item = self.menu.Append(-1, name)
|
item = self.menu.Append(-1, name)
|
||||||
self.Bind(wx.EVT_MENU, self.OnMenu, item)
|
self.Bind(wx.EVT_MENU, self.OnMenu, item)
|
||||||
@@ -1519,7 +1525,7 @@ class MidiJogWheel(QuiskControl):
|
|||||||
controls = wx.Menu()
|
controls = wx.Menu()
|
||||||
for name in application.midiControls:
|
for name in application.midiControls:
|
||||||
ctrl, func = application.midiControls[name]
|
ctrl, func = application.midiControls[name]
|
||||||
if not ctrl or not func:
|
if name != "Tune" and (not ctrl or not func):
|
||||||
continue
|
continue
|
||||||
item = controls.Append(-1, name)
|
item = controls.Append(-1, name)
|
||||||
self.Bind(wx.EVT_MENU, self.OnMenu, item)
|
self.Bind(wx.EVT_MENU, self.OnMenu, item)
|
||||||
@@ -2005,7 +2011,7 @@ class ControlMixin:
|
|||||||
if self.radio_name == Settings[1]: # changed for current radio
|
if self.radio_name == Settings[1]: # changed for current radio
|
||||||
if name in ('hot_key_ptt_toggle', 'hot_key_ptt_if_hidden', 'keyupDelay', 'cwTone', 'pulse_audio_verbose_output',
|
if name in ('hot_key_ptt_toggle', 'hot_key_ptt_if_hidden', 'keyupDelay', 'cwTone', 'pulse_audio_verbose_output',
|
||||||
'start_cw_delay', 'start_ssb_delay', 'maximum_tx_secs', 'quisk_serial_cts', 'quisk_serial_dsr',
|
'start_cw_delay', 'start_ssb_delay', 'maximum_tx_secs', 'quisk_serial_cts', 'quisk_serial_dsr',
|
||||||
'hot_key_ptt1', 'hot_key_ptt2', 'midi_ptt_toggle'):
|
'hot_key_ptt1', 'hot_key_ptt2', 'midi_ptt_toggle', 'TxRxSilenceMsec', 'hermes_lite2_enable'):
|
||||||
setattr(conf, name, x)
|
setattr(conf, name, x)
|
||||||
application.ImmediateChange(name)
|
application.ImmediateChange(name)
|
||||||
elif name[0:4] in ('lin_', 'win_'):
|
elif name[0:4] in ('lin_', 'win_'):
|
||||||
@@ -3399,14 +3405,20 @@ class RadioSound(BaseWindow): # The Sound page in the second-level notebook for
|
|||||||
('', '', '', '', 'digital_rx8_name'),
|
('', '', '', '', 'digital_rx8_name'),
|
||||||
('', '', '', '', 'digital_rx9_name'),
|
('', '', '', '', 'digital_rx9_name'),
|
||||||
)
|
)
|
||||||
|
hRx0 = "This is almost the same as the radio sound, but it is sent to a digital mode program on a different sound device."\
|
||||||
|
" It is analog audio and it is only sent if one of the DGT- modes is selected."\
|
||||||
|
" The volume is set by the digital output level instead of the volume control so you can mute the speaker if desired."\
|
||||||
|
" It can receive a greater bandwidth than the 3000 Hz limit of SSB."
|
||||||
|
hTx0 = "This is used instead of the microphone when one of the DGT- modes is selected."\
|
||||||
|
" The normal speech clipping and filtering is not used for DGT- modes."
|
||||||
label_help = ( # Same order as sound_names
|
label_help = ( # Same order as sound_names
|
||||||
(1, "Radio Sound Output", "This is the radio sound going to the headphones or speakers."),
|
(1, "Radio Sound Output", "This is the radio sound going to the headphones or speakers."),
|
||||||
(0, "Microphone Input", "This is the monophonic microphone source. Set the channel if the source is stereo."),
|
(0, "Microphone Input", "This is the monophonic microphone source. Set the channel if the source is stereo."),
|
||||||
(0, "I/Q Rx Sample Input", "This is the sample source if it comes from a sound device, such as a SoftRock."),
|
(0, "I/Q Rx Sample Input", "This is the sample source if it comes from a sound device, such as a SoftRock."),
|
||||||
(1, "I/Q Tx Sample Output", "This is the transmit sample audio sent to a SoftRock."),
|
(1, "I/Q Tx Sample Output", "This is the transmit sample audio sent to a SoftRock."),
|
||||||
(1, "Raw Digital Output", "This sends the received I/Q data to another program as stereo."),
|
(1, "Raw Digital Output", "This sends the received I/Q data to another program as stereo."),
|
||||||
(0, "Digital Tx0 Input", "This is the transmit audio coming from a digital mode program."),
|
(0, "Digital Tx0 Input", hTx0),
|
||||||
(1, "Digital Rx0 Output", "This is the main receiver Rx0 audio going to a digital mode program."),
|
(1, "Digital Rx0 Output", hRx0),
|
||||||
(1, "Digital Rx1 Output", "This is the sub-receiver 1 audio going to a digital mode program."),
|
(1, "Digital Rx1 Output", "This is the sub-receiver 1 audio going to a digital mode program."),
|
||||||
(1, "Digital Rx2 Output", "This is the sub-receiver 2 audio going to a digital mode program."),
|
(1, "Digital Rx2 Output", "This is the sub-receiver 2 audio going to a digital mode program."),
|
||||||
(1, "Digital Rx3 Output", "This is the sub-receiver 3 audio going to a digital mode program."),
|
(1, "Digital Rx3 Output", "This is the sub-receiver 3 audio going to a digital mode program."),
|
||||||
@@ -3978,28 +3990,7 @@ class BandPlanDlg(wx.Dialog, ControlMixin):
|
|||||||
if "BandPlanColors" in Settings[4] and "BandPlan" in Settings[4]:
|
if "BandPlanColors" in Settings[4] and "BandPlan" in Settings[4]:
|
||||||
colors = Settings[4]["BandPlanColors"]
|
colors = Settings[4]["BandPlanColors"]
|
||||||
else:
|
else:
|
||||||
Get = conf.__dict__.get # Get colors from the user's config file, if any.
|
colors = conf.BandPlanColors
|
||||||
dflt = "#555555"
|
|
||||||
colors = [
|
|
||||||
['CW, General', Get("CW", dflt)],
|
|
||||||
['CW, Extra', Get("eCW", dflt)],
|
|
||||||
['Phone, General', Get("Phone", dflt)],
|
|
||||||
['Phone, Extra', Get("ePhone", dflt)],
|
|
||||||
['AM', Get("AM", dflt)],
|
|
||||||
['Data', Get("Data", dflt)],
|
|
||||||
['DxData', Get("DxData", dflt)],
|
|
||||||
['RTTY', Get("RTTY", dflt)],
|
|
||||||
['SSTV', Get("SSTV", dflt)],
|
|
||||||
['Packet', Get("Packet", dflt)],
|
|
||||||
['Beacons', Get("Beacons", dflt)],
|
|
||||||
['Satellite', Get("Satellite",dflt)],
|
|
||||||
['Repeater out', Get("Repeater", dflt)],
|
|
||||||
['Repeater in', Get("RepInput", dflt)],
|
|
||||||
['Simplex', Get("Simplex", dflt)],
|
|
||||||
['Rx only', Get("RxOnly", dflt)],
|
|
||||||
['Special', Get("Special", dflt)],
|
|
||||||
['Other', Get("Other", dflt)]
|
|
||||||
]
|
|
||||||
self.modes = []
|
self.modes = []
|
||||||
self.color_dict = {None:"End"}
|
self.color_dict = {None:"End"}
|
||||||
self.mode_dict = {"End":None}
|
self.mode_dict = {"End":None}
|
||||||
@@ -4206,6 +4197,9 @@ The mode begins at the start frequency and ends at the next frequency.'
|
|||||||
plan.append([hertz, color])
|
plan.append([hertz, color])
|
||||||
Settings[4]["BandPlan"] = freq_mode
|
Settings[4]["BandPlan"] = freq_mode
|
||||||
application.BandPlan = plan
|
application.BandPlan = plan
|
||||||
|
application.BandPlanC2T = {}
|
||||||
|
for mode, color in mode_color:
|
||||||
|
application.BandPlanC2T[color] = mode
|
||||||
local_conf.settings_changed = True
|
local_conf.settings_changed = True
|
||||||
self.EndModal(wx.ID_OK)
|
self.EndModal(wx.ID_OK)
|
||||||
def OnCancel(self, event):
|
def OnCancel(self, event):
|
||||||
|
|||||||
@@ -1470,22 +1470,29 @@ remember the settings.
|
|||||||
<br>
|
<br>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
If you don't have PulseAudio or don't want to use it, you can use the ALSA loopback device.
|
If your digital program only uses Alsa devices or you don't want to use PulseAudio,
|
||||||
The ALSA loopback device works the same way as the Windows VAC. First
|
you can use the ALSA loopback device.
|
||||||
create the loopback device with the command "modprobe snd-aloop" (you
|
It works the same way as the Windows VAC. First create the loopback device with this command:
|
||||||
will need to be root). You can create the loopback device
|
<pre>
|
||||||
when the system starts, but the way to do that depends on your version of
|
sudo modprobe snd-aloop index=19
|
||||||
Linux. I added snd-aloop to /etc/modules. You could put the modprobe command in /etc/rc.local instead.
|
</pre>
|
||||||
|
The "index" is the card number, and it is best to use a number higher than your regular cards.
|
||||||
|
The loopback device will be gone on the next restart.
|
||||||
|
You can create the loopback device every time the system starts, but the way to do that depends on your version of Linux.
|
||||||
|
You could add this line to /etc/modprobe.d/alsa-base.conf:
|
||||||
|
<pre>
|
||||||
|
options snd-aloop index=19
|
||||||
|
</pre>
|
||||||
|
Or you could add snd-aloop to /etc/modules or put the modprobe command in /etc/rc.local instead.
|
||||||
Restart Linux. Now you can enter "cat /proc/asound/cards" to
|
Restart Linux. Now you can enter "cat /proc/asound/cards" to
|
||||||
print out your sound cards, and you should see a "Loopback" card
|
print out your sound cards, and you should see a "Loopback" card listed.
|
||||||
listed. The cards are also shown on the Quisk Sound
|
The Loopback card has one side that connects to Quisk and
|
||||||
screen. The Loopback card has one side that connects to Quisk and
|
|
||||||
another side that connects to your digital program. For the Quisk
|
another side that connects to your digital program. For the Quisk
|
||||||
side connect both Digital Input and Digital Output to Loopback,0.
|
side connect both Digital Input and Digital Output to the Loopback at hw:19,0.
|
||||||
Note that the Loopback card is full duplex, and handles both
|
Note that the Loopback card is full duplex, and handles both
|
||||||
input and output. There are actually eight loopbacks created at once,
|
input and output. There are actually eight loopbacks created at once,
|
||||||
but we are only using subdevice 0. For the digital program side, set the input and
|
but we are only using subdevice 0. For the digital program side, set the input and
|
||||||
output to "Loopback,1".
|
output to the Loopback at hw:19,1.
|
||||||
Your audio is now connected and you
|
Your audio is now connected and you
|
||||||
should be able to receive digital signals. Be sure to test your
|
should be able to receive digital signals. Be sure to test your
|
||||||
transmit signal off the air. You may need to reduce power to
|
transmit signal off the air. You may need to reduce power to
|
||||||
|
|||||||
@@ -168,6 +168,7 @@ static void modem_status(void)
|
|||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/time.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
|
|
||||||
static int fdComm = -1; // File descriptor to read the serial port
|
static int fdComm = -1; // File descriptor to read the serial port
|
||||||
|
|||||||
+7
-6
@@ -372,7 +372,7 @@ static void process_alc(complex double * cSamples, int count, struct alc * pt, r
|
|||||||
|
|
||||||
static int tx_filter(complex double * filtered, int count)
|
static int tx_filter(complex double * filtered, int count)
|
||||||
{ // Input samples are creal(filtered), output is filtered. The input rate must be 8000 or 48000 sps.
|
{ // Input samples are creal(filtered), output is filtered. The input rate must be 8000 or 48000 sps.
|
||||||
int i, is_ssb;
|
int i, is_ssb, mic_interp;
|
||||||
int sample_rate = 8000;
|
int sample_rate = 8000;
|
||||||
double dsample, dtmp, magn;
|
double dsample, dtmp, magn;
|
||||||
complex double csample;
|
complex double csample;
|
||||||
@@ -423,9 +423,10 @@ static int tx_filter(complex double * filtered, int count)
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
mic_interp = MIC_OUT_RATE / sample_rate;
|
||||||
// check size of dsamples[] and csamples[] buffer
|
// check size of dsamples[] and csamples[] buffer
|
||||||
if (count > samples_size) {
|
if (count > samples_size) {
|
||||||
samples_size = count * 2;
|
samples_size = count * 2 * mic_interp;
|
||||||
if (dsamples)
|
if (dsamples)
|
||||||
free(dsamples);
|
free(dsamples);
|
||||||
if (csamples)
|
if (csamples)
|
||||||
@@ -541,8 +542,8 @@ static int tx_filter(complex double * filtered, int count)
|
|||||||
// remove clipping distortion
|
// remove clipping distortion
|
||||||
count = quisk_cDecimate(csamples, count, &cfiltAudio3, 1);
|
count = quisk_cDecimate(csamples, count, &cfiltAudio3, 1);
|
||||||
// Interpolate up to 48000
|
// Interpolate up to 48000
|
||||||
if (MIC_OUT_RATE != sample_rate)
|
if (mic_interp != 1)
|
||||||
count = quisk_cInterpolate(csamples, count, &cfiltInterp, MIC_OUT_RATE / sample_rate);
|
count = quisk_cInterpolate(csamples, count, &cfiltInterp, mic_interp);
|
||||||
// convert back to 16 bits
|
// convert back to 16 bits
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
filtered[i] = csamples[i] * CLIP16;
|
filtered[i] = csamples[i] * CLIP16;
|
||||||
@@ -573,8 +574,8 @@ static int tx_filter(complex double * filtered, int count)
|
|||||||
// remove clipping distortion
|
// remove clipping distortion
|
||||||
count = quisk_dFilter(dsamples, count, &dfiltAudio3);
|
count = quisk_dFilter(dsamples, count, &dfiltAudio3);
|
||||||
// Interpolate up to 48000
|
// Interpolate up to 48000
|
||||||
if (MIC_OUT_RATE != sample_rate)
|
if (mic_interp != 1)
|
||||||
count = quisk_dInterpolate(dsamples, count, &dfiltInterp, MIC_OUT_RATE / sample_rate);
|
count = quisk_dInterpolate(dsamples, count, &dfiltInterp, mic_interp);
|
||||||
// convert back to 16 bits
|
// convert back to 16 bits
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
filtered[i] = dsamples[i] * CLIP16;
|
filtered[i] = dsamples[i] * CLIP16;
|
||||||
|
|||||||
@@ -155,6 +155,7 @@ static int freedv_monitor; // pass the Freedv audio to the speakers instead of
|
|||||||
|
|
||||||
static complex double PySampleBuf[SAMP_BUFFER_SIZE]; // buffer for samples returned from Python
|
static complex double PySampleBuf[SAMP_BUFFER_SIZE]; // buffer for samples returned from Python
|
||||||
static int PySampleCount; // count of samples in buffer
|
static int PySampleCount; // count of samples in buffer
|
||||||
|
static bool quisk_tx_inhibit;
|
||||||
|
|
||||||
static int multirx_data_width; // width of graph data to return
|
static int multirx_data_width; // width of graph data to return
|
||||||
static int multirx_fft_width; // size of FFT samples
|
static int multirx_fft_width; // size of FFT samples
|
||||||
@@ -181,6 +182,7 @@ int quisk_sidetoneFreq; // frequency in hertz for the sidetone
|
|||||||
int quisk_start_cw_delay = 15; // milliseconds to delay output on CW key down
|
int quisk_start_cw_delay = 15; // milliseconds to delay output on CW key down
|
||||||
int quisk_start_ssb_delay = 100; // milliseconds to discard output on SSB etc. key down
|
int quisk_start_ssb_delay = 100; // milliseconds to discard output on SSB etc. key down
|
||||||
static int maximum_tx_secs; // Failsafe timeout for Tx in seconds
|
static int maximum_tx_secs; // Failsafe timeout for Tx in seconds
|
||||||
|
static int TxRxSilenceMsec = 50; // Play silence in msec on Tx to Rx
|
||||||
static int key_is_down = 0; // internal key state up or down
|
static int key_is_down = 0; // internal key state up or down
|
||||||
|
|
||||||
static double agcReleaseGain=80; // AGC maximum gain
|
static double agcReleaseGain=80; // AGC maximum gain
|
||||||
@@ -1921,6 +1923,10 @@ static int quisk_process_demodulate(complex double * cSamples, double * dsamples
|
|||||||
}
|
}
|
||||||
if(bank == 0)
|
if(bank == 0)
|
||||||
dAutoNotch(dsamples, nSamples, rit_freq, quisk_filter_srate);
|
dAutoNotch(dsamples, nSamples, rit_freq, quisk_filter_srate);
|
||||||
|
if (ssb_squelch_enabled) {
|
||||||
|
ssb_squelch(dsamples, nSamples, quisk_filter_srate, MeasureSquelch + bank);
|
||||||
|
d_delay(dsamples, nSamples, bank, SQUELCH_FFT_SIZE);
|
||||||
|
}
|
||||||
nSamples = quisk_dInterpolate(dsamples, nSamples, &Storage[bank].filtAudio12p2, 2);
|
nSamples = quisk_dInterpolate(dsamples, nSamples, &Storage[bank].filtAudio12p2, 2);
|
||||||
nSamples = quisk_dInterp2HB45(dsamples, nSamples, &Storage[bank].HalfBand6);
|
nSamples = quisk_dInterp2HB45(dsamples, nSamples, &Storage[bank].HalfBand6);
|
||||||
nSamples = quisk_dInterp2HB45(dsamples, nSamples, &Storage[bank].HalfBand7);
|
nSamples = quisk_dInterp2HB45(dsamples, nSamples, &Storage[bank].HalfBand7);
|
||||||
@@ -1940,6 +1946,10 @@ static int quisk_process_demodulate(complex double * cSamples, double * dsamples
|
|||||||
}
|
}
|
||||||
if(bank == 0)
|
if(bank == 0)
|
||||||
dAutoNotch(dsamples, nSamples, rit_freq, quisk_filter_srate);
|
dAutoNotch(dsamples, nSamples, rit_freq, quisk_filter_srate);
|
||||||
|
if (ssb_squelch_enabled) {
|
||||||
|
ssb_squelch(dsamples, nSamples, quisk_filter_srate, MeasureSquelch + bank);
|
||||||
|
d_delay(dsamples, nSamples, bank, SQUELCH_FFT_SIZE);
|
||||||
|
}
|
||||||
nSamples = quisk_dInterpolate(dsamples, nSamples, &Storage[bank].filtAudio12p2, 2);
|
nSamples = quisk_dInterpolate(dsamples, nSamples, &Storage[bank].filtAudio12p2, 2);
|
||||||
nSamples = quisk_dInterp2HB45(dsamples, nSamples, &Storage[bank].HalfBand6);
|
nSamples = quisk_dInterp2HB45(dsamples, nSamples, &Storage[bank].HalfBand6);
|
||||||
nSamples = quisk_dInterp2HB45(dsamples, nSamples, &Storage[bank].HalfBand7);
|
nSamples = quisk_dInterp2HB45(dsamples, nSamples, &Storage[bank].HalfBand7);
|
||||||
@@ -2458,7 +2468,7 @@ int quisk_process_samples(complex double * cSamples, int nSamples)
|
|||||||
quisk_sound_state.sample_rate;
|
quisk_sound_state.sample_rate;
|
||||||
nout = (int)dOutCounter; // number of samples to output
|
nout = (int)dOutCounter; // number of samples to output
|
||||||
dOutCounter -= nout;
|
dOutCounter -= nout;
|
||||||
playSilence = (int)(quisk_sound_state.playback_rate * 50e-3); // Play silence after sidetone ends, number of samples
|
playSilence = (int)(quisk_sound_state.playback_rate * 1E-3 * TxRxSilenceMsec); // Play silence after sidetone ends, number of samples
|
||||||
keyupEnvelope = 0;
|
keyupEnvelope = 0;
|
||||||
if (quisk_active_sidetone == 2 && QUISK_CWKEY_DOWN) { // Play sidetone instead of radio for CW
|
if (quisk_active_sidetone == 2 && QUISK_CWKEY_DOWN) { // Play sidetone instead of radio for CW
|
||||||
if (! sidetoneIsOn) { // turn on sidetone
|
if (! sidetoneIsOn) { // turn on sidetone
|
||||||
@@ -2732,7 +2742,7 @@ int quisk_process_samples(complex double * cSamples, int nSamples)
|
|||||||
multirx_cSamples[0][i] = dsamples2[i] + I * dsamples2[i];
|
multirx_cSamples[0][i] = dsamples2[i] + I * dsamples2[i];
|
||||||
process_agc(&Agc3, multirx_cSamples[0], n, 0);
|
process_agc(&Agc3, multirx_cSamples[0], n, 0);
|
||||||
}
|
}
|
||||||
play_sound_interface(quiskPlaybackDevices[QUISK_INDEX_SUB_RX1], n, multirx_cSamples[0], 1, 1.0);
|
play_sound_interface(quiskPlaybackDevices[QUISK_INDEX_SUB_RX1], n, multirx_cSamples[0], 1, digital_output_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perhaps decimate by an additional fraction
|
// Perhaps decimate by an additional fraction
|
||||||
@@ -3147,6 +3157,8 @@ static PyObject * get_params(PyObject * self, PyObject * args)
|
|||||||
return PyInt_FromLong(quisk_serial_ptt);
|
return PyInt_FromLong(quisk_serial_ptt);
|
||||||
if (strcmp(name, "hl2_txbuf_errors") == 0)
|
if (strcmp(name, "hl2_txbuf_errors") == 0)
|
||||||
return PyInt_FromLong(hl2_txbuf_errors);
|
return PyInt_FromLong(hl2_txbuf_errors);
|
||||||
|
if (strcmp(name, "quisk_tx_inhibit") == 0)
|
||||||
|
return PyInt_FromLong((long)quisk_tx_inhibit);
|
||||||
Py_INCREF (Py_None);
|
Py_INCREF (Py_None);
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
@@ -3750,6 +3762,7 @@ 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++;
|
||||||
|
quisk_tx_inhibit = (quisk_hermes_to_pc[0] & 0x02) == 0; // should limit to Hermes Lite2 only
|
||||||
hardware_ptt = buf[start] & 0x01; // C0 bit zero is PTT
|
hardware_ptt = buf[start] & 0x01; // C0 bit zero is PTT
|
||||||
quisk_hardware_cwkey = (buf[start] & 0x04) >> 2; // C0 bit two is CW key state
|
quisk_hardware_cwkey = (buf[start] & 0x04) >> 2; // C0 bit two is CW key state
|
||||||
switch (hl2_txbuf_state) {
|
switch (hl2_txbuf_state) {
|
||||||
@@ -3861,6 +3874,10 @@ static int read_rx_udp17(complex double * cSamples0) // Read samples from UDP
|
|||||||
fft_data * ptFFT;
|
fft_data * ptFFT;
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
static int block_number=0;
|
static int block_number=0;
|
||||||
|
static complex double dc_average = 0; // Average DC component in samples
|
||||||
|
static complex double dc_sum = 0;
|
||||||
|
static int dc_count = 0;
|
||||||
|
static time_t time0 = 0;
|
||||||
// Data from the receiver is little-endian
|
// Data from the receiver is little-endian
|
||||||
|
|
||||||
if ( ! rx_udp_gain_correct) { // correct for second stage CIC decimation JIM JIM
|
if ( ! rx_udp_gain_correct) { // correct for second stage CIC decimation JIM JIM
|
||||||
@@ -3966,6 +3983,16 @@ static int read_rx_udp17(complex double * cSamples0) // Read samples from UDP
|
|||||||
if (xr & 0x100) { // channel 1
|
if (xr & 0x100) { // channel 1
|
||||||
if (quisk_invert_spectrum) // Invert spectrum
|
if (quisk_invert_spectrum) // Invert spectrum
|
||||||
sample = conj(sample);
|
sample = conj(sample);
|
||||||
|
// correct the DC level
|
||||||
|
dc_sum += sample;
|
||||||
|
dc_count++;
|
||||||
|
sample -= dc_average;
|
||||||
|
if (dc_count >= 48000 && time(NULL) != time0) {
|
||||||
|
time0 = time(NULL);
|
||||||
|
dc_average = dc_sum / dc_count;
|
||||||
|
dc_sum = dc_count = 0;
|
||||||
|
//printf ("New DC average %.0lf\n", cabs(dc_average));
|
||||||
|
}
|
||||||
// Put samples into the fft input array.
|
// Put samples into the fft input array.
|
||||||
ptFFT = fft_data_array + fft_data_index;
|
ptFFT = fft_data_array + fft_data_index;
|
||||||
if ( ! (xi & 0x100)) { // zero marker for start of first block
|
if ( ! (xi & 0x100)) { // zero marker for start of first block
|
||||||
@@ -4694,6 +4721,9 @@ static PyObject * ImmediateChange(PyObject * self, PyObject * args) // called fr
|
|||||||
else if ( ! strcmp(name, "maximum_tx_secs")) {
|
else if ( ! strcmp(name, "maximum_tx_secs")) {
|
||||||
maximum_tx_secs = QuiskGetConfigInt(name, 0);
|
maximum_tx_secs = QuiskGetConfigInt(name, 0);
|
||||||
}
|
}
|
||||||
|
else if ( ! strcmp(name, "TxRxSilenceMsec")) {
|
||||||
|
TxRxSilenceMsec = QuiskGetConfigInt(name, 50);
|
||||||
|
}
|
||||||
Py_INCREF (Py_None);
|
Py_INCREF (Py_None);
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
@@ -5851,6 +5881,7 @@ static PyObject * record_app(PyObject * self, PyObject * args)
|
|||||||
quisk_start_cw_delay = QuiskGetConfigInt("start_cw_delay", 15);
|
quisk_start_cw_delay = QuiskGetConfigInt("start_cw_delay", 15);
|
||||||
quisk_start_ssb_delay = QuiskGetConfigInt("start_ssb_delay", 100);
|
quisk_start_ssb_delay = QuiskGetConfigInt("start_ssb_delay", 100);
|
||||||
maximum_tx_secs = QuiskGetConfigInt("maximum_tx_secs", 0);
|
maximum_tx_secs = QuiskGetConfigInt("maximum_tx_secs", 0);
|
||||||
|
TxRxSilenceMsec = QuiskGetConfigInt("TxRxSilenceMsec", 50);
|
||||||
quisk_sound_state.sample_rate = rate;
|
quisk_sound_state.sample_rate = rate;
|
||||||
fft_sample_rate = rate;
|
fft_sample_rate = rate;
|
||||||
is_little_endian = 1; // Test machine byte order
|
is_little_endian = 1; // Test machine byte order
|
||||||
|
|||||||
@@ -320,6 +320,7 @@ extern int quisk_start_cw_delay; // milliseconds to delay output on serial or M
|
|||||||
extern int quisk_start_ssb_delay; // milliseconds to discard output for all modes except CW
|
extern int quisk_start_ssb_delay; // milliseconds to discard output for all modes except CW
|
||||||
extern struct sound_dev * quiskPlaybackDevices[]; // array of Playback sound devices
|
extern struct sound_dev * quiskPlaybackDevices[]; // array of Playback sound devices
|
||||||
extern int quisk_close_file_play;
|
extern int quisk_close_file_play;
|
||||||
|
extern double digital_output_level;
|
||||||
|
|
||||||
extern PyObject * quisk_set_spot_level(PyObject * , PyObject *);
|
extern PyObject * quisk_set_spot_level(PyObject * , PyObject *);
|
||||||
extern PyObject * quisk_get_tx_filter(PyObject * , PyObject *);
|
extern PyObject * quisk_get_tx_filter(PyObject * , PyObject *);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
# All QUISK software is Copyright (C) 2006-2021 by James C. Ahlstrom.
|
# All QUISK software is Copyright (C) 2006-2024 by James C. Ahlstrom.
|
||||||
# This free software is licensed for use under the GNU General Public
|
# This free software is licensed for use under the GNU General Public
|
||||||
# License (GPL), see http://www.opensource.org.
|
# License (GPL), see http://www.opensource.org.
|
||||||
# Note that there is NO WARRANTY AT ALL. USE AT YOUR OWN RISK!!
|
# Note that there is NO WARRANTY AT ALL. USE AT YOUR OWN RISK!!
|
||||||
@@ -658,6 +658,16 @@ class HamlibHandlerSerial:
|
|||||||
self.app.pttButton.SetValue(0, True)
|
self.app.pttButton.SetValue(0, True)
|
||||||
else:
|
else:
|
||||||
self.Error(cmd, data)
|
self.Error(cmd, data)
|
||||||
|
def ZZSM(self, cmd, data, length): # return the S-meter value in dB * 2; 0 to 260
|
||||||
|
if length == 0: # 0 to 260 is -140 to -10 dB; S9 == -73 dB == 134; dB = ZZSM / 2 - 140
|
||||||
|
i = round((self.app.hamlib_strength + 67) * 2)
|
||||||
|
if i < 0:
|
||||||
|
i = 0
|
||||||
|
elif i > 260:
|
||||||
|
i = 260
|
||||||
|
self.Write('%s%03d;' % (cmd, i))
|
||||||
|
else:
|
||||||
|
self.Error(cmd, data)
|
||||||
def ZZSP(self, cmd, data, length): # the split status
|
def ZZSP(self, cmd, data, length): # the split status
|
||||||
if length == 0:
|
if length == 0:
|
||||||
if self.app.split_rxtx:
|
if self.app.split_rxtx:
|
||||||
@@ -1151,7 +1161,7 @@ class HamlibHandlerRig2: # Test with telnet localhost 4532
|
|||||||
def GetLevel(self):
|
def GetLevel(self):
|
||||||
name = self.GetParamName()
|
name = self.GetParamName()
|
||||||
if name == '?': # send back supported parameters
|
if name == '?': # send back supported parameters
|
||||||
self.Reply2('AGC AF', 0)
|
self.Reply2('AGC AF STRENGTH', 0)
|
||||||
elif name == 'AGC':
|
elif name == 'AGC':
|
||||||
if self.app.BtnAGC.GetValue():
|
if self.app.BtnAGC.GetValue():
|
||||||
self.Reply2(4, 0)
|
self.Reply2(4, 0)
|
||||||
@@ -1160,6 +1170,9 @@ class HamlibHandlerRig2: # Test with telnet localhost 4532
|
|||||||
elif name == 'AF':
|
elif name == 'AF':
|
||||||
x = self.app.audio_volume # audio_volume is 0 to 1.000
|
x = self.app.audio_volume # audio_volume is 0 to 1.000
|
||||||
self.Reply2("%.5f" % x, 0)
|
self.Reply2("%.5f" % x, 0)
|
||||||
|
elif name == 'STRENGTH':
|
||||||
|
i = round(self.app.hamlib_strength)
|
||||||
|
self.Reply2(i, 0)
|
||||||
else:
|
else:
|
||||||
self.ErrParam()
|
self.ErrParam()
|
||||||
def SetLevel(self):
|
def SetLevel(self):
|
||||||
@@ -1762,6 +1775,12 @@ class GraphDisplay(wx.Window):
|
|||||||
dc.SetTextForeground(conf.color_graph_msg_fg)
|
dc.SetTextForeground(conf.color_graph_msg_fg)
|
||||||
dc.SetBackgroundMode(wx.SOLID)
|
dc.SetBackgroundMode(wx.SOLID)
|
||||||
dc.DrawText(self.display_text, 0, 0)
|
dc.DrawText(self.display_text, 0, 0)
|
||||||
|
if application.tx_inhibit:
|
||||||
|
dc.SetFont(self.font)
|
||||||
|
dc.SetTextBackground(conf.color_graph_msg_bg)
|
||||||
|
dc.SetTextForeground("red")
|
||||||
|
dc.SetBackgroundMode(wx.SOLID)
|
||||||
|
dc.DrawText(" *** Tx Inhibit ***", 0, self.chary * 15 // 10)
|
||||||
def DrawFilter(self, dc):
|
def DrawFilter(self, dc):
|
||||||
dc.SetPen(wx.TRANSPARENT_PEN)
|
dc.SetPen(wx.TRANSPARENT_PEN)
|
||||||
dc.SetLogicalFunction(wx.COPY)
|
dc.SetLogicalFunction(wx.COPY)
|
||||||
@@ -1873,6 +1892,12 @@ class GraphScreen(wx.Window):
|
|||||||
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
|
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
|
||||||
self.Bind(wx.EVT_MOTION, self.OnMotion)
|
self.Bind(wx.EVT_MOTION, self.OnMotion)
|
||||||
self.Bind(wx.EVT_MOUSEWHEEL, self.OnWheel)
|
self.Bind(wx.EVT_MOUSEWHEEL, self.OnWheel)
|
||||||
|
# handle bandplan info
|
||||||
|
self.bandplanWindow = wx.PopupWindow (parent)
|
||||||
|
self.bandplanInfo = wx.TextCtrl(self.bandplanWindow, style=wx.TE_READONLY)
|
||||||
|
self.bandplanInfo.SetFont(wx.Font(conf.status_font_size, wx.FONTFAMILY_SWISS, wx.NORMAL,
|
||||||
|
wx.FONTWEIGHT_NORMAL, False, conf.quisk_typeface))
|
||||||
|
self.bandplanWindow.Hide();
|
||||||
self.MakeDisplay()
|
self.MakeDisplay()
|
||||||
def MakeDisplay(self):
|
def MakeDisplay(self):
|
||||||
self.display = GraphDisplay(self, self.originX, 0, self.graph_width, 5, self.chary)
|
self.display = GraphDisplay(self, self.originX, 0, self.graph_width, 5, self.chary)
|
||||||
@@ -2224,6 +2249,44 @@ class GraphScreen(wx.Window):
|
|||||||
self.ChangeHwFrequency(self.txFreq, self.VFO, 'MouseMotion', event=event, rx_freq=freq2)
|
self.ChangeHwFrequency(self.txFreq, self.VFO, 'MouseMotion', event=event, rx_freq=freq2)
|
||||||
else: # Mouse motion changes the transmit frequency
|
else: # Mouse motion changes the transmit frequency
|
||||||
self.ChangeHwFrequency(self.txFreq + freq, self.VFO, 'MouseMotion', event=event)
|
self.ChangeHwFrequency(self.txFreq + freq, self.VFO, 'MouseMotion', event=event)
|
||||||
|
else:
|
||||||
|
mouse_x, mouse_y = self.GetMousePosition(event)
|
||||||
|
if not self.in_splitter and self.originY <= mouse_y <= self.originY + self.tick and (
|
||||||
|
self.originX <= mouse_x <= self.originX + self.graph_width):
|
||||||
|
#sample_rate = int(self.sample_rate * self.zoom) # Measure the frequency
|
||||||
|
#freq = float(mouse_x - self.x0) * sample_rate / self.data_width + self.zoom_deltaf + self.VFO
|
||||||
|
#freq = int(freq)
|
||||||
|
#color = None
|
||||||
|
#for start_freq, start_color in application.BandPlan:
|
||||||
|
# if start_freq >= freq:
|
||||||
|
# break
|
||||||
|
# color = start_color
|
||||||
|
dc = wx.ClientDC(self) # Read the pixel at the mouse position
|
||||||
|
pixel = dc.GetPixel(mouse_x, mouse_y)
|
||||||
|
pixel = "#%02X%02X%02X" % (pixel[0], pixel[1], pixel[2])
|
||||||
|
txt = application.BandPlanC2T.get(pixel, '')
|
||||||
|
if pixel == "#000000":
|
||||||
|
pass
|
||||||
|
elif txt:
|
||||||
|
self.bandplanInfo.Clear()
|
||||||
|
self.bandplanInfo.write(txt)
|
||||||
|
width, height = self.bandplanInfo.GetTextExtent(txt)
|
||||||
|
width += self.bandplanInfo.GetCharWidth() * 2
|
||||||
|
height += self.bandplanInfo.GetCharHeight() // 2
|
||||||
|
self.bandplanInfo.SetSize(wx.Size(width, height))
|
||||||
|
self.bandplanWindow.SetClientSize((width, height))
|
||||||
|
rect = self.GetScreenRect()
|
||||||
|
if mouse_x > self.originX + self.graph_width * 3 // 4:
|
||||||
|
self.bandplanWindow.Move(mouse_x + rect.GetX() - width, mouse_y + rect.GetY() - height * 12 // 10)
|
||||||
|
else:
|
||||||
|
self.bandplanWindow.Move(mouse_x + rect.GetX(), mouse_y + rect.GetY() - height * 12 // 10)
|
||||||
|
if not self.bandplanWindow.IsShown():
|
||||||
|
self.bandplanWindow.Show()
|
||||||
|
else:
|
||||||
|
if self.bandplanWindow.IsShown():
|
||||||
|
self.bandplanWindow.Hide()
|
||||||
|
elif self.bandplanWindow.IsShown():
|
||||||
|
self.bandplanWindow.Hide()
|
||||||
def OnWheel(self, event):
|
def OnWheel(self, event):
|
||||||
if conf.freq_spacing:
|
if conf.freq_spacing:
|
||||||
wm = conf.freq_spacing
|
wm = conf.freq_spacing
|
||||||
@@ -3497,6 +3560,8 @@ class App(wx.App):
|
|||||||
self.midi_message = []
|
self.midi_message = []
|
||||||
self.idName2Button = {}
|
self.idName2Button = {}
|
||||||
self.midi_handler = None
|
self.midi_handler = None
|
||||||
|
self.tx_inhibit = 0
|
||||||
|
self.old_tx_inhibit = 0
|
||||||
if conf.use_rx_udp == 10: # Hermes UDP protocol
|
if conf.use_rx_udp == 10: # Hermes UDP protocol
|
||||||
self.bandscope_clock = conf.rx_udp_clock
|
self.bandscope_clock = conf.rx_udp_clock
|
||||||
else:
|
else:
|
||||||
@@ -3557,6 +3622,7 @@ class App(wx.App):
|
|||||||
self.smeter_avg_seconds = 1.0 # seconds for S-meter average
|
self.smeter_avg_seconds = 1.0 # seconds for S-meter average
|
||||||
self.smeter_sunits = -87.0
|
self.smeter_sunits = -87.0
|
||||||
self.smeter_usage = "smeter" # specify use of s-meter display
|
self.smeter_usage = "smeter" # specify use of s-meter display
|
||||||
|
self.hamlib_strength = 0.0;
|
||||||
self.timer = time.time() # A seconds clock
|
self.timer = time.time() # A seconds clock
|
||||||
self.heart_time0 = self.timer # timer to call HeartBeat at intervals
|
self.heart_time0 = self.timer # timer to call HeartBeat at intervals
|
||||||
self.save_time0 = self.timer
|
self.save_time0 = self.timer
|
||||||
@@ -3762,7 +3828,8 @@ class App(wx.App):
|
|||||||
# 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.
|
||||||
if conf.window_width > 0:
|
if conf.window_width > 0:
|
||||||
wFrame, h = frame.GetClientSize().Get() # client window width
|
#wFrame, h = frame.GetClientSize().Get() # client window width
|
||||||
|
wFrame = conf.window_width - 15 # Thanks to Nick Abramenko, RA3PKJ
|
||||||
graph = GraphScreen(frame, self.width//2, self.width//2, None) # make a GraphScreen to calculate borders
|
graph = GraphScreen(frame, self.width//2, self.width//2, None) # make a GraphScreen to calculate borders
|
||||||
self.graph_width = wFrame - (graph.width - graph.graph_width) # less graph borders equals actual graph_width
|
self.graph_width = wFrame - (graph.width - graph.graph_width) # less graph borders equals actual graph_width
|
||||||
graph.Destroy()
|
graph.Destroy()
|
||||||
@@ -5034,6 +5101,7 @@ class App(wx.App):
|
|||||||
self.smeter_sunits_time0 = self.timer
|
self.smeter_sunits_time0 = self.timer
|
||||||
s = self.smeter_sunits / 6.0 # change to S units; 6db per S unit
|
s = self.smeter_sunits / 6.0 # change to S units; 6db per S unit
|
||||||
s += Hardware.correct_smeter # S-meter correction for the gain, band, etc.
|
s += Hardware.correct_smeter # S-meter correction for the gain, band, etc.
|
||||||
|
self.hamlib_strength = (s - 9.0) * 6.0 # convert to dB; 0 dB is S9
|
||||||
if s < 0:
|
if s < 0:
|
||||||
s = 0
|
s = 0
|
||||||
if s >= 9.5:
|
if s >= 9.5:
|
||||||
@@ -6369,7 +6437,7 @@ class App(wx.App):
|
|||||||
Hardware.RepeaterOffset(0)
|
Hardware.RepeaterOffset(0)
|
||||||
QS.set_ctcss(0)
|
QS.set_ctcss(0)
|
||||||
QS.tx_hold_state(1)
|
QS.tx_hold_state(1)
|
||||||
if QS.is_key_down(): # Tx indicator
|
if QS.is_key_down() and not self.tx_inhibit: # Tx indicator
|
||||||
if not self.tx_indicator:
|
if not self.tx_indicator:
|
||||||
self.tx_indicator = True
|
self.tx_indicator = True
|
||||||
self.pttButton.Tx.TurnOn(True)
|
self.pttButton.Tx.TurnOn(True)
|
||||||
@@ -6430,6 +6498,8 @@ class App(wx.App):
|
|||||||
self.hot_key_ptt_active = False
|
self.hot_key_ptt_active = False
|
||||||
self.hot_key_ptt_was_down = self.hot_key_ptt_is_down
|
self.hot_key_ptt_was_down = self.hot_key_ptt_is_down
|
||||||
self.hot_key_ptt_pressed = False
|
self.hot_key_ptt_pressed = False
|
||||||
|
if self.tx_inhibit:
|
||||||
|
ptt = False
|
||||||
if ptt is True and not ptt_button_down:
|
if ptt is True and not ptt_button_down:
|
||||||
self.SetPTT(True)
|
self.SetPTT(True)
|
||||||
elif ptt is False and ptt_button_down:
|
elif ptt is False and ptt_button_down:
|
||||||
@@ -6500,6 +6570,16 @@ class App(wx.App):
|
|||||||
if self.timer - self.heart_time0 > 0.10: # call hardware to perform background tasks:
|
if self.timer - self.heart_time0 > 0.10: # call hardware to perform background tasks:
|
||||||
self.heart_time0 = self.timer
|
self.heart_time0 = self.timer
|
||||||
Hardware.HeartBeat()
|
Hardware.HeartBeat()
|
||||||
|
if conf.hermes_lite2_enable:
|
||||||
|
self.tx_inhibit = QS.get_params('quisk_tx_inhibit')
|
||||||
|
else:
|
||||||
|
self.tx_inhibit = 0
|
||||||
|
if self.tx_inhibit != self.old_tx_inhibit:
|
||||||
|
self.old_tx_inhibit = self.tx_inhibit
|
||||||
|
self.graph.display.Refresh()
|
||||||
|
self.waterfall.pane1.display.Refresh()
|
||||||
|
if self.tx_inhibit and self.spotButton.GetValue():
|
||||||
|
self.spotButton.SetValue(0, True)
|
||||||
msg = QS.GetQuiskPrintf()
|
msg = QS.GetQuiskPrintf()
|
||||||
if msg:
|
if msg:
|
||||||
print(msg, end='')
|
print(msg, end='')
|
||||||
|
|||||||
@@ -419,6 +419,8 @@ hermes_PTT_hang_time = 4
|
|||||||
## hermes_antenna_tuner Antenna tuner, text choice
|
## hermes_antenna_tuner Antenna tuner, text choice
|
||||||
# This option only applies to the Hermes Lite 2. Set this to None if you don't have a tuner.
|
# This option only applies to the Hermes Lite 2. Set this to None if you don't have a tuner.
|
||||||
# Set this to "Tune" to control the Icom AH-4 compatible ATU attached to the Hermes Lite 2 end plate.
|
# Set this to "Tune" to control the Icom AH-4 compatible ATU attached to the Hermes Lite 2 end plate.
|
||||||
|
# Note that this option only applies to the HL2 end plate, not the IO board.
|
||||||
|
# A tuner attached to the IO board is controlled from a button on the last line of the screen.
|
||||||
# Then when the Spot button is pressed with a positive power, a tune request is sent to the ATU.
|
# Then when the Spot button is pressed with a positive power, a tune request is sent to the ATU.
|
||||||
# If the Spot button is pressed with a zero power level, the tuner is set to bypass mode.
|
# If the Spot button is pressed with a zero power level, the tuner is set to bypass mode.
|
||||||
# Changes are immediate (no need to restart).
|
# Changes are immediate (no need to restart).
|
||||||
@@ -471,6 +473,13 @@ hermes_iob_rxin = 'J10 available'
|
|||||||
#hermes_iob_rxin = 'HL2 Rx to J9'
|
#hermes_iob_rxin = 'HL2 Rx to J9'
|
||||||
#hermes_iob_rxin = 'Use J9 and J10'
|
#hermes_iob_rxin = 'Use J9 and J10'
|
||||||
|
|
||||||
|
## hermes_lite2_enable Hermes Lite2 protocol, boolean
|
||||||
|
# This turns on some of the protocol extensions for the Hermes Lite2 that are not part
|
||||||
|
# of the official Hermes Protocol 1. Currently this only enables Tx Inhibit (CN8).
|
||||||
|
# Changes are immediate (no need to restart).
|
||||||
|
hermes_lite2_enable = True
|
||||||
|
#hermes_lite2_enable = False
|
||||||
|
|
||||||
|
|
||||||
# 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 = {}
|
||||||
@@ -1646,6 +1655,15 @@ start_ssb_delay = 100
|
|||||||
# Changes are immediate (no need to restart).
|
# Changes are immediate (no need to restart).
|
||||||
maximum_tx_secs = 0
|
maximum_tx_secs = 0
|
||||||
|
|
||||||
|
## TxRxSilenceMsec Tx-Rx silence msec, integer
|
||||||
|
# When changing from transmit to receive a radio may receive either noise or the end of the transmission.
|
||||||
|
# This may be returned as received audio, and can be heard as a loud pop.
|
||||||
|
# This parameter plays silence for the specified number of milliseconds when changing from transmit to receive.
|
||||||
|
# Make it long enough to zero out the pop, but not too much longer.
|
||||||
|
# It is ignored when in full duplex mode.
|
||||||
|
# Changes are immediate (no need to restart).
|
||||||
|
TxRxSilenceMsec = 50
|
||||||
|
|
||||||
## keyupDelay Keyup delay msecs, integer
|
## keyupDelay Keyup delay msecs, integer
|
||||||
# This is the key hang time for semi-breakin CW. It is the time in milliseconds
|
# This is the key hang time for semi-breakin CW. It is the time in milliseconds
|
||||||
# from the last CW key release until changing to receive.
|
# from the last CW key release until changing to receive.
|
||||||
@@ -2085,6 +2103,26 @@ RxOnly = '#AAAAAA'
|
|||||||
# Colors start at the indicated frequency and continue until the
|
# Colors start at the indicated frequency and continue until the
|
||||||
# next frequency. The special color "None" turns off color.
|
# next frequency. The special color "None" turns off color.
|
||||||
#
|
#
|
||||||
|
BandPlanColors = [ # Display name and corresponding color
|
||||||
|
['CW, General', CW],
|
||||||
|
['CW, Extra', eCW],
|
||||||
|
['Phone, General', Phone],
|
||||||
|
['Phone, Extra', ePhone],
|
||||||
|
['AM', AM],
|
||||||
|
['Data', Data],
|
||||||
|
['DxData', DxData],
|
||||||
|
['RTTY', RTTY],
|
||||||
|
['SSTV', SSTV],
|
||||||
|
['Packet', Packet],
|
||||||
|
['Beacons', Beacons],
|
||||||
|
['Satellite', Satellite],
|
||||||
|
['Repeater out', Repeater],
|
||||||
|
['Repeater in', RepInput],
|
||||||
|
['Simplex', Simplex],
|
||||||
|
['Rx only', RxOnly],
|
||||||
|
['Special', Special],
|
||||||
|
['Other', Other]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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.29'
|
Version = '4.2.34'
|
||||||
|
|
||||||
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)
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ char * sound_format_names[4] = {"Int32", "Int16", "Float32", "Int24"} ;
|
|||||||
static struct wav_file file_rec_audio, file_rec_samples, file_rec_mic;
|
static struct wav_file file_rec_audio, file_rec_samples, file_rec_mic;
|
||||||
static int close_file_rec;
|
static int close_file_rec;
|
||||||
|
|
||||||
static double digital_output_level = 0.7;
|
double digital_output_level = 0.7;
|
||||||
static int dc_remove_bw=100; // bandwidth of DC removal filter
|
static int dc_remove_bw=100; // bandwidth of DC removal filter
|
||||||
|
|
||||||
static ty_sample_start pt_sample_start;
|
static ty_sample_start pt_sample_start;
|
||||||
|
|||||||
+30
-10
@@ -495,8 +495,37 @@ static snd_pcm_format_t check_formats(struct sound_dev * dev, snd_pcm_hw_params_
|
|||||||
{
|
{
|
||||||
snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN;
|
snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN;
|
||||||
dev->sample_bytes = 0;
|
dev->sample_bytes = 0;
|
||||||
|
#if 0
|
||||||
|
char * card_name;
|
||||||
|
int card;
|
||||||
|
snd_pcm_info_t * pcm_info;
|
||||||
|
printf("driver %s\n", snd_ctl_card_info_get_driver(info));
|
||||||
|
int loopback = 0;
|
||||||
|
if (snd_pcm_info_malloc(&pcm_info) == 0) {
|
||||||
|
if (snd_pcm_info (dev->handle, pcm_info) == 0) {
|
||||||
|
card = snd_pcm_info_get_card (pcm_info);
|
||||||
|
if (card >= 0) {
|
||||||
|
if (snd_card_get_name(card, &card_name) == 0) {
|
||||||
|
if (strcmp(card_name, "Loopback") == 0)
|
||||||
|
loopback = 1;
|
||||||
|
printf("name %s\n", card_name);
|
||||||
|
free(card_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
snd_pcm_info_free(pcm_info);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
strMcpy (dev->msg1, "Available formats: ", QUISK_SC_SIZE);
|
strMcpy (dev->msg1, "Available formats: ", QUISK_SC_SIZE);
|
||||||
|
if (snd_pcm_hw_params_test_format (dev->handle, hware, SND_PCM_FORMAT_S16) == 0) {
|
||||||
|
if (!dev->sample_bytes) {
|
||||||
|
strncat(dev->msg1, "*", QUISK_SC_SIZE);
|
||||||
|
dev->sample_bytes = 2;
|
||||||
|
dev->sound_format = Int16;
|
||||||
|
format = SND_PCM_FORMAT_S16;
|
||||||
|
}
|
||||||
|
strncat(dev->msg1, "S16 ", QUISK_SC_SIZE);
|
||||||
|
}
|
||||||
if (snd_pcm_hw_params_test_format (dev->handle, hware, SND_PCM_FORMAT_S32) == 0) {
|
if (snd_pcm_hw_params_test_format (dev->handle, hware, SND_PCM_FORMAT_S32) == 0) {
|
||||||
if (!dev->sample_bytes) {
|
if (!dev->sample_bytes) {
|
||||||
strncat(dev->msg1, "*", QUISK_SC_SIZE);
|
strncat(dev->msg1, "*", QUISK_SC_SIZE);
|
||||||
@@ -515,15 +544,6 @@ static snd_pcm_format_t check_formats(struct sound_dev * dev, snd_pcm_hw_params_
|
|||||||
if (snd_pcm_hw_params_test_format (dev->handle, hware, SND_PCM_FORMAT_U24) == 0) {
|
if (snd_pcm_hw_params_test_format (dev->handle, hware, SND_PCM_FORMAT_U24) == 0) {
|
||||||
strncat(dev->msg1, "U24 ", QUISK_SC_SIZE);
|
strncat(dev->msg1, "U24 ", QUISK_SC_SIZE);
|
||||||
}
|
}
|
||||||
if (snd_pcm_hw_params_test_format (dev->handle, hware, SND_PCM_FORMAT_S16) == 0) {
|
|
||||||
if (!dev->sample_bytes) {
|
|
||||||
strncat(dev->msg1, "*", QUISK_SC_SIZE);
|
|
||||||
dev->sample_bytes = 2;
|
|
||||||
dev->sound_format = Int16;
|
|
||||||
format = SND_PCM_FORMAT_S16;
|
|
||||||
}
|
|
||||||
strncat(dev->msg1, "S16 ", QUISK_SC_SIZE);
|
|
||||||
}
|
|
||||||
if (snd_pcm_hw_params_test_format (dev->handle, hware, SND_PCM_FORMAT_S24_3LE) == 0) {
|
if (snd_pcm_hw_params_test_format (dev->handle, hware, SND_PCM_FORMAT_S24_3LE) == 0) {
|
||||||
if (!dev->sample_bytes) {
|
if (!dev->sample_bytes) {
|
||||||
strncat(dev->msg1, "*", QUISK_SC_SIZE);
|
strncat(dev->msg1, "*", QUISK_SC_SIZE);
|
||||||
|
|||||||
Reference in New Issue
Block a user