Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31ecbce146 | ||
|
|
a1343c1264 | ||
|
|
71146c9eaf | ||
|
|
814e4ce08c |
@@ -1,3 +1,35 @@
|
||||
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
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
#Quisk version 4.2.30
|
||||
#Quisk version 4.2.34
|
||||
from .quisk import main
|
||||
|
||||
+21
-27
@@ -170,12 +170,16 @@ class Configuration:
|
||||
radio_dict["Hermes_BandDictTx"] = {}
|
||||
def UpdateGlobals(self):
|
||||
self.RadioName = Settings[1]
|
||||
application.BandPlanC2T = {}
|
||||
if self.RadioName == "ConfigFileRadio":
|
||||
application.BandPlan = conf.BandPlan
|
||||
for mode, color in conf.BandPlanColors:
|
||||
application.BandPlanC2T[color] = mode
|
||||
elif "BandPlanColors" in Settings[4] and "BandPlan" in Settings[4]:
|
||||
mode_dict = {"End":None}
|
||||
for mode, color in Settings[4]["BandPlanColors"]:
|
||||
mode_dict[mode] = color
|
||||
application.BandPlanC2T[color] = mode
|
||||
plan = []
|
||||
for freq, mode in Settings[4]["BandPlan"]:
|
||||
freq = int(float(freq) * 1E6 + 0.1)
|
||||
@@ -188,6 +192,8 @@ class Configuration:
|
||||
application.BandPlan = plan
|
||||
else:
|
||||
application.BandPlan = conf.BandPlan
|
||||
for mode, color in conf.BandPlanColors:
|
||||
application.BandPlanC2T[color] = mode
|
||||
if "MidiNoteDict" not in Settings[4]:
|
||||
Settings[4]["MidiNoteDict"] = {}
|
||||
self.settings_changed = True
|
||||
@@ -1484,7 +1490,7 @@ class MidiKnob(QuiskControl):
|
||||
self.menu = wx.Menu()
|
||||
for name in application.midiControls:
|
||||
ctrl, func = application.midiControls[name]
|
||||
if not ctrl or not func:
|
||||
if name != "Tune" and (not ctrl or not func):
|
||||
continue
|
||||
item = self.menu.Append(-1, name)
|
||||
self.Bind(wx.EVT_MENU, self.OnMenu, item)
|
||||
@@ -1519,7 +1525,7 @@ class MidiJogWheel(QuiskControl):
|
||||
controls = wx.Menu()
|
||||
for name in application.midiControls:
|
||||
ctrl, func = application.midiControls[name]
|
||||
if not ctrl or not func:
|
||||
if name != "Tune" and (not ctrl or not func):
|
||||
continue
|
||||
item = controls.Append(-1, name)
|
||||
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 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',
|
||||
'hot_key_ptt1', 'hot_key_ptt2', 'midi_ptt_toggle', 'TxRxSilenceMsec'):
|
||||
'hot_key_ptt1', 'hot_key_ptt2', 'midi_ptt_toggle', 'TxRxSilenceMsec', 'hermes_lite2_enable'):
|
||||
setattr(conf, name, x)
|
||||
application.ImmediateChange(name)
|
||||
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_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
|
||||
(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, "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, "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."),
|
||||
(1, "Digital Rx0 Output", "This is the main receiver Rx0 audio going to a digital mode program."),
|
||||
(0, "Digital Tx0 Input", hTx0),
|
||||
(1, "Digital Rx0 Output", hRx0),
|
||||
(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 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]:
|
||||
colors = Settings[4]["BandPlanColors"]
|
||||
else:
|
||||
Get = conf.__dict__.get # Get colors from the user's config file, if any.
|
||||
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)]
|
||||
]
|
||||
colors = conf.BandPlanColors
|
||||
self.modes = []
|
||||
self.color_dict = {None:"End"}
|
||||
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])
|
||||
Settings[4]["BandPlan"] = freq_mode
|
||||
application.BandPlan = plan
|
||||
application.BandPlanC2T = {}
|
||||
for mode, color in mode_color:
|
||||
application.BandPlanC2T[color] = mode
|
||||
local_conf.settings_changed = True
|
||||
self.EndModal(wx.ID_OK)
|
||||
def OnCancel(self, event):
|
||||
|
||||
@@ -1470,22 +1470,29 @@ remember the settings.
|
||||
<br>
|
||||
|
||||
<br>
|
||||
If you don't have PulseAudio or don't want to use it, you can use the ALSA loopback device.
|
||||
The ALSA loopback device works the same way as the Windows VAC. First
|
||||
create the loopback device with the command "modprobe snd-aloop" (you
|
||||
will need to be root). You can create the loopback device
|
||||
when the system starts, but the way to do that depends on your version of
|
||||
Linux. I added snd-aloop to /etc/modules. You could put the modprobe command in /etc/rc.local instead.
|
||||
If your digital program only uses Alsa devices or you don't want to use PulseAudio,
|
||||
you can use the ALSA loopback device.
|
||||
It works the same way as the Windows VAC. First create the loopback device with this command:
|
||||
<pre>
|
||||
sudo modprobe snd-aloop index=19
|
||||
</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
|
||||
print out your sound cards, and you should see a "Loopback" card
|
||||
listed. The cards are also shown on the Quisk Sound
|
||||
screen. The Loopback card has one side that connects to Quisk and
|
||||
print out your sound cards, and you should see a "Loopback" card listed.
|
||||
The Loopback card has one side that connects to Quisk and
|
||||
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
|
||||
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
|
||||
output to "Loopback,1".
|
||||
output to the Loopback at hw:19,1.
|
||||
Your audio is now connected and you
|
||||
should be able to receive digital signals. Be sure to test your
|
||||
transmit signal off the air. You may need to reduce power to
|
||||
|
||||
+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)
|
||||
{ // 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;
|
||||
double dsample, dtmp, magn;
|
||||
complex double csample;
|
||||
@@ -423,9 +423,10 @@ static int tx_filter(complex double * filtered, int count)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
mic_interp = MIC_OUT_RATE / sample_rate;
|
||||
// check size of dsamples[] and csamples[] buffer
|
||||
if (count > samples_size) {
|
||||
samples_size = count * 2;
|
||||
samples_size = count * 2 * mic_interp;
|
||||
if (dsamples)
|
||||
free(dsamples);
|
||||
if (csamples)
|
||||
@@ -541,8 +542,8 @@ static int tx_filter(complex double * filtered, int count)
|
||||
// remove clipping distortion
|
||||
count = quisk_cDecimate(csamples, count, &cfiltAudio3, 1);
|
||||
// Interpolate up to 48000
|
||||
if (MIC_OUT_RATE != sample_rate)
|
||||
count = quisk_cInterpolate(csamples, count, &cfiltInterp, MIC_OUT_RATE / sample_rate);
|
||||
if (mic_interp != 1)
|
||||
count = quisk_cInterpolate(csamples, count, &cfiltInterp, mic_interp);
|
||||
// convert back to 16 bits
|
||||
for (i = 0; i < count; i++) {
|
||||
filtered[i] = csamples[i] * CLIP16;
|
||||
@@ -573,8 +574,8 @@ static int tx_filter(complex double * filtered, int count)
|
||||
// remove clipping distortion
|
||||
count = quisk_dFilter(dsamples, count, &dfiltAudio3);
|
||||
// Interpolate up to 48000
|
||||
if (MIC_OUT_RATE != sample_rate)
|
||||
count = quisk_dInterpolate(dsamples, count, &dfiltInterp, MIC_OUT_RATE / sample_rate);
|
||||
if (mic_interp != 1)
|
||||
count = quisk_dInterpolate(dsamples, count, &dfiltInterp, mic_interp);
|
||||
// convert back to 16 bits
|
||||
for (i = 0; i < count; i++) {
|
||||
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 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_fft_width; // size of FFT samples
|
||||
@@ -2741,7 +2742,7 @@ int quisk_process_samples(complex double * cSamples, int nSamples)
|
||||
multirx_cSamples[0][i] = dsamples2[i] + I * dsamples2[i];
|
||||
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
|
||||
@@ -3156,6 +3157,8 @@ static PyObject * get_params(PyObject * self, PyObject * args)
|
||||
return PyInt_FromLong(quisk_serial_ptt);
|
||||
if (strcmp(name, "hl2_txbuf_errors") == 0)
|
||||
return PyInt_FromLong(hl2_txbuf_errors);
|
||||
if (strcmp(name, "quisk_tx_inhibit") == 0)
|
||||
return PyInt_FromLong((long)quisk_tx_inhibit);
|
||||
Py_INCREF (Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
@@ -3759,6 +3762,7 @@ static int read_rx_udp10(complex double * samp) // Read samples from UDP using t
|
||||
//code_version = quisk_hermes_to_pc[3];
|
||||
if ((quisk_hermes_to_pc[0] & 0x01) != 0) // C1
|
||||
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
|
||||
quisk_hardware_cwkey = (buf[start] & 0x04) >> 2; // C0 bit two is CW key state
|
||||
switch (hl2_txbuf_state) {
|
||||
@@ -3870,6 +3874,10 @@ static int read_rx_udp17(complex double * cSamples0) // Read samples from UDP
|
||||
fft_data * ptFFT;
|
||||
fd_set fds;
|
||||
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
|
||||
|
||||
if ( ! rx_udp_gain_correct) { // correct for second stage CIC decimation JIM JIM
|
||||
@@ -3975,6 +3983,16 @@ static int read_rx_udp17(complex double * cSamples0) // Read samples from UDP
|
||||
if (xr & 0x100) { // channel 1
|
||||
if (quisk_invert_spectrum) // Invert spectrum
|
||||
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.
|
||||
ptFFT = fft_data_array + fft_data_index;
|
||||
if ( ! (xi & 0x100)) { // zero marker for start of first block
|
||||
|
||||
@@ -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 struct sound_dev * quiskPlaybackDevices[]; // array of Playback sound devices
|
||||
extern int quisk_close_file_play;
|
||||
extern double digital_output_level;
|
||||
|
||||
extern PyObject * quisk_set_spot_level(PyObject * , PyObject *);
|
||||
extern PyObject * quisk_get_tx_filter(PyObject * , PyObject *);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/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
|
||||
# License (GPL), see http://www.opensource.org.
|
||||
# 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)
|
||||
else:
|
||||
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
|
||||
if length == 0:
|
||||
if self.app.split_rxtx:
|
||||
@@ -1151,7 +1161,7 @@ class HamlibHandlerRig2: # Test with telnet localhost 4532
|
||||
def GetLevel(self):
|
||||
name = self.GetParamName()
|
||||
if name == '?': # send back supported parameters
|
||||
self.Reply2('AGC AF', 0)
|
||||
self.Reply2('AGC AF STRENGTH', 0)
|
||||
elif name == 'AGC':
|
||||
if self.app.BtnAGC.GetValue():
|
||||
self.Reply2(4, 0)
|
||||
@@ -1160,6 +1170,9 @@ class HamlibHandlerRig2: # Test with telnet localhost 4532
|
||||
elif name == 'AF':
|
||||
x = self.app.audio_volume # audio_volume is 0 to 1.000
|
||||
self.Reply2("%.5f" % x, 0)
|
||||
elif name == 'STRENGTH':
|
||||
i = round(self.app.hamlib_strength)
|
||||
self.Reply2(i, 0)
|
||||
else:
|
||||
self.ErrParam()
|
||||
def SetLevel(self):
|
||||
@@ -1762,6 +1775,12 @@ class GraphDisplay(wx.Window):
|
||||
dc.SetTextForeground(conf.color_graph_msg_fg)
|
||||
dc.SetBackgroundMode(wx.SOLID)
|
||||
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):
|
||||
dc.SetPen(wx.TRANSPARENT_PEN)
|
||||
dc.SetLogicalFunction(wx.COPY)
|
||||
@@ -1873,6 +1892,12 @@ class GraphScreen(wx.Window):
|
||||
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
|
||||
self.Bind(wx.EVT_MOTION, self.OnMotion)
|
||||
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()
|
||||
def MakeDisplay(self):
|
||||
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)
|
||||
else: # Mouse motion changes the transmit frequency
|
||||
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):
|
||||
if conf.freq_spacing:
|
||||
wm = conf.freq_spacing
|
||||
@@ -3497,6 +3560,8 @@ class App(wx.App):
|
||||
self.midi_message = []
|
||||
self.idName2Button = {}
|
||||
self.midi_handler = None
|
||||
self.tx_inhibit = 0
|
||||
self.old_tx_inhibit = 0
|
||||
if conf.use_rx_udp == 10: # Hermes UDP protocol
|
||||
self.bandscope_clock = conf.rx_udp_clock
|
||||
else:
|
||||
@@ -3557,6 +3622,7 @@ class App(wx.App):
|
||||
self.smeter_avg_seconds = 1.0 # seconds for S-meter average
|
||||
self.smeter_sunits = -87.0
|
||||
self.smeter_usage = "smeter" # specify use of s-meter display
|
||||
self.hamlib_strength = 0.0;
|
||||
self.timer = time.time() # A seconds clock
|
||||
self.heart_time0 = self.timer # timer to call HeartBeat at intervals
|
||||
self.save_time0 = self.timer
|
||||
@@ -5035,6 +5101,7 @@ class App(wx.App):
|
||||
self.smeter_sunits_time0 = self.timer
|
||||
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.
|
||||
self.hamlib_strength = (s - 9.0) * 6.0 # convert to dB; 0 dB is S9
|
||||
if s < 0:
|
||||
s = 0
|
||||
if s >= 9.5:
|
||||
@@ -6370,7 +6437,7 @@ class App(wx.App):
|
||||
Hardware.RepeaterOffset(0)
|
||||
QS.set_ctcss(0)
|
||||
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:
|
||||
self.tx_indicator = True
|
||||
self.pttButton.Tx.TurnOn(True)
|
||||
@@ -6431,6 +6498,8 @@ class App(wx.App):
|
||||
self.hot_key_ptt_active = False
|
||||
self.hot_key_ptt_was_down = self.hot_key_ptt_is_down
|
||||
self.hot_key_ptt_pressed = False
|
||||
if self.tx_inhibit:
|
||||
ptt = False
|
||||
if ptt is True and not ptt_button_down:
|
||||
self.SetPTT(True)
|
||||
elif ptt is False and ptt_button_down:
|
||||
@@ -6501,6 +6570,16 @@ class App(wx.App):
|
||||
if self.timer - self.heart_time0 > 0.10: # call hardware to perform background tasks:
|
||||
self.heart_time0 = self.timer
|
||||
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()
|
||||
if msg:
|
||||
print(msg, end='')
|
||||
|
||||
@@ -473,6 +473,13 @@ hermes_iob_rxin = 'J10 available'
|
||||
#hermes_iob_rxin = 'HL2 Rx to J9'
|
||||
#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.
|
||||
power_meter_std_calibrations = {}
|
||||
@@ -2096,6 +2103,26 @@ RxOnly = '#AAAAAA'
|
||||
# Colors start at the indicated frequency and continue until the
|
||||
# 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
|
||||
# the version will be written to __init__.py and read by quisk.py.
|
||||
|
||||
Version = '4.2.30'
|
||||
Version = '4.2.34'
|
||||
|
||||
fp = open("__init__.py", "w") # write title string
|
||||
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 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 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;
|
||||
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);
|
||||
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 (!dev->sample_bytes) {
|
||||
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) {
|
||||
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 (!dev->sample_bytes) {
|
||||
strncat(dev->msg1, "*", QUISK_SC_SIZE);
|
||||
|
||||
Reference in New Issue
Block a user