Merge branch 'master' into opus

merge-requests/6/head
Phil Taylor 2021-07-29 16:18:59 +01:00
commit bc0d69ffb5
27 zmienionych plików z 2353 dodań i 227 usunięć

210
CHANGELOG
Wyświetl plik

@ -1,8 +1,218 @@
# CHANGELOG
- 20210724
small changes to INSTAll.md and addition of mint 20.2/openSUSE 15.3
- 20210720
Clear out meter values when type is switched.
Allow user to turn off power-down confirmation msgbox
- 20210719
wfview now uses the meter's own balistics (average and peak code). This
makes it very easy to meter any parameter 0-255. Meter Type "meterNone"
or other will display data in "raw" format.
- 20210718
Added center tuning for IC-R8600, partially moved meter balistics
(average and peak) to the meter class.
Quick debug for the metering queue, just in case.
20210717
Preliminary secondary meter support. See Settings tab for selection.
Some scales incomplete.
Added SWR and ALC scales to the meter.
Fix error in scale of power meter
- 20210716
Power meter for transmit. Much work remains on this meter alone.
Get antenna status on start-up and slow poll for it.
Add RX antenna selection for rigs that support it
- 20210714
Preferences added for Anti-Alias and Interpolate.
- 20210713
Added waterfall display options: anti-alias and interpolate. Not in
preferences yet. Debug button enables wf pan and zoom.
- 20210711
Allow user to select whether to confirm exit or not
- 20210709
Reset PTT timer for control-R keystroke.
Added a fix to keep the local frequency in-sync with any recent commands
sent to the radio.
Added more support for the IC-7600 in rigCaps.
Added time, date, and UTC offset commands. Currently initiated by the
debug button. There seems to be a bug in the 7300 where the UTC offset
has one hour subtracted, ie, -7 HRS becomes -8 HRS. The hex command
appears to be sent correctly.
- 20210708
Delete oldest entry from UDP buffer before adding new one.
If pty connected s/w sends a disable transceive command, dont' send any transceive commands to it
New about box!
- 20210706
Local af gain now has anti-log audio pot taper.
Only start audio when stream is ready
- 20210705
Added transceiver adjustment window show code, for the debug button only
currently.
Added window title text change to show radio model. Needs to be checked
cross-platform. On Linux Mint, displays: "IC-7300 -- wfview"
Applying setup.volume within audio handler if the audio handled is an
output. Added this to the init function.
waterfall theme is now saved.
Added local af gain and wf length to the preferences.
- 20210702
fixed small error where the tx latency was not copied in the UI
- 20210626
Merge branch 'sequence' of gitlab.com:eliggett/wfview into sequence
Duplicate of existing command.
Remove unnecessary escape sequence
Fix for fix of missing __PRETTY_FUNCTION__
Add __PRETTY_FUNCTION__ for compilers that don't have it.
- 20210625
Mode changes from the combo box now use the que. There are still other
methods to change mode which will transition shortly.
Faster PTT
Added PTT to the queue.
Added unique priority insertion methods.
Changed how commands with parameter data are added.
Initial queued "set" command commit. Only the frequency set command is
used so far, and only for the "Frequency" tab and the tuning knob.
- 20210624
Quick hack for WFM forcing FIL1 always
- 20210621
Added polling button
Moving to std::deque (double-ended que).
- 20210620
IC-R8600 span is now received into the UI correctly.
New unified outgoing command queue. Tested on IC-9700 and IC-718 (to
remote wfview server). CPU usage seems higher but please check your
system.
Timing seems to be acceptable but could probably use some tweaks.
S-meter polling is 25ms for fast radios, and slower rates for slower
radios. Half-duplex serial radios receive 3x slower polling to make room
for replies.
For Freq, Mode, etc "regular" constant polling (new feature):
IC-9700 polling is 5 per second, IC-718 is 1-2 per second.
Just helps keep the UI in sync with changes taking place at the rig. The
polling is slow enough that it doesn't impact anything. But quick enough
that it catches discrepencies pretty quickly.
- 20210619
Added a few more slider things
whatsnew: improved IC-R8600
- 20210618
Additional support for the IC-R8600, including wider scope spans.
Minor change to remove some old debug code that snuck in.
If no rig caps, then don't mess with the window!
Added full duplex comms parameter to rigCaps. We assume half-duplex
until we receive a reply to rigID.
Fixed accidental s-meter timing parameter change.
- 20210617
Radios without spectrum do not show spectrum, and, the window properly
resizes for those controls. Also, a new key command, control-shift-d has
been added to run debug functions from any tab in the program.
- 20210615
Additional code to hide/show spectrum and correcting an issue with the
rig name not populating for non-spectrum radios.
Dynamic show/hide spectrum for rigs without this feature.
Additional data corruption checking.
- 20210614
Changed collision detection code so that we can more easily see what
message was missed.
Added collision detection for serial commands. Collisions are aparently
frequent for true 1-wire CI-V radios.
We now calculate polling rates immediately upon receiveCommReady for
serial connections. For network connections, we assume sane values and
modify once we receive the baud rate from the server.
Add Neon (ARM) support to resampler
Revert to using resampler directory rather than opus-tools submodule
- 20210612
Add tooltip showing percentage of TX power when slider is moved
- 20210611
adding a second path/way for the qcustomplot link if the first fails
Update udpserver.cpp
Use global watchdog rather than per-connection

Wyświetl plik

@ -75,7 +75,7 @@ we need to add packages to be able to build the stuff.
- sudo zypper in --type pattern devel_basis
- sudo zypper in libQt5Widgets-devel libqt5-qtbase-common-devel libqt5-qtserialport-devel libQt5SerialPort5 qcustomplot-devel libqcustomplot2 libQt5PrintSupport-devel libqt5-qtmultimedia-devel
now get and install qt5:
optional (mainly for development specifics): get and install qt5:
- wget http://download.qt.io/official_releases/online_installers/qt-unified-linux-x64-online.run
- chmod +x qt-unified-linux-x64-online.run

Wyświetl plik

@ -1,4 +1,4 @@
# How to install wfview without building yourself on selected linux versions
# How to install wfview without building yourself on selected linux versions
@ -22,10 +22,12 @@ Debian 11 (Debian 10 is outdated)
Fedora 33
Fedora 34
mint 20.1 (and up?)
openSUSE 15.x
openSUSE Tumbleweed
openSUSE 15.2
openSUSE 15.3 (see notes at the end)
openSUSE Tumbleweed(s)
SLES 15.x
Ubuntu 20.04.2 and up (?)
Ubuntu 20.04.2
mint 20.2 (see notes at the end)
~~~
@ -69,12 +71,37 @@ note: if the above symlink fails, use the following line to fix the library link
sudo ln -s /lib/x86_64-linux-gnu/libqcustomplot.so.2.0.1 /lib/x86_64-linux-gnu/libqcustomplot.so.2
~~~
### openSUSE/Tumbleweed/SLES:
### Mint 20.2
~~~
SEE THE NOTES AT THE END. You need wfview153 binary here
sudo apt install libqcustomplot2.0 libqt5multimedia5 libqt5serialport5
sudo ln -s /usr/lib64/libqcustomplot-qt5.so.2 /usr/lib64/libqcustomplot.so.2
wfview
note: if the above symlink fails, use the following line to fix the library link:
sudo ln -s /lib/x86_64-linux-gnu/libqcustomplot.so.2.0.1 /lib/x86_64-linux-gnu/libqcustomplot.so.2
~~~
### openSUSE/Tumbleweed/SLES based on 15.2:
~~~
sudo zypper in libqcustomplot2 libQt5SerialPort5
wfview
~~~
### openSUSE/Tumbleweed/SLES based on 15.3:
~~~
SEE THE NOTES AT THE END. You need wfview153 here
sudo zypper in libqcustomplot2 libQt5SerialPort5
wfview
~~~
### UBUNTU:
~~~
sudo apt install libqcustomplot2.0 libqt5multimedia5 libqt5serialport5
@ -89,4 +116,18 @@ sudo ln -s /lib/x86_64-linux-gnu/libqcustomplot.so.2.0.1 /lib/x86_64-linux-gnu/l
### notes:
~~~
Some newer versions of mint. ubuntu, openSUSE have different kernels and such which cause wfview to segfault.
For these cases we created two binaries: one for current systems ("wfview") and one for the new systems ("wfview153")
So if you encounter a SEGFAULT at start:
go in to the dist directory, rename wfview to wfvie152; rename wfview153 to wfview and re-execute the install.sh
script
~~~

Wyświetl plik

@ -1,7 +1,7 @@
The following highlights are in this dot-release:
added IC7700
added IC7700, 718, 7100. (more testing needed)
fixes and improvements to audio
ability to choose between rtaudio and qtmultimedia (default) as compile time option
fixes and lots of improvements at the usb-server end
@ -12,3 +12,5 @@ The following highlights are in this dot-release:
wf display disappears when there is no wf capable rig
IC R8600 support improved
for older rigs added a polling timing box to keep stuff keeping smooth
Local af gain now has anti-log audio pot taper.

111
aboutbox.cpp 100644
Wyświetl plik

@ -0,0 +1,111 @@
#include "aboutbox.h"
#include "ui_aboutbox.h"
aboutbox::aboutbox(QWidget *parent) :
QWidget(parent),
ui(new Ui::aboutbox)
{
ui->setupUi(this);
setWindowTitle("About wfview");
setWindowIcon(QIcon(":resources/wfview.png"));
ui->logoBtn->setIcon(QIcon(":resources/wfview.png"));
ui->logoBtn->setStyleSheet("Text-align:left");
ui->topText->setText("wfview version 1.1");
QString head = QString("<html><head></head><body>");
QString copyright = QString("Copyright 2017-2021 Elliott H. Liggett, W6EL. All rights reserved. wfview source code is <a href=\"https://gitlab.com/eliggett/wfview/-/blob/master/LICENSE\">licensed</a> under the GNU GPLv3.");
QString nacode = QString("<br/><br/>Networking, audio, rigctl server, and much more written by Phil Taylor, M0VSE");
QString doctest = QString("<br/><br/>Testing, documentation, bug fixes, and development mentorship from<br/>Roeland Jansen, PA3MET, and Jim Nijkamp, PA8E.");
QString ssCredit = QString("<br/><br/>Stylesheet <a href=\"https://github.com/ColinDuquesnoy/QDarkStyleSheet/tree/master/qdarkstyle\" style=\"color: cyan;\">qdarkstyle</a> used under MIT license, stored in /usr/share/wfview/stylesheets/.");
QString website = QString("<br/><br/>Please visit <a href=\"https://wfview.org/\" style=\"color: cyan;\">https://wfview.org/</a> for the latest information.");
QString docs = QString("<br/><br/>Be sure to check the <a href=\"https://wfview.org/wfview-user-manual/\" style=\"color: cyan;\">User Manual</a> and <a href=\"https://forum.wfview.org/\" style=\"color: cyan;\">the Forum</a> if you have any questions.");
QString support = QString("<br/><br/>For support, please visit <a href=\"https://forum.wfview.org/\">the official wfview support forum</a>.");
QString gitcodelink = QString("<a href=\"https://gitlab.com/eliggett/wfview/-/tree/%1\" style=\"color: cyan;\">").arg(GITSHORT);
QString contact = QString("<br/>email W6EL: kilocharlie8@gmail.com");
QString buildInfo = QString("<br/><br/>Build " + gitcodelink + QString(GITSHORT) + "</a> on " + QString(__DATE__) + " at " + __TIME__ + " by " + UNAME + "@" + HOST);
QString end = QString("</body></html>");
// Short credit strings:
QString rsCredit = QString("<br/><br/><a href=\"https://www.speex.org/\" style=\"color: cyan;\">Speex</a> Resample library Copyright 2003-2008 Jean-Marc Valin");
#if defined(RTAUDIO)
QString rtaudiocredit = QString("<br/><br/>RT Audio, from <a href=\"https://www.music.mcgill.ca/~gary/rtaudio/index.html\">Gary P. Scavone</a>");
#endif
#if defined(PORTAUDIO)
QString portaudiocredit = QString("<br/><br/>Port Audio, from <a href=\"http://portaudio.com\">The Port Audio Community</a>");
#endif
QString qcpcredit = QString("<br/><br/>The waterfall and spectrum plot graphics use QCustomPlot, from <a href=\"https://www.qcustomplot.com/\">Emanuel Eichhammer</a>");
QString qtcredit = QString("<br/><br/>This copy of wfview was built against Qt version %1").arg(QT_VERSION_STR);
// Acknowledgement:
QString wfviewcommunityack = QString("<br/><br/>The developers of wfview wish to thank the many contributions from the wfview community at-large, including ideas, bug reports, and fixes.");
QString kappanhangack = QString("<br/><br/>Special thanks to Norbert Varga, and the <a href=\"https://github.com/nonoo/kappanhang\">nonoo/kappanhang team</a> for their initial work on the OEM protocol.");
QString sxcreditcopyright = QString("Speex copyright notice: \
Copyright (C) 2003 Jean-Marc Valin\n\
Redistribution and use in source and binary forms, with or without\n\
modification, are permitted provided that the following conditions\n\
are met:\n\
- Redistributions of source code must retain the above copyright\n\
notice, this list of conditions and the following disclaimer.\n\
- Redistributions in binary form must reproduce the above copyright\n\
notice, this list of conditions and the following disclaimer in the\n\
documentation and/or other materials provided with the distribution.\n\
- Neither the name of the Xiph.org Foundation nor the names of its\n\
contributors may be used to endorse or promote products derived from\n\
this software without specific prior written permission.\n\
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n\
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n\
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR\n\
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n\
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n\
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n\
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n\
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n\
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n\
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.");
// String it all together:
QString aboutText = head + copyright + "\n" + nacode + "\n" + doctest + wfviewcommunityack;
aboutText.append(website + "\n"+ docs + support + contact +"\n");
aboutText.append("\n" + ssCredit + "\n" + rsCredit + "\n");
#if defined(RTAUDIO)
aboutText.append(rtaudiocredit);
#endif
#if defined(PORTAUDIO)
aboutText.append(portaudiocredit);
#endif
aboutText.append(kappanhangack + qcpcredit + qtcredit);
aboutText.append("<br/><br/>");
aboutText.append("<pre>" + sxcreditcopyright + "</pre>");
aboutText.append("<br/><br/>");
aboutText.append(end);
ui->midTextBox->setText(aboutText);
ui->bottomText->setText(buildInfo);
ui->midTextBox->setFocus();
}
aboutbox::~aboutbox()
{
delete ui;
}
void aboutbox::on_logoBtn_clicked()
{
QDesktopServices::openUrl(QUrl("https://www.wfview.org/"));
}

26
aboutbox.h 100644
Wyświetl plik

@ -0,0 +1,26 @@
#ifndef ABOUTBOX_H
#define ABOUTBOX_H
#include <QWidget>
#include <QDesktopServices>
namespace Ui {
class aboutbox;
}
class aboutbox : public QWidget
{
Q_OBJECT
public:
explicit aboutbox(QWidget *parent = 0);
~aboutbox();
private slots:
void on_logoBtn_clicked();
private:
Ui::aboutbox *ui;
};
#endif // ABOUTBOX_H

77
aboutbox.ui 100644
Wyświetl plik

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>aboutbox</class>
<widget class="QWidget" name="aboutbox">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>700</width>
<height>567</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="logoBtn">
<property name="minimumSize">
<size>
<width>0</width>
<height>128</height>
</size>
</property>
<property name="sizeIncrement">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="iconSize">
<size>
<width>128</width>
<height>128</height>
</size>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="topText">
<property name="text">
<string>wfview version</string>
</property>
</widget>
</item>
<item>
<widget class="QTextBrowser" name="midTextBox">
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Noto Sans'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Detailed text here&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="bottomText">
<property name="text">
<string>Build String</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

Wyświetl plik

@ -91,7 +91,10 @@ bool audioHandler::init(audioSetup setupIn)
tempBuf.sent = 0;
if(!setup.isinput)
{
this->setVolume(setup.localAFgain);
}
#if defined(RTAUDIO)
#if !defined(Q_OS_MACX)
@ -322,7 +325,9 @@ void audioHandler::start()
void audioHandler::setVolume(unsigned char volume)
{
this->volume = (qreal)volume/255.0;
//this->volume = (qreal)volume/255.0;
this->volume = audiopot[volume];
qInfo(logAudio()) << (setup.isinput ? "Input" : "Output") << "setVolume: " << volume << "(" << this->volume << ")";
}

Wyświetl plik

@ -33,11 +33,14 @@ typedef signed short MY_TYPE;
#include <QMap>
#include "resampler/speex_resampler.h"
#include "ring/ring.h"
#ifdef Q_OS_WIN
#include "opus.h"
#else
#include "opus/opus.h"
#endif
#include "audiotaper.h"
#include <QDebug>
@ -71,6 +74,7 @@ struct audioSetup {
QAudioDeviceInfo port;
#endif
quint8 resampleQuality;
unsigned char localAFgain;
};
// For QtMultimedia, use a native QIODevice

273
audiotaper.h 100644
Wyświetl plik

@ -0,0 +1,273 @@
#ifndef AUDIOTAPER_H
#define AUDIOTAPER_H
#include <QtMath>
const qreal audiopot[256] =
{
0.00000,
0.00101,
0.00202,
0.00305,
0.00409,
0.00513,
0.00619,
0.00725,
0.00832,
0.00941,
0.01050,
0.01160,
0.01272,
0.01384,
0.01497,
0.01612,
0.01727,
0.01843,
0.01961,
0.02080,
0.02199,
0.02320,
0.02442,
0.02565,
0.02689,
0.02814,
0.02940,
0.03068,
0.03196,
0.03326,
0.03457,
0.03589,
0.03723,
0.03857,
0.03993,
0.04130,
0.04268,
0.04408,
0.04548,
0.04690,
0.04834,
0.04978,
0.05124,
0.05272,
0.05420,
0.05570,
0.05721,
0.05874,
0.06028,
0.06184,
0.06341,
0.06499,
0.06659,
0.06820,
0.06982,
0.07146,
0.07312,
0.07479,
0.07648,
0.07818,
0.07990,
0.08163,
0.08338,
0.08514,
0.08692,
0.08872,
0.09053,
0.09236,
0.09421,
0.09607,
0.09795,
0.09984,
0.10176,
0.10369,
0.10564,
0.10760,
0.10959,
0.11159,
0.11361,
0.11565,
0.11770,
0.11978,
0.12187,
0.12399,
0.12612,
0.12827,
0.13044,
0.13263,
0.13484,
0.13707,
0.13933,
0.14160,
0.14389,
0.14620,
0.14854,
0.15089,
0.15327,
0.15567,
0.15809,
0.16053,
0.16299,
0.16548,
0.16799,
0.17052,
0.17307,
0.17565,
0.17825,
0.18088,
0.18353,
0.18620,
0.18889,
0.19162,
0.19436,
0.19713,
0.19993,
0.20275,
0.20560,
0.20847,
0.21137,
0.21429,
0.21725,
0.22022,
0.22323,
0.22626,
0.22932,
0.23241,
0.23553,
0.23867,
0.24184,
0.24504,
0.24828,
0.25153,
0.25482,
0.25814,
0.26149,
0.26487,
0.26828,
0.27172,
0.27520,
0.27870,
0.28224,
0.28580,
0.28941,
0.29304,
0.29670,
0.30040,
0.30414,
0.30790,
0.31170,
0.31554,
0.31941,
0.32331,
0.32725,
0.33123,
0.33524,
0.33929,
0.34338,
0.34750,
0.35166,
0.35586,
0.36009,
0.36437,
0.36868,
0.37303,
0.37742,
0.38185,
0.38633,
0.39084,
0.39539,
0.39999,
0.40462,
0.40930,
0.41402,
0.41878,
0.42359,
0.42844,
0.43333,
0.43827,
0.44326,
0.44828,
0.45336,
0.45848,
0.46364,
0.46886,
0.47412,
0.47943,
0.48478,
0.49019,
0.49564,
0.50115,
0.50670,
0.51230,
0.51796,
0.52366,
0.52942,
0.53523,
0.54110,
0.54701,
0.55298,
0.55900,
0.56508,
0.57122,
0.57741,
0.58365,
0.58995,
0.59631,
0.60273,
0.60920,
0.61574,
0.62233,
0.62898,
0.63570,
0.64247,
0.64931,
0.65620,
0.66316,
0.67019,
0.67727,
0.68442,
0.69164,
0.69892,
0.70627,
0.71368,
0.72116,
0.72871,
0.73633,
0.74402,
0.75178,
0.75960,
0.76750,
0.77547,
0.78351,
0.79163,
0.79981,
0.80808,
0.81641,
0.82483,
0.83332,
0.84188,
0.85053,
0.85925,
0.86805,
0.87693,
0.88590,
0.89494,
0.90407,
0.91327,
0.92257,
0.93194,
0.94140,
0.95095,
0.96058,
0.97030,
0.98011,
0.99001,
1.00000
};
#endif // AUDIOTAPER_H

Wyświetl plik

@ -12,6 +12,7 @@ Q_DECLARE_LOGGING_CATEGORY(logUdp)
Q_DECLARE_LOGGING_CATEGORY(logUdpServer)
Q_DECLARE_LOGGING_CATEGORY(logRigCtlD)
#if defined(Q_OS_WIN) && !defined(__PRETTY_FUNCTION__)
#define __PRETTY_FUNCTION__ __FUNCSIG__
#endif

398
meter.cpp
Wyświetl plik

@ -23,6 +23,8 @@ meter::meter(QWidget *parent) : QWidget(parent)
//
// Text in qdarkstylesheet seems to be #EFF0F1
meterType = meterS;
currentColor.setNamedColor("#148CD2");
currentColor = currentColor.darker();
@ -34,8 +36,47 @@ meter::meter(QWidget *parent) : QWidget(parent)
lowTextColor.setNamedColor("#eff0f1");
lowLineColor = lowTextColor;
avgLevels.resize(averageBalisticLength, 0);
peakLevels.resize(peakBalisticLength, 0);
}
void meter::setMeterType(meterKind type)
{
if(type == meterType)
return;
meterType = type;
// clear average and peak vectors:
current = 0;
average = 0;
peak = 0;
avgLevels.clear();
peakLevels.clear();
avgLevels.resize(averageBalisticLength, 0);
peakLevels.resize(peakBalisticLength, 0);
peakPosition = 0;
avgPosition = 0;
// re-draw scale:
update();
}
meterKind meter::getMeterType()
{
return meterType;
}
void meter::setMeterShortString(QString s)
{
meterShortString = s;
}
QString meter::getMeterShortString()
{
return meterShortString;
}
void meter::paintEvent(QPaintEvent *)
{
@ -45,31 +86,125 @@ void meter::paintEvent(QPaintEvent *)
// The end effect, is that the drawing functions will all
// scale to the window size.
painter.setWindow(QRect(0, 0, 255+mstart, 50));
drawScale(&painter);
painter.setWindow(QRect(0, 0, 255+mXstart, widgetWindowHeight));
// Current:
painter.setPen(currentColor);
painter.setBrush(currentColor);
painter.drawRect(mstart,mheight,current,mstart);
// Average:
painter.setPen(averageColor);
painter.setBrush(averageColor);
painter.drawRect(mstart+average-1,mheight,1,mstart);
// Peak:
painter.setPen(peakColor);
painter.setBrush(peakColor);
if(peak > 120)
if(this->height() > widgetWindowHeight )
{
// 120 = +S9
painter.setBrush(Qt::red);
painter.setPen(Qt::red);
// Clamp down on stretching fonts.
// TODO: Make this more elegant
painter.setFont(QFont(this->fontInfo().family(), widgetWindowHeight/3.5));
widgetWindowHeight = this->height();
painter.setWindow(QRect(0, 0, 255+mXstart, widgetWindowHeight));
barHeight = widgetWindowHeight / 2;
//painter.setFont(QFont(this->fontInfo().family(), widgetWindowHeight/2.5));
}
painter.drawRect(mstart+peak-1,mheight,2,mstart);
switch(meterType)
{
case meterS:
peakRedLevel = 120; // S9+
drawScaleS(&painter);
break;
case meterPower:
peakRedLevel = 210; // 100%
drawScalePo(&painter);
break;
case meterALC:
peakRedLevel = 100;
drawScaleALC(&painter);
break;
case meterSWR:
peakRedLevel = 100; // SWR 2.5
drawScaleSWR(&painter);
break;
case meterCenter:
peakRedLevel = 256; // No need for red here
drawScaleCenter(&painter);
break;
case meterVoltage:
peakRedLevel = 241;
drawScaleVd(&painter);
break;
default:
peakRedLevel = 200;
drawScaleRaw(&painter);
break;
}
// Current: the most-current value.
// Draws a bar from start to value.
painter.setPen(currentColor);
painter.setBrush(currentColor);
if(meterType == meterCenter)
{
painter.drawRect(mXstart+128,mYstart,current-128,barHeight);
// Average:
painter.setPen(averageColor);
painter.setBrush(averageColor);
painter.drawRect(mXstart+average-1,mYstart,1,barHeight); // bar is 1 pixel wide, height = meter start?
// Peak:
painter.setPen(peakColor);
painter.setBrush(peakColor);
if((peak > 191) || (peak < 63))
{
painter.setBrush(Qt::red);
painter.setPen(Qt::red);
}
painter.drawRect(mXstart+peak-1,mYstart,1,barHeight);
} else {
// X, Y, Width, Height
painter.drawRect(mXstart,mYstart,current,barHeight);
// Average:
painter.setPen(averageColor);
painter.setBrush(averageColor);
painter.drawRect(mXstart+average-1,mYstart,1,barHeight); // bar is 1 pixel wide, height = meter start?
// Peak:
painter.setPen(peakColor);
painter.setBrush(peakColor);
if(peak > peakRedLevel)
{
painter.setBrush(Qt::red);
painter.setPen(Qt::red);
}
painter.drawRect(mXstart+peak-1,mYstart,2,barHeight);
}
}
void meter::setLevel(int current)
{
this->current = current;
avgLevels[(avgPosition++)%averageBalisticLength] = current;
peakLevels[(peakPosition++)%peakBalisticLength] = current;
int sum=0;
for(unsigned int i=0; i < (unsigned int)std::min(avgPosition, (int)avgLevels.size()); i++)
{
sum += avgLevels.at(i);
}
this->average = sum / std::min(avgPosition, (int)avgLevels.size());
this->peak = 0;
for(unsigned int i=0; i < peakLevels.size(); i++)
{
if( peakLevels.at(i) > this->peak)
this->peak = peakLevels.at(i);
}
this->update();
}
void meter::setLevels(int current, int peak, int average)
@ -77,6 +212,7 @@ void meter::setLevels(int current, int peak, int average)
this->current = current;
this->peak = peak;
this->average = average;
this->update();
}
@ -86,17 +222,221 @@ void meter::updateDrawing(int num)
length = num;
}
// The drawScale functions draw the numbers and number unerline for each type of meter
void meter::drawScale(QPainter *qp)
void meter::drawScaleRaw(QPainter *qp)
{
qp->setPen(lowTextColor);
qp->setFont(QFont("Arial", fontSize));
int i=mstart;
//qp->setFont(QFont("Arial", fontSize));
int i=mXstart;
for(; i<mXstart+256; i+=20)
{
qp->drawText(i,scaleTextYstart, QString("%1").arg(i) );
}
// Now the lines:
qp->setPen(lowLineColor);
// Line: X1, Y1 -->to--> X2, Y2
qp->drawLine(mXstart,scaleLineYstart,peakRedLevel+mXstart,scaleLineYstart);
qp->setPen(Qt::red);
qp->drawLine(peakRedLevel+mXstart,scaleLineYstart,255+mXstart,scaleLineYstart);
}
void meter::drawScaleVd(QPainter *qp)
{
qp->setPen(lowTextColor);
//qp->setFont(QFont("Arial", fontSize));
// 7300/9700 and others:
int midPointDn = 13;
int midPointVd = 10;
// 705:
//int midPointDn = 75;
//int midPointVd = 5;
int highPointDn = 241;
int highPointVd = 16;
float VdperDn = (float)(highPointVd-midPointVd) / float(highPointDn-midPointDn);
int i=mXstart;
for(; i<mXstart+midPointDn; i+=midPointDn/2)
{
qp->drawText(i,scaleTextYstart, QString("%1").arg( (int)((i-mXstart) * (float(midPointVd) / float(midPointDn)) )) );
}
for(; i<mXstart+255; i+= (highPointDn-midPointDn) / (highPointVd-midPointVd))
{
qp->drawText(i,scaleTextYstart, QString("%1").arg( (int) std::round( ((i-mXstart-midPointDn) * (VdperDn) ) + (midPointVd) )));
qp->drawLine(i,scaleTextYstart, i, scaleTextYstart+5);
}
// Now the lines:
qp->setPen(lowLineColor);
// Line: X1, Y1 -->to--> X2, Y2
qp->drawLine(mXstart,scaleLineYstart,peakRedLevel+mXstart,scaleLineYstart);
qp->setPen(Qt::red);
qp->drawLine(peakRedLevel+mXstart,scaleLineYstart,255+mXstart,scaleLineYstart);
}
void meter::drawScaleCenter(QPainter *qp)
{
// No known units
qp->setPen(lowLineColor);
qp->drawText(60+mXstart,scaleTextYstart, QString("-"));
qp->setPen(Qt::green);
// Attempt to draw the zero at the actual center
qp->drawText(128-2+mXstart,scaleTextYstart, QString("0"));
qp->setPen(lowLineColor);
qp->drawText(195+mXstart,scaleTextYstart, QString("+"));
qp->setPen(lowLineColor);
qp->drawLine(mXstart,scaleLineYstart,128-32+mXstart,scaleLineYstart);
qp->setPen(Qt::green);
qp->drawLine(128-32+mXstart,scaleLineYstart,128+32+mXstart,scaleLineYstart);
qp->setPen(lowLineColor);
qp->drawLine(128+32+mXstart,scaleLineYstart,255+mXstart,scaleLineYstart);
}
void meter::drawScalePo(QPainter *qp)
{
//From the manual: "0000=0% to 0143=50% to 0213=100%"
float dnPerWatt = 143.0 / 50.0;
qp->setPen(lowTextColor);
//qp->setFont(QFont("Arial", fontSize));
int i=mXstart;
// 13.3 DN per s-unit:
int p=0;
for(; i<mXstart+143; i+=(int)(10*dnPerWatt))
{
// Stop just before the next 10w spot
if(i<mXstart+140)
qp->drawText(i,scaleTextYstart, QString("%1").arg(10*(p++)) );
}
// Modify current scale position:
// Here, P is now 60 watts:
// Higher scale:
i = i - (int)(10*dnPerWatt); // back one tick first. Otherwise i starts at 178.
//qDebug() << "meter i: " << i;
dnPerWatt = (213-143.0) / 50.0; // 1.4 dn per watt
// P=5 here.
qp->setPen(Qt::yellow);
int k=0;
for(i=mXstart+143; i<mXstart+213; i+=(5*dnPerWatt))
{
k = 50+(( i-mXstart-143 ) / dnPerWatt);
if(k==40||k==50||k==65||k==80)
qp->drawText(i,scaleTextYstart, QString("%1").arg(k) );
}
// Now we're out past 100:
qp->setPen(Qt::red);
for(i=mXstart+213; i<mXstart+255; i+=(10*dnPerWatt))
{
k = 50+(( i-mXstart-143 ) / dnPerWatt);
if(k==100)
qp->drawText(i,scaleTextYstart, QString("%1").arg(k) );
}
// Now the lines:
qp->setPen(lowLineColor);
// Line: X1, Y1 -->to--> X2, Y2
qp->drawLine(mXstart,scaleLineYstart,213+mXstart,scaleLineYstart);
qp->setPen(Qt::red);
qp->drawLine(213+mXstart,scaleLineYstart,255+mXstart,scaleLineYstart);
(void)qp;
}
void meter::drawScaleRxdB(QPainter *qp)
{
(void)qp;
}
void meter::drawScaleALC(QPainter *qp)
{
// From the manual: 0000=Minimum to 0120=Maximum
qp->setPen(lowTextColor);
//qp->setFont(QFont("Arial", fontSize));
int i=mXstart;
int alc=0;
for(; i<mXstart+100; i += (20))
{
qp->drawText(i,scaleTextYstart, QString("%1").arg(alc) );
alc +=20;
}
qp->setPen(Qt::red);
for(; i<mXstart+120; i+=(int)(10*i))
{
qp->drawText(i,scaleTextYstart, QString("+%1").arg(alc) );
alc +=10;
}
qp->setPen(lowLineColor);
qp->drawLine(mXstart,scaleLineYstart,100+mXstart,scaleLineYstart);
qp->setPen(Qt::red);
qp->drawLine(100+mXstart,scaleLineYstart,255+mXstart,scaleLineYstart);
(void)qp;
}
void meter::drawScaleSWR(QPainter *qp)
{
// From the manual:
// 0000=SWR1.0,
// 0048=SWR1.5,
// 0080=SWR2.0,
// 0120=SWR3.0
qp->drawText(mXstart,scaleTextYstart, QString("1.0"));
qp->drawText(24+mXstart,scaleTextYstart, QString("1.3"));
qp->drawText(48+mXstart,scaleTextYstart, QString("1.5"));
qp->drawText(80+mXstart,scaleTextYstart, QString("2.0"));
qp->drawText(100+mXstart,scaleTextYstart, QString("2.5"));
qp->drawText(120+mXstart,scaleTextYstart, QString("3.0"));
qp->setPen(lowLineColor);
qp->drawLine(mXstart,scaleLineYstart,100+mXstart,scaleLineYstart);
qp->setPen(Qt::red);
qp->drawLine(100+mXstart,scaleLineYstart,255+mXstart,scaleLineYstart);
(void)qp;
}
void meter::drawScaleId(QPainter *qp)
{
(void)qp;
}
void meter::drawScaleS(QPainter *qp)
{
qp->setPen(lowTextColor);
//qp->setFont(QFont("Arial", fontSize));
int i=mXstart;
// 13.3 DN per s-unit:
int s=0;
for(; i<mstart+120; i+=13)
for(; i<mXstart+120; i+=13)
{
qp->drawText(i,mstart, QString("%1").arg(s++) );
qp->drawText(i,scaleTextYstart, QString("%1").arg(s++) );
}
// 2 DN per 1 dB now:
@ -109,16 +449,16 @@ void meter::drawScale(QPainter *qp)
qp->setPen(Qt::red);
for(; i<mstart+255; i+=40)
for(; i<mXstart+255; i+=40)
{
qp->drawText(i,mstart, QString("+%1").arg(s) );
qp->drawText(i,scaleTextYstart, QString("+%1").arg(s) );
s = s + 20;
}
qp->setPen(lowLineColor);
qp->drawLine(mstart,12,130,12);
qp->drawLine(mXstart,scaleLineYstart,130,scaleLineYstart);
qp->setPen(Qt::red);
qp->drawLine(130,12,255,12);
qp->drawLine(130,scaleLineYstart,255,scaleLineYstart);
}

45
meter.h
Wyświetl plik

@ -3,6 +3,12 @@
#include <QWidget>
#include <QPainter>
#include <vector>
#include <algorithm>
#include <numeric>
#include <cmath>
#include "rigcommander.h" // for meter types
class meter : public QWidget
{
@ -17,20 +23,51 @@ public slots:
void updateDrawing(int num);
void setLevels(int current, int peak, int average);
void setLevel(int current);
void setMeterType(meterKind type);
void setMeterShortString(QString);
QString getMeterShortString();
meterKind getMeterType();
private:
//QPainter painter;
int fontSize = 5;
meterKind meterType;
QString meterShortString;
int fontSize = 10;
int length=30;
int current=0;
int peak = 0;
int average = 0;
int mstart = 10; // Starting point for S=0.
int mheight = 14; // "thickness" of the meter block rectangle
int averageBalisticLength = 30;
int peakBalisticLength = 30;
int avgPosition=0;
int peakPosition=0;
std::vector<unsigned char> avgLevels;
std::vector<unsigned char> peakLevels;
void drawScale(QPainter *qp);
int peakRedLevel=0;
int mXstart = 0; // Starting point for S=0.
int mYstart = 14; // height, down from top, where the drawing starts
int barHeight = 10; // Height of meter "bar" indicators
int scaleLineYstart = 12;
int scaleTextYstart = 10;
int widgetWindowHeight = mYstart + barHeight + 0; // height of drawing canvis.
void drawScaleS(QPainter *qp);
void drawScaleCenter(QPainter *qp);
void drawScalePo(QPainter *qp);
void drawScaleRxdB(QPainter *qp);
void drawScaleALC(QPainter *qp);
void drawScaleSWR(QPainter *qp);
void drawScaleVd(QPainter *qp);
void drawScaleId(QPainter *qp);
void drawScaleRaw(QPainter *qp);
QColor currentColor;
QColor averageColor;

Wyświetl plik

@ -117,7 +117,7 @@ void pttyHandler::receiveDataFromRigToPtty(const QByteArray& data)
{
int fePos=data.lastIndexOf((char)0xfe);
if (fePos>0)
if (fePos > 0 && data.length() > fePos+2)
fePos=fePos-1;
else
{
@ -125,7 +125,14 @@ void pttyHandler::receiveDataFromRigToPtty(const QByteArray& data)
printHex(data,false,true);
}
if (isConnected && (unsigned char)data[fePos+2] != 0xE1 && (unsigned char)data[fePos+3] != 0xE1)
if (disableTransceive && ((unsigned char)data[fePos + 2] == 0x00 || (unsigned char)data[fePos + 3] == 0x00))
{
// Ignore data that is sent to/from transceive address as client has requested transceive disabled.
qDebug(logSerial()) << "Transceive command filtered";
return;
}
if (isConnected && (unsigned char)data[fePos + 2] != 0xE1 && (unsigned char)data[fePos + 3] != 0xE1)
{
// send to the pseudo port as well
// index 2 is dest, 0xE1 is wfview, 0xE0 is assumed to be the other device.
@ -133,7 +140,7 @@ void pttyHandler::receiveDataFromRigToPtty(const QByteArray& data)
// 0xE1 = wfview
// 0xE0 = pseudo-term host
// 0x00 = broadcast to all
//qInfo(logSerial()) << "Sending data from radio to pseudo-terminal";
//qInfo(logSerial()) << "Sending data from radio to pseudo-terminal";
sendDataOut(data);
}
}
@ -221,12 +228,16 @@ void pttyHandler::receiveDataIn(int fd) {
reply[3] = inPortData[2];
sendDataOut(inPortData); // Echo command back
sendDataOut(reply);
if (!disableTransceive) {
qInfo(logSerial()) << "pty requested CI-V Transceive disable";
disableTransceive = true;
}
}
else if (inPortData.length() > lastFE + 2 && ((quint8)inPortData[lastFE + 1] == civId || (quint8)inPortData[lastFE + 2] == civId))
{
emit haveDataFromPort(inPortData);
//qInfo(logSerial()) << "Data from pseudo term:";
//printHex(inPortData, false, true);
qDebug(logSerial()) << "Data from pseudo term:";
printHex(inPortData, false, true);
}
if (rolledBack)

Wyświetl plik

@ -65,7 +65,7 @@ private:
bool isConnected=false; // port opened
mutable QMutex mutex;
void printHex(const QByteArray& pdata, bool printVert, bool printHoriz);
bool disableTransceive = false;
QSocketNotifier *ptReader = nullptr;
quint8 civId=0;
};

Wyświetl plik

@ -133,7 +133,8 @@ void rigCommander::commSetup(unsigned char rigCivAddr, udpPreferences prefs, aud
connect(ptty, SIGNAL(haveSerialPortError(QString, QString)), this, SLOT(handleSerialPortError(QString, QString)));
connect(this, SIGNAL(getMoreDebug()), ptty, SLOT(debugThis()));
emit haveAfGain(255);
emit haveAfGain(rxSetup.localAFgain);
}
// data from the comm port to the program:
@ -1221,6 +1222,9 @@ void rigCommander::parseCommand()
case '\x11':
emit haveAttenuator((unsigned char)payloadIn.at(1));
break;
case '\x12':
emit haveAntenna((unsigned char)payloadIn.at(1), (bool)payloadIn.at(2));
break;
case '\x14':
// read levels
parseLevels();
@ -1385,6 +1389,11 @@ void rigCommander::parseLevels()
emit haveMeter(meterS, level);
rigState.sMeter = level;
break;
case '\x04':
// Center (IC-R8600)
emit haveMeter(meterCenter, level);
rigState.sMeter = level;
break;
case '\x11':
// RF-Power meter
emit haveMeter(meterPower, level);
@ -1913,6 +1922,9 @@ void rigCommander::getMeters(meterKind meter)
case meterS:
getSMeter();
break;
case meterCenter:
getCenterMeter();
break;
case meterSWR:
getSWRMeter();
break;
@ -1942,6 +1954,12 @@ void rigCommander::getSMeter()
prepDataAndSend(payload);
}
void rigCommander::getCenterMeter()
{
QByteArray payload("\x15\x04");
prepDataAndSend(payload);
}
void rigCommander::getRFPowerMeter()
{
QByteArray payload("\x15\x11");
@ -2019,6 +2037,143 @@ void rigCommander::setRefAdjustFine(unsigned char level)
prepDataAndSend(payload);
}
void rigCommander::setTime(timekind t)
{
QByteArray payload;
switch(rigCaps.model)
{
case model705:
payload.setRawData("\x1A\x05\x01\x66", 4);
break;
case model7300:
payload.setRawData("\x1A\x05\x00\x95", 4);
break;
case model7610:
payload.setRawData("\x1A\x05\x01\x59", 4);
break;
case model7700:
payload.setRawData("\x1A\x05\x00\x59", 4);
break;
case model7850:
payload.setRawData("\x1A\x05\x00\x96", 4);
break;
case model9700:
payload.setRawData("\x1A\x05\x01\x80", 4);
break;
case modelR8600:
payload.setRawData("\x1A\x05\x01\x32", 4);
break;
default:
return;
break;
}
payload.append(convertNumberToHex(t.hours));
payload.append(convertNumberToHex(t.minutes));
//qDebug(logRig()) << "Setting time to this: ";
//printHex(payload);
prepDataAndSend(payload);
}
void rigCommander::setDate(datekind d)
{
QByteArray payload;
switch(rigCaps.model)
{
case model705:
payload.setRawData("\x1A\x05\x01\x65", 4);
break;
case model7300:
payload.setRawData("\x1A\x05\x00\x94", 4);
break;
case model7610:
payload.setRawData("\x1A\x05\x01\x58", 4);
break;
case model7700:
payload.setRawData("\x1A\x05\x00\x58", 4);
break;
case model7850:
payload.setRawData("\x1A\x05\x00\x95", 4);
break;
case model9700:
payload.setRawData("\x1A\x05\x01\x79", 4);
break;
case modelR8600:
payload.setRawData("\x1A\x05\x01\x31", 4);
break;
default:
return;
break;
}
// YYYYMMDD
payload.append(convertNumberToHex(d.year/100)); // 20
payload.append(convertNumberToHex(d.year - 100*(d.year/100))); // 21
payload.append(convertNumberToHex(d.month));
payload.append(convertNumberToHex(d.day));
//qDebug(logRig()) << "Setting date to this: ";
//printHex(payload);
prepDataAndSend(payload);
}
void rigCommander::setUTCOffset(timekind t)
{
QByteArray payload;
switch(rigCaps.model)
{
case model705:
payload.setRawData("\x1A\x05\x01\x70", 4);
break;
case model7300:
payload.setRawData("\x1A\x05\x00\x96", 4);
break;
case model7610:
payload.setRawData("\x1A\x05\x01\x62", 4);
break;
case model7700:
payload.setRawData("\x1A\x05\x00\x61", 4);
break;
case model7850:
// Clock 1:
payload.setRawData("\x1A\x05\x00\x99", 4);
break;
case model9700:
payload.setRawData("\x1A\x05\x01\x84", 4);
break;
case modelR8600:
payload.setRawData("\x1A\x05\x01\x35", 4);
break;
default:
return;
break;
}
payload.append(convertNumberToHex(t.hours));
payload.append(convertNumberToHex(t.minutes));
payload.append((unsigned char)t.isMinus);
//qDebug(logRig()) << "Setting UTC Offset to this: ";
//printHex(payload);
prepDataAndSend(payload);
}
unsigned char rigCommander::convertNumberToHex(unsigned char num)
{
// Two digit only
if(num > 99)
{
qInfo(logRig()) << "Invalid numeric conversion from num " << num << " to hex.";
return 0xFA;
}
unsigned char result = 0;
result = (num/10) << 4;
result |= (num - 10*(num/10));
qDebug(logRig()) << "Converting number: " << num << " to hex: " + QString("0x%1").arg(result, 2, 16, QChar('0'));
return result;
}
void rigCommander::sendLevelCmd(unsigned char levAddr, unsigned char level)
{
QByteArray payload("\x14");
@ -2663,6 +2818,7 @@ void rigCommander::determineRigCaps()
rigCaps.preamps.push_back('\x00');
rigCaps.hasAntennaSel = false;
rigCaps.hasRXAntenna = false;
rigCaps.hasTransmit = true;
rigCaps.hasPTTCommand = true;
@ -2799,6 +2955,29 @@ void rigCommander::determineRigCaps()
rigCaps.bsr[band2m] = 0x01;
rigCaps.modes = commonModes;
break;
case model7600:
rigCaps.modelName = QString("IC-7600");
rigCaps.hasSpectrum = false;
rigCaps.inputs.append(inputACC);
rigCaps.inputs.append(inputUSB);
rigCaps.hasLan = false;
rigCaps.hasEthernet = false;
rigCaps.hasWiFi = false;
rigCaps.hasFDcomms = false;
rigCaps.hasATU = true;
rigCaps.hasCTCSS = false;
rigCaps.hasDTCS = false;
rigCaps.attenuators.insert(rigCaps.attenuators.end(), {0x00, 0x06, 0x12, 0x18});
rigCaps.preamps.push_back('\x01');
rigCaps.preamps.push_back('\x02');
rigCaps.antennas = {0x00, 0x01};
rigCaps.bands = standardHF;
rigCaps.bands.push_back(bandGen);
rigCaps.bsr[bandGen] = 0x11;
rigCaps.modes = commonModes;
rigCaps.modes.insert(rigCaps.modes.end(), {createMode(modePSK, 0x12, "PSK"),
createMode(modePSK_R, 0x13, "PSK-R")});
break;
case model7610:
rigCaps.modelName = QString("IC-7610");
rigCaps.hasSpectrum = true;
@ -2827,6 +3006,7 @@ void rigCommander::determineRigCaps()
rigCaps.bands.push_back(band630m);
rigCaps.bands.push_back(band2200m);
rigCaps.modes = commonModes;
rigCaps.hasRXAntenna = true;
break;
case model7850:
rigCaps.modelName = QString("IC-785x");
@ -2857,6 +3037,7 @@ void rigCommander::determineRigCaps()
rigCaps.modes = commonModes;
rigCaps.modes.insert(rigCaps.modes.end(), {createMode(modePSK, 0x12, "PSK"),
createMode(modePSK_R, 0x13, "PSK-R")});
rigCaps.hasRXAntenna = true;
break;
case model705:
rigCaps.modelName = QString("IC-705");
@ -3122,6 +3303,7 @@ void rigCommander::determineRigCaps()
break;
}
haveRigCaps = true;
if(lookingForRig)
{
lookingForRig = false;
@ -3548,11 +3730,11 @@ void rigCommander::setPreamp(unsigned char pre)
prepDataAndSend(payload);
}
void rigCommander::setAntenna(unsigned char ant)
void rigCommander::setAntenna(unsigned char ant, bool rx)
{
QByteArray payload("\x12");
payload.append(ant);
payload.append("\x00"); // 0x00 = use for TX and RX
payload.append((unsigned char)rx); // 0x00 = use for TX and RX
prepDataAndSend(payload);
}

Wyświetl plik

@ -19,13 +19,19 @@
#define compCivAddr 0xE1
enum meterKind {
meterNone=0,
meterS,
meterCenter,
meterSWR,
meterPower,
meterALC,
meterComp,
meterVoltage,
meterCurrent
meterCurrent,
meterRxdB,
meterTxMod,
meterRxAudio,
meterLatency
};
enum spectrumMode {
@ -41,6 +47,18 @@ struct freqt {
double MHzDouble;
};
struct datekind {
uint16_t year;
unsigned char month;
unsigned char day;
};
struct timekind {
unsigned char hours;
unsigned char minutes;
bool isMinus;
};
struct rigStateStruct {
freqt vfoAFreq;
freqt vfoBFreq;
@ -140,7 +158,7 @@ public slots:
void getAntenna();
void setAttenuator(unsigned char att);
void setPreamp(unsigned char pre);
void setAntenna(unsigned char ant);
void setAntenna(unsigned char ant, bool rx);
// Repeater:
void setDuplexMode(duplexMode dm);
@ -207,6 +225,7 @@ public slots:
// Meters:
void getSMeter();
void getCenterMeter();
void getRFPowerMeter();
void getSWRMeter();
void getALCMeter();
@ -226,6 +245,12 @@ public slots:
void setRefAdjustCourse(unsigned char level);
void setRefAdjustFine(unsigned char level);
// Time and Date:
void setTime(timekind t);
void setDate(datekind d);
void setUTCOffset(timekind t);
// Satellite:
void setSatelliteMode(bool enabled);
void getSatelliteMode();
@ -326,7 +351,7 @@ signals:
void haveATUStatus(unsigned char status);
void haveAttenuator(unsigned char att);
void havePreamp(unsigned char pre);
void haveAntenna(unsigned char ant);
void haveAntenna(unsigned char ant,bool rx);
// Rig State
void stateInfo(rigStateStruct* state);
@ -350,6 +375,7 @@ private:
QByteArray makeFreqPayload(freqt freq);
QByteArray encodeTone(quint16 tone, bool tinv, bool rinv);
QByteArray encodeTone(quint16 tone);
unsigned char convertNumberToHex(unsigned char num);
quint16 decodeTone(QByteArray eTone);
quint16 decodeTone(QByteArray eTone, bool &tinv, bool &rinv);

Wyświetl plik

@ -122,6 +122,8 @@ struct rigCapabilities {
bool hasAntennaSel;
bool hasDataModes;
bool hasRXAntenna;
std::vector <unsigned char> attenuators;
std::vector <unsigned char> preamps;
std::vector <unsigned char> antennas;

Wyświetl plik

@ -0,0 +1,16 @@
#include "transceiveradjustments.h"
#include "ui_transceiveradjustments.h"
transceiverAdjustments::transceiverAdjustments(QWidget *parent) :
QWidget(parent),
ui(new Ui::transceiverAdjustments)
{
ui->setupUi(this);
// request level updates
}
transceiverAdjustments::~transceiverAdjustments()
{
delete ui;
}

Wyświetl plik

@ -0,0 +1,22 @@
#ifndef TRANSCEIVERADJUSTMENTS_H
#define TRANSCEIVERADJUSTMENTS_H
#include <QWidget>
namespace Ui {
class transceiverAdjustments;
}
class transceiverAdjustments : public QWidget
{
Q_OBJECT
public:
explicit transceiverAdjustments(QWidget *parent = 0);
~transceiverAdjustments();
private:
Ui::transceiverAdjustments *ui;
};
#endif // TRANSCEIVERADJUSTMENTS_H

Wyświetl plik

@ -0,0 +1,329 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>transceiverAdjustments</class>
<widget class="QWidget" name="transceiverAdjustments">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>680</width>
<height>339</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>10</number>
</property>
<property name="topMargin">
<number>10</number>
</property>
<property name="rightMargin">
<number>10</number>
</property>
<property name="bottomMargin">
<number>10</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Transmitter</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QSlider" name="verticalSlider">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox">
<property name="text">
<string>Comp</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QSlider" name="verticalSlider_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="minimumSize">
<size>
<width>0</width>
<height>23</height>
</size>
</property>
<property name="text">
<string>Bass</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QSlider" name="verticalSlider_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="minimumSize">
<size>
<width>0</width>
<height>23</height>
</size>
</property>
<property name="text">
<string>Trebble</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_10">
<item>
<widget class="QSlider" name="verticalSlider_9">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_6">
<property name="minimumSize">
<size>
<width>0</width>
<height>23</height>
</size>
</property>
<property name="text">
<string>TBD</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Receiver</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<widget class="QSlider" name="verticalSlider_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="minimumSize">
<size>
<width>0</width>
<height>23</height>
</size>
</property>
<property name="text">
<string>Bass</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QSlider" name="verticalSlider_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="minimumSize">
<size>
<width>0</width>
<height>23</height>
</size>
</property>
<property name="text">
<string>Trebble</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QSlider" name="verticalSlider_8">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>IF Shift</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<widget class="QSlider" name="verticalSlider_6">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_2">
<property name="text">
<string>NR</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QSlider" name="verticalSlider_7">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_3">
<property name="text">
<string>NB</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_11">
<item>
<widget class="QSlider" name="verticalSlider_10">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_4">
<property name="text">
<string>Notch</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Bandwidth</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_12">
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>Low</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_2"/>
</item>
<item>
<widget class="QLabel" name="label_8">
<property name="text">
<string>High</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox"/>
</item>
<item>
<widget class="QLabel" name="label_9">
<property name="text">
<string>Filter</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_3"/>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

Wyświetl plik

@ -195,7 +195,7 @@ void udpHandler::dataReceived()
if (txSetup.codec == 0) {
txString = "(no tx)";
}
emit haveNetworkStatus(QString("<pre>%1 rx latency: %2 ms / rtt: %3 ms / loss: %4/%5</pre>").arg(txString).arg(tempLatency).arg(latency, 3).arg(totallost, 3).arg(totalsent, 3));
emit haveNetworkStatus(QString("<pre>%1 rx latency: %2 / rtt: %3 ms / loss: %4/%5</pre>").arg(txString).arg(tempLatency).arg(latency, 3).arg(totallost, 3).arg(totalsent, 3));
}
break;
}
@ -1142,6 +1142,10 @@ void udpBase::dataReceived(QByteArray r)
{
rxBufferMutex.lock();
if (rxSeqBuf.isEmpty()) {
if (rxSeqBuf.size() > 400)
{
rxSeqBuf.erase(rxSeqBuf.begin());
}
rxSeqBuf.insert(in->seq, QTime::currentTime());
}
else
@ -1162,6 +1166,10 @@ void udpBase::dataReceived(QByteArray r)
{
// Add incoming packet to the received buffer and if it is in the missing buffer, remove it.
rxSeqBuf.insert(in->seq, QTime::currentTime());
if (rxSeqBuf.size() > 400)
{
rxSeqBuf.erase(rxSeqBuf.begin());
}
}
else {
// This is probably one of our missing packets!
@ -1217,7 +1225,15 @@ void udpBase::sendRetransmitRequest()
{
// We haven't seen this missing packet before
qDebug(logUdp()) << this->metaObject()->className() << ": Adding to missing buffer (len=" << rxMissing.size() << "): " << j;
if (rxMissing.size() > 25)
{
rxMissing.erase(rxMissing.begin());
}
rxMissing.insert(j, 0);
if (rxSeqBuf.size() > 400)
{
rxSeqBuf.erase(rxSeqBuf.begin());
}
rxSeqBuf.insert(j, QTime::currentTime()); // Add this missing packet to the rxbuffer as we now long about it.
packetsLost++;
}
@ -1360,11 +1376,17 @@ void udpBase::sendTrackedPacket(QByteArray d)
congestion = 0;
}
txSeqBuf.insert(sendSeq,s);
if (txSeqBuf.size() > 400)
{
txSeqBuf.erase(txSeqBuf.begin());
}
txBufferMutex.unlock();
} else {
qInfo(logUdp()) << this->metaObject()->className() << ": txBuffer mutex is locked";
}
purgeOldEntries(); // Delete entries older than PURGE_SECONDS seconds (currently 5)
// Stop using purgeOldEntries() as it is likely slower than just removing the earliest packet.
//qInfo(logUdp()) << this->metaObject()->className() << "RX:" << rxSeqBuf.size() << "TX:" <<txSeqBuf.size() << "MISS:" << rxMissing.size();
//purgeOldEntries(); // Delete entries older than PURGE_SECONDS seconds (currently 5)
sendSeq++;
udpMutex.lock();

Wyświetl plik

@ -318,7 +318,8 @@ void udpServer::controlReceived()
passcode(user.username, usercomp);
QByteArray passcomp;
passcode(user.password, passcomp);
if (!strcmp(in->username, usercomp.constData()) && (!strcmp(in->password, user.password.toUtf8()) || !strcmp(in->password, passcomp.constData())))
if (!user.username.trimmed().isEmpty() && !user.password.trimmed().isEmpty() && !strcmp(in->username, usercomp.constData()) &&
(!strcmp(in->password, user.password.toUtf8()) || !strcmp(in->password, passcomp.constData())))
{
current->isAuthenticated = true;
current->user = user;

Wyświetl plik

@ -26,7 +26,9 @@ wfmain::wfmain(const QString serialPortCL, const QString hostCL, const QString s
cal = new calibrationWindow();
rpt = new repeaterSetup();
sat = new satelliteSetup();
trxadj = new transceiverAdjustments();
srv = new udpServerSetup();
abtBox = new aboutbox();
connect(this, SIGNAL(sendServerConfig(SERVERCONFIG)), srv, SLOT(receiveServerConfig(SERVERCONFIG)));
connect(srv, SIGNAL(serverConfig(SERVERCONFIG, bool)), this, SLOT(serverConfigRequested(SERVERCONFIG, bool)));
@ -42,6 +44,9 @@ wfmain::wfmain(const QString serialPortCL, const QString hostCL, const QString s
qRegisterMetaType<mode_info>();
qRegisterMetaType<audioPacket>();
qRegisterMetaType <audioSetup>();
qRegisterMetaType <timekind>();
qRegisterMetaType <datekind>();
haveRigCaps = false;
@ -106,11 +111,33 @@ wfmain::~wfmain()
void wfmain::closeEvent(QCloseEvent *event)
{
// Are you sure?
QMessageBox::StandardButton resBtn = QMessageBox::question( this, QString("Confirm close"),
tr("Are you sure you wish to exit?\n"),
QMessageBox::No | QMessageBox::Yes,
QMessageBox::Yes);
if (resBtn == QMessageBox::Yes) {
if (!prefs.confirmExit) {
QApplication::exit();
}
QCheckBox *cb = new QCheckBox("Don't ask me again");
QMessageBox msgbox;
msgbox.setText("Are you sure you wish to exit?\n");
msgbox.setIcon(QMessageBox::Icon::Question);
QAbstractButton *yesButton = msgbox.addButton(QMessageBox::Yes);
msgbox.addButton(QMessageBox::No);
msgbox.setDefaultButton(QMessageBox::Yes);
msgbox.setCheckBox(cb);
QObject::connect(cb, &QCheckBox::stateChanged, [this](int state){
if (static_cast<Qt::CheckState>(state) == Qt::CheckState::Checked) {
prefs.confirmExit=false;
} else {
prefs.confirmExit=true;
}
settings->beginGroup("Interface");
settings->setValue("ConfirmExit", this->prefs.confirmExit);
settings->endGroup();
settings->sync();
});
msgbox.exec();
if (msgbox.clickedButton() == yesButton) {
QApplication::exit();
} else {
event->ignore();
@ -180,9 +207,9 @@ void wfmain::openRig()
}
usingLAN = false;
emit sendCommSetup(prefs.radioCIVAddr, serialPortRig, prefs.serialPortBaud,prefs.virtualSerialPort);
ui->statusBar->showMessage(QString("Connecting to rig using serial port ").append(serialPortRig), 1000);
}
ui->statusBar->showMessage(QString("Connecting to rig using serial port ").append(serialPortRig), 1000);
}
@ -312,13 +339,13 @@ void wfmain::rigConnections()
connect(rig, SIGNAL(haveRigID(rigCapabilities)), this, SLOT(receiveRigID(rigCapabilities)));
connect(this, SIGNAL(setAttenuator(unsigned char)), rig, SLOT(setAttenuator(unsigned char)));
connect(this, SIGNAL(setPreamp(unsigned char)), rig, SLOT(setPreamp(unsigned char)));
connect(this, SIGNAL(setAntenna(unsigned char)), rig, SLOT(setAntenna(unsigned char)));
connect(this, SIGNAL(setAntenna(unsigned char, bool)), rig, SLOT(setAntenna(unsigned char, bool)));
connect(this, SIGNAL(getPreamp()), rig, SLOT(getPreamp()));
connect(rig, SIGNAL(havePreamp(unsigned char)), this, SLOT(receivePreamp(unsigned char)));
connect(this, SIGNAL(getAttenuator()), rig, SLOT(getAttenuator()));
connect(rig, SIGNAL(haveAttenuator(unsigned char)), this, SLOT(receiveAttenuator(unsigned char)));
connect(this, SIGNAL(getAntenna()), rig, SLOT(getAntenna()));
//connect(rig, SIGNAL(haveAntenna(unsigned char)), this, SLOT(receiveAntennaSel(unsigned char)));
connect(rig, SIGNAL(haveAntenna(unsigned char,bool)), this, SLOT(receiveAntennaSel(unsigned char,bool)));
// Speech (emitted from rig speaker)
@ -334,6 +361,11 @@ void wfmain::rigConnections()
connect(cal, SIGNAL(setRefAdjustCourse(unsigned char)), rig, SLOT(setRefAdjustCourse(unsigned char)));
connect(cal, SIGNAL(setRefAdjustFine(unsigned char)), rig, SLOT(setRefAdjustFine(unsigned char)));
// Date and Time:
connect(this, SIGNAL(setTime(timekind)), rig, SLOT(setTime(timekind)));
connect(this, SIGNAL(setDate(datekind)), rig, SLOT(setDate(datekind)));
connect(this, SIGNAL(setUTCOffset(timekind)), rig, SLOT(setUTCOffset(timekind)));
}
//void wfmain::removeRigConnections()
@ -629,6 +661,32 @@ void wfmain::setupMainUI()
ui->wfthemeCombo->addItem("Spectrum", QCPColorGradient::gpSpectrum);
ui->wfthemeCombo->addItem("Candy", QCPColorGradient::gpCandy);
ui->meter2selectionCombo->addItem("None", meterNone);
ui->meter2selectionCombo->addItem("SWR", meterSWR);
ui->meter2selectionCombo->addItem("ALC", meterALC);
ui->meter2selectionCombo->addItem("Compression", meterComp);
ui->meter2selectionCombo->addItem("Voltage", meterVoltage);
ui->meter2selectionCombo->addItem("Current", meterCurrent);
ui->meter2selectionCombo->addItem("Center", meterCenter);
ui->meter2Widget->hide();
#ifdef QT_DEBUG
// Experimental feature:
ui->meter2selectionCombo->show();
ui->secondaryMeterSelectionLabel->show();
#else
ui->meter2selectionCombo->hide();
ui->secondaryMeterSelectionLabel->hide();
#endif
// Future ideas:
//ui->meter2selectionCombo->addItem("Transmit Audio", meterTxMod);
//ui->meter2selectionCombo->addItem("Receive Audio", meterRxAudio);
//ui->meter2selectionCombo->addItem("Latency", meterLatency);
spans << "2.5k" << "5.0k" << "10k" << "25k";
spans << "50k" << "100k" << "250k" << "500k";
ui->scopeBWCombo->insertItems(0, spans);
@ -686,9 +744,6 @@ void wfmain::setupMainUI()
rigName->setText("NONE");
rigName->setFixedWidth(50);
SMeterReadings.fill(0,30);
powerMeterReadings.fill(0,30);
freq.MHzDouble = 0.0;
freq.Hz = 0;
oldFreqDialVal = ui->freqDial->value();
@ -832,6 +887,11 @@ void wfmain::setInitialTiming()
pttTimer->setInterval(180*1000); // 3 minute max transmit time in ms
pttTimer->setSingleShot(true);
connect(pttTimer, SIGNAL(timeout()), this, SLOT(handlePttLimit()));
timeSync = new QTimer(this);
connect(timeSync, SIGNAL(timeout()), this, SLOT(setRadioTimeDateSend()));
waitingToSetTimeDate = false;
lastFreqCmdTime_ms = QDateTime::currentMSecsSinceEpoch() - 5000; // 5 seconds ago
}
void wfmain::setServerToPrefs()
@ -877,6 +937,18 @@ void wfmain::setUIToPrefs()
ui->drawPeakChk->setChecked(prefs.drawPeaks);
on_drawPeakChk_clicked(prefs.drawPeaks);
drawPeaks = prefs.drawPeaks;
ui->wfAntiAliasChk->setChecked(prefs.wfAntiAlias);
on_wfAntiAliasChk_clicked(prefs.wfAntiAlias);
ui->wfInterpolateChk->setChecked(prefs.wfInterpolate);
on_wfInterpolateChk_clicked(prefs.wfInterpolate);
ui->wfLengthSlider->setValue(prefs.wflength);
prepareWf(prefs.wflength);
ui->wfthemeCombo->setCurrentIndex(ui->wfthemeCombo->findData(prefs.wftheme));
colorMap->setGradient(static_cast<QCPColorGradient::GradientPreset>(prefs.wftheme));
}
void wfmain::setAudioDevicesUI()
@ -1139,6 +1211,8 @@ void wfmain::setDefPrefs()
defPrefs.useDarkMode = true;
defPrefs.useSystemTheme = false;
defPrefs.drawPeaks = true;
defPrefs.wfAntiAlias = false;
defPrefs.wfInterpolate = true;
defPrefs.stylesheetPath = QString("qdarkstyle/style.qss");
defPrefs.radioCIVAddr = 0x00; // previously was 0x94 for 7300.
defPrefs.serialPortRadio = QString("auto");
@ -1148,6 +1222,11 @@ void wfmain::setDefPrefs()
defPrefs.enableRigCtlD = false;
defPrefs.rigCtlPort = 4533;
defPrefs.virtualSerialPort = QString("none");
defPrefs.localAFgain = 255;
defPrefs.wflength = 160;
defPrefs.wftheme = static_cast<int>(QCPColorGradient::gpJet);
defPrefs.confirmExit = true;
defPrefs.confirmPowerOff = true;
udpDefPrefs.ipAddress = QString("");
udpDefPrefs.controlLANPort = 50001;
@ -1156,7 +1235,6 @@ void wfmain::setDefPrefs()
udpDefPrefs.username = QString("");
udpDefPrefs.password = QString("");
udpDefPrefs.clientName = QHostInfo::localHostName();
}
void wfmain::loadSettings()
@ -1169,13 +1247,20 @@ void wfmain::loadSettings()
prefs.useFullScreen = settings->value("UseFullScreen", defPrefs.useFullScreen).toBool();
prefs.useDarkMode = settings->value("UseDarkMode", defPrefs.useDarkMode).toBool();
prefs.useSystemTheme = settings->value("UseSystemTheme", defPrefs.useSystemTheme).toBool();
prefs.wftheme = settings->value("WFTheme", defPrefs.wftheme).toInt();
prefs.drawPeaks = settings->value("DrawPeaks", defPrefs.drawPeaks).toBool();
prefs.wfAntiAlias = settings->value("WFAntiAlias", defPrefs.wfAntiAlias).toBool();
prefs.wfInterpolate = settings->value("WFInterpolate", defPrefs.wfInterpolate).toBool();
prefs.wflength = (unsigned int) settings->value("WFLength", defPrefs.wflength).toInt();
prefs.stylesheetPath = settings->value("StylesheetPath", defPrefs.stylesheetPath).toString();
ui->splitter->restoreState(settings->value("splitter").toByteArray());
restoreGeometry(settings->value("windowGeometry").toByteArray());
restoreState(settings->value("windowState").toByteArray());
setWindowState(Qt::WindowActive); // Works around QT bug to returns window+keyboard focus.
prefs.confirmExit = settings->value("ConfirmExit", defPrefs.confirmExit).toBool();
prefs.confirmPowerOff = settings->value("ConfirmPowerOff", defPrefs.confirmPowerOff).toBool();
settings->endGroup();
// Load color schemes:
@ -1253,7 +1338,8 @@ void wfmain::loadSettings()
ui->vspCombo->setCurrentIndex(ui->vspCombo->count()-1);
}
prefs.localAFgain = (unsigned char) settings->value("localAFgain", defPrefs.localAFgain).toUInt();
rxSetup.localAFgain = prefs.localAFgain;
settings->endGroup();
// Misc. user settings (enable PTT, draw peaks, etc)
@ -1309,7 +1395,7 @@ void wfmain::loadSettings()
txSetup.latency = settings->value("AudioTXLatency", "150").toInt();
ui->txLatencySlider->setEnabled(ui->lanEnableBtn->isChecked());
ui->txLatencySlider->setValue(rxSetup.latency);
ui->txLatencySlider->setValue(txSetup.latency);
ui->txLatencySlider->setTracking(false); // Stop it sending value on every change.
ui->audioSampleRateCombo->blockSignals(true);
@ -1461,10 +1547,16 @@ void wfmain::saveSettings()
settings->setValue("UseSystemTheme", prefs.useSystemTheme);
settings->setValue("UseDarkMode", prefs.useDarkMode);
settings->setValue("DrawPeaks", prefs.drawPeaks);
settings->setValue("WFAntiAlias", prefs.wfAntiAlias);
settings->setValue("WFInterpolate", prefs.wfInterpolate);
settings->setValue("WFTheme", prefs.wftheme);
settings->setValue("StylesheetPath", prefs.stylesheetPath);
settings->setValue("splitter", ui->splitter->saveState());
settings->setValue("windowGeometry", saveGeometry());
settings->setValue("windowState", saveState());
settings->setValue("WFLength", prefs.wflength);
settings->setValue("ConfirmExit", prefs.confirmExit);
settings->setValue("ConfirmPowerOff", prefs.confirmPowerOff);
settings->endGroup();
// Radio and Comms: C-IV addr, port to use
@ -1473,6 +1565,7 @@ void wfmain::saveSettings()
settings->setValue("SerialPortRadio", prefs.serialPortRadio);
settings->setValue("SerialPortBaud", prefs.serialPortBaud);
settings->setValue("VirtualSerialPort", prefs.virtualSerialPort);
settings->setValue("localAFgain", prefs.localAFgain);
settings->endGroup();
// Misc. user settings (enable PTT, draw peaks, etc)
@ -1781,7 +1874,7 @@ void wfmain::shortcutF10()
void wfmain::shortcutF12()
{
// Speak current frequency and mode via IC-7300
// Speak current frequency and mode from the radio
showStatusBarText("Sending speech command to radio.");
emit sayAll();
}
@ -1797,8 +1890,8 @@ void wfmain::shortcutControlT()
void wfmain::shortcutControlR()
{
// Receive
emit setPTT(false);
issueDelayedCommand(cmdGetPTT);
issueCmdUniquePriority(cmdSetPTT, false);
pttTimer->stop();
}
void wfmain::shortcutControlI()
@ -2238,6 +2331,7 @@ void wfmain::doCmd(commandtype cmddata)
{
case cmdSetFreq:
{
lastFreqCmdTime_ms = QDateTime::currentMSecsSinceEpoch();
freqt f = (*std::static_pointer_cast<freqt>(data));
emit setFrequency(f);
break;
@ -2295,6 +2389,12 @@ void wfmain::doCmd(commandtype cmddata)
{
bool pttrequest = (*std::static_pointer_cast<bool>(data));
emit setPTT(pttrequest);
if(pttrequest)
{
ui->meterSPoWidget->setMeterType(meterPower);
} else {
ui->meterSPoWidget->setMeterType(meterS);
}
break;
}
case cmdSetATU:
@ -2303,6 +2403,24 @@ void wfmain::doCmd(commandtype cmddata)
emit setATU(atuOn);
break;
}
case cmdSetUTCOffset:
{
timekind u = (*std::static_pointer_cast<timekind>(data));
emit setUTCOffset(u);
break;
}
case cmdSetTime:
{
timekind t = (*std::static_pointer_cast<timekind>(data));
emit setTime(t);
break;
}
case cmdSetDate:
{
datekind d = (*std::static_pointer_cast<datekind>(data));
emit setDate(d);
break;
}
default:
doCmd(cmd);
break;
@ -2454,10 +2572,18 @@ void wfmain::doCmd(cmds cmd)
if(!amTransmitting)
emit getMeters(meterS);
break;
case cmdGetCenterMeter:
if(!amTransmitting)
emit getMeters(meterCenter);
break;
case cmdGetPowerMeter:
if(amTransmitting)
emit getMeters(meterPower);
break;
case cmdGetSWRMeter:
if(amTransmitting)
emit getMeters(meterSWR);
break;
case cmdGetIdMeter:
emit getMeters(meterCurrent);
break;
@ -2594,10 +2720,27 @@ void wfmain::issueCmd(cmds cmd, freqt f)
commandtype cmddata;
cmddata.cmd = cmd;
cmddata.data = std::shared_ptr<freqt>(new freqt(f));
//*static_cast<freqt*>(cmddata.data.get()) = f;
delayedCmdQue.push_back(cmddata);
}
void wfmain::issueCmd(cmds cmd, timekind t)
{
qDebug(logSystem()) << "Issuing timekind command with data: " << t.hours << " hours, " << t.minutes << " minutes, " << t.isMinus << " isMinus";
commandtype cmddata;
cmddata.cmd = cmd;
cmddata.data = std::shared_ptr<timekind>(new timekind(t));
delayedCmdQue.push_front(cmddata);
}
void wfmain::issueCmd(cmds cmd, datekind d)
{
qDebug(logSystem()) << "Issuing datekind command with data: " << d.day << " day, " << d.month << " month, " << d.year << " year.";
commandtype cmddata;
cmddata.cmd = cmd;
cmddata.data = std::shared_ptr<datekind>(new datekind(d));
delayedCmdQue.push_front(cmddata);
}
void wfmain::issueCmd(cmds cmd, int i)
{
commandtype cmddata;
@ -2702,6 +2845,7 @@ void wfmain::receiveRigID(rigCapabilities rigCaps)
this->rigCaps = rigCaps;
rigName->setText(rigCaps.modelName);
setWindowTitle(rigCaps.modelName);
this->spectWidth = rigCaps.spectLenMax; // used once haveRigCaps is true.
haveRigCaps = true;
// Added so that server receives rig capabilities.
@ -2809,6 +2953,9 @@ void wfmain::receiveRigID(rigCapabilities rigCaps)
ui->antennaSelCombo->setDisabled(true);
}
ui->rxAntennaCheck->setEnabled(rigCaps.hasRXAntenna);
ui->rxAntennaCheck->setChecked(false);
ui->scopeBWCombo->blockSignals(true);
ui->scopeBWCombo->clear();
if(rigCaps.hasSpectrum)
@ -2823,14 +2970,17 @@ void wfmain::receiveRigID(rigCapabilities rigCaps)
}
ui->scopeBWCombo->blockSignals(false);
setBandButtons();
ui->tuneEnableChk->setEnabled(rigCaps.hasATU);
ui->tuneNowBtn->setEnabled(rigCaps.hasATU);
ui->connectBtn->setText("Disconnect"); // We must be connected now.
prepareWf();
prepareWf(ui->wfLengthSlider->value());
if(usingLAN)
{
ui->afGainSlider->setValue(prefs.localAFgain);
}
// Adding these here because clearly at this point we have valid
// rig comms. In the future, we should establish comms and then
// do all the initial grabs. For now, this hack of adding them here and there:
@ -2858,6 +3008,9 @@ void wfmain::initPeriodicCommands()
insertSlowPeriodicCommand(cmdGetAttenuator, 128);
insertSlowPeriodicCommand(cmdGetPTT, 128);
insertSlowPeriodicCommand(cmdGetPreamp, 128);
if (rigCaps.hasRXAntenna) {
insertSlowPeriodicCommand(cmdGetAntenna, 128);
}
}
void wfmain::insertPeriodicCommand(cmds cmd, unsigned char priority)
@ -2873,6 +3026,31 @@ void wfmain::insertPeriodicCommand(cmds cmd, unsigned char priority)
}
}
void wfmain::insertPeriodicCommandUnique(cmds cmd)
{
// Use this function to insert a non-duplicate command
// into the fast periodic polling queue, typically
// meter commands where high refresh rates are desirable.
removePeriodicCommand(cmd);
periodicCmdQueue.push_front(cmd);
}
void wfmain::removePeriodicCommand(cmds cmd)
{
while(true)
{
auto it = std::find(this->periodicCmdQueue.begin(), this->periodicCmdQueue.end(), cmd);
if(it != periodicCmdQueue.end())
{
periodicCmdQueue.erase(it);
} else {
break;
}
}
}
void wfmain::insertSlowPeriodicCommand(cmds cmd, unsigned char priority)
{
// TODO: meaningful priority
@ -2889,10 +3067,15 @@ void wfmain::insertSlowPeriodicCommand(cmds cmd, unsigned char priority)
void wfmain::receiveFreq(freqt freqStruct)
{
//qInfo(logSystem()) << "HEY WE GOT A Frequency: " << freqMhz;
ui->freqLabel->setText(QString("%1").arg(freqStruct.MHzDouble, 0, 'f'));
freq = freqStruct;
//showStatusBarText(QString("Frequency: %1").arg(freqMhz));
qint64 tnow_ms = QDateTime::currentMSecsSinceEpoch();
if(tnow_ms - lastFreqCmdTime_ms > delayedCommand->interval() * 2)
{
ui->freqLabel->setText(QString("%1").arg(freqStruct.MHzDouble, 0, 'f'));
freq = freqStruct;
} else {
qDebug(logSystem()) << "Rejecting stale frequency: " << freqStruct.Hz << " Hz, delta time ms = " << tnow_ms - lastFreqCmdTime_ms\
<< ", tnow_ms " << tnow_ms << ", last: " << lastFreqCmdTime_ms;
}
}
void wfmain::receivePTTstatus(bool pttOn)
@ -3036,20 +3219,23 @@ void wfmain::receiveSpectrumMode(spectrumMode spectMode)
void wfmain::handlePlotDoubleClick(QMouseEvent *me)
{
double x;
freqt freq;
freqt freqGo;
//double y;
//double px;
if(!freqLock)
{
//y = plot->yAxis->pixelToCoord(me->pos().y());
x = plot->xAxis->pixelToCoord(me->pos().x());
freq.Hz = x*1E6;
freqGo.Hz = x*1E6;
freq.Hz = roundFrequency(freq.Hz, tsWfScrollHz);
freqGo.Hz = roundFrequency(freqGo.Hz, tsWfScrollHz);
freqGo.MHzDouble = (float)freqGo.Hz / 1E6;
//emit setFrequency(freq);
issueCmd(cmdSetFreq, freq);
issueDelayedCommand(cmdGetFreq);
issueCmd(cmdSetFreq, freqGo);
freq = freqGo;
setUIFreq();
//issueDelayedCommand(cmdGetFreq);
showStatusBarText(QString("Going to %1 MHz").arg(x));
}
}
@ -3057,7 +3243,7 @@ void wfmain::handlePlotDoubleClick(QMouseEvent *me)
void wfmain::handleWFDoubleClick(QMouseEvent *me)
{
double x;
freqt freq;
freqt freqGo;
//double y;
//x = wf->xAxis->pixelToCoord(me->pos().x());
//y = wf->yAxis->pixelToCoord(me->pos().y());
@ -3065,13 +3251,15 @@ void wfmain::handleWFDoubleClick(QMouseEvent *me)
if(!freqLock)
{
x = plot->xAxis->pixelToCoord(me->pos().x());
freq.Hz = x*1E6;
freqGo.Hz = x*1E6;
freq.Hz = roundFrequency(freq.Hz, tsWfScrollHz);
freqGo.Hz = roundFrequency(freqGo.Hz, tsWfScrollHz);
freqGo.MHzDouble = (float)freqGo.Hz / 1E6;
//emit setFrequency(freq);
issueCmd(cmdSetFreq, freq);
issueDelayedCommand(cmdGetFreq);
issueCmd(cmdSetFreq, freqGo);
freq = freqGo;
setUIFreq();
showStatusBarText(QString("Going to %1 MHz").arg(x));
}
}
@ -3126,7 +3314,7 @@ void wfmain::handleWFScroll(QWheelEvent *we)
//emit setFrequency(f);
issueCmdUniquePriority(cmdSetFreq, f);
ui->freqLabel->setText(QString("%1").arg(f.MHzDouble, 0, 'f'));
issueDelayedCommandUnique(cmdGetFreq);
//issueDelayedCommandUnique(cmdGetFreq);
}
void wfmain::handlePlotScroll(QWheelEvent *we)
@ -3245,32 +3433,32 @@ void wfmain::on_goFreqBtn_clicked()
{
freqt f;
bool ok = false;
double freq = 0;
double freqDbl = 0;
int KHz = 0;
if(ui->freqMhzLineEdit->text().contains("."))
{
freq = ui->freqMhzLineEdit->text().toDouble(&ok);
freqDbl = ui->freqMhzLineEdit->text().toDouble(&ok);
if(ok)
{
f.Hz = freq*1E6;
//emit setFrequency(f);
issueCmd(cmdSetFreq, f);
//issueCmdSetFreq(f);
issueDelayedCommand(cmdGetFreq);
f.Hz = freqDbl*1E6;
issueCmd(cmdSetFreq, f);
}
} else {
KHz = ui->freqMhzLineEdit->text().toInt(&ok);
if(ok)
{
f.Hz = KHz*1E3;
//issueCmdSetFreq(f);
//emit setFrequency(f);
issueCmd(cmdSetFreq, f);
issueDelayedCommand(cmdGetFreq);
}
}
if(ok)
{
f.MHzDouble = (float)f.Hz / 1E6;
freq = f;
setUIFreq();
}
ui->freqMhzLineEdit->selectAll();
freqTextSelected = true;
@ -3550,17 +3738,19 @@ void wfmain::on_freqDial_valueChanged(int value)
}
}
void wfmain::receiveBandStackReg(freqt freq, char mode, char filter, bool dataOn)
void wfmain::receiveBandStackReg(freqt freqGo, char mode, char filter, bool dataOn)
{
// read the band stack and apply by sending out commands
qInfo(logSystem()) << __func__ << "BSR received into main: Freq: " << freq.Hz << ", mode: " << (unsigned int)mode << ", filter: " << (unsigned int)filter << ", data mode: " << dataOn;
qInfo(logSystem()) << __func__ << "BSR received into main: Freq: " << freqGo.Hz << ", mode: " << (unsigned int)mode << ", filter: " << (unsigned int)filter << ", data mode: " << dataOn;
//emit setFrequency(freq);
issueCmd(cmdSetFreq, freq);
issueCmd(cmdSetFreq, freqGo);
setModeVal = (unsigned char) mode;
setFilterVal = (unsigned char) filter;
issueDelayedCommand(cmdSetModeFilter);
freq = freqGo;
setUIFreq();
if(dataOn)
{
@ -3568,8 +3758,8 @@ void wfmain::receiveBandStackReg(freqt freq, char mode, char filter, bool dataOn
} else {
issueDelayedCommand(cmdSetDataModeOff);
}
issueDelayedCommand(cmdGetFreq);
issueDelayedCommand(cmdGetMode);
//issueDelayedCommand(cmdGetFreq);
//issueDelayedCommand(cmdGetMode);
ui->tabWidget->setCurrentIndex(0);
receiveMode((unsigned char) mode, (unsigned char) filter); // update UI
@ -3737,58 +3927,9 @@ void wfmain::on_bandGenbtn_clicked()
void wfmain::on_aboutBtn_clicked()
{
QMessageBox msgBox(this);
msgBox.setWindowTitle("Abou wfview");
msgBox.setTextFormat(Qt::RichText);
msgBox.setWindowIcon(QIcon(":resources/wfview.png"));
// TODO: change style of link color based on current CSS sheet.
abtBox->show();
QString head = QString("<html><head></head><body>");
QString copyright = QString("Copyright 2017-2021 Elliott H. Liggett, W6EL. All rights reserved.");
QString nacode = QString("<br/><br/>Networking and audio code written by Phil Taylor, M0VSE");
QString doctest = QString("<br/><br/>Testing, documentation, bug fixes, and development mentorship from<br/>Roeland Jansen, PA3MET, and Jim Nijkamp, PA8E.");
QString ssCredit = QString("<br/><br/>Stylesheet <a href=\"https://github.com/ColinDuquesnoy/QDarkStyleSheet/tree/master/qdarkstyle\" style=\"color: cyan;\">qdarkstyle</a> used under MIT license, stored in /usr/share/wfview/stylesheets/.");
QString rsCredit = QString("<br/><br/><a href=\"https://www.speex.org/\" style=\"color: cyan;\">Speex</a> Resample library Copyright 2003-2008 Jean-Marc Valin");
QString website = QString("<br/><br/>Please visit <a href=\"https://wfview.org/\" style=\"color: cyan;\">https://wfview.org/</a> for the latest information.");
QString docs = QString("<br/><br/>Be sure to check the <a href=\"https://wfview.org/wfview-user-manual/\" style=\"color: cyan;\">User Manual</a> and <a href=\"https://forum.wfview.org/\" style=\"color: cyan;\">the Forum</a> if you have any questions.");
QString gitcodelink = QString("<a href=\"https://gitlab.com/eliggett/wfview/-/tree/%1\" style=\"color: cyan;\">").arg(GITSHORT);
QString contact = QString("<br/>email the author: kilocharlie8@gmail.com or W6EL on the air!");
QString buildInfo = QString("<br/><br/>Build " + gitcodelink + QString(GITSHORT) + "</a> on " + QString(__DATE__) + " at " + __TIME__ + " by " + UNAME + "@" + HOST);
QString end = QString("</body></html>");
QString aboutText = head + copyright + "\n" + nacode + "\n" + doctest + "\n" + ssCredit + "\n" + rsCredit + "\n";
aboutText.append(website + "\n"+ docs + contact +"\n" + buildInfo + end);
msgBox.setText(aboutText);
msgBox.exec();
volatile QString sxcreditcopyright = QString("Speex copyright notice:\
Copyright (C) 2003 Jean-Marc Valin\n\
Redistribution and use in source and binary forms, with or without\
modification, are permitted provided that the following conditions\
are met:\n\
- Redistributions of source code must retain the above copyright\
notice, this list of conditions and the following disclaimer.\n\
- Redistributions in binary form must reproduce the above copyright\
notice, this list of conditions and the following disclaimer in the\
documentation and/or other materials provided with the distribution.\n\
- Neither the name of the Xiph.org Foundation nor the names of its\
contributors may be used to endorse or promote products derived from\
this software without specific prior written permission.\n\
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR\
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.");
}
@ -3840,7 +3981,6 @@ void wfmain::on_fRclBtn_clicked()
setModeVal = temp.mode;
setFilterVal = ui->modeFilterCombo->currentIndex()+1; // TODO, add to memory
issueDelayedCommand(cmdSetModeFilter);
issueDelayedCommand(cmdGetFreq);
issueDelayedCommand(cmdGetMode);
} else {
qInfo(logSystem()) << "Could not recall preset. Valid presets are 0 through 99.";
@ -3856,6 +3996,11 @@ void wfmain::on_rfGainSlider_valueChanged(int value)
void wfmain::on_afGainSlider_valueChanged(int value)
{
issueCmdUniquePriority(cmdSetAfGain, (unsigned char)value);
if(usingLAN)
{
rxSetup.localAFgain = (unsigned char)(value);
prefs.localAFgain = (unsigned char)(value);
}
}
void wfmain::receiveRfGain(unsigned char level)
@ -4019,7 +4164,7 @@ void wfmain::on_lanEnableBtn_clicked(bool checked)
//ui->udpServerSetupBtn->setEnabled(false);
if(checked)
{
showStatusBarText("After filling in values, press Save Settings and re-start wfview.");
showStatusBarText("After filling in values, press Save Settings.");
}
}
@ -4216,6 +4361,57 @@ void wfmain::on_satOpsBtn_clicked()
sat->show();
}
void wfmain::setRadioTimeDatePrep()
{
if(!waitingToSetTimeDate)
{
// 1: Find the current time and date
QDateTime now = QDateTime::currentDateTime();
now.setTime(QTime::currentTime());
int second = now.time().second();
// 2: Find how many mseconds until next minute
int msecdelay = QTime::currentTime().msecsTo( QTime::currentTime().addSecs(60-second) );
// 3: Compute time and date at one minute later
QDateTime setpoint = now.addMSecs(msecdelay); // at HMS or posibly HMS + some ms. Never under though.
// 4: Prepare data structs for the time at one minute later
timesetpoint.hours = (unsigned char)setpoint.time().hour();
timesetpoint.minutes = (unsigned char)setpoint.time().minute();
datesetpoint.day = (unsigned char)setpoint.date().day();
datesetpoint.month = (unsigned char)setpoint.date().month();
datesetpoint.year = (uint16_t)setpoint.date().year();
unsigned int utcOffsetSeconds = (unsigned int)abs(setpoint.offsetFromUtc());
bool isMinus = setpoint.offsetFromUtc() < 0;
utcsetting.hours = utcOffsetSeconds / 60 / 60;
utcsetting.minutes = (utcOffsetSeconds - (utcsetting.hours*60*60) ) / 60;
utcsetting.isMinus = isMinus;
timeSync->setInterval(msecdelay);
timeSync->setSingleShot(true);
// 5: start one-shot timer for the delta computed in #2.
timeSync->start();
waitingToSetTimeDate = true;
showStatusBarText(QString("Setting time, date, and UTC offset for radio in %1 seconds.").arg(msecdelay/1000));
}
}
void wfmain::setRadioTimeDateSend()
{
// Issue priority commands for UTC offset, date, and time
// UTC offset must come first, otherwise the radio may "help" and correct for any changes.
showStatusBarText(QString("Setting time, date, and UTC offset for radio now."));
issueCmd(cmdSetTime, timesetpoint);
issueCmd(cmdSetDate, datesetpoint);
issueCmd(cmdSetUTCOffset, utcsetting);
waitingToSetTimeDate = false;
}
void wfmain::changeSliderQuietly(QSlider *slider, int value)
{
slider->blockSignals(true);
@ -4355,54 +4551,23 @@ void wfmain::receiveLANGain(unsigned char level)
void wfmain::receiveMeter(meterKind inMeter, unsigned char level)
{
unsigned int peak = 0;
unsigned int sum=0;
unsigned int average=0;
switch(inMeter)
{
case meterS:
SMeterReadings[(smeterPos++)%SMeterReadings.length()] = level;
for(int i=0; i < SMeterReadings.length(); i++)
{
if((unsigned char)SMeterReadings.at(i) > peak)
peak = (unsigned char)SMeterReadings.at(i);
sum += (unsigned char)SMeterReadings.at(i);
}
average = sum / SMeterReadings.length();
ui->meterWidget->setLevels(level, peak, average);
ui->meterWidget->repaint();
//ui->levelIndicator->setValue((int)level);
break;
case meterSWR:
//ui->levelIndicator->setValue((int)level);
ui->meterSPoWidget->setMeterType(meterS);
ui->meterSPoWidget->setLevel(level);
ui->meterSPoWidget->repaint();
break;
case meterPower:
powerMeterReadings[(powerMeterPos++)%powerMeterReadings.length()] = level;
for(int i=0; i < powerMeterReadings.length(); i++)
{
if((unsigned char)powerMeterReadings.at(i) > peak)
peak = (unsigned char)powerMeterReadings.at(i);
sum += (unsigned char)powerMeterReadings.at(i);
}
average = sum / powerMeterReadings.length();
ui->meterWidget->setLevels(level, peak, average);
ui->meterWidget->update();
//ui->levelIndicator->setValue((int)level);
break;
case meterALC:
//ui->levelIndicator->setValue((int)level);
break;
case meterComp:
//ui->levelIndicator->setValue((int)level);
break;
case meterCurrent:
//ui->levelIndicator->setValue((int)level);
break;
case meterVoltage:
//ui->levelIndicator->setValue((int)level);
ui->meterSPoWidget->setMeterType(meterPower);
ui->meterSPoWidget->setLevel(level);
ui->meterSPoWidget->update();
break;
default:
if(ui->meter2Widget->getMeterType() == inMeter)
{
ui->meter2Widget->setLevel(level);
}
break;
}
}
@ -4611,12 +4776,18 @@ void wfmain::on_preampSelCombo_activated(int index)
void wfmain::on_antennaSelCombo_activated(int index)
{
unsigned char ant = (unsigned char)ui->antennaSelCombo->itemData(index).toInt();
emit setAntenna(ant);
emit setAntenna(ant,ui->rxAntennaCheck->isChecked());
}
void wfmain::on_rxAntennaCheck_clicked(bool value)
{
unsigned char ant = (unsigned char)ui->antennaSelCombo->itemData(ui->antennaSelCombo->currentIndex()).toInt();
emit setAntenna(ant, value);
}
void wfmain::on_wfthemeCombo_activated(int index)
{
colorMap->setGradient(static_cast<QCPColorGradient::GradientPreset>(ui->wfthemeCombo->itemData(index).toInt()));
prefs.wftheme = ui->wfthemeCombo->itemData(index).toInt();
}
void wfmain::receivePreamp(unsigned char pre)
@ -4631,6 +4802,12 @@ void wfmain::receiveAttenuator(unsigned char att)
ui->attSelCombo->setCurrentIndex(attindex);
}
void wfmain::receiveAntennaSel(unsigned char ant, bool rx)
{
ui->antennaSelCombo->setCurrentIndex(ant);
ui->rxAntennaCheck->setChecked(rx);
}
void wfmain::receiveSpectrumSpan(freqt freqspan, bool isSub)
{
if(!isSub)
@ -4728,10 +4905,37 @@ void wfmain::on_rigPowerOnBtn_clicked()
void wfmain::on_rigPowerOffBtn_clicked()
{
QMessageBox::StandardButton reply;
reply = QMessageBox::question(this, "Power", "Power down the radio?",
QMessageBox::Yes|QMessageBox::No);
if (reply == QMessageBox::Yes) {
// Are you sure?
if (!prefs.confirmPowerOff) {
powerRigOff();
return;
}
QCheckBox* cb = new QCheckBox("Don't ask me again");
QMessageBox msgbox;
msgbox.setWindowTitle("Power");
msgbox.setText("Power down the radio?\n");
msgbox.setIcon(QMessageBox::Icon::Question);
QAbstractButton* yesButton = msgbox.addButton(QMessageBox::Yes);
msgbox.addButton(QMessageBox::No);
msgbox.setDefaultButton(QMessageBox::Yes);
msgbox.setCheckBox(cb);
QObject::connect(cb, &QCheckBox::stateChanged, [this](int state) {
if (static_cast<Qt::CheckState>(state) == Qt::CheckState::Checked) {
prefs.confirmPowerOff = false;
}
else {
prefs.confirmPowerOff = true;
}
settings->beginGroup("Interface");
settings->setValue("ConfirmPowerOff", this->prefs.confirmPowerOff);
settings->endGroup();
settings->sync();
});
msgbox.exec();
if (msgbox.clickedButton() == yesButton) {
powerRigOff();
}
}
@ -4949,6 +5153,7 @@ void wfmain::on_baudRateCombo_activated(int index)
void wfmain::on_wfLengthSlider_valueChanged(int value)
{
prefs.wflength = (unsigned int)(value);
prepareWf(value);
}
@ -4966,12 +5171,92 @@ void wfmain::on_pollingBtn_clicked()
}
}
void wfmain::on_wfAntiAliasChk_clicked(bool checked)
{
colorMap->setAntialiased(checked);
prefs.wfAntiAlias = checked;
}
void wfmain::on_wfInterpolateChk_clicked(bool checked)
{
colorMap->setInterpolate(checked);
prefs.wfInterpolate = checked;
}
wfmain::cmds wfmain::meterKindToMeterCommand(meterKind m)
{
cmds c;
switch(m)
{
case meterNone:
c = cmdNone;
break;
case meterS:
c = cmdGetSMeter;
break;
case meterCenter:
c = cmdGetCenterMeter;
break;
case meterPower:
c = cmdGetPowerMeter;
break;
case meterSWR:
c = cmdGetSWRMeter;
break;
case meterALC:
c = cmdGetALCMeter;
break;
case meterComp:
c = cmdGetCompMeter;
break;
case meterCurrent:
c = cmdGetIdMeter;
break;
case meterVoltage:
c = cmdGetVdMeter;
break;
default:
c = cmdNone;
break;
}
return c;
}
void wfmain::on_meter2selectionCombo_activated(int index)
{
meterKind newMeterType;
meterKind oldMeterType;
newMeterType = static_cast<meterKind>(ui->meter2selectionCombo->currentData().toInt());
oldMeterType = ui->meter2Widget->getMeterType();
if(newMeterType == oldMeterType)
return;
cmds newCmd = meterKindToMeterCommand(newMeterType);
cmds oldCmd = meterKindToMeterCommand(oldMeterType);
removePeriodicCommand(oldCmd);
if(newMeterType==meterNone)
{
ui->meter2Widget->hide();
} else {
ui->meter2Widget->show();
ui->meter2Widget->setMeterType(newMeterType);
insertPeriodicCommandUnique(newCmd);
}
(void)index;
}
// --- DEBUG FUNCTION ---
void wfmain::on_debugBtn_clicked()
{
qInfo(logSystem()) << "Debug button pressed.";
freqt f;
f.Hz = 14290000;
issueCmd(cmdSetFreq, f);
}
//trxadj->show();
//setRadioTimeDatePrep();
//wf->setInteraction(QCP::iRangeZoom, true);
//wf->setInteraction(QCP::iRangeDrag, true);
}

Wyświetl plik

@ -21,10 +21,12 @@
#include "calibrationwindow.h"
#include "repeatersetup.h"
#include "satellitesetup.h"
#include "transceiveradjustments.h"
#include "udpserversetup.h"
#include "udpserver.h"
#include "qledlabel.h"
#include "rigctld.h"
#include "aboutbox.h"
#include <qcustomplot.h>
#include <qserialportinfo.h>
@ -118,11 +120,16 @@ signals:
void getAntenna();
void setAttenuator(unsigned char att);
void setPreamp(unsigned char pre);
void setAntenna(unsigned char ant);
void setAntenna(unsigned char ant, bool rx);
void startATU();
void setATU(bool atuEnabled);
void getATUStatus();
// Time and date:
void setTime(timekind t);
void setDate(datekind d);
void setUTCOffset(timekind t);
void getRigID(); // this is the model of the rig
void getRigCIV(); // get the rig's CIV addr
void spectOutputEnable();
@ -227,7 +234,7 @@ private slots:
void receiveATUStatus(unsigned char atustatus);
void receivePreamp(unsigned char pre);
void receiveAttenuator(unsigned char att);
//void receiveAntennaSel(unsigned char ant);
void receiveAntennaSel(unsigned char ant, bool rx);
void receiveRigID(rigCapabilities rigCaps);
void receiveFoundRigID(rigCapabilities rigCaps);
void receiveSerialPortError(QString port, QString errorText);
@ -243,6 +250,9 @@ private slots:
void serverConfigRequested(SERVERCONFIG conf, bool store);
void receiveBaudRate(quint32 baudrate);
void setRadioTimeDateSend();
// void on_getFreqBtn_clicked();
// void on_getModeBtn_clicked();
@ -418,6 +428,8 @@ private slots:
void on_antennaSelCombo_activated(int index);
void on_rxAntennaCheck_clicked(bool value);
void on_wfthemeCombo_activated(int index);
void on_rigPowerOnBtn_clicked();
@ -454,6 +466,12 @@ private slots:
void on_pollingBtn_clicked();
void on_wfAntiAliasChk_clicked(bool checked);
void on_wfInterpolateChk_clicked(bool checked);
void on_meter2selectionCombo_activated(int index);
private:
Ui::wfmain *ui;
void closeEvent(QCloseEvent *event);
@ -560,12 +578,6 @@ private:
QByteArray spectrumPeaks;
QByteArray powerMeterReadings;
int powerMeterPos = 0;
QByteArray SMeterReadings;
int smeterPos=0;
QVector <QByteArray> wfimage;
unsigned int wfLengthMax;
@ -588,8 +600,9 @@ private:
cmdGetSql, cmdSetSql, cmdGetATUStatus, cmdSetATU, cmdStartATU, cmdGetSpectrumMode, cmdGetSpectrumSpan, cmdScopeCenterMode, cmdScopeFixedMode, cmdGetPTT, cmdSetPTT,
cmdGetTxPower, cmdSetTxPower, cmdGetMicGain, cmdSetMicGain, cmdSetModLevel, cmdGetSpectrumRefLevel, cmdGetDuplexMode, cmdGetModInput, cmdGetModDataInput,
cmdGetCurrentModLevel, cmdStartRegularPolling, cmdStopRegularPolling, cmdQueNormalSpeed,
cmdGetVdMeter, cmdGetIdMeter, cmdGetSMeter, cmdGetPowerMeter, cmdGetALCMeter, cmdGetCompMeter, cmdGetTxRxMeter,
cmdGetTone, cmdGetTSQL, cmdGetDTCS, cmdGetRptAccessMode, cmdGetPreamp, cmdGetAttenuator, cmdGetAntenna};
cmdGetVdMeter, cmdGetIdMeter, cmdGetSMeter, cmdGetCenterMeter, cmdGetPowerMeter, cmdGetSWRMeter, cmdGetALCMeter, cmdGetCompMeter, cmdGetTxRxMeter,
cmdGetTone, cmdGetTSQL, cmdGetDTCS, cmdGetRptAccessMode, cmdGetPreamp, cmdGetAttenuator, cmdGetAntenna,
cmdSetTime, cmdSetDate, cmdSetUTCOffset};
struct commandtype {
cmds cmd;
@ -604,6 +617,8 @@ private:
void issueCmd(cmds cmd, freqt f);
void issueCmd(cmds cmd, mode_info m);
void issueCmd(cmds cmd, timekind t);
void issueCmd(cmds cmd, datekind d);
void issueCmd(cmds cmd, int i);
void issueCmd(cmds cmd, unsigned char c);
void issueCmd(cmds cmd, char c);
@ -617,6 +632,8 @@ private:
void removeSimilarCommand(cmds cmd);
qint64 lastFreqCmdTime_ms;
int pCmdNum = 0;
int delayedCmdIntervalLAN_ms = 100;
int delayedCmdIntervalSerial_ms = 100;
@ -624,6 +641,14 @@ private:
bool runPeriodicCommands;
bool usingLAN = false;
// Radio time sync:
QTimer *timeSync;
bool waitingToSetTimeDate;
void setRadioTimeDatePrep();
timekind timesetpoint;
timekind utcsetting;
datekind datesetpoint;
freqMemory mem;
struct colors {
QColor Dark_PlotBackground;
@ -655,6 +680,8 @@ private:
bool useDarkMode;
bool useSystemTheme;
bool drawPeaks;
bool wfAntiAlias;
bool wfInterpolate;
QString stylesheetPath;
unsigned char radioCIVAddr;
QString serialPortRadio;
@ -666,6 +693,12 @@ private:
quint16 rigCtlPort;
colors colorScheme;
QString virtualSerialPort;
unsigned char localAFgain;
unsigned int wflength;
int wftheme;
bool confirmExit;
bool confirmPowerOff;
// plot scheme
} prefs;
preferences defPrefs;
@ -707,14 +740,20 @@ private:
void changeModLabelAndSlider(rigInput source);
// Fast command queue:
void initPeriodicCommands();
void insertPeriodicCommand(cmds cmd, unsigned char priority);
void insertPeriodicCommandUnique(cmds cmd);
void removePeriodicCommand(cmds cmd);
void insertSlowPeriodicCommand(cmds cmd, unsigned char priority);
void calculateTimingParameters();
void changeMode(mode_kind mode);
void changeMode(mode_kind mode, bool dataOn);
cmds meterKindToMeterCommand(meterKind m);
int oldFreqDialVal;
rigCapabilities rigCaps;
@ -737,7 +776,10 @@ private:
calibrationWindow *cal;
repeaterSetup *rpt;
satelliteSetup *sat;
transceiverAdjustments *trxadj;
udpServerSetup *srv;
aboutbox *abtBox;
udpServer* udp = Q_NULLPTR;
rigCtlD* rigCtl = Q_NULLPTR;
@ -776,6 +818,8 @@ Q_DECLARE_METATYPE(struct udpPreferences)
Q_DECLARE_METATYPE(struct rigStateStruct)
Q_DECLARE_METATYPE(struct audioPacket)
Q_DECLARE_METATYPE(struct audioSetup)
Q_DECLARE_METATYPE(struct timekind)
Q_DECLARE_METATYPE(struct datekind)
Q_DECLARE_METATYPE(enum rigInput)
Q_DECLARE_METATYPE(enum meterKind)
Q_DECLARE_METATYPE(enum spectrumMode)

Wyświetl plik

@ -141,8 +141,11 @@
</item>
<item>
<widget class="QComboBox" name="wfthemeCombo">
<property name="toolTip">
<string>Waterfall color theme</string>
</property>
<property name="accessibleName">
<string>Spectrum color theme</string>
<string>Waterfall display color theme</string>
</property>
<property name="accessibleDescription">
<string>Selects the theme for the color waterfall dispaly</string>
@ -238,9 +241,18 @@
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_21">
<layout class="QVBoxLayout" name="meterLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="topMargin">
<number>10</number>
</property>
<property name="bottomMargin">
<number>10</number>
</property>
<item>
<widget class="meter" name="meterWidget" native="true">
<widget class="meter" name="meterSPoWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -255,6 +267,9 @@
</property>
</widget>
</item>
<item>
<widget class="meter" name="meter2Widget" native="true"/>
</item>
</layout>
</item>
<item>
@ -990,6 +1005,16 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="rxAntennaCheck">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>RX</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
@ -2051,6 +2076,23 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="wfAntiAliasChk">
<property name="text">
<string>Anti-Alias Waterfall</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="wfInterpolateChk">
<property name="text">
<string>Interpolate Waterfall</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="fullScreenChk">
<property name="text">
@ -2179,6 +2221,16 @@
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="secondaryMeterSelectionLabel">
<property name="text">
<string>Secondary Meter Selection:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="meter2selectionCombo"/>
</item>
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
@ -2678,7 +2730,7 @@
<item>
<widget class="QLabel" name="label_33">
<property name="text">
<string>Please note: Changing CI-V Address, Serial Device, and Baud rate requires pressing &quot;Save Settings&quot;, closing wfview, and re-opening. </string>
<string>Please note: Changing the built-in network server requires pressing &quot;Save Settings&quot;, closing wfview, and re-opening. </string>
</property>
</widget>
</item>
@ -2730,7 +2782,7 @@
<x>0</x>
<y>0</y>
<width>934</width>
<height>22</height>
<height>21</height>
</rect>
</property>
</widget>

Wyświetl plik

@ -132,7 +132,9 @@ SOURCES += main.cpp\
resampler/resample.c \
repeatersetup.cpp \
rigctld.cpp \
ring/ring.cpp
ring/ring.cpp \
transceiveradjustments.cpp \
aboutbox.cpp
HEADERS += wfmain.h \
commhandler.h \
@ -157,14 +159,19 @@ HEADERS += wfmain.h \
repeaterattributes.h \
rigctld.h \
ulaw.h \
ring/ring.h
ring/ring.h \
transceiveradjustments.h \
audiotaper.h \
aboutbox.h
FORMS += wfmain.ui \
calibrationwindow.ui \
satellitesetup.ui \
udpserversetup.ui \
repeatersetup.ui
repeatersetup.ui \
transceiveradjustments.ui \
aboutbox.ui