diff --git a/CatRadio.pro b/CatRadio.pro
new file mode 100644
index 0000000..4fdc6ae
--- /dev/null
+++ b/CatRadio.pro
@@ -0,0 +1,51 @@
+QT += core gui
+
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
+
+CONFIG += c++11
+
+# You can make your code fail to compile if it uses deprecated APIs.
+# In order to do so, uncomment the following line.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
+
+SOURCES += \
+ dialogconfig.cpp \
+ dialogsetup.cpp \
+ guidata.cpp \
+ main.cpp \
+ mainwindow.cpp \
+ rigcommand.cpp \
+ rigdaemon.cpp \
+ rigdata.cpp \
+ smeter.cpp \
+ submeter.cpp \
+ vfodisplay.cpp
+
+HEADERS += \
+ dialogconfig.h \
+ dialogsetup.h \
+ guidata.h \
+ mainwindow.h \
+ rigcommand.h \
+ rigdaemon.h \
+ rigdata.h \
+ smeter.h \
+ submeter.h \
+ vfodisplay.h
+
+FORMS += \
+ dialogconfig.ui \
+ dialogsetup.ui \
+ mainwindow.ui
+
+# Default rules for deployment.
+qnx: target.path = /tmp/$${TARGET}/bin
+else: unix:!android: target.path = /opt/$${TARGET}/bin
+!isEmpty(target.path): INSTALLS += target
+
+LIBS += -L$$PWD/hamlib/ -llibhamlib
+INCLUDEPATH += $$PWD/hamlib
+
+VERSION = 1.0.0
+
+RC_ICONS = catradio.ico
diff --git a/CatRadio.pro.user b/CatRadio.pro.user
new file mode 100644
index 0000000..7239cd7
--- /dev/null
+++ b/CatRadio.pro.user
@@ -0,0 +1,426 @@
+
+
+
+
+
+ EnvironmentId
+ {3eda28a5-2ae6-4f98-9ee1-3326cb54ce82}
+
+
+ ProjectExplorer.Project.ActiveTarget
+ 0
+
+
+ ProjectExplorer.Project.EditorSettings
+
+ true
+ false
+ true
+
+ Cpp
+
+ CppGlobal
+
+
+
+ QmlJS
+
+ QmlJSGlobal
+
+
+ 2
+ UTF-8
+ false
+ 4
+ false
+ 80
+ true
+ true
+ 1
+ false
+ true
+ false
+ 0
+ true
+ true
+ 0
+ 8
+ true
+ false
+ 1
+ true
+ true
+ true
+ *.md, *.MD, Makefile
+ false
+ true
+
+
+
+ ProjectExplorer.Project.PluginSettings
+
+
+ true
+ false
+ true
+ true
+ true
+ true
+
+
+ 0
+ true
+
+ -fno-delayed-template-parsing
+
+ true
+ Builtin.BuildSystem
+
+ true
+ true
+ Builtin.DefaultTidyAndClazy
+ 4
+
+
+
+ true
+
+
+
+
+ ProjectExplorer.Project.Target.0
+
+ Desktop
+ Desktop Qt 5.15.2 MinGW 32-bit
+ Desktop Qt 5.15.2 MinGW 32-bit
+ qt.qt5.5152.win32_mingw81_kit
+ 0
+ 0
+ 0
+
+ 0
+ C:\Users\Johnny\Documents\QT\build-CatRadio-Desktop_Qt_5_15_2_MinGW_32_bit-Debug
+ C:/Users/Johnny/Documents/QT/build-CatRadio-Desktop_Qt_5_15_2_MinGW_32_bit-Debug
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Debug
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 2
+
+
+ C:\Users\Johnny\Documents\QT\build-CatRadio-Desktop_Qt_5_15_2_MinGW_32_bit-Release
+ C:/Users/Johnny/Documents/QT/build-CatRadio-Desktop_Qt_5_15_2_MinGW_32_bit-Release
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Release
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+
+
+ 0
+ C:\Users\Johnny\Documents\QT\build-CatRadio-Desktop_Qt_5_15_2_MinGW_32_bit-Profile
+ C:/Users/Johnny/Documents/QT/build-CatRadio-Desktop_Qt_5_15_2_MinGW_32_bit-Profile
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Profile
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+ 0
+
+ 3
+
+
+ 0
+ Deploy
+ Deploy
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 1
+
+ true
+ true
+ true
+
+ 2
+
+ CatRadio2
+ Qt4ProjectManager.Qt4RunConfiguration:C:/Users/Johnny/Documents/QT/CatRadio_1.0.0/CatRadio.pro
+ C:/Users/Johnny/Documents/QT/CatRadio_1.0.0/CatRadio.pro
+ false
+ true
+ true
+ false
+ true
+ C:/Users/Johnny/Documents/QT/build-CatRadio-Desktop_Qt_5_15_2_MinGW_32_bit-Debug
+
+ 1
+
+
+
+ ProjectExplorer.Project.Target.1
+
+ Desktop
+ Desktop Qt 6.1.3 MinGW 64-bit
+ Desktop Qt 6.1.3 MinGW 64-bit
+ qt.qt6.613.win64_mingw81_kit
+ 1
+ 0
+ 0
+
+ 0
+ C:\Users\Johnny\Documents\QT\build-CatRadio-Desktop_Qt_6_1_3_MinGW_64_bit-Debug
+ C:/Users/Johnny/Documents/QT/build-CatRadio-Desktop_Qt_6_1_3_MinGW_64_bit-Debug
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Debug
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 2
+
+
+ C:\Users\Johnny\Documents\QT\build-CatRadio-Desktop_Qt_6_1_3_MinGW_64_bit-Release
+ C:/Users/Johnny/Documents/QT/build-CatRadio-Desktop_Qt_6_1_3_MinGW_64_bit-Release
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Release
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+
+
+ 0
+ C:\Users\Johnny\Documents\QT\build-CatRadio-Desktop_Qt_6_1_3_MinGW_64_bit-Profile
+ C:/Users/Johnny/Documents/QT/build-CatRadio-Desktop_Qt_6_1_3_MinGW_64_bit-Profile
+
+
+ true
+ QtProjectManager.QMakeBuildStep
+ false
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+
+ 2
+ Build
+ Build
+ ProjectExplorer.BuildSteps.Build
+
+
+
+ true
+ Qt4ProjectManager.MakeStep
+ clean
+
+ 1
+ Clean
+ Clean
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+
+ Profile
+ Qt4ProjectManager.Qt4BuildConfiguration
+ 0
+ 0
+ 0
+
+ 3
+
+
+ 0
+ Deploy
+ Deploy
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 1
+
+ true
+ true
+ true
+
+ 2
+
+ Qt4ProjectManager.Qt4RunConfiguration:C:/Users/Johnny/Documents/QT/CatRadio/CatRadio.pro
+ C:/Users/Johnny/Documents/QT/CatRadio/CatRadio.pro
+ false
+ true
+ true
+ false
+ true
+
+ 1
+
+
+
+ ProjectExplorer.Project.TargetCount
+ 2
+
+
+ ProjectExplorer.Project.Updater.FileVersion
+ 22
+
+
+ Version
+ 22
+
+
diff --git a/CatRadio.qss b/CatRadio.qss
new file mode 100644
index 0000000..b1463fe
--- /dev/null
+++ b/CatRadio.qss
@@ -0,0 +1,1249 @@
+/*Copyright (c) DevSec Studio. All rights reserved.
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+/*-----QWidget-----*/
+QWidget
+{
+ background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(102, 115, 140, 255),stop:1 rgba(56, 63, 77, 255));
+ color: #ffffff;
+ border-color: #051a39;
+
+}
+
+
+/*-----QLabel-----*/
+QLabel
+{
+ background-color: transparent;
+ color: #ffffff;
+ font-weight: bold;
+
+}
+
+
+QLabel::disabled
+{
+ background-color: transparent;
+ color: #898988;
+
+}
+
+
+/*-----QMenuBar-----*/
+QMenuBar
+{
+ background-color: #484c58;
+ color: #ffffff;
+ border-color: #051a39;
+ font-weight: bold;
+
+}
+
+
+QMenuBar::disabled
+{
+ background-color: #404040;
+ color: #898988;
+ border-color: #051a39;
+
+}
+
+
+QMenuBar::item
+{
+ background-color: transparent;
+
+}
+
+
+QMenuBar::item:selected
+{
+ background-color: #c4c5c3;
+ color: #000000;
+ border: 1px solid #000000;
+
+}
+
+
+QMenuBar::item:pressed
+{
+ background-color: #979796;
+ border: 1px solid #000;
+ margin-bottom: -1px;
+ padding-bottom: 1px;
+
+}
+
+
+/*-----QMenu-----*/
+QMenu
+{
+ background-color: #c4c5c3;
+ border: 1px solid;
+ color: #000000;
+ font-weight: bold;
+
+}
+
+
+QMenu::separator
+{
+ height: 1px;
+ background-color: #363942;
+ color: #ffffff;
+ padding-left: 4px;
+ margin-left: 10px;
+ margin-right: 5px;
+
+}
+
+
+QMenu::item
+{
+ min-width : 150px;
+ padding: 3px 20px 3px 20px;
+
+}
+
+
+QMenu::item:selected
+{
+ background-color: #363942;
+ color: #ffffff;
+
+}
+
+
+QMenu::item:disabled
+{
+ color: #898988;
+}
+
+
+/*-----QToolTip-----*/
+QToolTip
+{
+ background-color: #bbbcba;
+ color: #000000;
+ border-color: #051a39;
+ border : 1px solid #000000;
+ border-radius: 2px;
+
+}
+
+
+/*-----QPushButton-----*/
+QPushButton
+{
+ background-color: qlineargradient(spread:repeat, x1:0.486, y1:0, x2:0.505, y2:1, stop:0.00480769 rgba(170, 0, 0, 255),stop:1 rgba(122, 0, 0, 255));
+ color: #ffffff;
+ font-weight: bold;
+ border-style: solid;
+ border-width: 1px;
+ border-radius: 3px;
+ border-color: #051a39;
+ padding: 5px;
+
+}
+
+
+QPushButton::disabled
+{
+ background-color: #404040;
+ color: #656565;
+ border-color: #051a39;
+
+}
+
+
+QPushButton::hover
+{
+ background-color: #9c0000;
+ color: #ffffff;
+ border-style: solid;
+ border-width: 1px;
+ border-radius: 3px;
+ border-color: #051a39;
+ padding: 5px;
+
+}
+
+
+QPushButton::pressed
+{
+ background-color: #880000;
+ color: #ffffff;
+ border-style: solid;
+ border-width: 2px;
+ border-radius: 3px;
+ border-color: #000000;
+ padding: 5px;
+
+}
+
+
+/*-----QToolButton-----*/
+QToolButton
+{
+ background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(177, 181, 193, 255),stop:1 rgba(159, 163, 174, 255));
+ color: #ffffff;
+ font-weight: bold;
+ border-style: solid;
+ border-width: 1px;
+ border-radius: 3px;
+ border-color: #051a39;
+ padding: 5px;
+
+}
+
+
+QToolButton::disabled
+{
+ background-color: #404040;
+ color: #656565;
+ border-color: #051a39;
+
+}
+
+
+QToolButton::hover
+{
+ background-color: #9fa3ae;
+ color: #ffffff;
+ border-style: solid;
+ border-width: 1px;
+ border-radius: 3px;
+ border-color: #051a39;
+ padding: 5px;
+
+}
+
+
+QToolButton::pressed
+{
+ background-color: #7b7e86;
+ color: #ffffff;
+ border-style: solid;
+ border-width: 2px;
+ border-radius: 3px;
+ border-color: #000000;
+ padding: 5px;
+
+}
+
+
+/*-----QComboBox-----*/
+QComboBox
+{
+ background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(118, 118, 118, 255),stop:1 rgba(70, 70, 70, 255));
+ border: 1px solid #333333;
+ border-radius: 3px;
+ padding-left: 6px;
+ color: lightgray;
+ font-weight: bold;
+ height: 20px;
+
+}
+
+
+QComboBox::disabled
+{
+ background-color: #404040;
+ color: #656565;
+ border-color: #051a39;
+
+}
+
+
+QComboBox:hover
+{
+ background-color: #646464;
+
+}
+
+
+QComboBox:on
+{
+ background-color: #979796;
+ color: #000000;
+
+}
+
+
+QComboBox QAbstractItemView
+{
+ background-color: #c4c5c3;
+ color: #000000;
+ border: 1px solid black;
+ selection-background-color: #363942;
+ selection-color: #ffffff;
+ outline: 0;
+
+}
+
+
+QComboBox::drop-down
+{
+ subcontrol-origin: padding;
+ subcontrol-position: top right;
+ width: 15px;
+ border-left-width: 1px;
+ border-left-color: darkgray;
+ border-left-style: solid;
+ border-top-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+
+}
+
+
+QComboBox::down-arrow
+{
+ image: url(://arrow-down.png);
+ width: 8px;
+ height: 8px;
+}
+
+
+/*-----QSpinBox & QDoubleSpinBox & QDateTimeEdit-----*/
+QSpinBox,
+QDoubleSpinBox,
+QDateTimeEdit
+{
+ background-color: #000000;
+ color: #00ff00;
+ font-weight: bold;
+ border: 1px solid #333333;
+ padding : 4px;
+
+}
+
+
+QSpinBox::disabled,
+QDoubleSpinBox::disabled,
+QDateTimeEdit::disabled
+{
+ background-color: #404040;
+ color: #656565;
+ border-color: #051a39;
+
+}
+
+
+QSpinBox:hover,
+QDoubleSpinBox::hover,
+QDateTimeEdit::hover
+{
+ border: 1px solid #00ff00;
+
+}
+
+
+QSpinBox::up-button, QSpinBox::down-button,
+QDoubleSpinBox::up-button, QDoubleSpinBox::down-button,
+QDateTimeEdit::up-button, QDateTimeEdit::down-button
+{
+ background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(118, 118, 118, 255),stop:1 rgba(70, 70, 70, 255));
+ border: 0px solid #333333;
+
+}
+
+
+QSpinBox::disabled,
+QDoubleSpinBox::disabled,
+QDateTimeEdit::disabled
+{
+ background-color: #404040;
+ color: #656565;
+ border-color: #051a39;
+
+}
+
+
+QSpinBox::up-button:hover, QSpinBox::down-button:hover,
+QDoubleSpinBox::up-button:hover, QDoubleSpinBox::down-button:hover,
+QDateTimeEdit::up-button:hover, QDateTimeEdit::down-button:hover
+{
+ background-color: #646464;
+ border: 1px solid #333333;
+
+
+}
+
+
+QSpinBox::up-button:disabled, QSpinBox::down-button:disabled,
+QDoubleSpinBox::up-button:disabled, QDoubleSpinBox::down-button:disabled,
+QDateTimeEdit::up-button:disabled, QDateTimeEdit::down-button:disabled
+{
+ background-color: #404040;
+ color: #656565;
+ border-color: #051a39;
+
+}
+
+
+QSpinBox::up-button:pressed, QSpinBox::down-button:pressed,
+QDoubleSpinBox::up-button:pressed, QDoubleSpinBox::down-button::pressed,
+QDateTimeEdit::up-button:pressed, QDateTimeEdit::down-button::pressed
+{
+ background-color: #979796;
+ border: 1px solid #444444;
+
+}
+
+
+QSpinBox::down-arrow,
+QDoubleSpinBox::down-arrow,
+QDateTimeEdit::down-arrow
+{
+ image: url(://arrow-down.png);
+ width: 7px;
+
+}
+
+
+QSpinBox::up-arrow,
+QDoubleSpinBox::up-arrow,
+QDateTimeEdit::up-arrow
+{
+ image: url(://arrow-up.png);
+ width: 7px;
+
+}
+
+
+/*-----QLineEdit-----*/
+QLineEdit
+{
+ background-color: #000000;
+ color: #00ff00;
+ font-weight: bold;
+ border: 1px solid #333333;
+ padding: 4px;
+
+}
+
+
+QLineEdit:hover
+{
+ border: 1px solid #00ff00;
+
+}
+
+
+QLineEdit::disabled
+{
+ background-color: #404040;
+ color: #656565;
+ border-width: 1px;
+ border-color: #051a39;
+ padding: 2px;
+
+}
+
+
+/*-----QTextEdit-----*/
+QTextEdit
+{
+ background-color: #808080;
+ color: #fff;
+ border: 1px groove #333333;
+
+}
+
+
+QTextEdit::disabled
+{
+ background-color: #404040;
+ color: #656565;
+ border-color: #051a39;
+
+}
+
+
+/*-----QGroupBox-----*/
+QGroupBox
+{
+ border: 1px groove #333333;
+ border-radius: 2px;
+ margin-top: 20px;
+
+}
+
+
+QGroupBox
+{
+ background-color: qlineargradient(spread:repeat, x1:0.486, y1:0, x2:0.505, y2:1, stop:0.00480769 rgba(170, 169, 169, 255),stop:1 rgba(122, 122, 122, 255));
+ font-weight: bold;
+
+}
+
+
+QGroupBox::title
+{
+ background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(71, 75, 87, 255),stop:1 rgba(35, 37, 43, 255));
+ color: #ffffff;
+ border: 2px groove #333333;
+ subcontrol-origin: margin;
+ subcontrol-position: top left;
+ padding: 2px;
+
+}
+
+
+QGroupBox::title::disabled
+{
+ background-color: #404040;
+ color: #656565;
+ subcontrol-origin: margin;
+ subcontrol-position: top left;
+ padding: 5px;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+
+}
+
+
+/*-----QCheckBox-----*/
+QCheckBox{
+ background-color: transparent;
+ font-weight: bold;
+ color: #fff;
+
+}
+
+
+QCheckBox::indicator
+{
+ color: #b1b1b1;
+ background-color: #323232;
+ border: 2px solid #222222;
+ width: 12px;
+ height: 12px;
+
+}
+
+
+QCheckBox::indicator:checked
+{
+ image:url(://checkbox.png);
+ border: 2px solid #00ff00;
+
+}
+
+
+QCheckBox::indicator:unchecked:hover
+{
+ border: 2px solid #00ff00;
+
+}
+
+
+QCheckBox::disabled
+{
+ color: #656565;
+
+}
+
+
+QCheckBox::indicator:disabled
+{
+ background-color: #656565;
+ color: #656565;
+ border: 1px solid #656565;
+
+}
+
+
+/*-----QRadioButton-----*/
+QRadioButton{
+ background-color: transparent;
+ font-weight: bold;
+ color: #fff;
+
+}
+
+
+QRadioButton::indicator::unchecked
+{
+ border: 2px inset #222222;
+ border-radius: 6px;
+ background-color: #323232;
+ width: 9px;
+ height: 9px;
+
+}
+
+
+QRadioButton::indicator::unchecked:hover
+{
+ border: 2px solid #00ff00;
+ border-radius: 5px;
+ background-color: #323232;
+ width: 9px;
+ height: 9px;
+
+}
+
+
+QRadioButton::indicator::checked
+{
+ border: 2px inset #222222;
+ border-radius: 5px;
+ background-color: #00ff00;
+ width: 9px;
+ height: 9px;
+
+}
+
+
+QRadioButton::disabled
+{
+ color: #656565;
+
+}
+
+
+QRadioButton::indicator:disabled
+{
+ background-color: #656565;
+ color: #656565;
+ border: 2px solid #656565;
+
+}
+
+
+/*-----QTableView & QTableWidget-----*/
+QTableView
+{
+ background-color: #808080;
+ border: 1px groove #333333;
+ color: #f0f0f0;
+ font-weight: bold;
+ gridline-color: #333333;
+ outline : 0;
+
+}
+
+
+QTableView::disabled
+{
+ background-color: #242526;
+ border: 1px solid #32414B;
+ color: #656565;
+ gridline-color: #656565;
+ outline : 0;
+
+}
+
+
+QTableView::item:hover
+{
+ background-color: #484c58;
+ color: #f0f0f0;
+
+}
+
+
+QTableView::item:selected
+{
+ background-color: #484c58;
+ border: 2px groove #00ff00;
+ color: #F0F0F0;
+
+}
+
+
+QTableView::item:selected:disabled
+{
+ background-color: #1a1b1c;
+ border: 2px solid #525251;
+ color: #656565;
+
+}
+
+
+QTableCornerButton::section
+{
+ background-color: #282830;
+
+}
+
+
+QHeaderView::section
+{
+ background-color: #282830;
+ color: #fff;
+ font-weight: bold;
+ text-align: left;
+ padding: 4px;
+
+}
+
+
+QHeaderView::section:disabled
+{
+ background-color: #525251;
+ color: #656565;
+
+}
+
+
+QHeaderView::section:checked
+{
+ background-color: #00ff00;
+
+}
+
+
+QHeaderView::section:checked:disabled
+{
+ color: #656565;
+ background-color: #525251;
+
+}
+
+
+QHeaderView::section::vertical::first,
+QHeaderView::section::vertical::only-one
+{
+ border-top: 0px;
+
+}
+
+
+QHeaderView::section::vertical
+{
+ border-top: 0px;
+
+}
+
+
+QHeaderView::section::horizontal::first,
+QHeaderView::section::horizontal::only-one
+{
+ border-left: 0px;
+
+}
+
+
+QHeaderView::section::horizontal
+{
+ border-left: 0px;
+
+}
+
+
+/*-----QTabWidget-----*/
+QTabBar::tab
+{
+ background-color: transparent;
+ color: #ffffff;
+ font-weight: bold;
+ width: 80px;
+ height: 9px;
+
+}
+
+
+QTabBar::tab:disabled
+{
+ background-color: #656565;
+ color: #656565;
+
+}
+
+
+QTabWidget::pane
+{
+ background-color: transparent;
+ color: #ffffff;
+ border: 1px groove #333333;
+
+}
+
+
+QTabBar::tab:selected
+{
+ background-color: #484c58;
+ color: #ffffff;
+ border: 1px groove #333333;
+ border-bottom: 0px;
+
+}
+
+
+QTabBar::tab:selected:disabled
+{
+ background-color: #404040;
+ color: #656565;
+
+}
+
+
+QTabBar::tab:!selected
+{
+ background-color: #a3a7b2;
+
+}
+
+
+QTabBar::tab:!selected:hover
+{
+ background-color: #484c58;
+
+}
+
+
+QTabBar::tab:top:!selected
+{
+ margin-top: 1px;
+
+}
+
+
+QTabBar::tab:bottom:!selected
+{
+ margin-bottom: 3px;
+
+}
+
+
+QTabBar::tab:top, QTabBar::tab:bottom
+{
+ min-width: 8ex;
+ margin-right: -1px;
+ padding: 5px 10px 5px 10px;
+
+}
+
+
+QTabBar::tab:top:selected
+{
+ border-bottom-color: none;
+
+}
+
+
+QTabBar::tab:bottom:selected
+{
+ border-top-color: none;
+
+}
+
+
+QTabBar::tab:top:last, QTabBar::tab:bottom:last,
+QTabBar::tab:top:only-one, QTabBar::tab:bottom:only-one
+{
+ margin-right: 0;
+
+}
+
+
+QTabBar::tab:left:!selected
+{
+ margin-right: 2px;
+
+}
+
+
+QTabBar::tab:right:!selected
+{
+ margin-left: 2px;
+
+}
+
+
+QTabBar::tab:left, QTabBar::tab:right
+{
+ min-height: 15ex;
+ margin-bottom: -1px;
+ padding: 10px 5px 10px 5px;
+
+}
+
+
+QTabBar::tab:left:selected
+{
+ border-left-color: none;
+
+}
+
+
+QTabBar::tab:right:selected
+{
+ border-right-color: none;
+
+}
+
+
+QTabBar::tab:left:last, QTabBar::tab:right:last,
+QTabBar::tab:left:only-one, QTabBar::tab:right:only-one
+{
+ margin-bottom: 0;
+
+}
+
+
+/*-----QSlider-----*/
+QSlider{
+ background-color: transparent;
+
+}
+
+
+QSlider::groove:horizontal
+{
+ background-color: transparent;
+ height: 6px;
+
+}
+
+
+QSlider::sub-page:horizontal
+{
+ background-color: qlineargradient(spread:reflect, x1:1, y1:0, x2:1, y2:1, stop:0.00480769 rgba(201, 201, 201, 255),stop:1 rgba(72, 72, 72, 255));
+ border: 1px solid #000;
+
+}
+
+
+QSlider::add-page:horizontal
+{
+ background-color: #404040;
+ border: 1px solid #000;
+
+}
+
+
+QSlider::handle:horizontal
+{
+ background-color: qlineargradient(spread:reflect, x1:1, y1:0, x2:1, y2:1, stop:0.00480769 rgba(201, 201, 201, 255),stop:1 rgba(72, 72, 72, 255));
+ border: 1px solid #000;
+ width: 12px;
+ margin-top: -6px;
+ margin-bottom: -6px;
+
+}
+
+
+QSlider::handle:horizontal:hover
+{
+ background-color: #808080;
+
+}
+
+
+QSlider::sub-page:horizontal:disabled
+{
+ background-color: #bbb;
+ border-color: #999;
+
+}
+
+
+QSlider::add-page:horizontal:disabled
+{
+ background-color: #eee;
+ border-color: #999;
+
+}
+
+
+QSlider::handle:horizontal:disabled
+{
+ background-color: #eee;
+ border: 1px solid #aaa;
+
+}
+
+
+QSlider::groove:vertical
+{
+ background-color: transparent;
+ width: 6px;
+
+}
+
+
+QSlider::sub-page:vertical
+{
+ background-color: qlineargradient(spread:reflect, x1:0, y1:0.483, x2:1, y2:0.517, stop:0.00480769 rgba(201, 201, 201, 255),stop:1 rgba(72, 72, 72, 255));
+ border: 1px solid #000;
+
+}
+
+
+QSlider::add-page:vertical
+{
+ background-color: #404040;
+ border: 1px solid #000;
+
+}
+
+
+QSlider::handle:vertical
+{
+ background-color: qlineargradient(spread:reflect, x1:0, y1:0.483, x2:1, y2:0.517, stop:0.00480769 rgba(201, 201, 201, 255),stop:1 rgba(72, 72, 72, 255));
+ border: 1px solid #000;
+ height: 12px;
+ margin-left: -6px;
+ margin-right: -6px;
+
+}
+
+
+QSlider::handle:vertical:hover
+{
+ background-color: #808080;
+
+}
+
+
+QSlider::sub-page:vertical:disabled
+{
+ background-color: #bbb;
+ border-color: #999;
+
+}
+
+
+QSlider::add-page:vertical:disabled
+{
+ background-color: #eee;
+ border-color: #999;
+
+}
+
+
+QSlider::handle:vertical:disabled
+{
+ background-color: #eee;
+ border: 1px solid #aaa;
+ border-radius: 3px;
+
+}
+
+
+/*-----QDial-----*/
+QDial
+{
+ background-color: #600000;
+
+}
+
+
+QDial::disabled
+{
+ background-color: #404040;
+
+}
+
+
+/*-----QScrollBar-----*/
+QScrollBar:horizontal
+{
+ border: 1px solid #222222;
+ background-color: #63676d;
+ height: 18px;
+ margin: 0px 18px 0 18px;
+
+}
+
+
+QScrollBar::handle:horizontal
+{
+ background-color: #a6acb3;
+ border: 1px solid #656565;
+ border-radius: 2px;
+ min-height: 20px;
+
+}
+
+
+QScrollBar::add-line:horizontal
+{
+ border: 1px solid #1b1b19;
+ background-color: #a6acb3;
+ width: 18px;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+
+}
+
+
+QScrollBar::sub-line:horizontal
+{
+ border: 1px solid #1b1b19;
+ background-color: #a6acb3;
+ width: 18px;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+
+}
+
+
+QScrollBar::right-arrow:horizontal
+{
+ image: url(://arrow-right.png);
+ width: 8px;
+ height: 8px;
+
+}
+
+
+QScrollBar::left-arrow:horizontal
+{
+ image: url(://arrow-left.png);
+ width: 8px;
+ height: 8px;
+
+}
+
+
+QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal
+{
+ background: none;
+
+}
+
+
+QScrollBar:vertical
+{
+ background-color: #63676d;
+ width: 18px;
+ margin: 18px 0 18px 0;
+ border: 1px solid #222222;
+
+}
+
+
+QScrollBar::handle:vertical
+{
+ background-color: #a6acb3;
+ border: 1px solid #656565;
+ border-radius: 2px;
+ min-height: 20px;
+
+}
+
+
+QScrollBar::add-line:vertical
+{
+ border: 1px solid #1b1b19;
+ background-color: #a6acb3;
+ height: 18px;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+
+}
+
+
+QScrollBar::sub-line:vertical
+{
+ border: 1px solid #1b1b19;
+ background-color: #a6acb3;
+ height: 18px;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+
+}
+
+
+QScrollBar::up-arrow:vertical
+{
+ image: url(://arrow-up.png);
+ width: 8px;
+ height: 8px;
+
+}
+
+
+QScrollBar::down-arrow:vertical
+{
+ image: url(://arrow-down.png);
+ width: 8px;
+ height: 8px;
+
+}
+
+
+QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical
+{
+ background: none;
+
+}
+
+
+/*-----QProgressBar-----*/
+QProgressBar
+{
+ background-color: #000;
+ color: #00ff00;
+ font-weight: bold;
+ border: 0px groove #000;
+ border-radius: 10px;
+ text-align: center;
+
+}
+
+
+QProgressBar:disabled
+{
+ background-color: #404040;
+ color: #656565;
+ border-color: #051a39;
+ border: 1px solid #000;
+ border-radius: 10px;
+ text-align: center;
+
+}
+
+
+QProgressBar::chunk {
+ background-color: #ffaf02;
+ border: 0px;
+ border-radius: 10px;
+ color: #000;
+
+}
+
+
+QProgressBar::chunk:disabled {
+ background-color: #333;
+ border: 0px;
+ border-radius: 10px;
+ color: #656565;
+}
+
+
+/*-----QStatusBar-----*/
+QStatusBar
+{
+ background-color: qlineargradient(spread:repeat, x1:1, y1:0, x2:1, y2:1, stop:0 rgba(102, 115, 140, 255),stop:1 rgba(56, 63, 77, 255));
+ color: #ffffff;
+ border-color: #051a39;
+ font-weight: bold;
+
+}
+
+
diff --git a/catradio.ico b/catradio.ico
new file mode 100644
index 0000000..37954a6
Binary files /dev/null and b/catradio.ico differ
diff --git a/catradio.png b/catradio.png
new file mode 100644
index 0000000..1b3c75d
Binary files /dev/null and b/catradio.png differ
diff --git a/dialogconfig.cpp b/dialogconfig.cpp
new file mode 100644
index 0000000..2a0fe0f
--- /dev/null
+++ b/dialogconfig.cpp
@@ -0,0 +1,115 @@
+/**
+ ** This file is part of the CatRadio project.
+ ** Copyright 2022 Gianfranco Sordetti IZ8EWD .
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see .
+ **/
+
+
+#include "dialogconfig.h"
+#include "ui_dialogconfig.h"
+
+#include
+#include
+#include
+
+#include "rigdata.h"
+
+#include
+
+
+extern rigConnect rigCom;
+
+
+QString rigListFile = "rig.lst"; //Text file containing the list of rig supported by hamlib
+QFile file(rigListFile);
+
+
+DialogConfig::DialogConfig(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::DialogConfig)
+{
+ ui->setupUi(this);
+
+ //* rigModel comboBox
+ if (!file.exists()) //Create file rig.lst if not exists
+ {
+ file.open(QIODevice::ReadWrite);
+ rig_load_all_backends(); //Load all backends information
+ rig_list_foreach(printRigList, NULL); //Create the rig list
+ }
+ else file.open(QIODevice::ReadOnly); //Open file rig.lst and populate the combobox
+ file.seek(0);
+ ui->comboBox_rigModel->clear();
+ while(!file.atEnd())
+ {
+ QString line = file.readLine();
+ ui->comboBox_rigModel->addItem(line.trimmed());
+ }
+ file.close();
+
+ //* serialSpeed comboBox
+ ui->comboBox_serialSpeed->clear();
+ ui->comboBox_serialSpeed->addItem("4800");
+ ui->comboBox_serialSpeed->addItem("9600");
+ ui->comboBox_serialSpeed->addItem("19200");
+ ui->comboBox_serialSpeed->addItem("38400");
+ ui->comboBox_serialSpeed->addItem("57600");
+ ui->comboBox_serialSpeed->addItem("115200");
+
+ //* Update values in the GUI
+ ui->comboBox_rigModel->setCurrentIndex(ui->comboBox_rigModel->findText(QString::number(rigCom.rigModel),Qt::MatchStartsWith));
+ ui->lineEdit_RigPath->setText(rigCom.rigPort);
+ ui->comboBox_serialSpeed->setCurrentText(QString::number(rigCom.serialSpeed));
+ if (rigCom.civAddr) ui->lineEdit_civAddr->setText(QString::number(rigCom.civAddr));
+ ui->spinBox_RefreshRate->setValue(rigCom.rigRefresh);
+ ui->checkBox_fullPoll->setChecked(rigCom.fullPoll);
+}
+
+DialogConfig::~DialogConfig()
+{
+ delete ui;
+}
+
+void DialogConfig::on_buttonBox_accepted()
+{
+ //* Read settings from GUI
+ QString rigModel = ui->comboBox_rigModel->currentText();
+ QRegularExpression regexp("[0-9]+");
+ QRegularExpressionMatch rigNumber = regexp.match(rigModel);
+ rigCom.rigModel = rigNumber.captured(0).toInt();
+
+ rigCom.rigPort = ui->lineEdit_RigPath->text();
+ rigCom.serialSpeed = ui->comboBox_serialSpeed->currentText().toInt();
+ rigCom.civAddr = ui->lineEdit_civAddr->text().toInt();
+ rigCom.rigRefresh = ui->spinBox_RefreshRate->value();
+ rigCom.fullPoll = ui->checkBox_fullPoll->isChecked();
+
+ //* Save settings in config.ini
+ QSettings configFile(QString("config.ini"), QSettings::IniFormat);
+ configFile.setValue("rigModel", rigCom.rigModel);
+ configFile.setValue("rigPort", ui->lineEdit_RigPath->text());
+ configFile.setValue("serialSpeed", ui->comboBox_serialSpeed->currentText());
+ configFile.setValue("civAddress", ui->lineEdit_civAddr->text());
+ configFile.setValue("rigRefresh", ui->spinBox_RefreshRate->value());
+ configFile.setValue("fullPolling", ui->checkBox_fullPoll->isChecked());
+}
+
+int printRigList(const struct rig_caps *rigCaps, void *data) //Load rig list from hamlib and save into file rig.lst
+{
+ if (data) return 0;
+ QTextStream stream(&file);
+ stream << rigCaps->rig_model << " " << rigCaps->mfg_name << " " << rigCaps->model_name << "\n";
+ return 1;
+}
diff --git a/dialogconfig.h b/dialogconfig.h
new file mode 100644
index 0000000..3afdf77
--- /dev/null
+++ b/dialogconfig.h
@@ -0,0 +1,46 @@
+/**
+ ** This file is part of the CatRadio project.
+ ** Copyright 2022 Gianfranco Sordetti IZ8EWD .
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see .
+ **/
+
+
+#ifndef DIALOGCONFIG_H
+#define DIALOGCONFIG_H
+
+#include
+
+namespace Ui {
+class DialogConfig;
+}
+
+class DialogConfig : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit DialogConfig(QWidget *parent = nullptr);
+ ~DialogConfig();
+
+private slots:
+ void on_buttonBox_accepted();
+
+private:
+ Ui::DialogConfig *ui;
+};
+
+int printRigList(const struct rig_caps *rigCaps, void *data);
+
+#endif // DIALOGCONFIG_H
diff --git a/dialogconfig.ui b/dialogconfig.ui
new file mode 100644
index 0000000..0447762
--- /dev/null
+++ b/dialogconfig.ui
@@ -0,0 +1,164 @@
+
+
+ DialogConfig
+
+
+
+ 0
+ 0
+ 400
+ 300
+
+
+
+ Config
+
+
+ -
+
+
+ Model
+
+
+
+ -
+
+
+ -
+
+
+ Path
+
+
+ lineEdit_RigPath
+
+
+
+ -
+
+
+ -
+
+
+ Speed
+
+
+ comboBox_serialSpeed
+
+
+
+ -
+
+
+ -
+
+
+ Refresh Rate
+
+
+ spinBox_RefreshRate
+
+
+
+ -
+
+
+ 50
+
+
+ 1000
+
+
+ 50
+
+
+ 200
+
+
+
+ -
+
+
+ Options
+
+
+
-
+
+
+ CI-V Address
+
+
+
+ -
+
+
+ Full polling
+
+
+
+ -
+
+
+ CI-V address (decimal, Icom only)
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+
+ lineEdit_RigPath
+ comboBox_serialSpeed
+ spinBox_RefreshRate
+
+
+
+
+ buttonBox
+ accepted()
+ DialogConfig
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ DialogConfig
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
diff --git a/dialogsetup.cpp b/dialogsetup.cpp
new file mode 100644
index 0000000..ce6d7fb
--- /dev/null
+++ b/dialogsetup.cpp
@@ -0,0 +1,43 @@
+#include "dialogsetup.h"
+#include "ui_dialogsetup.h"
+
+#include "guidata.h"
+
+#include
+#include
+
+
+extern guiConfig guiConf;
+
+
+DialogSetup::DialogSetup(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::DialogSetup)
+{
+ ui->setupUi(this);
+
+ if (guiConf.vfoDisplayMode) ui->radioButton_vfoDispMode_UD->setChecked(true);
+}
+
+DialogSetup::~DialogSetup()
+{
+ delete ui;
+}
+
+void DialogSetup::on_radioButton_vfoDispMode_LR_toggled(bool checked)
+{
+ if (checked) guiConf.vfoDisplayMode=0;
+}
+
+void DialogSetup::on_radioButton_vfoDispMode_UD_toggled(bool checked)
+{
+ if (checked) guiConf.vfoDisplayMode=1;
+}
+
+void DialogSetup::on_buttonBox_accepted()
+{
+ //* Save settings in config.ini
+ QSettings configFile(QString("config.ini"), QSettings::IniFormat);
+ configFile.setValue("vfoDisplayMode", guiConf.vfoDisplayMode);
+}
+
diff --git a/dialogsetup.h b/dialogsetup.h
new file mode 100644
index 0000000..c39b453
--- /dev/null
+++ b/dialogsetup.h
@@ -0,0 +1,31 @@
+#ifndef DIALOGSETUP_H
+#define DIALOGSETUP_H
+
+#include
+
+namespace Ui {
+class DialogSetup;
+}
+
+class DialogSetup : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit DialogSetup(QWidget *parent = nullptr);
+ ~DialogSetup();
+
+private slots:
+
+
+ void on_radioButton_vfoDispMode_LR_toggled(bool checked);
+
+ void on_radioButton_vfoDispMode_UD_toggled(bool checked);
+
+ void on_buttonBox_accepted();
+
+private:
+ Ui::DialogSetup *ui;
+};
+
+#endif // DIALOGSETUP_H
diff --git a/dialogsetup.ui b/dialogsetup.ui
new file mode 100644
index 0000000..9a40c03
--- /dev/null
+++ b/dialogsetup.ui
@@ -0,0 +1,103 @@
+
+
+ DialogSetup
+
+
+
+ 0
+ 0
+ 400
+ 300
+
+
+
+ Setup
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+ -
+
+
+ VFO Display Mode
+
+
+
-
+
+
+ Left/Right buttons
+
+
+ true
+
+
+
+ -
+
+
+ Up/Down click
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ DialogSetup
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ DialogSetup
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
diff --git a/guidata.cpp b/guidata.cpp
new file mode 100644
index 0000000..d700faa
--- /dev/null
+++ b/guidata.cpp
@@ -0,0 +1,22 @@
+/**
+ ** This file is part of the CatRadio project.
+ ** Copyright 2022 Gianfranco Sordetti IZ8EWD .
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see .
+ **/
+
+
+#include "guidata.h"
+
+guiConfig guiConf;
diff --git a/guidata.h b/guidata.h
new file mode 100644
index 0000000..2fdd987
--- /dev/null
+++ b/guidata.h
@@ -0,0 +1,10 @@
+#ifndef GUIDATA_H
+#define GUIDATA_H
+
+#endif // GUIDATA_H
+
+
+typedef struct {
+ int vfoDisplayMode; //0: use Left/Right mouse button, 1: click digit up or down
+
+} guiConfig;
diff --git a/main.cpp b/main.cpp
new file mode 100644
index 0000000..f8a5cf6
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,43 @@
+/**
+ ** This file is part of the CatRadio project.
+ ** Copyright 2022 Gianfranco Sordetti IZ8EWD .
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see .
+ **/
+
+#include "mainwindow.h"
+
+#include
+#include
+#include
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ MainWindow w;
+
+/*
+ QFile file("./CatRadio.qss"); //open qss file
+ //if(!file.open(QFile::ReadOnly))
+ file.open(QFile::ReadOnly);
+
+ QString styleSheet (file.readAll());
+ file.close();
+
+ a.setStyleSheet(styleSheet); //setup stylesheet
+*/
+
+ w.show();
+ return a.exec();
+}
diff --git a/mainwindow.cpp b/mainwindow.cpp
new file mode 100644
index 0000000..36d1921
--- /dev/null
+++ b/mainwindow.cpp
@@ -0,0 +1,839 @@
+/**
+ ** This file is part of the CatRadio project.
+ ** Copyright 2022 Gianfranco Sordetti IZ8EWD .
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see .
+ **/
+
+
+#include "mainwindow.h"
+#include "ui_mainwindow.h"
+#include "dialogconfig.h"
+#include "dialogsetup.h"
+#include "rigdaemon.h"
+#include "rigdata.h"
+#include "guidata.h"
+#include "rigcommand.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#include //Hamlib
+
+extern RIG *my_rig; //Defined in rigdaemon.cpp
+
+extern rigConnect rigCom;
+extern rigSettings rigGet;
+extern rigSettings rigSet;
+extern rigCommand rigCmd;
+extern rigCommand rigCap;
+extern guiConfig guiConf;
+
+int retcode; //Return code from function
+int i; //Index
+int prevDial; //Previous dial value
+int fastDial; //Fast pushbutton state
+
+FILE* debugFile;
+
+
+QThread workerThread; //
+RigDaemon *rigDaemon = new RigDaemon;
+
+
+//***** MainWindow *****
+
+MainWindow::MainWindow(QWidget *parent)
+ : QMainWindow(parent)
+ , ui(new Ui::MainWindow)
+{
+ ui->setupUi(this);
+
+ timer = new QTimer(this); //timer for rigDaemon thread call
+
+ //* Debug
+ rig_set_debug_level(RIG_DEBUG_WARN);
+ rig_set_debug_time_stamp(true);
+ if ((debugFile=fopen("debug.log","w+")) == NULL) rig_set_debug_level(RIG_DEBUG_NONE);
+ else rig_set_debug_file(debugFile);
+
+ //* Signal and Slot connection for Slider and associated Label
+ connect(ui->horizontalSlider_RFpower, &QAbstractSlider::valueChanged, ui->label_RFpowerValue, qOverload(&QLabel::setNum));
+ connect(ui->horizontalSlider_RFgain, &QAbstractSlider::valueChanged, ui->label_RFgainValue, qOverload(&QLabel::setNum));
+ connect(ui->horizontalSlider_IFshift, &QAbstractSlider::valueChanged, ui->label_IFshiftValue, qOverload(&QLabel::setNum));
+
+ //* Signal and Slot connection for vfoDisplay
+ connect(ui->lineEdit_vfoMain, &vfoDisplay::on_valueChanged, this, &MainWindow::on_vfoDisplayValueChanged);
+
+ //* Thread for RigDaemon
+ rigDaemon->moveToThread(&workerThread); //
+ connect(&workerThread, &QThread::finished, rigDaemon, &QObject::deleteLater);
+ connect(timer, &QTimer::timeout, rigDaemon, &RigDaemon::rigUpdate);
+ connect(rigDaemon, &RigDaemon::resultReady, this, &MainWindow::on_rigDaemonResultReady);
+ workerThread.start();
+
+ //* Load settings from config.ini
+ QSettings configFile(QString("config.ini"), QSettings::IniFormat);
+ rigCom.rigModel = configFile.value("rigModel", 0).toInt();
+ rigCom.rigPort = configFile.value("rigPort").toString();
+ rigCom.serialSpeed = configFile.value("serialSpeed", 9600).toInt();
+ rigCom.civAddr = configFile.value("civAddress", 0).toInt();
+ rigCom.rigRefresh = configFile.value("rigRefresh", 100).toInt();
+ rigCom.fullPoll = configFile.value("fullPolling", false).toBool();
+ guiConf.vfoDisplayMode = configFile.value("vfoDisplayMode", 0).toInt();
+}
+
+MainWindow::~MainWindow()
+{
+ workerThread.quit(); //
+ workerThread.wait();
+
+ if (rigCom.connected)
+ {
+ timer->stop();
+
+ rigCom.connected = 0;
+ rig_close(my_rig); //Close the communication to the rig
+ }
+
+ rig_cleanup(my_rig); //Release rig handle and free associated memory
+
+ fclose(debugFile); //Close debug.log
+
+ delete ui;
+}
+
+
+//***** GUI function *****
+
+void MainWindow::guiInit()
+{
+ ui->statusbar->showMessage(my_rig->caps->model_name);
+
+ if (rig_has_set_func(my_rig, RIG_FUNCTION_SET_POWERSTAT)==0) //Power pushbutton
+ {
+ ui->pushButton_Power->setDisabled(true);
+ rigCap.onoff = 0;
+ }
+ else
+ {
+ ui->pushButton_Power->setDisabled(false);
+ rigCap.onoff = 1;
+ }
+
+ if (rig_has_set_func(my_rig, RIG_FUNCTION_SET_PTT)==0) //PTT pushbutton
+ {
+ ui->pushButton_PTT->setDisabled(true);
+ rigCap.ptt = 0;
+ }
+ else
+ {
+ ui->pushButton_PTT->setDisabled(false);
+ rigCap.ptt = 1;
+ }
+
+ //* Mode combobox
+ if (my_rig->state.mode_list==RIG_MODE_NONE)
+ {
+ ui->comboBox_Mode->setDisabled(true);
+ ui->comboBox_ModeSub->setDisabled(true);
+ }
+ else
+ {
+ ui->comboBox_Mode->clear(); //Clear old contents
+ ui->comboBox_ModeSub->clear();
+ for (i=0; istate.mode_list & (1ULL << i))
+ {
+ ui->comboBox_Mode->addItem(rig_strrmode(my_rig->state.mode_list & (1ULL << i)));
+ ui->comboBox_ModeSub->addItem(rig_strrmode(my_rig->state.mode_list & (1ULL << i)));
+ }
+ }
+ rigCmd.bwidthList = 1; //Command to populate BW combobox in guiUpdate()
+ }
+
+ //* AGC level comboBox
+ ui->comboBox_AGC->clear();
+ /* It seems that has_set_level or has_get_level is not well implemented in Hamlib, at the moment it is skipped in favour of fix values entry
+ agc_level_e agcLevel;
+ for (i = 0; i < 7; i++)
+ {
+ agcLevel = levelagcvalue(i);
+ if (rig_has_set_level(my_rig, agcLevel))
+ {
+ ui->comboBox_AGC->addItem(rig_stragclevel(agcLevel));
+ }
+ }*/
+ ui->comboBox_AGC->addItem(rig_stragclevel(RIG_AGC_OFF));
+ ui->comboBox_AGC->addItem(rig_stragclevel(RIG_AGC_AUTO));
+ ui->comboBox_AGC->addItem(rig_stragclevel(RIG_AGC_FAST));
+ ui->comboBox_AGC->addItem(rig_stragclevel(RIG_AGC_MEDIUM));
+ ui->comboBox_AGC->addItem(rig_stragclevel(RIG_AGC_SLOW));
+
+ //* Meter comboBox
+ ui->comboBox_Meter->clear();
+ if (rig_has_get_level(my_rig, RIG_METER_SWR)) ui->comboBox_Meter->addItem("SWR");
+ if (rig_has_get_level(my_rig, RIG_METER_ALC)) ui->comboBox_Meter->addItem("ALC");
+ rigSet.meter = levelmeterstr (ui->comboBox_Meter->currentText());
+ setSubMeter();
+
+ //* Attenuator comboBox
+ ui->comboBox_Att->clear();
+ ui->comboBox_Att->addItem("0");
+ for (i = 0; i < HAMLIB_MAXDBLSTSIZ && my_rig->state.attenuator[i] != 0; i++)
+ {
+ ui->comboBox_Att->addItem(QString::number(my_rig->state.attenuator[i]));
+ }
+
+ //* Preamp comboBox
+ ui->comboBox_Preamp->clear();
+ ui->comboBox_Preamp->addItem("0");
+ for (i = 0; i < HAMLIB_MAXDBLSTSIZ && my_rig->state.preamp[i] != 0; i++)
+ {
+ ui->comboBox_Preamp->addItem(QString::number(my_rig->state.preamp[i]));
+ }
+
+ rigCmd.rangeList = 1;
+ rigCmd.antList = 1;
+}
+
+void MainWindow::guiUpdate()
+{
+ //* Power button
+ if (rigGet.onoff == RIG_POWER_ON) ui->pushButton_Power->setChecked(true);
+
+ //* VFOs
+ ui->lineEdit_vfoMain->setValue(rigGet.freqMain);
+ ui->lineEdit_vfoSub->setText(QString::number(rigGet.freqSub/1000,'f',2));
+
+ ui->label_vfoMain->setText(rig_strvfo(rigGet.vfoMain));
+ switch (rigGet.vfoMain)
+ {
+ case RIG_VFO_A: rigGet.vfoSub = RIG_VFO_B; break;
+ case RIG_VFO_B: rigGet.vfoSub = RIG_VFO_A; break;
+ case RIG_VFO_MAIN: rigGet.vfoSub = RIG_VFO_SUB; break;
+ case RIG_VFO_SUB: rigGet.vfoSub = RIG_VFO_MAIN; break;
+ }
+ ui->label_vfoSub->setText(rig_strvfo(rigGet.vfoSub));
+
+ //* Mode
+ ui->comboBox_Mode->setCurrentText(rig_strrmode(rigGet.mode));
+ ui->comboBox_ModeSub->setCurrentText(rig_strrmode(rigGet.modeSub));
+
+ //* BW combobox
+ if (rigCmd.bwidthList)
+ {
+ ui->comboBox_BW->clear();
+ filter_list bwidth_list; //IF filter bandwidth per mode
+ for (i=0; istate.filters[i]); i++)
+ {
+ char modeslist[1000] = "";
+ QString modes, mode;
+ bwidth_list = my_rig->state.filters[i];
+ rig_strrmodes(bwidth_list.modes, modeslist, sizeof(modeslist));
+ modes = modeslist;
+ modes.append(" ");
+ //qDebug() << modes << bwidth_list.width;
+ mode = rig_strrmode(rigGet.mode);
+ QRegularExpression rx("\\b"+mode+"?\\s");
+ if (modes.contains (rx) && bwidth_list.width != RIG_FLT_ANY) ui->comboBox_BW->addItem(QString::number(bwidth_list.width));
+ }
+ ui->comboBox_BW->model()->sort(0, Qt::DescendingOrder);
+ rigCmd.bwidthList = 0;
+ }
+
+ ui->comboBox_BW->setCurrentText(QString::number(rigGet.bwidth));
+ ui->checkBox_NAR->setChecked(rigGet.bwNarrow);
+
+ //* Range list
+ if (rigCmd.rangeList)
+ {
+ for (i=0; i= my_rig->state.tx_range_list[i].startf && rigGet.freqMain <= my_rig->state.tx_range_list[i].endf) break;
+ }
+ rigGet.rangeListTxIndex = i;
+
+ for (i=0; i= my_rig->state.rx_range_list[i].startf && rigGet.freqMain <= my_rig->state.rx_range_list[i].endf) break;
+ }
+ if (rigGet.rangeListRxIndex != i) rigCmd.antList = 1;
+ rigGet.rangeListRxIndex = i;
+
+ rigCmd.rangeList = 0;
+ }
+
+ //* Antenna comboBox
+ if (rigCmd.antList)
+ {
+ ui->comboBox_Ant->clear();
+ if (my_rig->state.tx_range_list[rigGet.rangeListRxIndex].ant == RIG_ANT_NONE) ui->comboBox_Ant->addItem("NONE"); //RIG_ANT_NONE
+ else for (i=0; i < RIG_ANT_MAX; i++)
+ {
+ if (my_rig->state.tx_range_list[rigGet.rangeListRxIndex].ant & (1UL << i))
+ {
+ switch (i)
+ {
+ case 0: ui->comboBox_Ant->addItem("ANT1"); break; //RIG_ANT_1
+ case 1: ui->comboBox_Ant->addItem("ANT2"); break; //RIG_ANT_2
+ case 2: ui->comboBox_Ant->addItem("ANT3"); break; //RIG_ANT_3
+ case 3: ui->comboBox_Ant->addItem("ANT4"); break; //RIG_ANT_4
+ case 4: ui->comboBox_Ant->addItem("ANT5"); break; //RIG_ANT_5
+ case 30: ui->comboBox_Ant->addItem("UNK"); break; //RIG_ANT_UNKNOWN
+ case 31: ui->comboBox_Ant->addItem("CURR"); break; //RIG_ANT_CURR
+ default: ui->comboBox_Ant->addItem("UNK"); break;
+ }
+ }
+ }
+ rigCmd.antList = 0;
+ }
+
+ //* Split
+ if (rigGet.split == RIG_SPLIT_ON)
+ {
+ ui->pushButton_Split->setChecked(true);
+ if (rigGet.vfoSub == rigGet.vfoTx)
+ {
+ ui->label_vfoMainRxTx->setText("RX");
+ ui->label_vfoSubRxTx->setText("TX");
+ }
+ else
+ {
+ ui->label_vfoMainRxTx->setText("TX");
+ ui->label_vfoSubRxTx->setText("RX");
+ }
+ }
+ else
+ {
+ ui->pushButton_Split->setChecked(false);
+ ui->label_vfoMainRxTx->setText("RX TX");
+ ui->label_vfoSubRxTx->setText("");
+ }
+
+ //* PTT & Meter
+ if (rigGet.ptt == RIG_PTT_ON)
+ {
+ ui->pushButton_PTT->setChecked(true);
+
+ ui->progressBar_Smeter->setTx(true);
+ ui->progressBar_Smeter->setValue(rigGet.powerMeter.f*100);
+ ui->progressBar_subMeter->setValue(rigGet.subMeter.f);
+ }
+ else
+ {
+ ui->pushButton_PTT->setChecked(false);
+
+ ui->progressBar_Smeter->setTx(false);
+ ui->progressBar_Smeter->setValue(rigGet.sMeter.i);
+ if (rigSet.meter == RIG_LEVEL_SWR) ui->progressBar_subMeter->setValue(1.0);
+ else ui->progressBar_subMeter->setValue(0.0);
+ }
+
+ //*
+ if (!ui->horizontalSlider_RFpower->isSliderDown()) ui->horizontalSlider_RFpower->setValue((int)(rigGet.rfPower*100));
+
+ //*
+ ui->radioButton_Tuner->setChecked(rigGet.tuner);
+
+ ui->checkBox_BKIN->setChecked(rigGet.bkin);
+
+ ui->comboBox_AGC->setCurrentText(rig_stragclevel(rigGet.agc));
+
+ ui->comboBox_Att->setCurrentText(QString::number(rigGet.att));
+
+ ui->comboBox_Preamp->setCurrentText(QString::number(rigGet.pre));
+}
+
+
+//* RigDaemon handle results
+void MainWindow::on_rigDaemonResultReady()
+{
+ guiUpdate();
+}
+
+//* SubMeter
+void MainWindow::setSubMeter()
+{
+ if (rigSet.meter == RIG_LEVEL_SWR)
+ {
+ ui->progressBar_subMeter->setMaxValue(5.0);
+ ui->progressBar_subMeter->setMinValue(1.0);
+ ui->progressBar_subMeter->setGateValue(2.0);
+ ui->progressBar_subMeter->setPrecision(1);
+ ui->progressBar_subMeter->setLongStep(0.5);
+ ui->progressBar_subMeter->setShortStep(0.1);
+ ui->progressBar_subMeter->setValue(1);
+ }
+ else
+ {
+ ui->progressBar_subMeter->setMaxValue(1.0);
+ ui->progressBar_subMeter->setMinValue(0.0);
+ ui->progressBar_subMeter->setGateValue(0.5);
+ ui->progressBar_subMeter->setPrecision(1);
+ ui->progressBar_subMeter->setLongStep(0.5);
+ ui->progressBar_subMeter->setShortStep(0.1);
+ ui->progressBar_subMeter->setValue(0);
+ }
+}
+
+
+//***** PushButton *****
+
+void MainWindow::on_pushButton_Connect_toggled(bool checked)
+{
+ if (checked && rigCom.connected == 0)
+ {
+ retcode = rigDaemon->rigConnect(); //Open Rig connection
+
+ if (retcode != RIG_OK) //Connection error
+ {
+ rigCom.connected = 0;
+ ui->statusbar->showMessage(rigerror(retcode));
+ ui->pushButton_Connect->setChecked(false); //Uncheck the button
+ }
+ else //Rig connected
+ {
+ rigCom.connected = 1;
+ guiInit();
+ if (rigCap.onoff == 0 || rigGet.onoff == RIG_POWER_ON) timer->start(rigCom.rigRefresh);
+ }
+ }
+ else if (rigCom.connected) //Button unchecked
+ {
+ rigCom.connected = 0;
+ timer->stop();
+ rig_close(my_rig); //Close the communication to the rig
+ //rig_cleanup(my_rig); //Release rig handle and free associated memory
+ }
+}
+
+void MainWindow::on_pushButton_Power_toggled(bool checked)
+{
+ if (checked && !rigGet.onoff)
+ {
+ retcode = rig_set_powerstat(my_rig, RIG_POWER_ON);
+ if (retcode != RIG_OK)
+ {
+ ui->pushButton_Power->setChecked(false); //Uncheck the button
+ ui->statusbar->showMessage(rigerror(retcode));
+ }
+ else timer->start(rigCom.rigRefresh);
+ }
+ else if (!checked && rigGet.onoff)
+ {
+ retcode = rig_set_powerstat(my_rig, RIG_POWER_OFF);
+ if (retcode != RIG_OK)
+ {
+ ui->pushButton_Power->setChecked(false); //Uncheck the button
+ timer->stop();
+ }
+ }
+}
+
+void MainWindow::on_pushButton_PTT_toggled(bool checked)
+{
+ if (checked && !rigGet.ptt)
+ {
+ rigSet.ptt = RIG_PTT_ON;
+ rigCmd.ptt = 1;
+ }
+ else if (!checked && rigGet.ptt)
+ {
+ rigSet.ptt = RIG_PTT_OFF;
+ rigCmd.ptt = 1;
+ }
+}
+
+void MainWindow::on_pushButton_Split_toggled(bool checked)
+{
+ if (checked && !rigGet.split)
+ {
+ rigSet.split = RIG_SPLIT_ON;
+ rigCmd.split = 1;
+ }
+ else if (!checked && rigGet.split)
+ {
+ rigSet.split = RIG_SPLIT_OFF;
+ rigCmd.split = 1;
+ }
+}
+
+void MainWindow::on_pushButton_QSplit_clicked()
+{
+ quick_split();
+}
+
+void MainWindow::on_pushButton_AB_clicked()
+{
+ rigCmd.vfoXchange = 1;
+}
+
+void MainWindow::on_pushButton_AeqB_clicked()
+{
+ rigCmd.vfoCopy = 1;
+}
+
+void MainWindow::on_pushButton_Fast_toggled(bool checked)
+{
+ if (checked) fastDial = 1;
+ else fastDial = 0;
+}
+
+void MainWindow::on_pushButton_Tune_clicked()
+{
+ rigCmd.tune = 1;
+}
+
+void MainWindow::on_pushButton_Band160_clicked()
+{
+ set_band(160);
+}
+
+void MainWindow::on_pushButton_Band80_clicked()
+{
+ set_band(80);
+}
+
+void MainWindow::on_pushButton_Band60_clicked()
+{
+ set_band(60);
+}
+
+void MainWindow::on_pushButton_Band40_clicked()
+{
+ set_band(40);
+}
+
+void MainWindow::on_pushButton_Band30_clicked()
+{
+ set_band(30);
+}
+
+void MainWindow::on_pushButton_Band20_clicked()
+{
+ set_band(20);
+}
+
+void MainWindow::on_pushButton_Band17_clicked()
+{
+ set_band(17);
+}
+
+void MainWindow::on_pushButton_Band15_clicked()
+{
+ set_band(15);
+}
+
+void MainWindow::on_pushButton_Band12_clicked()
+{
+ set_band(12);
+}
+
+void MainWindow::on_pushButton_Band10_clicked()
+{
+ set_band(10);
+}
+
+void MainWindow::on_pushButton_Band6_clicked()
+{
+ set_band(6);
+}
+
+void MainWindow::on_pushButton_Band2_clicked()
+{
+ set_band(2);
+}
+
+void MainWindow::on_pushButton_Band70_clicked()
+{
+ set_band(70);
+}
+
+void MainWindow::on_pushButton_BandGen_clicked()
+{
+ set_band(1);
+}
+
+void MainWindow::on_pushButton_BandDown_clicked()
+{
+ rigCmd.bandDown = 1;
+}
+
+void MainWindow::on_pushButton_BandUp_clicked()
+{
+ rigCmd.bandUp = 1;
+}
+
+//***** CheckBox *****
+
+void MainWindow::on_checkBox_NAR_toggled(bool checked)
+{
+ if (checked && !rigGet.bwNarrow)
+ {
+ rigSet.bwidth = rig_passband_narrow(my_rig, rigGet.mode);
+ rigCmd.bwidth = 1;
+ }
+ else if (!checked && rigGet.bwNarrow)
+ {
+ rigSet.bwidth = RIG_PASSBAND_NORMAL;
+ rigCmd.bwidth = 1;
+ }
+}
+
+void MainWindow::on_checkBox_BKIN_toggled(bool checked)
+{
+ if (checked && !rigGet.bkin)
+ {
+ rigSet.bkin = 1;
+ rigCmd.bkin = 1;
+ }
+ else if (!checked && rigGet.bkin)
+ {
+ rigSet.bkin = 0;
+ rigCmd.bkin = 1;
+ }
+}
+
+void MainWindow::on_checkBox_NB_toggled(bool checked)
+{
+ if (checked && !rigGet.noiseBlanker)
+ {
+ rigSet.noiseBlanker = 1;
+ rigCmd.noiseBlanker = 1;
+ }
+ else if (!checked && rigGet.noiseBlanker)
+ {
+ rigSet.noiseBlanker = 0;
+ rigCmd.noiseBlanker = 1;
+ }
+}
+
+void MainWindow::on_checkBox_NR_toggled(bool checked)
+{
+ if (checked && !rigGet.noiseReduction)
+ {
+ rigSet.noiseReduction = 1;
+ rigCmd.noiseReduction = 1;
+ }
+ else if (!checked && rigGet.noiseReduction)
+ {
+ rigSet.noiseReduction = 0;
+ rigCmd.noiseReduction = 1;
+ }
+}
+
+void MainWindow::on_checkBox_NF_toggled(bool checked)
+{
+ if (checked && !rigGet.notchFilter)
+ {
+ rigSet.notchFilter = 1;
+ rigCmd.notchFilter = 1;
+ }
+ else if (!checked && rigGet.notchFilter)
+ {
+ rigSet.notchFilter = 0;
+ rigCmd.notchFilter = 1;
+ }
+}
+
+
+//***** RadioButton *****
+
+void MainWindow::on_radioButton_Tuner_toggled(bool checked)
+{
+ if (checked && !rigGet.tuner)
+ {
+ rigSet.tuner = 1;
+ rigCmd.tuner = 1;
+ }
+ else if (!checked && rigGet.tuner)
+ {
+ rigSet.tuner = 0;
+ rigCmd.tuner = 1;
+ }
+}
+
+
+//***** Dial *****
+
+void MainWindow::on_dial_valueChanged(int value)
+{
+ int step;
+
+ step = value - prevDial;
+ if (step<=99 && step>50) step = value - 100 - prevDial;
+ if (step>=-99 && step<-50) step = value + 100 - prevDial;
+ prevDial = value;
+
+ if (ui->radioButton_VFOSub->isChecked()) //dial VFO Sub
+ {
+ rigSet.freqSub = rigGet.freqSub + step*(!fastDial*10+fastDial*100);
+ rigCmd.freqSub = 1;
+ }
+ else //dial VFO Main
+ {
+ rigSet.freqMain = rigGet.freqMain + step*(!fastDial*10+fastDial*100);
+ rigCmd.freqMain = 1;
+ }
+}
+
+void MainWindow::on_vfoDisplayValueChanged(int value)
+{
+ rigSet.freqMain = value;
+ rigCmd.freqMain = 1;
+}
+
+//***** ComboBox *****
+
+void MainWindow::on_comboBox_Mode_activated(int index)
+{
+ rigSet.mode = rig_parse_mode(ui->comboBox_Mode->itemText(index).toLatin1());
+ rigCmd.mode = 1;
+}
+
+void MainWindow::on_comboBox_BW_activated(int index)
+{
+ rigSet.bwidth = ui->comboBox_BW->itemText(index).toInt();
+ rigCmd.bwidth = 1;
+}
+
+void MainWindow::on_comboBox_AGC_activated(int index)
+{
+ rigSet.agc = levelagcstr(ui->comboBox_AGC->itemText(index));
+ rigCmd.agc = 1;
+}
+
+void MainWindow::on_comboBox_Att_activated(int index)
+{
+ rigSet.att = ui->comboBox_Att->itemText(index).toInt();
+ rigCmd.att = 1;
+}
+
+void MainWindow::on_comboBox_Preamp_activated(int index)
+{
+ rigSet.pre = ui->comboBox_Preamp->itemText(index).toInt();
+ rigCmd.pre = 1;
+}
+
+void MainWindow::on_comboBox_Ant_activated(int index)
+{
+ rigSet.ant = antstr(ui->comboBox_Ant->itemText(index));
+ rigCmd.ant = 1;
+}
+
+void MainWindow::on_comboBox_Meter_activated(int index)
+{
+ rigSet.meter = levelmeterstr (ui->comboBox_Meter->itemText(index));
+ setSubMeter();
+}
+
+
+//***** Spin Box *****
+
+void MainWindow::on_spinBox_NR_valueChanged(int arg1)
+{
+ rigSet.noiseReductionLevel = arg1;
+ rigCmd.noiseReductionLevel = 1;
+}
+
+
+//***** Slider *****
+
+void MainWindow::on_horizontalSlider_RFpower_valueChanged(int value)
+{
+ if (!rigCmd.rfPower)
+ {
+ if (value < 5) value = 5;
+ rigSet.rfPower = (float)(value)/100;
+ if (rigSet.rfPower != rigGet.rfPower) rigCmd.rfPower = 1;
+ }
+}
+
+void MainWindow::on_horizontalSlider_RFgain_valueChanged(int value)
+{
+ if (!rigCmd.rfGain)
+ {
+ rigSet.rfGain = (float)(value)/100;
+ if (rigSet.rfGain != rigGet.rfGain) rigCmd.rfGain = 1;
+ }
+}
+
+void MainWindow::on_horizontalSlider_IFshift_valueChanged(int value)
+{
+ if (!rigCmd.ifShift)
+ {
+ rigSet.ifShift = value;
+ if (rigSet.ifShift != rigGet.ifShift) rigCmd.ifShift = 1;
+ }
+}
+
+
+//***** Menu *****
+
+void MainWindow::on_action_Connection_triggered()
+{
+ DialogConfig config;
+ config.setModal(true);
+ config.exec();
+}
+
+void MainWindow::on_action_Setup_triggered()
+{
+ DialogSetup setup;
+ setup.setModal(true);
+ setup.exec();
+}
+
+void MainWindow::on_action_AboutCatRadio_triggered()
+{
+ QMessageBox msgBox;
+ msgBox.setWindowTitle("About");
+ msgBox.setTextFormat(Qt::RichText);
+ QString version = QString::number(VERSION_MAJ)+"."+QString::number(VERSION_MIN)+"."+QString::number(VERSION_MIC);
+ msgBox.setText("CatRadio Radio control software
version "+version+" "+RELEASE_DATE);
+ msgBox.setInformativeText("Copyright (C) 2022 Gianfranco Sordetti IZ8EWD
"
+ "www.pianetaradio.it
"
+ "This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
"
+ "This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
"
+ "You should have received a copy of the GNU General Public License along with this program. If not, see www.gnu.org/licenses.");
+ msgBox.setIcon(QMessageBox::NoIcon);
+ msgBox.setStandardButtons(QMessageBox::Ok);
+
+ QPixmap icon("catradio.png");
+ msgBox.setIconPixmap(icon);
+
+ msgBox.exec();
+}
+
+void MainWindow::on_action_AboutQT_triggered()
+{
+ QMessageBox::aboutQt(this);
+}
+
+void MainWindow::on_action_AboutHamLib_triggered()
+{
+ QMessageBox msgBox;
+ msgBox.setWindowTitle("About Hamlib");
+ msgBox.setText(rig_version());
+ msgBox.setInformativeText(rig_copyright());
+ //msgBox.setDetailedText(rig_license());
+ msgBox.setIcon(QMessageBox::Information);
+ msgBox.setStandardButtons(QMessageBox::Ok);
+ msgBox.exec();
+}
diff --git a/mainwindow.h b/mainwindow.h
new file mode 100644
index 0000000..a095a46
--- /dev/null
+++ b/mainwindow.h
@@ -0,0 +1,153 @@
+/**
+ ** This file is part of the CatRadio project.
+ ** Copyright 2022 Gianfranco Sordetti IZ8EWD .
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see .
+ **/
+
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include
+#include
+
+#define RELEASE_DATE __DATE__
+#define VERSION_MAJ 1
+#define VERSION_MIN 0
+#define VERSION_MIC 0
+
+
+QT_BEGIN_NAMESPACE
+namespace Ui { class MainWindow; }
+QT_END_NAMESPACE
+
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow(QWidget *parent = nullptr);
+ ~MainWindow();
+
+public slots:
+ void guiUpdate();
+ void on_rigDaemonResultReady(); //Slot for rigDaemon resultReady
+ void on_vfoDisplayValueChanged(int value); //Slot for vfoDisplay valueChanged
+
+signals:
+
+private slots:
+ void on_pushButton_Connect_toggled(bool checked);
+ void on_pushButton_Power_toggled(bool checked);
+ void on_pushButton_PTT_toggled(bool checked);
+ void on_pushButton_Split_toggled(bool checked);
+ void on_pushButton_AB_clicked();
+ void on_pushButton_AeqB_clicked();
+
+ void on_dial_valueChanged(int value);
+
+ void on_action_AboutQT_triggered();
+ void on_action_AboutHamLib_triggered();
+
+
+
+ void on_comboBox_Mode_activated(int index);
+
+ void on_pushButton_Fast_toggled(bool checked);
+
+ void on_horizontalSlider_RFpower_valueChanged(int value);
+
+ void on_pushButton_Band160_clicked();
+
+ void on_pushButton_Band80_clicked();
+
+ void on_pushButton_Band60_clicked();
+
+ void on_pushButton_Band40_clicked();
+
+ void on_pushButton_Band30_clicked();
+
+ void on_pushButton_Band20_clicked();
+
+ void on_pushButton_Band17_clicked();
+
+ void on_pushButton_Band15_clicked();
+
+ void on_pushButton_Band12_clicked();
+
+ void on_pushButton_Band10_clicked();
+
+ void on_pushButton_Band6_clicked();
+
+ void on_pushButton_Tune_clicked();
+
+ void on_radioButton_Tuner_toggled(bool checked);
+
+ void on_pushButton_BandDown_clicked();
+
+ void on_pushButton_BandUp_clicked();
+
+ void on_pushButton_QSplit_clicked();
+
+ void on_action_Connection_triggered();
+
+ void on_comboBox_BW_activated(int index);
+
+ void on_checkBox_NAR_toggled(bool checked);
+
+ void on_checkBox_BKIN_toggled(bool checked);
+
+ void on_comboBox_AGC_activated(int index);
+
+ void on_comboBox_Att_activated(int index);
+
+ void on_comboBox_Preamp_activated(int index);
+
+ void on_comboBox_Ant_activated(int index);
+
+ void on_action_AboutCatRadio_triggered();
+
+ void on_checkBox_NB_toggled(bool checked);
+
+ void on_checkBox_NR_toggled(bool checked);
+
+ void on_checkBox_NF_toggled(bool checked);
+
+ void on_comboBox_Meter_activated(int index);
+
+ void on_horizontalSlider_RFgain_valueChanged(int value);
+
+ void on_spinBox_NR_valueChanged(int arg1);
+
+ void on_horizontalSlider_IFshift_valueChanged(int value);
+
+ void on_pushButton_Band2_clicked();
+
+ void on_pushButton_Band70_clicked();
+
+ void on_pushButton_BandGen_clicked();
+
+ void on_action_Setup_triggered();
+
+private:
+ Ui::MainWindow *ui;
+ QTimer *timer;
+
+ void guiInit();
+ void setSubMeter();
+};
+
+#endif // MAINWINDOW_H
diff --git a/mainwindow.ui b/mainwindow.ui
new file mode 100644
index 0000000..eb08f7b
--- /dev/null
+++ b/mainwindow.ui
@@ -0,0 +1,1353 @@
+
+
+ MainWindow
+
+
+ true
+
+
+
+ 0
+ 0
+ 600
+ 560
+
+
+
+ CatRadio
+
+
+
+ catradio.icocatradio.ico
+
+
+
+
+
+ 10
+ 10
+ 91
+ 401
+
+
+
+ -
+
+
+ Connect
+
+
+ true
+
+
+
+ -
+
+
+ Power
+
+
+ true
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Tuner
+
+
+
+ -
+
+
+ Tune
+
+
+
+ -
+
+
+ Antenna
+
+
+ comboBox_Ant
+
+
+
+ -
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ AGC
+
+
+ comboBox_AGC
+
+
+
+ -
+
+
+ -
+
+
+ Attenuator
+
+
+ comboBox_Att
+
+
+
+ -
+
+
+ -
+
+
+ Preamp
+
+
+ comboBox_Preamp
+
+
+
+ -
+
+
+
+
+
+
+ true
+
+
+
+ 110
+ 80
+ 481
+ 131
+
+
+
+ QFrame::Box
+
+
+ QFrame::Raised
+
+
+ 0
+
+
+
+
+ 200
+ 10
+ 40
+ 16
+
+
+
+ VFO
+
+
+
+
+
+ 400
+ 10
+ 40
+ 16
+
+
+
+ VFO
+
+
+
+
+ true
+
+
+
+ 10
+ 60
+ 81
+ 24
+
+
+
+
+
+
+ 100
+ 60
+ 81
+ 24
+
+
+
+
+
+
+ 10
+ 100
+ 80
+ 20
+
+
+
+ A / B
+
+
+
+
+
+ 100
+ 100
+ 80
+ 20
+
+
+
+ A = B
+
+
+
+
+
+ 190
+ 100
+ 80
+ 20
+
+
+
+ Split
+
+
+ true
+
+
+
+
+
+ 280
+ 100
+ 80
+ 20
+
+
+
+ Q Split
+
+
+
+
+
+ 200
+ 30
+ 41
+ 16
+
+
+
+ RX TX
+
+
+
+
+
+ 400
+ 30
+ 41
+ 16
+
+
+
+ RX TX
+
+
+
+
+ true
+
+
+
+ 250
+ 10
+ 140
+ 40
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 18
+
+
+
+ Qt::RightToLeft
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ true
+
+
+
+
+ true
+
+
+
+ 250
+ 60
+ 81
+ 24
+
+
+
+ false
+
+
+
+
+
+ 10
+ 9
+ 181
+ 41
+
+
+
+
+
+
+
+ 110
+ 220
+ 151
+ 191
+
+
+
+ Band
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 20
+ 20
+
+
+
+
+ 16
+ 16
+
+
+
+ 1.8
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 20
+ 20
+
+
+
+
+ 16
+ 16
+
+
+
+ 3.5
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 20
+ 20
+
+
+
+
+ 16
+ 16
+
+
+
+ 5.3
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 20
+ 20
+
+
+
+
+ 16
+ 16
+
+
+
+ 7
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 20
+ 20
+
+
+
+
+ 16
+ 16
+
+
+
+ 10
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 20
+ 20
+
+
+
+
+ 16
+ 16
+
+
+
+ 14
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 20
+ 20
+
+
+
+
+ 16
+ 16
+
+
+
+ 18
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 20
+ 20
+
+
+
+
+ 16
+ 16
+
+
+
+ 21
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 20
+ 20
+
+
+
+
+ 16
+ 16
+
+
+
+ 24.5
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 20
+ 20
+
+
+
+
+ 16
+ 16
+
+
+
+ 28
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 20
+ 20
+
+
+
+
+ 16
+ 16
+
+
+
+ Gen
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 20
+ 20
+
+
+
+
+ 16
+ 16
+
+
+
+ 50
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 20
+ 20
+
+
+
+
+ 16
+ 16
+
+
+
+ <<
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 20
+ 20
+
+
+
+
+ 16
+ 16
+
+
+
+ 144
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 20
+ 20
+
+
+
+
+ 16
+ 16
+
+
+
+ 430
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 20
+ 20
+
+
+
+
+ 16
+ 16
+
+
+
+ >>
+
+
+
+
+
+
+
+
+ 470
+ 230
+ 121
+ 181
+
+
+
+ Filter
+
+
+
+
+ 10
+ 30
+ 51
+ 22
+
+
+
+ Noise Blanking
+
+
+ NB
+
+
+
+
+
+ 10
+ 60
+ 51
+ 22
+
+
+
+ Noise Reduction
+
+
+ NR
+
+
+
+
+
+ 10
+ 90
+ 51
+ 22
+
+
+
+ Notch Filter
+
+
+ NF
+
+
+
+
+
+ 70
+ 60
+ 46
+ 25
+
+
+
+ 1
+
+
+ 15
+
+
+
+
+
+ 10
+ 120
+ 51
+ 22
+
+
+
+ BW Narrow
+
+
+ NAR
+
+
+
+
+
+ 10
+ 160
+ 101
+ 18
+
+
+
+ -1200
+
+
+ 1200
+
+
+ 10
+
+
+ 100
+
+
+ false
+
+
+ Qt::Horizontal
+
+
+
+
+
+ 10
+ 150
+ 55
+ 16
+
+
+
+ IF-Shift
+
+
+ horizontalSlider_IFshift
+
+
+
+
+ true
+
+
+
+ 40
+ 140
+ 41
+ 16
+
+
+
+ 0
+
+
+ Qt::AlignCenter
+
+
+
+
+
+
+ 470
+ 420
+ 120
+ 91
+
+
+
+ CW
+
+
+
+
+ 10
+ 30
+ 71
+ 22
+
+
+
+ Break-In
+
+
+ BK IN
+
+
+
+
+
+ 10
+ 60
+ 71
+ 22
+
+
+
+ APF
+
+
+
+
+
+
+ 270
+ 220
+ 191
+ 191
+
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
+
+ 10
+ 150
+ 171
+ 31
+
+
+
+ PTT
+
+
+ \
+
+
+ true
+
+
+
+
+
+ 20
+ 0
+ 150
+ 150
+
+
+
+ 100
+
+
+ false
+
+
+ true
+
+
+ 10.000000000000000
+
+
+ false
+
+
+
+
+
+ 10
+ 110
+ 31
+ 25
+
+
+
+ Fast
+
+
+ true
+
+
+
+
+
+ 10
+ 0
+ 51
+ 22
+
+
+
+ Main
+
+
+ true
+
+
+
+
+
+ 130
+ 0
+ 51
+ 22
+
+
+
+ Qt::RightToLeft
+
+
+ Sub
+
+
+
+
+
+
+ 110
+ 9
+ 481
+ 61
+
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
+
+ 0
+ 0
+ 191
+ 61
+
+
+
+
+
+
+ 250
+ 0
+ 151
+ 61
+
+
+
+
+
+
+ 400
+ 20
+ 75
+ 24
+
+
+
+
+
+
+
+ 10
+ 420
+ 451
+ 91
+
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Raised
+
+
+
+
+ 10
+ 10
+ 55
+ 16
+
+
+
+ RF Gain
+
+
+ horizontalSlider_RFgain
+
+
+
+
+
+ 10
+ 50
+ 55
+ 16
+
+
+
+ RF Power
+
+
+ horizontalSlider_RFpower
+
+
+
+
+
+ 60
+ 10
+ 200
+ 20
+
+
+
+ 0
+
+
+ 100
+
+
+ 100
+
+
+ true
+
+
+ Qt::Horizontal
+
+
+ QSlider::TicksBothSides
+
+
+ 10
+
+
+
+
+
+ 60
+ 50
+ 200
+ 20
+
+
+
+ 0
+
+
+ 100
+
+
+ 100
+
+
+ true
+
+
+ Qt::Horizontal
+
+
+ QSlider::TicksBothSides
+
+
+ 10
+
+
+
+
+ true
+
+
+
+ 270
+ 10
+ 31
+ 16
+
+
+
+ 100
+
+
+
+
+ true
+
+
+
+ 270
+ 50
+ 31
+ 16
+
+
+
+ 100
+
+
+
+ frame_2
+ frame
+ verticalLayoutWidget
+ groupBox_Band
+ groupBox_filter
+ groupBox_CW
+ frame_3
+ frame_4
+
+
+
+
+
+ Connection
+
+
+
+
+ About CatRadio
+
+
+
+
+ About HamLib
+
+
+
+
+ About QT
+
+
+
+
+ Setup
+
+
+
+
+
+ SMeter
+ QWidget
+
+ 1
+
+
+ SubMeter
+ QWidget
+
+ 1
+
+
+ vfoDisplay
+ QWidget
+
+ 1
+
+
+
+
+
diff --git a/rigcommand.cpp b/rigcommand.cpp
new file mode 100644
index 0000000..a56a9c5
--- /dev/null
+++ b/rigcommand.cpp
@@ -0,0 +1,153 @@
+/**
+ ** This file is part of the CatRadio project.
+ ** Copyright 2022 Gianfranco Sordetti IZ8EWD .
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see .
+ **/
+
+
+#include "rigcommand.h"
+#include "rigdata.h"
+
+#include //Hamlib
+
+#include
+
+extern rigSettings rigGet;
+extern rigSettings rigSet;
+extern rigCommand rigCmd;
+extern rigCommand rigCap;
+
+void set_band (int band)
+{
+ freq_t freq;
+
+ switch (band)
+ {
+ case 160: freq = 1840000; break;
+ case 80: freq = 3600000; break;
+ case 60: freq = 5355000; break;
+ case 40: freq = 7100000; break;
+ case 30: freq = 10130000; break;
+ case 20: freq = 14100000; break;
+ case 17: freq = 18120000; break;
+ case 15: freq = 21150000; break;
+ case 12: freq = 24940000; break;
+ case 10: freq = 28320000; break;
+ case 6: freq = 50150000; break;
+ case 2: freq = 144300000; break;
+ case 70: freq = 432200000; break;
+ default: freq = rigSet.freqMain; break;
+ }
+
+ rigSet.freqMain = freq;
+ rigCmd.freqMain = 1;
+ rigCmd.bandChange = 1;
+}
+
+void quick_split ()
+{
+ if (rigGet.vfoMain == RIG_VFO_A)
+ {
+ rigSet.freqSub = rigGet.freqMain + 5000;
+ //rigSet.modeSub = rigGet.modeMain;
+ rigCmd.freqSub = 1;
+ //rigCmd.modeSub = 1;
+ }
+ else
+ {
+ rigSet.freqMain = rigGet.freqSub + 5000;
+ rigCmd.freqMain = 1;
+ }
+ rigCmd.split = 1;
+}
+
+agc_level_e levelagcvalue (int agcValue)
+{
+ agc_level_e agcLevel;
+
+ switch (agcValue)
+ {
+ case 0: agcLevel = RIG_AGC_OFF; break;
+ case 1: agcLevel = RIG_AGC_SUPERFAST; break;
+ case 2: agcLevel = RIG_AGC_FAST; break;
+ case 3: agcLevel = RIG_AGC_SLOW; break;
+ case 4: agcLevel = RIG_AGC_USER; break;
+ case 5: agcLevel = RIG_AGC_MEDIUM; break;
+ case 6: agcLevel = RIG_AGC_AUTO; break;
+ default: agcLevel = RIG_AGC_AUTO; break;
+ }
+
+ return agcLevel;
+}
+
+agc_level_e levelagcstr (QString agcString)
+{
+ agc_level_e agcLevel;
+
+ if (agcString == "OFF") agcLevel = RIG_AGC_OFF;
+ else if (agcString == "SUPERFAST") agcLevel = RIG_AGC_SUPERFAST;
+ else if (agcString == "FAST") agcLevel = RIG_AGC_FAST;
+ else if (agcString == "SLOW") agcLevel = RIG_AGC_SLOW;
+ else if (agcString == "USER") agcLevel = RIG_AGC_USER;
+ else if (agcString == "MEDIUM") agcLevel = RIG_AGC_MEDIUM;
+ else agcLevel = RIG_AGC_AUTO;
+
+ return agcLevel;
+}
+
+value_t valueagclevel (agc_level_e agcLevel)
+{
+ value_t value;
+
+ if (agcLevel == RIG_AGC_OFF) value.i = 0;
+ else if (agcLevel == RIG_AGC_SUPERFAST) value.i = 1;
+ else if (agcLevel == RIG_AGC_FAST) value.i = 2;
+ else if (agcLevel == RIG_AGC_SLOW) value.i = 3;
+ else if (agcLevel == RIG_AGC_USER) value.i = 4;
+ else if (agcLevel == RIG_AGC_MEDIUM) value.i = 5;
+ else value.i = 6; //RIG_AGC_AUTO
+
+ return value;
+}
+
+ant_t antstr (QString antString)
+{
+ ant_t ant;
+
+ if (antString == "NONE") ant = RIG_ANT_NONE;
+ else if (antString == "ANT1") ant = RIG_ANT_1;
+ else if (antString == "ANT2") ant = RIG_ANT_2;
+ else if (antString == "ANT3") ant = RIG_ANT_3;
+ else if (antString == "ANT4") ant = RIG_ANT_4;
+ else if (antString == "ANT5") ant = RIG_ANT_5;
+ else if (antString == "UNK") ant = RIG_ANT_UNKNOWN;
+ else if (antString == "CURR") ant = RIG_ANT_CURR;
+ else ant = RIG_ANT_UNKNOWN;
+
+ return ant;
+}
+
+unsigned levelmeterstr (QString meterString)
+{
+ unsigned levelMeter;
+
+ if (meterString == "SWR") levelMeter = RIG_LEVEL_SWR;
+ else if (meterString == "COMP") levelMeter = RIG_LEVEL_COMP;
+ else if (meterString == "ALC") levelMeter = RIG_LEVEL_ALC;
+ //...
+ else levelMeter = RIG_METER_NONE;
+
+ return levelMeter;
+}
diff --git a/rigcommand.h b/rigcommand.h
new file mode 100644
index 0000000..7c76aeb
--- /dev/null
+++ b/rigcommand.h
@@ -0,0 +1,36 @@
+/**
+ ** This file is part of the CatRadio project.
+ ** Copyright 2022 Gianfranco Sordetti IZ8EWD .
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see .
+ **/
+
+
+#ifndef RIGCOMMAND_H
+#define RIGCOMMAND_H
+
+#endif // RIGCOMMAND_H
+
+#include
+
+#include
+
+
+void set_band (int band);
+void quick_split ();
+agc_level_e levelagcvalue (int agcValue);
+agc_level_e levelagcstr (QString agcString);
+value_t valueagclevel (agc_level_e agcLevel);
+ant_t antstr (QString antString);
+unsigned levelmeterstr (QString meterString);
diff --git a/rigdaemon.cpp b/rigdaemon.cpp
new file mode 100644
index 0000000..408a278
--- /dev/null
+++ b/rigdaemon.cpp
@@ -0,0 +1,424 @@
+/**
+ ** This file is part of the CatRadio project.
+ ** Copyright 2022 Gianfranco Sordetti IZ8EWD .
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see .
+ **/
+
+
+#include "rigdaemon.h"
+#include "rigdata.h"
+#include "rigcommand.h"
+
+#include
+#include
+#include
+
+#include
+
+
+RIG *my_rig;
+
+extern rigConnect rigCom;
+extern rigSettings rigGet;
+extern rigSettings rigSet;
+extern rigCommand rigCmd;
+extern rigCommand rigCap;
+
+int commandPriority = 0;
+
+
+RigDaemon::RigDaemon(QObject *parent) : QObject(parent)
+{
+
+}
+
+int RigDaemon::rigConnect()
+{
+ int retcode;
+
+ my_rig = rig_init(rigCom.rigModel); //Allocate rig handle
+
+ if (!my_rig) //Wrong Rig number
+ {
+ QMessageBox msgBox; //Show error MessageBox
+ msgBox.setWindowTitle("Warning");
+ msgBox.setText("Rig model error");
+ msgBox.setIcon(QMessageBox::Warning);
+ msgBox.setStandardButtons(QMessageBox::Ok);
+ msgBox.exec();
+
+ return -1; //RIG_EINVAL, Invalid parameter
+ }
+ else
+ {
+ if (rigCom.rigModel == 2) //Rigctld
+ {
+ //myport.type.rig = RIG_PORT_NETWORK;
+ strncpy(my_rig->state.rigport.pathname, rigCom.rigPort.toLatin1(), HAMLIB_FILPATHLEN - 1);
+ //strncpy(my_rig->state.rigport.pathname, RIG_FILE, HAMLIB_FILPATHLEN - 1);
+ }
+ else
+ {
+ //myport.type.rig = RIG_PORT_SERIAL;
+ strncpy(my_rig->state.rigport.pathname, rigCom.rigPort.toLatin1(), HAMLIB_FILPATHLEN - 1);
+ my_rig->state.rigport.parm.serial.rate = rigCom.serialSpeed;
+ if (rigCom.civAddr) //CI-V address Icom
+ {
+ std::string civaddrS = std::to_string(rigCom.civAddr); //Convert int to string
+ char const *civaddr = civaddrS.c_str(); //Convert string to char*
+ rig_set_conf(my_rig, rig_token_lookup(my_rig, "civaddr"), civaddr);
+ }
+ }
+
+ retcode = rig_open(my_rig);
+
+ if (retcode != RIG_OK) return retcode; //Rig not connected
+ else //Rig connected
+ {
+ rig_get_powerstat(my_rig, &rigGet.onoff);
+ return 0;
+ }
+
+ }
+}
+
+void RigDaemon::rigUpdate()
+{
+ int retcode;
+ value_t retvalue;
+
+ //***** Command execution *****
+ //* PTT
+ if (rigCmd.ptt)
+ {
+ retcode = rig_set_ptt(my_rig, RIG_VFO_CURR, rigSet.ptt);
+ if (retcode == RIG_OK) rigGet.ptt = rigSet.ptt;
+ rigCmd.ptt = 0;
+ }
+
+ //* VFO
+ if (rigCmd.freqMain) //VFO Main
+ {
+ retcode = rig_set_freq(my_rig, RIG_VFO_CURR, rigSet.freqMain);
+ if (retcode == RIG_OK) rigGet.freqMain = rigSet.freqMain;
+ rigCmd.freqMain = 0;
+ rigCmd.rangeList = 1;
+ }
+
+ else if (rigCmd.freqSub) //VFO Sub
+ {
+ retcode = rig_set_freq(my_rig, rigGet.vfoSub, rigSet.freqSub);
+ if (retcode == RIG_OK) rigGet.freqSub = rigSet.freqSub;
+ rigCmd.freqSub = 0;
+ }
+
+ else
+ {
+ freq_t retfreq;
+ retcode = rig_get_freq(my_rig, RIG_VFO_CURR, &retfreq);
+ if (retcode == RIG_OK) rigGet.freqMain = retfreq;
+ retcode = rig_get_freq(my_rig, rigGet.vfoSub, &retfreq);
+ if (retcode == RIG_OK) rigGet.freqSub = retfreq;
+
+ ptt_t retptt;
+ retcode = rig_get_ptt(my_rig, RIG_VFO_CURR, &retptt);
+ if (retcode == RIG_OK) rigGet.ptt = retptt;
+
+ //* Meter
+ if (rigGet.ptt==1)
+ {
+ rig_get_level(my_rig, RIG_VFO_CURR, RIG_LEVEL_RFPOWER_METER, &rigGet.powerMeter);
+ rig_get_level(my_rig, RIG_VFO_CURR, rigSet.meter, &rigGet.subMeter);
+ }
+ else
+ {
+ retcode = rig_get_level(my_rig, RIG_VFO_CURR, RIG_LEVEL_STRENGTH, &retvalue);
+ if (retcode == RIG_OK) rigGet.sMeter = retvalue;
+ }
+
+ if (!rigGet.ptt)
+ {
+ //* Mode
+ if (rigCmd.mode)
+ {
+ retcode = rig_set_mode(my_rig, RIG_VFO_CURR, rigSet.mode, RIG_PASSBAND_NOCHANGE);
+ if (retcode == RIG_OK)
+ {
+ rigCmd.bwidthList = 1; //Update BWidth list
+ commandPriority = 0;
+ //rig_get_mode(my_rig, RIG_VFO_CURR, &rigGet.mode, &rigGet.bwidth); //Get BW
+ }
+ rigCmd.mode = 0;
+ }
+
+ //* BandWidth
+ if (rigCmd.bwidth)
+ {
+ retcode = rig_set_mode(my_rig, RIG_VFO_CURR, rigGet.mode, rigSet.bwidth);
+ if (retcode == RIG_OK) rigGet.bwidth = rigSet.bwidth;
+ rigCmd.bwidth = 0;
+ }
+
+ //* Split
+ if (rigCmd.split)
+ {
+ retcode = rig_set_split_vfo(my_rig, RIG_VFO_RX, rigSet.split, RIG_VFO_TX);
+ if (retcode == RIG_OK) rigGet.split = rigSet.split;
+ rigCmd.split = 0;
+ }
+
+ //* VFO Exchange
+ if (rigCmd.vfoXchange)
+ {
+ retcode = rig_vfo_op(my_rig, RIG_VFO_CURR, RIG_OP_XCHG);
+ if (retcode == RIG_OK) commandPriority = 0;
+ rigCmd.vfoXchange = 0;
+ }
+
+ //* VFO Copy
+ if (rigCmd.vfoCopy)
+ {
+ rig_vfo_op(my_rig, RIG_VFO_CURR, RIG_OP_CPY);
+ rigCmd.vfoCopy = 0;
+ }
+
+ //* Band Up
+ if (rigCmd.bandUp)
+ {
+ retcode = rig_vfo_op(my_rig, RIG_VFO_CURR, RIG_OP_BAND_UP);
+ if (retcode == RIG_OK) commandPriority = 0;
+ rigCmd.bandUp = 0;
+ }
+
+ //* Band Down
+ if (rigCmd.bandDown)
+ {
+ retcode = rig_vfo_op(my_rig, RIG_VFO_CURR, RIG_OP_BAND_DOWN);
+ if (retcode == RIG_OK) commandPriority = 0;
+ rigCmd.bandDown = 0;
+ }
+
+ //* Band change
+ if (rigCmd.bandChange) commandPriority = 0;
+
+ //* Tune
+ if (rigCmd.tune)
+ {
+ rig_vfo_op(my_rig, RIG_VFO_CURR, RIG_OP_TUNE);
+ rigCmd.tune = 0;
+ }
+
+ //* Antenna
+ if (rigCmd.ant)
+ {
+ retcode = rig_set_ant(my_rig, RIG_VFO_CURR, rigSet.ant, retvalue);
+ if (retcode == RIG_OK) rigGet.ant = rigSet.ant;
+ rigCmd.ant = 0;
+ }
+
+ //* AGC
+ if (rigCmd.agc)
+ {
+ retcode = rig_set_level(my_rig, RIG_VFO_CURR, RIG_LEVEL_AGC, valueagclevel(rigSet.agc));
+ if (retcode == RIG_OK) rigGet.agc = rigSet.agc;
+ rigCmd.agc = 0;
+ }
+
+ //* Attenuator
+ if (rigCmd.att)
+ {
+ retvalue.i = rigSet.att;
+ retcode = rig_set_level(my_rig, RIG_VFO_CURR, RIG_LEVEL_ATT, retvalue);
+ if (retcode == RIG_OK) rigGet.att = rigSet.att;
+ rigCmd.att = 0;
+ }
+
+ //* Preamp
+ if (rigCmd.pre)
+ {
+ retvalue.i = rigSet.pre;
+ retcode = rig_set_level(my_rig, RIG_VFO_CURR, RIG_LEVEL_PREAMP, retvalue);
+ if (retcode == RIG_OK) rigGet.pre = rigSet.pre;
+ rigCmd.pre = 0;
+ }
+
+ //* RF gain
+ if (rigCmd.rfGain)
+ {
+ retvalue.f = rigSet.rfGain;
+ retcode = rig_set_level(my_rig, RIG_VFO_CURR, RIG_LEVEL_RF, retvalue);
+ if (retcode == RIG_OK) rigGet.rfGain = rigSet.rfGain;
+ rigCmd.rfGain = 0;
+ }
+
+ //* NB noise blanker
+ if (rigCmd.noiseBlanker)
+ {
+ retcode = rig_set_func(my_rig, RIG_VFO_CURR, RIG_FUNC_NB, rigSet.noiseBlanker);
+ if (retcode == RIG_OK) rigGet.noiseBlanker = rigSet.noiseBlanker;
+ rigCmd.noiseBlanker = 0;
+ }
+
+ //* NR noise reduction
+ if (rigCmd.noiseReduction)
+ {
+ retcode = rig_set_func(my_rig, RIG_VFO_CURR, RIG_FUNC_NR, rigSet.noiseReduction);
+ if (retcode == RIG_OK) rigGet.noiseReduction = rigSet.noiseReduction;
+ rigCmd.noiseReduction = 0;
+ }
+
+ if (rigCmd.noiseReductionLevel)
+ {
+ retvalue.i = rigSet.noiseReductionLevel;
+ retcode = rig_set_level(my_rig, RIG_VFO_CURR, RIG_LEVEL_NR, retvalue);
+ if (retcode == RIG_OK) rigGet.noiseReductionLevel = rigSet.noiseReductionLevel;
+ rigCmd.noiseReductionLevel = 0;
+ }
+
+ //* NF notch filter
+ if (rigCmd.notchFilter)
+ {
+ retcode = rig_set_func(my_rig, RIG_VFO_CURR, RIG_FUNC_ANF, rigSet.notchFilter);
+ if (retcode == RIG_OK) rigGet.notchFilter = rigSet.notchFilter;
+ rigCmd.notchFilter = 0;
+ }
+
+ //* IF Shift
+ if (rigCmd.ifShift)
+ {
+ retvalue.i = rigSet.ifShift;
+ retcode = rig_set_level(my_rig, RIG_VFO_CURR, RIG_LEVEL_IF, retvalue);
+ if (retcode == RIG_OK) rigGet.ifShift = rigSet.ifShift;
+ rigCmd.ifShift = 0;
+ }
+ } //end if (!rigGet.ptt)
+
+ //* Tuner
+ if (rigCmd.tuner)
+ {
+ retcode = rig_set_func(my_rig, RIG_VFO_CURR, RIG_FUNC_TUNER, rigSet.tuner);
+ if (retcode == RIG_OK) rigGet.tuner = rigSet.tuner;
+ rigCmd.tune = 0;
+ }
+
+ //* RF power
+ if (rigCmd.rfPower)
+ {
+ retvalue.f = rigSet.rfPower;
+ retcode = rig_set_level(my_rig, RIG_VFO_CURR, RIG_LEVEL_RFPOWER, retvalue);
+ if (retcode == RIG_OK) rigGet.rfPower = rigSet.rfPower;
+ rigCmd.rfPower = 0;
+ }
+
+ //***** Poll execution *****
+ if ((commandPriority == 1 && !rigGet.ptt && rigCom.fullPoll) || commandPriority == 0)
+ {
+ //* Mode and BW
+ rig_get_mode(my_rig, RIG_VFO_CURR, &rigGet.mode, &rigGet.bwidth);
+ //rig_get_mode(my_rig, rigGet.vfoSub, &rigGet.modeSub, &rigGet.bwidthSub);
+ if (rigGet.bwidth == rig_passband_narrow(my_rig, rigGet.mode)) rigGet.bwNarrow = 1;
+ else rigGet.bwNarrow = 0;
+ }
+
+ if ((commandPriority == 2 && !rigGet.ptt && rigCom.fullPoll) || commandPriority == 0)
+ {
+ //* Split
+ rig_get_split_vfo(my_rig, RIG_VFO_CURR, &rigGet.split, &rigGet.vfoTx);
+ //else rig_get_split(my_rig, RIG_VFO_CURR, &rigGet.split);
+
+ rig_get_vfo(my_rig, &rigGet.vfoMain);
+ }
+
+ //* Tuner
+ if ((commandPriority == 3 && !rigGet.ptt && rigCom.fullPoll) || commandPriority == 0) rig_get_func(my_rig, RIG_VFO_CURR, RIG_FUNC_TUNER, &rigGet.tuner);
+
+ //* Antenna
+ if ((commandPriority == 4 && !rigGet.ptt && rigCom.fullPoll) || commandPriority == 0) rig_get_ant(my_rig, RIG_VFO_CURR, RIG_ANT_CURR, &retvalue, &rigGet.ant, &rigGet.antTx, &rigGet.antRx);
+
+ //* AGC
+ if ((commandPriority == 5 && !rigGet.ptt && rigCom.fullPoll) || commandPriority == 0)
+ {
+ rig_get_level(my_rig, RIG_VFO_CURR, RIG_LEVEL_AGC, &retvalue);
+ rigGet.agc = levelagcvalue(retvalue.i);
+ }
+
+ //* Attenuator
+ if ((commandPriority == 6 && !rigGet.ptt && rigCom.fullPoll) || commandPriority == 0)
+ {
+ rig_get_level(my_rig, RIG_VFO_CURR, RIG_LEVEL_ATT, &retvalue);
+ rigGet.att = retvalue.i;
+ }
+
+ //* Preamp
+ if ((commandPriority == 7 && !rigGet.ptt && rigCom.fullPoll) || commandPriority == 0)
+ {
+ rig_get_level(my_rig, RIG_VFO_CURR, RIG_LEVEL_PREAMP, &retvalue);
+ rigGet.pre = retvalue.i;
+ }
+
+ //* RF power
+ if ((commandPriority == 8 && !rigGet.ptt && rigCom.fullPoll) || commandPriority == 0)
+ {
+ rig_get_level(my_rig, RIG_VFO_CURR, RIG_LEVEL_RFPOWER, &retvalue);
+ rigGet.rfPower = retvalue.f;
+ }
+
+ //* RF gain
+ if ((commandPriority == 9 && !rigGet.ptt && rigCom.fullPoll) || commandPriority == 0)
+ {
+ rig_get_level(my_rig, RIG_VFO_CURR, RIG_LEVEL_RF, &retvalue);
+ rigGet.rfGain = retvalue.f;
+ }
+
+ //* NB noise blanker
+ if ((commandPriority == 10 && !rigGet.ptt && rigCom.fullPoll) || commandPriority == 0) rig_get_func(my_rig, RIG_VFO_CURR, RIG_FUNC_NB, &rigGet.noiseBlanker);
+
+ //* NR noise reduction
+ if ((commandPriority == 11 && !rigGet.ptt && rigCom.fullPoll) || commandPriority == 0)
+ {
+ rig_get_func(my_rig, RIG_VFO_CURR, RIG_FUNC_NR, &rigGet.noiseReduction);
+ rig_get_level(my_rig, RIG_VFO_CURR, RIG_LEVEL_NR, &retvalue);
+ rigGet.noiseReductionLevel = retvalue.i;
+ }
+
+ //* NF notch filter
+ if ((commandPriority == 12 && !rigGet.ptt && rigCom.fullPoll) || commandPriority == 0) rig_get_func(my_rig, RIG_VFO_CURR, RIG_FUNC_ANF, &rigGet.notchFilter);
+
+ //* IF Shift
+ if ((commandPriority == 13 && !rigGet.ptt && rigCom.fullPoll) || commandPriority == 0)
+ {
+ rig_get_level(my_rig, RIG_VFO_CURR, RIG_LEVEL_IF, &retvalue);
+ rigGet.ifShift = retvalue.i;
+ }
+
+ if ((commandPriority == 14 && !rigGet.ptt && rigCom.fullPoll) || commandPriority == 0) //&& mode=CW
+ {
+ //* CW Full Break-in
+ if (rigCmd.bkin)
+ {
+ retcode = rig_set_func(my_rig, RIG_VFO_CURR, RIG_FUNC_FBKIN, rigSet.bkin);
+ if (retcode == RIG_OK) rigGet.bkin = rigSet.bkin;
+ rigCmd.bkin = 0;
+ }
+ else rig_get_func(my_rig, RIG_VFO_CURR, RIG_FUNC_FBKIN, &rigGet.bkin);
+ }
+
+ commandPriority ++;
+ if (commandPriority == 15) commandPriority = 1;
+
+ }
+
+ emit resultReady();
+}
diff --git a/rigdaemon.h b/rigdaemon.h
new file mode 100644
index 0000000..4020535
--- /dev/null
+++ b/rigdaemon.h
@@ -0,0 +1,42 @@
+/**
+ ** This file is part of the CatRadio project.
+ ** Copyright 2022 Gianfranco Sordetti IZ8EWD .
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see .
+ **/
+
+
+#ifndef RIGDAEMON_H
+#define RIGDAEMON_H
+
+#include
+#include
+
+class RigDaemon : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit RigDaemon(QObject *parent = nullptr);
+ int rigConnect();
+
+public slots:
+ void rigUpdate();
+
+signals:
+ void resultReady();
+
+};
+
+#endif // RIGDAEMON_H
diff --git a/rigdata.cpp b/rigdata.cpp
new file mode 100644
index 0000000..84560e7
--- /dev/null
+++ b/rigdata.cpp
@@ -0,0 +1,26 @@
+/**
+ ** This file is part of the CatRadio project.
+ ** Copyright 2022 Gianfranco Sordetti IZ8EWD .
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see .
+ **/
+
+
+#include "rigdata.h"
+
+rigConnect rigCom;
+rigSettings rigGet;
+rigSettings rigSet;
+rigCommand rigCmd;
+rigCommand rigCap;
diff --git a/rigdata.h b/rigdata.h
new file mode 100644
index 0000000..87fe302
--- /dev/null
+++ b/rigdata.h
@@ -0,0 +1,100 @@
+/**
+ ** This file is part of the CatRadio project.
+ ** Copyright 2022 Gianfranco Sordetti IZ8EWD .
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see .
+ **/
+
+
+#ifndef RIGDATA_H
+#define RIGDATA_H
+
+#endif // RIGDATA_H
+
+#include //Hamlib
+
+#include
+
+typedef struct {
+ unsigned rigModel; //Hamlib rig model
+ QString rigPort; //COM port or IP address
+ unsigned serialSpeed; //Serial port baud rate
+ int civAddr; //CI-V address (decimal, Icom radio)
+ unsigned rigRefresh; //GUI refresh interval (ms)
+ int connected; //connected flag
+ bool fullPoll; //full polling flag
+} rigConnect;
+
+typedef struct {
+ powerstat_t onoff; //on/off status
+ freq_t freqMain, freqSub; //Frequency
+ rmode_t mode, modeSub; //Mode
+ pbwidth_t bwidth, bwidthSub; //IF filter bandwidth
+ int bwNarrow; //IF narrow filter
+ vfo_t vfoMain, vfoSub; //VFO
+ vfo_t vfoTx;
+ split_t split; //Split
+ ptt_t ptt; //PTT
+ value_t sMeter; //Smeter signal strenght
+ value_t powerMeter; //RF power meter
+ value_t subMeter; //secondary meter
+ unsigned meter; //secondary meter type
+ float rfPower; //RF power output level
+ float rfGain; //RF gain rx
+ agc_level_e agc; //AGC level
+ int att; //Attenuator
+ int pre; //Preamplifier
+ ant_t ant, antTx, antRx; //Antenna
+ int rangeListTxIndex, rangeListRxIndex;
+ int tuner; //Tuner
+ int bkin; //CW Break-in
+ int apf;
+ int noiseBlanker;
+ int noiseReduction, noiseReductionLevel;
+ int notchFilter;
+ int ifShift;
+} rigSettings;
+
+typedef struct {
+ int onoff;
+ int freqMain;
+ int freqSub;
+ int mode;
+ int bwidth;
+ int bwidthList;
+ int vfo;
+ int split;
+ int vfoXchange;
+ int vfoCopy;
+ int ptt;
+ int rfPower;
+ int rfGain;
+ int agc;
+ int att;
+ int pre;
+ int ant;
+ int antList;
+ int rangeList;
+ int tuner;
+ int tune;
+ int bandUp;
+ int bandDown;
+ int bandChange;
+ int bkin;
+ int apf;
+ int noiseBlanker;
+ int noiseReduction, noiseReductionLevel;
+ int notchFilter;
+ int ifShift;
+} rigCommand;
diff --git a/smeter.cpp b/smeter.cpp
new file mode 100644
index 0000000..442f1a8
--- /dev/null
+++ b/smeter.cpp
@@ -0,0 +1,318 @@
+/**
+ ** This file is part of the CatRadio project.
+ ** Copyright 2022 Gianfranco Sordetti IZ8EWD .
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see .
+ **/
+
+
+#include "smeter.h"
+#include
+
+SMeter::SMeter(QWidget *parent) : QWidget(parent)
+{
+ lineColor = QColor(Qt::black);
+ bgColor = QColor(Qt::white);
+ progressColor = QColor(Qt::green);
+
+ //Default value
+ minValue = 0;
+ maxValue = 100;
+ gateValue = 80;
+ longStep = 20;
+ shortStep = 10;
+ precision = 0;
+
+ meterTx = 0;
+
+ currentValue = -54;
+}
+
+void SMeter::paintEvent(QPaintEvent *)
+{
+ QPainter painter(this);
+ painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
+
+ QFont font;
+ font = painter.font();
+ font.setPointSize(font.pointSize() - 2);
+ painter.setFont(font);
+
+ drawMeter(&painter);
+ drawProgress(&painter);
+ drawScaleSMeter(&painter);
+ drawScalePWRMeter(&painter);
+}
+
+void SMeter::drawMeter(QPainter *painter)
+{
+ painter->save();
+
+ QPen pen(lineColor, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
+ painter->setPen(pen);
+ painter->setBrush(bgColor);
+ painter->drawRect(0, height()/3+2, width()-12, height()/3-4);
+ painter->restore();
+}
+
+void SMeter::drawProgress(QPainter *painter)
+{
+ double max, min;
+ double gate;
+
+ painter->save();
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(progressColor);
+
+ if (meterTx) //RF power meter
+ {
+ max = maxValue;
+ min = minValue;
+ gate = gateValue;
+ }
+ else //SMeter
+ {
+ max = 60;
+ min = -54;
+ gate = 0;
+ }
+
+ double length = width()-14;
+ double increment = length / (max - min);
+ double initX, initXX;
+
+ if (currentValue>gate)
+ {
+ initX = (gate - min) * increment;
+ QRect rect(1, height()/3+2+1, initX, height()/3-4-2);
+ painter->drawRect(rect);
+
+ //Red bar
+ initXX = (currentValue - gate) * increment;
+ QRect rect2(initX+1, height()/3+2+1, initXX, height()/3-4-2);
+ painter->setBrush(Qt::red);
+ painter->drawRect(rect2);
+ }
+ else
+ {
+ initX = (currentValue - min) * increment;
+ QRect rect(1, height()/3+2+1, initX, height()/3-4-2);
+ painter->drawRect(rect);
+ }
+
+ painter->restore();
+}
+
+void SMeter::drawScalePWRMeter(QPainter *painter)
+{
+ painter->save();
+ painter->setPen(lineColor);
+
+ double initX = 0;
+ double initTopY = height()*2/3-2;
+ double length = width()-12;
+ double increment = length / (maxValue - minValue);
+
+ int longLineLen = 6;
+ int shortLineLen = 3;
+
+ QFontMetrics meterFont(painter->font());
+ double textHeight = meterFont.height();
+
+ //Draw scale values and scale values based on range values Long lines
+ int stepNumber = (maxValue - minValue) / shortStep;
+ for (int i = 0; i <= stepNumber; i++)
+ {
+ double j = i * shortStep + minValue;
+ if (fmod(j,longStep) == 0)
+ {
+ if (j == minValue) //Do not draw the first value
+ {
+ QPointF textPot = QPointF(initX, initTopY + textHeight);
+ painter->drawText(textPot, "PO");
+
+ initX += increment * shortStep;
+ continue;
+ }
+
+ QPointF topPot = QPointF(initX, initTopY);
+ QPointF bottomPot = QPointF(initX, initTopY + longLineLen);
+ painter->drawLine(topPot, bottomPot);
+
+ QString strValue = QString("%1").arg(j, 0, 'f', precision);
+ double textWidth = fontMetrics().horizontalAdvance(strValue);
+
+ QPointF textPot = QPointF(initX - textWidth / 2, initTopY + textHeight + longLineLen);
+ painter->drawText(textPot, strValue);
+ }
+ else
+ {
+
+ QPointF topPot = QPointF(initX, initTopY);
+ QPointF bottomPot = QPointF(initX, initTopY + shortLineLen);
+ painter->drawLine(topPot, bottomPot);
+ }
+
+ initX += increment * shortStep;
+ }
+
+ painter->restore();
+}
+
+void SMeter::drawScaleSMeter(QPainter *painter)
+{
+ int minValue = -54; //Set min and max value according to Hamlib SMeter definition
+ int maxValue = 60;
+
+ int longLineLen = 6;
+ int shortLineLen = 3;
+
+ double initX = 0;
+ int sUnit = 0;
+
+ double initBottomY = height()/3+2;
+ double length = width()-12;
+ double increment = length / (maxValue - minValue);
+
+ QFontMetrics meterFont(painter->font());
+ double textHeight = meterFont.height();
+
+ painter->save();
+ painter->setPen(lineColor);
+
+ //Draw scale values and scale values based on range values
+ int longStep = 12;
+ int shortStep = 6;
+
+ for (int i = minValue; i <= 0; i = i + shortStep) //S0 to S9
+ {
+ if (i == minValue)
+ {
+ QPointF textPot = QPointF(initX, initBottomY - 2);
+ painter->drawText(textPot, "S");
+
+ initX += increment * shortStep;
+ sUnit = sUnit + 1;
+ continue;
+ }
+
+ if (i % longStep == 0)
+ {
+ QPointF topPot = QPointF(initX, initBottomY);
+ QPointF bottomPot = QPointF(initX, initBottomY - longLineLen);
+ painter->drawLine(topPot, bottomPot);
+
+ QString strValue = QString::number(sUnit);
+ double textWidth = fontMetrics().horizontalAdvance(strValue);
+ QPointF textPot = QPointF(initX - textWidth / 2, initBottomY - textHeight / 2 - longLineLen + 2);
+ painter->drawText(textPot, strValue);
+ }
+ else
+ {
+ QPointF topPot = QPointF(initX, initBottomY);
+ QPointF bottomPot = QPointF(initX, initBottomY - shortLineLen);
+ painter->drawLine(topPot, bottomPot);
+ }
+
+ sUnit = sUnit + 1;
+ initX += increment * shortStep;
+ }
+ initX -= increment * shortStep;
+
+ shortStep = 10;
+ longStep = 20;
+
+ for (int i = 0; i <= maxValue; i = i + shortStep) //S9+ to S9+60
+ {
+ if (i % longStep == 0)
+ {
+ QPointF topPot = QPointF(initX, initBottomY);
+ QPointF bottomPot = QPointF(initX, initBottomY - longLineLen);
+ painter->drawLine(topPot, bottomPot);
+
+ if (i == 0) //Do not draw the first value
+ {
+ initX += increment * shortStep;
+ continue;
+ }
+
+ QString strValue = "+" + QString::number(i);
+ double textWidth = fontMetrics().horizontalAdvance(strValue);
+
+ QPointF textPot = QPointF(initX - textWidth / 2, initBottomY - textHeight / 2 - longLineLen + 2);
+ painter->drawText(textPot, strValue);
+ }
+ else
+ {
+ QPointF topPot = QPointF(initX, initBottomY);
+ QPointF bottomPot = QPointF(initX, initBottomY - shortLineLen);
+ painter->drawLine(topPot, bottomPot);
+ }
+
+ initX += increment * shortStep;
+ }
+
+ painter->restore();
+}
+
+void SMeter::setMinValue(double value)
+{
+ minValue = value;
+ update();
+}
+
+void SMeter::setMaxValue(double value)
+{
+ maxValue = value;
+ update();
+}
+
+void SMeter::setGateValue(double value)
+{
+ gateValue = value;
+}
+
+void SMeter::setLongStep(double value)
+{
+ longStep = value;
+ update();
+}
+
+void SMeter::setShortStep(double value)
+{
+ shortStep = value;
+ update();
+}
+
+void SMeter::setPrecision(int value)
+{
+ precision = value;
+ update();
+}
+
+void SMeter::setValue(double value)
+{
+ currentValue = value;
+ update();
+}
+
+void SMeter::setValue(int value)
+{
+ setValue(double(value));
+}
+
+void SMeter::setTx(bool Tx)
+{
+ meterTx = Tx;
+}
diff --git a/smeter.h b/smeter.h
new file mode 100644
index 0000000..f35c0f3
--- /dev/null
+++ b/smeter.h
@@ -0,0 +1,73 @@
+/**
+ ** This file is part of the CatRadio project.
+ ** Copyright 2022 Gianfranco Sordetti IZ8EWD .
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see .
+ **/
+
+
+#ifndef SMETER_H
+#define SMETER_H
+
+#include
+
+class SMeter : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit SMeter(QWidget *parent = nullptr);
+
+public slots:
+ void setMinValue(double value);
+ void setMaxValue(double value);
+ void setGateValue(double value);
+ void setLongStep(double value);
+ void setShortStep(double value);
+ void setPrecision(int value);
+
+ void setValue(double value);
+ void setValue(int value);
+
+ void setTx(bool Tx);
+
+protected:
+ void paintEvent(QPaintEvent *);
+ void drawMeter(QPainter *painter);
+ void drawProgress(QPainter *painter);
+ void drawScaleSMeter(QPainter *painter);
+ void drawScalePWRMeter(QPainter *painter);
+
+private:
+ double minValue; //Minimum scale value
+ double maxValue; //Maximum scale value
+ double gateValue; //Gate value to bar color change
+ double longStep; //Long lines with equal steps
+ double shortStep; //Short lines with equal steps
+ int precision; //Precision, the last few decimal places
+
+ double value; //target value
+ double currentValue; //current value
+
+ bool meterTx; //Switch between SMeter or PowerMeter
+
+ QColor bgColor; //background color
+ QColor lineColor; //line color
+ QColor progressColor; //progress color
+
+signals:
+
+};
+
+#endif // SMETER_H
diff --git a/submeter.cpp b/submeter.cpp
new file mode 100644
index 0000000..5052a38
--- /dev/null
+++ b/submeter.cpp
@@ -0,0 +1,195 @@
+/**
+ ** This file is part of the CatRadio project.
+ ** Copyright 2022 Gianfranco Sordetti IZ8EWD .
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see .
+ **/
+
+
+#include "submeter.h"
+#include
+#include
+
+SubMeter::SubMeter(QWidget *parent) : QWidget(parent)
+{
+ lineColor = QColor(Qt::black);
+ bgColor = QColor(Qt::white);
+ progressColor = QColor(Qt::green);
+
+ //Default value
+ minValue = 0;
+ maxValue = 10;
+ gateValue = 10;
+ longStep = 5;
+ shortStep = 1;
+ precision = 0;
+
+ currentValue = 0;
+}
+
+void SubMeter::paintEvent(QPaintEvent *)
+{
+ QPainter painter(this);
+ painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
+
+ QFont font;
+ font = painter.font();
+ font.setPointSize(font.pointSize() - 2);
+ painter.setFont(font);
+
+ drawMeter(&painter);
+ drawProgress(&painter);
+ drawScale(&painter);
+}
+
+void SubMeter::drawMeter(QPainter *painter)
+{
+ painter->save();
+ QPen pen(lineColor, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
+ painter->setPen(pen);
+ painter->setBrush(bgColor);
+ painter->drawRect(0, height()/3+2, width()-12, height()/3-4);
+ painter->restore();
+}
+
+void SubMeter::drawProgress(QPainter *painter)
+{
+ painter->save();
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(progressColor);
+
+ double length = width()-14;
+ double increment = length / (maxValue - minValue);
+
+ double initX, initXX;
+
+ if (currentValue>gateValue)
+ {
+ initX = (gateValue - minValue) * increment;
+ QRect rect(1, height()/3+2+1, initX, height()/3-4-2);
+ painter->drawRect(rect);
+
+ //Red bar
+ initXX = (currentValue - gateValue) * increment;
+ QRect rect2(initX+1, height()/3+2+1, initXX, height()/3-4-2);
+ painter->setBrush(Qt::red);
+ painter->drawRect(rect2);
+ }
+ else
+ {
+ initX = (currentValue - minValue) * increment;
+ QRect rect(1, height()/3+2+1, initX, height()/3-4-2);
+ painter->drawRect(rect);
+ }
+
+ painter->restore();
+}
+
+void SubMeter::drawScale(QPainter *painter)
+{
+ painter->save();
+ painter->setPen(lineColor);
+
+ double initX = 0;
+ double initTopY = height()*2/3-2;
+ double length = width()-12;
+ double increment = length / (maxValue - minValue);
+
+ int longLineLen = 6;
+ int shortLineLen = 3;
+
+ QFontMetrics meterFont(painter->font());
+ double textHeight = meterFont.height();
+
+ //Draw scale values and scale values based on range values
+ int stepNumber = (maxValue - minValue) / shortStep;
+ for (int i = 0; i <= stepNumber; i++)
+ {
+ double j = i * shortStep + minValue;
+ if (fmod(j,longStep) == 0)
+ {
+ if (j == minValue) //Do not draw the first value
+ {
+ initX += increment * shortStep;
+ continue;
+ }
+
+ QPointF topPot = QPointF(initX, initTopY);
+ QPointF bottomPot = QPointF(initX, initTopY + longLineLen);
+ painter->drawLine(topPot, bottomPot);
+
+ QString strValue = QString("%1").arg(j, 0, 'f', precision);
+ double textWidth = fontMetrics().horizontalAdvance(strValue);
+
+ QPointF textPot = QPointF(initX - textWidth / 2, initTopY + textHeight + longLineLen);
+ painter->drawText(textPot, strValue);
+ }
+ else
+ {
+ QPointF topPot = QPointF(initX, initTopY);
+ QPointF bottomPot = QPointF(initX, initTopY + shortLineLen);
+ painter->drawLine(topPot, bottomPot);
+ }
+
+ initX += increment * shortStep;
+ }
+
+ painter->restore();
+}
+
+void SubMeter::setMinValue(double value)
+{
+ minValue = value;
+ update();
+}
+
+void SubMeter::setMaxValue(double value)
+{
+ maxValue = value;
+ update();
+}
+
+void SubMeter::setGateValue(double value)
+{
+ gateValue = value;
+}
+
+void SubMeter::setLongStep(double value)
+{
+ longStep = value;
+ update();
+}
+
+void SubMeter::setShortStep(double value)
+{
+ shortStep = value;
+ update();
+}
+
+void SubMeter::setPrecision(int value)
+{
+ precision = value;
+ update();
+}
+
+void SubMeter::setValue(double value)
+{
+ currentValue = value;
+ update();
+}
+
+void SubMeter::setValue(int value)
+{
+ setValue(double(value));
+}
diff --git a/submeter.h b/submeter.h
new file mode 100644
index 0000000..f65573d
--- /dev/null
+++ b/submeter.h
@@ -0,0 +1,67 @@
+/**
+ ** This file is part of the CatRadio project.
+ ** Copyright 2022 Gianfranco Sordetti IZ8EWD .
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see .
+ **/
+
+
+#ifndef SUBMETER_H
+#define SUBMETER_H
+
+#include
+
+class SubMeter : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit SubMeter(QWidget *parent = nullptr);
+
+public slots:
+ void setMinValue(double value);
+ void setMaxValue(double value);
+ void setGateValue(double value);
+ void setLongStep(double value);
+ void setShortStep(double value);
+ void setPrecision(int value);
+
+ void setValue(double value);
+ void setValue(int value);
+
+protected:
+ void paintEvent(QPaintEvent *);
+ void drawMeter(QPainter *painter);
+ void drawProgress(QPainter *painter);
+ void drawScale(QPainter *painter);
+
+private:
+ double minValue; //Minimum scale value
+ double maxValue; //Maximum scale value
+ double gateValue; //Gate value to bar color change
+ double longStep; //Long lines with equal steps
+ double shortStep; //Short lines with equal steps
+ int precision; //Precision, the last few decimal places
+
+ double value; //target value
+ double currentValue; //current value
+
+ QColor bgColor; //background color
+ QColor lineColor; //line color
+ QColor progressColor; //progress color
+
+signals:
+
+};
+
+#endif // SUBMETER_H
diff --git a/vfodisplay.cpp b/vfodisplay.cpp
new file mode 100644
index 0000000..67c6d7c
--- /dev/null
+++ b/vfodisplay.cpp
@@ -0,0 +1,152 @@
+/**
+ ** This file is part of the CatRadio project.
+ ** Copyright 2022 Gianfranco Sordetti IZ8EWD .
+ **
+ ** This program is free software: you can redistribute it and/or modify
+ ** it under the terms of the GNU General Public License as published by
+ ** the Free Software Foundation, either version 3 of the License, or
+ ** (at your option) any later version.
+ **
+ ** This program is distributed in the hope that it will be useful,
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ** GNU General Public License for more details.
+ **
+ ** You should have received a copy of the GNU General Public License
+ ** along with this program. If not, see .
+ **/
+
+
+#include "vfodisplay.h"
+#include "guidata.h"
+
+#include
+#include
+#include
+
+
+extern guiConfig guiConf;
+
+
+vfoDisplay::vfoDisplay(QWidget *parent) : QWidget(parent)
+{
+ lineColor = QColor(Qt::black);
+ bgColor = QColor(Qt::white);
+ textColor = QColor(Qt::black);
+}
+
+void vfoDisplay::paintEvent(QPaintEvent *)
+{
+ //setMouseTracking(true);
+
+ QPainter painter(this);
+ painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
+
+ QFont font;
+ font = painter.font();
+ font.setPointSize(height() - 18);
+ painter.setFont(font);
+
+ drawDisplay(&painter);
+ drawText(&painter);
+}
+
+void vfoDisplay::drawDisplay(QPainter *painter)
+{
+ painter->save();
+
+ QPen pen(lineColor, 1, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin);
+ painter->setPen(pen);
+ painter->setBrush(bgColor);
+ painter->drawRect(1, 1, width()-3, height()-2);
+ painter->restore();
+}
+
+void vfoDisplay::drawText(QPainter *painter)
+{
+ painter->save();
+ painter->setPen(textColor);
+
+ QFontMetrics meterFont(painter->font());
+ double textHeight = meterFont.ascent();
+ textWidth = meterFont.horizontalAdvance("0",-1);
+
+ QPointF textPot;
+
+ long val = currentValue;
+
+ for (int i = 1; i < 10; i++)
+ {
+ val = qFloor(val/10);
+ int d = val % 10;
+
+ if (i==2)
+ {
+ textPot = QPointF(width()-3-(textWidth+2)*i-4, textHeight);
+ painter->drawText(textPot, ".");
+ }
+
+ textPot = QPointF(width()-3-(textWidth+2)*i, textHeight);
+
+ if (val==0 && d==0) painter->drawText(textPot, " ");
+ else painter->drawText(textPot, QString::number(d));
+ }
+
+ painter->restore();
+}
+
+void vfoDisplay::setValue(unsigned long value)
+{
+ currentValue = value;
+ update();
+}
+
+//* Tuning using mouse buttons
+void vfoDisplay::mousePressEvent(QMouseEvent *event)
+{
+ event->accept();
+
+ QPoint pointerPos = event->pos();
+
+ for (int i = 1; i < 10; i ++)
+ {
+ if (pointerPos.x() > (width()-3-(textWidth+2)*i+1) && pointerPos.x() < (width()-3-(textWidth+2)*(i-1)-1))
+ {
+ if (guiConf.vfoDisplayMode && event->button() == Qt::LeftButton) //Up/Down mode
+ {
+ if (pointerPos.y() < height()/2) currentValue = currentValue + pow(10,i); //Up
+ else if (currentValue - pow(10,i) > 0) currentValue = currentValue - pow(10,i); //Down
+ }
+ else if (!guiConf.vfoDisplayMode) //Left/Right mode
+ {
+ if (event->button() == Qt::LeftButton) currentValue = currentValue + pow(10,i); //LeftButton
+ else if (currentValue - pow(10,i) > 0) currentValue = currentValue - pow(10,i); //RightButton
+ }
+
+ break;
+ }
+ }
+
+ update();
+ emit on_valueChanged(currentValue);
+}
+
+//* Tuning using mouse wheel
+void vfoDisplay::wheelEvent(QWheelEvent *event)
+{
+ event->accept();
+
+ QPointF pointerPos = event->position();
+
+ for (int i = 1; i < 10; i ++)
+ {
+ if (pointerPos.x() > (width()-3-(textWidth+2)*i+1) && pointerPos.x() < (width()-3-(textWidth+2)*(i-1)-1))
+ {
+ if (event->angleDelta().y() > 0) currentValue = currentValue + pow(10,i); //Wheel up
+ else if (currentValue - pow(10,i) > 0) currentValue = currentValue - pow(10,i); //Wheel down
+ }
+ }
+
+ update();
+ emit on_valueChanged(currentValue);
+}
diff --git a/vfodisplay.h b/vfodisplay.h
new file mode 100644
index 0000000..9dee447
--- /dev/null
+++ b/vfodisplay.h
@@ -0,0 +1,37 @@
+#ifndef VFODISPLAY_H
+#define VFODISPLAY_H
+
+#include
+
+class vfoDisplay : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit vfoDisplay(QWidget *parent = nullptr);
+
+public slots:
+ void setValue(unsigned long value);
+
+signals:
+ void on_valueChanged(int value);
+
+protected:
+ void paintEvent(QPaintEvent *);
+ void drawDisplay(QPainter *painter);
+ void drawText(QPainter *painter);
+ void mousePressEvent(QMouseEvent *event); //Mouse buttons
+ void wheelEvent(QWheelEvent *event); //Mouse wheel
+
+private:
+ QColor bgColor; //background color
+ QColor lineColor; //line color
+ QColor textColor; //text color
+
+ unsigned long currentValue; //current frequency value (Hz)
+ unsigned long value; //target value
+
+ int textWidth; //number width
+};
+
+#endif // VFODISPLAY_H