From 9247e10115f067ba2b0d86c0637fe1190c5a9f47 Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Wed, 26 Mar 2014 13:21:00 +0000 Subject: [PATCH] Added support for use of "Standard" locations for writable files. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows writable files to be located in the "correct" location for each platform rather than in the directory of the executable which, in general, is not recommended or allowed in some cases. A preprocessor macro WSJT_STANDARD_FILE_LOCATIONS is used to switch be tween old and new functionality, currently it is on by default. It can be turned off by defining it to a false value (0) or more simply with cmake-gui setting the option with the same name. JTAlert can only work with the old non-standard file locations until Laurie VK3AMA chooses to support the new file locations. Even if the above is not enabled; the QSettings file is written to a user specific location so it will be shared by all instances of the program (i.e. across upgrades). See below for multiple concurrent instance support changes. Added a command line parser module for Fortran. Added 'lib/options.f90' to facilitate more complex argument passing to jt9 to cover explicit file locations. Changed the way multiple concurrent instances are handled. This is to allow the program to be run multiple times from the same installation directory. A new wsjtx command line optional argument is available "-r" or "--rig" which enables multiple concurrent instance support. The parameter of the new option is a unique name signifying a rig or equivalent. The name is used as the shared memory segment key and in window titles. The name is also used to access unique settings files and writable data files like ALL.TXT and log files. No attempt has been made to share these files between concurrent instances. If "-r" or "--rig" is used without a parameter it still enables multiple concurrent instance support for that instance. All instances must use a unique parameter, one of which may be empty. The rig name is appended the QCoreApplication::applicationName() for convenient usage like window titles. Set non Qt locale to "C". This ensures that C library functions give consistent results whatever the system locale is set to. QApplication follows the system locale as before. Thus using QApplication and its descendants like widgets and QString for all user visible formating will give correct l10n and using C/C++ library will give consistent formatting across locales. Added top level C++ exception handling to main.cpp. Because the new transceiver framework uses exceptions internally, the main function now handles any exceptions that aren't caught. Retired devsetup, replaced with Configuration. Configuration is a class that encapsulates most of the configuration behavior. Because rig configuration is so closely coupled with rig operation, Configuration serves as a proxy for access to the rig control functions. See Configuration.hpp for more details of the Configuration interface. Menu changes. Various checkable menu actions moved from main menu to the Configuration dialog. The whole settings menu has been retired with the single "Settings..." action moved to the file menu for consistency on Mac where it appears as "Preferences" in line with Mac guidelines. New data models for data used by the application. ADIF amateur band parameters, free text message macros, spot working frequencies and, station information (station descriptions and transverter offsets per band) each implement the QAbstractItemModel interface allowing them to be used directly with Qt view widgets (Bands.hpp, FrequencyList.hpp and, StationList.hpp). Configuration manages maintenance of an instance of all but the former of the above models. The ADIF band model is owned by Configuration but requires no user maintenance as it is immutable. Band combo box gets more functionality. This widget is now an editable QComboBox with some extra input capabilities. The popup list is still the list of spot working frequencies, now showing the actual frequency decorated with the band name. This allows multiple spot frequencies on a band if required. The line edit allows direct frequency entry in mega-Hertz with a completer built in to suggest the available spot working frequencies. It also allows band name entry where the first available spot working frequency is selected. Recognized band names are those that are defined by the ADIF specification and can be found in in the implementation of the ADIF bands model (Bands.cpp). If an out of band frequency is chosen, the line edit shows a warning red background and the text "OOB". Out of band is only defined by the ADIF band limits which in general are wider than any entities regulations. Qt 5.2 now supports default audio i/p and o/p devices. These devices are placeholders for whatever the user defines as the default device. Because of this they need special treatment as the actual device used is chosen at open time behind the scenes. Close-down behavior is simplified. The close-down semantics were broken such that some objects were not being shut down cleanly, this required amendments to facilitate correct close down of threads. User font selection added to Configuration UI. Buttons to set the application font and the font for the band and Rx frequency activity widgets have been added to the Configuration UI to replace the file based font size control. Free text macros now selected directly. The free text line edit widgets are now editable combo boxes that have the current free text macro definitions as their popup list. The old context menu to do this has been retired. Astronomical data window dynamically formatted and has font a chooser. This window is now autonomous, has its own font chooser and, dynamically resizes to cover the contents. Double click to Tx enabled now has its own widget in the status bar. QDir used for portable path and file name handling throughout. The "Monitor", "Decode", "Enable Tx" and, "Tune" buttons are now checkable. Being checkable allows these buttons control their own state and rendering. Calls to PSK Reporter interface simplified. In mainwindow.cpp the calls to this interface are rationalized to just 3 locations. Manipulation of ALL.TXT simplified. Moved, where possible, to common functions. Elevated frequency types to be Qt types. Frequency and FrequencyDelta defined as Qt types in their meta-type system (Radio.hpp). They are integral types for maximum accuracy. Re-factored rig control calls in mainwindow.cpp. The new Configuration proxy access to rig control required many changes (mostly simplifications) to the MainWindow rig control code. Some common code has been gathered in member functions like qsy(), monitor(), band_changed() and auto_tx_mode(). Rig control enhancements. The rig control for clients interface is declared as an abstract interface (See Transceiver.hpp). Concrete implementations of this interface are provided for the Hamlib rig control library, DX Lab Suite Commander via a TCP/IP command channel, Ham Radio Deluxe also via a TCP/IP command channel and, OmniRig via its Windows COM server interface. Concrete Transceiver implementations are expected to be moved to a separate thread after construction since many operations are blocking and not suitable for running in a GUI thread. To facilitate this all instantiation of concrete Transceiver instances are handled by Configuration using a factory class (TransceiverFactory) for configuration parameter based instantiation. Various common functionality shared by different rig interface implementations are factored out into helper base classes that implement or delegate parts of the Transceiver interface. They are TransceiverBase which caches state to minimize expensive rig commands, it also maps the Transceiver interface into a more convenient form for implementation (template methods). PollingTransceiver that provides a state polling mechanism that only reports actual changes. EmulateSplitTransceiver that provides split operation by QSYing on PTT state changes. EmulateSplitTransceiver can be used with any implementation as it follows the GoF Decorator pattern and can wrap any Transceiver implementation. OmniRigTransceiver is derived directly from TransceiverBase since it doesn't require polling due to its asynchronous nature. OmniRigTransceiver is only built on Windows as it is a COM server client. To build it you must first install the OmniRig client on the development machine (http://www.dxatlas.com/omnirig/). DXLabSuiteCommanderTransceiver derives from PollingTransceiver since it is a synchronous communications channel. No third party library is required for this interface. HRDTransceiver also derives from PollingTransceiver. The HRD interface library has been reverse engineered to provide functionality with all available versions of HRD. No third party libraries are required. HamlibTransceiver likewise derives from PollingTransceiver since the Hamlib asynchronous interface is non-functional. Although this class will interface with the release version of Hamlib (1.2.15.3); for correct operation on most rigs it needs to run with the latest master branch code of Hamlib. During development many changes to Hamlib have been submitted and accepted, hence this requirement. Hamlib source can be obtained from git://git.code.sf.net/p/hamlib/code and at the time of writing he master branch was at SHA 6e4432. The Hamlib interface directly calls the "C" interface and the modified rigclass.{h,cpp} files have been retired. There is a rig type selection of "None" which may be used for non-CAT rigs, this is actually a connection to the dummy Hamlib device. PollingTransvceiver derives from TransceiverBase and TransceiverBase derives from the Transceiver interface. Each interface implementation offers some possibility of PTT control via a different serial port than the CAT port. We also support PTT control directly via a second serial port. This is done by delegating to a dummy Hamlib instance which is only used for PTT control. This means that DXLabSuiteCommanderTransceiver, HRDTransceiver and OmniRigTransceiver always wrap a dummy HamlibTransceiver instance. The factory class TransceiverFactory manages all these constructional complexities. Serial port selection combo boxes are now editable with a manually entered value being saved to the settings file. This allows a non-standard port device to be used without having to edit the settings file manually. For TCP/IP network CAT interfaces; the network address and port may be specified allowing the target device to be located on a different machine from the one running wsjtx if required. The default used when the address field is left blank is the correct one for normal usage on the local host. Selecting a polling interval of zero is no longer possible, this is because the rig control capability can no longer support one way connection. This is in line with most other CAT control software. In the Configuration dialog there are options to select split mode control by the software and mode control by the software. For the former "None", "Rig" and "Fake it" are available, for the latter "None", "USB" and, "Data" are available. Because tone generation is implicitly linked to split mode operation; it is no longer possible to have the software in split mode and the rig not or vice versa. This may mean some rigs cannot be used in split mode and therefore not in dual JT65+JT9 until issues with CAT control with that rig are resolved. Single mode with VOX keying and no CAT control are still possible so even the most basic transceiver setup is supported as before. Configuration now supports a frequency offset suitable for transverter operation. The station details model (StationList.hpp) includes a column to store an offset for each band if required. CMake build script improvements. The CMakeLists.txt from the 'lib' directory has been retired with its contents merged into the top level CMakeLists.txt. Install target support has been greatly improved with the Release build configuration now building a fully standalone installation on Mac and Windows. The Debug configuration still builds an installation that has environment dependencies for external libraries, which is desirable for testing and debugging. Package target support is largely complete for Mac, Windows and, Linux, it should be possible to build release installers directly from CMake/CPack. Cmake FindXXXX.cmake modules have been added to improve the location of fftw-3 and Hamlib packages. Version numbers are now stored in Versions.cmake and work in concert with automatic svn revision lookup during build. The version string becomes 'rlocal'± if there are any uncommitted changes in the build source tree. Moved resource like files to Qt resources. Because location of resource files (when they cannot go into the installation directory because of packaging rules) is hard to standardize. I have used the Qt resource system for all ancillary data files. Some like kvasd.dat are dumped out to the temp (working directory) because they are accessed by an external program, others like the audio samples are copied out so they appear in the data directory under the default save directory. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@3929 ab8295b8-cf94-4d9e-aec4-7959e3be5d79 --- AudioDevice.cpp | 23 + AudioDevice.hpp | 8 +- Bands.cpp | 196 ++ Bands.hpp | 58 + CALL3.TXT | 0 CMake/Modules/FindFFTW3.cmake | 93 + CMake/Modules/Findhamlib.cmake | 28 + CMake/Modules/LibFindMacros.cmake | 112 + CMake/Modules/QtAxMacros.cmake | 36 + CMake/VersionCompute.cmake | 8 + CMake/cmake_uninstall.cmake.in | 22 + CMake/getsvn.cmake | 15 + CMakeCPackOptions.cmake.in | 81 + CMakeLists.txt | 852 ++++- ConfigTest.cpp | 63 + Configuration.cpp | 2128 +++++++++++++ Configuration.hpp | 188 ++ Configuration.ui | 1812 +++++++++++ Copyright.txt | 1 + DXLabSuiteCommanderTransceiver.cpp | 377 +++ DXLabSuiteCommanderTransceiver.hpp | 50 + Detector.cpp | 2 + Detector.hpp | 2 +- EmulateSplitTransceiver.cpp | 102 + EmulateSplitTransceiver.hpp | 52 + ForeignKeyDelegate.cpp | 77 + ForeignKeyDelegate.hpp | 34 + FrequencyItemDelegate.cpp | 36 + FrequencyItemDelegate.hpp | 56 + FrequencyLineEdit.cpp | 40 + FrequencyLineEdit.hpp | 45 + FrequencyList.cpp | 358 +++ FrequencyList.hpp | 59 + GetUserId.cpp | 75 + GetUserId.hpp | 8 + HRDTransceiver.cpp | 766 +++++ HRDTransceiver.hpp | 95 + HamlibTransceiver.cpp | 845 +++++ HamlibTransceiver.hpp | 68 + Info.plist.in | 10 + LICENSE_WHEATLEY.TXT => LICENSE_WHEATLEY.txt | 60 +- LiveFrequencyValidator.cpp | 92 + LiveFrequencyValidator.hpp | 52 + Mac-wsjtx-startup.sh | 16 + Modulator.cpp | 5 +- Modulator.hpp | 2 +- NetworkServerLookup.cpp | 83 + NetworkServerLookup.hpp | 38 + OmniRigTransceiver.cpp | 741 +++++ OmniRigTransceiver.hpp | 73 + PollingTransceiver.cpp | 209 ++ PollingTransceiver.hpp | 60 + Radio.cpp | 72 + Radio.hpp | 47 + SettingsGroup.hpp | 34 + StationList.cpp | 551 ++++ StationList.hpp | 96 + TestConfiguration.cpp | 470 +++ TestConfiguration.hpp | 21 + TestConfiguration.ui | 627 ++++ TraceFile.cpp | 118 + TraceFile.hpp | 23 + Transceiver.cpp | 51 + Transceiver.hpp | 169 + TransceiverBase.cpp | 269 ++ TransceiverBase.hpp | 136 + TransceiverFactory.cpp | 301 ++ TransceiverFactory.hpp | 155 + Versions.cmake | 10 + about.cpp | 2 + about.ui | 74 +- artwork/DragNDrop Background.svg | 143 + artwork/README | 27 + artwork/installer_logo.svg | 1126 +++++++ artwork/make_graphics.sh | 58 + artwork/wsjtx_globe_1024x1024.svg | 602 ++++ artwork/wsjtx_globe_128x128.svg | 839 +++++ astro.cpp | 208 +- astro.h | 50 +- astro.ui | 109 +- contrib/Commander TCPIP Mesages.pdf | Bin 0 -> 168173 bytes contrib/HRDInterface001.dll | Bin 1635328 -> 0 bytes devsetup.cpp | 750 ----- devsetup.h | 156 - devsetup.ui | 2835 ----------------- displaytext.cpp | 4 +- displaytext.h | 2 +- getfile.cpp | 11 +- icons/Darwin/DragNDrop Background.png | Bin 0 -> 32276 bytes icons/Darwin/wsjtx.iconset/icon_128x128.png | Bin 0 -> 17659 bytes .../Darwin/wsjtx.iconset/icon_128x128@2x.png | Bin 0 -> 43423 bytes icons/Darwin/wsjtx.iconset/icon_16x16.png | Bin 0 -> 1084 bytes icons/Darwin/wsjtx.iconset/icon_16x16@2x.png | Bin 0 -> 2448 bytes icons/Darwin/wsjtx.iconset/icon_256x256.png | Bin 0 -> 43423 bytes .../Darwin/wsjtx.iconset/icon_256x256@2x.png | Bin 0 -> 104868 bytes icons/Darwin/wsjtx.iconset/icon_32x32.png | Bin 0 -> 2448 bytes icons/Darwin/wsjtx.iconset/icon_32x32@2x.png | Bin 0 -> 5864 bytes icons/Darwin/wsjtx.iconset/icon_512x512.png | Bin 0 -> 104868 bytes .../Darwin/wsjtx.iconset/icon_512x512@2x.png | Bin 0 -> 251432 bytes icons/README | 3 + icons/Unix/wsjtx_icon.png | Bin 0 -> 17659 bytes icons/windows-icons/installer_logo.bmp | Bin 0 -> 25818 bytes icons/windows-icons/wsjtx.ico | Bin 0 -> 550870 bytes lib/CMakeLists.txt | 208 -- lib/decoder.f90 | 2 + lib/extract.F90 | 13 +- lib/jt9.f90 | 71 +- lib/jt9a.f90 | 17 +- lib/jt9c.f90 | 2 +- lib/options.f90 | 337 ++ lib/prog_args.f90 | 4 + lib/tmoonsub.c | 10 +- lib/usleep.c | 2 + libHRDInterface001.a | Bin 8546 -> 0 bytes logbook/logbook.cpp | 90 +- logbook/logbook.h | 4 +- logqso.cpp | 25 +- logqso.h | 4 +- main.cpp | 151 +- mainwindow.cpp | 2513 +++++++-------- mainwindow.h | 203 +- mainwindow.ui | 270 +- meterwidget.cpp | 2 + pimpl_h.hpp | 29 + pimpl_impl.hpp | 28 + plotter.cpp | 58 +- postflight.sh.in | 3 + postupgrade.sh.in | 2 + psk_reporter.cpp | 2 + qt_helpers.hpp | 59 + rigclass.cpp | 335 -- rigclass.h | 98 - signalmeter.cpp | 2 + soundin.cpp | 4 +- soundin.h | 14 +- soundout.cpp | 4 +- soundout.h | 6 +- widegraph.cpp | 25 +- widegraph.h | 3 + wsjtx.desktop | 11 + wsjtx.pro | 118 +- wsjtx.qrc | 39 + wsjtx.rc | 2 +- wsjtx_DMG.DS_Store | Bin 0 -> 15364 bytes wsjtx_config.h.in | 27 + 145 files changed, 18714 insertions(+), 6544 deletions(-) create mode 100644 AudioDevice.cpp create mode 100644 Bands.cpp create mode 100644 Bands.hpp delete mode 100644 CALL3.TXT create mode 100644 CMake/Modules/FindFFTW3.cmake create mode 100644 CMake/Modules/Findhamlib.cmake create mode 100644 CMake/Modules/LibFindMacros.cmake create mode 100644 CMake/Modules/QtAxMacros.cmake create mode 100644 CMake/VersionCompute.cmake create mode 100644 CMake/cmake_uninstall.cmake.in create mode 100644 CMake/getsvn.cmake create mode 100644 CMakeCPackOptions.cmake.in create mode 100644 ConfigTest.cpp create mode 100644 Configuration.cpp create mode 100644 Configuration.hpp create mode 100644 Configuration.ui create mode 100644 Copyright.txt create mode 100644 DXLabSuiteCommanderTransceiver.cpp create mode 100644 DXLabSuiteCommanderTransceiver.hpp create mode 100644 EmulateSplitTransceiver.cpp create mode 100644 EmulateSplitTransceiver.hpp create mode 100644 ForeignKeyDelegate.cpp create mode 100644 ForeignKeyDelegate.hpp create mode 100644 FrequencyItemDelegate.cpp create mode 100644 FrequencyItemDelegate.hpp create mode 100644 FrequencyLineEdit.cpp create mode 100644 FrequencyLineEdit.hpp create mode 100644 FrequencyList.cpp create mode 100644 FrequencyList.hpp create mode 100644 GetUserId.cpp create mode 100644 GetUserId.hpp create mode 100644 HRDTransceiver.cpp create mode 100644 HRDTransceiver.hpp create mode 100644 HamlibTransceiver.cpp create mode 100644 HamlibTransceiver.hpp create mode 100644 Info.plist.in rename LICENSE_WHEATLEY.TXT => LICENSE_WHEATLEY.txt (98%) create mode 100644 LiveFrequencyValidator.cpp create mode 100644 LiveFrequencyValidator.hpp create mode 100644 Mac-wsjtx-startup.sh create mode 100644 NetworkServerLookup.cpp create mode 100644 NetworkServerLookup.hpp create mode 100644 OmniRigTransceiver.cpp create mode 100644 OmniRigTransceiver.hpp create mode 100644 PollingTransceiver.cpp create mode 100644 PollingTransceiver.hpp create mode 100644 Radio.cpp create mode 100644 Radio.hpp create mode 100644 SettingsGroup.hpp create mode 100644 StationList.cpp create mode 100644 StationList.hpp create mode 100644 TestConfiguration.cpp create mode 100644 TestConfiguration.hpp create mode 100644 TestConfiguration.ui create mode 100644 TraceFile.cpp create mode 100644 TraceFile.hpp create mode 100644 Transceiver.cpp create mode 100644 Transceiver.hpp create mode 100644 TransceiverBase.cpp create mode 100644 TransceiverBase.hpp create mode 100644 TransceiverFactory.cpp create mode 100644 TransceiverFactory.hpp create mode 100644 Versions.cmake create mode 100644 artwork/DragNDrop Background.svg create mode 100644 artwork/README create mode 100644 artwork/installer_logo.svg create mode 100644 artwork/make_graphics.sh create mode 100644 artwork/wsjtx_globe_1024x1024.svg create mode 100644 artwork/wsjtx_globe_128x128.svg create mode 100644 contrib/Commander TCPIP Mesages.pdf delete mode 100644 contrib/HRDInterface001.dll delete mode 100644 devsetup.cpp delete mode 100644 devsetup.h delete mode 100644 devsetup.ui create mode 100644 icons/Darwin/DragNDrop Background.png create mode 100644 icons/Darwin/wsjtx.iconset/icon_128x128.png create mode 100644 icons/Darwin/wsjtx.iconset/icon_128x128@2x.png create mode 100644 icons/Darwin/wsjtx.iconset/icon_16x16.png create mode 100644 icons/Darwin/wsjtx.iconset/icon_16x16@2x.png create mode 100644 icons/Darwin/wsjtx.iconset/icon_256x256.png create mode 100644 icons/Darwin/wsjtx.iconset/icon_256x256@2x.png create mode 100644 icons/Darwin/wsjtx.iconset/icon_32x32.png create mode 100644 icons/Darwin/wsjtx.iconset/icon_32x32@2x.png create mode 100644 icons/Darwin/wsjtx.iconset/icon_512x512.png create mode 100644 icons/Darwin/wsjtx.iconset/icon_512x512@2x.png create mode 100644 icons/README create mode 100644 icons/Unix/wsjtx_icon.png create mode 100644 icons/windows-icons/installer_logo.bmp create mode 100644 icons/windows-icons/wsjtx.ico delete mode 100644 lib/CMakeLists.txt create mode 100644 lib/options.f90 create mode 100644 lib/prog_args.f90 delete mode 100644 libHRDInterface001.a create mode 100644 pimpl_h.hpp create mode 100644 pimpl_impl.hpp create mode 100644 postflight.sh.in create mode 100644 postupgrade.sh.in create mode 100644 qt_helpers.hpp delete mode 100644 rigclass.cpp delete mode 100644 rigclass.h create mode 100644 wsjtx.desktop create mode 100644 wsjtx.qrc create mode 100644 wsjtx_DMG.DS_Store diff --git a/AudioDevice.cpp b/AudioDevice.cpp new file mode 100644 index 000000000..871273d19 --- /dev/null +++ b/AudioDevice.cpp @@ -0,0 +1,23 @@ +#include "AudioDevice.hpp" + +#include + +namespace +{ + struct init + { + init () + { + qRegisterMetaType ("AudioDevice::Channel"); + } + } static_initializer; +} + +bool AudioDevice::open (OpenMode mode, Channel channel) +{ + m_channel = channel; + + // ensure we are unbuffered + return QIODevice::open (mode | QIODevice::Unbuffered); +} + diff --git a/AudioDevice.hpp b/AudioDevice.hpp index 5139c35e4..63f8b5999 100644 --- a/AudioDevice.hpp +++ b/AudioDevice.hpp @@ -24,13 +24,7 @@ public: return "both" == s ? Both : "right" == s ? Right : "left" == s ? Left : Mono; } - bool open (OpenMode mode, Channel channel) - { - m_channel = channel; - - // ensure we are unbuffered - return QIODevice::open (mode | QIODevice::Unbuffered); - } + bool open (OpenMode mode, Channel channel); bool isSequential () const {return true;} diff --git a/Bands.cpp b/Bands.cpp new file mode 100644 index 000000000..747eb7f41 --- /dev/null +++ b/Bands.cpp @@ -0,0 +1,196 @@ +#include "Bands.hpp" + +#include + +#include +#include + +namespace +{ + // Local structure to hold a single ADIF band definition. + struct ADIF_band + { + char const * const name_; + Radio::Frequency lower_bound_; + Radio::Frequency upper_bound_; + }; + + // Table of ADIF band definitions as defined in the ADIF + // specification. + ADIF_band constexpr ADIF_bands[] = { + {"2190m", 136000u, 137000u}, + {"630m", 472000u, 479000u}, + {"560m", 501000u, 504000u}, + {"160m", 1800000u, 2000000u}, + {"80m", 3500000u, 4000000u}, + {"60m", 5102000u, 5406500u}, + {"40m", 7000000u, 7300000u}, + {"30m", 10000000u, 10150000u}, + {"20m", 14000000u, 14350000u}, + {"17m", 18068000u, 18168000u}, + {"15m", 21000000u, 21450000u}, + {"12m", 24890000u, 24990000u}, + {"10m", 28000000u, 29700000u}, + {"6m", 50000000u, 54000000u}, + {"4m", 70000000u, 71000000u}, + {"2m", 144000000u, 148000000u}, + {"1.25m", 222000000u, 225000000u}, + {"70cm", 420000000u, 450000000u}, + {"33cm", 902000000u, 928000000u}, + {"23cm", 1240000000u, 1300000000u}, + {"13cm", 2300000000u, 2450000000u}, + {"9cm", 3300000000u, 3500000000u}, + {"6cm", 5650000000u, 5925000000u}, + {"3cm", 10000000000u, 10500000000u}, + {"1.25cm", 24000000000u, 24250000000u}, + {"6mm", 47000000000u, 47200000000u}, + {"4mm", 75500000000u, 81000000000u}, + {"2.5mm", 119980000000u, 120020000000u}, + {"2mm", 142000000000u, 149000000000u}, + {"1mm", 241000000000u, 250000000000u}, + }; + + auto constexpr out_of_band = "OOB"; + + int constexpr table_rows () + { + return sizeof (ADIF_bands) / sizeof (ADIF_bands[0]); + } +} + +Bands::Bands (QObject * parent) + : QAbstractTableModel {parent} +{ +} + +QModelIndex Bands::find (QVariant const& v) const +{ + auto f = v.value (); + auto end_iter = ADIF_bands + table_rows (); + auto row_iter = std::find_if (ADIF_bands, end_iter, [f] (ADIF_band const& band) { + return band.lower_bound_ <= f && f <= band.upper_bound_; + }); + if (row_iter != end_iter) + { + return index (row_iter - ADIF_bands, 0); // return the band row index + } + + return QModelIndex {}; +} + +int Bands::rowCount (QModelIndex const& parent) const +{ + return parent.isValid () ? 0 : table_rows (); +} + +int Bands::columnCount (QModelIndex const& parent) const +{ + return parent.isValid () ? 0 : 3; +} + +Qt::ItemFlags Bands::flags (QModelIndex const& index) const +{ + return QAbstractTableModel::flags (index) | Qt::ItemIsDropEnabled; +} + +QVariant Bands::data (QModelIndex const& index, int role) const +{ + QVariant item; + + if (!index.isValid ()) + { + // Hijack root for OOB string. + if (Qt::DisplayRole == role) + { + item = out_of_band; + } + } + else + { + auto row = index.row (); + auto column = index.column (); + + if (row < table_rows ()) + { + switch (role) + { + case Qt::ToolTipRole: + case Qt::AccessibleDescriptionRole: + switch (column) + { + case 0: item = tr ("Band name"); break; + case 1: item = tr ("Lower frequency limit"); break; + case 2: item = tr ("Upper frequency limit"); break; + } + break; + + case SortRole: + case Qt::DisplayRole: + case Qt::EditRole: + switch (column) + { + case 0: + if (SortRole == role) + { + // band name sorts by lower bound + item = ADIF_bands[row].lower_bound_; + } + else + { + item = ADIF_bands[row].name_; + } + break; + + case 1: item = ADIF_bands[row].lower_bound_; break; + case 2: item = ADIF_bands[row].upper_bound_; break; + } + break; + + case Qt::AccessibleTextRole: + switch (column) + { + case 0: item = ADIF_bands[row].name_; break; + case 1: item = ADIF_bands[row].lower_bound_; break; + case 2: item = ADIF_bands[row].upper_bound_; break; + } + break; + + case Qt::TextAlignmentRole: + switch (column) + { + case 0: + item = Qt::AlignHCenter + Qt::AlignVCenter; + break; + + case 1: + case 2: + item = Qt::AlignRight + Qt::AlignVCenter; + break; + } + break; + } + } + } + return item; +} + +QVariant Bands::headerData (int section, Qt::Orientation orientation, int role) const +{ + QVariant result; + + if (Qt::DisplayRole == role && Qt::Horizontal == orientation) + { + switch (section) + { + case 0: result = tr ("Band"); break; + case 1: result = tr ("Lower Limit"); break; + case 2: result = tr ("Upper Limit"); break; + } + } + else + { + result = QAbstractTableModel::headerData (section, orientation, role); + } + + return result; +} diff --git a/Bands.hpp b/Bands.hpp new file mode 100644 index 000000000..41d3810af --- /dev/null +++ b/Bands.hpp @@ -0,0 +1,58 @@ +#ifndef BANDS_HPP__ +#define BANDS_HPP__ + +#include + +#include "Radio.hpp" + +// +// Class Bands +// +// Encapsulates information about amateur radio bands as defined by +// the ADIF specification. The model is immutable. The rows are +// stored in asscending order of frequency. +// +// Responsibilities +// +// Provides a well known band name mapped to lower and upper +// frequency limits. Also provides a convenience operation to +// determine the band details for any given frequency, the result of +// which may be invalid if the given frequency doesn't lie within a +// recognised band. +// +// Collaborations +// +// Implements the QAbstractTableModel interface as an immutable table +// where rows are bands and columns are band name, lower frequency +// limit and, upper ferquency limit respectively. +// +class Bands final + : public QAbstractTableModel +{ +public: + explicit Bands (QObject * parent = nullptr); + + // + // Model API + // + QModelIndex find (QVariant const&) const; // find band Frequency is in + + // Custom role for sorting. + static int constexpr SortRole = Qt::UserRole; + + // Implement the QAbstractTableModel interface + int rowCount (QModelIndex const& parent = QModelIndex {}) const override; + int columnCount (QModelIndex const& parent = QModelIndex {}) const override; + Qt::ItemFlags flags (QModelIndex const& = QModelIndex {}) const override; + QVariant headerData (int section, Qt::Orientation, int = Qt::DisplayRole) const override; + + // The value return for the Qt::DisplayRole role for the root of the + // model (invalid index) is a special string representing out of + // band. + // + // All columns return a number for the custom role SortRole, this + // number defines a strict frequency order for the rows. + QVariant data (QModelIndex const&, int role = Qt::DisplayRole) const override; +}; + +#endif diff --git a/CALL3.TXT b/CALL3.TXT deleted file mode 100644 index e69de29bb..000000000 diff --git a/CMake/Modules/FindFFTW3.cmake b/CMake/Modules/FindFFTW3.cmake new file mode 100644 index 000000000..b242bc71b --- /dev/null +++ b/CMake/Modules/FindFFTW3.cmake @@ -0,0 +1,93 @@ +# - Try to find FFTW3. +# Usage: find_package(FFTW3 [COMPONENTS [single double long-double threads]]) +# +# Variables used by this module: +# FFTW3_ROOT_DIR - FFTW3 root directory +# Variables defined by this module: +# FFTW3_FOUND - system has FFTW3 +# FFTW3_INCLUDE_DIR - the FFTW3 include directory (cached) +# FFTW3_INCLUDE_DIRS - the FFTW3 include directories +# (identical to FFTW3_INCLUDE_DIR) +# FFTW3[FL]?_LIBRARY - the FFTW3 library - double, single(F), +# long-double(L) precision (cached) +# FFTW3[FL]?_THREADS_LIBRARY - the threaded FFTW3 library - double, single(F), +# long-double(L) precision (cached) +# FFTW3_LIBRARIES - list of all FFTW3 libraries found + +# Copyright (C) 2009-2010 +# ASTRON (Netherlands Institute for Radio Astronomy) +# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +# +# This file is part of the LOFAR software suite. +# The LOFAR software suite 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. +# +# The LOFAR software suite 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 the LOFAR software suite. If not, see . +# +# $Id: FindFFTW3.cmake 15918 2010-06-25 11:12:42Z loose $ + +# Use double precision by default. +if (FFTW3_FIND_COMPONENTS MATCHES "^$") + set (_components double) +else () + set (_components ${FFTW3_FIND_COMPONENTS}) +endif () + +# Loop over each component. +set (_libraries) +foreach (_comp ${_components}) + if (_comp STREQUAL "single") + list (APPEND _libraries fftw3f) + elseif (_comp STREQUAL "double") + list (APPEND _libraries fftw3) + elseif (_comp STREQUAL "long-double") + list (APPEND _libraries fftw3l) + elseif (_comp STREQUAL "threads") + set (_use_threads ON) + else (_comp STREQUAL "single") + message (FATAL_ERROR "FindFFTW3: unknown component `${_comp}' specified. " + "Valid components are `single', `double', `long-double', and `threads'.") + endif (_comp STREQUAL "single") +endforeach (_comp ${_components}) + +# If using threads, we need to link against threaded libraries as well. +if (_use_threads) + set (_thread_libs) + foreach (_lib ${_libraries}) + list (APPEND _thread_libs ${_lib}_threads) + endforeach (_lib ${_libraries}) + set (_libraries ${_thread_libs} ${_libraries}) +endif (_use_threads) + +# Keep a list of variable names that we need to pass on to +# find_package_handle_standard_args(). +set (_check_list) + +# Search for all requested libraries. +foreach (_lib ${_libraries}) + string (TOUPPER ${_lib} _LIB) + find_library (${_LIB}_LIBRARY NAMES ${_lib} ${_lib}-3 + HINTS ${FFTW3_ROOT_DIR} PATH_SUFFIXES lib) + mark_as_advanced (${_LIB}_LIBRARY) + list (APPEND FFTW3_LIBRARIES ${${_LIB}_LIBRARY}) + list (APPEND _check_list ${_LIB}_LIBRARY) +endforeach (_lib ${_libraries}) + +# Search for the header file. +find_path (FFTW3_INCLUDE_DIR fftw3.h + HINTS ${FFTW3_ROOT_DIR} PATH_SUFFIXES include) +mark_as_advanced (FFTW3_INCLUDE_DIR) +list(APPEND _check_list FFTW3_INCLUDE_DIR) + +# Handle the QUIETLY and REQUIRED arguments and set FFTW_FOUND to TRUE if +# all listed variables are TRUE +include (FindPackageHandleStandardArgs) +find_package_handle_standard_args (FFTW3 DEFAULT_MSG ${_check_list}) diff --git a/CMake/Modules/Findhamlib.cmake b/CMake/Modules/Findhamlib.cmake new file mode 100644 index 000000000..2a368188a --- /dev/null +++ b/CMake/Modules/Findhamlib.cmake @@ -0,0 +1,28 @@ +# - Try to find hamlib +# Once done, this will define: +# +# hamlib_FOUND - system has Hamlib-2 +# hamlib_INCLUDE_DIRS - the Hamlib-2 include directories +# hamlib_LIBRARIES - link these to use Hamlib-2 + +include (LibFindMacros) + +# Use pkg-config to get hints about paths +libfind_pkg_check_modules (hamlib_PKGCONF hamlib) + +# Include dirs +find_path (hamlib_INCLUDE_DIR + NAMES hamlib/rig.h + PATHS ${hamlib_PKGCONF_INCLUDE_DIRS} +) + +# The library +find_library (hamlib_LIBRARY + NAMES hamlib hamlib-2 + PATHS ${hamlib_PKGCONF_LIBRARY_DIRS} +) + +# Set the include dir variables and the libraries and let libfind_process do the rest +set (hamlib_PROCESS_INCLUDES hamlib_INCLUDE_DIR) +set (hamlib_PROCESS_LIBS hamlib_LIBRARY) +libfind_process (hamlib) diff --git a/CMake/Modules/LibFindMacros.cmake b/CMake/Modules/LibFindMacros.cmake new file mode 100644 index 000000000..aa2143c82 --- /dev/null +++ b/CMake/Modules/LibFindMacros.cmake @@ -0,0 +1,112 @@ +# Version 1.0 (2013-04-12) +# Public Domain, originally written by Lasse Kärkkäinen +# Published at http://www.cmake.org/Wiki/CMake:How_To_Find_Libraries + +# If you improve the script, please modify the forementioned wiki page because +# I no longer maintain my scripts (hosted as static files at zi.fi). Feel free +# to remove this entire header if you use real version control instead. + +# Changelog: +# 2013-04-12 Added version number (1.0) and this header, no other changes +# 2009-10-08 Originally published + + +# Works the same as find_package, but forwards the "REQUIRED" and "QUIET" arguments +# used for the current package. For this to work, the first parameter must be the +# prefix of the current package, then the prefix of the new package etc, which are +# passed to find_package. +macro (libfind_package PREFIX) + set (LIBFIND_PACKAGE_ARGS ${ARGN}) + if (${PREFIX}_FIND_QUIETLY) + set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} QUIET) + endif (${PREFIX}_FIND_QUIETLY) + if (${PREFIX}_FIND_REQUIRED) + set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} REQUIRED) + endif (${PREFIX}_FIND_REQUIRED) + find_package(${LIBFIND_PACKAGE_ARGS}) +endmacro (libfind_package) + +# CMake developers made the UsePkgConfig system deprecated in the same release (2.6) +# where they added pkg_check_modules. Consequently I need to support both in my scripts +# to avoid those deprecated warnings. Here's a helper that does just that. +# Works identically to pkg_check_modules, except that no checks are needed prior to use. +macro (libfind_pkg_check_modules PREFIX PKGNAME) + if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) + include(UsePkgConfig) + pkgconfig(${PKGNAME} ${PREFIX}_INCLUDE_DIRS ${PREFIX}_LIBRARY_DIRS ${PREFIX}_LDFLAGS ${PREFIX}_CFLAGS) + else (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) + find_package(PkgConfig) + if (PKG_CONFIG_FOUND) + pkg_check_modules(${PREFIX} ${PKGNAME}) + endif (PKG_CONFIG_FOUND) + endif (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) +endmacro (libfind_pkg_check_modules) + +# Do the final processing once the paths have been detected. +# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain +# all the variables, each of which contain one include directory. +# Ditto for ${PREFIX}_PROCESS_LIBS and library files. +# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES. +# Also handles errors in case library detection was required, etc. +macro (libfind_process PREFIX) + # Skip processing if already processed during this run + if (NOT ${PREFIX}_FOUND) + # Start with the assumption that the library was found + set (${PREFIX}_FOUND TRUE) + + # Process all includes and set _FOUND to false if any are missing + foreach (i ${${PREFIX}_PROCESS_INCLUDES}) + if (${i}) + set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIRS} ${${i}}) + mark_as_advanced(${i}) + else (${i}) + set (${PREFIX}_FOUND FALSE) + endif (${i}) + endforeach (i) + + # Process all libraries and set _FOUND to false if any are missing + foreach (i ${${PREFIX}_PROCESS_LIBS}) + if (${i}) + set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARIES} ${${i}}) + mark_as_advanced(${i}) + else (${i}) + set (${PREFIX}_FOUND FALSE) + endif (${i}) + endforeach (i) + + # Print message and/or exit on fatal error + if (${PREFIX}_FOUND) + if (NOT ${PREFIX}_FIND_QUIETLY) + message (STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}") + endif (NOT ${PREFIX}_FIND_QUIETLY) + else (${PREFIX}_FOUND) + if (${PREFIX}_FIND_REQUIRED) + foreach (i ${${PREFIX}_PROCESS_INCLUDES} ${${PREFIX}_PROCESS_LIBS}) + message("${i}=${${i}}") + endforeach (i) + message (FATAL_ERROR "Required library ${PREFIX} NOT FOUND.\nInstall the library (dev version) and try again. If the library is already installed, use ccmake to set the missing variables manually.") + endif (${PREFIX}_FIND_REQUIRED) + endif (${PREFIX}_FOUND) + endif (NOT ${PREFIX}_FOUND) +endmacro (libfind_process) + +macro(libfind_library PREFIX basename) + set(TMP "") + if(MSVC80) + set(TMP -vc80) + endif(MSVC80) + if(MSVC90) + set(TMP -vc90) + endif(MSVC90) + set(${PREFIX}_LIBNAMES ${basename}${TMP}) + if(${ARGC} GREATER 2) + set(${PREFIX}_LIBNAMES ${basename}${TMP}-${ARGV2}) + string(REGEX REPLACE "\\." "_" TMP ${${PREFIX}_LIBNAMES}) + set(${PREFIX}_LIBNAMES ${${PREFIX}_LIBNAMES} ${TMP}) + endif(${ARGC} GREATER 2) + find_library(${PREFIX}_LIBRARY + NAMES ${${PREFIX}_LIBNAMES} + PATHS ${${PREFIX}_PKGCONF_LIBRARY_DIRS} + ) +endmacro(libfind_library) + diff --git a/CMake/Modules/QtAxMacros.cmake b/CMake/Modules/QtAxMacros.cmake new file mode 100644 index 000000000..6a4cd1442 --- /dev/null +++ b/CMake/Modules/QtAxMacros.cmake @@ -0,0 +1,36 @@ +# +# Macros for processing ActiveX and COM controls with ActiveQt +# + +if (WIN32) + include (CMakeParseArguments) + + find_program (DUMPCPP_Executable dumpcpp.exe) + + # wrap_ax_server (outfiles inputfile ...) + + function (WRAP_AX_SERVER outfiles) + set (options) + set (oneValueArgs) + set (multiValueArgs OPTIONS) + + cmake_parse_arguments (_WRAP_AX_SERVER "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + set (ax_server_files ${_WRAP_AX_SERVER_UNPARSED_ARGUMENTS}) + set (ax_server_options ${_WRAP_AX_SERVER_OPTIONS}) + + foreach (it ${ax_server_files}) + get_filename_component (outfile ${it} NAME_WE) + get_filename_component (infile ${it} ABSOLUTE) + set (outfile ${CMAKE_CURRENT_BINARY_DIR}/${outfile}) + add_custom_command ( + OUTPUT ${outfile}.h ${outfile}.cpp + COMMAND ${DUMPCPP_Executable} + ARGS ${AX_SERVER_options} -o "${outfile}" "${infile}" + MAIN_DEPENDENCY ${infile} VERBATIM) + list (APPEND ${outfiles} ${outfile}.cpp) + endforeach() + set(${outfiles} ${${outfiles}} PARENT_SCOPE) + endfunction () + +endif (WIN32) \ No newline at end of file diff --git a/CMake/VersionCompute.cmake b/CMake/VersionCompute.cmake new file mode 100644 index 000000000..b726a9161 --- /dev/null +++ b/CMake/VersionCompute.cmake @@ -0,0 +1,8 @@ +# Load version number components. +include (${wsjtx_SOURCE_DIR}/Versions.cmake) + +# Compute the full version string. +set (wsjtx_VERSION ${WSJTX_VERSION_MAJOR}.${WSJTX_VERSION_MINOR}.${WSJTX_VERSION_PATCH}) +if (WSJTX_RC) + set (wsjtx_VERSION ${wsjtx_VERSION}-rc${WSJTX_RC}) +endif () diff --git a/CMake/cmake_uninstall.cmake.in b/CMake/cmake_uninstall.cmake.in new file mode 100644 index 000000000..23b3064a0 --- /dev/null +++ b/CMake/cmake_uninstall.cmake.in @@ -0,0 +1,22 @@ +if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + message (FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +endif () + +file (READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +string (REGEX REPLACE "\n" ";" files "${files}") +foreach (file ${files}) + message (STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + if (EXISTS "$ENV{DESTDIR}${file}") + exec_program ( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + if ("${rm_retval}" STREQUAL 0) + else () + message (FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + endif () + else () + message (STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") + endif () +endforeach () diff --git a/CMake/getsvn.cmake b/CMake/getsvn.cmake new file mode 100644 index 000000000..7d946d597 --- /dev/null +++ b/CMake/getsvn.cmake @@ -0,0 +1,15 @@ +find_package (Subversion) +if (Subversion_FOUND AND EXISTS ${PROJECT_SOURCE_DIR}/.svn) + # the FindSubversion.cmake module is part of the standard distribution + include (FindSubversion) + # extract working copy information for SOURCE_DIR into MY_XXX variables + Subversion_WC_INFO (${SOURCE_DIR} MY) + # write a file with the SVNVERSION define + file (WRITE svnversion.h.txt "#define SVNVERSION r${MY_WC_REVISION}\n") +else (Subversion_FOUND AND EXISTS ${PROJECT_SOURCE_DIR}/.svn) + file (WRITE svnversion.h.txt "#define SVNVERSION local\n") +endif (Subversion_FOUND AND EXISTS ${PROJECT_SOURCE_DIR}/.svn) + +# copy the file to the final header only if the version changes +# reduces needless rebuilds +execute_process (COMMAND ${CMAKE_COMMAND} -E copy_if_different svnversion.h.txt svnversion.h) diff --git a/CMakeCPackOptions.cmake.in b/CMakeCPackOptions.cmake.in new file mode 100644 index 000000000..43b566c0d --- /dev/null +++ b/CMakeCPackOptions.cmake.in @@ -0,0 +1,81 @@ +# This file is configured at cmake time, and loaded at cpack time. +# To pass variables to cpack from cmake, they must be configured +# in this file. + +set (CPACK_PACKAGE_VENDOR "Joe Taylor, K1JT") +set (CPACK_PACKAGE_CONTACT "k1jt@arrl.net") +set (CPACK_PACKAGE_DESCRIPTION_FILE "@PROJECT_SOURCE_DIR@/Copyright.txt") +set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "WSJT-X - JT9 and JT65 Modes for LF, MF and HF Amateur Radio") +set (CPACK_RESOURCE_FILE_LICENSE "@PROJECT_SOURCE_DIR@/LICENSE_WHEATLEY.txt") +set (CPACK_PACKAGE_INSTALL_DIRECTORY ${CPACK_PACKAGE_NAME}) +set (CPACK_PACKAGE_EXECUTABLES wsjtx "WSJT-X") +set (CPACK_CREATE_DESKTOP_LINKS wsjtx) +set (CPACK_STRIP_FILES TRUE) + +# +# components +# +#set (CPACK_COMPONENT_APPLICATIONS_DISPLAY_NAME "WSJT-X Application") +#set (CPACK_COMPONENT_APPLICATIONS_DESCRIPTION "@WSJTX_DESCRIPTION_SUMMARY@") + +if (CPACK_GENERATOR MATCHES "NSIS") + set (CPACK_STRIP_FILES FALSE) # breaks Qt packaging on Windows + + set (CPACK_NSIS_INSTALL_ROOT "C:\\WSJT") + + # set the install/unistall icon used for the installer itself + # There is a bug in NSI that does not handle full unix paths properly. + set (CPACK_NSIS_MUI_ICON "@PROJECT_SOURCE_DIR@/icons/windows-icons\\wsjtx.ico") + set (CPACK_NSIS_MUI_UNIICON "@PROJECT_SOURCE_DIR@/icons/windows-icons\\wsjtx.ico") + # set the package header icon for MUI + set (CPACK_PACKAGE_ICON "@PROJECT_SOURCE_DIR@/icons/windows-icons\\installer_logo.bmp") + # tell cpack to create links to the doc files + set (CPACK_NSIS_MENU_LINKS + "@PROJECT_MANUAL@" "WSJT-X Documentation" + "@PROJECT_HOMEPAGE@" "WSJT-X Web Site" + ) + # Use the icon from wsjtx for add-remove programs + set (CPACK_NSIS_INSTALLED_ICON_NAME "@PROJECT_BINARY_DIR@\\wsjtx.exe") + + set (CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_DESCRIPTION_SUMMARY}") + set (CPACK_NSIS_HELP_LINK "@PROJECT_MANUAL@") + set (CPACK_NSIS_URL_INFO_ABOUT "@PROJECT_HOMEPAGE@") + set (CPACK_NSIS_CONTACT "${CPACK_PACKAGE_CONTACT}") + set (CPACK_NSIS_MUI_FINISHPAGE_RUN "wsjtx.exe") + set (CPACK_NSIS_MODIFY_PATH ON) +endif () + +if ("${CPACK_GENERATOR}" STREQUAL "PackageMaker") + set (CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-pkg") + set (CPACK_PACKAGE_DEFAULT_LOCATION "/Applications") + set (CPACK_PACKAGING_INSTALL_PREFIX "/") +endif () + +if ("${CPACK_GENERATOR}" STREQUAL "DragNDrop") + set (CPACK_DMG_BACKGROUND_IMAGE "@PROJECT_SOURCE_DIR@/icons/Darwin/DragNDrop Background.png") + set (CPACK_DMG_DS_STORE "@PROJECT_SOURCE_DIR@/wsjtx_DMG.DS_Store") + set (CPACK_BUNDLE_NAME "@WSJTX_BUNDLE_NAME@") + set (CPACK_PACKAGE_ICON "@PROJECT_BINARY_DIR@/wsjtx.icns") + set (CPACK_BUNDLE_ICON "@PROJECT_BINARY_DIR@/wsjtx.icns") + set (CPACK_BUNDLE_STARTUP_COMMAND "@PROJECT_SOURCE_DIR@/Mac-wsjtx-startup.sh") +endif () + +if ("${CPACK_GENERATOR}" STREQUAL "WIX") + # Reset CPACK_PACKAGE_VERSION to deal with WiX restriction. + # But the file names still use the full CMake_VERSION value: + set (CPACK_PACKAGE_FILE_NAME + "${CPACK_PACKAGE_NAME}-@wsjtx_VERSION@-${CPACK_SYSTEM_NAME}") + set (CPACK_SOURCE_PACKAGE_FILE_NAME + "${CPACK_PACKAGE_NAME}-@wsjtx_VERSION@-Source") + + if (NOT CPACK_WIX_SIZEOF_VOID_P) + set (CPACK_WIX_SIZEOF_VOID_P "@CMAKE_SIZEOF_VOID_P@") + endif () +endif () + +if ("${CPACK_GENERATOR}" STREQUAL "DEB") + set (CPACK_PACKAGE_FILE_NAME "@DEBIAN_PACKAGE_FILE_NAME@") + set (CPACK_DEBIAN_PACKAGE_HOMEPAGE "@PROJECT_HOMEPAGE@") +endif ("${CPACK_GENERATOR}" STREQUAL "DEB") + +message (STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}") diff --git a/CMakeLists.txt b/CMakeLists.txt index f0dc4ca71..fbb57a18e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,314 @@ -cmake_minimum_required (VERSION 2.8.9) +cmake_minimum_required (VERSION 2.8.9 FATAL_ERROR) project (wsjtx C CXX Fortran) -set (WSJTX_VERSION_MAJOR 1) -set (WSJTX_VERSION_MINOR 3) +set (WSJTX_COPYRIGHT "Copyright (C) 2001-2014 by Joe Taylor, K1JT") + +set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMake/Modules) + +include (${PROJECT_SOURCE_DIR}/CMake/VersionCompute.cmake) + + +# +# Options & features +# +# Some of these directly effect compilation by being defined in +# wsjtx_config.h.in which makes them available to the C/C++ +# pre-processor. +# +option (UPDATE_TRANSLATIONS "Update source translation translations/*.ts +files (WARNING: make clean will delete the source .ts files! Danger!)") +option (WSJT_SHARED_RUNTIME "Debugging option that allows running from a shared Cloud directory.") +option (WSJT_QDEBUG_IN_RELEASE "Leave qDebug statements in Release configuration.") +option (WSJT_TRACE_CAT "Debugging option that turns on CAT diagnostics.") +option (WSJT_TRACE_CAT_POLLS "Debugging option that turns on CAT diagnostics during polling.") +option (WSJT_HAMLIB_TRACE "Debugging option that turns on full Hamlib internal diagnostics.") +option (WSJT_STANDARD_FILE_LOCATIONS "All non-installation files located in \"Standard\" platfom specific locations." ON) + + +# +# install locations +# +set (WSJT_BIN_DESTINATION bin) +set (WSJT_LIB_DESTINATION lib) +set (WSJT_SHARE_DESTINATION share/wsjtx) +set (WSJT_DOC_DESTINATION share/wsjtx/doc) +set (WSJT_PLUGIN_DESTINATION lib/plugins) +set (WSJT_QT_CONF_DESTINATION bin) + + +# +# project information +# +set (PROJECT_HOMEPAGE "http://www.physics.princeton.edu/pulsar/K1JT/wsjtx.html") +set (PROJECT_MANUAL "http://www.physics.princeton.edu/pulsar/K1JT/wsjtx-doc/wsjtx-main-toc2.html") + + +# +# Project sources +# +set (wsjt_qt_CXXSRCS + NetworkServerLookup.cpp + Radio.cpp + Bands.cpp + FrequencyList.cpp + StationList.cpp + FrequencyLineEdit.cpp + FrequencyItemDelegate.cpp + ForeignKeyDelegate.cpp + LiveFrequencyValidator.cpp + GetUserId.cpp + TraceFile.cpp + AudioDevice.cpp + Transceiver.cpp + TransceiverBase.cpp + EmulateSplitTransceiver.cpp + TransceiverFactory.cpp + PollingTransceiver.cpp + HamlibTransceiver.cpp + HRDTransceiver.cpp + DXLabSuiteCommanderTransceiver.cpp + ) + +set (ConfigTest_CXXSRCS + Configuration.cpp + TestConfiguration.cpp + ConfigTest.cpp + ) + +set (jt9_CXXSRCS + lib/ipcomm.cpp + ) + +set (wsjtx_CXXSRCS + logbook/adif.cpp + logbook/countrydat.cpp + logbook/countriesworked.cpp + logbook/logbook.cpp + psk_reporter.cpp + Modulator.cpp + Detector.cpp + logqso.cpp + displaytext.cpp + decodedtext.cpp + getfile.cpp + soundout.cpp + soundin.cpp + meterwidget.cpp + signalmeter.cpp + plotter.cpp + widegraph.cpp + about.cpp + astro.cpp + mainwindow.cpp + Configuration.cpp + main.cpp + ) + +if (WIN32) + set (ConfigTest_CXXSRCS + ${ConfigTest_CXXSRCS} + OmniRigTransceiver.cpp + ) + + set (wsjt_CXXSRCS + ${wsjt_CXXSRCS} + killbyname.cpp + ) + + set (wsjt_qt_CXXSRCS + ${wsjt_qt_CXXSRCS} + OmniRigTransceiver.cpp + ) +endif (WIN32) + +set (wsjt_FSRCS + lib/afc65b.f90 + lib/afc9.f90 + lib/analytic.f90 + lib/astro.f90 + lib/astrosub.f90 + lib/astro0.f90 + lib/azdist.f90 + lib/baddata.f90 + lib/ccf2.f90 + lib/ccf65.f90 + lib/chkhist.f90 + lib/chkss2.f90 + lib/coord.f90 + lib/db.f90 + lib/dcoord.f90 + lib/decode65a.f90 + lib/decode65b.f90 + lib/decode9.f90 + lib/decoder.f90 + lib/deg2grid.f90 + lib/demod64a.f90 + lib/determ.f90 + lib/dot.f90 + lib/downsam9.f90 + lib/encode232.f90 + lib/entail.f90 + lib/extract.F90 + lib/geocentric.f90 + lib/f77_wisdom.f90 + lib/fano232.f90 + lib/fchisq.f90 + lib/fchisq65.f90 + lib/fil3.f90 + lib/fil4.f90 + lib/fil6521.f90 + lib/filbig.f90 + lib/fillcom.f90 + lib/flat1.f90 + lib/flat2.f90 + lib/flat3.f90 + lib/flat65.f90 + lib/four2a.f90 + lib/gen65.f90 + lib/genjt9.f90 + lib/geodist.f90 + lib/getlags.f90 + lib/getpfx1.f90 + lib/getpfx2.f90 + lib/graycode.f90 + lib/graycode65.f90 + lib/grid2deg.f90 + lib/grid2k.f90 + lib/grid2n.f90 + lib/indexx.f90 + lib/interleave63.f90 + lib/interleave9.f90 + lib/jt65a.f90 + lib/k2grid.f90 + lib/moon2.f90 + lib/moondop.f90 + lib/morse.f90 + lib/move.f90 + lib/n2grid.f90 + lib/nchar.f90 + lib/options.f90 + lib/packbits.f90 + lib/packcall.f90 + lib/packgrid.f90 + lib/packmsg.f90 + lib/packtext.f90 + lib/pctile.f90 + lib/peakdt9.f90 + lib/pfxdump.f90 + lib/polfit.f90 + lib/prog_args.f90 + lib/sec_midn.f90 + lib/setup65.f90 + lib/sleep_msec.f90 + lib/smo.f90 + lib/smo121.f90 + lib/softsym.f90 + lib/sort.f90 + lib/ssort.f90 + lib/stdmsg.f90 + lib/sun.f90 + lib/symspec.f90 + lib/symspec2.f90 + lib/symspec65.f90 + lib/sync9.f90 + lib/timer.f90 + lib/tm2.f90 + lib/toxyz.f90 + lib/twkfreq.f90 + lib/twkfreq65.f90 + lib/unpackbits.f90 + lib/unpackcall.f90 + lib/unpackgrid.f90 + lib/unpackmsg.f90 + lib/unpacktext.f90 + lib/zplot9.f90 + ) + +set (wsjt_CSRCS + lib/decode_rs.c + lib/encode_rs.c + lib/gran.c + lib/igray.c + lib/init_rs.c + lib/tmoonsub.c + lib/usleep.c + lib/wrapkarn.c + ) + +set (ConfigTest_UISRCS + TestConfiguration.ui + Configuration.ui + ) + +set (wsjtx_UISRCS + mainwindow.ui + about.ui + astro.ui + widegraph.ui + logqso.ui + Configuration.ui + ) + +set (all_C_and_CXXSRCS + ${wsjt_CSRCS} + ${wsjt_CXXSRCS} + ${wsjt_qt_CXXSRCS} + ${jt9_CXXSRCS} + ${ConfigTest_CXXSRCS} + ${wsjtx_CXXSRCS} + ) + +if (APPLE) + set (WSJTX_ICON_FILE ${CMAKE_PROJECT_NAME}.icns) + set (ICONSRCS + icons/Darwin/${CMAKE_PROJECT_NAME}.iconset/icon_16x16.png + icons/Darwin/${CMAKE_PROJECT_NAME}.iconset/icon_16x16@2x.png + icons/Darwin/${CMAKE_PROJECT_NAME}.iconset/icon_32x32.png + icons/Darwin/${CMAKE_PROJECT_NAME}.iconset/icon_32x32@2x.png + icons/Darwin/${CMAKE_PROJECT_NAME}.iconset/icon_128x128.png + icons/Darwin/${CMAKE_PROJECT_NAME}.iconset/icon_128x128@2x.png + icons/Darwin/${CMAKE_PROJECT_NAME}.iconset/icon_256x256.png + icons/Darwin/${CMAKE_PROJECT_NAME}.iconset/icon_256x256@2x.png + icons/Darwin/${CMAKE_PROJECT_NAME}.iconset/icon_512x512.png + icons/Darwin/${CMAKE_PROJECT_NAME}.iconset/icon_512x512@2x.png + ) + add_custom_command ( + OUTPUT ${WSJTX_ICON_FILE} + COMMAND iconutil -c icns --output "${CMAKE_BINARY_DIR}/${WSJTX_ICON_FILE}" "${CMAKE_SOURCE_DIR}/icons/Darwin/${CMAKE_PROJECT_NAME}.iconset" + DEPENDS ${ICONSRCS} + COMMENT "Building Icons" + ) +endif (APPLE) + +set_source_files_properties (${WSJTX_ICON_FILE} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) + +if (NOT WSJT_QDEBUG_IN_RELEASE) + set_directory_properties (PROPERTIES COMPILE_DEFINITIONS_RELEASE "QT_NO_DEBUG_OUTPUT;QT_NO_WARNING_OUTPUT") + set_directory_properties (PROPERTIES COMPILE_DEFINITIONS_MINSIZEREL "QT_NO_DEBUG_OUTPUT;QT_NO_WARNING_OUTPUT") +endif (NOT WSJT_QDEBUG_IN_RELEASE) + +set_property (SOURCE ${all_C_and_CXXSRCS} APPEND PROPERTY COMPILE_FLAGS "-include wsjtx_config.h") +set_property (SOURCE ${all_C_and_CXXSRCS} APPEND PROPERTY OBJECT_DEPENDS wsjtx_config.h) + +if (WIN32) + # generate the OmniRig COM interface source + find_program (DUMPCPP dumpcpp) + if (DUMPCPP-NOTFOUND) + message (FATAL_ERROR "dumpcpp tool not found") + endif (DUMPCPP-NOTFOUND) + execute_process ( + COMMAND ${DUMPCPP} -getfile {4FE359C5-A58F-459D-BE95-CA559FB4F270} + OUTPUT_VARIABLE AXSERVER + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + string (STRIP "${AXSERVER}" AXSERVER) + if (NOT AXSERVER) + message (FATAL_ERROR "You need to install OmniRig on this computer") + endif (NOT AXSERVER) + string (REPLACE "\"" "" AXSERVER ${AXSERVER}) + file (TO_CMAKE_PATH ${AXSERVER} AXSERVERSRCS) +endif (WIN32) if (POLICY CMP0020) cmake_policy (SET CMP0020 NEW) # link to Qt winmain on Windows @@ -18,79 +323,142 @@ endif (NOT CMAKE_BUILD_TYPE) # -# C++ setup +# decide on platform specifc packing and fixing up # +if (APPLE) + set (WSJTX_BUNDLE_VERSION ${wsjtx_VERSION}) -set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") + # make sure CMAKE_INSTALL_PREFIX ends in / + string (LENGTH "${CMAKE_INSTALL_PREFIX}" LEN) + math (EXPR LEN "${LEN} -1" ) + string (SUBSTRING "${CMAKE_INSTALL_PREFIX}" ${LEN} 1 ENDCH) + if (NOT "${ENDCH}" STREQUAL "/") + set (CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/") + endif () + # install inside bundle + # set (CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}wsjtx.app") + + set (WSJT_PLUGIN_DESTINATION ${CMAKE_PROJECT_NAME}.app/Contents/PlugIns) + set (WSJT_QT_CONF_DESTINATION ${CMAKE_PROJECT_NAME}.app/Contents/Resources) + set (WSJT_SHARE_DESTINATION ${CMAKE_PROJECT_NAME}.app/Contents/Resources) + set (WSJT_BIN_DESTINATION ${CMAKE_PROJECT_NAME}.app/Contents/MacOS) +endif (APPLE) + +#set (QT_NEED_RPATH FALSE) +#if (NOT "${QT_LIBRARY_DIR}" STREQUAL "/lib" AND NOT "${QT_LIBRARY_DIR}" STREQUAL "/usr/lib" AND NOT "${QT_LIBRARY_DIR}" STREQUAL "/lib64" AND NOT "${QT_LIBRARY_DIR}" STREQUAL "/usr/lib64") +# set (QT_NEED_RPATH TRUE) +#endif () + + +# +# C & C++ setup +# +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra") +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -std=c++11 -fexceptions -frtti") if (WIN32) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-keep-inline-dllexport") endif (WIN32) +if (APPLE) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") +else (APPLE) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") +endif (APPLE) -set (CXXSRCS - logbook/adif.cpp - logbook/countrydat.cpp - logbook/countriesworked.cpp - logbook/logbook.cpp - rigclass.cpp - psk_reporter.cpp - Modulator.cpp - Detector.cpp - logqso.cpp - displaytext.cpp - decodedtext.cpp - getfile.cpp - soundout.cpp - soundin.cpp - meterwidget.cpp - signalmeter.cpp - plotter.cpp - widegraph.cpp - devsetup.cpp - about.cpp - astro.cpp - mainwindow.cpp - main.cpp - ) +# +# Fortran setup +# +set (General_FFLAGS "-fbounds-check -Wall -Wno-conversion -fno-second-underscore") -if (WIN32) - set (CXXSRCS ${CXXSRCS} killbyname.cpp) -endif (WIN32) +# FFLAGS depend on the compiler +get_filename_component (Fortran_COMPILER_NAME ${CMAKE_Fortran_COMPILER} NAME) -set_property (SOURCE ${CXXSRCS} APPEND PROPERTY COMPILE_FLAGS "-include wsjtx_config.h") +if (Fortran_COMPILER_NAME MATCHES "gfortran.*") + # gfortran + set (CMAKE_Fortran_FLAGS_RELEASE "-funroll-all-loops -fno-f2c -O3 ${General_FFLAGS}") + set (CMAKE_Fortran_FLAGS_DEBUG "-fno-f2c -O0 -g ${General_FFLAGS}") +elseif (Fortran_COMPILER_NAME MATCHES "ifort.*") + # ifort (untested) + set (CMAKE_Fortran_FLAGS_RELEASE "-f77rtl -O3 ${General_FFLAGS}") + set (CMAKE_Fortran_FLAGS_DEBUG "-f77rtl -O0 -g ${General_FFLAGS}") +elseif (Fortran_COMPILER_NAME MATCHES "g77") + # g77 + set (CMAKE_Fortran_FLAGS_RELEASE "-funroll-all-loops -fno-f2c -O3 -m32 ${General_FFLAGS}") + set (CMAKE_Fortran_FLAGS_DEBUG "-fno-f2c -O0 -g -m32 ${General_FFLAGS}") +else (Fortran_COMPILER_NAME MATCHES "gfortran.*") + message ("CMAKE_Fortran_COMPILER full path: " ${CMAKE_Fortran_COMPILER}) + message ("Fortran compiler: " ${Fortran_COMPILER_NAME}) + message ("No optimized Fortran compiler flags are known, we just try -O2...") + set (CMAKE_Fortran_FLAGS_RELEASE "-O2 ${General_FFLAGS}") + set (CMAKE_Fortran_FLAGS_DEBUG "-O0 -g ${General_FFLAGS}") +endif (Fortran_COMPILER_NAME MATCHES "gfortran.*") + + +# +# setup and test Fortran C/C++ interaction +# + +include (FortranCInterface) +FortranCInterface_VERIFY (CXX QUIET) +FortranCInterface_HEADER (FC.h MACRO_NAMESPACE "FC_" SYMBOL_NAMESPACE "FC_" + SYMBOLS ) -set (UISRCS - mainwindow.ui - about.ui - astro.ui - devsetup.ui - widegraph.ui - logqso.ui -) # # sort out pre-requisites # # -# libfftw3 setup +# Setup RPATH so that built executable targets will run in both the +# build tree and the install location without having to set a +# (DYLD|LD)_LIBRARY_PATH override. # -find_path (fftw3f_INCLUDES fftw3.f) -find_library (fftw3f_LIBRARIES NAMES fftw3f fftw3f-3) -include_directories (${fftw3f_INCLUDES}) + +# use the full RPATH of the build tree +set (CMAKE_SKIP_BUILD_RPATH FALSE) + +# when building, don't use the install RPATH, it will still be used +# later on in the install phase +set (CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) + +set (CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${WSJT_LIB_DESTINATION}") + +# add teh automaticaly determined parts of the RPATH which point to +# directories outside of the build tree to the install RPATH +set (CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + +# the RPATH to be used when installing, but only if it's not a system +# directory +list (FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/${WSJT_LIB_DESTINATION}" isSystemDir) +if ("${isSystemDir}" STREQUAL "-1") + set (CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${WSJT_LIB_DESTINATION}") +endif ("${isSystemDir}" STREQUAL "-1") + + +# +# fftw3 single precsion library +# +find_package (FFTW3 COMPONENTS single REQUIRED) +if (NOT FFTW3_FOUND) + message (FATAL_ERROR "fftw3 single precsion library not found") +endif (NOT FFTW3_FOUND) +include_directories (${FFTW3_INCLUDE_DIRS}) # # libhamlib setup # -find_path (hamlib_INCLUDES hamlib/rig.h) -find_library (hamlib_LIBRARIES NAMES hamlib hamlib-2 PATH_SUFFIXES msvc gcc) -include_directories (${hamlib_INCLUDES}) +find_package (hamlib REQUIRED) +if (NOT hamlib_FOUND) + message (FATAL_ERROR "hamlib library not found") +endif (NOT hamlib_FOUND) +include_directories (${hamlib_INCLUDE_DIRS}) if (WIN32) - find_library (hamlib_RUNTIME NAMES hamlib hamlib-2 PATH_SUFFIXES bin) - get_filename_component (_hamlib_runtime_path "${hamlib_RUNTIME}" PATH) - file (GLOB hamlib_BACKENDS ${_hamlib_runtime_path}/hamlib*.dll) - find_library (usb_RUNTIME NAMES usb0 PATH_SUFFIXES bin) + find_library (hamlib_RUNTIME NAMES hamlib hamlib-2 PATH_SUFFIXES bin) + get_filename_component (_hamlib_runtime_path "${hamlib_RUNTIME}" PATH) + file (GLOB hamlib_BACKENDS ${_hamlib_runtime_path}/hamlib*.dll) + find_library (usb_RUNTIME NAMES usb0 PATH_SUFFIXES bin) endif (WIN32) @@ -102,117 +470,373 @@ endif (WIN32) find_package (Qt5Widgets REQUIRED) find_package (Qt5Multimedia REQUIRED) +if (WIN32) + add_definitions (-DQT_NEEDS_QTMAIN) + find_package (Qt5AxContainer REQUIRED) +endif (WIN32) + +# +# stuff only qmake can tell us +# +get_target_property (QMAKE_EXECUTABLE Qt5::qmake LOCATION) +function (QUERY_QMAKE VAR RESULT) + exec_program (${QMAKE_EXECUTABLE} ARGS "-query ${VAR}" RETURN_VALUE return_code OUTPUT_VARIABLE output) + if (NOT return_code) + file (TO_CMAKE_PATH "${output}" output) + set (${RESULT} ${output} PARENT_SCOPE) + endif (NOT return_code) +endfunction (QUERY_QMAKE) + +query_qmake (QT_INSTALL_PLUGINS QT_PLUGINS_DIR) +query_qmake (QT_INSTALL_IMPORTS QT_IMPORTS_DIR) +query_qmake (QT_HOST_DATA QT_DATA_DIR) +set (QT_MKSPECS_DIR ${QT_DATA_DIR}/mkspecs) + # Tell CMake to run moc when necessary set (CMAKE_AUTOMOC ON) # don't use Qt "keywords" signal, slot, emit in generated files to # avoid compatability issue with other libraries -#ADD_DEFINITIONS (-DQT_NO_KEYWORDS) +# ADD_DEFINITIONS (-DQT_NO_KEYWORDS) +# ADD_DEFINITIONS (-DUNICODE) #as per qmake # As moc files are generated in the binary dir, tell CMake to always # look for includes there: set (CMAKE_INCLUDE_CURRENT_DIR ON) # project definitions -add_definitions (-DQT5) +add_definitions (-DQT5 -DCMAKE_BUILD -DBIGSYM=1) if (CMAKE_HOST_UNIX) add_definitions (-DUNIX) elseif (CMAKE_HOST_WIN32) add_definitions (-DWIN32) endif () -# add_definitions (-DWSJT_SOFT_KEYING) -set_property (DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_RELEASE QT_NO_DEBUG_OUTPUT QT_NO_WARNING_OUTPUT) - - -# -# build the subdirectories -# -add_subdirectory (lib) - # # fetch kvasd # -if (APPLE) - set (kvasd_NAME http://svn.berlios.de/wsvn/wsjt/trunk/KVASD_gfortran_Mac${CMAKE_EXECUTABLE_SUFFIX}) -else () - set (kvasd_NAME http://www.physics.princeton.edu/pulsar/K1JT/kvasd${CMAKE_EXECUTABLE_SUFFIX}) -endif () +set (kvasd_NAME https://svn.code.sf.net/p/wsjt/wsjt/trunk/kvasd-binary/${CMAKE_SYSTEM_NAME}/kvasd${CMAKE_EXECUTABLE_SUFFIX}) file ( DOWNLOAD ${kvasd_NAME} contrib/kvasd${CMAKE_EXECUTABLE_SUFFIX} + TIMEOUT 10 STATUS kvasd_STATUS LOG kvasd_LOG SHOW_PROGRESS ) message (${kvasd_LOG}) list (GET kvasd_STATUS 0 kvasd_RC) -if (!kvasd_RC) - message (FATAL_ERROR "${kvasd_STATUS}") -endif (!kvasd_RC) +if (kvasd_RC) + message (WARNING "${kvasd_STATUS}") +endif (kvasd_RC) add_custom_target (kvasd DEPENDS contrib/kvasd${CMAKE_EXECUTABLE_SUFFIX}) # UI generation -qt5_wrap_ui (GENUISRCS ${UISRCS}) +qt5_wrap_ui (GENUISRCS ${ConfigTest_UISRCS} ${wsjtx_UISRCS}) -add_executable (wsjtx ${CXXSRCS} ${GENUISRCS} wsjtx.rc) -target_link_libraries (wsjtx jt9impl ${hamlib_LIBRARIES} ${fftw3f_LIBRARIES}) +# Resource generation +qt5_add_resources (wsjtx_RESOURCES_RCC wsjtx.qrc) + +# AX COM servers if (WIN32) - target_link_libraries (wsjtx ${CMAKE_CURRENT_SOURCE_DIR}/libHRDInterface001.a) - set_target_properties (wsjtx PROPERTIES LINK_FLAGS_RELEASE "${LINKER_FLAGS_RELEASE} -mwindows") + include (QtAxMacros) + wrap_ax_server (GENAXSRCS ${AXSERVERSRCS}) endif (WIN32) + + +# +# targets +# + +# build a library of package functionality +add_library (wsjt STATIC ${wsjt_CSRCS} ${wsjt_CXXSRCS} ${wsjt_FSRCS}) + +# build a library of package Qt functionality +add_library (wsjt_qt STATIC ${wsjt_qt_CXXSRCS} ${GENAXSRCS}) +qt5_use_modules (wsjt_qt Widgets OpenGL Network) +if (WIN32) + qt5_use_modules (wsjt_qt AxContainer AxBase) +endif (WIN32) + +add_executable (jt9sim lib/jt9sim.f90 wsjtx.rc) +target_link_libraries (jt9sim wsjt) + +add_executable (jt9code lib/jt9code.f90 wsjtx.rc) +target_link_libraries (jt9code wsjt) + +add_executable (jt9 lib/jt9.f90 lib/jt9a.f90 lib/jt9b.f90 lib/jt9c.f90 ${jt9_CXXSRCS} wsjtx.rc) +target_link_libraries (jt9 wsjt ${FFTW3F_LIBRARY}) +qt5_use_modules (jt9 Core) + +# build configuration dialog and transceiver interface test application +#add_executable (ConfigTest ${ConfigTest_CXXSRCS} ${ConfigTest_UISRCS} wsjtx.rc) +#target_link_libraries (ConfigTest wsjt wsjt_qt ${hamlib_LIBRARIES}) +#qt5_use_modules (ConfigTest Widgets OpenGL Network Multimedia) + +# build the main application +add_executable (wsjtx WIN32 MACOSX_BUNDLE ${wsjtx_CXXSRCS} ${wsjtx_UISRCS} wsjtx.rc ${WSJTX_ICON_FILE} ${wsjtx_RESOURCES_RCC}) +qt5_use_modules (wsjtx Widgets OpenGL Network Multimedia) + +set_target_properties (wsjtx PROPERTIES + MACOSX_BUNDLE_INFO_STRING "${WSJTX_DESCRIPTION_SUMMARY}" + MACOSX_BUNDLE_ICON_FILE "${WSJTX_ICON_FILE}" + MACOSX_BUNDLE_BUNDLE_VERSION ${wsjtx_VERSION} + MACOSX_BUNDLE_SHORT_VERSION_STRING "v${wsjtx_VERSION}" + MACOSX_BUNDLE_LONG_VERSION_STRING "Version ${wsjtx_VERSION}" + MACOSX_BUNDLE_BUNDLE_NAME "WSJT-X" + MACOSX_BUNDLE_COPYRIGHT "${WSJTX_COPYRIGHT}" + ) + +target_link_libraries (wsjtx wsjt wsjt_qt ${hamlib_LIBRARIES} ${FFTW3F_LIBRARY}) add_dependencies (wsjtx kvasd) -qt5_use_modules (wsjtx Widgets Multimedia OpenGL) - - -install ( - TARGETS wsjtx - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ) - -install (DIRECTORY Palettes DESTINATION bin PATTERN *.pal) -install (DIRECTORY samples DESTINATION bin/save) -install (FILES - shortcuts.txt - mouse_commands.txt - prefixes.txt - cty.dat - kvasd.dat - DESTINATION bin - ) - -install ( - PROGRAMS ${CMAKE_BINARY_DIR}/contrib/kvasd${CMAKE_EXECUTABLE_SUFFIX} - DESTINATION bin -) if (WIN32) - install ( - FILES ${hamlib_RUNTIME} ${hamlib_BACKENDS} ${fftw3f_LIBRARIES} ${usb_RUNTIME} contrib/HRDInterface001.dll - DESTINATION bin COMPONENT Runtime + set_target_properties ( + wsjtx + # ConfigTest + PROPERTIES LINK_FLAGS_RELEASE "${LINKER_FLAGS_RELEASE} -mwindows" ) endif (WIN32) -# a custom target that is always built -ADD_CUSTOM_TARGET (revisiontag ALL) +# +# installation +# +install (TARGETS wsjtx + RUNTIME DESTINATION ${WSJT_BIN_DESTINATION} + LIBRARY DESTINATION ${WSJT_LIB_DESTINATION} + BUNDLE DESTINATION . + # COMPONENT Runtime + ) -# creates svnversion.h using cmake script -ADD_CUSTOM_COMMAND (TARGET revisiontag COMMAND ${CMAKE_COMMAND} - -DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} - -P ${CMAKE_CURRENT_SOURCE_DIR}/getsvn.cmake) +install (TARGETS jt9 + RUNTIME DESTINATION ${WSJT_BIN_DESTINATION} + LIBRARY DESTINATION ${WSJT_LIB_DESTINATION} + BUNDLE DESTINATION ${WSJT_BIN_DESTINATION} + # COMPONENT Runtime + ) + +install (PROGRAMS + ${CMAKE_BINARY_DIR}/contrib/kvasd${CMAKE_EXECUTABLE_SUFFIX} + DESTINATION ${WSJT_BIN_DESTINATION} + # COMPONENT Runtime + ) -# explicitly say that the executable depends on custom target -add_dependencies(wsjtx revisiontag) # -# versioning +# uninstall support +# +configure_file ( + "${CMAKE_CURRENT_SOURCE_DIR}/CMake/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + @ONLY) +add_custom_target (uninstall + "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") + + +# creates svnversion.h using cmake script +add_custom_target (revisiontag + COMMAND ${CMAKE_COMMAND} -D SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} -P ${CMAKE_CURRENT_SOURCE_DIR}/CMake/getsvn.cmake + COMMENT "Generating Subversion revision information" + VERBATIM + ) +# explicitly say that the executable depends on custom target, this is +# done indirectly so that the revisiontag target gets built exactly +# once per build +add_dependencies(wsjt revisiontag) +add_dependencies(jt9 revisiontag) +add_dependencies(wsjtx revisiontag) + + +# +# versioning and configuration # configure_file ( "${PROJECT_SOURCE_DIR}/wsjtx_config.h.in" "${PROJECT_BINARY_DIR}/wsjtx_config.h" ) - include_directories ("${PROJECT_BINARY_DIR}") + + +if (NOT WIN32 AND NOT APPLE) + # install a desktop file so wsjtx appears in the application start + # menu with an icon + install (FILES wsjtx.desktop DESTINATION share/applications) + install (FILES icons/Unix/wsjtx_icon.png DESTINATION share/pixmaps) +endif (NOT WIN32 AND NOT APPLE) + + +# +# bundle fixup only done in Release or MinSizeRel configurations +# +if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug") + + # get_target_property (QtCore_location Qt5::Core LOCATION) + # get_filename_component (QtCore_location ${QtCore_location} PATH) + # list (APPEND fixup_library_dirs ${QtCore_location}) + + if (APPLE) + set (CMAKE_POSTFLIGHT_SCRIPT + "${wsjtx_BINARY_DIR}/postflight.sh") + set (CMAKE_POSTUPGRADE_SCRIPT + "${wsjtx_BINARY_DIR}/postupgrade.sh") + configure_file ("${wsjtx_SOURCE_DIR}/postflight.sh.in" + "${wsjtx_BINARY_DIR}/postflight.sh") + configure_file ("${wsjtx_SOURCE_DIR}/postupgrade.sh.in" + "${wsjtx_BINARY_DIR}/postupgrade.sh") + endif () + + if (APPLE OR WIN32) + # install rules for including 3rd party libs such as Qt + + # install a qt.conf file + install (CODE " + file (WRITE \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${WSJT_QT_CONF_DESTINATION}/qt.conf\" +\"[Paths] +\") +" #COMPONENT Runtime + ) + + # if a system Qt is used (e.g. installed in /usr/lib/), it will not be included in the installation + set (fixup_exe "\${CMAKE_INSTALL_PREFIX}/${WSJT_BIN_DESTINATION}/${CMAKE_PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}") + get_filename_component (hamlib_lib_dir ${hamlib_LIBRARIES} PATH) + + if (APPLE) + # install required Qt plugins + install ( + DIRECTORY + ${QT_PLUGINS_DIR}/platforms + ${QT_PLUGINS_DIR}/audio + DESTINATION ${WSJT_PLUGIN_DESTINATION} + CONFIGURATIONS Release MinSizeRel + # COMPONENT Runtime + FILES_MATCHING PATTERN "*${CMAKE_SHARED_LIBRARY_SUFFIX}" + PATTERN "*minimal*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE + PATTERN "*offscreen*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE + PATTERN "*_debug${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE + ) + # install ( + # DIRECTORY + # ${QT_PLUGINS_DIR}/platforms + # ${QT_PLUGINS_DIR}/audio + # DESTINATION ${WSJT_PLUGIN_DESTINATION} + # CONFIGURATIONS Debug + # # COMPONENT Runtime + # FILES_MATCHING PATTERN "*_debug${CMAKE_SHARED_LIBRARY_SUFFIX}" + # PATTERN "*minimal*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE + # PATTERN "*offscreen*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE + # ) + + # add plugins path for Mac Bundle + install (CODE " +file (APPEND \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${WSJT_QT_CONF_DESTINATION}/qt.conf\" +\"Plugins = Plugins +\") +" #COMPONENT Runtime + ) + endif (APPLE) + + if (WIN32) + # DLL directory + set (hamlib_lib_dir ${hamlib_lib_dir}/../bin) + + get_filename_component (fftw_lib_dir ${FFTW3F_LIBRARY} PATH) + list (APPEND fixup_library_dirs ${fftw_lib_dir}) + + # install required Qt plugins + install ( + DIRECTORY + ${QT_PLUGINS_DIR}/platforms + DESTINATION ${WSJT_PLUGIN_DESTINATION} + CONFIGURATIONS Release MinSizeRel + # COMPONENT Runtime + FILES_MATCHING PATTERN "*${CMAKE_SHARED_LIBRARY_SUFFIX}" + PATTERN "*minimal*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE + PATTERN "*offscreen*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE + PATTERN "*d${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE + ) + # install ( + # DIRECTORY + # ${QT_PLUGINS_DIR}/platforms + # DESTINATION ${WSJT_PLUGIN_DESTINATION} + # CONFIGURATIONS Debug + # # COMPONENT Runtime + # FILES_MATCHING PATTERN "*d${CMAKE_SHARED_LIBRARY_SUFFIX}" + # PATTERN "*minimal*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE + # PATTERN "*offscreen*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE + # ) + + # add plugins path for WIN32 + file (RELATIVE_PATH _plugins_path "${CMAKE_INSTALL_PREFIX}/${WSJT_QT_CONF_DESTINATION}" "${CMAKE_INSTALL_PREFIX}/${WSJT_PLUGIN_DESTINATION}") + install (CODE " +file (APPEND \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${WSJT_QT_CONF_DESTINATION}/qt.conf\" +\"Plugins = ${_plugins_path} +\") +" #COMPONENT Runtime + ) + + # set (gp_tool "objdump") # we want MinGW tool - not MSVC (See GetPrerequisites.cmake) + endif (WIN32) + + list (APPEND fixup_library_dirs ${hamlib_lib_dir}) + + install (CODE " + file (GLOB_RECURSE QTPLUGINS + \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${WSJT_PLUGIN_DESTINATION}/*${CMAKE_SHARED_LIBRARY_SUFFIX}\") + include (BundleUtilities) + set (BU_CHMOD_BUNDLE_ITEMS ON) + set (gp_tool ${gp_tool}) + message (STATUS \"fixup_exe: ${fixup_exe}\") + fixup_bundle (\"${fixup_exe}\" \"\${QTPLUGINS}\" \"${fixup_library_dirs}\") + " + #COMPONENT Runtime + ) + endif (APPLE OR WIN32) + +endif (NOT CMAKE_BUILD_TYPE STREQUAL "Debug") + + +# +# packaging +# +set (CPACK_PACKAGE_NAME "${CMAKE_PROJECT_NAME}") +set (CPACK_PACKAGE_VERSION_MAJOR ${WSJTX_VERSION_MAJOR}) +set (CPACK_PACKAGE_VERSION_MINOR ${WSJTX_VERSION_MINOR}) +set (CPACK_PACKAGE_VERSION_PATCH ${WSJTX_VERSION_PATCH}) + +if (WIN32) + set (CPACK_GENERATOR "NSIS") +elseif (APPLE) + set (CPACK_GENERATOR "DragNDrop" "PackageMaker") +else () + # + # Derive the correct filename for a Debian package because the DEB + # generator doesn't do this correctly at present. + # + string (TOLOWER "${CPACK_PACKAGE_NAME}" CPACK_PACKAGE_NAME_LOWERCASE) + find_program (DPKG_PROGRAM dpkg DOC "dpkg program of Debian-based systems") + if (DPKG_PROGRAM) + execute_process ( + COMMAND ${DPKG_PROGRAM} --print-architecture + OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + set (DEBIAN_PACKAGE_FILE_NAME + "${CPACK_PACKAGE_NAME_LOWERCASE}_${wsjtx_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}") + + else (DPKG_PROGRAM) + set (DEBIAN_PACKAGE_FILE_NAME + "${CPACK_PACKAGE_NAME_LOWERCASE}_${wsjtx_VERSION}_${CMAKE_SYSTEM_NAME}") + endif (DPKG_PROGRAM) + + set (CPACK_DEBIAN_PACKAGE_PACKAGE_SHLIBDEPS ON) + + set (CPACK_GENERATOR "DEB" "RPM" "TGZ") +endif () + +configure_file ("${PROJECT_SOURCE_DIR}/CMakeCPackOptions.cmake.in" + "${PROJECT_BINARY_DIR}/CMakeCPackOptions.cmake" @ONLY) +set (CPACK_PROJECT_CONFIG_FILE "${PROJECT_BINARY_DIR}/CMakeCPackOptions.cmake") + +include (CPack) diff --git a/ConfigTest.cpp b/ConfigTest.cpp new file mode 100644 index 000000000..1d596c861 --- /dev/null +++ b/ConfigTest.cpp @@ -0,0 +1,63 @@ +#include +#include + +#include + +#include +#include +#include +#include + +#include "GetUserId.hpp" +#include "TraceFile.hpp" +#include "TestConfiguration.hpp" +#include "AudioDevice.hpp" +#include "TransceiverFactory.hpp" +#include "Configuration.hpp" + +int main (int argc, char *argv[]) +{ + try + { + QApplication application {argc, argv}; + setlocale (LC_NUMERIC, "C"); // ensure number forms are in + // consistent format, do this after + // instantiating QApplication so + // that GUI has correct l18n + + // get a unique id from the user + auto id = get_user_id (); + + // open a user specific trace file + TraceFile trace_file {QDir {QApplication::applicationDirPath () + "/logs"}.absoluteFilePath (id + "_config_test.log")}; + + // announce to log file + qDebug () << "Configuration Test v" WSJTX_STRINGIZE (CONFIG_TEST_VERSION_MAJOR) "." WSJTX_STRINGIZE (CONFIG_TEST_VERSION_MINOR) "." WSJTX_STRINGIZE (CONFIG_TEST_VERSION_PATCH) ", " WSJTX_STRINGIZE (SVNVERSION) " - Program startup"; + + // open user specific settings + QSettings settings {QDir {QApplication::applicationDirPath () + "/settings"}.absoluteFilePath (id + "_config_test.ini"), QSettings::IniFormat}; + + // the test GUI + TestConfiguration main_window ("ConfigTest", &settings); + + // hook up close down mechanism + QObject::connect (&application, SIGNAL (lastWindowClosed ()), &application, SLOT (quit ())); + + // start event loop + auto status = application.exec(); + qDebug () << "Normal exit with status: " << status; + return status; + } + catch (std::exception const& e) + { + qDebug () << "Error exit: " << e.what () << '\n'; + std::cerr << "Error: " << e.what () << '\n'; + } + catch (...) + { + qDebug () << "Unknown error exit\n"; + std::cerr << "Unexpected error\n"; + throw; // hoping the runtime might tell us more about the exception + } + return -1; +} diff --git a/Configuration.cpp b/Configuration.cpp new file mode 100644 index 000000000..15e50ec0b --- /dev/null +++ b/Configuration.cpp @@ -0,0 +1,2128 @@ +#include "Configuration.hpp" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ui_Configuration.h" + +#include "SettingsGroup.hpp" +#include "FrequencyLineEdit.hpp" +#include "FrequencyItemDelegate.hpp" +#include "ForeignKeyDelegate.hpp" +#include "TransceiverFactory.hpp" +#include "Transceiver.hpp" +#include "Bands.hpp" +#include "FrequencyList.hpp" +#include "StationList.hpp" + +#include "pimpl_impl.hpp" + +#include "moc_Configuration.cpp" + +namespace +{ + struct init + { + init () + { + qRegisterMetaType ("Configuration::DataMode"); + qRegisterMetaTypeStreamOperators ("Configuration::DataMode"); + } + } static_initializer; + + // these undocumented flag values when stored in (Qt::UserRole - 1) + // of a ComboBox item model index allow the item to be enabled or + // disabled + int const combo_box_item_enabled (32 | 1); + int const combo_box_item_disabled (0); +} + + +// +// Dialog to get a new Frequency item +// +class FrequencyDialog final + : public QDialog +{ +public: + using Frequency = Radio::Frequency; + + explicit FrequencyDialog (QWidget * parent = nullptr) + : QDialog {parent} + { + setWindowTitle (QApplication::applicationName () + " - " + tr ("Add Frequency")); + + auto form_layout = new QFormLayout (); + form_layout->addRow (tr ("&Frequency (MHz):"), &frequency_line_edit_); + + auto main_layout = new QVBoxLayout (this); + main_layout->addLayout (form_layout); + + auto button_box = new QDialogButtonBox {QDialogButtonBox::Ok | QDialogButtonBox::Cancel}; + main_layout->addWidget (button_box); + + connect (button_box, &QDialogButtonBox::accepted, this, &FrequencyDialog::accept); + connect (button_box, &QDialogButtonBox::rejected, this, &FrequencyDialog::reject); + } + + Frequency frequency () const + { + return frequency_line_edit_.frequency (); + } + +private: + FrequencyLineEdit frequency_line_edit_; +}; + + +// +// Dialog to get a new Station item +// +class StationDialog final + : public QDialog +{ +public: + explicit StationDialog (Bands * bands, QWidget * parent = nullptr) + : QDialog {parent} + , bands_ {bands} + { + setWindowTitle (QApplication::applicationName () + " - " + tr ("Add Station")); + + band_.setModel (bands_); + + auto form_layout = new QFormLayout (); + form_layout->addRow (tr ("&Band:"), &band_); + form_layout->addRow (tr ("&Offset (MHz):"), &delta_); + form_layout->addRow (tr ("&Antenna:"), &description_); + + auto main_layout = new QVBoxLayout (this); + main_layout->addLayout (form_layout); + + auto button_box = new QDialogButtonBox {QDialogButtonBox::Ok | QDialogButtonBox::Cancel}; + main_layout->addWidget (button_box); + + connect (button_box, &QDialogButtonBox::accepted, this, &StationDialog::accept); + connect (button_box, &QDialogButtonBox::rejected, this, &StationDialog::reject); + + if (delta_.text ().isEmpty ()) + { + delta_.setText ("0"); + } + } + + StationList::Station station () const + { + return {band_.currentText (), delta_.frequency_delta (), description_.text ()}; + } + +private: + Bands * bands_; + + QComboBox band_; + FrequencyDeltaLineEdit delta_; + QLineEdit description_; +}; + +// Fields that are transceiver related. +// +// These are aggregated in a structure to enable a non-equivalence to +// be provided. +// +// don't forget to update the != operator if any fields are added +// otherwise rig parameter changes will not trigger reconfiguration +struct RigParams +{ + QString CAT_serial_port_; + QString CAT_network_port_; + qint32 CAT_baudrate_; + TransceiverFactory::DataBits CAT_data_bits_; + TransceiverFactory::StopBits CAT_stop_bits_; + TransceiverFactory::Handshake CAT_handshake_; + bool CAT_DTR_always_on_; + bool CAT_RTS_always_on_; + qint32 CAT_poll_interval_; + TransceiverFactory::PTTMethod PTT_method_; + QString PTT_port_; + TransceiverFactory::TXAudioSource TX_audio_source_; + TransceiverFactory::SplitMode split_mode_; + QString rig_name_; +}; +bool operator != (RigParams const&, RigParams const&); + +inline +bool operator == (RigParams const& lhs, RigParams const& rhs) +{ + return !(lhs != rhs); +} + + +// Internal implementation of the Configuration class. +class Configuration::impl final + : public QDialog +{ + Q_OBJECT; + +public: + using FrequencyDelta = Radio::FrequencyDelta; + + explicit impl (Configuration * self, QString const& instance_key, QSettings * settings, QWidget * parent); + ~impl (); + + bool have_rig (bool open_if_closed = true); + + void transceiver_frequency (Frequency); + void transceiver_tx_frequency (Frequency); + void transceiver_mode (MODE); + void transceiver_ptt (bool); + void sync_transceiver (bool force_signal); + + Q_SLOT int exec () override; + Q_SLOT void accept () override; + Q_SLOT void reject () override; + Q_SLOT void done (int) override; + +private: + typedef QList AudioDevices; + + void read_settings (); + void write_settings (); + + bool load_audio_devices (QAudio::Mode, QComboBox *, QAudioDeviceInfo *); + void update_audio_channels (QComboBox const *, int, QComboBox *, bool); + + void initialise_models (); + bool open_rig (); + bool set_mode (); + void close_rig (); + void enumerate_rigs (); + void set_rig_invariants (); + bool validate (); + void message_box (QString const& reason, QString const& detail = QString ()); + void fill_port_combo_box (QComboBox *); + + Q_SLOT void on_font_push_button_clicked (); + Q_SLOT void on_decoded_text_font_push_button_clicked (); + + Q_SLOT void on_PTT_port_combo_box_activated (int); + + Q_SLOT void on_CAT_port_combo_box_activated (int); + + Q_SLOT void on_CAT_serial_baud_combo_box_currentIndexChanged (int); + + Q_SLOT void on_CAT_data_bits_button_group_buttonClicked (int); + + Q_SLOT void on_CAT_stop_bits_button_group_buttonClicked (int); + + Q_SLOT void on_CAT_handshake_button_group_buttonClicked (int); + + Q_SLOT void on_CAT_poll_interval_spin_box_valueChanged (int); + + Q_SLOT void on_split_mode_button_group_buttonClicked (int); + + Q_SLOT void on_test_CAT_push_button_clicked (); + + Q_SLOT void on_test_PTT_push_button_clicked (); + + Q_SLOT void on_CAT_DTR_check_box_toggled (bool); + + Q_SLOT void on_CAT_RTS_check_box_toggled (bool); + + Q_SLOT void on_rig_combo_box_currentIndexChanged (int); + + Q_SLOT void on_sound_input_combo_box_currentTextChanged (QString const&); + Q_SLOT void on_sound_output_combo_box_currentTextChanged (QString const&); + + Q_SLOT void on_add_macro_push_button_clicked (bool = false); + Q_SLOT void on_delete_macro_push_button_clicked (bool = false); + + Q_SLOT void on_PTT_method_button_group_buttonClicked (int); + + Q_SLOT void on_callsign_line_edit_editingFinished (); + + Q_SLOT void on_grid_line_edit_editingFinished (); + + Q_SLOT void on_add_macro_line_edit_editingFinished (); + Q_SLOT void delete_macro (); + + Q_SLOT void on_save_path_select_push_button_clicked (bool); + + Q_SLOT void delete_frequencies (); + Q_SLOT void insert_frequency (); + + Q_SLOT void delete_stations (); + Q_SLOT void insert_station (); + + Q_SLOT void handle_transceiver_update (TransceiverState); + Q_SLOT void handle_transceiver_failure (QString reason); + + // typenames used as arguments must match registered type names :( + Q_SIGNAL void stop_transceiver () const; + Q_SIGNAL void frequency (Frequency rx) const; + Q_SIGNAL void tx_frequency (Frequency tx, bool rationalize_mode) const; + Q_SIGNAL void mode (Transceiver::MODE, bool rationalize) const; + Q_SIGNAL void ptt (bool) const; + Q_SIGNAL void sync (bool force_signal) const; + + Configuration * const self_; // back pointer to public interface + + QThread transceiver_thread_; + TransceiverFactory transceiver_factory_; + + Ui::configuration_dialog * ui_; + + QSettings * settings_; + + QDir temp_path_; + QDir data_path_; + QDir default_save_directory_; + QDir save_directory_; + + QFont font_; + bool font_changed_; + QFont next_font_; + + QFont decoded_text_font_; + bool decoded_text_font_changed_; + QFont next_decoded_text_font_; + + bool restart_sound_input_device_; + bool restart_sound_output_device_; + + unsigned jt9w_bw_mult_; + float jt9w_min_dt_; + float jt9w_max_dt_; + + QStringListModel macros_; + QStringListModel next_macros_; + QAction * macro_delete_action_; + + Bands bands_; + FrequencyList frequencies_; + FrequencyList next_frequencies_; + StationList stations_; + StationList next_stations_; + + QAction * frequency_delete_action_; + QAction * frequency_insert_action_; + FrequencyDialog * frequency_dialog_; + + QAction * station_delete_action_; + QAction * station_insert_action_; + StationDialog * station_dialog_; + + RigParams rig_params_; + RigParams saved_rig_params_; + bool rig_active_; + bool have_rig_; + bool rig_changed_; + TransceiverState cached_rig_state_; + bool ptt_state_; + bool setup_split_; + bool enforce_mode_and_split_; + FrequencyDelta transceiver_offset_; + + // configuration fields that we publish + QString my_callsign_; + QString my_grid_; + qint32 id_interval_; + bool id_after_73_; + bool spot_to_psk_reporter_; + bool monitor_off_at_startup_; + bool log_as_RTTY_; + bool report_in_comments_; + bool prompt_to_log_; + bool insert_blank_; + bool DXCC_; + bool clear_DX_; + bool miles_; + bool quick_call_; + bool disable_TX_on_73_; + bool watchdog_; + bool TX_messages_; + DataMode data_mode_; + + QAudioDeviceInfo audio_input_device_; + bool default_audio_input_device_selected_; + AudioDevice::Channel audio_input_channel_; + QAudioDeviceInfo audio_output_device_; + bool default_audio_output_device_selected_; + AudioDevice::Channel audio_output_channel_; + + friend class Configuration; +}; + +#include "Configuration.moc" + + +// delegate to implementation class +Configuration::Configuration (QString const& instance_key, QSettings * settings, QWidget * parent) + : m_ {this, instance_key, settings, parent} +{ +} + +Configuration::~Configuration () +{ +} + +QDir Configuration::data_path () const {return m_->data_path_;} + +int Configuration::exec () {return m_->exec ();} + +QAudioDeviceInfo const& Configuration::audio_input_device () const {return m_->audio_input_device_;} +AudioDevice::Channel Configuration::audio_input_channel () const {return m_->audio_input_channel_;} +QAudioDeviceInfo const& Configuration::audio_output_device () const {return m_->audio_output_device_;} +AudioDevice::Channel Configuration::audio_output_channel () const {return m_->audio_output_channel_;} +bool Configuration::restart_audio_input () const {return m_->restart_sound_input_device_;} +bool Configuration::restart_audio_output () const {return m_->restart_sound_output_device_;} +unsigned Configuration::jt9w_bw_mult () const {return m_->jt9w_bw_mult_;} +float Configuration::jt9w_min_dt () const {return m_->jt9w_min_dt_;} +float Configuration::jt9w_max_dt () const {return m_->jt9w_max_dt_;} +QString Configuration::my_callsign () const {return m_->my_callsign_;} +QString Configuration::my_grid () const {return m_->my_grid_;} +QFont Configuration::decoded_text_font () const {return m_->decoded_text_font_;} +qint32 Configuration::id_interval () const {return m_->id_interval_;} +bool Configuration::id_after_73 () const {return m_->id_after_73_;} +bool Configuration::spot_to_psk_reporter () const {return m_->spot_to_psk_reporter_;} +bool Configuration::monitor_off_at_startup () const {return m_->monitor_off_at_startup_;} +bool Configuration::log_as_RTTY () const {return m_->log_as_RTTY_;} +bool Configuration::report_in_comments () const {return m_->report_in_comments_;} +bool Configuration::prompt_to_log () const {return m_->prompt_to_log_;} +bool Configuration::insert_blank () const {return m_->insert_blank_;} +bool Configuration::DXCC () const {return m_->DXCC_;} +bool Configuration::clear_DX () const {return m_->clear_DX_;} +bool Configuration::miles () const {return m_->miles_;} +bool Configuration::quick_call () const {return m_->quick_call_;} +bool Configuration::disable_TX_on_73 () const {return m_->disable_TX_on_73_;} +bool Configuration::watchdog () const {return m_->watchdog_;} +bool Configuration::TX_messages () const {return m_->TX_messages_;} +bool Configuration::split_mode () const {return m_->rig_params_.split_mode_ != TransceiverFactory::split_mode_none;} +Bands * Configuration::bands () {return &m_->bands_;} +StationList * Configuration::stations () {return &m_->stations_;} +FrequencyList * Configuration::frequencies () {return &m_->frequencies_;} +QStringListModel * Configuration::macros () {return &m_->macros_;} +QDir Configuration::save_directory () const {return m_->save_directory_;} +QString Configuration::rig_name () const {return m_->rig_params_.rig_name_;} + +bool Configuration::transceiver_online (bool open_if_closed) +{ +#if WSJT_TRACE_CAT + qDebug () << "Configuration::transceiver_online: open_if_closed:" << open_if_closed << m_->cached_rig_state_; +#endif + + return m_->have_rig (open_if_closed); +} + +void Configuration::transceiver_offline () +{ +#if WSJT_TRACE_CAT + qDebug () << "Configuration::transceiver_offline:" << m_->cached_rig_state_; +#endif + + return m_->close_rig (); +} + +void Configuration::transceiver_frequency (Frequency f) +{ +#if WSJT_TRACE_CAT + qDebug () << "Configuration::transceiver_frequency:" << f << m_->cached_rig_state_; +#endif + + m_->transceiver_frequency (f); +} + +void Configuration::transceiver_tx_frequency (Frequency f) +{ +#if WSJT_TRACE_CAT + qDebug () << "Configuration::transceiver_tx_frequency:" << f << m_->cached_rig_state_; +#endif + + m_->setup_split_ = true; + m_->transceiver_tx_frequency (f); +} + +void Configuration::transceiver_mode (MODE mode) +{ +#if WSJT_TRACE_CAT + qDebug () << "Configuration::transceiver_mode:" << mode << m_->cached_rig_state_; +#endif + + m_->transceiver_mode (mode); +} + +void Configuration::transceiver_ptt (bool on) +{ +#if WSJT_TRACE_CAT + qDebug () << "Configuration::transceiver_ptt:" << on << m_->cached_rig_state_; +#endif + + m_->transceiver_ptt (on); +} + +void Configuration::sync_transceiver (bool force_signal, bool enforce_mode_and_split) +{ +#if WSJT_TRACE_CAT + qDebug () << "Configuration::sync_transceiver: force signal:" << force_signal << "enforce_mode_and_split:" << enforce_mode_and_split << m_->cached_rig_state_; +#endif + + m_->enforce_mode_and_split_ = enforce_mode_and_split; + m_->setup_split_ = enforce_mode_and_split; + m_->sync_transceiver (force_signal); +} + + +Configuration::impl::impl (Configuration * self, QString const& instance_key, QSettings * settings, QWidget * parent) + : QDialog {parent} + , self_ {self} + , ui_ {new Ui::configuration_dialog} + , settings_ {settings} + , temp_path_ {QApplication::applicationDirPath ()} + , data_path_ {QApplication::applicationDirPath ()} + , font_ {QApplication::font ()} + , font_changed_ {false} + , decoded_text_font_changed_ {false} + , frequencies_ { + { + 136130, + 474200, + 1838000, + 3576000, + 5357000, + 7076000, + 10138000, + 14076000, + 18102000, + 21076000, + 24917000, + 28076000, + 50276000, + 70091000, + 144489000, + } + } + , stations_ {&bands_} + , next_stations_ {&bands_} + , frequency_dialog_ {new FrequencyDialog {this}} + , station_dialog_ {new StationDialog {&bands_, this}} + , rig_active_ {false} + , have_rig_ {false} + , rig_changed_ {false} + , ptt_state_ {false} + , setup_split_ {false} + , enforce_mode_and_split_ {false} + , transceiver_offset_ {0} + , default_audio_input_device_selected_ {false} + , default_audio_output_device_selected_ {false} +{ + (void)instance_key; // quell compiler warning + + ui_->setupUi (this); + +#if WSJT_STANDARD_FILE_LOCATIONS + // the following needs to be done on all platforms but changes need + // coordination with JTAlert developers + { + // Create a temporary directory in a suitable location + QString temp_location {QStandardPaths::writableLocation (QStandardPaths::TempLocation)}; + if (!temp_location.isEmpty ()) + { + temp_path_.setPath (temp_location); + } + + QString unique_directory {instance_key}; + if (!temp_path_.mkpath (unique_directory) || !temp_path_.cd (unique_directory)) + { + QMessageBox::critical (this, "WSJT-X", tr ("Create temporary directory error: ") + temp_path_.absolutePath ()); + throw std::runtime_error {"Failed to create usable temporary directory"}; + } + } + + // kvasd writes files to $cwd so by changing to the temp directory + // we can keep these files out of the startup directory + QDir::setCurrent (temp_path_.absolutePath ()); + + // we run kvasd with a $cwd of our temp directory so we need to copy + // in a fresh kvasd.dat for it + // + // this requirement changes with kvasd v 1.12 since it has a + // parameter to set the data file path + QString kvasd_data_file {"kvasd.dat"}; + if (!temp_path_.exists (kvasd_data_file)) + { + auto dest_file = temp_path_.absoluteFilePath (kvasd_data_file); + if (!QFile::copy (":/" + kvasd_data_file, dest_file)) + { + QMessageBox::critical (this, "WSJT-X", tr ("Cannot copy: :/") + kvasd_data_file + tr (" to: ") + temp_path_.absolutePath ()); + throw std::runtime_error {"Failed to copy kvasd.dat to temporary directory"}; + } + else + { + QFile {dest_file}.setPermissions (QFile::ReadOwner | QFile::WriteOwner); + } + } + + + { + // Find a suitable data file location + QString data_location {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}; + if (!data_location.isEmpty ()) + { + data_path_.setPath (data_location); + } + + if (!data_path_.mkpath (".")) + { + QMessageBox::critical (this, "WSJT-X", tr ("Create data directory error: ") + data_path_.absolutePath ()); + throw std::runtime_error {"Failed to create data directory"}; + } + } + // qDebug () << "Data store path:" << data_path_.absolutePath (); + // auto paths = QStandardPaths::standardLocations (QStandardPaths::DataLocation); + // Q_FOREACH (auto const& path, paths) + // { + // qDebug () << "path:" << path; + // } +#endif + + { + // Make sure the default save directory exists + QString save_dir {"save"}; + default_save_directory_ = data_path_; + if (!default_save_directory_.mkpath (save_dir) || !default_save_directory_.cd (save_dir)) + { + QMessageBox::critical (this, "WSJT-X", tr ("Create Directory", "Cannot create directory \"") + default_save_directory_.absoluteFilePath (save_dir) + "\"."); + throw std::runtime_error {"Failed to create save directory"}; + } + + // we now have a deafult save path that exists + + // make sure samples directory exists + QString samples_dir {"samples"}; + if (!default_save_directory_.mkpath (samples_dir)) + { + QMessageBox::critical (this, "WSJT-X", tr ("Create Directory", "Cannot create directory \"") + default_save_directory_.absoluteFilePath (samples_dir) + "\"."); + throw std::runtime_error {"Failed to create save directory"}; + } + + // copy in any new sample files to the sample directory + QDir dest_dir {default_save_directory_}; + dest_dir.cd (samples_dir); + + QDir source_dir {":/" + samples_dir}; + source_dir.cd (save_dir); + source_dir.cd (samples_dir); + auto list = source_dir.entryInfoList (QStringList {{"*.wav"}}, QDir::Files | QDir::Readable); + Q_FOREACH (auto const& item, list) + { + if (!dest_dir.exists (item.fileName ())) + { + QFile file {item.absoluteFilePath ()}; + file.copy (dest_dir.absoluteFilePath (item.fileName ())); + } + } + } + + // this must be done after the default paths above are set + read_settings (); + + // + // validation + // + ui_->callsign_line_edit->setValidator (new QRegExpValidator {QRegExp {"[A-Za-z0-9/]+"}, this}); + ui_->grid_line_edit->setValidator (new QRegExpValidator {QRegExp {"[A-Ra-r]{2,2}[0-9]{2,2}[A-Xa-x]{0,2}"}, this}); + ui_->add_macro_line_edit->setValidator (new QRegExpValidator {QRegExp {"[ A-Za-z0-9/?]+"}, this}); + + // + // assign ids to radio buttons + // + ui_->CAT_data_bits_button_group->setId (ui_->CAT_7_bit_radio_button, TransceiverFactory::seven_data_bits); + ui_->CAT_data_bits_button_group->setId (ui_->CAT_8_bit_radio_button, TransceiverFactory::eight_data_bits); + + ui_->CAT_stop_bits_button_group->setId (ui_->CAT_one_stop_bit_radio_button, TransceiverFactory::one_stop_bit); + ui_->CAT_stop_bits_button_group->setId (ui_->CAT_two_stop_bit_radio_button, TransceiverFactory::two_stop_bits); + + ui_->CAT_handshake_button_group->setId (ui_->CAT_handshake_none_radio_button, TransceiverFactory::handshake_none); + ui_->CAT_handshake_button_group->setId (ui_->CAT_handshake_xon_radio_button, TransceiverFactory::handshake_XonXoff); + ui_->CAT_handshake_button_group->setId (ui_->CAT_handshake_hardware_radio_button, TransceiverFactory::handshake_hardware); + + ui_->PTT_method_button_group->setId (ui_->PTT_VOX_radio_button, TransceiverFactory::PTT_method_VOX); + ui_->PTT_method_button_group->setId (ui_->PTT_CAT_radio_button, TransceiverFactory::PTT_method_CAT); + ui_->PTT_method_button_group->setId (ui_->PTT_DTR_radio_button, TransceiverFactory::PTT_method_DTR); + ui_->PTT_method_button_group->setId (ui_->PTT_RTS_radio_button, TransceiverFactory::PTT_method_RTS); + + ui_->TX_audio_source_button_group->setId (ui_->TX_source_mic_radio_button, TransceiverFactory::TX_audio_source_front); + ui_->TX_audio_source_button_group->setId (ui_->TX_source_data_radio_button, TransceiverFactory::TX_audio_source_rear); + + ui_->TX_mode_button_group->setId (ui_->mode_none_radio_button, data_mode_none); + ui_->TX_mode_button_group->setId (ui_->mode_USB_radio_button, data_mode_USB); + ui_->TX_mode_button_group->setId (ui_->mode_data_radio_button, data_mode_data); + + ui_->split_mode_button_group->setId (ui_->split_none_radio_button, TransceiverFactory::split_mode_none); + ui_->split_mode_button_group->setId (ui_->split_rig_radio_button, TransceiverFactory::split_mode_rig); + ui_->split_mode_button_group->setId (ui_->split_emulate_radio_button, TransceiverFactory::split_mode_emulate); + + // + // setup PTT port combo box drop down content + // + fill_port_combo_box (ui_->PTT_port_combo_box); + ui_->PTT_port_combo_box->addItem ("CAT"); + + // + // setup hooks to keep audio channels aligned with devices + // + { + using namespace std; + using namespace std::placeholders; + + function cb (bind (&Configuration::impl::update_audio_channels, this, ui_->sound_input_combo_box, _1, ui_->sound_input_channel_combo_box, false)); + connect (ui_->sound_input_combo_box, static_cast (&QComboBox::currentIndexChanged), cb); + cb = bind (&Configuration::impl::update_audio_channels, this, ui_->sound_output_combo_box, _1, ui_->sound_output_channel_combo_box, true); + connect (ui_->sound_output_combo_box, static_cast (&QComboBox::currentIndexChanged), cb); + } + + // + // setup macros list view + // + ui_->macros_list_view->setModel (&next_macros_); + + macro_delete_action_ = new QAction {tr ("&Delete"), ui_->macros_list_view}; + ui_->macros_list_view->insertAction (nullptr, macro_delete_action_); + connect (macro_delete_action_, &QAction::triggered, this, &Configuration::impl::delete_macro); + + + // + // setup working frequencies table model & view + // + frequencies_.sort (0); + + ui_->frequencies_table_view->setModel (&next_frequencies_); + ui_->frequencies_table_view->sortByColumn (0, Qt::AscendingOrder); + ui_->frequencies_table_view->setItemDelegateForColumn (0, new FrequencyItemDelegate {&bands_, this}); + ui_->frequencies_table_view->setColumnHidden (1, true); + + frequency_delete_action_ = new QAction {tr ("&Delete"), ui_->frequencies_table_view}; + ui_->frequencies_table_view->insertAction (nullptr, frequency_delete_action_); + connect (frequency_delete_action_, &QAction::triggered, this, &Configuration::impl::delete_frequencies); + + frequency_insert_action_ = new QAction {tr ("&Insert ..."), ui_->frequencies_table_view}; + ui_->frequencies_table_view->insertAction (nullptr, frequency_insert_action_); + connect (frequency_insert_action_, &QAction::triggered, this, &Configuration::impl::insert_frequency); + + + // + // setup stations table model & view + // + stations_.sort (0); + + ui_->stations_table_view->setModel (&next_stations_); + ui_->stations_table_view->sortByColumn (0, Qt::AscendingOrder); + ui_->stations_table_view->setColumnWidth (1, 150); + ui_->stations_table_view->setItemDelegateForColumn (0, new ForeignKeyDelegate {&next_stations_, &bands_, 0, this}); + ui_->stations_table_view->setItemDelegateForColumn (1, new FrequencyDeltaItemDelegate {this}); + + station_delete_action_ = new QAction {tr ("&Delete"), ui_->stations_table_view}; + ui_->stations_table_view->insertAction (nullptr, station_delete_action_); + connect (station_delete_action_, &QAction::triggered, this, &Configuration::impl::delete_stations); + + station_insert_action_ = new QAction {tr ("&Insert ..."), ui_->stations_table_view}; + ui_->stations_table_view->insertAction (nullptr, station_insert_action_); + connect (station_insert_action_, &QAction::triggered, this, &Configuration::impl::insert_station); + + // + // load combo boxes with audio setup choices + // + default_audio_input_device_selected_ = load_audio_devices (QAudio::AudioInput, ui_->sound_input_combo_box, &audio_input_device_); + default_audio_output_device_selected_ = load_audio_devices (QAudio::AudioOutput, ui_->sound_output_combo_box, &audio_output_device_); + + update_audio_channels (ui_->sound_input_combo_box, ui_->sound_input_combo_box->currentIndex (), ui_->sound_input_channel_combo_box, false); + update_audio_channels (ui_->sound_output_combo_box, ui_->sound_output_combo_box->currentIndex (), ui_->sound_output_channel_combo_box, true); + + ui_->sound_input_channel_combo_box->setCurrentIndex (audio_input_channel_); + ui_->sound_output_channel_combo_box->setCurrentIndex (audio_output_channel_); + + restart_sound_input_device_ = false; + restart_sound_output_device_ = false; + + enumerate_rigs (); + initialise_models (); + + transceiver_thread_.start (); +} + +Configuration::impl::~impl () +{ + write_settings (); + + close_rig (); + + transceiver_thread_.quit (); + transceiver_thread_.wait (); + + QDir::setCurrent (QApplication::applicationDirPath ()); +#if WSJT_STANDARD_FILE_LOCATIONS + temp_path_.removeRecursively (); // clean up temp files +#endif +} + +void Configuration::impl::initialise_models () +{ + auto pal = ui_->callsign_line_edit->palette (); + if (my_callsign_.isEmpty ()) + { + pal.setColor (QPalette::Base, "#ffccff"); + } + else + { + pal.setColor (QPalette::Base, Qt::white); + } + ui_->callsign_line_edit->setPalette (pal); + ui_->grid_line_edit->setPalette (pal); + ui_->callsign_line_edit->setText (my_callsign_); + ui_->grid_line_edit->setText (my_grid_); + font_changed_ = false; + decoded_text_font_changed_ = false; + ui_->CW_id_interval_spin_box->setValue (id_interval_); + ui_->PTT_method_button_group->button (rig_params_.PTT_method_)->setChecked (true); + ui_->save_path_display_label->setText (save_directory_.absolutePath ()); + ui_->CW_id_after_73_check_box->setChecked (id_after_73_); + ui_->psk_reporter_check_box->setChecked (spot_to_psk_reporter_); + ui_->monitor_off_check_box->setChecked (monitor_off_at_startup_); + ui_->log_as_RTTY_check_box->setChecked (log_as_RTTY_); + ui_->report_in_comments_check_box->setChecked (report_in_comments_); + ui_->prompt_to_log_check_box->setChecked (prompt_to_log_); + ui_->insert_blank_check_box->setChecked (insert_blank_); + ui_->DXCC_check_box->setChecked (DXCC_); + ui_->clear_DX_check_box->setChecked (clear_DX_); + ui_->miles_check_box->setChecked (miles_); + ui_->quick_call_check_box->setChecked (quick_call_); + ui_->disable_TX_on_73_check_box->setChecked (disable_TX_on_73_); + ui_->watchdog_check_box->setChecked (watchdog_); + ui_->TX_messages_check_box->setChecked (TX_messages_); + ui_->jt9w_bandwidth_mult_combo_box->setCurrentText (QString::number (jt9w_bw_mult_)); + ui_->jt9w_min_dt_double_spin_box->setValue (jt9w_min_dt_); + ui_->jt9w_max_dt_double_spin_box->setValue (jt9w_max_dt_); + ui_->rig_combo_box->setCurrentText (rig_params_.rig_name_); + ui_->TX_mode_button_group->button (data_mode_)->setChecked (true); + ui_->split_mode_button_group->button (rig_params_.split_mode_)->setChecked (true); + ui_->CAT_port_combo_box->setCurrentText (rig_params_.CAT_serial_port_); + ui_->CAT_serial_baud_combo_box->setCurrentText (QString::number (rig_params_.CAT_baudrate_)); + ui_->CAT_data_bits_button_group->button (rig_params_.CAT_data_bits_)->setChecked (true); + ui_->CAT_stop_bits_button_group->button (rig_params_.CAT_stop_bits_)->setChecked (true); + ui_->CAT_handshake_button_group->button (rig_params_.CAT_handshake_)->setChecked (true); + ui_->CAT_DTR_check_box->setChecked (rig_params_.CAT_DTR_always_on_); + ui_->CAT_RTS_check_box->setChecked (rig_params_.CAT_RTS_always_on_); + ui_->TX_audio_source_button_group->button (rig_params_.TX_audio_source_)->setChecked (true); + ui_->CAT_poll_interval_spin_box->setValue (rig_params_.CAT_poll_interval_); + + if (rig_params_.PTT_port_.isEmpty ()) + { + if (ui_->PTT_port_combo_box->count ()) + { + ui_->PTT_port_combo_box->setCurrentText (ui_->PTT_port_combo_box->itemText (0)); + } + } + else + { + ui_->PTT_port_combo_box->setCurrentText (rig_params_.PTT_port_); + } + + next_macros_.setStringList (macros_.stringList ()); + next_frequencies_ = frequencies_.frequencies (); + next_stations_ = stations_.stations (); + + set_rig_invariants (); +} + +void Configuration::impl::done (int r) +{ + // do this here since window is still on screen at this point + SettingsGroup g {settings_, "Configuration"}; + settings_->setValue ("window/size", size ()); + settings_->setValue ("window/pos", pos ()); + + QDialog::done (r); +} + +void Configuration::impl::read_settings () +{ + SettingsGroup g {settings_, "Configuration"}; + + resize (settings_->value ("window/size", size ()).toSize ()); + move (settings_->value ("window/pos", pos ()).toPoint ()); + + my_callsign_ = settings_->value ("MyCall", "").toString (); + my_grid_ = settings_->value ("MyGrid", "").toString (); + + if (next_font_.fromString (settings_->value ("Font", QGuiApplication::font ().toString ()).toString ()) + && next_font_ != QGuiApplication::font ()) + { + font_ = next_font_; + QApplication::setFont (font_); + } + + if (next_decoded_text_font_.fromString (settings_->value ("DecodedTextFont", "Courier, 10").toString ()) + && decoded_text_font_ != next_decoded_text_font_) + { + decoded_text_font_ = next_decoded_text_font_; + Q_EMIT self_->decoded_text_font_changed (decoded_text_font_); + } + + id_interval_ = settings_->value ("IDint", 0).toInt (); + + save_directory_ = settings_->value ("SaveDir", default_save_directory_.absolutePath ()).toString (); + + { + // + // retrieve audio input device + // + auto saved_name = settings_->value ("SoundInName").toString (); + + // deal with special Windows default audio devices + auto default_device = QAudioDeviceInfo::defaultInputDevice (); + if (saved_name == default_device.deviceName ()) + { + audio_input_device_ = default_device; + default_audio_input_device_selected_ = true; + } + else + { + default_audio_input_device_selected_ = false; + Q_FOREACH (auto const& p, QAudioDeviceInfo::availableDevices (QAudio::AudioInput)) // available audio input devices + { + if (p.deviceName () == saved_name) + { + audio_input_device_ = p; + } + } + } + } + + { + // + // retrieve audio output device + // + auto saved_name = settings_->value("SoundOutName").toString(); + + // deal with special Windows default audio devices + auto default_device = QAudioDeviceInfo::defaultOutputDevice (); + if (saved_name == default_device.deviceName ()) + { + audio_output_device_ = default_device; + default_audio_output_device_selected_ = true; + } + else + { + default_audio_output_device_selected_ = false; + Q_FOREACH (auto const& p, QAudioDeviceInfo::availableDevices (QAudio::AudioOutput)) // available audio output devices + { + if (p.deviceName () == saved_name) + { + audio_output_device_ = p; + } + } + } + } + + // retrieve audio channel info + audio_input_channel_ = AudioDevice::fromString (settings_->value ("AudioInputChannel", "Mono").toString ()); + audio_output_channel_ = AudioDevice::fromString (settings_->value ("AudioOutputChannel", "Mono").toString ()); + + jt9w_bw_mult_ = settings_->value ("ToneMult", 1).toUInt (); + jt9w_min_dt_ = settings_->value ("DTmin", -2.5).toFloat (); + jt9w_max_dt_ = settings_->value ("DTmax", 5.).toFloat (); + + monitor_off_at_startup_ = settings_->value ("MonitorOFF", false).toBool (); + spot_to_psk_reporter_ = settings_->value ("PSKReporter", false).toBool (); + id_after_73_ = settings_->value ("After73", false).toBool (); + + macros_.setStringList (settings_->value ("Macros", QStringList {"TNX 73 GL"}).toStringList ()); + + if (settings_->contains ("frequencies")) + { + frequencies_ = settings_->value ("frequencies").value (); + } + + stations_ = settings_->value ("stations").value (); + + log_as_RTTY_ = settings_->value ("toRTTY", false).toBool (); + report_in_comments_ = settings_->value("dBtoComments", false).toBool (); + rig_params_.rig_name_ = settings_->value ("Rig", TransceiverFactory::basic_transceiver_name_).toString (); + rig_params_.CAT_network_port_ = settings_->value ("CATNetworkPort").toString (); + rig_params_.CAT_serial_port_ = settings_->value ("CATSerialPort").toString (); + rig_params_.CAT_baudrate_ = settings_->value ("CATSerialRate", 4800).toInt (); + rig_params_.CAT_data_bits_ = settings_->value ("CATDataBits", QVariant::fromValue (TransceiverFactory::eight_data_bits)).value (); + rig_params_.CAT_stop_bits_ = settings_->value ("CATStopBits", QVariant::fromValue (TransceiverFactory::two_stop_bits)).value (); + rig_params_.CAT_handshake_ = settings_->value ("CATHandshake", QVariant::fromValue (TransceiverFactory::handshake_none)).value (); + rig_params_.CAT_DTR_always_on_ = settings_->value ("DTR", false).toBool (); + rig_params_.CAT_RTS_always_on_ = settings_->value ("RTS", false).toBool (); + rig_params_.PTT_method_ = settings_->value ("PTTMethod", QVariant::fromValue (TransceiverFactory::PTT_method_VOX)).value (); + rig_params_.TX_audio_source_ = settings_->value ("TXAudioSource", QVariant::fromValue (TransceiverFactory::TX_audio_source_front)).value (); + rig_params_.PTT_port_ = settings_->value ("PTTport").toString (); + data_mode_ = settings_->value ("DataMode", QVariant::fromValue (data_mode_none)).value (); + prompt_to_log_ = settings_->value ("PromptToLog", false).toBool (); + insert_blank_ = settings_->value ("InsertBlank", false).toBool (); + DXCC_ = settings_->value ("DXCCEntity", false).toBool (); + clear_DX_ = settings_->value ("ClearCallGrid", false).toBool (); + miles_ = settings_->value ("Miles", false).toBool (); + quick_call_ = settings_->value ("QuickCall", false).toBool (); + disable_TX_on_73_ = settings_->value ("73TxDisable", false).toBool (); + watchdog_ = settings_->value ("Runaway", false).toBool (); + TX_messages_ = settings_->value ("Tx2QSO", false).toBool (); + rig_params_.CAT_poll_interval_ = settings_->value ("Polling", 0).toInt (); + rig_params_.split_mode_ = settings_->value ("SplitMode", QVariant::fromValue (TransceiverFactory::split_mode_none)).value (); +} + +void Configuration::impl::write_settings () +{ + SettingsGroup g {settings_, "Configuration"}; + + settings_->setValue ("MyCall", my_callsign_); + settings_->setValue ("MyGrid", my_grid_); + + settings_->setValue ("Font", font_.toString ()); + settings_->setValue ("DecodedTextFont", decoded_text_font_.toString ()); + + settings_->setValue ("IDint", id_interval_); + + settings_->setValue ("PTTMethod", QVariant::fromValue (rig_params_.PTT_method_)); + settings_->setValue ("PTTport", rig_params_.PTT_port_); + settings_->setValue ("SaveDir", save_directory_.absolutePath ()); + + if (default_audio_input_device_selected_) + { + settings_->setValue ("SoundInName", QAudioDeviceInfo::defaultInputDevice ().deviceName ()); + } + else + { + settings_->setValue ("SoundInName", audio_input_device_.deviceName ()); + } + + if (default_audio_output_device_selected_) + { + settings_->setValue ("SoundOutName", QAudioDeviceInfo::defaultOutputDevice ().deviceName ()); + } + else + { + settings_->setValue ("SoundOutName", audio_output_device_.deviceName ()); + } + + settings_->setValue ("AudioInputChannel", AudioDevice::toString (audio_input_channel_)); + settings_->setValue ("AudioOutputChannel", AudioDevice::toString (audio_output_channel_)); + settings_->setValue ("ToneMult", jt9w_bw_mult_); + settings_->setValue ("DTmin", jt9w_min_dt_); + settings_->setValue ("DTmax", jt9w_max_dt_); + settings_->setValue ("MonitorOFF", monitor_off_at_startup_); + settings_->setValue ("PSKReporter", spot_to_psk_reporter_); + settings_->setValue ("After73", id_after_73_); + settings_->setValue ("Macros", macros_.stringList ()); + settings_->setValue ("frequencies", QVariant::fromValue (frequencies_.frequencies ())); + settings_->setValue ("stations", QVariant::fromValue (stations_.stations ())); + settings_->setValue ("toRTTY", log_as_RTTY_); + settings_->setValue ("dBtoComments", report_in_comments_); + settings_->setValue ("Rig", rig_params_.rig_name_); + settings_->setValue ("CATNetworkPort", rig_params_.CAT_network_port_); + settings_->setValue ("CATSerialPort", rig_params_.CAT_serial_port_); + settings_->setValue ("CATSerialRate", rig_params_.CAT_baudrate_); + settings_->setValue ("CATDataBits", QVariant::fromValue (rig_params_.CAT_data_bits_)); + settings_->setValue ("CATStopBits", QVariant::fromValue (rig_params_.CAT_stop_bits_)); + settings_->setValue ("CATHandshake", QVariant::fromValue (rig_params_.CAT_handshake_)); + settings_->setValue ("DataMode", QVariant::fromValue (data_mode_)); + settings_->setValue ("PromptToLog", prompt_to_log_); + settings_->setValue ("InsertBlank", insert_blank_); + settings_->setValue ("DXCCEntity", DXCC_); + settings_->setValue ("ClearCallGrid", clear_DX_); + settings_->setValue ("Miles", miles_); + settings_->setValue ("QuickCall", quick_call_); + settings_->setValue ("73TxDisable", disable_TX_on_73_); + settings_->setValue ("Runaway", watchdog_); + settings_->setValue ("Tx2QSO", TX_messages_); + settings_->setValue ("DTR", rig_params_.CAT_DTR_always_on_); + settings_->setValue ("RTS", rig_params_.CAT_RTS_always_on_); + settings_->setValue ("pttData", TransceiverFactory::TX_audio_source_rear == rig_params_.TX_audio_source_); + settings_->setValue ("Polling", rig_params_.CAT_poll_interval_); + settings_->setValue ("SplitMode", QVariant::fromValue (rig_params_.split_mode_)); +} + +void Configuration::impl::set_rig_invariants () +{ + auto const& rig = ui_->rig_combo_box->currentText (); + auto const& ptt_port = ui_->PTT_port_combo_box->currentText (); + auto ptt_method = static_cast (ui_->PTT_method_button_group->checkedId ()); + + auto CAT_PTT_enabled = transceiver_factory_.has_CAT_PTT (rig); + auto CAT_indirect_serial_PTT = transceiver_factory_.has_CAT_indirect_serial_PTT (rig); + auto asynchronous_CAT = transceiver_factory_.has_asynchronous_CAT (rig); + + ui_->test_CAT_push_button->setStyleSheet ({}); + + ui_->CAT_poll_interval_label->setEnabled (!asynchronous_CAT); + ui_->CAT_poll_interval_spin_box->setEnabled (!asynchronous_CAT); + + static TransceiverFactory::Capabilities::PortType last_port_type = TransceiverFactory::Capabilities::none; + auto port_type = transceiver_factory_.CAT_port_type (rig); + + bool is_serial_CAT (TransceiverFactory::Capabilities::serial == port_type); + + if (port_type != last_port_type) + { + last_port_type = port_type; + + switch (port_type) + { + case TransceiverFactory::Capabilities::serial: + fill_port_combo_box (ui_->CAT_port_combo_box); + if (ui_->CAT_port_combo_box->currentText ().isEmpty ()) + { + if (ui_->CAT_port_combo_box->count ()) + { + ui_->CAT_port_combo_box->setCurrentText (ui_->CAT_port_combo_box->itemText (0)); + } + } + else + { + ui_->CAT_port_combo_box->setCurrentText (rig_params_.CAT_serial_port_); + } + + ui_->CAT_control_group_box->setEnabled (true); + ui_->CAT_port_label->setText (tr ("Serial Port:")); + ui_->CAT_port_combo_box->setToolTip (tr ("Serial port used for CAT control")); + break; + + case TransceiverFactory::Capabilities::network: + ui_->CAT_port_combo_box->clear (); + if (!rig_params_.CAT_network_port_.isEmpty ()) + { + ui_->CAT_port_combo_box->setCurrentText (rig_params_.CAT_network_port_); + } + + ui_->CAT_control_group_box->setEnabled (true); + ui_->CAT_port_label->setText (tr ("Network Server:")); + ui_->CAT_port_combo_box->setToolTip (tr ("Optional hostname and port of network service\n" + "You can usually leave this blank\n" + "for a sensible default on this machine\n" + "formats:\n" + "\thostname:port\n" + "\tIPv4-address:port\n" + "\t[IPv6-address]:port")); + break; + + default: + ui_->CAT_port_combo_box->clear (); + ui_->CAT_control_group_box->setEnabled (false); + break; + } + } + + auto const& cat_port = ui_->CAT_port_combo_box->currentText (); + + ui_->CAT_serial_port_parameters_group_box->setEnabled (is_serial_CAT); + + auto is_hw_handshake = TransceiverFactory::handshake_hardware == static_cast (ui_->CAT_handshake_button_group->checkedId ()); + ui_->CAT_RTS_check_box->setEnabled (is_serial_CAT && !is_hw_handshake); + + ui_->TX_audio_source_group_box->setEnabled (transceiver_factory_.has_CAT_PTT_mic_data (rig) && TransceiverFactory::PTT_method_CAT == ptt_method); + + // if (ui_->test_PTT_push_button->isEnabled ()) // don't enable if disabled - "Test CAT" must succeed first + // { + // ui_->test_PTT_push_button->setEnabled ((TransceiverFactory::PTT_method_CAT == ptt_method && CAT_PTT_enabled) + // || TransceiverFactory::PTT_method_DTR == ptt_method + // || TransceiverFactory::PTT_method_RTS == ptt_method); + // } + ui_->test_PTT_push_button->setEnabled (false); + + // only enable CAT option if transceiver has CAT PTT + ui_->PTT_CAT_radio_button->setEnabled (CAT_PTT_enabled); + + auto enable_ptt_port = TransceiverFactory::PTT_method_CAT != ptt_method && TransceiverFactory::PTT_method_VOX != ptt_method; + ui_->PTT_port_combo_box->setEnabled (enable_ptt_port); + ui_->PTT_port_label->setEnabled (enable_ptt_port); + + ui_->PTT_port_combo_box->setItemData (ui_->PTT_port_combo_box->findText ("CAT") + , CAT_indirect_serial_PTT ? combo_box_item_enabled : combo_box_item_disabled + , Qt::UserRole - 1); + + ui_->PTT_DTR_radio_button->setEnabled (!(ui_->CAT_DTR_check_box->isChecked () + && ((is_serial_CAT && ptt_port == cat_port) + || ("CAT" == ptt_port && !CAT_indirect_serial_PTT)))); + + ui_->PTT_RTS_radio_button->setEnabled (!((ui_->CAT_RTS_check_box->isChecked () || is_hw_handshake) + && ((ptt_port == cat_port && is_serial_CAT) + || ("CAT" == ptt_port && !CAT_indirect_serial_PTT)))); +} + +bool Configuration::impl::validate () +{ + if (ui_->sound_input_combo_box->currentIndex () < 0 + && !QAudioDeviceInfo::availableDevices (QAudio::AudioInput).empty ()) + { + message_box (tr ("Invalid audio input device")); + return false; + } + + if (ui_->sound_output_combo_box->currentIndex () < 0 + && !QAudioDeviceInfo::availableDevices (QAudio::AudioOutput).empty ()) + { + message_box (tr ("Invalid audio output device")); + return false; + } + + if (!ui_->PTT_method_button_group->checkedButton ()->isEnabled ()) + { + message_box (tr ("Invalid PTT method")); + return false; + } + + // auto CAT_port = ui_->CAT_port_combo_box->currentText (); + // if (ui_->CAT_port_combo_box->isEnabled () && CAT_port.isEmpty ()) + // { + // message_box (tr ("Invalid CAT port")); + // return false; + // } + + auto ptt_method = static_cast (ui_->PTT_method_button_group->checkedId ()); + auto ptt_port = ui_->PTT_port_combo_box->currentText (); + if ((TransceiverFactory::PTT_method_DTR == ptt_method || TransceiverFactory::PTT_method_RTS == ptt_method) + && (ptt_port.isEmpty () + || combo_box_item_disabled == ui_->PTT_port_combo_box->itemData (ui_->PTT_port_combo_box->findText (ptt_port), Qt::UserRole - 1))) + { + message_box (tr ("Invalid PTT port")); + return false; + } + + return true; +} + +int Configuration::impl::exec () +{ + ptt_state_ = false; + have_rig_ = rig_active_; // record that we started with a rig open + + saved_rig_params_ = rig_params_; // used to detect changes that + // require the Transceiver to be + // re-opened + rig_changed_ = false; + + return QDialog::exec(); +} + +void Configuration::impl::accept () +{ + // Called when OK button is clicked. + + if (!validate ()) + { + return; // not accepting + } + + // extract all rig related configuration parameters into temporary + // structure for checking if the rig needs re-opening without + // actually updating our live state + RigParams temp_rig_params; + temp_rig_params.rig_name_ = ui_->rig_combo_box->currentText (); + + switch (transceiver_factory_.CAT_port_type (temp_rig_params.rig_name_)) + { + case TransceiverFactory::Capabilities::serial: + temp_rig_params.CAT_serial_port_ = ui_->CAT_port_combo_box->currentText (); + break; + + case TransceiverFactory::Capabilities::network: + temp_rig_params.CAT_network_port_ = ui_->CAT_port_combo_box->currentText (); + break; + + default: + break; + } + + temp_rig_params.CAT_baudrate_ = ui_->CAT_serial_baud_combo_box->currentText ().toInt (); + temp_rig_params.CAT_data_bits_ = static_cast (ui_->CAT_data_bits_button_group->checkedId ()); + temp_rig_params.CAT_stop_bits_ = static_cast (ui_->CAT_stop_bits_button_group->checkedId ()); + temp_rig_params.CAT_handshake_ = static_cast (ui_->CAT_handshake_button_group->checkedId ()); + temp_rig_params.CAT_DTR_always_on_ = ui_->CAT_DTR_check_box->isChecked (); + temp_rig_params.CAT_RTS_always_on_ = ui_->CAT_RTS_check_box->isChecked (); + temp_rig_params.CAT_poll_interval_ = ui_->CAT_poll_interval_spin_box->value (); + temp_rig_params.PTT_method_ = static_cast (ui_->PTT_method_button_group->checkedId ()); + temp_rig_params.PTT_port_ = ui_->PTT_port_combo_box->currentText (); + temp_rig_params.TX_audio_source_ = static_cast (ui_->TX_audio_source_button_group->checkedId ()); + temp_rig_params.split_mode_ = static_cast (ui_->split_mode_button_group->checkedId ()); + + // open_rig() uses values from models so we use it to validate the + // Transceiver settings before agreeing to accept the configuration + if (temp_rig_params != rig_params_ && !open_rig ()) + { + return; // not accepting + } + sync_transceiver (true); // force an update + + // + // from here on we are bound to accept the new configuration + // parameters so extract values from models and make them live + // + + if (font_changed_) + { + font_changed_ = false; + font_ = next_font_; + QApplication::setFont (font_); + } + + if (decoded_text_font_changed_) + { + decoded_text_font_changed_ = false; + decoded_text_font_ = next_decoded_text_font_; + Q_EMIT self_->decoded_text_font_changed (decoded_text_font_); + } + + rig_params_ = temp_rig_params; // now we can go live with the rig + // related configuration parameters + + // Check to see whether SoundInThread must be restarted, + // and save user parameters. + { + auto const& device_name = ui_->sound_input_combo_box->currentText (); + if (device_name != audio_input_device_.deviceName ()) + { + auto const& default_device = QAudioDeviceInfo::defaultInputDevice (); + if (device_name == default_device.deviceName ()) + { + audio_input_device_ = default_device; + } + else + { + bool found {false}; + Q_FOREACH (auto const& d, QAudioDeviceInfo::availableDevices (QAudio::AudioInput)) + { + if (device_name == d.deviceName ()) + { + audio_input_device_ = d; + found = true; + } + } + if (!found) + { + audio_input_device_ = default_device; + } + } + restart_sound_input_device_ = true; + } + } + + { + auto const& device_name = ui_->sound_output_combo_box->currentText (); + if (device_name != audio_output_device_.deviceName ()) + { + auto const& default_device = QAudioDeviceInfo::defaultOutputDevice (); + if (device_name == default_device.deviceName ()) + { + audio_output_device_ = default_device; + } + else + { + bool found {false}; + Q_FOREACH (auto const& d, QAudioDeviceInfo::availableDevices (QAudio::AudioOutput)) + { + if (device_name == d.deviceName ()) + { + audio_output_device_ = d; + found = true; + } + } + if (!found) + { + audio_output_device_ = default_device; + } + } + restart_sound_output_device_ = true; + } + } + + if (audio_input_channel_ != static_cast (ui_->sound_input_channel_combo_box->currentIndex ())) + { + audio_input_channel_ = static_cast (ui_->sound_input_channel_combo_box->currentIndex ()); + restart_sound_input_device_ = true; + } + Q_ASSERT (audio_input_channel_ <= AudioDevice::Right); + + if (audio_output_channel_ != static_cast (ui_->sound_output_channel_combo_box->currentIndex ())) + { + audio_output_channel_ = static_cast (ui_->sound_output_channel_combo_box->currentIndex ()); + restart_sound_output_device_ = true; + } + Q_ASSERT (audio_output_channel_ <= AudioDevice::Both); + + my_callsign_ = ui_->callsign_line_edit->text (); + my_grid_ = ui_->grid_line_edit->text (); + spot_to_psk_reporter_ = ui_->psk_reporter_check_box->isChecked (); + id_interval_ = ui_->CW_id_interval_spin_box->value (); + id_after_73_ = ui_->CW_id_after_73_check_box->isChecked (); + monitor_off_at_startup_ = ui_->monitor_off_check_box->isChecked (); + jt9w_bw_mult_ = ui_->jt9w_bandwidth_mult_combo_box->currentText ().toUInt (); + jt9w_min_dt_ = static_cast (ui_->jt9w_min_dt_double_spin_box->value ()); + jt9w_max_dt_ = static_cast (ui_->jt9w_max_dt_double_spin_box->value ()); + log_as_RTTY_ = ui_->log_as_RTTY_check_box->isChecked (); + report_in_comments_ = ui_->report_in_comments_check_box->isChecked (); + prompt_to_log_ = ui_->prompt_to_log_check_box->isChecked (); + insert_blank_ = ui_->insert_blank_check_box->isChecked (); + DXCC_ = ui_->DXCC_check_box->isChecked (); + clear_DX_ = ui_->clear_DX_check_box->isChecked (); + miles_ = ui_->miles_check_box->isChecked (); + quick_call_ = ui_->quick_call_check_box->isChecked (); + disable_TX_on_73_ = ui_->disable_TX_on_73_check_box->isChecked (); + watchdog_ = ui_->watchdog_check_box->isChecked (); + TX_messages_ = ui_->TX_messages_check_box->isChecked (); + data_mode_ = static_cast (ui_->TX_mode_button_group->checkedId ()); + save_directory_ = ui_->save_path_display_label->text (); + macros_.setStringList (next_macros_.stringList ()); + frequencies_ = next_frequencies_.frequencies (); + frequencies_.sort (0); + stations_ = next_stations_.stations (); + stations_.sort (0); + + write_settings (); // make visible to all + + QDialog::accept(); +} + +void Configuration::impl::reject () +{ + initialise_models (); // reverts to settings as at exec () + + // check if the Transceiver instance changed, in which case we need + // to re open any prior Transceiver type + if (rig_changed_) + { + if (have_rig_) + { + // we have to do this since the rig has been opened since we + // were exec'ed even though it might fail + open_rig (); + } + else + { + close_rig (); + } + } + + QDialog::reject (); +} + +void Configuration::impl::message_box (QString const& reason, QString const& detail) +{ + QMessageBox mb; + mb.setText (reason); + if (!detail.isEmpty ()) + { + mb.setDetailedText (detail); + } + mb.setStandardButtons (QMessageBox::Ok); + mb.setDefaultButton (QMessageBox::Ok); + mb.setIcon (QMessageBox::Critical); + mb.exec (); +} + +void Configuration::impl::on_font_push_button_clicked () +{ + next_font_ = QFontDialog::getFont (&font_changed_, this); +} + +void Configuration::impl::on_decoded_text_font_push_button_clicked () +{ + next_decoded_text_font_ = QFontDialog::getFont (&decoded_text_font_changed_ + , decoded_text_font_ + , this + , tr ("WSJT-X Decoded Text Font Chooser") +#if QT_VERSION >= 0x050201 + , QFontDialog::MonospacedFonts +#endif + ); +} + +void Configuration::impl::on_PTT_port_combo_box_activated (int /* index */) +{ + set_rig_invariants (); +} + +void Configuration::impl::on_CAT_port_combo_box_activated (int /* index */) +{ + set_rig_invariants (); +} + +void Configuration::impl::on_CAT_serial_baud_combo_box_currentIndexChanged (int /* index */) +{ + set_rig_invariants (); +} + +void Configuration::impl::on_CAT_handshake_button_group_buttonClicked (int /* id */) +{ + set_rig_invariants (); +} + +void Configuration::impl::on_rig_combo_box_currentIndexChanged (int /* index */) +{ + set_rig_invariants (); +} + +void Configuration::impl::on_CAT_data_bits_button_group_buttonClicked (int /* id */) +{ + set_rig_invariants (); +} + +void Configuration::impl::on_CAT_stop_bits_button_group_buttonClicked (int /* id */) +{ + set_rig_invariants (); +} + +void Configuration::impl::on_CAT_poll_interval_spin_box_valueChanged (int /* value */) +{ + set_rig_invariants (); +} + +void Configuration::impl::on_split_mode_button_group_buttonClicked (int /* id */) +{ + setup_split_ = true; +} + +void Configuration::impl::on_test_CAT_push_button_clicked () +{ + if (!validate ()) + { + return; + } + + ui_->test_CAT_push_button->setStyleSheet ({}); + if (open_rig ()) + { + Q_EMIT sync (true); + } + + set_rig_invariants (); +} + +void Configuration::impl::on_test_PTT_push_button_clicked () +{ + if (!validate ()) + { + return; + } + + Q_EMIT self_->transceiver_ptt ((ptt_state_ = !ptt_state_)); + + ui_->test_PTT_push_button->setStyleSheet (ptt_state_ ? "QPushButton{background-color: red;" + "border-style: outset; border-width: 1px; border-radius: 5px;" + "border-color: black; min-width: 5em; padding: 3px;}" + : ""); +} + +void Configuration::impl::on_CAT_DTR_check_box_toggled (bool /* checked */) +{ + set_rig_invariants (); +} + +void Configuration::impl::on_CAT_RTS_check_box_toggled (bool /* checked */) +{ + set_rig_invariants (); +} + +void Configuration::impl::on_PTT_method_button_group_buttonClicked (int /* id */) +{ + set_rig_invariants (); +} + +void Configuration::impl::on_callsign_line_edit_editingFinished () +{ + ui_->callsign_line_edit->setText (ui_->callsign_line_edit->text ().toUpper ()); +} + +void Configuration::impl::on_grid_line_edit_editingFinished () +{ + auto text = ui_->grid_line_edit->text (); + ui_->grid_line_edit->setText (text.left (4).toUpper () + text.mid (4).toLower ()); +} + +void Configuration::impl::on_sound_input_combo_box_currentTextChanged (QString const& text) +{ + default_audio_input_device_selected_ = QAudioDeviceInfo::defaultInputDevice ().deviceName () == text; +} + +void Configuration::impl::on_sound_output_combo_box_currentTextChanged (QString const& text) +{ + default_audio_output_device_selected_ = QAudioDeviceInfo::defaultOutputDevice ().deviceName () == text; +} + +void Configuration::impl::on_add_macro_line_edit_editingFinished () +{ + ui_->add_macro_line_edit->setText (ui_->add_macro_line_edit->text ().toUpper ()); +} + +void Configuration::impl::on_delete_macro_push_button_clicked (bool /* checked */) +{ + auto index = ui_->macros_list_view->selectionModel ()->currentIndex (); + if (index.isValid ()) + { + next_macros_.removeRow (index.row ()); + } +} + +void Configuration::impl::delete_macro () +{ + auto index = ui_->macros_list_view->currentIndex (); + if (index.isValid ()) + { + next_macros_.removeRow (index.row ()); + } +} + +void Configuration::impl::on_add_macro_push_button_clicked (bool /* checked */) +{ + if (next_macros_.insertRow (next_macros_.rowCount ())) + { + auto index = next_macros_.index (next_macros_.rowCount () - 1); + ui_->macros_list_view->setCurrentIndex (index); + next_macros_.setData (index, ui_->add_macro_line_edit->text ()); + ui_->add_macro_line_edit->clear (); + } +} + +void Configuration::impl::delete_frequencies () +{ + auto selection_model = ui_->frequencies_table_view->selectionModel (); + selection_model->select (selection_model->selection (), QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); + next_frequencies_.removeDisjointRows (selection_model->selectedRows ()); +} + +void Configuration::impl::insert_frequency () +{ + if (QDialog::Accepted == frequency_dialog_->exec ()) + { + ui_->frequencies_table_view->setCurrentIndex (next_frequencies_.add (frequency_dialog_->frequency ())); + } +} + +void Configuration::impl::delete_stations () +{ + auto selection_model = ui_->stations_table_view->selectionModel (); + selection_model->select (selection_model->selection (), QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); + next_stations_.removeDisjointRows (selection_model->selectedRows ()); +} + +void Configuration::impl::insert_station () +{ + if (QDialog::Accepted == station_dialog_->exec ()) + { + ui_->stations_table_view->setCurrentIndex (next_stations_.add (station_dialog_->station ())); + } +} + +void Configuration::impl::on_save_path_select_push_button_clicked (bool /* checked */) +{ + QFileDialog fd {this, tr ("Save Directory"), ui_->save_path_display_label->text ()}; + fd.setFileMode (QFileDialog::Directory); + fd.setOption (QFileDialog::ShowDirsOnly); + if (fd.exec ()) + { + if (fd.selectedFiles ().size ()) + { + ui_->save_path_display_label->setText (fd.selectedFiles ().at (0)); + } + } +} + +bool Configuration::impl::have_rig (bool open_if_closed) +{ + if (open_if_closed && !rig_active_ && !open_rig ()) + { + QMessageBox::critical (this, "WSJT-X", tr ("Failed to open connection to rig")); + } + return rig_active_; +} + +bool Configuration::impl::open_rig () +{ + auto result = false; + + try + { + close_rig (); + + // create a new Transceiver object + auto rig = transceiver_factory_.create (ui_->rig_combo_box->currentText () + , ui_->CAT_port_combo_box->currentText () + , ui_->CAT_serial_baud_combo_box->currentText ().toInt () + , static_cast (ui_->CAT_data_bits_button_group->checkedId ()) + , static_cast (ui_->CAT_stop_bits_button_group->checkedId ()) + , static_cast (ui_->CAT_handshake_button_group->checkedId ()) + , ui_->CAT_DTR_check_box->isChecked () + , ui_->CAT_RTS_check_box->isChecked () + , static_cast (ui_->PTT_method_button_group->checkedId ()) + , static_cast (ui_->TX_audio_source_button_group->checkedId ()) + , static_cast (ui_->split_mode_button_group->checkedId ()) + , ui_->PTT_port_combo_box->currentText () + , ui_->CAT_poll_interval_spin_box->value () * 1000 + , &transceiver_thread_); + + // hook up Configuration transceiver control signals to Transceiver slots + // + // these connections cross the thread boundary + connect (this, &Configuration::impl::frequency, rig.get (), &Transceiver::frequency); + connect (this, &Configuration::impl::tx_frequency, rig.get (), &Transceiver::tx_frequency); + connect (this, &Configuration::impl::mode, rig.get (), &Transceiver::mode); + connect (this, &Configuration::impl::ptt, rig.get (), &Transceiver::ptt); + connect (this, &Configuration::impl::sync, rig.get (), &Transceiver::sync); + + // hook up Transceiver signals to Configuration signals + // + // these connections cross the thread boundary + connect (rig.get (), &Transceiver::update, this, &Configuration::impl::handle_transceiver_update); + connect (rig.get (), &Transceiver::failure, this, &Configuration::impl::handle_transceiver_failure); + + // setup thread safe startup and close down semantics + connect (this, &Configuration::impl::stop_transceiver, rig.get (), &Transceiver::stop); + + auto p = rig.release (); // take ownership + // schedule eventual destruction + // + // must be queued connection to avoid premature self-immolation + // since finished signal is going to be emitted from the object + // that will get destroyed in its own stop slot i.e. a same + // thread signal to slot connection which by default will be + // reduced to a method function call. + connect (p, &Transceiver::finished, p, &Transceiver::deleteLater, Qt::QueuedConnection); + + ui_->test_CAT_push_button->setStyleSheet ({}); + rig_active_ = true; + QTimer::singleShot (0, p, SLOT (start ())); // start rig on its thread + result = true; + } + catch (std::exception const& e) + { + handle_transceiver_failure (e.what ()); + } + + rig_changed_ = true; + return result; +} + +void Configuration::impl::transceiver_frequency (Frequency f) +{ +#if WSJT_TRACE_CAT + qDebug () << "Configuration::transceiver_frequency:" << f; +#endif + + if (set_mode () || cached_rig_state_.frequency () != f) + { + cached_rig_state_.frequency (f); + + // lookup offset + transceiver_offset_ = stations_.offset (f); + Q_EMIT frequency (f + transceiver_offset_); + } +} + +bool Configuration::impl::set_mode () +{ + // Some rigs change frequency when switching between some modes so + // we need to check if we change mode and not elide the frequency + // setting in the same as the cached frequency. + bool mode_changed {false}; + + auto data_mode = static_cast (ui_->TX_mode_button_group->checkedId ()); + + // Set mode if we are responsible for it. + if (data_mode_USB == data_mode && cached_rig_state_.mode () != Transceiver::USB) + { + if (Transceiver::USB != cached_rig_state_.mode ()) + { + cached_rig_state_.mode (Transceiver::USB); + Q_EMIT mode (Transceiver::USB, cached_rig_state_.split () && data_mode_none != data_mode_); + mode_changed = true; + } + } + if (data_mode_data == data_mode && cached_rig_state_.mode () != Transceiver::DIG_U) + { + if (Transceiver::DIG_U != cached_rig_state_.mode ()) + { + cached_rig_state_.mode (Transceiver::DIG_U); + Q_EMIT mode (Transceiver::DIG_U, cached_rig_state_.split () && data_mode_none != data_mode_); + mode_changed = true; + } + } + + return mode_changed; +} + +void Configuration::impl::transceiver_tx_frequency (Frequency f) +{ + if (set_mode () || cached_rig_state_.tx_frequency () != f) + { + cached_rig_state_.tx_frequency (f); + cached_rig_state_.split (f); + + // lookup offset if we are in split mode + if (f) + { + transceiver_offset_ = stations_.offset (f); + } + + // Rationalise TX VFO mode if we ask for split and are + // responsible for mode. + Q_EMIT tx_frequency (f, cached_rig_state_.split () && data_mode_none != data_mode_); + } +} + +void Configuration::impl::transceiver_mode (MODE m) +{ + if (cached_rig_state_.mode () != m) + { + cached_rig_state_.mode (m); + + // Rationalise mode if we are responsible for it and in split mode. + Q_EMIT mode (m, cached_rig_state_.split () && data_mode_none != data_mode_); + } +} + +void Configuration::impl::transceiver_ptt (bool on) +{ + set_mode (); + + cached_rig_state_.ptt (on); + + // pass this on regardless of cache + Q_EMIT ptt (on); +} + +void Configuration::impl::sync_transceiver (bool force_signal) +{ + // pass this on as cache must be ignored + Q_EMIT sync (force_signal); +} + +void Configuration::impl::handle_transceiver_update (TransceiverState state) +{ +#if WSJT_TRACE_CAT + qDebug () << "Configuration::handle_transceiver_update: Transceiver State:" << state; +#endif + + if (state.online ()) + { + TransceiverFactory::SplitMode split_mode_selected; + if (isVisible ()) + { + ui_->test_CAT_push_button->setStyleSheet ("QPushButton {background-color: green;}"); + + auto const& rig = ui_->rig_combo_box->currentText (); + auto ptt_method = static_cast (ui_->PTT_method_button_group->checkedId ()); + auto CAT_PTT_enabled = transceiver_factory_.has_CAT_PTT (rig); + ui_->test_PTT_push_button->setEnabled ((TransceiverFactory::PTT_method_CAT == ptt_method && CAT_PTT_enabled) + || TransceiverFactory::PTT_method_DTR == ptt_method + || TransceiverFactory::PTT_method_RTS == ptt_method); + + set_mode (); + + // Follow the setup choice. + split_mode_selected = static_cast (ui_->split_mode_button_group->checkedId ()); + } + else + { + // Follow the rig unless configuration has been changed. + split_mode_selected = static_cast (rig_params_.split_mode_); + + if (enforce_mode_and_split_) + { + if ((TransceiverFactory::split_mode_none != split_mode_selected) != state.split ()) + { + if (!setup_split_) + { + // Rig split mode isn't consistent with settings so + // change settings. + // + // For rigs that can't report split mode changes + // (e.g.Icom) this is going to confuse operators, but + // what can we do if they change the rig? + // auto split_mode = state.split () ? TransceiverFactory::split_mode_rig : TransceiverFactory::split_mode_none; + // rig_params_.split_mode_ = split_mode; + // ui_->split_mode_button_group->button (split_mode)->setChecked (true); + // split_mode_selected = split_mode; + setup_split_ = true; + + // Q_EMIT self_->transceiver_failure (tr ("Rig split mode setting not consistent with WSJT-X settings. Changing WSJT-X settings for you.")); + Q_EMIT self_->transceiver_failure (tr ("Rig split mode setting not consistent with WSJT-X settings.")); + } + } + + set_mode (); + } + } + + // One time rig setup split + if (setup_split_ && cached_rig_state_.split () != state.split ()) + { + Q_EMIT tx_frequency (TransceiverFactory::split_mode_none != split_mode_selected ? state.tx_frequency () : 0, true); + } + setup_split_ = false; + + // if (TransceiverFactory::split_mode_emulate == split_mode_selected) + // { + // state.split (true); // complete the illusion + // } + } + else + { + close_rig (); + } + + cached_rig_state_ = state; + + // take off offset + cached_rig_state_.frequency (cached_rig_state_.frequency () - transceiver_offset_); + if (cached_rig_state_.tx_frequency ()) + { + cached_rig_state_.tx_frequency (cached_rig_state_.tx_frequency () - transceiver_offset_); + } + + // pass on to clients + Q_EMIT self_->transceiver_update (cached_rig_state_); +} + +void Configuration::impl::handle_transceiver_failure (QString reason) +{ +#if WSJT_TRACE_CAT + qDebug () << "Configuration::handle_transceiver_failure: reason:" << reason; +#endif + + close_rig (); + + if (isVisible ()) + { + message_box (tr ("Rig failure"), reason); + } + else + { + // pass on if our dialog isn't active + Q_EMIT self_->transceiver_failure (reason); + } +} + +void Configuration::impl::close_rig () +{ + ui_->test_PTT_push_button->setStyleSheet ({}); + ui_->test_PTT_push_button->setEnabled (false); + ptt_state_ = false; + + // revert to no rig configured + if (rig_active_) + { + ui_->test_CAT_push_button->setStyleSheet ("QPushButton {background-color: red;}"); + Q_EMIT stop_transceiver (); + rig_active_ = false; + } +} + +// load the available audio devices into the selection combo box and +// select the default device if the current device isn't set or isn't +// available +bool Configuration::impl::load_audio_devices (QAudio::Mode mode, QComboBox * combo_box, QAudioDeviceInfo * device) +{ + using std::copy; + using std::back_inserter; + + bool result {false}; + + combo_box->clear (); + + int current_index = -1; + int default_index = -1; + + int extra_items {0}; + + auto const& default_device = (mode == QAudio::AudioInput ? QAudioDeviceInfo::defaultInputDevice () : QAudioDeviceInfo::defaultOutputDevice ()); + + // deal with special default audio devices on Windows + if ("Default Input Device" == default_device.deviceName () + || "Default Output Device" == default_device.deviceName ()) + { + default_index = 0; + + QList channel_counts; + auto scc = default_device.supportedChannelCounts (); + copy (scc.cbegin (), scc.cend (), back_inserter (channel_counts)); + + combo_box->addItem (default_device.deviceName (), channel_counts); + ++extra_items; + if (default_device == *device) + { + current_index = 0; + result = true; + } + } + + Q_FOREACH (auto const& p, QAudioDeviceInfo::availableDevices (mode)) + { + // convert supported channel counts into something we can store in the item model + QList channel_counts; + auto scc = p.supportedChannelCounts (); + copy (scc.cbegin (), scc.cend (), back_inserter (channel_counts)); + + combo_box->addItem (p.deviceName (), channel_counts); + if (p == *device) + { + current_index = combo_box->count () - 1; + } + else if (p == default_device) + { + default_index = combo_box->count () - 1; + } + } + if (current_index < 0) // not found - use default + { + *device = default_device; + result = true; + current_index = default_index; + } + combo_box->setCurrentIndex (current_index); + + return result; +} + +// enable only the channels that are supported by the selected audio device +void Configuration::impl::update_audio_channels (QComboBox const * source_combo_box, int index, QComboBox * combo_box, bool allow_both) +{ + // disable all items + for (int i (0); i < combo_box->count (); ++i) + { + combo_box->setItemData (i, combo_box_item_disabled, Qt::UserRole - 1); + } + + Q_FOREACH (QVariant const& v, source_combo_box->itemData (index).toList ()) + { + // enable valid options + int n {v.toInt ()}; + if (2 == n) + { + combo_box->setItemData (AudioDevice::Left, combo_box_item_enabled, Qt::UserRole - 1); + combo_box->setItemData (AudioDevice::Right, combo_box_item_enabled, Qt::UserRole - 1); + if (allow_both) + { + combo_box->setItemData (AudioDevice::Both, combo_box_item_enabled, Qt::UserRole - 1); + } + } + else if (1 == n) + { + combo_box->setItemData (AudioDevice::Mono, combo_box_item_enabled, Qt::UserRole - 1); + } + } +} + +// load all the supported rig names into the selection combo box +void Configuration::impl::enumerate_rigs () +{ + ui_->rig_combo_box->clear (); + + auto rigs = transceiver_factory_.supported_transceivers (); + + for (auto r = rigs.cbegin (); r != rigs.cend (); ++r) + { + if ("None" == r.key ()) + { + // put None first + ui_->rig_combo_box->insertItem (0, r.key (), r.value ().model_number_); + } + else + { + ui_->rig_combo_box->addItem (r.key (), r.value ().model_number_); + } + } + + ui_->rig_combo_box->setCurrentText (rig_params_.rig_name_); +} + +void Configuration::impl::fill_port_combo_box (QComboBox * cb) +{ + auto current_text = cb->currentText (); + + cb->clear (); + +#ifdef WIN32 + + for (int i {1}; i < 100; ++i) + { + auto item = "COM" + QString::number (i); + cb->addItem (item); + } + cb->addItem("USB"); + +#else + + QStringList ports = { + "/dev/ttyS0" + , "/dev/ttyS1" + , "/dev/ttyS2" + , "/dev/ttyS3" + , "/dev/ttyS4" + , "/dev/ttyS5" + , "/dev/ttyS6" + , "/dev/ttyS7" + , "/dev/ttyUSB0" + , "/dev/ttyUSB1" + , "/dev/ttyUSB2" + , "/dev/ttyUSB3" + }; + cb->addItems (ports); + +#endif + + cb->setEditText (current_text); +} + + +inline +bool operator != (RigParams const& lhs, RigParams const& rhs) +{ + return + lhs.CAT_serial_port_ != rhs.CAT_serial_port_ + || lhs.CAT_network_port_ != rhs.CAT_network_port_ + || lhs.CAT_baudrate_ != rhs.CAT_baudrate_ + || lhs.CAT_data_bits_ != rhs.CAT_data_bits_ + || lhs.CAT_stop_bits_ != rhs.CAT_stop_bits_ + || lhs.CAT_handshake_ != rhs.CAT_handshake_ + || lhs.CAT_DTR_always_on_ != rhs.CAT_DTR_always_on_ + || lhs.CAT_RTS_always_on_ != rhs.CAT_RTS_always_on_ + || lhs.CAT_poll_interval_ != rhs.CAT_poll_interval_ + || lhs.PTT_method_ != rhs.PTT_method_ + || lhs.PTT_port_ != rhs.PTT_port_ + || lhs.TX_audio_source_ != rhs.TX_audio_source_ + || lhs.split_mode_ != rhs.split_mode_ + || lhs.rig_name_ != rhs.rig_name_; +} + + +#if !defined (QT_NO_DEBUG_STREAM) +ENUM_QDEBUG_OPS_IMPL (Configuration, DataMode); +#endif + +ENUM_QDATASTREAM_OPS_IMPL (Configuration, DataMode); + +ENUM_CONVERSION_OPS_IMPL (Configuration, DataMode); diff --git a/Configuration.hpp b/Configuration.hpp new file mode 100644 index 000000000..caff847d8 --- /dev/null +++ b/Configuration.hpp @@ -0,0 +1,188 @@ +#ifndef CONFIGURATION_HPP_ +#define CONFIGURATION_HPP_ + +#include + +#include "Radio.hpp" +#include "AudioDevice.hpp" +#include "Transceiver.hpp" + +#include "pimpl_h.hpp" + +class QSettings; +class QWidget; +class QAudioDeviceInfo; +class QString; +class QDir; +class QFont; +class Bands; +class FrequencyList; +class StationList; +class QStringListModel; + +// +// Class Configuration +// +// Encapsulates the control, access and, persistence of user defined +// settings for the wsjtx GUI. Setting values are accessed through a +// QDialog window containing concept orientated tab windows. +// +// Responsibilities +// +// Provides management of the CAT and PTT rig interfaces, providing +// control access via a minimal generic set of Qt slots and status +// updates via Qt signals. Internally the rig control capability is +// farmed out to a separate thread since many of the rig control +// functions are blocking. +// +// All user settings required by the wsjtx GUI are exposed through +// query methods. +// +// The QSettings instance passed to the constructor is used to read +// and write user settings. +// +// Pointers to three QAbstractItemModel objects are provided to give +// access to amateur band information, user working frequencies and, +// user operating band information. These porovide consistent data +// models that can be used in GUI lists or tables or simply queried +// for user defined bands, default operating frequencies and, station +// descriptions. +// +class Configuration final + : public QObject +{ + Q_OBJECT; + Q_ENUMS (DataMode); + +public: + using MODE = Transceiver::MODE; + using TransceiverState = Transceiver::TransceiverState; + using Frequency = Radio::Frequency; + + enum DataMode {data_mode_none, data_mode_USB, data_mode_data}; + + explicit Configuration (QString const& instance_key, QSettings * settings, QWidget * parent = nullptr); + ~Configuration (); + + int exec (); + + QDir data_path () const; + + QAudioDeviceInfo const& audio_input_device () const; + AudioDevice::Channel audio_input_channel () const; + QAudioDeviceInfo const& audio_output_device () const; + AudioDevice::Channel audio_output_channel () const; + + // These query methods should be used after a call to exec() to + // determine if either the audio input or audio output stream + // parameters have changed. The respective streams should be + // re-opened if they return true. + bool restart_audio_input () const; + bool restart_audio_output () const; + + QString my_callsign () const; + QString my_grid () const; + QFont decoded_text_font () const; + qint32 id_interval () const; + bool id_after_73 () const; + bool spot_to_psk_reporter () const; + bool monitor_off_at_startup () const; + bool log_as_RTTY () const; + bool report_in_comments () const; + bool prompt_to_log () const; + bool insert_blank () const; + bool DXCC () const; + bool clear_DX () const; + bool miles () const; + bool quick_call () const; + bool disable_TX_on_73 () const; + bool watchdog () const; + bool TX_messages () const; + bool split_mode () const; + Bands * bands (); + FrequencyList * frequencies (); + StationList * stations (); + QStringListModel * macros (); + QDir save_directory () const; + QString rig_name () const; + unsigned jt9w_bw_mult () const; + float jt9w_min_dt () const; + float jt9w_max_dt () const; + + // This method queries if a CAT and PTT connection is operational, + // + // It also doubles as an initialisation method when the + // open_if_closed parameter is passed as true. + bool transceiver_online (bool open_if_closed = false); + + // Close down connection to rig. + void transceiver_offline (); + + // Set transceiver frequency in Hertz. + Q_SLOT void transceiver_frequency (Frequency); + + // Setting a non zero TX frequency means split operation + // rationalise_mode means ensure TX uses same mode as RX. + Q_SLOT void transceiver_tx_frequency (Frequency = 0u); + + // Set transceiver mode. + // + // Rationalise means ensure TX uses same mode as RX. + Q_SLOT void transceiver_mode (MODE); + + // Set/unset PTT. + // + // Note that this must be called even if VOX PTT is selected since + // the "Emulate Split" mode requires PTT information to coordinate + // frequency changes. + Q_SLOT void transceiver_ptt (bool = true); + + // Attempt to (re-)synchronise transceiver state. + // + // Force signal guarantees either a transceiver_update or a + // transceiver_failure signal. + // + // The enforce_mode_and_split parameter ensures that future + // transceiver updates have the correct mode and split setting + // i.e. the transceiver is ready for use. + Q_SLOT void sync_transceiver (bool force_signal = false, bool enforce_mode_and_split = false); + + + // + // This signal indicates that a font has been selected and accepted + // for the decoded text. + // + Q_SIGNAL void decoded_text_font_changed (QFont); + + + // + // These signals are emitted and reflect transceiver state changes + // + + // signals a change in one of the TransceiverState members + Q_SIGNAL void transceiver_update (Transceiver::TransceiverState) const; + + // Signals a failure of a control rig CAT or PTT connection. + // + // A failed rig CAT or PTT connection is fatal and the underlying + // connections are closed automatically. The connections can be + // re-established with a call to transceiver_online(true) assuming + // the fault condition has been rectified or is transient. + Q_SIGNAL void transceiver_failure (QString reason) const; + +private: + class impl; + pimpl m_; +}; + +Q_DECLARE_METATYPE (Configuration::DataMode); + +#if !defined (QT_NO_DEBUG_STREAM) +ENUM_QDEBUG_OPS_DECL (Configuration, DataMode); +#endif + +ENUM_QDATASTREAM_OPS_DECL (Configuration, DataMode); + +ENUM_CONVERSION_OPS_DECL (Configuration, DataMode); + +#endif diff --git a/Configuration.ui b/Configuration.ui new file mode 100644 index 000000000..5c3883a13 --- /dev/null +++ b/Configuration.ui @@ -0,0 +1,1812 @@ + + + configuration_dialog + + + + 0 + 0 + 508 + 471 + + + + Configuration + + + + + + Select tab to change configuration parameters. + + + 0 + + + + Genera&l + + + General station details and settings. + + + + + + Station Details + + + + + + My C&all: + + + callsign_line_edit + + + + + + + Station callsign. + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + M&y Grid: + + + grid_line_edit + + + + + + + Maidenhead locator (only the first four characters are required). + + + + + + + + + + Qt::Horizontal + + + + + + + Display + + + + + + Show if decoded stations are new DXCC entities or worked before. + + + Show &DXCC entity and worked before status + + + false + + + + + + + Include a separator line between periods in the band activity window. + + + &Blank line between decoding periods + + + + + + + + + Set the font characteristics for the application. + + + Font ... + + + + + + + Set the font characteristics for the Band Activity and Rx Frequency areas. + + + Decoded text font ... + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Show distance to DX station in miles rather than kilometers. + + + Display dista&nce in miles + + + + + + + Show outgoing transmitted messages in the Rx frequency window. + + + &Tx messages to Rx frequency window + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Qt::Horizontal + + + + + + + Behaviour + + + + + + Don't start decoding until the monitor button is clicked. + + + Mon&itor off at startup + + + false + + + + + + + Automatic transmission mode. + + + Doubl&e-click on call sets Tx enable + + + + + + + Turns off automatic transmissions after sending a 73 or any other free +text message. + + + Di&sable Tx after sending 73 + + + + + + + Stop transmitting automatically after five periods. + + + Runaway Tx &watchdog + + + + + + + + + Send a CW ID after every 73 or free text message. + + + CW ID a&fter 73 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + Periodic CW ID Inter&val: + + + CW_id_interval_spin_box + + + + + + + + 0 + 0 + + + + Send a CW ID periodically every few minutes. +This might be required under your countries licence regulations. +It will not interfere with other users as it is always sent in the +quiet period when decoding is done. + + + + + + + + + + + + + &Radio + + + Radio interface configuration settings. + + + + + + + 0 + 0 + + + + Settings that control your CAT interface. + + + CAT Control + + + + + + + + Port: + + + CAT_port_combo_box + + + + + + + Serial port used for CAT control. + + + true + + + + + + QComboBox::NoInsert + + + + + + + + + Serial Port Parameters + + + + + + + + Baud Rate: + + + CAT_serial_baud_combo_box + + + + + + + Serial port data rate which must match the setting of your radio. + + + 2 + + + + 1200 + + + + + 2400 + + + + + 4800 + + + + + 9600 + + + + + 19200 + + + + + 38400 + + + + + 57600 + + + + + + + + + + Number of data bits used to communicate with your radios CAT interface (nealy always 8). + + + Data Bits + + + + + + Se&ven + + + CAT_data_bits_button_group + + + + + + + E&ight + + + true + + + CAT_data_bits_button_group + + + + + + + + + + Number of stop bits used when communicating with your radios CAT interface +(consult you radio manual for details). + + + Stop Bits + + + + + + On&e + + + CAT_stop_bits_button_group + + + + + + + T&wo + + + true + + + CAT_stop_bits_button_group + + + + + + + + + + Flow control protocol used between this computer and your radios CAT interface (usually "None" but some require "Hardware"). + + + Handshake + + + + + + &None + + + true + + + CAT_handshake_button_group + + + + + + + Software flow control (very rare on CAT interfaces). + + + XON/XOFF + + + CAT_handshake_button_group + + + + + + + Flow control using the RTS and CTS RS-232 control lines +not often used but some radios have it as an option and +a few, particularly some Kenwood rigs, require it). + + + &Hardware + + + CAT_handshake_button_group + + + + + + + + + + Special control of CAT port control lines. + + + Force Control Lines + + + + + + Force the DTR control line high on the CAT serial port. +This is required for a few CAT interfaces that are powered +from the DTR control line. +Normally you should leave this unchecked. + + + DTR + + + + + + + Force the RTS control line high on the CAT serial port. +This is required for a few CAT interfaces that are powered +from the RTS control line. +Normally you should leave this unchecked. +This option is only available if Hardware handshaking is not +selected above. + + + RTS + + + + + + + + + + + + + + + + Qt::Horizontal + + + + + + + Qt::Vertical + + + + + + + How this program activates the PTT on your radio + + + PTT Method + + + + + + No PTT activation, instead the radios automatic VOX is used to key the transmitter. +Use this if you have no radio interface hardware. + + + VO&X + + + PTT_method_button_group + + + + + + + Use the RS-232 DTR control line to toggle your radios PTT, +requires hardware to inteface the line. +Some commercial interface units also use this method. +The DTR control line of the CAT serial port may be used for this or +a DTR control line on a different serial port may be used. + + + &DTR + + + true + + + PTT_method_button_group + + + + + + + Some radios support PTT via CAT commands, +use this option if your radio supports it and you have no +other hardware interface for PTT. + + + C&AT + + + PTT_method_button_group + + + + + + + Use the RS-232 RTS control line to toggle your radios PTT, +requires hardware to inteface the line. +Some commercial interface units also use this method. +The RTS control line of the CAT serial port may be used for this or +a RTS control line on a different serial port may be used. +Note that this options is not available on the CAT serial port +when hardware flow control is used. + + + R&TS + + + PTT_method_button_group + + + + + + + + + Port: + + + PTT_port_combo_box + + + + + + + + 1 + 0 + + + + Select the RS-232 serial port utilised for PTT control, +this option is available when DTR or RTS is selected above +as a transmit method. +This port can be the same one as the one used for CAT control. +For some interface types the special value CAT may be choosen, +this is used for non-serial CAT interfaces that can control +serial port control lines remotely (OmniRig for example). + + + true + + + + + + -1 + + + QComboBox::NoInsert + + + + + + + + + + + + Modulation mode selected on radio. + + + Mode + + + + + + USB is the usually the correct modulation mode, +unless the radio has a special data or packet mode setting +for AFSK operation. + + + US&B + + + true + + + TX_mode_button_group + + + + + + + Don't allow the program to set the radio mode +(not recommended but use if the wrong mode +or bandwidth is selected). + + + None + + + TX_mode_button_group + + + + + + + If this is availabe then it is usually the correct mode for this program. + + + Data/P&kt + + + TX_mode_button_group + + + + + + + + + + Some radios can select the audio input using a CAT command, +this setting allows you to select which audio input will be used +(if it is available then generally the Rear/Data option is best). + + + Transmit Audio Source + + + + + + Rear&/Data + + + TX_audio_source_button_group + + + + + + + &Front/Mic + + + true + + + TX_audio_source_button_group + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Rig: + + + rig_combo_box + + + + + + + + 1 + 0 + + + + + + + + Poll Interval: + + + CAT_poll_interval_spin_box + + + + + + + 1 + + + + + + + + + Qt::Horizontal + + + + + + + + + Attempt to connect to the radio with these settings. +Another dialog will pop up where you can verify correct operation. + + + Test CAT + + + + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 40 + 20 + + + + + + + + Attempt to activate the transmitter. +Click again to deactivate. Normally no power should be +output since there is no audio being generated at this time. +Check that any Tx indication on your radio and/or your +radio interface behave as expected. + + + Test PTT + + + + + + + + + Split Operation + + + + + + None + + + true + + + split_mode_button_group + + + + + + + Rig + + + split_mode_button_group + + + + + + + Fake It + + + split_mode_button_group + + + + + + + + + + + A&udio + + + Audio interface settings + + + + + + Save Directory + + + + + + Loc&ation: + + + save_path_select_push_button + + + + + + + + 1 + 0 + + + + Path to which .WAV files are saved. + + + false + + + background-color: rgb(255, 255, 255); + + + TextLabel + + + + + + + Click to select a different save directory for .WAV files. + + + S&elect + + + + + + + + + + Soundcard + + + + + + + 1 + 0 + + + + Select the audio CODEC to use for transmitting. +If this is your default device for system sounds then +ensure that all system sounds are disabled otherwise +you will broadcast any systems sounds generated during +transmitting periods. + + + + + + + + 1 + 0 + + + + Select the audio CODEC to use for receiving. + + + + + + + &Input: + + + sound_input_combo_box + + + + + + + Select the channel to use for receiving. + + + + Mono + + + + + Left + + + + + Right + + + + + Both + + + + + + + + Select the audio channel used for transmission. +Unless you have multiple radios connected on different +channels; then you will usually want to select mono or +both here. + + + + Mono + + + + + Left + + + + + Right + + + + + Both + + + + + + + + Ou&tput: + + + sound_output_combo_box + + + + + + + + + + JT9W Settings + + + + + + + + + 1 + + + + + 2 + + + + + 4 + + + + + 8 + + + + + 16 + + + + + 32 + + + + + 64 + + + + + 128 + + + + + + + + Bandwidth Multiplier: + + + jt9w_bandwidth_mult_combo_box + + + + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + DT Max: + + + jt9w_max_dt_double_spin_box + + + + + + + DT Min: + + + jt9w_min_dt_double_spin_box + + + + + + + s + + + 1 + + + -2.500000000000000 + + + 5.000000000000000 + + + 0.100000000000000 + + + -2.500000000000000 + + + + + + + s + + + 1 + + + -2.500000000000000 + + + 5.000000000000000 + + + 0.100000000000000 + + + 5.000000000000000 + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + + + + + + Tx &Macros + + + Canned free text messages setup + + + + + + &Add + + + + + + + 13 + + + + + + + &Delete + + + + + + + Qt::ActionsContextMenu + + + QListView { + show-decoration-selected: 1; /* make the selection span the entire width of the view */ +} + +QListView::item:alternate { + background: #EEEEEE; +} + +QListView::item:selected { + border: 1px solid #6a6ea9; +} + +QListView::item:selected:!active { + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #ABAFE5, stop: 1 #8588B2); +} + +QListView::item:selected:active { + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #6a6ea9, stop: 1 #888dd9); +} + +QListView::item:hover { + background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #FAFBFE, stop: 1 #DCDEF1); +} + + + QAbstractItemView::SingleSelection + + + true + + + + + + + + Reportin&g + + + Reporting and logging settings + + + + + + Logging + + + + + + The program will pop up a partially completed Log QSO dialog when you send a 73 or free text message. + + + Promp&t me to log QSO + + + + + + + Some logging programs will not accept JT-65 or JT9 as a recognized mode. + + + Con&vert mode to RTTY + + + + + + + Some logging programs will not accept the type of reports +saved by this program. +Check this option to save the sent and received reports in the +comments field. + + + d&B reports to comments + + + + + + + Check this option to force the clearing of the DX Call +and DX Grid fields when a 73 or free text message is sent. + + + Clear &DX call and grid after logging + + + + + + + + + + Qt::Horizontal + + + + + + + Network + + + + + + The program can send your station details and all +decoded signals as spots to the http://pskreporter.info web site. +This is used for reverse beacon analysis which is very useful +for assessing propagation and system performance. + + + Enable &PSK Reporter Spotting + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Frequencies + + + Default frequencies and band specific station details setup + + + + + + Working Frequencies + + + + + + Qt::ActionsContextMenu + + + Right click to add or delete frequencies. + + + QAbstractItemView::DragOnly + + + true + + + QAbstractItemView::SelectRows + + + true + + + true + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Station Information + + + + + + Qt::ActionsContextMenu + + + true + + + Items may be edited. +Right click for insert and delete options. + + + true + + + true + + + QAbstractItemView::DragDrop + + + Qt::MoveAction + + + true + + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectRows + + + true + + + true + + + true + + + false + + + + + + + + + + + + + + Discard or apply configuration changes including +resetting the radio interface and applying any +soundcard changes + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + configuration_tabs + callsign_line_edit + grid_line_edit + insert_blank_check_box + miles_check_box + TX_messages_check_box + DXCC_check_box + font_push_button + decoded_text_font_push_button + monitor_off_check_box + quick_call_check_box + disable_TX_on_73_check_box + watchdog_check_box + CW_id_after_73_check_box + CW_id_interval_spin_box + rig_combo_box + CAT_poll_interval_spin_box + CAT_port_combo_box + CAT_serial_baud_combo_box + CAT_7_bit_radio_button + CAT_8_bit_radio_button + CAT_one_stop_bit_radio_button + CAT_two_stop_bit_radio_button + CAT_handshake_none_radio_button + CAT_handshake_xon_radio_button + CAT_handshake_hardware_radio_button + CAT_DTR_check_box + CAT_RTS_check_box + PTT_VOX_radio_button + PTT_DTR_radio_button + PTT_CAT_radio_button + PTT_RTS_radio_button + PTT_port_combo_box + TX_source_data_radio_button + TX_source_mic_radio_button + mode_none_radio_button + mode_USB_radio_button + mode_data_radio_button + split_none_radio_button + split_rig_radio_button + split_emulate_radio_button + test_CAT_push_button + test_PTT_push_button + sound_input_combo_box + sound_input_channel_combo_box + sound_output_combo_box + sound_output_channel_combo_box + save_path_select_push_button + jt9w_bandwidth_mult_combo_box + jt9w_min_dt_double_spin_box + jt9w_max_dt_double_spin_box + add_macro_line_edit + add_macro_push_button + delete_macro_push_button + macros_list_view + prompt_to_log_check_box + log_as_RTTY_check_box + report_in_comments_check_box + clear_DX_check_box + psk_reporter_check_box + frequencies_table_view + stations_table_view + configuration_dialog_button_box + + + + + configuration_dialog_button_box + accepted() + configuration_dialog + accept() + + + 236 + 540 + + + 157 + 274 + + + + + configuration_dialog_button_box + rejected() + configuration_dialog + reject() + + + 304 + 540 + + + 286 + 274 + + + + + add_macro_line_edit + returnPressed() + add_macro_push_button + setFocus() + + + 188 + 62 + + + 406 + 62 + + + + + add_macro_push_button + clicked() + add_macro_line_edit + setFocus() + + + 406 + 62 + + + 188 + 62 + + + + + + + + + + + + + + diff --git a/Copyright.txt b/Copyright.txt new file mode 100644 index 000000000..09cf8de7d --- /dev/null +++ b/Copyright.txt @@ -0,0 +1 @@ +Copyright (C) 2001-2014 by Joe Taylor, K1JT diff --git a/DXLabSuiteCommanderTransceiver.cpp b/DXLabSuiteCommanderTransceiver.cpp new file mode 100644 index 000000000..d118074fd --- /dev/null +++ b/DXLabSuiteCommanderTransceiver.cpp @@ -0,0 +1,377 @@ +#include "DXLabSuiteCommanderTransceiver.hpp" + +#include +#include + +#include "NetworkServerLookup.hpp" + +namespace +{ + char const * const commander_transceiver_name {"DX Lab Suite Commander"}; + int socket_wait_time {5000}; + + QString map_mode (Transceiver::MODE mode) + { + switch (mode) + { + case Transceiver::AM: return "AM"; + case Transceiver::CW: return "CW"; + case Transceiver::CW_R: return "CW-R"; + case Transceiver::USB: return "USB"; + case Transceiver::LSB: return "LSB"; + case Transceiver::FSK: return "RTTY"; + case Transceiver::FSK_R: return "RTTY-R"; + case Transceiver::DIG_L: return "DATA-L"; + case Transceiver::DIG_U: return "DATA-U"; + case Transceiver::FM: + case Transceiver::DIG_FM: + return "FM"; + default: break; + } + return "USB"; + } +} + +void DXLabSuiteCommanderTransceiver::register_transceivers (TransceiverFactory::Transceivers * registry, int id) +{ + (*registry)[commander_transceiver_name] = TransceiverFactory::Capabilities {id, TransceiverFactory::Capabilities::network, true}; +} + +DXLabSuiteCommanderTransceiver::DXLabSuiteCommanderTransceiver (std::unique_ptr wrapped, QString const& address, bool use_for_ptt, int poll_interval) + : PollingTransceiver {poll_interval} + , wrapped_ {std::move (wrapped)} + , use_for_ptt_ {use_for_ptt} + , server_ {address} + , commander_ {nullptr} +{ +} + +DXLabSuiteCommanderTransceiver::~DXLabSuiteCommanderTransceiver () +{ +} + +void DXLabSuiteCommanderTransceiver::do_start () +{ +#if WSJT_TRACE_CAT + qDebug () << "DXLabSuiteCommanderTransceiver::start"; +#endif + + wrapped_->start (); + + auto server_details = network_server_lookup (server_, 52002u, QHostAddress::LocalHost, QAbstractSocket::IPv4Protocol); + + if (!commander_) + { + commander_ = new QTcpSocket {this}; // QObject takes ownership + } + + commander_->connectToHost (std::get<0> (server_details), std::get<1> (server_details)); + if (!commander_->waitForConnected (socket_wait_time)) + { +#if WSJT_TRACE_CAT + qDebug () << "DXLabSuiteCommanderTransceiver::start failed to connect" << commander_->errorString (); +#endif + + throw error {"Failed to connect to DX Lab Suite Commander\n" + commander_->errorString ().toLocal8Bit ()}; + } + + poll (); +} + +void DXLabSuiteCommanderTransceiver::do_stop () +{ + if (commander_) + { + commander_->close (); + delete commander_, commander_ = nullptr; + } + + wrapped_->stop (); + +#if WSJT_TRACE_CAT + qDebug () << "DXLabSuiteCommanderTransceiver::stop"; +#endif +} + +void DXLabSuiteCommanderTransceiver::do_ptt (bool on) +{ +#if WSJT_TRACE_CAT + qDebug () << "DXLabSuiteCommanderTransceiver::do_ptt:" << on << state (); +#endif + + if (use_for_ptt_) + { + send_command (on ? "CmdTX" : "CmdRX"); + } + else + { + wrapped_->ptt (on); + } + + update_PTT (on); +} + +void DXLabSuiteCommanderTransceiver::do_frequency (Frequency f) +{ +#if WSJT_TRACE_CAT + qDebug () << "DXLabSuiteCommanderTransceiver::do_frequency:" << f << state (); +#endif + + // number is localised + // avoid floating point translation errors by adding a small number (0.1Hz) + send_command ("CmdSetFreq" + QString ("%L1").arg (f / 1e3 + 1e-4, 10, 'f', 3).toLocal8Bit ()); + update_rx_frequency (f); +} + +void DXLabSuiteCommanderTransceiver::do_tx_frequency (Frequency tx, bool /* rationalise_mode */) +{ +#if WSJT_TRACE_CAT + qDebug () << "DXLabSuiteCommanderTransceiver::do_tx_frequency:" << tx << state (); +#endif + + if (tx) + { + send_command ("CmdSplit<1:2>on"); + update_split (true); + + // number is localised + // avoid floating point translation errors by adding a small number (0.1Hz) + + // set TX frequency after going split because going split + // rationalises TX VFO mode and that can change the frequency on + // Yaesu rigs if CW is involved + send_command ("CmdSetTxFreq" + QString ("%L1").arg (tx / 1e3 + 1e-4, 10, 'f', 3).toLocal8Bit ()); + } + else + { + send_command ("CmdSplit<1:3>off"); + } + update_other_frequency (tx); +} + +void DXLabSuiteCommanderTransceiver::do_mode (MODE mode, bool /* rationalise */) +{ +#if WSJT_TRACE_CAT + qDebug () << "DXLabSuiteCommanderTransceiver::do_mode:" << mode << state (); +#endif + + auto mapped = map_mode (mode); + send_command ((QString ("CmdSetMode<1:%2>").arg (5 + mapped.size ()).arg (mapped.size ()) + mapped).toLocal8Bit ()); + + if (state ().split ()) + { + // this toggle ensures that the TX VFO mode is the same as the RX VFO + send_command ("CmdSplit<1:3>off"); + send_command ("CmdSplit<1:2>on"); + } + + // setting TX frequency rationalises the mode on Icoms so get current and set + poll (); +} + +void DXLabSuiteCommanderTransceiver::poll () +{ +#if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS + bool quiet {false}; +#else + bool quiet {true}; +#endif + + send_command ("CmdSendFreq", quiet); + auto reply = read_reply (quiet); + if (0 == reply.indexOf ("') + 1).replace (",", "").replace (".", ""); + update_rx_frequency (reply.toUInt ()); + } + else + { +#if WSJT_TRACE_CAT + qDebug () << "DXLabSuiteCommanderTransceiver::poll: get frequency unexpected response"; +#endif + + throw error {"DX Lab Suite Commander didn't respond correctly polling frequency"}; + } + + send_command ("CmdSendTXFreq", quiet); + reply = read_reply (quiet); + if (0 == reply.indexOf ("') + 1).replace (",", "").replace (".", ""); + if ("000" != text) + { + update_other_frequency (text.toUInt ()); + } + } + else + { +#if WSJT_TRACE_CAT + qDebug () << "DXLabSuiteCommanderTransceiver::poll: get tx frequency unexpected response"; +#endif + + throw error {"DX Lab Suite Commander didn't respond correctly polling TX frequency"}; + } + + send_command ("CmdSendSplit", quiet); + reply = read_reply (quiet); + if (0 == reply.indexOf ("') + 1); + if ("ON" == split) + { + update_split (true); + } + else if ("OFF" == split) + { + update_split (false); + } + else + { +#if WSJT_TRACE_CAT + qDebug () << "DXLabSuiteCommanderTransceiver::poll: unexpected split state" << split; +#endif + + throw error {"DX Lab Suite Commander sent an unrecognised split state: " + split}; + } + } + else + { +#if WSJT_TRACE_CAT + qDebug () << "DXLabSuiteCommanderTransceiver::poll: get split mode unexpected response"; +#endif + + throw error {"DX Lab Suite Commander didn't respond correctly polling split status"}; + } + + send_command ("CmdSendMode", quiet); + reply = read_reply (quiet); + if (0 == reply.indexOf ("') + 1); + MODE m {UNK}; + if ("AM" == mode) + { + m = AM; + } + else if ("CW" == mode) + { + m = CW; + } + else if ("CW-R" == mode) + { + m = CW_R; + } + else if ("FM" == mode || "WBFM" == mode) + { + m = FM; + } + else if ("LSB" == mode) + { + m = LSB; + } + else if ("USB" == mode) + { + m = USB; + } + else if ("RTTY" == mode) + { + m = FSK; + } + else if ("RTTY-R" == mode) + { + m = FSK_R; + } + else if ("PKT" == mode || "DATA-L" == mode || "Data-L" == mode) + { + m = DIG_L; + } + else if ("PKT-R" == mode || "DATA-U" == mode || "Data-U" == mode) + { + m = DIG_U; + } + else + { +#if WSJT_TRACE_CAT + qDebug () << "DXLabSuiteCommanderTransceiver::poll: unexpected mode name" << mode; +#endif + + throw error {"DX Lab Suite Commander sent an unrecognised mode: " + mode}; + } + update_mode (m); + } + else + { +#if WSJT_TRACE_CAT + qDebug () << "DXLabSuiteCommanderTransceiver::poll: unexpected response"; +#endif + + throw error {"DX Lab Suite Commander didn't respond correctly polling mode"}; + } +} + +void DXLabSuiteCommanderTransceiver::send_command (QByteArray const& cmd, bool no_debug) +{ + Q_ASSERT (commander_); + + if (!no_debug) + { +#if WSJT_TRACE_CAT + qDebug () << "DXLabSuiteCommanderTransceiver:send_command(" << cmd << ')'; +#endif + } + + if (QTcpSocket::ConnectedState != commander_->state ()) + { +#if WSJT_TRACE_CAT + qDebug () << "DXLabSuiteCommanderTransceiver::send_command failed:" << commander_->errorString (); +#endif + + throw error {"DX Lab Suite Commander send command failed\n" + commander_->errorString ().toLocal8Bit ()}; + } + + commander_->write (cmd); + if (!commander_->waitForBytesWritten (socket_wait_time)) + { +#if WSJT_TRACE_CAT + qDebug () << "DXLabSuiteCommanderTransceiver::send_command failed:" << commander_->errorString (); +#endif + + throw error {"DX Lab Suite Commander send command failed\n" + commander_->errorString ().toLocal8Bit ()}; + } +} + +QByteArray DXLabSuiteCommanderTransceiver::read_reply (bool no_debug) +{ + Q_ASSERT (commander_); + + if (QTcpSocket::ConnectedState != commander_->state ()) + { +#if WSJT_TRACE_CAT + qDebug () << "DXLabSuiteCommanderTransceiver::read_reply failed:" << commander_->errorString (); +#endif + + throw error {"DX Lab Suite Commander read reply failed\n" + commander_->errorString ().toLocal8Bit ()}; + } + + if (!commander_->waitForReadyRead (socket_wait_time)) + { +#if WSJT_TRACE_CAT + qDebug () << "DXLabSuiteCommanderTransceiver::read_reply failed:" << commander_->errorString (); +#endif + + throw error {"DX Lab Suite Commander read reply failed\n" + commander_->errorString ().toLocal8Bit ()}; + } + + auto result = commander_->readAll (); + + if (!no_debug) + { +#if WSJT_TRACE_CAT + qDebug () << "DXLabSuiteCommanderTransceiver:read_reply() ->" << result; +#endif + } + + return result; +} diff --git a/DXLabSuiteCommanderTransceiver.hpp b/DXLabSuiteCommanderTransceiver.hpp new file mode 100644 index 000000000..05dfab74a --- /dev/null +++ b/DXLabSuiteCommanderTransceiver.hpp @@ -0,0 +1,50 @@ +#ifndef DX_LAB_SUITE_COMMANDER_TRANSCEIVER_HPP__ +#define DX_LAB_SUITE_COMMANDER_TRANSCEIVER_HPP__ + +#include + +#include + +#include "TransceiverFactory.hpp" +#include "PollingTransceiver.hpp" + +class QTcpSocket; + +// +// DX Lab Suite Commander Interface +// +// Implemented as a Transceiver decorator because we may want the PTT +// services of another Transceiver type such as the HamlibTransceiver +// which can be enabled by wrapping a HamlibTransceiver instantiated +// as a "Hamlib Dummy" transceiver in the Transceiver factory method. +// +class DXLabSuiteCommanderTransceiver final + : public PollingTransceiver +{ +public: + static void register_transceivers (TransceiverFactory::Transceivers *, int id); + + // takes ownership of wrapped Transceiver + explicit DXLabSuiteCommanderTransceiver (std::unique_ptr wrapped, QString const& address, bool use_for_ptt, int poll_interval); + ~DXLabSuiteCommanderTransceiver (); + +private: + void do_start () override; + void do_stop () override; + void do_frequency (Frequency) override; + void do_tx_frequency (Frequency, bool rationalise_mode) override; + void do_mode (MODE, bool rationalise) override; + void do_ptt (bool on) override; + + void poll () override; + + void send_command (QByteArray const&, bool no_debug = false); + QByteArray read_reply (bool no_debug = false); + + std::unique_ptr wrapped_; + bool use_for_ptt_; + QString server_; + QTcpSocket * commander_; +}; + +#endif diff --git a/Detector.cpp b/Detector.cpp index 7f99a6599..48a251b49 100644 --- a/Detector.cpp +++ b/Detector.cpp @@ -4,6 +4,8 @@ #include #include "commons.h" +#include "moc_Detector.cpp" + extern "C" { void fil4_(qint16*, qint32*, qint16*, qint32*); } diff --git a/Detector.hpp b/Detector.hpp index 6003b7fd8..3004408be 100644 --- a/Detector.hpp +++ b/Detector.hpp @@ -45,7 +45,7 @@ private: Q_SLOT bool reset (); Q_SLOT void close () {AudioDevice::close ();} - Q_SIGNAL void framesWritten (qint64); + Q_SIGNAL void framesWritten (qint64) const; void clear (); // discard buffer contents unsigned secondInPeriod () const; diff --git a/EmulateSplitTransceiver.cpp b/EmulateSplitTransceiver.cpp new file mode 100644 index 000000000..ba0dbc6ee --- /dev/null +++ b/EmulateSplitTransceiver.cpp @@ -0,0 +1,102 @@ +#include "EmulateSplitTransceiver.hpp" + +EmulateSplitTransceiver::EmulateSplitTransceiver (std::unique_ptr wrapped) + : wrapped_ {std::move (wrapped)} + , frequency_ {0, 0} + , tx_ {false} +{ + // Connect update signal of wrapped Transceiver object instance to ours. + connect (wrapped_.get (), &Transceiver::update, this, &EmulateSplitTransceiver::handle_update); + + // Connect failure signal of wrapped Transceiver object to our + // parent failure signal. + connect (wrapped_.get (), &Transceiver::failure, this, &Transceiver::failure); +} + +void EmulateSplitTransceiver::start () noexcept +{ + wrapped_->start (); + wrapped_->tx_frequency (0, false); +} + +void EmulateSplitTransceiver::frequency (Frequency rx) noexcept +{ +#if WSJT_TRACE_CAT + qDebug () << "EmulateSplitTransceiver::frequency:" << rx; +#endif + + // Save frequency parameters. + frequency_[0] = rx; + + // Set active frequency. + wrapped_->frequency (rx); +} + +void EmulateSplitTransceiver::tx_frequency (Frequency tx, bool /* rationalise_mode */) noexcept +{ +#if WSJT_TRACE_CAT + qDebug () << "EmulateSplitTransceiver::tx_frequency:" << tx; +#endif + + // Save frequency parameter. + frequency_[1] = tx; + + // Set active frequency. + wrapped_->frequency (frequency_[(tx_ && frequency_[1]) ? 1 : 0]); +} + +void EmulateSplitTransceiver::ptt (bool on) noexcept +{ +#if WSJT_TRACE_CAT + qDebug () << "EmulateSplitTransceiver::ptt:" << on; +#endif + + // Save TX state for future frequency change requests. + tx_ = on; + + // Switch to other frequency if we have one i.e. client wants split + // operation). + wrapped_->frequency (frequency_[(on && frequency_[1]) ? 1 : 0]); + + // Change TX state. + wrapped_->ptt (on); +} + +void EmulateSplitTransceiver::handle_update (TransceiverState state) +{ +#if WSJT_TRACE_CAT + qDebug () << "EmulateSplitTransceiver::handle_update: from wrapped:" << state; +#endif + + // Change to reflect emulated state, we don't want to report the + // shifted frequency when transmitting. + if (tx_) + { + state.frequency (frequency_[0]); + } + else + { + // Follow the rig if in RX mode. + frequency_[0] = state.frequency (); + } + + // Always report the other frequency as the Tx frequency we will use. + state.tx_frequency (frequency_[1]); + + if (state.split ()) + { + Q_EMIT failure (tr ("Emulated split mode requires rig to in simplex mode")); + } + else + { + // Always emit rigs split state so clients can detect abuse. + state.split (true); + +#if WSJT_TRACE_CAT + qDebug () << "EmulateSplitTransceiver::handle_update: signalling:" << state; +#endif + + // signal emulated state + Q_EMIT update (state); + } +} diff --git a/EmulateSplitTransceiver.hpp b/EmulateSplitTransceiver.hpp new file mode 100644 index 000000000..7f32247e0 --- /dev/null +++ b/EmulateSplitTransceiver.hpp @@ -0,0 +1,52 @@ +#ifndef EMULATE_SPLIT_TRANSCEIVER_HPP__ +#define EMULATE_SPLIT_TRANSCEIVER_HPP__ + +#include + +#include "Transceiver.hpp" + +// +// Emulate Split Transceiver +// +// Helper decorator class that encapsulates the emulation of split TX +// operation. +// +// Responsibilities +// +// Delegates all but setting of other (split) frequency to the +// wrapped Transceiver instance. Also routes failure signals from the +// wrapped Transceiver instance to this instances failure signal. +// +// Intercepts status updates from the wrapped Transceiver instance +// and re-signals it with the emulated status. +// +// Generates a status update signal if the other (split) frequency is +// changed, this is necessary since the wrapped transceiver instance +// never receives other frequency changes. +// +class EmulateSplitTransceiver final + : public Transceiver +{ +public: + // takes ownership of wrapped Transceiver + explicit EmulateSplitTransceiver (std::unique_ptr wrapped); + + void start () noexcept override; + void frequency (Frequency) noexcept override; + void tx_frequency (Frequency, bool rationalise_mode) noexcept override; + void ptt (bool on) noexcept override; + + // forward everything else to wrapped Transceiver + void stop () noexcept override {wrapped_->stop (); Q_EMIT finished ();} + void mode (MODE m, bool /* rationalise */) noexcept override {wrapped_->mode (m, false);} + void sync (bool force_signal) noexcept override {wrapped_->sync (force_signal);} + +private: + void handle_update (TransceiverState); + + std::unique_ptr wrapped_; + Frequency frequency_[2]; // [0] <- RX, [1] <- other + bool tx_; +}; + +#endif diff --git a/ForeignKeyDelegate.cpp b/ForeignKeyDelegate.cpp new file mode 100644 index 000000000..e3c717299 --- /dev/null +++ b/ForeignKeyDelegate.cpp @@ -0,0 +1,77 @@ +#include "ForeignKeyDelegate.hpp" + +#include +#include + +class CandidateKeyFilter final + : public QSortFilterProxyModel +{ +public: + explicit CandidateKeyFilter (QAbstractItemModel const * referencing_model + , QAbstractItemModel * referenced_model + , int referenced_key_column + , int referencing_key_role + , int referenced_key_role) + : QSortFilterProxyModel {nullptr} // ForeignKeyDelegate owns us + , referencing_ {referencing_model} + , referencing_key_role_ {referencing_key_role} + , referenced_key_column_ {referenced_key_column} + , referenced_key_role_ {referenced_key_role} + { + setSourceModel (referenced_model); + } + + void set_active_key (QModelIndex const& index) + { + active_key_ = index; + invalidateFilter (); + } + +protected: + bool filterAcceptsRow (int candidate_row, QModelIndex const& candidate_parent) const override + { + auto candidate_key = sourceModel ()->index (candidate_row, referenced_key_column_, candidate_parent).data (referenced_key_role_); + + // Include the current key. + if (candidate_key == active_key_.data (referencing_key_role_)) + { + return true; + } + + // Filter out any candidates already in the referencing key rows. + return referencing_->match (referencing_->index (0, active_key_.column ()), referencing_key_role_, candidate_key, 1, Qt::MatchExactly).isEmpty (); + } + +private: + QAbstractItemModel const * referencing_; + int referencing_key_role_; + int referenced_key_column_; + int referenced_key_role_; + QModelIndex active_key_; +}; + +ForeignKeyDelegate::ForeignKeyDelegate (QAbstractItemModel const * referencing_model + , QAbstractItemModel * referenced_model + , int referenced_key_column + , QObject * parent + , int referencing_key_role + , int referenced_key_role) + : QStyledItemDelegate {parent} + , candidate_key_filter_ {new CandidateKeyFilter {referencing_model, referenced_model, referenced_key_column, referencing_key_role, referenced_key_role}} +{ +} + +ForeignKeyDelegate::~ForeignKeyDelegate () +{ +} + +QWidget * ForeignKeyDelegate::createEditor (QWidget * parent + , QStyleOptionViewItem const& /* option */ + , QModelIndex const& index) const +{ + auto editor = new QComboBox {parent}; + editor->setFrame (false); + candidate_key_filter_->set_active_key (index); + editor->setModel (candidate_key_filter_.data ()); + return editor; +} diff --git a/ForeignKeyDelegate.hpp b/ForeignKeyDelegate.hpp new file mode 100644 index 000000000..6e6797079 --- /dev/null +++ b/ForeignKeyDelegate.hpp @@ -0,0 +1,34 @@ +#ifndef FOREIGN_KEY_DELEGATE_HPP_ +#define FOREIGN_KEY_DELEGATE_HPP_ + +#include +#include + +class CandidateKeyFilter; + +// +// Class ForeignKeyDelegate +// +// Item delegate for editing a foreign key item in a one or many +// to one relationship. A QComboBox is used as an item delegate +// for the edit role. +// +class ForeignKeyDelegate final + : public QStyledItemDelegate +{ +public: + explicit ForeignKeyDelegate (QAbstractItemModel const * referencing_model + , QAbstractItemModel * referenced_model + , int referenced_key_column = 0 + , QObject * parent = nullptr + , int referencing_key_role = Qt::EditRole + , int referenced_key_role = Qt::EditRole); + ~ForeignKeyDelegate (); + + QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override; + +private: + QScopedPointer candidate_key_filter_; +}; + +#endif diff --git a/FrequencyItemDelegate.cpp b/FrequencyItemDelegate.cpp new file mode 100644 index 000000000..8e9ebd5dc --- /dev/null +++ b/FrequencyItemDelegate.cpp @@ -0,0 +1,36 @@ +#include "FrequencyItemDelegate.hpp" + +#include "Radio.hpp" +#include "FrequencyLineEdit.hpp" +#include "Bands.hpp" + +QString FrequencyItemDelegate::displayText (QVariant const& value, QLocale const& locale) const +{ + auto frequency = value.value (); + auto band_name = bands_->data (bands_->find (frequency)); + return Radio::pretty_frequency_MHz_string (frequency, locale) + " MHz (" + band_name.toString () + ')'; +} + +QWidget * FrequencyItemDelegate::createEditor (QWidget * parent + , QStyleOptionViewItem const& /* option */ + , QModelIndex const& /* index */) const +{ + auto editor = new FrequencyLineEdit {parent}; + editor->setFrame (false); + return editor; +} + + +QString FrequencyDeltaItemDelegate::displayText (QVariant const& value, QLocale const& locale) const +{ + return Radio::pretty_frequency_MHz_string (value.value (), locale) + " MHz"; +} + +QWidget * FrequencyDeltaItemDelegate::createEditor (QWidget * parent + , QStyleOptionViewItem const& /* option */ + , QModelIndex const& /* index */) const +{ + auto editor = new FrequencyDeltaLineEdit {parent}; + editor->setFrame (false); + return editor; +} diff --git a/FrequencyItemDelegate.hpp b/FrequencyItemDelegate.hpp new file mode 100644 index 000000000..5d35a9a0a --- /dev/null +++ b/FrequencyItemDelegate.hpp @@ -0,0 +1,56 @@ +#ifndef FREQUENCY_ITEM_DELEGATE_HPP_ +#define FREQUENCY_ITEM_DELEGATE_HPP_ + +#include + +class QStyleOptionItemView; +class QWidget; +class QModelIndex; +class Bands; + +// +// Class FrequencyItemDelegate +// +// Item delegate for displaying and editing a Frequency item in a +// view that uses a FrequencyLineEdit as an item delegate for the +// edit role. +// +class FrequencyItemDelegate final + : public QStyledItemDelegate +{ +public: + explicit FrequencyItemDelegate (Bands const * bands, QObject * parent = nullptr) + : QStyledItemDelegate {parent} + , bands_ {bands} + { + } + + QString displayText (QVariant const& value, QLocale const&) const override; + QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override; + +private: + Bands const * bands_; +}; + + +// +// Class FrequencyDeltaItemDelegate +// +// Item delegate for displaying and editing a FrequencyDelta item +// in a view that uses a FrequencyDeltaLineEdit as an item +// delegate for the edit role. +// +class FrequencyDeltaItemDelegate final + : public QStyledItemDelegate +{ +public: + explicit FrequencyDeltaItemDelegate (QObject * parent = nullptr) + : QStyledItemDelegate {parent} + { + } + + QString displayText (QVariant const& value, QLocale const&) const override; + QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override; +}; + +#endif diff --git a/FrequencyLineEdit.cpp b/FrequencyLineEdit.cpp new file mode 100644 index 000000000..e37800f8d --- /dev/null +++ b/FrequencyLineEdit.cpp @@ -0,0 +1,40 @@ +#include "FrequencyLineEdit.hpp" + +#include +#include +#include + +#include "moc_FrequencyLineEdit.cpp" + +FrequencyLineEdit::FrequencyLineEdit (QWidget * parent) + : QLineEdit (parent) +{ + setValidator (new QRegExpValidator {QRegExp {R"(\d{0,6}(\.\d{0,6})?)"}, this}); +} + +auto FrequencyLineEdit::frequency () const -> Frequency +{ + return Radio::frequency (text (), 6); +} + +void FrequencyLineEdit::frequency (Frequency f) +{ + setText (Radio::frequency_MHz_string (f)); +} + + +FrequencyDeltaLineEdit::FrequencyDeltaLineEdit (QWidget * parent) + : QLineEdit (parent) +{ + setValidator (new QRegExpValidator {QRegExp {R"(-?\d{0,6}(\.\d{0,6})?)"}, this}); +} + +auto FrequencyDeltaLineEdit::frequency_delta () const -> FrequencyDelta +{ + return Radio::frequency_delta (text (), 6); +} + +void FrequencyDeltaLineEdit::frequency_delta (FrequencyDelta d) +{ + setText (Radio::frequency_MHz_string (d)); +} diff --git a/FrequencyLineEdit.hpp b/FrequencyLineEdit.hpp new file mode 100644 index 000000000..f59a37b07 --- /dev/null +++ b/FrequencyLineEdit.hpp @@ -0,0 +1,45 @@ +#ifndef FREQUENCY_LINE_EDIT_HPP_ +#define FREQUENCY_LINE_EDIT_HPP_ + +#include + +#include "Radio.hpp" + +class QWidget; + +// +// MHz frequency line edits with validation +// +class FrequencyLineEdit final + : public QLineEdit +{ + Q_OBJECT; + Q_PROPERTY (Frequency frequency READ frequency WRITE frequency USER true); + +public: + using Frequency = Radio::Frequency; + + explicit FrequencyLineEdit (QWidget * parent = nullptr); + + // Property frequency implementation + Frequency frequency () const; + void frequency (Frequency); +}; + +class FrequencyDeltaLineEdit final + : public QLineEdit +{ + Q_OBJECT; + Q_PROPERTY (FrequencyDelta frequency_delta READ frequency_delta WRITE frequency_delta USER true); + +public: + using FrequencyDelta = Radio::FrequencyDelta; + + explicit FrequencyDeltaLineEdit (QWidget * parent = nullptr); + + // Property frequency_delta implementation + FrequencyDelta frequency_delta () const; + void frequency_delta (FrequencyDelta); +}; + +#endif diff --git a/FrequencyList.cpp b/FrequencyList.cpp new file mode 100644 index 000000000..b2daf7549 --- /dev/null +++ b/FrequencyList.cpp @@ -0,0 +1,358 @@ +#include "FrequencyList.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pimpl_impl.hpp" + +class FrequencyList::impl final + : public QAbstractTableModel +{ +public: + impl (Frequencies frequencies, QObject * parent) + : QAbstractTableModel {parent} + , frequencies_ {frequencies} + { + } + + Frequencies const& frequencies () const {return frequencies_;} + void assign (Frequencies); + QModelIndex add (Frequency); + +protected: + // Implement the QAbstractTableModel interface + int rowCount (QModelIndex const& parent = QModelIndex {}) const override; + int columnCount (QModelIndex const& parent = QModelIndex {}) const override; + Qt::ItemFlags flags (QModelIndex const& = QModelIndex {}) const override; + QVariant data (QModelIndex const&, int role = Qt::DisplayRole) const override; + bool setData (QModelIndex const&, QVariant const& value, int role = Qt::EditRole) override; + QVariant headerData (int section, Qt::Orientation, int = Qt::DisplayRole) const override; + bool removeRows (int row, int count, QModelIndex const& parent = QModelIndex {}) override; + bool insertRows (int row, int count, QModelIndex const& parent = QModelIndex {}) override; + QStringList mimeTypes () const override; + QMimeData * mimeData (QModelIndexList const&) const override; + +private: + static int constexpr num_cols {2}; + static auto constexpr mime_type ="application/wsjt.Frequencies"; + + Frequencies frequencies_; +}; + +FrequencyList::FrequencyList (QObject * parent) + : FrequencyList {{}, parent} +{ +} + +FrequencyList::FrequencyList (Frequencies frequencies, QObject * parent) + : QSortFilterProxyModel {parent} + , m_ {frequencies, parent} +{ + // setDynamicSortFilter (true); + setSourceModel (&*m_); + setSortRole (SortRole); +} + +FrequencyList::~FrequencyList () +{ +} + +FrequencyList& FrequencyList::operator = (Frequencies frequencies) +{ + m_->assign (frequencies); + return *this; +} + +auto FrequencyList::frequencies () const -> Frequencies +{ + return m_->frequencies (); +} + +QModelIndex FrequencyList::add (Frequency f) +{ + return mapFromSource (m_->add (f)); +} + +bool FrequencyList::remove (Frequency f) +{ + auto row = m_->frequencies ().indexOf (f); + + if (0 > row) + { + return false; + } + + return m_->removeRow (row); +} + +namespace +{ + bool row_is_higher (QModelIndex const& lhs, QModelIndex const& rhs) + { + return lhs.row () > rhs.row (); + } +} + +bool FrequencyList::removeDisjointRows (QModelIndexList rows) +{ + bool result {true}; + + // We must work with source model indexes because we don't want row + // removes to invalidate model indexes we haven't yet processed. We + // achieve that by processing them in decending row order. + for (int r = 0; r < rows.size (); ++r) + { + rows[r] = mapToSource (rows[r]); + } + + // reverse sort by row + qSort (rows.begin (), rows.end (), row_is_higher); + Q_FOREACH (auto index, rows) + { + if (result && !m_->removeRow (index.row ())) + { + result = false; + } + } + + return result; +} + + +void FrequencyList::impl::assign (Frequencies frequencies) +{ + beginResetModel (); + std::swap (frequencies_, frequencies); + endResetModel (); +} + +QModelIndex FrequencyList::impl::add (Frequency f) +{ + // Any Frequency that isn't in the list may be added + if (!frequencies_.contains (f)) + { + auto row = frequencies_.size (); + + beginInsertRows (QModelIndex {}, row, row); + frequencies_.append (f); + endInsertRows (); + + return index (row, 0); + } + + return QModelIndex {}; +} + +int FrequencyList::impl::rowCount (QModelIndex const& parent) const +{ + return parent.isValid () ? 0 : frequencies_.size (); +} + +int FrequencyList::impl::columnCount (QModelIndex const& parent) const +{ + return parent.isValid () ? 0 : num_cols; +} + +Qt::ItemFlags FrequencyList::impl::flags (QModelIndex const& index) const +{ + auto result = QAbstractTableModel::flags (index) | Qt::ItemIsDropEnabled; + + auto row = index.row (); + auto column = index.column (); + + if (index.isValid () + && row < frequencies_.size () + && column < num_cols) + { + switch (column) + { + case 0: + result |= Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; + break; + + case 1: + result |= Qt::ItemIsDragEnabled; + break; + } + } + + return result; +} + +QVariant FrequencyList::impl::data (QModelIndex const& index, int role) const +{ + QVariant item; + + auto row = index.row (); + auto column = index.column (); + + if (index.isValid () + && row < frequencies_.size () + && column < num_cols) + { + auto frequency = frequencies_.at (row); + + switch (column) + { + case 0: + switch (role) + { + case SortRole: + case Qt::DisplayRole: + case Qt::EditRole: + case Qt::AccessibleTextRole: + item = frequency; + break; + + case Qt::ToolTipRole: + case Qt::AccessibleDescriptionRole: + item = tr ("Frequency"); + break; + + case Qt::TextAlignmentRole: + item = Qt::AlignRight + Qt::AlignVCenter; + break; + } + break; + + case 1: + switch (role) + { + case Qt::DisplayRole: + case Qt::EditRole: + case Qt::AccessibleTextRole: + item = static_cast (frequency / 1.e6); + break; + + case SortRole: // use the underlying Frequency value + item = frequency; + break; + + case Qt::ToolTipRole: + case Qt::AccessibleDescriptionRole: + item = tr ("Frequency MHz"); + break; + + case Qt::TextAlignmentRole: + item = Qt::AlignRight + Qt::AlignVCenter; + break; + } + break; + } + } + + return item; +} + +bool FrequencyList::impl::setData (QModelIndex const& model_index, QVariant const& value, int role) +{ + bool changed {false}; + + auto row = model_index.row (); + if (model_index.isValid () + && Qt::EditRole == role + && row < frequencies_.size () + && 0 == model_index.column () + && value.canConvert ()) + { + auto frequency = value.value (); + auto original_frequency = frequencies_.at (row); + if (frequency != original_frequency) + { + frequencies_.replace (row, frequency); + Q_EMIT dataChanged (model_index, index (model_index.row (), 1), QVector {} << role); + } + changed = true; + } + + return changed; +} + +QVariant FrequencyList::impl::headerData (int section, Qt::Orientation orientation, int role) const +{ + QVariant header; + + if (Qt::DisplayRole == role + && Qt::Horizontal == orientation + && section < num_cols) + { + switch (section) + { + case 0: header = tr ("Frequency"); break; + case 1: header = tr ("Frequency (MHz)"); break; + } + } + else + { + header = QAbstractTableModel::headerData (section, orientation, role); + } + + return header; +} + +bool FrequencyList::impl::removeRows (int row, int count, QModelIndex const& parent) +{ + if (0 < count && (row + count) <= rowCount (parent)) + { + beginRemoveRows (parent, row, row + count - 1); + for (auto r = 0; r < count; ++r) + { + frequencies_.removeAt (row); + } + endRemoveRows (); + return true; + } + + return false; +} + +bool FrequencyList::impl::insertRows (int row, int count, QModelIndex const& parent) +{ + if (0 < count) + { + beginInsertRows (parent, row, row + count - 1); + for (auto r = 0; r < count; ++r) + { + frequencies_.insert (row, Frequency {}); + } + endInsertRows (); + return true; + } + + return false; +} + +QStringList FrequencyList::impl::mimeTypes () const +{ + QStringList types; + types << mime_type; + return types; +} + +QMimeData * FrequencyList::impl::mimeData (QModelIndexList const& items) const +{ + QMimeData * mime_data = new QMimeData {}; + QByteArray encoded_data; + QDataStream stream {&encoded_data, QIODevice::WriteOnly}; + + Q_FOREACH (auto const& item, items) + { + if (item.isValid ()) + { + stream << QString {data (item, Qt::DisplayRole).toString ()}; + } + } + + mime_data->setData (mime_type, encoded_data); + return mime_data; +} diff --git a/FrequencyList.hpp b/FrequencyList.hpp new file mode 100644 index 000000000..1ff7427d7 --- /dev/null +++ b/FrequencyList.hpp @@ -0,0 +1,59 @@ +#ifndef FREQUENCY_LIST_HPP__ +#define FREQUENCY_LIST_HPP__ + +#include "pimpl_h.hpp" + +#include + +#include "Radio.hpp" + +// +// Class FrequencyList +// +// Encapsulates a collection of frequencies. The implementation is a +// table containing the list of Frequency type elements which is +// editable and a second column which is an immutable double +// representation of the corresponding Frequency item scaled to +// mega-Hertz. +// +// The list is ordered. +// +// Responsibilities +// +// Stores internally a list of unique frequencies. Provides methods +// to add and delete list elements. +// +// Collaborations +// +// Implements the QSortFilterProxyModel interface for a list of spot +// frequencies. +// +class FrequencyList final + : public QSortFilterProxyModel +{ +public: + using Frequency = Radio::Frequency; + using Frequencies = Radio::Frequencies; + + explicit FrequencyList (QObject * parent = nullptr); + explicit FrequencyList (Frequencies, QObject * parent = nullptr); + ~FrequencyList (); + + // Load and store contents + FrequencyList& operator = (Frequencies); + Frequencies frequencies () const; + + // Model API + QModelIndex add (Frequency); + bool remove (Frequency); + bool removeDisjointRows (QModelIndexList); + + // Custom roles. + static int constexpr SortRole = Qt::UserRole; + +private: + class impl; + pimpl m_; +}; + +#endif diff --git a/GetUserId.cpp b/GetUserId.cpp new file mode 100644 index 000000000..238c3b5a9 --- /dev/null +++ b/GetUserId.cpp @@ -0,0 +1,75 @@ +#include "GetUserId.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Dialog to get callsign +// +class CallsignDialog final + : public QDialog +{ + Q_OBJECT; + +private: + Q_DISABLE_COPY (CallsignDialog); + +public: + explicit CallsignDialog (QWidget * parent = nullptr) + : QDialog {parent} + { + setWindowTitle (QApplication::applicationName () + " - " + tr ("Callsign")); + + callsign_.setValidator (new QRegExpValidator {QRegExp {"[A-Za-z0-9]+"}, this}); + + auto form_layout = new QFormLayout (); + form_layout->addRow ("&Callsign:", &callsign_); + + auto main_layout = new QVBoxLayout (this); + main_layout->addLayout (form_layout); + + auto button_box = new QDialogButtonBox {QDialogButtonBox::Ok | QDialogButtonBox::Cancel}; + main_layout->addWidget (button_box); + + connect (button_box, &QDialogButtonBox::accepted, this, &CallsignDialog::accept); + connect (button_box, &QDialogButtonBox::rejected, this, &CallsignDialog::reject); + } + + QString callsign () const {return callsign_.text ();} + +private: + QLineEdit callsign_; +}; + +#include "GetUserId.moc" + +QString get_user_id () +{ + // get the users callsign so we can use it to persist the + // settings and log file against a unique tag + QString id; + { + CallsignDialog dialog; + while (id.isEmpty ()) + { + if (QDialog::Accepted == dialog.exec ()) + { + id = dialog.callsign ().toUpper (); + } + else + { + throw std::runtime_error ("Callsign required"); + } + } + } + + return id; +} diff --git a/GetUserId.hpp b/GetUserId.hpp new file mode 100644 index 000000000..205042f98 --- /dev/null +++ b/GetUserId.hpp @@ -0,0 +1,8 @@ +#ifndef GETUSERID_HPP_ +#define GETUSERID_HPP_ + +#include + +QString get_user_id (); + +#endif diff --git a/HRDTransceiver.cpp b/HRDTransceiver.cpp new file mode 100644 index 000000000..0ddf5aa15 --- /dev/null +++ b/HRDTransceiver.cpp @@ -0,0 +1,766 @@ +#include "HRDTransceiver.hpp" + +#include +#include +#include +#include +#include + +#include "NetworkServerLookup.hpp" + +namespace +{ + char const * const HRD_transceiver_name = "Ham Radio Deluxe"; + int socket_wait_time {5000}; +} + +void HRDTransceiver::register_transceivers (TransceiverFactory::Transceivers * registry, int id) +{ + (*registry)[HRD_transceiver_name] = TransceiverFactory::Capabilities (id, TransceiverFactory::Capabilities::network, "localhost:7809", true); +} + +struct HRDMessage +{ + // placement style new overload for outgoing messages that does the construction too + static void * operator new (size_t size, QString const& payload) + { + size += sizeof (QChar) * (payload.size () + 1); // space for terminator too + HRDMessage * storage (reinterpret_cast (new char[size])); + storage->size_ = size ; + ushort const * pl (payload.utf16 ()); + qCopy (pl, pl + payload.size () + 1, storage->payload_); // copy terminator too + storage->magic_1_ = magic_1_value_; + storage->magic_2_ = magic_2_value_; + storage->checksum_ = 0; + return storage; + } + + // placement style new overload for incoming messages that does the construction too + // + // no memory allocation here + static void * operator new (size_t /* size */, QByteArray const& message) + { + // nasty const_cast here to avoid copying the message buffer + return const_cast (reinterpret_cast (message.data ())); + } + + void operator delete (void * p, size_t) + { + delete [] reinterpret_cast (p); // mirror allocation in operator new above + } + + qint32 size_; + qint32 magic_1_; + qint32 magic_2_; + qint32 checksum_; // apparently not used + QChar payload_[0]; // UTF-16 (which is wchar_t on Windows) + + static qint32 const magic_1_value_; + static qint32 const magic_2_value_; +}; + +qint32 const HRDMessage::magic_1_value_ (0x1234ABCD); +qint32 const HRDMessage::magic_2_value_ (0xABCD1234); + +HRDTransceiver::HRDTransceiver (std::unique_ptr wrapped, QString const& server, bool use_for_ptt, int poll_interval) + : PollingTransceiver {poll_interval} + , wrapped_ {std::move (wrapped)} + , use_for_ptt_ {use_for_ptt} + , server_ {server} + , hrd_ {0} + , protocol_ {none} + , current_radio_ {0} + , vfo_count_ {0} + , vfo_A_button_ {-1} + , vfo_B_button_ {-1} + , vfo_toggle_button_ {-1} + , mode_A_dropdown_ {-1} + , mode_B_dropdown_ {-1} + , split_mode_button_ {-1} + , split_mode_dropdown_ {-1} + , split_mode_dropdown_write_only_ {false} + , split_mode_dropdown_selection_on_ {-1} + , split_mode_dropdown_selection_off_ {-1} + , split_off_button_ {-1} + , tx_A_button_ {-1} + , tx_B_button_ {-1} + , ptt_button_ {-1} + , reversed_ {false} +{ +} + +HRDTransceiver::~HRDTransceiver () +{ +} + +void HRDTransceiver::do_start () +{ +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::start"; +#endif + + wrapped_->start (); + + auto server_details = network_server_lookup (server_, 7809u); + + if (!hrd_) + { + hrd_ = new QTcpSocket {this}; // QObject takes ownership + } + + hrd_->connectToHost (std::get<0> (server_details), std::get<1> (server_details)); + if (!hrd_->waitForConnected (socket_wait_time)) + { +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::start failed to connect:" << hrd_->errorString (); +#endif + + throw error {"Failed to connect to Ham Radio Deluxe\n" + hrd_->errorString ().toLocal8Bit ()}; + } + + init_radio (); +} + +void HRDTransceiver::do_stop () +{ + if (hrd_) + { + hrd_->close (); + } + + if (wrapped_) + { + wrapped_->stop (); + } + +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::stop: state:" << state () << "reversed =" << reversed_; +#endif +} + +void HRDTransceiver::init_radio () +{ + Q_ASSERT (hrd_); + + if (none == protocol_) + { + try + { + protocol_ = v5; // try this first (works for v6 too) + send_command ("get context", false, false); + } + catch (error const&) + { + protocol_ = none; + } + } + + if (none == protocol_) + { + hrd_->close (); + + protocol_ = v4; // try again with older protocol + hrd_->connectToHost (QHostAddress::LocalHost, 7809); + if (!hrd_->waitForConnected (socket_wait_time)) + { +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::init_radio failed to connect:" << hrd_->errorString (); +#endif + + throw error {"Failed to connect to Ham Radio Deluxe\n" + hrd_->errorString ().toLocal8Bit ()}; + } + + send_command ("get context", false, false); + } + +#if WSJT_TRACE_CAT + qDebug () << send_command ("get id", false, false); + qDebug () << send_command ("get version", false, false); +#endif + + auto radios = send_command ("get radios", false, false).trimmed ().split (',', QString::SkipEmptyParts); + if (radios.isEmpty ()) + { +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::init_radio no rig found"; +#endif + + throw error {"Ham Radio Deluxe: no rig found"}; + } + + Q_FOREACH (auto const& radio, radios) + { + auto entries = radio.trimmed ().split (':', QString::SkipEmptyParts); + radios_.push_back (std::forward_as_tuple (entries[0].toUInt (), entries[1])); + } + +#if WSJT_TRACE_CAT + qDebug () << "radios:"; + Q_FOREACH (auto const& radio, radios_) + { + qDebug () << "\t[" << std::get<0> (radio) << "] " << std::get<1> (radio); + } +#endif + + if (send_command ("get radio", false, false, true).isEmpty ()) + { +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::init_radio no rig found"; +#endif + + throw error {"Ham Radio Deluxe: no rig found"}; + } + + vfo_count_ = send_command ("get vfo-count").toUInt (); + +#if WSJT_TRACE_CAT + qDebug () << "vfo count:" << vfo_count_; +#endif + + buttons_ = send_command ("get buttons").trimmed ().split (',', QString::SkipEmptyParts).replaceInStrings (" ", "~"); + +#if WSJT_TRACE_CAT + qDebug () << "HRD Buttons: " << buttons_; +#endif + + dropdown_names_ = send_command ("get dropdowns").trimmed ().split (',', QString::SkipEmptyParts); + Q_FOREACH (auto d, dropdown_names_) + { + dropdowns_[d] = send_command ("get dropdown-list {" + d + "}").trimmed ().split (',', QString::SkipEmptyParts); + } + +#if WSJT_TRACE_CAT + qDebug () << "HRD Dropdowns: " << dropdowns_; +#endif + + vfo_A_button_ = find_button (QRegExp ("^(VFO~A|Main)$")); + vfo_B_button_ = find_button (QRegExp ("^(VFO~B|Sub)$")); + vfo_toggle_button_ = find_button (QRegExp ("^(A~/~B)$")); + Q_ASSERT (vfo_toggle_button_ >= 0 || (vfo_A_button_ >= 0 && vfo_B_button_ >=0)); + + split_mode_button_ = find_button (QRegExp ("^(Spl~On|Spl_On|Split)$")); + split_off_button_ = find_button (QRegExp ("^(Spl~Off|Spl_Off)$")); + + if ((split_mode_dropdown_ = find_dropdown (QRegExp ("^(Split)$"))) >= 0) + { + split_mode_dropdown_selection_on_ = find_dropdown_selection (split_mode_dropdown_, QRegExp ("^(On)$")); + split_mode_dropdown_selection_off_ = find_dropdown_selection (split_mode_dropdown_, QRegExp ("^(Off)$")); + } + + tx_A_button_ = find_button (QRegExp ("^(TX~main|TX~-~A)$")); + tx_B_button_ = find_button (QRegExp ("^(TX~sub|TX~-~B)$")); + + Q_ASSERT (split_mode_button_ >= 0 || split_mode_dropdown_ >= 0 || (tx_A_button_ >= 0 && tx_B_button_ >= 0)); + + mode_A_dropdown_ = find_dropdown (QRegExp ("^(Main Mode|Mode)$")); + map_modes (mode_A_dropdown_, &mode_A_map_); + + if ((mode_B_dropdown_ = find_dropdown (QRegExp ("^(Sub Mode)$"))) >= 0) + { + map_modes (mode_B_dropdown_, &mode_B_map_); + } + + ptt_button_ = find_button (QRegExp ("^(TX)$")); + + sync_impl (); +} + +void HRDTransceiver::sync_impl () +{ + if (vfo_count_ == 1) + { + // put the rig into a known state + auto f = send_command ("get frequency").toUInt (); + auto m = lookup_mode (get_dropdown (mode_A_dropdown_), mode_A_map_); + set_button (vfo_B_button_ >= 0 ? vfo_B_button_ : vfo_toggle_button_); + auto fo = send_command ("get frequency").toUInt (); + update_other_frequency (fo); + auto mo = lookup_mode (get_dropdown (mode_A_dropdown_), mode_A_map_); + set_button (vfo_A_button_ >= 0 ? vfo_A_button_ : vfo_toggle_button_); + if (f != fo || m != mo) + { + // we must have started with A/MAIN + update_rx_frequency (f); + update_mode (m); + } + else + { + update_rx_frequency (send_command ("get frequency").toUInt ()); + update_mode (lookup_mode (get_dropdown (mode_A_dropdown_), mode_A_map_)); + } + } + + poll (); +} + +int HRDTransceiver::find_button (QRegExp const& re) const +{ + return buttons_.indexOf (re); +} + +int HRDTransceiver::find_dropdown (QRegExp const& re) const +{ + return dropdown_names_.indexOf (re); +} + +int HRDTransceiver::find_dropdown_selection (int dropdown, QRegExp const& re) const +{ + return dropdowns_.value (dropdown_names_.value (dropdown)).lastIndexOf (re); // backwards because more specialised modes tend to be later in list +} + +int HRDTransceiver::lookup_dropdown_selection (int dropdown, QString const& selection) const +{ + int index {dropdowns_.value (dropdown_names_.value (dropdown)).indexOf (selection)}; + Q_ASSERT (-1 != index); + return index; +} + +void HRDTransceiver::map_modes (int dropdown, ModeMap *map) +{ + // order matters here (both in the map and in the regexps) + map->push_back (std::forward_as_tuple (CW, find_dropdown_selection (dropdown, QRegExp ("^(CW|CW\\(N\\))$")))); + map->push_back (std::forward_as_tuple (CW_R, find_dropdown_selection (dropdown, QRegExp ("^(CW-R|CW)$")))); + map->push_back (std::forward_as_tuple (LSB, find_dropdown_selection (dropdown, QRegExp ("^(LSB)$")))); + map->push_back (std::forward_as_tuple (USB, find_dropdown_selection (dropdown, QRegExp ("^(USB)$")))); + map->push_back (std::forward_as_tuple (DIG_U, find_dropdown_selection (dropdown, QRegExp ("^(DIG|PKT-U|USB)$")))); + map->push_back (std::forward_as_tuple (DIG_L, find_dropdown_selection (dropdown, QRegExp ("^(DIG|PKT-L|LSB)$")))); + map->push_back (std::forward_as_tuple (FSK, find_dropdown_selection (dropdown, QRegExp ("^(DIG|FSK|RTTY)$")))); + map->push_back (std::forward_as_tuple (FSK_R, find_dropdown_selection (dropdown, QRegExp ("^(DIG|FSK-R|RTTY-R|RTTY)$")))); + map->push_back (std::forward_as_tuple (AM, find_dropdown_selection (dropdown, QRegExp ("^(AM)$")))); + map->push_back (std::forward_as_tuple (FM, find_dropdown_selection (dropdown, QRegExp ("^(FM|FM\\(N\\)|WFM)$")))); + map->push_back (std::forward_as_tuple (DIG_FM, find_dropdown_selection (dropdown, QRegExp ("^(PKT-FM|PKT|FM)$")))); + +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::map_modes: for dropdown" << dropdown_names_[dropdown]; + + std::for_each (map->begin (), map->end (), [this, dropdown] (ModeMap::value_type const& item) + { + auto rhs = std::get<1> (item); + qDebug () << '\t' << std::get<0> (item) << "<->" << (rhs >= 0 ? dropdowns_[dropdown_names_[dropdown]][rhs] : "None"); + }); +#endif +} + +int HRDTransceiver::lookup_mode (MODE mode, ModeMap const& map) const +{ + auto it = std::find_if (map.begin (), map.end (), [mode] (ModeMap::value_type const& item) {return std::get<0> (item) == mode;}); + if (map.end () == it) + { + throw error {"Ham Radio Deluxe: rig doesn't support mode"}; + } + return std::get<1> (*it); +} + +auto HRDTransceiver::lookup_mode (int mode, ModeMap const& map) const -> MODE +{ + auto it = std::find_if (map.begin (), map.end (), [mode] (ModeMap::value_type const& item) {return std::get<1> (item) == mode;}); + if (map.end () == it) + { + throw error {"Ham Radio Deluxe: sent an unrecognised mode"}; + } + return std::get<0> (*it); +} + +int HRDTransceiver::get_dropdown (int dd, bool no_debug) +{ + auto dd_name = dropdown_names_.value (dd); + auto reply = send_command ("get dropdown-text {" + dd_name + "}", no_debug); + auto colon_index = reply.indexOf (':'); + + if (colon_index < 0) + { + +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::get_dropdown bad response"; +#endif + + throw error {"Ham Radio Deluxe didn't respond as expected"}; + } + + Q_ASSERT (reply.left (colon_index).trimmed () == dd_name); + return lookup_dropdown_selection (dd, reply.mid (colon_index + 1).trimmed ()); +} + +void HRDTransceiver::set_dropdown (int dd, int value) +{ + auto dd_name = dropdown_names_.value (dd); + if (value >= 0) + { + send_simple_command ("set dropdown " + dd_name.replace (' ', '~') + ' ' + dropdowns_.value (dd_name).value (value) + ' ' + QString::number (value)); + } + else + { +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::set_dropdown item" << value << "not found in" << dd_name; +#endif + + throw error {("Ham Radio Deluxe: item not found in " + dd_name + " dropdown list").toLocal8Bit ()}; + } +} + +void HRDTransceiver::do_ptt (bool on) +{ +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::do_ptt:" << on; +#endif + + if (use_for_ptt_) + { + set_button (ptt_button_, on); + } + else + { + wrapped_->ptt (on); + } + update_PTT (on); +} + +void HRDTransceiver::set_button (int button_index, bool checked) +{ + if (button_index >= 0) + { + send_simple_command ("set button-select " + buttons_.value (button_index) + (checked ? " 1" : " 0")); + } + else + { +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::set_button invalid button"; +#endif + + throw error {"Ham Radio Deluxe: button not available"}; + } +} + +void HRDTransceiver::do_frequency (Frequency f) +{ +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::do_frequency:" << f << "reversed:" << reversed_; +#endif + + send_simple_command ("set frequency-hz " + QString::number (f)); + update_rx_frequency (f); +} + +void HRDTransceiver::do_tx_frequency (Frequency tx, bool rationalise_mode) +{ +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::do_tx_frequency:" << tx << "reversed:" << reversed_; +#endif + + bool split {tx != 0}; + + if (vfo_count_ > 1) + { + reversed_ = is_button_checked (vfo_B_button_); + } + + if (split) + { + auto fo_string = QString::number (tx); + if (reversed_) + { + Q_ASSERT (vfo_count_ > 1); + + auto frequencies = send_command ("get frequencies").trimmed ().split ('-', QString::SkipEmptyParts); + send_simple_command ("set frequencies-hz " + fo_string + ' ' + QString::number (frequencies[1].toUInt ())); + } + else + { + if (vfo_count_ > 1) + { + auto frequencies = send_command ("get frequencies").trimmed ().split ('-', QString::SkipEmptyParts); + send_simple_command ("set frequencies-hz " + QString::number (frequencies[0].toUInt ()) + ' ' + fo_string); + } + else + { + // we rationalise the modes and VFOs here as well as the frequencies + set_button (vfo_B_button_ >= 0 ? vfo_B_button_ : vfo_toggle_button_); + send_simple_command ("set frequency-hz " + fo_string); + if (rationalise_mode) + { + set_dropdown (mode_B_dropdown_ >= 0 ? mode_B_dropdown_ : mode_A_dropdown_, lookup_mode (state ().mode (), mode_B_dropdown_ >= 0 ? mode_B_map_ : mode_A_map_)); + } + set_button (vfo_A_button_ >= 0 ? vfo_A_button_ : vfo_toggle_button_); + } + } + if (rationalise_mode) + { + set_dropdown (mode_B_dropdown_ >= 0 ? mode_B_dropdown_ : mode_A_dropdown_, lookup_mode (state ().mode (), mode_B_dropdown_ >= 0 ? mode_B_map_ : mode_A_map_)); + } + } + update_other_frequency (tx); + + if (split_mode_button_ >= 0) + { + if (split_off_button_ >= 0 && !split) + { + set_button (split_off_button_); + } + else + { + set_button (split_mode_button_, split); + } + } + else if (split_mode_dropdown_ >= 0) + { + set_dropdown (split_mode_dropdown_, split ? split_mode_dropdown_selection_on_ : split_mode_dropdown_selection_off_); + } + else if (vfo_A_button_ >= 0 && vfo_B_button_ >= 0 && tx_A_button_ >= 0 && tx_B_button_ >= 0) + { + if (split) + { + if (reversed_ != is_button_checked (tx_A_button_)) + { + set_button (reversed_ ? tx_A_button_ : tx_B_button_); + } + } + else + { + if (reversed_ != is_button_checked (tx_B_button_)) + { + set_button (reversed_ ? tx_B_button_ : tx_A_button_); + } + } + } + update_split (split); +} + +void HRDTransceiver::do_mode (MODE mode, bool rationalise) +{ +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::do_mode:" << mode; +#endif + + set_dropdown (mode_A_dropdown_, lookup_mode (mode, mode_A_map_)); + + if (rationalise && state ().split ()) // rationalise mode if split + { + if (mode_B_dropdown_ >= 0) + { + set_dropdown (mode_B_dropdown_, lookup_mode (mode, mode_B_map_)); + } + else if (vfo_count_ < 2) + { + set_button (vfo_B_button_ >= 0 ? vfo_B_button_ : vfo_toggle_button_); + set_dropdown (mode_B_dropdown_ >= 0 ? mode_B_dropdown_ : mode_A_dropdown_, lookup_mode (mode, mode_B_dropdown_ >= 0 ? mode_B_map_ : mode_A_map_)); + set_button (vfo_A_button_ >= 0 ? vfo_A_button_ : vfo_toggle_button_); + } + } + + update_mode (mode); +} + +bool HRDTransceiver::is_button_checked (int button_index, bool no_debug) +{ + auto reply = send_command ("get button-select " + buttons_.value (button_index), no_debug); + if ("1" != reply && "0" != reply) + { +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::is_button_checked bad response"; +#endif + + throw error {"Ham Radio Deluxe didn't respond as expected"}; + } + return "1" == reply; +} + +void HRDTransceiver::poll () +{ +#if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS + bool quiet {false}; +#else + bool quiet {true}; +#endif + + if (split_off_button_ >= 0) + { + // we are probably dealing with an Icom and have to guess SPLIT mode :( + } + else if (split_mode_button_ >= 0) + { + update_split (is_button_checked (split_mode_button_, quiet)); + } + else if (split_mode_dropdown_ >= 0) + { + if (!split_mode_dropdown_write_only_) + { + try + { + update_split (get_dropdown (split_mode_dropdown_, quiet) == split_mode_dropdown_selection_on_); + } + catch (error const&) + { + // leave split alone as we can't query it - it should be + // correct so long as rig or HRD haven't been changed + split_mode_dropdown_write_only_ = true; + } + } + } + else if (vfo_A_button_ >= 0 && vfo_B_button_ >= 0 && tx_A_button_ >= 0 && tx_B_button_ >= 0) + { + auto vfo_A = is_button_checked (vfo_A_button_, quiet); + auto tx_A = is_button_checked (tx_A_button_, quiet); + + update_split (vfo_A != tx_A); + reversed_ = !vfo_A; + } + + if (vfo_count_ > 1) + { + auto frequencies = send_command ("get frequencies", quiet).trimmed ().split ('-', QString::SkipEmptyParts); + update_rx_frequency (frequencies[reversed_ ? 1 : 0].toUInt ()); + update_other_frequency (frequencies[reversed_ ? 0 : 1].toUInt ()); + } + else + { + update_rx_frequency (send_command ("get frequency", quiet).toUInt ()); + } + + update_mode (lookup_mode (get_dropdown (mode_A_dropdown_, quiet), mode_A_map_)); +} + +QString HRDTransceiver::send_command (QString const& cmd, bool no_debug, bool prepend_context, bool recurse) +{ + Q_ASSERT (hrd_); + + QString result; + + if (current_radio_ && prepend_context && vfo_count_ < 2) + { + // TODO G4WJS: get rid of this or move to a thread required on some + // radios because commands don't get executed correctly (ICOM for + // example) + QThread::msleep (50); + } + + if (QTcpSocket::ConnectedState != hrd_->state ()) + { +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::send_command connection failed:" << hrd_->errorString (); +#endif + + throw error {"Ham Radio Deluxe connection failed\n" + hrd_->errorString ().toLocal8Bit ()}; + } + + if (!recurse && prepend_context) + { + auto radio_name = send_command ("get radio", no_debug, current_radio_, true); + auto radio_iter = std::find_if (radios_.begin (), radios_.end (), [this, &radio_name] (RadioMap::value_type const& radio) + { + return std::get<1> (radio) == radio_name; + }); + if (radio_iter == radios_.end ()) + { +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::send_command rig disappeared or changed"; +#endif + + throw error {"Ham Radio Deluxe: rig has disappeared or changed"}; + } + + if (0u == current_radio_ || std::get<0> (*radio_iter) != current_radio_) + { + current_radio_ = std::get<0> (*radio_iter); + } + } + + auto context = '[' + QString::number (current_radio_) + "] "; + + int bytes_to_send; + int bytes_sent; + if (v4 == protocol_) + { + auto message = ((prepend_context ? context + cmd : cmd) + "\r").toLocal8Bit (); + bytes_to_send = message.size (); + bytes_sent = hrd_->write (message.data (), bytes_to_send); + + if (!no_debug) + { +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::send_command:" << message; +#endif + } + } + else + { + auto string = prepend_context ? context + cmd : cmd; + if (!no_debug) + { +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::send_command:" << string; +#endif + } + + QScopedPointer message (new (string) HRDMessage); + bytes_to_send = message->size_; + bytes_sent = hrd_->write (reinterpret_cast (message.data ()), bytes_to_send); + } + + if (bytes_sent < bytes_to_send + || !hrd_->waitForBytesWritten (socket_wait_time) + || QTcpSocket::ConnectedState != hrd_->state ()) + { +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::send_command failed" << hrd_->errorString (); +#endif + + throw error {"Ham Radio Deluxe send command failed\n" + hrd_->errorString ().toLocal8Bit ()}; + } + + if (!hrd_->waitForReadyRead (socket_wait_time)) + { +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::send_command failed to reply" << hrd_->errorString (); +#endif + + throw error {"Ham Radio Deluxe failed to reply to command\n" + hrd_->errorString ().toLocal8Bit ()}; + } + QByteArray buffer (hrd_->readAll ()); + if (!no_debug) + { +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::send_command: reply byte count:" << buffer.size (); +#endif + } + + if (v4 == protocol_) + { + result = QString {buffer}.trimmed (); + } + else + { + HRDMessage const * reply (new (buffer) HRDMessage); + + if (reply->magic_1_value_ != reply->magic_1_ && reply->magic_2_value_ != reply->magic_2_) + { +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::send_command invalid reply"; +#endif + + throw error {"Ham Radio Deluxe sent an invalid reply to our command"}; + } + + result = QString {reply->payload_}; // this is not a memory leak (honest!) + } + + if (!no_debug) + { +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::send_command: reply: " << result; +#endif + } + + return result; +} + +void HRDTransceiver::send_simple_command (QString const& command, bool no_debug) +{ + if ("OK" != send_command (command, no_debug)) + { +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::send_simple_command unexpected response"; +#endif + + throw error {"Ham Radio Deluxe didn't respond as expected"}; + } +} diff --git a/HRDTransceiver.hpp b/HRDTransceiver.hpp new file mode 100644 index 000000000..7eae74eb1 --- /dev/null +++ b/HRDTransceiver.hpp @@ -0,0 +1,95 @@ +#ifndef HRD_TRANSCEIVER_HPP__ +#define HRD_TRANSCEIVER_HPP__ + +#include +#include +#include + +#include +#include +#include + +#include "TransceiverFactory.hpp" +#include "PollingTransceiver.hpp" + +class QRegExp; +class QTcpSocket; + +// +// Ham Radio Deluxe Transceiver Interface +// +// Implemented as a Transceiver decorator because we may want the PTT +// services of another Transceiver type such as the HamlibTransceiver +// which can be enabled by wrapping a HamlibTransceiver instantiated +// as a "Hamlib Dummy" transceiver in the Transceiver factory method. +// +class HRDTransceiver final + : public PollingTransceiver +{ +public: + static void register_transceivers (TransceiverFactory::Transceivers *, int id); + + // takes ownership of wrapped Transceiver + explicit HRDTransceiver (std::unique_ptr wrapped, QString const& server, bool use_for_ptt, int poll_interval); + ~HRDTransceiver (); + +private: + void do_start () override; + void do_stop () override; + void do_frequency (Frequency) override; + void do_tx_frequency (Frequency, bool rationalise_mode) override; + void do_mode (MODE, bool rationalise) override; + void do_ptt (bool on) override; + + void poll () override; + + void init_radio (); + QString send_command (QString const&, bool no_debug = false, bool prepend_context = true, bool recurse = false); + void send_simple_command (QString const&, bool no_debug = false); + void sync_impl (); + int find_button (QRegExp const&) const; + int find_dropdown (QRegExp const&) const; + int find_dropdown_selection (int dropdown, QRegExp const&) const; + int lookup_dropdown_selection (int dropdown, QString const&) const; + int get_dropdown (int, bool no_debug = false); + void set_dropdown (int, int); + void set_button (int button_index, bool checked = true); + bool is_button_checked (int button_index, bool no_debug = false); + + using ModeMap = std::vector >; + void map_modes (int dropdown, ModeMap *); + int lookup_mode (MODE, ModeMap const&) const; + MODE lookup_mode (int, ModeMap const&) const; + + std::unique_ptr wrapped_; + bool use_for_ptt_; + QString server_; + QTcpSocket * hrd_; + enum {none, v4, v5} protocol_; + using RadioMap = std::vector >; + RadioMap radios_; + unsigned current_radio_; + unsigned vfo_count_; + QStringList buttons_; + QStringList dropdown_names_; + QMap dropdowns_; + int vfo_A_button_; + int vfo_B_button_; + int vfo_toggle_button_; + int mode_A_dropdown_; + ModeMap mode_A_map_; + int mode_B_dropdown_; + ModeMap mode_B_map_; + int split_mode_button_; + int split_mode_dropdown_; + bool split_mode_dropdown_write_only_; + int split_mode_dropdown_selection_on_; + int split_mode_dropdown_selection_off_; + int split_off_button_; + int tx_A_button_; + int tx_B_button_; + int ptt_button_; + bool reversed_; +}; + +#endif diff --git a/HamlibTransceiver.cpp b/HamlibTransceiver.cpp new file mode 100644 index 000000000..ddfbd811a --- /dev/null +++ b/HamlibTransceiver.cpp @@ -0,0 +1,845 @@ +#include "HamlibTransceiver.hpp" + +#include + +#include +#include +#include + +namespace +{ + // Unfortunately bandwidth is conflated with mode, this is probably + // because Icom do the same. So we have to care about bandwidth if + // we want to set mode otherwise we will end up setting unwanted + // bandwidths every time we change mode. The best we can do via the + // Hamlib API is to request the normal option for the mode and hope + // that an appropriate filter is selected. Also ensure that mode is + // only set is absolutely necessary. On Icoms (and probably others) + // the filter is selected by number without checking the actual BW + // so unless the "normal" defaults are set on the rig we won't get + // desirable results. + // + // As an ultimate workaround make sure the user always has the + // option to skip mode setting altogether. + + // reroute Hamlib diagnostic messages to Qt + int debug_callback (enum rig_debug_level_e level, rig_ptr_t /* arg */, char const * format, va_list ap) + { + QString message; + message = message.vsprintf (format, ap).trimmed (); + + switch (level) + { + case RIG_DEBUG_BUG: + qFatal ("%s", message.toLocal8Bit ().data ()); + break; + + case RIG_DEBUG_ERR: + qCritical ("%s", message.toLocal8Bit ().data ()); + break; + + case RIG_DEBUG_WARN: + qWarning ("%s", message.toLocal8Bit ().data ()); + break; + + default: + qDebug ("%s", message.toLocal8Bit ().data ()); + break; + } + + return 0; + } + + // callback function that receives transceiver capabilities from the + // hamlib libraries + int rigCallback (rig_caps const * caps, void * callback_data) + { + TransceiverFactory::Transceivers * rigs = reinterpret_cast (callback_data); + + QString key; + if ("Hamlib" == QString::fromLatin1 (caps->mfg_name).trimmed () + && "Dummy" == QString::fromLatin1 (caps->model_name).trimmed ()) + { + key = TransceiverFactory::basic_transceiver_name_; + } + else + { + key = QString::fromLatin1 (caps->mfg_name).trimmed () + + ' '+ QString::fromLatin1 (caps->model_name).trimmed () + // + ' '+ QString::fromLatin1 (caps->version).trimmed () + // + " (" + QString::fromLatin1 (rig_strstatus (caps->status)).trimmed () + ')' + ; + } + + auto port_type = TransceiverFactory::Capabilities::none; + switch (caps->port_type) + { + case RIG_PORT_SERIAL: + port_type = TransceiverFactory::Capabilities::serial; + break; + + case RIG_PORT_NETWORK: + port_type = TransceiverFactory::Capabilities::network; + break; + + default: break; + } + (*rigs)[key] = TransceiverFactory::Capabilities (caps->rig_model + , port_type + , RIG_PTT_RIG == caps->ptt_type || RIG_PTT_RIG_MICDATA == caps->ptt_type + , RIG_PTT_RIG_MICDATA == caps->ptt_type); + + return 1; // keep them coming + } + + // int frequency_change_callback (RIG * /* rig */, vfo_t vfo, freq_t f, rig_ptr_t arg) + // { + // (void)vfo; // unused in release build + + // Q_ASSERT (vfo == RIG_VFO_CURR); // G4WJS: at the time of writing only current VFO is signalled by hamlib + + // HamlibTransceiver * transceiver (reinterpret_cast (arg)); + // Q_EMIT transceiver->frequency_change (f, Transceiver::A); + // return RIG_OK; + // } + + class hamlib_tx_vfo_fixup final + { + public: + hamlib_tx_vfo_fixup (RIG * rig, vfo_t tx_vfo) + : rig_ {rig} + { + original_vfo_ = rig_->state.tx_vfo; + rig_->state.tx_vfo = tx_vfo; + } + + ~hamlib_tx_vfo_fixup () + { + rig_->state.tx_vfo = original_vfo_; + } + + private: + RIG * rig_; + vfo_t original_vfo_; + }; +} + +void HamlibTransceiver::register_transceivers (TransceiverFactory::Transceivers * registry) +{ + rig_set_debug_callback (debug_callback, nullptr); + +#if WSJT_HAMLIB_TRACE + rig_set_debug (RIG_DEBUG_TRACE); +#elif defined (NDEBUG) + rig_set_debug (RIG_DEBUG_ERR); +#else + rig_set_debug (RIG_DEBUG_VERBOSE); +#endif + + rig_load_all_backends (); + rig_list_foreach (rigCallback, registry); +} + +void HamlibTransceiver::RIGDeleter::cleanup (RIG * rig) +{ + if (rig) + { + // rig->state.obj = 0; + rig_cleanup (rig); + } +} + +HamlibTransceiver::HamlibTransceiver (int model_number + , QString const& cat_port + , int cat_baud + , TransceiverFactory::DataBits cat_data_bits + , TransceiverFactory::StopBits cat_stop_bits + , TransceiverFactory::Handshake cat_handshake + , bool cat_dtr_always_on + , bool cat_rts_always_on + , TransceiverFactory::PTTMethod ptt_type + , TransceiverFactory::TXAudioSource back_ptt_port + , QString const& ptt_port + , int poll_interval) +: PollingTransceiver {poll_interval} +, rig_ {rig_init (model_number)} +, back_ptt_port_ {TransceiverFactory::TX_audio_source_rear == back_ptt_port} +, is_dummy_ {RIG_MODEL_DUMMY == model_number} +, reversed_ {false} +{ + if (!rig_) + { + throw error {"Hamlib initialisation error"}; + } + + // rig_->state.obj = this; + + if (/*!is_dummy_ &&*/ !cat_port.isEmpty () /*&& cat_port != "None"*/) + { +// #if defined (WIN32) +// set_conf ("rig_pathname", ("\\\\.\\" + cat_port).toLatin1 ().data ()); +// #else + set_conf ("rig_pathname", cat_port.toLatin1 ().data ()); +// #endif + } + + set_conf ("serial_speed", QByteArray::number (cat_baud).data ()); + set_conf ("data_bits", TransceiverFactory::seven_data_bits == cat_data_bits ? "7" : "8"); + set_conf ("stop_bits", TransceiverFactory::one_stop_bit == cat_stop_bits ? "1" : "2"); + + switch (cat_handshake) + { + case TransceiverFactory::handshake_none: set_conf ("serial_handshake", "None"); break; + case TransceiverFactory::handshake_XonXoff: set_conf ("serial_handshake", "XONXOFF"); break; + case TransceiverFactory::handshake_hardware: set_conf ("serial_handshake", "Hardware"); break; + } + + if (cat_dtr_always_on) + { + set_conf ("dtr_state", "ON"); + } + if (TransceiverFactory::handshake_hardware != cat_handshake && cat_rts_always_on) + { + set_conf ("rts_state", "ON"); + } + + switch (ptt_type) + { + case TransceiverFactory::PTT_method_VOX: + set_conf ("ptt_type", "None"); + break; + + case TransceiverFactory::PTT_method_CAT: + set_conf ("ptt_type", "RIG"); + break; + + case TransceiverFactory::PTT_method_DTR: + case TransceiverFactory::PTT_method_RTS: + if (!ptt_port.isEmpty () && ptt_port != "None" && ptt_port != cat_port) + { +#if defined (WIN32) + set_conf ("ptt_pathname", ("\\\\.\\" + ptt_port).toLatin1 ().data ()); +#else + set_conf ("ptt_pathname", ptt_port.toLatin1 ().data ()); +#endif + } + + if (TransceiverFactory::PTT_method_DTR == ptt_type) + { + set_conf ("ptt_type", "DTR"); + } + else + { + set_conf ("ptt_type", "RTS"); + } + } + + // Make Icom CAT split commands less glitchy + set_conf ("no_xchg", "1"); + + // would be nice to get events but not supported on Windows and also not on a lot of rigs + // rig_set_freq_callback (rig_.data (), &frequency_change_callback, this); +} + +HamlibTransceiver::~HamlibTransceiver () +{ +} + +void HamlibTransceiver::do_start () +{ +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::do_start rig:" << QString::fromLatin1 (rig_->caps->mfg_name).trimmed () + ' ' + + QString::fromLatin1 (rig_->caps->model_name).trimmed (); +#endif + + error_check (rig_open (rig_.data ())); + + init_rig (); +} + +void HamlibTransceiver::do_stop () +{ + if (rig_) + { + rig_close (rig_.data ()); + } + +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::do_stop: state:" << state () << "reversed =" << reversed_; +#endif +} + +void HamlibTransceiver::init_rig () +{ + if (!is_dummy_) + { + freq_t f1; + freq_t f2; + rmode_t m {RIG_MODE_USB}; + rmode_t mb; + pbwidth_t w {rig_passband_wide (rig_.data (), m)}; + pbwidth_t wb; + if (!rig_->caps->get_vfo) + { + // Icom have deficient CAT protocol with no way of reading which + // VFO is selected or if SPLIT is selected so we have to simply + // assume it is as when we started by setting at open time right + // here. We also gather/set other initial state. + error_check (rig_get_freq (rig_.data (), RIG_VFO_CURR, &f1)); + +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::init_rig rig_get_freq =" << f1; +#endif + + error_check (rig_get_mode (rig_.data (), RIG_VFO_CURR, &m, &w)); + +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::init_rig rig_get_mode =" << m << "bw =" << w; +#endif + + if (!rig_->caps->set_vfo) + { + if (rig_has_vfo_op (rig_.data (), RIG_OP_TOGGLE)) + { + +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::init_rig rig_vfo_op TOGGLE"; +#endif + + error_check (rig_vfo_op (rig_.data (), RIG_VFO_CURR, RIG_OP_TOGGLE)); + } + else + { + throw error {"Hamlib: unable to initialise rig"}; + } + } + else + { + +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::init_rig rig_set_vfo"; +#endif + + error_check (rig_set_vfo (rig_.data (), rig_->state.vfo_list & RIG_VFO_B ? RIG_VFO_B : RIG_VFO_SUB)); + } + + error_check (rig_get_freq (rig_.data (), RIG_VFO_CURR, &f2)); + +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::init_rig rig_get_freq =" << f2; +#endif + + error_check (rig_get_mode (rig_.data (), RIG_VFO_CURR, &mb, &wb)); + +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::init_rig rig_get_mode =" << mb << "bw =" << wb; +#endif + + update_other_frequency (f2); + + if (!rig_->caps->set_vfo) + { + +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::init_rig rig_vfo_op TOGGLE"; +#endif + + error_check (rig_vfo_op (rig_.data (), RIG_VFO_CURR, RIG_OP_TOGGLE)); + } + else + { +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::init_rig rig_set_vfo"; +#endif + + error_check (rig_set_vfo (rig_.data (), rig_->state.vfo_list & RIG_VFO_A ? RIG_VFO_A : RIG_VFO_MAIN)); + } + + if (f1 != f2 || m != mb || w != wb) // we must have started with MAIN/A + { + update_rx_frequency (f1); + } + else + { + error_check (rig_get_freq (rig_.data (), RIG_VFO_CURR, &f1)); + +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::init_rig rig_get_freq =" << f1; +#endif + + error_check (rig_get_mode (rig_.data (), RIG_VFO_CURR, &m, &w)); + +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::init_rig rig_get_mode =" << m << "bw =" << w; +#endif + + update_rx_frequency (f1); + } + +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::init_rig rig_set_split_vfo"; +#endif + + // error_check (rig_set_split_vfo (rig_.data (), RIG_VFO_CURR, RIG_SPLIT_OFF, RIG_VFO_CURR)); + // update_split (false); + } + else + { + vfo_t v; + error_check (rig_get_vfo (rig_.data (), &v)); // has side effect of establishing current VFO inside hamlib + +#if WSJT_TRACE_CAT + qDebug ().nospace () << "HamlibTransceiver::init_rig rig_get_vfo = 0x" << hex << v; +#endif + + reversed_ = RIG_VFO_B == v; + + if (!(rig_->caps->targetable_vfo & (RIG_TARGETABLE_MODE | RIG_TARGETABLE_PURE))) + { + error_check (rig_get_mode (rig_.data (), RIG_VFO_CURR, &m, &w)); + +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::init_rig rig_get_mode =" << m << "bw =" << w; +#endif + } + } + update_mode (map_mode (m)); + } + + poll (); + +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::init_rig exit" << state () << "reversed =" << reversed_; +#endif +} + +auto HamlibTransceiver::get_vfos () const -> std::tuple +{ + if (rig_->caps->get_vfo) + { + vfo_t v; + error_check (rig_get_vfo (rig_.data (), &v)); // has side effect of establishing current VFO inside hamlib + +#if WSJT_TRACE_CAT + qDebug ().nospace () << "HamlibTransceiver::get_vfos rig_get_vfo = 0x" << hex << v; +#endif + + reversed_ = RIG_VFO_B == v; + } + else if (rig_->caps->set_vfo) + { + // use VFO A/MAIN for main frequency and B/SUB for Tx + // frequency if split since these type of radios can only + // support this way around + +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::get_vfos rig_set_vfo"; +#endif + + error_check (rig_set_vfo (rig_.data (), rig_->state.vfo_list & RIG_VFO_A ? RIG_VFO_A : RIG_VFO_MAIN)); + } + // else only toggle available but both VFOs should be substitutable + + auto rx_vfo = rig_->state.vfo_list & RIG_VFO_A ? RIG_VFO_A : RIG_VFO_MAIN; + auto tx_vfo = state ().split () ? (rig_->state.vfo_list & RIG_VFO_B ? RIG_VFO_B : RIG_VFO_SUB) : rx_vfo; + if (reversed_) + { +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::get_vfos reversing VFOs"; +#endif + + std::swap (rx_vfo, tx_vfo); + } + +#if WSJT_TRACE_CAT + qDebug ().nospace () << "HamlibTransceiver::get_vfos RX VFO = 0x" << hex << rx_vfo << " TX VFO = 0x" << hex << tx_vfo; +#endif + + return std::make_tuple (rx_vfo, tx_vfo); +} + +void HamlibTransceiver::do_frequency (Frequency f) +{ +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::do_frequency:" << f << "reversed:" << reversed_; +#endif + + if (!is_dummy_) + { + error_check (rig_set_freq (rig_.data (), RIG_VFO_CURR, f)); + } + + update_rx_frequency (f); +} + +void HamlibTransceiver::do_tx_frequency (Frequency tx, bool rationalise_mode) +{ +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::do_tx_frequency:" << tx << "rationalise mode:" << rationalise_mode << "reversed:" << reversed_; +#endif + + if (!is_dummy_) + { + auto vfos = get_vfos (); + // auto rx_vfo = std::get<0> (vfos); + auto tx_vfo = std::get<1> (vfos); + + if (tx) + { +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::do_tx_frequency rig_set_split_freq"; +#endif + + hamlib_tx_vfo_fixup fixup (rig_.data (), tx_vfo); + error_check (rig_set_split_freq (rig_.data (), RIG_VFO_CURR, tx)); + + if (rationalise_mode) + { + rmode_t current_mode; + pbwidth_t current_width; + +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::mode rig_get_split_mode"; +#endif + auto new_mode = map_mode (state ().mode ()); + error_check (rig_get_split_mode (rig_.data (), RIG_VFO_CURR, ¤t_mode, ¤t_width)); + + if (new_mode != current_mode) + { +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::do_tx_frequency rig_set_split_mode"; +#endif + + error_check (rig_set_split_mode (rig_.data (), RIG_VFO_CURR, new_mode, rig_passband_wide (rig_.data (), new_mode))); + } + } + } + + // enable split last since some rigs (Kenwood for one) come out + // of split when you switch RX VFO (to set split mode above for + // example) + +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::do_tx_frequency rig_set_split_vfo"; +#endif + + error_check (rig_set_split_vfo (rig_.data (), RIG_VFO_CURR, tx ? RIG_SPLIT_ON : RIG_SPLIT_OFF, tx_vfo)); + } + + update_split (tx); + update_other_frequency (tx); +} + +void HamlibTransceiver::do_mode (MODE mode, bool rationalise) +{ +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::do_mode:" << mode << "rationalise:" << rationalise; +#endif + + if (!is_dummy_) + { + auto vfos = get_vfos (); + // auto rx_vfo = std::get<0> (vfos); + auto tx_vfo = std::get<1> (vfos); + + rmode_t current_mode; + pbwidth_t current_width; + +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::mode rig_get_mode"; +#endif + error_check (rig_get_mode (rig_.data (), RIG_VFO_CURR, ¤t_mode, ¤t_width)); + + auto new_mode = map_mode (mode); + if (new_mode != current_mode) + { +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::mode rig_set_mode"; +#endif + error_check (rig_set_mode (rig_.data (), RIG_VFO_CURR, new_mode, rig_passband_wide (rig_.data (), new_mode))); + } + + if (state ().split () && rationalise) + { +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::mode rig_get_split_mode"; +#endif + error_check (rig_get_split_mode (rig_.data (), RIG_VFO_CURR, ¤t_mode, ¤t_width)); + + if (new_mode != current_mode) + { +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::mode rig_set_split_mode"; +#endif + hamlib_tx_vfo_fixup fixup (rig_.data (), tx_vfo); + error_check (rig_set_split_mode (rig_.data (), RIG_VFO_CURR, new_mode, rig_passband_wide (rig_.data (), new_mode))); + } + } + } + + update_mode (mode); +} + +void HamlibTransceiver::poll () +{ + if (is_dummy_) + { + // split with dummy is never reported since there is no rig + if (state ().split ()) + { + update_split (false); + } + } + else + { +#if !WSJT_TRACE_CAT_POLLS +#if defined (NDEBUG) + rig_set_debug (RIG_DEBUG_ERR); +#else + rig_set_debug (RIG_DEBUG_VERBOSE); +#endif +#endif + + freq_t f; + rmode_t m; + pbwidth_t w; + split_t s; + + if (rig_->caps->get_vfo) + { + vfo_t v; + error_check (rig_get_vfo (rig_.data (), &v)); // has side effect of establishing current VFO inside hamlib + +#if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS + qDebug ().nospace () << "HamlibTransceiver::state rig_get_vfo = 0x" << hex << v; +#endif + + reversed_ = RIG_VFO_B == v; + } + + error_check (rig_get_freq (rig_.data (), RIG_VFO_CURR, &f)); + +#if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS + qDebug () << "HamlibTransceiver::state rig_get_freq =" << f; +#endif + + update_rx_frequency (f); + + if (rig_->caps->targetable_vfo & (RIG_TARGETABLE_FREQ | RIG_TARGETABLE_PURE)) + { + // we can only probe current VFO unless rig supports reading the other one directly + error_check (rig_get_freq (rig_.data () + , reversed_ + ? (rig_->state.vfo_list & RIG_VFO_A ? RIG_VFO_A : RIG_VFO_MAIN) + : (rig_->state.vfo_list & RIG_VFO_B ? RIG_VFO_B : RIG_VFO_SUB) + , &f)); + +#if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS + qDebug () << "HamlibTransceiver::state rig_get_freq other =" << f; +#endif + + update_other_frequency (f); + } + + error_check (rig_get_mode (rig_.data (), RIG_VFO_CURR, &m, &w)); + +#if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS + qDebug () << "HamlibTransceiver::state rig_get_mode =" << m << "bw =" << w; +#endif + + update_mode (map_mode (m)); + + vfo_t v {RIG_VFO_NONE}; // so we can tell if it doesn't get updated :( + auto rc = rig_get_split_vfo (rig_.data (), RIG_VFO_CURR, &s, &v); + if (RIG_OK == rc && RIG_SPLIT_ON == s) + { + +#if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS + qDebug ().nospace () << "HamlibTransceiver::state rig_get_split_vfo split = " << s << " VFO = 0x" << hex << v; +#endif + + update_split (true); + // if (RIG_VFO_A == v) + // { + // reversed_ = true; // not sure if this helps us here + // } + } + else if (RIG_OK == rc) // not split + { +#if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS + qDebug ().nospace () << "HamlibTransceiver::state rig_get_split_vfo split = " << s << " VFO = 0x" << hex << v; +#endif + + update_split (false); + } + else if (-RIG_ENAVAIL == rc) // Some rigs (Icom) don't have a way of reporting SPLIT mode + { +#if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS + qDebug ().nospace () << "HamlibTransceiver::state rig_get_split_vfo can't do on this rig"; +#endif + + // just report how we see it based on prior commands + } + else + { + error_check (rc); + } + + if (RIG_PTT_NONE != rig_->state.pttport.type.ptt && rig_->caps->get_ptt) + { + ptt_t p; + error_check (rig_get_ptt (rig_.data (), RIG_VFO_CURR, &p)); + +#if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS + qDebug () << "HamlibTransceiver::state rig_get_ptt =" << p; +#endif + + update_PTT (!(RIG_PTT_OFF == p)); + } + +#if !WSJT_TRACE_CAT_POLLS +#if WSJT_HAMLIB_TRACE + rig_set_debug (RIG_DEBUG_TRACE); +#elif defined (NDEBUG) + rig_set_debug (RIG_DEBUG_ERR); +#else + rig_set_debug (RIG_DEBUG_VERBOSE); +#endif +#endif + } +} + +void HamlibTransceiver::do_ptt (bool on) +{ +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::do_ptt:" << on << state () << "reversed =" << reversed_; +#endif + + if (on) + { + if (RIG_PTT_NONE != rig_->state.pttport.type.ptt) + { +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::ptt rig_set_ptt"; +#endif + + error_check (rig_set_ptt (rig_.data (), RIG_VFO_CURR, back_ptt_port_ ? RIG_PTT_ON_DATA : RIG_PTT_ON)); + } + } + else + { + if (RIG_PTT_NONE != rig_->state.pttport.type.ptt) + { +#if WSJT_TRACE_CAT + qDebug () << "HamlibTransceiver::ptt rig_set_ptt"; +#endif + + error_check (rig_set_ptt (rig_.data (), RIG_VFO_CURR, RIG_PTT_OFF)); + } + } + + update_PTT (on); +} + +void HamlibTransceiver::error_check (int ret_code) const +{ + if (RIG_OK != ret_code) + { +#if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS + qDebug () << "HamlibTransceiver::error_check: error:" << rigerror (ret_code); +#endif + + throw error {QByteArray ("Hamlib error: ") + rigerror (ret_code)}; + } +} + +void HamlibTransceiver::set_conf (char const * item, char const * value) +{ + token_t token = rig_token_lookup (rig_.data (), item); + if (RIG_CONF_END != token) // only set if valid for rig model + { + error_check (rig_set_conf (rig_.data (), token, value)); + } +} + +QByteArray HamlibTransceiver::get_conf (char const * item) +{ + token_t token = rig_token_lookup (rig_.data (), item); + QByteArray value {128, '\0'}; + if (RIG_CONF_END != token) // only get if valid for rig model + { + error_check (rig_get_conf (rig_.data (), token, value.data ())); + } + return value; +} + +auto HamlibTransceiver::map_mode (rmode_t m) const -> MODE +{ + switch (m) + { + case RIG_MODE_AM: + case RIG_MODE_SAM: + case RIG_MODE_AMS: + case RIG_MODE_DSB: + return AM; + + case RIG_MODE_CW: + return CW; + + case RIG_MODE_CWR: + return CW_R; + + case RIG_MODE_USB: + case RIG_MODE_ECSSUSB: + case RIG_MODE_SAH: + case RIG_MODE_FAX: + return USB; + + case RIG_MODE_LSB: + case RIG_MODE_ECSSLSB: + case RIG_MODE_SAL: + return LSB; + + case RIG_MODE_RTTY: + return FSK; + + case RIG_MODE_RTTYR: + return FSK_R; + + case RIG_MODE_PKTLSB: + return DIG_L; + + case RIG_MODE_PKTUSB: + return DIG_U; + + case RIG_MODE_FM: + case RIG_MODE_WFM: + return FM; + + case RIG_MODE_PKTFM: + return DIG_FM; + + default: + return UNK; + } +} + +rmode_t HamlibTransceiver::map_mode (MODE mode) const +{ + switch (mode) + { + case AM: return RIG_MODE_AM; + case CW: return RIG_MODE_CW; + case CW_R: return RIG_MODE_CWR; + case USB: return RIG_MODE_USB; + case LSB: return RIG_MODE_LSB; + case FSK: return RIG_MODE_RTTY; + case FSK_R: return RIG_MODE_RTTYR; + case DIG_L: return RIG_MODE_PKTLSB; + case DIG_U: return RIG_MODE_PKTUSB; + case FM: return RIG_MODE_FM; + case DIG_FM: return RIG_MODE_PKTFM; + default: break; + } + return RIG_MODE_USB; // quieten compiler grumble +} diff --git a/HamlibTransceiver.hpp b/HamlibTransceiver.hpp new file mode 100644 index 000000000..57b3742c0 --- /dev/null +++ b/HamlibTransceiver.hpp @@ -0,0 +1,68 @@ +#ifndef HAMLIB_TRANSCEIVER_HPP_ +#define HAMLIB_TRANSCEIVER_HPP_ + +#include + +#include + +#include + +#include "TransceiverFactory.hpp" +#include "PollingTransceiver.hpp" + +extern "C" +{ + typedef struct rig RIG; + struct rig_caps; + typedef int vfo_t; +} + +// hamlib transceiver and PTT mostly delegated directly to hamlib Rig class +class HamlibTransceiver final + : public PollingTransceiver +{ + public: + static void register_transceivers (TransceiverFactory::Transceivers *); + + explicit HamlibTransceiver (int model_number + , QString const& cat_port + , int cat_baud + , TransceiverFactory::DataBits cat_data_bits + , TransceiverFactory::StopBits cat_stop_bits + , TransceiverFactory::Handshake cat_handshake + , bool cat_dtr_always_on + , bool cat_rts_always_on + , TransceiverFactory::PTTMethod ptt_type + , TransceiverFactory::TXAudioSource back_ptt_port + , QString const& ptt_port + , int poll_interval = 0); + ~HamlibTransceiver (); + + private: + void do_start () override; + void do_stop () override; + void do_frequency (Frequency) override; + void do_tx_frequency (Frequency, bool rationalise_mode) override; + void do_mode (MODE, bool rationalise) override; + void do_ptt (bool) override; + + void poll () override; + + void error_check (int ret_code) const; + void set_conf (char const * item, char const * value); + QByteArray get_conf (char const * item); + Transceiver::MODE map_mode (rmode_t) const; + rmode_t map_mode (Transceiver::MODE mode) const; + void init_rig (); + std::tuple get_vfos () const; + + struct RIGDeleter {static void cleanup (RIG *);}; + QScopedPointer rig_; + + bool back_ptt_port_; + bool is_dummy_; + + bool mutable reversed_; +}; + +#endif diff --git a/Info.plist.in b/Info.plist.in new file mode 100644 index 000000000..2ad1e0db0 --- /dev/null +++ b/Info.plist.in @@ -0,0 +1,10 @@ + + + + + CFBundleExecutable + @WSJTX_BUNDLE_NAME@ + CFBundleDisplayName + @WSJTX_BUNDLE_NAME@ + + diff --git a/LICENSE_WHEATLEY.TXT b/LICENSE_WHEATLEY.txt similarity index 98% rename from LICENSE_WHEATLEY.TXT rename to LICENSE_WHEATLEY.txt index 8b0ce2498..8adb5204b 100644 --- a/LICENSE_WHEATLEY.TXT +++ b/LICENSE_WHEATLEY.txt @@ -1,30 +1,30 @@ -+ + + This Software is released under the "Simplified BSD License" + + + -Copyright 2010 Moe Wheatley. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - -THIS SOFTWARE IS PROVIDED BY Moe Wheatley ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL Moe Wheatley OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -The views and conclusions contained in the software and documentation -are those of the authors and should not be interpreted as representing -official policies, either expressed or implied, of Moe Wheatley. ++ + + This Software is released under the "Simplified BSD License" + + + +Copyright 2010 Moe Wheatley. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +THIS SOFTWARE IS PROVIDED BY Moe Wheatley ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL Moe Wheatley OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation +are those of the authors and should not be interpreted as representing +official policies, either expressed or implied, of Moe Wheatley. diff --git a/LiveFrequencyValidator.cpp b/LiveFrequencyValidator.cpp new file mode 100644 index 000000000..f234122c1 --- /dev/null +++ b/LiveFrequencyValidator.cpp @@ -0,0 +1,92 @@ +#include "LiveFrequencyValidator.hpp" + +#include +#include +#include +#include + +#include "Bands.hpp" +#include "FrequencyList.hpp" + +#include "moc_LiveFrequencyValidator.cpp" + +LiveFrequencyValidator::LiveFrequencyValidator (QComboBox * combo_box + , Bands const * bands + , FrequencyList const * frequencies + , QWidget * parent) + : QRegExpValidator { + QRegExp { // frequency in MHz or band + bands->data (QModelIndex {}).toString () // out of band string + + QString {R"(|((\d{0,6}(\)"} // up to 6 digits + + QLocale {}.decimalPoint () // (followed by decimal separator + + R"(\d{0,2})?)([Mm]{1,2}|([Cc][Mm])))|(\d{0,4}(\)" // followed by up to 2 digits and either 'm' or 'cm' or 'mm' (case insensitive)) + + QLocale {}.decimalPoint () // or a decimal separator + + R"(\d{0,6})?))" // followed by up to 6 digits + } + , parent + } + , bands_ {bands} + , frequencies_ {frequencies} + , combo_box_ {combo_box} +{ +} + +auto LiveFrequencyValidator::validate (QString& input, int& pos) const -> State +{ + auto state = QRegExpValidator::validate (input, pos); + + // by never being Acceptable we force fixup calls on ENTER or + // losing focus + return Acceptable == state ? Intermediate : state; +} + +void LiveFrequencyValidator::fixup (QString& input) const +{ + QRegExpValidator::fixup (input); + + auto out_of_band = bands_->data (QModelIndex {}).toString (); + + if (!out_of_band.startsWith (input)) + { + if (input.contains ('m', Qt::CaseInsensitive)) + { + input = input.toLower (); + + QVector frequencies; + for (int r = 0; r < frequencies_->rowCount (); ++r) + { + auto frequency = frequencies_->index (r, 0).data (); + auto band_index = bands_->find (frequency); + if (band_index.data ().toString () == input) + { + frequencies << frequency; + } + } + if (!frequencies.isEmpty ()) + { + Q_EMIT valid (frequencies.first ().value ()); + } + else + { + input = QString {}; + } + } + else + { + // frequency input + auto f = Radio::frequency (input, 6); + input = bands_->data (bands_->find (f)).toString (); + Q_EMIT valid (f); + } + + if (out_of_band == input) + { + combo_box_->lineEdit ()->setStyleSheet ("QLineEdit {color: yellow; background-color : red;}"); + } + else + { + combo_box_->lineEdit ()->setStyleSheet ({}); + } + combo_box_->setCurrentText (input); + } +} diff --git a/LiveFrequencyValidator.hpp b/LiveFrequencyValidator.hpp new file mode 100644 index 000000000..d4d6cc696 --- /dev/null +++ b/LiveFrequencyValidator.hpp @@ -0,0 +1,52 @@ +#ifndef LIVE_FREQUENCY_VALIDATOR_HPP__ +#define LIVE_FREQUENCY_VALIDATOR_HPP__ + +#include +#include + +#include "Radio.hpp" + +class Bands; +class FrequencyList; +class QComboBox; +class QWidget; + +// +// Class LiveFrequencyValidator +// +// QLineEdit validator that controls input to an editable +// QComboBox where the user can enter a valid band or a valid +// frequency in megahetz. +// +// Collabrations +// +// Implements the QRegExpValidator interface. Validates input +// from the supplied QComboBox as either a valid frequency in +// megahertz or a valid band as defined by the supplied column of +// the supplied QAbstractItemModel. +// +class LiveFrequencyValidator final + : public QRegExpValidator +{ + Q_OBJECT; + +public: + using Frequency = Radio::Frequency; + + LiveFrequencyValidator (QComboBox * combo_box // associated combo box + , Bands const * bands // bands model + , FrequencyList const * frequencies // working frequencies model + , QWidget * parent = nullptr); + + State validate (QString& input, int& pos) const override; + void fixup (QString& input) const override; + + Q_SIGNAL void valid (Frequency) const; + +private: + Bands const * bands_; + FrequencyList const * frequencies_; + QComboBox * combo_box_; +}; + +#endif diff --git a/Mac-wsjtx-startup.sh b/Mac-wsjtx-startup.sh new file mode 100644 index 000000000..b3939102a --- /dev/null +++ b/Mac-wsjtx-startup.sh @@ -0,0 +1,16 @@ +#!/bin/sh +WSJTX_BUNDLE="`echo "$0" | sed -e 's/\/Contents\/MacOS\/.*//'`" +WSJTX_RESOURCES="$WSJTX_BUNDLE/Contents/Resources" +WSJTX_TEMP="/tmp/wsjtx/$UID" + +echo "running $0" +echo "WSJTX_BUNDLE: $WSJTX_BUNDLE" + +# Setup temporary runtime files +rm -rf "$WSJTX_TEMP" + +export "DYLD_LIBRARY_PATH=$WSJTX_RESOURCES/lib" +export "PATH=$WSJTX_RESOURCES/bin:$PATH" + +#export +exec "$WSJTX_RESOURCES/bin/wsjtx" \ No newline at end of file diff --git a/Modulator.cpp b/Modulator.cpp index 0708d3e28..927882023 100644 --- a/Modulator.cpp +++ b/Modulator.cpp @@ -5,7 +5,10 @@ #include #include "mainwindow.h" -extern float gran(); // Noise generator (for tests only) +#include "moc_Modulator.cpp" + +extern float gran(); // Noise generator (for tests only) + #define RAMP_INCREMENT 64 // MUST be an integral factor of 2^16 #if defined (WSJT_SOFT_KEYING) diff --git a/Modulator.hpp b/Modulator.hpp index ba6b8edc2..d6ec3a5a9 100644 --- a/Modulator.hpp +++ b/Modulator.hpp @@ -57,7 +57,7 @@ private: Q_SLOT void tune (bool newState = true) {m_tuning = newState;} Q_SLOT void mute (bool newState = true) {m_muted = newState;} Q_SLOT void setFrequency (unsigned newFrequency) {m_frequency = newFrequency;} - Q_SIGNAL void stateChanged (ModulatorState); + Q_SIGNAL void stateChanged (ModulatorState) const; private: qint16 postProcessSample (qint16 sample) const; diff --git a/NetworkServerLookup.cpp b/NetworkServerLookup.cpp new file mode 100644 index 000000000..be872e715 --- /dev/null +++ b/NetworkServerLookup.cpp @@ -0,0 +1,83 @@ +#include "NetworkServerLookup.hpp" + +#include + +#include +#include + +std::tuple +network_server_lookup (QString const& query + , quint16 default_service_port + , QHostAddress default_host_address + , QAbstractSocket::NetworkLayerProtocol required_protocol) +{ + QHostAddress host_address {default_host_address}; + quint16 service_port {default_service_port}; + + QString host_name; + if (!query.isEmpty ()) + { + int port_colon_index {-1}; + + if ('[' == query[0]) + { + // assume IPv6 combined address/port syntax [
]: + auto close_bracket_index = query.lastIndexOf (']'); + host_name = query.mid (1, close_bracket_index - 1); + port_colon_index = query.indexOf (':', close_bracket_index); + } + else + { + port_colon_index = query.lastIndexOf (':'); + host_name = query.left (port_colon_index); + } + + if (port_colon_index >= 0) + { + bool ok; + service_port = query.mid (port_colon_index + 1).toUShort (&ok); + if (!ok) + { + throw std::runtime_error {"network server lookup error: invalid port"}; + } + } + } + + if (!host_name.isEmpty ()) + { + auto host_info = QHostInfo::fromName (host_name); + if (host_info.addresses ().isEmpty ()) + { + throw std::runtime_error {"network server lookup error: host name lookup failed"}; + } + + bool found {false}; + for (int i {0}; i < host_info.addresses ().size () && !found; ++i) + { + host_address = host_info.addresses ().at (i); + switch (required_protocol) + { + case QAbstractSocket::IPv4Protocol: + case QAbstractSocket::IPv6Protocol: + if (required_protocol != host_address.protocol ()) + { + break; + } + // drop through + + case QAbstractSocket::AnyIPProtocol: + found = true; + break; + + default: + throw std::runtime_error {"network server lookup error: invalid required protocol"}; + } + } + if (!found) + { + throw std::runtime_error {"network server lookup error: no suitable host address found"}; + } + } + + return std::make_tuple (host_address, service_port); +} diff --git a/NetworkServerLookup.hpp b/NetworkServerLookup.hpp new file mode 100644 index 000000000..1f21ad591 --- /dev/null +++ b/NetworkServerLookup.hpp @@ -0,0 +1,38 @@ +#ifndef NETWORK_SERVER_LOOKUP_HPP__ +#define NETWORK_SERVER_LOOKUP_HPP__ + +#include + +#include +#include + +class QString; + +// +// Do a blocking DNS lookup using query as a destination host address +// and port. +// +// query can be one of: +// +// 1) "" (empty string) - use defaults +// 2) ":nnnnn" - override default service port with port nnnnn +// 3) "" - override default host address with DNS lookup +// 4) "nnn.nnn.nnn.nnn" - override default host address with the IPv4 address given by nnn.nnn.nnn.nnn +// 5) "[:nnnnn" - use as per (3) & (2) +// 7) "nnn.nnn.nnn.nnn:nnnnn" - use as per (4) & (2) +// 8) "[ +network_server_lookup (QString const& query + , quint16 default_service_port + , QHostAddress default_host_address = QHostAddress::LocalHost + , QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::AnyIPProtocol); + +#endif diff --git a/OmniRigTransceiver.cpp b/OmniRigTransceiver.cpp new file mode 100644 index 000000000..5d81db23a --- /dev/null +++ b/OmniRigTransceiver.cpp @@ -0,0 +1,741 @@ +#include "OmniRigTransceiver.hpp" + +#include +#include + +#include + +#include "moc_OmniRigTransceiver.cpp" + +namespace +{ + auto constexpr OmniRig_transceiver_one_name = "OmniRig Rig 1"; + auto constexpr OmniRig_transceiver_two_name = "OmniRig Rig 2"; +} + +auto OmniRigTransceiver::map_mode (OmniRig::RigParamX param) -> MODE +{ + if (param & OmniRig::PM_CW_U) + { + return CW_R; + } + else if (param & OmniRig::PM_CW_L) + { + return CW; + } + else if (param & OmniRig::PM_SSB_U) + { + return USB; + } + else if (param & OmniRig::PM_SSB_L) + { + return LSB; + } + else if (param & OmniRig::PM_DIG_U) + { + return DIG_U; + } + else if (param & OmniRig::PM_DIG_L) + { + return DIG_L; + } + else if (param & OmniRig::PM_AM) + { + return AM; + } + else if (param & OmniRig::PM_FM) + { + return FM; + } + +#if WSJT_TRACE_CAT + qDebug () << "OmniRig map_mode unrecognized mode"; +#endif + + throw error {"OmniRig: unrecognized mode"}; +} + +OmniRig::RigParamX OmniRigTransceiver::map_mode (MODE mode) +{ + switch (mode) + { + case AM: return OmniRig::PM_AM; + case CW: return OmniRig::PM_CW_L; + case CW_R: return OmniRig::PM_CW_U; + case USB: return OmniRig::PM_SSB_U; + case LSB: return OmniRig::PM_SSB_L; + case FSK: return OmniRig::PM_DIG_L; + case FSK_R: return OmniRig::PM_DIG_U; + case DIG_L: return OmniRig::PM_DIG_L; + case DIG_U: return OmniRig::PM_DIG_U; + case FM: return OmniRig::PM_FM; + case DIG_FM: return OmniRig::PM_FM; + default: break; + } + return OmniRig::PM_SSB_U; // quieten compiler grumble +} + +void OmniRigTransceiver::register_transceivers (TransceiverFactory::Transceivers * registry, int id1, int id2) +{ + (*registry)[OmniRig_transceiver_one_name] = TransceiverFactory::Capabilities { + id1 + , TransceiverFactory::Capabilities::none // COM isn't serial or network + , true // does PTT + , false // doesn't select mic/data (use OmniRig config file) + , true // can remote control RTS nd DTR + , true // asynchronous interface + }; + (*registry)[OmniRig_transceiver_two_name] = TransceiverFactory::Capabilities { + id2 + , TransceiverFactory::Capabilities::none // COM isn't serial or network + , true // does PTT + , false // doesn't select mic/data (use OmniRig config file) + , true // can remote control RTS nd DTR + , true // asynchronous interface + }; +} + +OmniRigTransceiver::OmniRigTransceiver (std::unique_ptr wrapped, RigNumber n, TransceiverFactory::PTTMethod ptt_type, QString const& ptt_port) + : wrapped_ {std::move (wrapped)} + , use_for_ptt_ {TransceiverFactory::PTT_method_CAT == ptt_type || ("CAT" == ptt_port && (TransceiverFactory::PTT_method_RTS == ptt_type || TransceiverFactory::PTT_method_DTR == ptt_type))} + , ptt_type_ {ptt_type} + , startup_poll_countdown_ {2} + , rig_number_ {n} + , readable_params_ {0} + , writable_params_ {0} + , send_update_signal_ {false} + , reversed_ {false} + , starting_ {false} +{ +} + +OmniRigTransceiver::~OmniRigTransceiver () +{ +} + +void OmniRigTransceiver::do_start () +{ +#if WSJT_TRACE_CAT + qDebug () << "OmniRigTransceiver::do_start"; +#endif + + wrapped_->start (); + + CoInitializeEx (nullptr, 0 /*COINIT_APARTMENTTHREADED*/); // required because Qt only does this for GUI thread + + omni_rig_.reset (new OmniRig::OmniRigX {this}); + if (omni_rig_->isNull ()) + { +#if WSJT_TRACE_CAT + qDebug () << "OmniRigTransceiver::do_start: failed to start COM server"; +#endif + + throw error {"Failed to start OmniRig COM server"}; + } + + // COM/OLE exceptions get signalled + connect (&*omni_rig_, SIGNAL (exception (int, QString, QString, QString)), this, SLOT (handle_COM_exception (int, QString, QString, QString))); + + // IOmniRigXEvent interface signals + connect (&*omni_rig_, SIGNAL (VisibleChange ()), this, SLOT (handle_visible_change ())); + connect (&*omni_rig_, SIGNAL (RigTypeChange (int)), this, SLOT (handle_rig_type_change (int))); + connect (&*omni_rig_, SIGNAL (StatusChange (int)), this, SLOT (handle_status_change (int))); + connect (&*omni_rig_, SIGNAL (ParamsChange (int, int)), this, SLOT (handle_params_change (int, int))); + connect (&*omni_rig_ + , SIGNAL (CustomReply (int, QVariant const&, QVariant const&)) + , this, SLOT (handle_custom_reply (int, QVariant const&, QVariant const&))); + +#if WSJT_TRACE_CAT + qDebug () + << "OmniRig s/w version:" << QString::number (omni_rig_->SoftwareVersion ()).toLocal8Bit () + << "i/f version:" << QString::number (omni_rig_->InterfaceVersion ()).toLocal8Bit () + ; +#endif + + // fetch the interface of the RigX CoClass and instantiate a proxy object + switch (rig_number_) + { + case One: rig_.reset (new OmniRig::RigX (omni_rig_->Rig1 ())); break; + case Two: rig_.reset (new OmniRig::RigX (omni_rig_->Rig2 ())); break; + } + + Q_ASSERT (rig_); + Q_ASSERT (!rig_->isNull ()); + + if (use_for_ptt_ && (TransceiverFactory::PTT_method_DTR == ptt_type_ || TransceiverFactory::PTT_method_RTS == ptt_type_)) + { + // fetch the interface for the serial port if we need it for PTT + port_.reset (new OmniRig::PortBits (rig_->PortBits ())); + + Q_ASSERT (port_); + Q_ASSERT (!port_->isNull ()); + + // if (!port_->Lock ()) // try to take exclusive use of the OmniRig serial port for PTT + // { + // throw error {("Failed to get exclusive use of " + ptt_type + " from OmniRig").toLocal8Bit ()}; + // } + + // start off so we don't accidentally key the radio + if (TransceiverFactory::PTT_method_DTR == ptt_type_) + { + port_->SetDtr (false); + } + else // RTS + { + port_->SetRts (false); + } + } + + readable_params_ = rig_->ReadableParams (); + writable_params_ = rig_->WriteableParams (); + +#if WSJT_TRACE_CAT + qDebug () + << QString ("OmniRig initial rig type: %1 readable params = 0x%2 writable params = 0x%3 for rig %4") + .arg (rig_->RigType ()) + .arg (readable_params_, 8, 16, QChar ('0')) + .arg (writable_params_, 8, 16, QChar ('0')) + .arg (rig_number_).toLocal8Bit () + ; +#endif + + starting_ = true; + QTimer::singleShot (5000, this, SLOT (startup_check ())); +} + +void OmniRigTransceiver::do_stop () +{ + if (port_) + { + // port_->Unlock (); // release serial port + port_->clear (); + } + + rig_->clear (); + + omni_rig_->clear (); + + CoUninitialize (); + + wrapped_->stop (); + +#if WSJT_TRACE_CAT + qDebug () << "OmniRigTransceiver::do_stop"; +#endif +} + +void OmniRigTransceiver::startup_check () +{ + if (starting_) + { + if (--startup_poll_countdown_) + { + init_rig (); + QTimer::singleShot (5000, this, SLOT (startup_check ())); + } + else + { + startup_poll_countdown_ = 2; + + // signal that we haven't seen anything from OmniRig + offline ("OmniRig initialisation timeout"); + } + } +} + +void OmniRigTransceiver::init_rig () +{ + if (writable_params_ & OmniRig::PM_VFOA) + { +#if WSJT_TRACE_CAT + qDebug () << "OmniRigTransceiver::init_rig: set VFO A"; +#endif + + rig_->SetVfo (OmniRig::PM_VFOA); + if (writable_params_ & OmniRig::PM_SPLITOFF) + { +#if WSJT_TRACE_CAT + qDebug () << "OmniRigTransceiver::init_rig: set SPLIT off"; +#endif + + rig_->SetSplit (OmniRig::PM_SPLITOFF); + } + } + else if (writable_params_ & OmniRig::PM_VFOAA) + { +#if WSJT_TRACE_CAT + qDebug () << "OmniRigTransceiver::init_rig: set VFO A and SPLIT off"; +#endif + + rig_->SetVfo (OmniRig::PM_VFOAA); + } + + reversed_ = false; +} + +void OmniRigTransceiver::do_sync (bool force_signal) +{ + // nothing much we can do here, we just have to let OmniRig do its + // stuff and its first poll should send us and update that will + // trigger a update signal from us. Any attempt to query OmniRig + // leads to a whole mess of trouble since its internal state is + // garbage until it has done its first rig poll. + send_update_signal_ = force_signal; +} + +void OmniRigTransceiver::handle_COM_exception (int code, QString source, QString desc, QString help) +{ +#if WSJT_TRACE_CAT + qDebug () << "OmniRigTransceiver::handle_COM_exception:" << QString::number (code) + " at " + source + ": " + desc + " (" + help + ')'; +#endif + + throw error {("OmniRig COM/OLE error: " + QString::number (code) + " at " + source + ": " + desc + " (" + help + ')').toLocal8Bit ()}; +} + +void OmniRigTransceiver::handle_visible_change () +{ +#if WSJT_TRACE_CAT + qDebug () << "OmniRig visibility change: visibility =" << omni_rig_->DialogVisible (); +#endif +} + +void OmniRigTransceiver::handle_rig_type_change (int rig_number) +{ + if (rig_number_ == rig_number) + { + readable_params_ = rig_->ReadableParams (); + writable_params_ = rig_->WriteableParams (); + +#if WSJT_TRACE_CAT + qDebug () + << QString ("OmniRig rig type change to: %1 readable params = 0x%2 writable params = 0x%3 for rig %4") + .arg (rig_->RigType ()) + .arg (readable_params_, 8, 16, QChar ('0')) + .arg (writable_params_, 8, 16, QChar ('0')) + .arg (rig_number).toLocal8Bit () + ; +#endif + + offline ("OmniRig rig changed"); + } +} + +void OmniRigTransceiver::handle_status_change (int rig_number) +{ + if (rig_number_ == rig_number) + { +#if WSJT_TRACE_CAT + qDebug () + << QString ("OmniRig status change: new status for rig %1 =").arg (rig_number).toLocal8Bit () << rig_->StatusStr ().toLocal8Bit (); +#endif + + if (OmniRig::ST_ONLINE != rig_->Status ()) + { + offline ("OmniRig rig went offline"); + } + else + { + starting_ = false; + + TransceiverState old_state {state ()}; + init_rig (); + + if (old_state != state () || send_update_signal_) + { + update_complete (); + send_update_signal_ = false; + } + } + } +} + +void OmniRigTransceiver::handle_params_change (int rig_number, int params) +{ + if (rig_number_ == rig_number) + { +#if WSJT_TRACE_CAT + qDebug () + << QString ("OmniRig params change: params = 0x%1 for rig %2") + .arg (params, 8, 16, QChar ('0')) + .arg (rig_number).toLocal8Bit () + << "state before:" << state () + ; +#endif + + starting_ = false; + + TransceiverState old_state {state ()}; + auto need_frequency = false; + + // state_.online = true; // sometimes we don't get an initial + // // OmniRig::ST_ONLINE status change + // // event + + if (params & OmniRig::PM_VFOAA) + { + update_split (false); + reversed_ = false; + update_rx_frequency (rig_->FreqA ()); + update_other_frequency (rig_->FreqB ()); + } + if (params & OmniRig::PM_VFOAB) + { + update_split (true); + reversed_ = false; + update_rx_frequency (rig_->FreqA ()); + update_other_frequency (rig_->FreqB ()); + } + if (params & OmniRig::PM_VFOBA) + { + update_split (true); + reversed_ = true; + update_other_frequency (rig_->FreqA ()); + update_rx_frequency (rig_->FreqB ()); + } + if (params & OmniRig::PM_VFOBB) + { + update_split (false); + reversed_ = true; + update_other_frequency (rig_->FreqA ()); + update_rx_frequency (rig_->FreqB ()); + } + if (params & OmniRig::PM_VFOA) + { + reversed_ = false; + need_frequency = true; + } + if (params & OmniRig::PM_VFOB) + { + reversed_ = true; + need_frequency = true; + } + + if (params & OmniRig::PM_FREQ) + { + need_frequency = true; + } + if (params & OmniRig::PM_FREQA) + { + if (reversed_) + { + update_other_frequency (rig_->FreqA ()); + } + else + { + update_rx_frequency (rig_->FreqA ()); + } + } + if (params & OmniRig::PM_FREQB) + { + if (reversed_) + { + update_rx_frequency (rig_->FreqB ()); + } + else + { + update_other_frequency (rig_->FreqB ()); + } + } + + if (need_frequency) + { + if (readable_params_ & OmniRig::PM_FREQA) + { + if (reversed_) + { + update_other_frequency (rig_->FreqA ()); + } + else + { + update_rx_frequency (rig_->FreqA ()); + } + need_frequency = false; + } + if (readable_params_ & OmniRig::PM_FREQB) + { + if (reversed_) + { + update_rx_frequency (rig_->FreqB ()); + } + else + { + update_other_frequency (rig_->FreqB ()); + } + } + } + if (need_frequency && (readable_params_ & OmniRig::PM_FREQ)) + { + update_rx_frequency (rig_->Freq ()); + } + + if (params & OmniRig::PM_PITCH) + { + } + if (params & OmniRig::PM_RITOFFSET) + { + } + if (params & OmniRig::PM_RIT0) + { + } + if (params & OmniRig::PM_VFOEQUAL) + { + auto f = readable_params_ & OmniRig::PM_FREQA ? rig_->FreqA () : rig_->Freq (); + update_rx_frequency (f); + update_other_frequency (f); + update_mode (map_mode (rig_->Mode ())); + } + if (params & OmniRig::PM_VFOSWAP) + { + auto temp = state ().tx_frequency (); + update_other_frequency (state ().frequency ()); + update_rx_frequency (temp); + update_mode (map_mode (rig_->Mode ())); + } + if (params & OmniRig::PM_SPLITON) + { + update_split (true); + } + if (params & OmniRig::PM_SPLITOFF) + { + update_split (false); + } + if (params & OmniRig::PM_RITON) + { + } + if (params & OmniRig::PM_RITOFF) + { + } + if (params & OmniRig::PM_XITON) + { + } + if (params & OmniRig::PM_XITOFF) + { + } + if (params & OmniRig::PM_RX) + { + update_PTT (false); + } + if (params & OmniRig::PM_TX) + { + update_PTT (); + } + if (params & OmniRig::PM_CW_U) + { + update_mode (CW_R); + } + if (params & OmniRig::PM_CW_L) + { + update_mode (CW); + } + if (params & OmniRig::PM_SSB_U) + { + update_mode (USB); + } + if (params & OmniRig::PM_SSB_L) + { + update_mode (LSB); + } + if (params & OmniRig::PM_DIG_U) + { + update_mode (DIG_U); + } + if (params & OmniRig::PM_DIG_L) + { + update_mode (DIG_L); + } + if (params & OmniRig::PM_AM) + { + update_mode (AM); + } + if (params & OmniRig::PM_FM) + { + update_mode (FM); + } + + if (old_state != state () || send_update_signal_) + { + update_complete (); + send_update_signal_ = false; + } + +#if WSJT_TRACE_CAT + qDebug () + << "OmniRig params change: state after:" << state () + ; +#endif + } +} + +void OmniRigTransceiver::handle_custom_reply (int rig_number, QVariant const& command, QVariant const& reply) +{ + (void)command; + (void)reply; + + if (rig_number_ == rig_number) + { +#if WSJT_TRACE_CAT + qDebug () + << "OmniRig custom command" << command.toString ().toLocal8Bit () + << "with reply" << reply.toString ().toLocal8Bit () + << QString ("for rig %1").arg (rig_number).toLocal8Bit () + ; + + qDebug () << "OmniRig rig number:" << rig_number_ << ':' << state (); +#endif + } +} + +void OmniRigTransceiver::do_ptt (bool on) +{ +#if WSJT_TRACE_CAT + qDebug () << "OmniRigTransceiver::do_ptt:" << on << state (); +#endif + + if (use_for_ptt_ && TransceiverFactory::PTT_method_CAT == ptt_type_) + { +#if WSJT_TRACE_CAT + qDebug () << "OmniRigTransceiver::do_ptt: set PTT"; +#endif + + rig_->SetTx (on ? OmniRig::PM_TX : OmniRig::PM_RX); + } + else + { + if (port_) + { + if (TransceiverFactory::PTT_method_RTS == ptt_type_) + { +#if WSJT_TRACE_CAT + qDebug () << "OmniRigTransceiver::do_ptt: set RTS"; +#endif + port_->SetRts (on); + } + else // "DTR" + { +#if WSJT_TRACE_CAT + qDebug () << "OmniRigTransceiver::do_ptt: set DTR"; +#endif + + port_->SetDtr (on); + } + } + else + { +#if WSJT_TRACE_CAT + qDebug () << "OmniRigTransceiver::do_ptt: set PTT using basic transceiver"; +#endif + + wrapped_->ptt (on); + } + + if (state ().ptt () != on) + { + update_PTT (on); + update_complete (); + } + } +} + +void OmniRigTransceiver::do_frequency (Frequency f) +{ +#if WSJT_TRACE_CAT + qDebug () << "OmniRigTransceiver::do_frequency:" << f << state (); +#endif + + if (OmniRig::PM_FREQ & writable_params_) + { + rig_->SetFreq (f); + update_rx_frequency (f); + } + else if (reversed_ && (OmniRig::PM_FREQB & writable_params_)) + { + rig_->SetFreqB (f); + update_rx_frequency (f); + } + else if (!reversed_ && (OmniRig::PM_FREQA & writable_params_)) + { + rig_->SetFreqA (f); + update_rx_frequency (f); + } + else + { + throw error {"OmniRig: don't know how to set rig frequency"}; + } +} + +void OmniRigTransceiver::do_tx_frequency (Frequency tx, bool /* rationalise_mode */) +{ +#if WSJT_TRACE_CAT + qDebug () << "OmniRigTransceiver::do_tx_frequency:" << tx << state (); +#endif + + bool split {tx != 0}; + + if (split) + { +#if WSJT_TRACE_CAT + qDebug () << "OmniRigTransceiver::do_tx_frequency: set SPLIT mode on"; +#endif + + rig_->SetSplitMode (state ().frequency (), tx); + update_other_frequency (tx); + update_split (true); + } + else + { +#if WSJT_TRACE_CAT + qDebug () << "OmniRigTransceiver::do_tx_frequency: set SPLIT mode off"; +#endif + + rig_->SetSimplexMode (state ().frequency ()); + update_split (false); + } + + bool notify {false}; + + if (readable_params_ & OmniRig::PM_FREQ || !(readable_params_ & (OmniRig::PM_FREQA | OmniRig::PM_FREQB))) + { + update_other_frequency (tx); // async updates won't return this + // so just store it and hope + // operator doesn't change the + // "back" VFO on rig + notify = true; + } + + if (!((OmniRig::PM_VFOAB | OmniRig::PM_VFOBA | OmniRig::PM_SPLITON) & readable_params_)) + { +#if WSJT_TRACE_CAT + qDebug () << "OmniRigTransceiver::do_tx_frequency: setting SPLIT manually"; +#endif + + update_split (split); // we can't read it so just set and + // hope op doesn't change it + notify = true; + } + + if (notify) + { + update_complete (); + } +} + +void OmniRigTransceiver::do_mode (MODE mode, bool /* rationalise */) +{ +#if WSJT_TRACE_CAT + qDebug () << "OmniRigTransceiver::do_mode:" << mode << state (); +#endif + + // TODO: G4WJS OmniRig doesn't seem to have any capability of tracking/setting VFO B mode + + auto mapped = map_mode (mode); + + if (mapped & writable_params_) + { + rig_->SetMode (mapped); + update_mode (mode); + } + else + { + offline ("OmniRig invalid mode"); + } +} diff --git a/OmniRigTransceiver.hpp b/OmniRigTransceiver.hpp new file mode 100644 index 000000000..b875165fa --- /dev/null +++ b/OmniRigTransceiver.hpp @@ -0,0 +1,73 @@ +#ifndef OMNI_RIG_TRANSCEIVER_HPP__ +#define OMNI_RIG_TRANSCEIVER_HPP__ + +#include + +#include +#include + +#include "TransceiverFactory.hpp" +#include "TransceiverBase.hpp" + +#include "OmniRig.h" + +// +// OmniRig Transceiver Interface +// +// Implemented as a Transceiver decorator because we may want the PTT +// services of another Transceiver type such as the HamlibTransceiver +// which can be enabled by wrapping a HamlibTransceiver instantiated +// as a "Hamlib Dummy" transceiver in the Transceiver factory method. +// +class OmniRigTransceiver final + : public TransceiverBase +{ + Q_OBJECT; + +public: + static void register_transceivers (TransceiverFactory::Transceivers *, int id1, int id2); + + enum RigNumber {One = 1, Two}; + + // takes ownership of wrapped Transceiver + explicit OmniRigTransceiver (std::unique_ptr wrapped, RigNumber, TransceiverFactory::PTTMethod ptt_type, QString const& ptt_port); + ~OmniRigTransceiver (); + + void do_start () override; + void do_stop () override; + void do_frequency (Frequency) override; + void do_tx_frequency (Frequency, bool rationalise_mode) override; + void do_mode (MODE, bool rationalise) override; + void do_ptt (bool on) override; + void do_sync (bool force_signal) override; + +private: + Q_SLOT void startup_check (); + Q_SLOT void handle_COM_exception (int, QString, QString, QString); + Q_SLOT void handle_visible_change (); + Q_SLOT void handle_rig_type_change (int rig_number); + Q_SLOT void handle_status_change (int rig_number); + Q_SLOT void handle_params_change (int rig_number, int params); + Q_SLOT void handle_custom_reply (int, QVariant const& command, QVariant const& reply); + + void init_rig (); + + static MODE map_mode (OmniRig::RigParamX param); + static OmniRig::RigParamX map_mode (MODE mode); + + std::unique_ptr wrapped_; + bool use_for_ptt_; + TransceiverFactory::PTTMethod ptt_type_; + unsigned startup_poll_countdown_; + QScopedPointer omni_rig_; + RigNumber rig_number_; + QScopedPointer rig_; + QScopedPointer port_; + int readable_params_; + int writable_params_; + bool send_update_signal_; + bool reversed_; // some rigs can reverse VFOs + bool starting_; +}; + +#endif diff --git a/PollingTransceiver.cpp b/PollingTransceiver.cpp new file mode 100644 index 000000000..51073704a --- /dev/null +++ b/PollingTransceiver.cpp @@ -0,0 +1,209 @@ +#include "PollingTransceiver.hpp" + +#include + +#include +#include +#include + +#include "pimpl_impl.hpp" + +namespace +{ + unsigned const polls_to_stabilize {3}; +} + +// Internal implementation of the PollingTransceiver class. +class PollingTransceiver::impl final + : public QObject +{ + Q_OBJECT; + +private: + Q_DISABLE_COPY (impl); + +public: + impl (PollingTransceiver * self, int poll_interval) + : QObject {self} + , self_ {self} + , interval_ {poll_interval} + , poll_timer_ {nullptr} + , retries_ {0} + { + } + +private: + void start_timer () + { + if (interval_) + { + if (!poll_timer_) + { + poll_timer_ = new QTimer {this}; // pass ownership to QObject which handles destruction for us + + connect (poll_timer_, &QTimer::timeout, this, &PollingTransceiver::impl::handle_timeout); + } + poll_timer_->start (interval_); + } + } + + void stop_timer () + { + if (poll_timer_) + { + poll_timer_->stop (); + } + } + + Q_SLOT void handle_timeout (); + + PollingTransceiver * self_; // our owner so we can call methods + int interval_; // polling interval in milliseconds + QTimer * poll_timer_; + + // keep a record of the last state signalled so we can elide + // duplicate updates + Transceiver::TransceiverState last_signalled_state_; + + // keep a record of expected state so we can compare with actual + // updates to determine when state changes have bubbled through + Transceiver::TransceiverState next_state_; + + unsigned retries_; // number of incorrect polls left + + friend class PollingTransceiver; +}; + +#include "PollingTransceiver.moc" + + +PollingTransceiver::PollingTransceiver (int poll_interval) + : m_ {this, poll_interval} +{ +} + +PollingTransceiver::~PollingTransceiver () +{ +} + +void PollingTransceiver::do_post_start () +{ + m_->start_timer (); + if (!m_->next_state_.online ()) + { + // remember that we are expecting to go online + m_->next_state_.online (true); + m_->retries_ = polls_to_stabilize; + } +} + +void PollingTransceiver::do_post_stop () +{ + // not much point waiting for rig to go offline since we are ceasing + // polls + m_->stop_timer (); +} + +void PollingTransceiver::do_post_frequency (Frequency f) +{ + if (m_->next_state_.frequency () != f) + { + // update expected state with new frequency and set poll count + m_->next_state_.frequency (f); + m_->retries_ = polls_to_stabilize; + } +} + +void PollingTransceiver::do_post_tx_frequency (Frequency f) +{ + if (m_->next_state_.tx_frequency () != f) + { + // update expected state with new TX frequency and set poll + // count + m_->next_state_.tx_frequency (f); + m_->next_state_.split (f); // setting non-zero TX frequency means split + m_->retries_ = polls_to_stabilize; + } +} + +void PollingTransceiver::do_post_mode (MODE m) +{ + if (m_->next_state_.mode () != m) + { + // update expected state with new mode and set poll count + m_->next_state_.mode (m); + m_->retries_ = polls_to_stabilize; + } +} + +bool PollingTransceiver::do_pre_update () +{ + // if we are holding off a change then withhold the signal + if (m_->retries_ && state () != m_->next_state_) + { + return false; + } + return true; +} + +void PollingTransceiver::do_sync (bool force_signal) +{ + poll (); // tell sub-classes to update our + // state + + // Signal new state if it is directly requested or, what we expected + // or, hasn't become what we expected after polls_to_stabilize + // polls. Unsolicited changes will be signalled immediately unless + // they intervene in a expected sequence where they will be delayed. + if (m_->retries_) + { + --m_->retries_; + if (force_signal || state () == m_->next_state_ || !m_->retries_) + { + // our client wants a signal regardless + // or the expected state has arrived + // or there are no more retries + force_signal = true; + } + } + else if (force_signal || state () != m_->last_signalled_state_) + { + // here is the normal passive polling path + // either our client has requested a state update regardless of change + // or sate has changed asynchronously + force_signal = true; + } + + if (force_signal) + { + // reset everything, record and signal the current state + m_->retries_ = 0; + m_->next_state_ = state (); + m_->last_signalled_state_ = state (); + update_complete (); + } +} + +void PollingTransceiver::impl::handle_timeout () +{ + QString message; + + // we must catch all exceptions here since we are called by Qt and + // inform our parent of the failure via the offline() message + try + { + self_->do_sync (false); + } + catch (std::exception const& e) + { + message = e.what (); + } + catch (...) + { + message = "Unexpected rig error"; + } + if (!message.isEmpty ()) + { + self_->offline (message); + } +} diff --git a/PollingTransceiver.hpp b/PollingTransceiver.hpp new file mode 100644 index 000000000..8353eb303 --- /dev/null +++ b/PollingTransceiver.hpp @@ -0,0 +1,60 @@ +#ifndef POLLING_TRANSCEIVER_HPP__ +#define POLLING_TRANSCEIVER_HPP__ + +#include + +#include "TransceiverBase.hpp" + +#include "pimpl_h.hpp" + +// +// Polling Transceiver +// +// Helper base class that encapsulates the emulation of continuous +// update and caching of a transceiver state. +// +// Collaborations +// +// Implements the TransceiverBase post action interface and provides +// the abstract poll() operation for sub-classes to implement. The +// pol operation is invoked every poll_interval milliseconds. +// +// Responsibilities +// +// Because some rig interfaces don't immediately update after a state +// change request; this class allows a rig a few polls to stabilise +// to the requested state before signalling the change. This means +// that clients don't see intermediate states that are sometimes +// inaccurate, e.g. changing the split TX frequency on Icom rigs +// requires a VFO switch and polls while switched will return the +// wrong current frequency. +// +class PollingTransceiver + : public TransceiverBase +{ +protected: + explicit PollingTransceiver (int poll_interval); // in milliseconds + +public: + ~PollingTransceiver (); + +protected: + void do_sync (bool /* force_signal */) override final; + + // Sub-classes implement this and fetch what they can from the rig + // in a non-intrusive manner. + virtual void poll () = 0; + + void do_post_start () override final; + void do_post_stop () override final; + void do_post_frequency (Frequency) override final; + void do_post_tx_frequency (Frequency) override final; + void do_post_mode (MODE) override final; + bool do_pre_update () override final; + +private: + class impl; + pimpl m_; +}; + +#endif diff --git a/Radio.cpp b/Radio.cpp new file mode 100644 index 000000000..d93df3983 --- /dev/null +++ b/Radio.cpp @@ -0,0 +1,72 @@ +#include "Radio.hpp" + +#include + +#include +#include +#include +#include +#include +#include + +namespace Radio +{ + namespace + { + struct init + { + init () + { + qRegisterMetaType ("Frequency"); + + qRegisterMetaType ("Frequencies"); + qRegisterMetaTypeStreamOperators ("Frequencies"); + + qRegisterMetaType ("FrequencyDelta"); + } + } static_initaializer; + + double constexpr MHz_factor {1.e6}; + int constexpr frequency_precsion {6}; + } + + + Frequency frequency (QVariant const& v, int scale) + { + return std::llround (v.toDouble () * std::pow (10., scale)); + } + + FrequencyDelta frequency_delta (QVariant const& v, int scale) + { + return std::llround (v.toDouble () * std::pow (10., scale)); + } + + + QString frequency_MHz_string (Frequency f, QLocale const& locale) + { + return locale.toString (f / MHz_factor, 'f', frequency_precsion); + } + + QString frequency_MHz_string (FrequencyDelta d, QLocale const& locale) + { + return locale.toString (d / MHz_factor, 'f', frequency_precsion); + } + + QString pretty_frequency_MHz_string (Frequency f, QLocale const& locale) + { + auto f_string = locale.toString (f / MHz_factor, 'f', frequency_precsion); + return f_string.insert (f_string.size () - 3, QChar::Nbsp); + } + + QString pretty_frequency_MHz_string (double f, int scale, QLocale const& locale) + { + auto f_string = locale.toString (f / std::pow (10., scale - 6), 'f', frequency_precsion); + return f_string.insert (f_string.size () - 3, QChar::Nbsp); + } + + QString pretty_frequency_MHz_string (FrequencyDelta d, QLocale const& locale) + { + auto d_string = locale.toString (d / MHz_factor, 'f', frequency_precsion); + return d_string.insert (d_string.size () - 3, QChar::Nbsp); + } +} diff --git a/Radio.hpp b/Radio.hpp new file mode 100644 index 000000000..c9e279244 --- /dev/null +++ b/Radio.hpp @@ -0,0 +1,47 @@ +#ifndef RADIO_HPP_ +#define RADIO_HPP_ + +#include +#include +#include + +class QVariant; +class QString; + +// +// Declarations common to radio software. +// + +namespace Radio +{ + // + // Frequency types + // + using Frequency = quint64; + using Frequencies = QList; + using FrequencyDelta = qint64; + + // + // Frequency type conversion. + // + // QVariant argument is convertible to double and is assumed to + // be scaled by (10 ** -scale). + // + Frequency frequency (QVariant const&, int scale); + FrequencyDelta frequency_delta (QVariant const&, int scale); + + // + // Frequency type formatting + // + QString frequency_MHz_string (Frequency, QLocale const& = QLocale ()); + QString frequency_MHz_string (FrequencyDelta, QLocale const& = QLocale ()); + QString pretty_frequency_MHz_string (Frequency, QLocale const& = QLocale ()); + QString pretty_frequency_MHz_string (double, int scale, QLocale const& = QLocale ()); + QString pretty_frequency_MHz_string (FrequencyDelta, QLocale const& = QLocale ()); +} + +Q_DECLARE_METATYPE (Radio::Frequency); +Q_DECLARE_METATYPE (Radio::Frequencies); +Q_DECLARE_METATYPE (Radio::FrequencyDelta); + +#endif diff --git a/SettingsGroup.hpp b/SettingsGroup.hpp new file mode 100644 index 000000000..e728e6c30 --- /dev/null +++ b/SettingsGroup.hpp @@ -0,0 +1,34 @@ +#ifndef SETTINGS_GROUP_HPP_ +#define SETTINGS_GROUP_HPP_ + +#include +#include + +// +// Class SettingsGroup +// +// Simple RAII type class to apply a QSettings group witin a +// scope. +// +class SettingsGroup +{ +public: + SettingsGroup (QSettings * settings, QString const& group) + : settings_ {settings} + { + settings_->beginGroup (group); + } + + SettingsGroup (SettingsGroup const&) = delete; + SettingsGroup& operator = (SettingsGroup const&) = delete; + + ~SettingsGroup () + { + settings_->endGroup (); + } + +private: + QSettings * settings_; +}; + +#endif diff --git a/StationList.cpp b/StationList.cpp new file mode 100644 index 000000000..069dc0730 --- /dev/null +++ b/StationList.cpp @@ -0,0 +1,551 @@ +#include "StationList.hpp" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pimpl_impl.hpp" + +#include "Bands.hpp" + +namespace +{ + struct init + { + init () + { + qRegisterMetaType ("Station"); + qRegisterMetaTypeStreamOperators ("Station"); + qRegisterMetaType ("Stations"); + qRegisterMetaTypeStreamOperators ("Stations"); + } + } static_initializer; +} + +#if !defined (QT_NO_DEBUG_STREAM) +QDebug operator << (QDebug debug, StationList::Station const& station) +{ + debug.nospace () << "Station(" + << station.band_name_ << ", " + << station.offset_ << ", " + << station.antenna_description_ << ')'; + return debug.space (); +} +#endif + +QDataStream& operator << (QDataStream& os, StationList::Station const& station) +{ + return os << station.band_name_ + << station.offset_ + << station.antenna_description_; +} + +QDataStream& operator >> (QDataStream& is, StationList::Station& station) +{ + return is >> station.band_name_ + >> station.offset_ + >> station.antenna_description_; +} + + +class StationList::impl final + : public QAbstractTableModel +{ +public: + impl (Bands const * bands, Stations stations, QObject * parent) + : QAbstractTableModel {parent} + , bands_ {bands} + , stations_ {stations} + { + } + + Stations const& stations () const {return stations_;} + void assign (Stations); + QModelIndex add (Station); + FrequencyDelta offset (Frequency) const; + +protected: + // Implement the QAbstractTableModel interface. + int rowCount (QModelIndex const& parent = QModelIndex {}) const override; + int columnCount (QModelIndex const& parent = QModelIndex {}) const override; + Qt::ItemFlags flags (QModelIndex const& = QModelIndex {}) const override; + QVariant data (QModelIndex const&, int role) const override; + QVariant headerData (int section, Qt::Orientation, int = Qt::DisplayRole) const override; + bool setData (QModelIndex const&, QVariant const& value, int role = Qt::EditRole) override; + bool removeRows (int row, int count, QModelIndex const& parent = QModelIndex {}) override; + bool insertRows (int row, int count, QModelIndex const& parent = QModelIndex {}) override; + Qt::DropActions supportedDropActions () const override; + QStringList mimeTypes () const override; + QMimeData * mimeData (QModelIndexList const&) const override; + bool dropMimeData (QMimeData const *, Qt::DropAction, int row, int column, QModelIndex const& parent) override; + +private: + // Helper method for band validation. + QModelIndex first_matching_band (QString const& band_name) const + { + // find first exact match in bands + auto matches = bands_->match (bands_->index (0, 0) + , Qt::DisplayRole + , band_name + , 1 + , Qt::MatchExactly); + return matches.isEmpty () ? QModelIndex {} : matches.first (); + } + + static int constexpr num_columns {3}; + static auto constexpr mime_type = "application/wsjt.antenna-descriptions"; + + Bands const * bands_; + Stations stations_; +}; + +StationList::StationList (Bands const * bands, QObject * parent) + : StationList {bands, {}, parent} +{ +} + +StationList::StationList (Bands const * bands, Stations stations, QObject * parent) + : QSortFilterProxyModel {parent} + , m_ {bands, stations, parent} +{ + // setDynamicSortFilter (true); + setSourceModel (&*m_); + setSortRole (SortRole); +} + +StationList::~StationList () +{ +} + +StationList& StationList::operator = (Stations stations) +{ + m_->assign (stations); + return *this; +} + +auto StationList::stations () const -> Stations +{ + return m_->stations (); +} + +QModelIndex StationList::add (Station s) +{ + return mapFromSource (m_->add (s)); +} + +bool StationList::remove (Station s) +{ + auto row = m_->stations ().indexOf (s); + + if (0 > row) + { + return false; + } + + return removeRow (row); +} + +namespace +{ + bool row_is_higher (QModelIndex const& lhs, QModelIndex const& rhs) + { + return lhs.row () > rhs.row (); + } +} + +bool StationList::removeDisjointRows (QModelIndexList rows) +{ + bool result {true}; + + // We must work with source model indexes because we don't want row + // removes to invalidate model indexes we haven't yet processed. We + // achieve that by processing them in decending row order. + for (int r = 0; r < rows.size (); ++r) + { + rows[r] = mapToSource (rows[r]); + } + + // reverse sort by row + qSort (rows.begin (), rows.end (), row_is_higher); + Q_FOREACH (auto index, rows) + { + if (result && !m_->removeRow (index.row ())) + { + result = false; + } + } + + return result; +} + +auto StationList::offset (Frequency f) const -> FrequencyDelta +{ + return m_->offset (f); +} + + +void StationList::impl::assign (Stations stations) +{ + beginResetModel (); + std::swap (stations_, stations); + endResetModel (); +} + +QModelIndex StationList::impl::add (Station s) +{ + // Any band that isn't in the list may be added + if (!stations_.contains (s)) + { + auto row = stations_.size (); + + beginInsertRows (QModelIndex {}, row, row); + stations_.append (s); + endInsertRows (); + + return index (row, 0); + } + + return QModelIndex {}; +} + +auto StationList::impl::offset (Frequency f) const -> FrequencyDelta +{ + // Lookup band for frequency + auto band_index = bands_->find (f); + if (band_index.isValid ()) + { + auto band_name = band_index.data ().toString (); + + // Lookup station for band + for (int i = 0; i < stations ().size (); ++i) + { + if (stations_[i].band_name_ == band_name) + { + return stations_[i].offset_; + } + } + } + + return 0; // no offset +} + +int StationList::impl::rowCount (QModelIndex const& parent) const +{ + return parent.isValid () ? 0 : stations_.size (); +} + +int StationList::impl::columnCount (QModelIndex const& parent) const +{ + return parent.isValid () ? 0 : num_columns; +} + +Qt::ItemFlags StationList::impl::flags (QModelIndex const& index) const +{ + auto result = QAbstractTableModel::flags (index); + + auto row = index.row (); + auto column = index.column (); + + if (index.isValid () + && row < stations_.size () + && column < num_columns) + { + if (2 == column) + { + result |= Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; + } + else + { + result |= Qt::ItemIsEditable | Qt::ItemIsDropEnabled; + } + } + else + { + result |= Qt::ItemIsDropEnabled; + } + + return result; +} + +QVariant StationList::impl::data (QModelIndex const& index, int role) const +{ + QVariant item; + + auto row = index.row (); + auto column = index.column (); + + if (index.isValid () + && row < stations_.size ()) + { + switch (column) + { + case 0: // band name + switch (role) + { + case SortRole: + { + // Lookup band. + auto band_index = first_matching_band (stations_.at (row).band_name_); + // Use the sort role value of the band. + item = band_index.data (Bands::SortRole); + } + break; + + case Qt::DisplayRole: + case Qt::EditRole: + case Qt::AccessibleTextRole: + item = stations_.at (row).band_name_; + break; + + case Qt::ToolTipRole: + case Qt::AccessibleDescriptionRole: + item = tr ("Band name"); + break; + + case Qt::TextAlignmentRole: + item = Qt::AlignHCenter + Qt::AlignVCenter; + break; + } + break; + + case 1: // frequency offset + { + auto frequency_offset = stations_.at (row).offset_; + switch (role) + { + case Qt::AccessibleTextRole: + item = frequency_offset; + break; + + case SortRole: + case Qt::DisplayRole: + case Qt::EditRole: + item = frequency_offset; + break; + + case Qt::ToolTipRole: + case Qt::AccessibleDescriptionRole: + item = tr ("Frequency offset"); + break; + + case Qt::TextAlignmentRole: + item = Qt::AlignRight + Qt::AlignVCenter; + break; + } + } + break; + + case 2: // antenna description + switch (role) + { + case SortRole: + case Qt::EditRole: + case Qt::DisplayRole: + case Qt::AccessibleTextRole: + item = stations_.at (row).antenna_description_; + break; + + case Qt::ToolTipRole: + case Qt::AccessibleDescriptionRole: + item = tr ("Antenna description"); + break; + + case Qt::TextAlignmentRole: + item = Qt::AlignLeft + Qt::AlignVCenter; + break; + } + break; + } + } + + return item; +} + +QVariant StationList::impl::headerData (int section, Qt::Orientation orientation, int role) const +{ + QVariant header; + + if (Qt::DisplayRole == role && Qt::Horizontal == orientation) + { + switch (section) + { + case 0: header = tr ("Band"); break; + case 1: header = tr ("Offset"); break; + case 2: header = tr ("Antenna Description"); break; + } + } + else + { + header = QAbstractTableModel::headerData (section, orientation, role); + } + + return header; +} + +bool StationList::impl::setData (QModelIndex const& model_index, QVariant const& value, int role) +{ + bool changed {false}; + + auto row = model_index.row (); + auto size = stations_.size (); + if (model_index.isValid () + && Qt::EditRole == role + && row < size) + { + QVector roles; + roles << role; + + switch (model_index.column ()) + { + case 0: + { + // Check if band name is valid. + auto band_index = first_matching_band (value.toString ()); + if (band_index.isValid ()) + { + stations_[row].band_name_ = band_index.data ().toString (); + Q_EMIT dataChanged (model_index, model_index, roles); + changed = true; + } + } + break; + + case 1: + { + stations_[row].offset_ = value.value (); + Q_EMIT dataChanged (model_index, model_index, roles); + changed = true; + } + break; + + case 2: + stations_[row].antenna_description_ = value.toString (); + Q_EMIT dataChanged (model_index, model_index, roles); + changed = true; + break; + } + } + + return changed; +} + +bool StationList::impl::removeRows (int row, int count, QModelIndex const& parent) +{ + if (0 < count && (row + count) <= rowCount (parent)) + { + beginRemoveRows (parent, row, row + count - 1); + for (auto r = 0; r < count; ++r) + { + stations_.removeAt (row); + } + endRemoveRows (); + return true; + } + + return false; +} + +bool StationList::impl::insertRows (int row, int count, QModelIndex const& parent) +{ + if (0 < count) + { + beginInsertRows (parent, row, row + count - 1); + for (auto r = 0; r < count; ++r) + { + stations_.insert (row, Station ()); + } + endInsertRows (); + return true; + } + + return false; +} + +Qt::DropActions StationList::impl::supportedDropActions () const +{ + return Qt::CopyAction | Qt::MoveAction; +} + +QStringList StationList::impl::mimeTypes () const +{ + QStringList types; + types << mime_type; + types << "application/wsjt.Frequencies"; + return types; +} + +QMimeData * StationList::impl::mimeData (QModelIndexList const& items) const +{ + QMimeData * mime_data = new QMimeData {}; + QByteArray encoded_data; + QDataStream stream {&encoded_data, QIODevice::WriteOnly}; + + Q_FOREACH (auto const& item, items) + { + if (item.isValid ()) + { + stream << QString {data (item, Qt::DisplayRole).toString ()}; + } + } + + mime_data->setData (mime_type, encoded_data); + return mime_data; +} + +bool StationList::impl::dropMimeData (QMimeData const * data, Qt::DropAction action, int /* row */, int /* column */, QModelIndex const& parent) +{ + if (Qt::IgnoreAction == action) + { + return true; + } + + if (parent.isValid () + && 2 == parent.column () + && data->hasFormat (mime_type)) + { + QByteArray encoded_data {data->data (mime_type)}; + QDataStream stream {&encoded_data, QIODevice::ReadOnly}; + auto dest_index = parent; + while (!stream.atEnd ()) + { + QString text; + stream >> text; + setData (dest_index, text); + dest_index = index (dest_index.row () + 1, dest_index.column (), QModelIndex {}); + } + return true; + } + else if (data->hasFormat ("application/wsjt.Frequencies")) + { + QByteArray encoded_data {data->data ("application/wsjt.Frequencies")}; + QDataStream stream {&encoded_data, QIODevice::ReadOnly}; + while (!stream.atEnd ()) + { + QString frequency_string; + stream >> frequency_string; + auto frequency = Radio::frequency (frequency_string, 0); + auto band_index = bands_->find (frequency); + if (stations_.cend () == std::find_if (stations_.cbegin () + , stations_.cend () + , [&band_index] (Station const& s) {return s.band_name_ == band_index.data ().toString ();})) + { + add (Station {band_index.data ().toString (), 0, QString {}}); + } + } + + return true; + } + + return false; +} diff --git a/StationList.hpp b/StationList.hpp new file mode 100644 index 000000000..389719629 --- /dev/null +++ b/StationList.hpp @@ -0,0 +1,96 @@ +#ifndef STATION_LIST_HPP__ +#define STATION_LIST_HPP__ + +#include +#include +#include + +#include "pimpl_h.hpp" + +#include "Radio.hpp" + +class Bands; + +// +// Class StationList +// +// Encapsulates information about a collection of unique operating +// stations per band. The implementation is a table model with the +// first column being the unique (within the table rows) band name +// and, the second the frequency offset for transverter usage and, +// the third the antenna description. All are editable. +// +// Responsibilities +// +// Stores internally an unordered table of bands. +// +// If an ordered representaion is required then wrapping with an +// appropriate proxy model is sufficient +// e.g. QSortFilterProxyModel. A custom SortRole role is provided for +// the band name column which returns a numeric value (Bands lower +// frequency limit) which gives a strict frequency ordering by band. +// +// Collaborations +// +// Implements the QAbstractTableModel interface for a grid of bands +// with offset frequencies and antenna descriptions. +// +// Uses the QAbstractItemModel interface of the bands model to lookup +// band information. +// +class StationList final + : public QSortFilterProxyModel +{ +public: + using Frequency = Radio::Frequency; + using FrequencyDelta = Radio::FrequencyDelta; + + // + // Struct Station + // + // Aggregation of fields that describe a radio station on a band. + // + struct Station + { + QString band_name_; + FrequencyDelta offset_; + QString antenna_description_; + }; + + using Stations = QList; + + explicit StationList (Bands const * bands, QObject * parent = nullptr); + explicit StationList (Bands const * bands, Stations, QObject * parent = nullptr); + ~StationList (); + + // Load and store contents. + StationList& operator = (Stations); + Stations stations () const; + + // + // Model API + // + QModelIndex add (Station); // Add a new Station + bool remove (Station); // Remove a Station + bool removeDisjointRows (QModelIndexList); // Remove one or more stations + FrequencyDelta offset (Frequency) const; // Return the offset to be used for a Frequency + + // Custom sort role. + static int constexpr SortRole = Qt::UserRole; + +private: + class impl; + pimpl m_; +}; + +// Station equivalence is based on band name alone. +inline +bool operator == (StationList::Station const& lhs, StationList::Station const& rhs) +{ + return lhs.band_name_ == rhs.band_name_; +} + +Q_DECLARE_METATYPE (StationList::Station); +Q_DECLARE_METATYPE (StationList::Stations); + +#endif diff --git a/TestConfiguration.cpp b/TestConfiguration.cpp new file mode 100644 index 000000000..da41cbd27 --- /dev/null +++ b/TestConfiguration.cpp @@ -0,0 +1,470 @@ +#include "TestConfiguration.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Bands.hpp" +#include "FrequencyList.hpp" +#include "Configuration.hpp" +#include "LiveFrequencyValidator.hpp" + +#include "pimpl_impl.hpp" + +#include "ui_TestConfiguration.h" + +namespace +{ + char const * const title = "Configuration Test v" WSJTX_STRINGIZE (CONFIG_TEST_VERSION_MAJOR) "." WSJTX_STRINGIZE (CONFIG_TEST_VERSION_MINOR) "." WSJTX_STRINGIZE (CONFIG_TEST_VERSION_PATCH) ", " WSJTX_STRINGIZE (SVNVERSION); + + // these undocumented flag values when stored in (Qt::UserRole - 1) + // of a ComboBox item model index allow the item to be enabled or + // disabled + int const combo_box_item_enabled (32 | 1); + int const combo_box_item_disabled (0); + + auto LCD_error = "-- Error --"; +} + +class status_bar_frequency final + : public QLabel +{ +public: + status_bar_frequency (QString const& prefix, QWidget * parent = 0) + : QLabel {parent} + , prefix_ {prefix} + { + } + + void setText (QString const& text) + { + QLabel::setText (prefix_ + " Frequency: " + text); + } + +private: + QString prefix_; +}; + +class TestConfiguration::impl final + : public QMainWindow +{ + Q_OBJECT; + +public: + using Frequency = Radio::Frequency; + + explicit impl (QString const& instance_key, QSettings *, QWidget * parent = nullptr); + + void closeEvent (QCloseEvent *) override; + + Q_SIGNAL void new_frequency (Frequency) const; + Q_SIGNAL void new_tx_frequency (Frequency = 0, bool rationalise_mode = true) const; + +private: + Q_SLOT void on_configuration_action_triggered (); + Q_SLOT void on_band_combo_box_activated (int); + Q_SLOT void on_mode_combo_box_activated (int); + Q_SLOT void on_PTT_push_button_clicked (bool); + Q_SLOT void on_split_push_button_clicked (bool); + Q_SLOT void on_TX_offset_spin_box_valueChanged (int); + Q_SLOT void on_sync_push_button_clicked (bool); + + Q_SLOT void handle_transceiver_update (Transceiver::TransceiverState); + Q_SLOT void handle_transceiver_failure (QString); + + void information_message_box (QString const& reason, QString const& detail); + void read_settings (); + void write_settings (); + void load_models (); + void sync_rig (); + void band_changed (Frequency); + void frequency_changed (Frequency); + + Ui::test_configuration_main_window * ui_; + QSettings * settings_; + QString callsign_; + Configuration configuration_dialog_; + bool updating_models_; // hold off UI reaction while adjusting models + bool band_edited_; + + Transceiver::TransceiverState rig_state_; + + Frequency desired_frequency_; + + status_bar_frequency RX_frequency_; + status_bar_frequency TX_frequency_; +}; + +#include "TestConfiguration.moc" + +TestConfiguration::TestConfiguration (QString const& instance_key, QSettings * settings, QWidget * parent) + : m_ {instance_key, settings, parent} +{ +} + +TestConfiguration::~TestConfiguration () +{ +} + +TestConfiguration::impl::impl (QString const& instance_key, QSettings * settings, QWidget * parent) + : QMainWindow {parent} + , ui_ {new Ui::test_configuration_main_window} + , settings_ {settings} + , configuration_dialog_ {instance_key, settings, this} + , updating_models_ {false} + , band_edited_ {false} + , desired_frequency_ {0u} + , RX_frequency_ {"RX"} + , TX_frequency_ {"TX"} +{ + ui_->setupUi (this); + + setWindowTitle (QApplication::applicationName () + " - " + title); + + // mode "Unknown" is display only + ui_->mode_combo_box->setItemData (ui_->mode_combo_box->findText ("Unknown"), combo_box_item_disabled, Qt::UserRole - 1); + + // setup status bar widgets + statusBar ()->insertPermanentWidget (0, &TX_frequency_); + statusBar ()->insertPermanentWidget (0, &RX_frequency_); + + // assign push button ids + ui_->TX_button_group->setId (ui_->vfo_0_TX_push_button, 0); + ui_->TX_button_group->setId (ui_->vfo_1_TX_push_button, 1); + + // enable live band combo box entry validation and action + auto band_validator = new LiveFrequencyValidator {ui_->band_combo_box + , configuration_dialog_.bands () + , configuration_dialog_.frequencies () + , this}; + ui_->band_combo_box->setValidator (band_validator); + connect (band_validator, &LiveFrequencyValidator::valid, this, &TestConfiguration::impl::band_changed); + connect (ui_->band_combo_box->lineEdit (), &QLineEdit::textEdited, [this] (QString const&) {band_edited_ = true;}); + + // hook up band data model + ui_->band_combo_box->setModel (configuration_dialog_.frequencies ()); + + // combo box drop downs are limited to the drop down selector width, + // this almost random increase improves the situation + ui_->band_combo_box->view ()->setMinimumWidth (ui_->band_combo_box->view ()->sizeHintForColumn (0) + 10); + + // hook up configuration signals + connect (&configuration_dialog_, &Configuration::transceiver_update, this, &TestConfiguration::impl::handle_transceiver_update); + connect (&configuration_dialog_, &Configuration::transceiver_failure, this, &TestConfiguration::impl::handle_transceiver_failure); + + // hook up configuration slots + connect (this, &TestConfiguration::impl::new_frequency, &configuration_dialog_, &Configuration::transceiver_frequency); + connect (this, &TestConfiguration::impl::new_tx_frequency, &configuration_dialog_, &Configuration::transceiver_tx_frequency); + + load_models (); + + read_settings (); + + show (); +} + +void TestConfiguration::impl::closeEvent (QCloseEvent * e) +{ + write_settings (); + + QMainWindow::closeEvent (e); +} + +void TestConfiguration::impl::on_configuration_action_triggered () +{ + qDebug () << "TestConfiguration::on_configuration_action_triggered"; + if (QDialog::Accepted == configuration_dialog_.exec ()) + { + qDebug () << "TestConfiguration::on_configuration_action_triggered: Configuration changed"; + qDebug () << "TestConfiguration::on_configuration_action_triggered: rig is" << configuration_dialog_.rig_name (); + + if (configuration_dialog_.restart_audio_input ()) + { + qDebug () << "Audio Device Changes - Configuration changes require an audio input device to be restarted"; + } + if (configuration_dialog_.restart_audio_output ()) + { + qDebug () << "Audio Device Changes - Configuration changes require an audio output device to be restarted"; + } + + load_models (); + } + else + { + qDebug () << "TestConfiguration::on_configuration_action_triggered: Confiugration changes cancelled"; + } +} + +void TestConfiguration::impl::on_band_combo_box_activated (int index) +{ + qDebug () << "TestConfiguration::on_band_combo_box_activated: " << ui_->band_combo_box->currentText (); + + auto model = configuration_dialog_.frequencies (); + auto value = model->data (model->index (index, 2), Qt::DisplayRole).toString (); + + if (configuration_dialog_.bands ()->data (QModelIndex {}).toString () == value) + { + ui_->band_combo_box->lineEdit ()->setStyleSheet ("QLineEdit {color: yellow; background-color : red;}"); + } + else + { + ui_->band_combo_box->lineEdit ()->setStyleSheet ({}); + } + + ui_->band_combo_box->setCurrentText (value); + + auto f = model->data (model->index (index, 0), Qt::UserRole + 1).value (); + + band_edited_ = true; + band_changed (f); +} + +void TestConfiguration::impl::band_changed (Frequency f) +{ + if (band_edited_) + { + band_edited_ = false; + frequency_changed (f); + sync_rig (); + } +} + +void TestConfiguration::impl::frequency_changed (Frequency f) +{ + desired_frequency_ = f; + + // lookup band + auto bands_model = configuration_dialog_.bands (); + ui_->band_combo_box->setCurrentText (bands_model->data (bands_model->find (f)).toString ()); +} + +void TestConfiguration::impl::on_sync_push_button_clicked (bool /* checked */) +{ + qDebug () << "TestConfiguration::on_sync_push_button_clicked"; + + auto model = configuration_dialog_.frequencies (); + auto model_index = model->index (ui_->band_combo_box->currentIndex (), 0); + desired_frequency_ = model->data (model_index, Qt::UserRole + 1).value (); + + sync_rig (); +} + +void TestConfiguration::impl::on_mode_combo_box_activated (int index) +{ + qDebug () << "TestConfiguration::on_vfo_A_mode_combo_box_activated: " << static_cast (index); + + // reset combo box back to current mode and let status update do the actual change + ui_->mode_combo_box->setCurrentIndex (rig_state_.mode ()); + + Q_EMIT configuration_dialog_.transceiver_mode (static_cast (index)); +} + +void TestConfiguration::impl::on_TX_offset_spin_box_valueChanged (int value) +{ + qDebug () << "TestConfiguration::on_TX_offset_spin_box_editingFinished: " << value; + + Q_EMIT new_tx_frequency (rig_state_.frequency () + value); +} + +void TestConfiguration::impl::on_PTT_push_button_clicked (bool checked) +{ + qDebug () << "TestConfiguration::on_PTT_push_button_clicked: " << (checked ? "true" : "false"); + + // reset button and let status update do the actual checking + ui_->PTT_push_button->setChecked (rig_state_.ptt ()); + + Q_EMIT configuration_dialog_.transceiver_ptt (checked); +} + +void TestConfiguration::impl::on_split_push_button_clicked (bool checked) +{ + qDebug () << "TestConfiguration::on_split_push_button_clicked: " << (checked ? "true" : "false"); + + // reset button and let status update do the actual checking + ui_->split_push_button->setChecked (rig_state_.split ()); + + if (checked) + { + Q_EMIT new_tx_frequency (rig_state_.frequency () + ui_->TX_offset_spin_box->value ()); + } + else + { + Q_EMIT new_tx_frequency (); + } +} + +void TestConfiguration::impl::sync_rig () +{ + if (!updating_models_) + { + if (configuration_dialog_.transceiver_online (true)) + { + if (configuration_dialog_.split_mode ()) + { + Q_EMIT new_frequency (desired_frequency_); + Q_EMIT new_tx_frequency (desired_frequency_ + ui_->TX_offset_spin_box->value ()); + } + else + { + Q_EMIT new_frequency (desired_frequency_); + Q_EMIT new_tx_frequency (); + } + } + } +} + +void TestConfiguration::impl::handle_transceiver_update (Transceiver::TransceiverState s) +{ + rig_state_ = s; + + auto model = configuration_dialog_.frequencies (); + bool valid {false}; + for (int row = 0; row < model->rowCount (); ++row) + { + auto working_frequency = model->data (model->index (row, 0), Qt::UserRole + 1).value (); + if (std::abs (static_cast (working_frequency - s.frequency ())) < 10000) + { + valid = true; + } + } + if (!valid) + { + ui_->vfo_0_lcd_number->setStyleSheet ("QLCDNumber {background-color: red;}"); + } + else + { + ui_->vfo_0_lcd_number->setStyleSheet (QString {}); + } + + ui_->vfo_0_lcd_number->display (Radio::pretty_frequency_MHz_string (s.frequency ())); + + if (s.split ()) + { + ui_->vfo_1_lcd_number->display (Radio::pretty_frequency_MHz_string (s.tx_frequency ())); + + valid = false; + for (int row = 0; row < model->rowCount (); ++row) + { + auto working_frequency = model->data (model->index (row, 0), Qt::UserRole + 1).value (); + if (std::abs (static_cast (working_frequency - s.tx_frequency ())) < 10000) + { + valid = true; + } + } + if (!valid) + { + ui_->vfo_1_lcd_number->setStyleSheet ("QLCDNumber {background-color: red;}"); + } + else + { + ui_->vfo_1_lcd_number->setStyleSheet (QString {}); + } + ui_->vfo_1_lcd_number->show (); + ui_->vfo_1_TX_push_button->show (); + } + else + { + ui_->vfo_1_lcd_number->hide (); + ui_->vfo_1_TX_push_button->hide (); + } + + frequency_changed (s.frequency ()); + + ui_->radio_widget->setEnabled (s.online ()); + + ui_->mode_combo_box->setCurrentIndex (s.mode ()); + + RX_frequency_.setText (Radio::pretty_frequency_MHz_string (s.frequency ())); + TX_frequency_.setText (Radio::pretty_frequency_MHz_string (s.split () ? s.tx_frequency () : s.frequency ())); + + ui_->TX_button_group->button (s.split ())->setChecked (true); + + ui_->PTT_push_button->setChecked (s.ptt ()); + + ui_->split_push_button->setChecked (s.split ()); + + ui_->radio_widget->setEnabled (s.online ()); +} + +void TestConfiguration::impl::handle_transceiver_failure (QString reason) +{ + ui_->radio_widget->setEnabled (false); + + ui_->vfo_0_lcd_number->display (LCD_error); + ui_->vfo_1_lcd_number->display (LCD_error); + information_message_box ("Rig failure", reason); +} + +void TestConfiguration::impl::read_settings () +{ + settings_->beginGroup ("TestConfiguration"); + resize (settings_->value ("window/size", size ()).toSize ()); + move (settings_->value ("window/pos", pos ()).toPoint ()); + restoreState (settings_->value ("window/state", saveState ()).toByteArray ()); + ui_->band_combo_box->setCurrentText (settings_->value ("Band").toString ()); + settings_->endGroup (); + + settings_->beginGroup ("Configuration"); + callsign_ = settings_->value ("MyCall").toString (); + settings_->endGroup (); +} + +void TestConfiguration::impl::write_settings () +{ + settings_->beginGroup ("TestConfiguration"); + settings_->setValue ("window/size", size ()); + settings_->setValue ("window/pos", pos ()); + settings_->setValue ("window/state", saveState ()); + settings_->setValue ("Band", ui_->band_combo_box->currentText ()); + settings_->endGroup (); +} + +void TestConfiguration::impl::load_models () +{ + updating_models_ = true; + + ui_->frequency_group_box->setTitle (configuration_dialog_.rig_name ()); + // if (auto rig = configuration_dialog_.rig (false)) // don't open radio + if (configuration_dialog_.transceiver_online (false)) // don't open radio + { + Q_EMIT configuration_dialog_.sync_transceiver (true); + } + else + { + ui_->radio_widget->setEnabled (false); + ui_->vfo_0_lcd_number->display (Radio::pretty_frequency_MHz_string (static_cast (0))); + ui_->vfo_1_lcd_number->display (Radio::pretty_frequency_MHz_string (static_cast (0))); + } + + if (!configuration_dialog_.split_mode ()) + { + ui_->vfo_1_lcd_number->hide (); + ui_->vfo_1_TX_push_button->hide (); + } + + updating_models_ = false; +} + +void TestConfiguration::impl::information_message_box (QString const& reason, QString const& detail) +{ + qDebug () << "TestConfiguration::information_message_box: reason =" << reason << "detail =" << detail; + QMessageBox mb; + mb.setWindowFlags (mb.windowFlags () | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint); + mb.setText (reason); + if (!detail.isEmpty ()) + { + mb.setDetailedText (detail); + } + mb.setStandardButtons (QMessageBox::Ok); + mb.setDefaultButton (QMessageBox::Ok); + mb.setIcon (QMessageBox::Information); + mb.exec (); +} diff --git a/TestConfiguration.hpp b/TestConfiguration.hpp new file mode 100644 index 000000000..428afef6f --- /dev/null +++ b/TestConfiguration.hpp @@ -0,0 +1,21 @@ +#ifndef TEST_CONFIGURATION_HPP_ +#define TEST_CONFIGURATION_HPP_ + +#include "pimpl_h.hpp" + +class QString; +class QSettings; +class QWidget; + +class TestConfiguration final +{ + public: + explicit TestConfiguration (QString const& instance_key, QSettings *, QWidget * parent = nullptr); + ~TestConfiguration (); + + private: + class impl; + pimpl m_; +}; + +#endif diff --git a/TestConfiguration.ui b/TestConfiguration.ui new file mode 100644 index 000000000..89c206f47 --- /dev/null +++ b/TestConfiguration.ui @@ -0,0 +1,627 @@ + + + test_configuration_main_window + + + + 0 + 0 + 550 + 227 + + + + + 0 + 0 + + + + + 550 + 227 + + + + Configuration Test + + + + + + + true + + + + 1 + 0 + + + + + + + true + + + + 1 + 0 + + + + Frequency + + + + + + + 1 + 0 + + + + + 11 + + + + 12 + + + + + + + + 1 + 0 + + + + + 11 + + + + 12 + + + + + + + false + + + + 0 + 0 + + + + + 20 + 20 + + + + + 20 + 20 + + + + QPushButton { + border: 2px solid #8f8f91; + border-radius: 6px; + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #f6f7fa, stop: 1 #dadbde); + min-width: 16px; +} + +QPushButton:checked { + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #ff2a2e, stop: 1 #ffc6ca); +} + +QPushButton:flat { + border: none; /* no border for a flat push button */ +} + +QPushButton:default { + border-color: navy; /* make the default button prominent */ +} + + + + + + true + + + true + + + true + + + TX_button_group + + + + + + + false + + + + 0 + 0 + + + + + 20 + 20 + + + + + 20 + 20 + + + + QPushButton { + border: 2px solid #8f8f91; + border-radius: 6px; + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #f6f7fa, stop: 1 #dadbde); + min-width: 16px; +} + +QPushButton:checked { + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #ff2a2e, stop: 1 #ffc6ca); +} + +QPushButton:flat { + border: none; /* no border for a flat push button */ +} + +QPushButton:default { + border-color: navy; /* make the default button prominent */ +} + + + + + + true + + + false + + + true + + + TX_button_group + + + + + + + + + + + 0 + 0 + + + + Mode + + + + + + + 0 + 0 + + + + 0 + + + + Unknown + + + + + CW + + + + + CW_R + + + + + USB + + + + + LSB + + + + + FSK + + + + + FSK_R + + + + + DIG_U + + + + + DIG_L + + + + + AM + + + + + FM + + + + + DIG_FM + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + QPushButton { + border: 2px solid #8f8f91; + border-radius: 6px; + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #9aff9a, stop: 1 #2aff2e); + min-width: 80px; +} + +QPushButton:checked { + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #ff2b2e, stop: 1 #ff979a); +} + +QPushButton:flat { + border: none; /* no border for a flat push button */ +} + +QPushButton:default { + border-color: navy; /* make the default button prominent */ +} + + + PTT + + + true + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 0 + 0 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + QPushButton { + border: 2px solid #8f8f91; + border-radius: 6px; + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #9aff9a, stop: 1 #2aff2e); + min-width: 80px; +} + +QPushButton:checked { + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0 #ff2b2e, stop: 1 #ff979a); +} + +QPushButton:flat { + border: none; /* no border for a flat push button */ +} + +QPushButton:default { + border-color: navy; /* make the default button prominent */ +} + + + Split + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 0 + + + + Split Offset: + + + TX_offset_spin_box + + + + + + + + 0 + 0 + + + + Hz + + + -10000 + + + 10000 + + + 100 + + + + + + + + + + + + + + + + Band: + + + band_combo_box + + + + + + + + 0 + 0 + + + + + 100 + 0 + + + + true + + + QComboBox::NoInsert + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Sync + + + + + + + + + + + 0 + 0 + 550 + 20 + + + + + &File + + + + + + &Options + + + + + + + + + + toolBar + + + TopToolBarArea + + + false + + + + + E&xit + + + + + &Configuration + + + + + + + exit_action + triggered() + test_configuration_main_window + close() + + + -1 + -1 + + + 261 + 214 + + + + + + + + diff --git a/TraceFile.cpp b/TraceFile.cpp new file mode 100644 index 000000000..022a020d7 --- /dev/null +++ b/TraceFile.cpp @@ -0,0 +1,118 @@ +#include "TraceFile.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pimpl_impl.hpp" + +namespace +{ + QMutex lock; +} + +class TraceFile::impl +{ +public: + impl (QString const& trace_file_path); + ~impl (); + + // no copying + impl (impl const&) = delete; + impl& operator = (impl const&) = delete; + +private: + // write Qt messages to the diagnostic log file + static void message_handler (QtMsgType type, QMessageLogContext const& context, QString const& msg); + + QFile file_; + QTextStream stream_; + QTextStream * original_stream_; + QtMessageHandler original_handler_; + static QTextStream * current_stream_; +}; + +QTextStream * TraceFile::impl::current_stream_; + + +// delegate to implementation class +TraceFile::TraceFile (QString const& trace_file_path) + : m_ {trace_file_path} +{ +} + +TraceFile::~TraceFile () +{ +} + + +TraceFile::impl::impl (QString const& trace_file_path) + : file_ {trace_file_path} + , original_stream_ {current_stream_} + , original_handler_ {nullptr} +{ + // if the log file is writeable; initialise diagnostic logging to it + // for append and hook up the Qt global message handler + if (file_.open (QFile::WriteOnly | QFile::Append | QFile::Text)) + { + stream_.setDevice (&file_); + current_stream_ = &stream_; + original_handler_ = qInstallMessageHandler (message_handler); + } +} + +TraceFile::impl::~impl () +{ + // unhook our message handler before the stream and file are destroyed + if (original_handler_) + { + qInstallMessageHandler (original_handler_); + } + current_stream_ = original_stream_; // revert to prior stream +} + +// write Qt messages to the diagnostic log file +void TraceFile::impl::message_handler (QtMsgType type, QMessageLogContext const& context, QString const& msg) +{ + char const * severity; + switch (type) + { + case QtDebugMsg: + severity = "Debug"; + break; + + case QtWarningMsg: + severity = "Warning"; + break; + + case QtFatalMsg: + severity = "Fatal"; + break; + + default: + severity = "Critical"; + break; + } + + { + // guard against multiple threads with overlapping messages + QMutexLocker guard (&lock); + Q_ASSERT_X (current_stream_, "TraceFile:message_handler", "no stream to write to"); + *current_stream_ + << QDateTime::currentDateTimeUtc ().toString () + << '(' << context.file << ':' << context.line /* << ", " << context.function */ << ')' + << severity << ": " << msg.trimmed () << endl; + } + + if (QtFatalMsg == type) + { + throw std::runtime_error {"Fatal Qt Error"}; + } +} diff --git a/TraceFile.hpp b/TraceFile.hpp new file mode 100644 index 000000000..6a27b842f --- /dev/null +++ b/TraceFile.hpp @@ -0,0 +1,23 @@ +#ifndef TRACE_FILE_HPP_ +#define TRACE_FILE_HPP_ + +#include "pimpl_h.hpp" + +class QString; + +class TraceFile final +{ +public: + explicit TraceFile (QString const& TraceFile_file_path); + ~TraceFile (); + + // copying not allowed + TraceFile (TraceFile const&) = delete; + TraceFile& operator = (TraceFile const&) = delete; + +private: + class impl; + pimpl m_; +}; + +#endif diff --git a/Transceiver.cpp b/Transceiver.cpp new file mode 100644 index 000000000..2665a2783 --- /dev/null +++ b/Transceiver.cpp @@ -0,0 +1,51 @@ +#include "Transceiver.hpp" + +#include "moc_Transceiver.cpp" + +namespace +{ + struct init + { + init () + { + qRegisterMetaType ("Transceiver::TransceiverState"); + qRegisterMetaType ("Transceiver::MODE"); + } + } static_initialization; +} + +#if !defined (QT_NO_DEBUG_STREAM) + +ENUM_QDEBUG_OPS_IMPL (Transceiver, MODE); + +QDebug operator << (QDebug d, Transceiver::TransceiverState const& s) +{ + d.nospace () + << "Transceiver::TransceiverState(online: " << (s.online_ ? "yes" : "no") + << " Frequency {" << s.frequency_[0] << "Hz, " << s.frequency_[1] << "Hz} " << s.mode_ + << "; SPLIT: " << (Transceiver::TransceiverState::on == s.split_ ? "on" : Transceiver::TransceiverState::off == s.split_ ? "off" : "unknown") + << "; PTT: " << (s.ptt_ ? "on" : "off") + << ')'; + return d.space (); +} + +#endif + +ENUM_QDATASTREAM_OPS_IMPL (Transceiver, MODE); + +ENUM_CONVERSION_OPS_IMPL (Transceiver, MODE); + +bool operator != (Transceiver::TransceiverState const& lhs, Transceiver::TransceiverState const& rhs) +{ + return lhs.online_ != rhs.online_ + || lhs.frequency_[0] != rhs.frequency_[0] + || lhs.frequency_[1] != rhs.frequency_[1] + || lhs.mode_ != rhs.mode_ + || lhs.split_ != rhs.split_ + || lhs.ptt_ != rhs.ptt_; +} + +bool operator == (Transceiver::TransceiverState const& lhs, Transceiver::TransceiverState const& rhs) +{ + return !(lhs != rhs); +} diff --git a/Transceiver.hpp b/Transceiver.hpp new file mode 100644 index 000000000..b30150552 --- /dev/null +++ b/Transceiver.hpp @@ -0,0 +1,169 @@ +#ifndef TRANSCEIVER_HPP__ +#define TRANSCEIVER_HPP__ + +#include + +#include "qt_helpers.hpp" +#include "Radio.hpp" + +class QString; + +// +// Abstract Transceiver Interface +// +// This is the minimal generic interface to a rig as required by +// wsjtx. +// +// Responsibilities +// +// Provides Qt slots to set the frequency, mode and PTT of some +// transceiver. They are Qt slots so that they may be invoked across +// a thread boundary. +// +// Provides a synchronisation Qt slot which should be implemented in +// sub-classes in such a way that normal operation of the rig is not +// disturbed. This is intended to be use to poll rig state +// periodically and changing VFO to read the other VFO frequency or +// mode for example should not be done since the operator may be +// tuning the VFO at the time and would be surprised by an unprompted +// VFO change. +// +// Provides a control interface using Qt slots to start and stop the +// rig control and PTT connections. +// +// These are Qt slots rather than the constructor and destructor +// because it is expected that the concrete Transceiver +// implementations will run in a separate thread from where they are +// constructed. +// +// Qt signals are defined to notify clients of asynchronous rig state +// changes and failures. These can and are expected to cross thread +// boundaries. +// +// A signal finished() is defined that concrete Transceiver +// implementations must emit when they are ripe for destruction. This +// is intended to be used by clients that move the Transceiver +// instance to a thread and need to use QObject::deleteLater() to +// safely dispose of the Transceiver instance. Implementations should +// expect Qt slot calls after emitting finished, it is up to the +// implementation whether these slot invocations are ignored. +// +class Transceiver + : public QObject +{ + Q_OBJECT; + Q_ENUMS (MODE); + +public: + using Frequency = Radio::Frequency; + +protected: + Transceiver () + { + } + +public: + virtual ~Transceiver () + { + } + + enum MODE {UNK, CW, CW_R, USB, LSB, FSK, FSK_R, DIG_U, DIG_L, AM, FM, DIG_FM}; + + // + // Aggregation of all of the rig and PTT state accessible via this + // interface. + class TransceiverState + { + public: + TransceiverState () + : online_ {false} + , frequency_ {0, 0} + , mode_ {UNK} + , split_ {unknown} + , ptt_ {false} + { + } + + bool online () const {return online_;} + Frequency frequency () const {return frequency_[0];} + Frequency tx_frequency () const {return frequency_[1];} + bool split () const {return on == split_;} + MODE mode () const {return mode_;} + bool ptt () const {return ptt_;} + + void online (bool state) {online_ = state;} + void frequency (Frequency f) {frequency_[0] = f;} + void tx_frequency (Frequency f) {frequency_[1] = f;} + void split (bool state) {split_ = state ? on : off;} + void mode (MODE m) {mode_ = m;} + void ptt (bool state) {ptt_ = state;} + + private: + bool online_; + Frequency frequency_[2]; // [0] -> Rx; [1] -> Other + MODE mode_; + enum {unknown, off, on} split_; + bool ptt_; + // Don't forget to update the debug print and != operator if you + // add more members here + + friend QDebug operator << (QDebug, TransceiverState const&); + friend bool operator != (TransceiverState const&, TransceiverState const&); + }; + + // + // The following slots and signals are expected to all run in the + // same thread which is not necessarily the main GUI thread. It is + // up to the client of the Transceiver class to organise the + // allocation to a thread and the lifetime of the object instances. + // + + // Connect and disconnect. + Q_SLOT virtual void start () noexcept = 0; + Q_SLOT virtual void stop () noexcept = 0; + + // Ready to be destroyed. + Q_SIGNAL void finished () const; + + // Set frequency in Hertz. + Q_SLOT virtual void frequency (Frequency) noexcept = 0; + + // Setting a non-zero TX frequency means split operation, the value + // zero means simplex operation. + // + // Rationalise_mode means ensure TX uses same mode as RX. + Q_SLOT virtual void tx_frequency (Frequency tx = 0, bool rationalise_mode = true) noexcept = 0; + + // Set mode. + // Rationalise means ensure TX uses same mode as RX. + Q_SLOT virtual void mode (MODE, bool rationalise = true) noexcept = 0; + + // Set/unset PTT. + Q_SLOT virtual void ptt (bool = true) noexcept = 0; + + // Attempt to re-synchronise or query state. + // Force_signal guarantees a update or failure signal. + Q_SLOT virtual void sync (bool force_signal = false) noexcept = 0; + + // asynchronous status updates + Q_SIGNAL void update (Transceiver::TransceiverState) const; + Q_SIGNAL void failure (QString reason) const; +}; + +Q_DECLARE_METATYPE (Transceiver::TransceiverState); +Q_DECLARE_METATYPE (Transceiver::MODE); + +#if !defined (QT_NO_DEBUG_STREAM) +ENUM_QDEBUG_OPS_DECL (Transceiver, MODE); + +QDebug operator << (QDebug, Transceiver::TransceiverState const&); +#endif + +ENUM_QDATASTREAM_OPS_DECL (Transceiver, MODE); + +ENUM_CONVERSION_OPS_DECL (Transceiver, MODE); + +bool operator != (Transceiver::TransceiverState const&, Transceiver::TransceiverState const&); +bool operator == (Transceiver::TransceiverState const&, Transceiver::TransceiverState const&); + +#endif diff --git a/TransceiverBase.cpp b/TransceiverBase.cpp new file mode 100644 index 000000000..6e664bb55 --- /dev/null +++ b/TransceiverBase.cpp @@ -0,0 +1,269 @@ +#include "TransceiverBase.hpp" + +#include + +#include + +#include "pimpl_impl.hpp" + +class TransceiverBase::impl final +{ +public: + impl () + { + } + + impl (impl const&) = delete; + impl& operator = (impl const&) = delete; + + TransceiverState state_; +}; + + +TransceiverBase::TransceiverBase () +{ +} + +TransceiverBase::~TransceiverBase () +{ +} + +void TransceiverBase::start () noexcept +{ + QString message; + try + { + if (m_->state_.online ()) + { + do_stop (); + do_post_stop (); + m_->state_.online (false); + } + do_start (); + do_post_start (); + m_->state_.online (true); + } + catch (std::exception const& e) + { + message = e.what (); + } + catch (...) + { + message = "Unexpected rig error"; + } + if (!message.isEmpty ()) + { + offline (message); + } +} + +void TransceiverBase::stop () noexcept +{ + QString message; + try + { + do_stop (); + do_post_stop (); + m_->state_.online (false); + } + catch (std::exception const& e) + { + message = e.what (); + } + catch (...) + { + message = "Unexpected rig error"; + } + if (!message.isEmpty ()) + { + offline (message); + } + else + { + Q_EMIT finished (); + } +} + +void TransceiverBase::frequency (Frequency f) noexcept +{ + QString message; + try + { + if (m_->state_.online ()) + { + do_frequency (f); + do_post_frequency (f); + } + } + catch (std::exception const& e) + { + message = e.what (); + } + catch (...) + { + message = "Unexpected rig error"; + } + if (!message.isEmpty ()) + { + offline (message); + } +} + +void TransceiverBase::tx_frequency (Frequency tx, bool rationalise_mode) noexcept +{ + QString message; + try + { + if (m_->state_.online ()) + { + do_tx_frequency (tx, rationalise_mode); + do_post_tx_frequency (tx); + } + } + catch (std::exception const& e) + { + message = e.what (); + } + catch (...) + { + message = "Unexpected rig error"; + } + if (!message.isEmpty ()) + { + offline (message); + } +} + +void TransceiverBase::mode (MODE m, bool rationalise) noexcept +{ + QString message; + try + { + if (m_->state_.online ()) + { + do_mode (m, rationalise); + do_post_mode (m); + } + } + catch (std::exception const& e) + { + message = e.what (); + } + catch (...) + { + message = "Unexpected rig error"; + } + if (!message.isEmpty ()) + { + offline (message); + } +} + +void TransceiverBase::ptt (bool on) noexcept +{ + QString message; + try + { + if (m_->state_.online ()) + { + do_ptt (on); + do_post_ptt (on); + } + } + catch (std::exception const& e) + { + message = e.what (); + } + catch (...) + { + message = "Unexpected rig error"; + } + if (!message.isEmpty ()) + { + offline (message); + } +} + +void TransceiverBase::sync (bool force_signal) noexcept +{ + QString message; + try + { + if (m_->state_.online ()) + { + do_sync (force_signal); + } + } + catch (std::exception const& e) + { + message = e.what (); + } + catch (...) + { + message = "Unexpected rig error"; + } + if (!message.isEmpty ()) + { + offline (message); + } +} + +void TransceiverBase::update_rx_frequency (Frequency rx) +{ + m_->state_.frequency (rx); +} + +void TransceiverBase::update_other_frequency (Frequency tx) +{ + m_->state_.tx_frequency (tx); +} + +void TransceiverBase::update_split (bool state) +{ + m_->state_.split (state); +} + +void TransceiverBase::update_mode (MODE m) +{ + m_->state_.mode (m); +} + +void TransceiverBase::update_PTT (bool state) +{ + m_->state_.ptt (state); +} + +void TransceiverBase::update_complete () +{ + if (do_pre_update ()) + { + Q_EMIT update (m_->state_); + } +} + +void TransceiverBase::offline (QString const& reason) +{ + QString message; + try + { + if (m_->state_.online ()) + { + m_->state_.online (false); + do_stop (); + } + } + catch (std::exception const& e) + { + message = e.what (); + } + catch (...) + { + message = "Unexpected rig error"; + } + Q_EMIT failure (reason + '\n' + message); +} + +auto TransceiverBase::state () const -> TransceiverState const& +{ + return m_->state_; +} diff --git a/TransceiverBase.hpp b/TransceiverBase.hpp new file mode 100644 index 000000000..62a0cfc68 --- /dev/null +++ b/TransceiverBase.hpp @@ -0,0 +1,136 @@ +#ifndef TRANSCEIVER_BASE_HPP__ +#define TRANSCEIVER_BASE_HPP__ + +#include + +#include "Transceiver.hpp" + +#include "pimpl_h.hpp" + +class QString; + +// +// Base Transceiver Implementation +// +// Behaviour common to all Transceiver implementations. +// +// Collaborations +// +// Implements the Transceiver abstract interface as template methods +// and provides a new abstract interface with similar functionality +// (do_XXXXX operations). Provides and calls abstract interface that +// gets called post the above operations (do_post_XXXXX) to allow +// caching implementation etc. +// +// A key factor is to catch all exceptions thrown by sub-class +// implementations where the template method is a Qt slot which is +// therefore likely to be called by Qt which doesn't handle +// exceptions. Any exceptions are converted to Transceiver::failure() +// signals. +// +// Sub-classes update the stored state via a protected interface. +// +// Responsibilities: +// +// Wrap incoming Transceiver messages catching all exceptions in Qt +// slot driven messages and converting them to Qt signals. This is +// done because exceptions make concrete Transceiver implementations +// simpler to write, but exceptions cannot cross signal/slot +// boundaries (especially across threads). This also removes any +// requirement for the client code to handle exceptions. +// +// Maintain the state of the concrete Transceiver instance that is +// passed back via the Transceiver::update(TransceiverState) signal, +// it is still the responsibility of concrete Transceiver +// implementations to emit the state_change signal when they have a +// status update. +// +// Maintain a go/no-go status for concrete Transceiver +// implementations ensuring only a valid sequence of messages are +// passed. A concrete Transceiver instance must be started before it +// can receive messages, any exception thrown takes the Transceiver +// offline. +// +// Implements methods that concrete Transceiver implementations use +// to update the Transceiver state. These do not signal state change +// to clients as this is the responsibility of the concrete +// Transceiver implementation, thus allowing multiple state component +// updates to be signalled together if required. +// +class TransceiverBase + : public Transceiver +{ +protected: + TransceiverBase (); + +public: + ~TransceiverBase (); + + // + // Implement the Transceiver abstract interface. + // + void start () noexcept override final; + void stop () noexcept override final; + void frequency (Frequency rx) noexcept override final; + void tx_frequency (Frequency tx, bool rationalise_mode) noexcept override final; + void mode (MODE, bool rationalise) noexcept override final; + void ptt (bool) noexcept override final; + void sync (bool force_signal) noexcept override final; + +protected: + // + // Error exception which is thrown to signal unexpected errors. + // + struct error + : public std::runtime_error + { + error (char const * msg) : std::runtime_error (msg) {} + }; + + // Template methods that sub classes implement to do what they need to do. + // + // These methods may throw exceptions to signal errors. + virtual void do_start () = 0; + virtual void do_post_start () {} + + virtual void do_stop () = 0; + virtual void do_post_stop () {} + + virtual void do_frequency (Frequency rx) = 0; + virtual void do_post_frequency (Frequency) {} + + virtual void do_tx_frequency (Frequency tx = 0, bool rationalise_mode = true) = 0; + virtual void do_post_tx_frequency (Frequency) {} + + virtual void do_mode (MODE, bool rationalise = true) = 0; + virtual void do_post_mode (MODE) {} + + virtual void do_ptt (bool = true) = 0; + virtual void do_post_ptt (bool) {} + + virtual void do_sync (bool force_signal = false) = 0; + + virtual bool do_pre_update () {return true;} + + // sub classes report rig state changes with these methods + void update_rx_frequency (Frequency); + void update_other_frequency (Frequency = 0); + void update_split (bool); + void update_mode (MODE); + void update_PTT (bool = true); + + // Calling this triggers the Transceiver::update(State) signal. + void update_complete (); + + // sub class may asynchronously take the rig offline by calling this + void offline (QString const& reason); + + // and query state with this one + TransceiverState const& state () const; + +private: + class impl; + pimpl m_; +}; + +#endif diff --git a/TransceiverFactory.cpp b/TransceiverFactory.cpp new file mode 100644 index 000000000..bb6c04145 --- /dev/null +++ b/TransceiverFactory.cpp @@ -0,0 +1,301 @@ +#include "TransceiverFactory.hpp" + +#include + +#include "HamlibTransceiver.hpp" +#include "DXLabSuiteCommanderTransceiver.hpp" +#include "HRDTransceiver.hpp" +#include "EmulateSplitTransceiver.hpp" + +#if defined (WIN32) +#include "OmniRigTransceiver.hpp" +#endif + +#include "moc_TransceiverFactory.cpp" + +// we use the hamlib "Hamlib Dummy" transceiver for non-CAT radios, +// this allows us to still use the hamlib PTT control features for a +// unified PTT control solution + +char const * const TransceiverFactory::basic_transceiver_name_ = "None"; + +namespace +{ + struct init + { + init () + { + qRegisterMetaType ("TransceiverFactory::DataBits"); + qRegisterMetaTypeStreamOperators ("TransceiverFactory::DataBits"); + qRegisterMetaType ("TransceiverFactory::StopBits"); + qRegisterMetaTypeStreamOperators ("TransceiverFactory::StopBits"); + qRegisterMetaType ("TransceiverFactory::Handshake"); + qRegisterMetaTypeStreamOperators ("TransceiverFactory::Handshake"); + qRegisterMetaType ("TransceiverFactory::PTTMethod"); + qRegisterMetaTypeStreamOperators ("TransceiverFactory::PTTMethod"); + qRegisterMetaType ("TransceiverFactory::TXAudioSource"); + qRegisterMetaTypeStreamOperators ("TransceiverFactory::TXAudioSource"); + qRegisterMetaType ("TransceiverFactory::SplitMode"); + qRegisterMetaTypeStreamOperators ("TransceiverFactory::SplitMode"); + } + } static_initializer; + + enum // supported non-hamlib radio interfaces + { + NonHamlibBaseId = 9899 + , CommanderId + , HRDId + , OmniRigOneId + , OmniRigTwoId + }; +} + +TransceiverFactory::TransceiverFactory () +{ + HamlibTransceiver::register_transceivers (&transceivers_); + DXLabSuiteCommanderTransceiver::register_transceivers (&transceivers_, CommanderId); + HRDTransceiver::register_transceivers (&transceivers_, HRDId); + +#if defined (WIN32) + // OmniRig is ActiveX/COM server so only on Windows + OmniRigTransceiver::register_transceivers (&transceivers_, OmniRigOneId, OmniRigTwoId); +#endif +} + +auto TransceiverFactory::supported_transceivers () const -> Transceivers const& +{ + return transceivers_; +} + +auto TransceiverFactory::CAT_port_type (QString const& name) const -> Capabilities::PortType +{ + return supported_transceivers ()[name].port_type_; +} + +bool TransceiverFactory::has_CAT_PTT (QString const& name) const +{ + return + supported_transceivers ()[name].has_CAT_PTT_ + || supported_transceivers ()[name].model_number_ > NonHamlibBaseId; +} + +bool TransceiverFactory::has_CAT_PTT_mic_data (QString const& name) const +{ + return supported_transceivers ()[name].has_CAT_PTT_mic_data_; +} + +bool TransceiverFactory::has_CAT_indirect_serial_PTT (QString const& name) const +{ + return supported_transceivers ()[name].has_CAT_indirect_serial_PTT_; +} + +bool TransceiverFactory::has_asynchronous_CAT (QString const& name) const +{ + return supported_transceivers ()[name].asynchronous_; +} + +std::unique_ptr TransceiverFactory::create (QString const& name + , QString const& cat_port + , int cat_baud + , DataBits cat_data_bits + , StopBits cat_stop_bits + , Handshake cat_handshake + , bool cat_dtr_always_on + , bool cat_rts_always_on + , PTTMethod ptt_type + , TXAudioSource ptt_use_data_ptt + , SplitMode split_mode + , QString const& ptt_port + , int poll_interval + , QThread * target_thread) +{ + std::unique_ptr result; + switch (supported_transceivers ()[name].model_number_) + { + case CommanderId: + { + // we start with a dummy HamlibTransceiver object instance that can support direct PTT + std::unique_ptr basic_transceiver { + new HamlibTransceiver { + supported_transceivers ()[basic_transceiver_name_].model_number_ + , cat_port + , cat_baud + , cat_data_bits + , cat_stop_bits + , cat_handshake + , cat_dtr_always_on + , cat_rts_always_on + , ptt_type + , ptt_use_data_ptt + , "CAT" == ptt_port ? "" : ptt_port + } + }; + if (target_thread) + { + basic_transceiver.get ()->moveToThread (target_thread); + } + + // wrap the basic Transceiver object instance with a decorator object that talks to DX Lab Suite Commander + result.reset (new DXLabSuiteCommanderTransceiver {std::move (basic_transceiver), cat_port, PTT_method_CAT == ptt_type, poll_interval}); + if (target_thread) + { + result.get ()->moveToThread (target_thread); + } + } + break; + + case HRDId: + { + // we start with a dummy HamlibTransceiver object instance that can support direct PTT + std::unique_ptr basic_transceiver { + new HamlibTransceiver { + supported_transceivers ()[basic_transceiver_name_].model_number_ + , cat_port + , cat_baud + , cat_data_bits + , cat_stop_bits + , cat_handshake + , cat_dtr_always_on + , cat_rts_always_on + , ptt_type + , ptt_use_data_ptt + , "CAT" == ptt_port ? "" : ptt_port + } + }; + if (target_thread) + { + basic_transceiver.get ()->moveToThread (target_thread); + } + + // wrap the basic Transceiver object instance with a decorator object that talks to ham Radio Deluxe + result.reset (new HRDTransceiver {std::move (basic_transceiver), cat_port, PTT_method_CAT == ptt_type, poll_interval}); + if (target_thread) + { + result.get ()->moveToThread (target_thread); + } + } + break; + +#if defined (WIN32) + case OmniRigOneId: + { + // we start with a dummy HamlibTransceiver object instance that can support direct PTT + std::unique_ptr basic_transceiver { + new HamlibTransceiver { + supported_transceivers ()[basic_transceiver_name_].model_number_ + , cat_port + , cat_baud + , cat_data_bits + , cat_stop_bits + , cat_handshake + , cat_dtr_always_on + , cat_rts_always_on + , ptt_type + , ptt_use_data_ptt + , "CAT" == ptt_port ? "" : ptt_port + } + }; + if (target_thread) + { + basic_transceiver.get ()->moveToThread (target_thread); + } + + // wrap the basic Transceiver object instance with a decorator object that talks to OmniRig rig one + result.reset (new OmniRigTransceiver {std::move (basic_transceiver), OmniRigTransceiver::One, ptt_type, ptt_port}); + if (target_thread) + { + result.get ()->moveToThread (target_thread); + } + } + break; + + case OmniRigTwoId: + { + // we start with a dummy HamlibTransceiver object instance that can support direct PTT + std::unique_ptr basic_transceiver { + new HamlibTransceiver { + supported_transceivers ()[basic_transceiver_name_].model_number_ + , cat_port + , cat_baud + , cat_data_bits + , cat_stop_bits + , cat_handshake + , cat_dtr_always_on + , cat_rts_always_on + , ptt_type + , ptt_use_data_ptt + , "CAT" == ptt_port ? "" : ptt_port + } + }; + if (target_thread) + { + basic_transceiver.get ()->moveToThread (target_thread); + } + + // wrap the basic Transceiver object instance with a decorator object that talks to OmniRig rig two + result.reset (new OmniRigTransceiver {std::move (basic_transceiver), OmniRigTransceiver::Two, ptt_type, ptt_port}); + if (target_thread) + { + result.get ()->moveToThread (target_thread); + } + } + break; +#endif + + default: + result.reset (new HamlibTransceiver { + supported_transceivers ()[name].model_number_ + , cat_port + , cat_baud + , cat_data_bits + , cat_stop_bits + , cat_handshake + , cat_dtr_always_on + , cat_rts_always_on + , ptt_type + , ptt_use_data_ptt + , "CAT" == ptt_port ? cat_port : ptt_port + , poll_interval + }); + if (target_thread) + { + result.get ()->moveToThread (target_thread); + } + break; + } + + if (split_mode_emulate == split_mode) + { + // wrap the Transceiver object instance with a decorator that emulates split mode + result.reset (new EmulateSplitTransceiver {std::move (result)}); + if (target_thread) + { + result.get ()->moveToThread (target_thread); + } + } + + return std::move (result); +} + +#if !defined (QT_NO_DEBUG_STREAM) +ENUM_QDEBUG_OPS_IMPL (TransceiverFactory, DataBits); +ENUM_QDEBUG_OPS_IMPL (TransceiverFactory, StopBits); +ENUM_QDEBUG_OPS_IMPL (TransceiverFactory, Handshake); +ENUM_QDEBUG_OPS_IMPL (TransceiverFactory, PTTMethod); +ENUM_QDEBUG_OPS_IMPL (TransceiverFactory, TXAudioSource); +ENUM_QDEBUG_OPS_IMPL (TransceiverFactory, SplitMode); +#endif + +ENUM_QDATASTREAM_OPS_IMPL (TransceiverFactory, DataBits); +ENUM_QDATASTREAM_OPS_IMPL (TransceiverFactory, StopBits); +ENUM_QDATASTREAM_OPS_IMPL (TransceiverFactory, Handshake); +ENUM_QDATASTREAM_OPS_IMPL (TransceiverFactory, PTTMethod); +ENUM_QDATASTREAM_OPS_IMPL (TransceiverFactory, TXAudioSource); +ENUM_QDATASTREAM_OPS_IMPL (TransceiverFactory, SplitMode); + +ENUM_CONVERSION_OPS_IMPL (TransceiverFactory, DataBits); +ENUM_CONVERSION_OPS_IMPL (TransceiverFactory, StopBits); +ENUM_CONVERSION_OPS_IMPL (TransceiverFactory, Handshake); +ENUM_CONVERSION_OPS_IMPL (TransceiverFactory, PTTMethod); +ENUM_CONVERSION_OPS_IMPL (TransceiverFactory, TXAudioSource); +ENUM_CONVERSION_OPS_IMPL (TransceiverFactory, SplitMode); diff --git a/TransceiverFactory.hpp b/TransceiverFactory.hpp new file mode 100644 index 000000000..176c91612 --- /dev/null +++ b/TransceiverFactory.hpp @@ -0,0 +1,155 @@ +#ifndef TRANSCEIVER_FACTORY_HPP__ +#define TRANSCEIVER_FACTORY_HPP__ + +#include + +#include +#include + +#include "Transceiver.hpp" + +#include "qt_helpers.hpp" + +class QString; +class QThread; + +// +// Transceiver Factory +// +class TransceiverFactory + : public QObject +{ + Q_OBJECT; + Q_ENUMS (DataBits StopBits Handshake PTTMethod TXAudioSource SplitMode); + +private: + Q_DISABLE_COPY (TransceiverFactory); + +public: + // + // Capabilities of a Transceiver that can be determined without + // actually instantiating one, these are for use in Configuration + // GUI behaviour determination + // + struct Capabilities + { + enum PortType {none, serial, network}; + + explicit Capabilities (int model_number = 0 + , PortType port_type = none + , bool has_CAT_PTT = false + , bool has_CAT_PTT_mic_data = false + , bool has_CAT_indirect_serial_PTT = false + , bool asynchronous = false) + : model_number_ {model_number} + , port_type_ {port_type} + , has_CAT_PTT_ {has_CAT_PTT} + , has_CAT_PTT_mic_data_ {has_CAT_PTT_mic_data} + , has_CAT_indirect_serial_PTT_ {has_CAT_indirect_serial_PTT} + , asynchronous_ {asynchronous} + { + } + + int model_number_; + PortType port_type_; + bool has_CAT_PTT_; + bool has_CAT_PTT_mic_data_; + bool has_CAT_indirect_serial_PTT_; // OmniRig controls RTS/DTR via COM interface + bool asynchronous_; + }; + + // + // Dictionary of Transceiver types Capabilities + // + typedef QMap Transceivers; + + // + // various Transceiver parameters + // + enum DataBits {seven_data_bits = 7, eight_data_bits}; + enum StopBits {one_stop_bit = 1, two_stop_bits}; + enum Handshake {handshake_none, handshake_XonXoff, handshake_hardware}; + enum PTTMethod {PTT_method_VOX, PTT_method_CAT, PTT_method_DTR, PTT_method_RTS}; + enum TXAudioSource {TX_audio_source_front, TX_audio_source_rear}; + enum SplitMode {split_mode_none, split_mode_rig, split_mode_emulate}; + + TransceiverFactory (); + + static char const * const basic_transceiver_name_; // dummy transceiver is basic model + + // + // fetch all supported rigs as a list of name and model id + // + Transceivers const& supported_transceivers () const; + + // supported model queries + Capabilities::PortType CAT_port_type (QString const& name) const; // how to talk to CAT + bool has_CAT_PTT (QString const& name) const; // can be keyed via CAT + bool has_CAT_PTT_mic_data (QString const& name) const; // Tx audio port is switchable via CAT + bool has_CAT_indirect_serial_PTT (QString const& name) const; // Can PTT via CAT port use DTR or RTS (OmniRig for example) + bool has_asynchronous_CAT (QString const& name) const; // CAT asynchronous rather than polled + + // make a new Transceiver instance + // + // cat_port, cat_baud, cat_data_bits, cat_stop_bits, cat_handshake, + // cat_dtr_alway_on, cat_rts_always_on are only relevant to + // interfaces that are served by hamlib + // + // PTT port and to some extent ptt_type are independent of interface + // type + // + std::unique_ptr create (QString const& name // from supported_transceivers () key + , QString const& cat_port // serial port device name or empty + , int cat_baud + , DataBits cat_data_bits + , StopBits cat_stop_bits + , Handshake cat_handshake + , bool cat_dtr_always_on // to power interface + , bool cat_rts_always_on // to power inteface + , PTTMethod ptt_type // "CAT" | "DTR" | "RTS" | "VOX" + , TXAudioSource ptt_use_data_ptt // some rigs allow audio routing to Mic/Data connector + , SplitMode split_mode // how to support split TX mode + , QString const& ptt_port // serial port device name or special value "CAT" + , int poll_interval // in milliseconds for interfaces that require polling for parameter changes + , QThread * target_thread = nullptr + ); + +private: + Transceivers transceivers_; +}; + +// +// boilerplate routines to make enum types useable and debuggable in +// Qt +// +Q_DECLARE_METATYPE (TransceiverFactory::DataBits); +Q_DECLARE_METATYPE (TransceiverFactory::StopBits); +Q_DECLARE_METATYPE (TransceiverFactory::Handshake); +Q_DECLARE_METATYPE (TransceiverFactory::PTTMethod); +Q_DECLARE_METATYPE (TransceiverFactory::TXAudioSource); +Q_DECLARE_METATYPE (TransceiverFactory::SplitMode); + +#if !defined (QT_NO_DEBUG_STREAM) +ENUM_QDEBUG_OPS_DECL (TransceiverFactory, DataBits); +ENUM_QDEBUG_OPS_DECL (TransceiverFactory, StopBits); +ENUM_QDEBUG_OPS_DECL (TransceiverFactory, Handshake); +ENUM_QDEBUG_OPS_DECL (TransceiverFactory, PTTMethod); +ENUM_QDEBUG_OPS_DECL (TransceiverFactory, TXAudioSource); +ENUM_QDEBUG_OPS_DECL (TransceiverFactory, SplitMode); +#endif + +ENUM_QDATASTREAM_OPS_DECL (TransceiverFactory, DataBits); +ENUM_QDATASTREAM_OPS_DECL (TransceiverFactory, StopBits); +ENUM_QDATASTREAM_OPS_DECL (TransceiverFactory, Handshake); +ENUM_QDATASTREAM_OPS_DECL (TransceiverFactory, PTTMethod); +ENUM_QDATASTREAM_OPS_DECL (TransceiverFactory, TXAudioSource); +ENUM_QDATASTREAM_OPS_DECL (TransceiverFactory, SplitMode); + +ENUM_CONVERSION_OPS_DECL (TransceiverFactory, DataBits); +ENUM_CONVERSION_OPS_DECL (TransceiverFactory, StopBits); +ENUM_CONVERSION_OPS_DECL (TransceiverFactory, Handshake); +ENUM_CONVERSION_OPS_DECL (TransceiverFactory, PTTMethod); +ENUM_CONVERSION_OPS_DECL (TransceiverFactory, TXAudioSource); +ENUM_CONVERSION_OPS_DECL (TransceiverFactory, SplitMode); + +#endif diff --git a/Versions.cmake b/Versions.cmake new file mode 100644 index 000000000..2984af67d --- /dev/null +++ b/Versions.cmake @@ -0,0 +1,10 @@ +# Version number components +set (WSJTX_VERSION_MAJOR 1) +set (WSJTX_VERSION_MINOR 4) +set (WSJTX_VERSION_PATCH 0) +#set (WSJTX_RC 1) +set (WSJTX_VERSION_IS_RELEASE 0) + +set (CONFIG_TEST_VERSION_MAJOR 0) +set (CONFIG_TEST_VERSION_MINOR 2) +set (CONFIG_TEST_VERSION_PATCH 13) diff --git a/about.cpp b/about.cpp index f23486116..734503ecc 100644 --- a/about.cpp +++ b/about.cpp @@ -1,6 +1,8 @@ #include "about.h" #include "ui_about.h" +#include "moc_about.cpp" + CAboutDlg::CAboutDlg(QWidget *parent, QString Revision) : QDialog(parent), m_Revision(Revision), diff --git a/about.ui b/about.ui index 3a862599c..23d3eff21 100644 --- a/about.ui +++ b/about.ui @@ -10,7 +10,7 @@ 0 0 374 - 164 + 144 @@ -24,17 +24,75 @@ - - - + + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + + Qt::Vertical - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 20 + 40 + - + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + OK + + + + - + + + okButton + clicked() + CAboutDlg + accept() + + + 321 + 120 + + + 186 + 71 + + + + diff --git a/artwork/DragNDrop Background.svg b/artwork/DragNDrop Background.svg new file mode 100644 index 000000000..fa325a7f2 --- /dev/null +++ b/artwork/DragNDrop Background.svg @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + Drag the icononto the linkto install WSJT-X + + + + + image/svg+xml + + + + + Openclipart + + + + 2010-03-28T09:25:56 + Drawing by Francesco 'Architetto' Rollandin. From OCAL 0.18 release. + http://openclipart.org/detail/34711/architetto----tasto-5-by-anonymous + + + Anonymous + + + + + arrow + clip art + clipart + green + icon + right + sign + symbol + + + + + + + + + + + diff --git a/artwork/README b/artwork/README new file mode 100644 index 000000000..3b5fd5826 --- /dev/null +++ b/artwork/README @@ -0,0 +1,27 @@ +This directory contains original artwork used to generate the graphics +used in various parts of the WSJT-X ecosystem. The CMake build scripts +do not generate the final image bitmaps becuase of teh extra tools +required to complete this step. Instead there is shell script here +(make_graphics.sh) that does the generation. If you want to modify the +sourec graphics or add new ones then you need an SVG editor (I use +inkscape) and a tool to do various conversion steps (I use +ImageMagick), the sheel script explicitly uses these tools. + +The files here are: + +installer_logo.svg - A 150x57 pixel image (the size is important with + a whte background that is used at the top right of the NSIS + Windows installer. + +wsjtx_globe_1024x1024.svg - A 1024x1024 pixel image which is used in + various places, mainly for high resolution icons. + +wsjtx_globe_128x128.svg - A 128x128 pixel image which is used for low + resolution icons. + +make_graphics.sh - Run this script (on Linux) to generate the + intermediate bitmap image files used in the wsjtx build. This + script generates all but the final Mac iconset file which is + generated by a build on Mac since it requires a Mac developer tool + (iconutil). This script requires that inkscape and ImageMagick are + installed. \ No newline at end of file diff --git a/artwork/installer_logo.svg b/artwork/installer_logo.svg new file mode 100644 index 000000000..4dcf15e6f --- /dev/null +++ b/artwork/installer_logo.svg @@ -0,0 +1,1126 @@ + + + + + + + + Simple globe centered on North America + + + earth globe northamerica + + + + + Open Clip Art Library + + + + + Dan Gerhrads + + + + + Dan Gerhrads + + + May 1, 2005 + image/svg+xml + + + en + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + wmf2svg + + + + + + + + + + + + + + + WSJT-XJT65&JT9by K1JT + diff --git a/artwork/make_graphics.sh b/artwork/make_graphics.sh new file mode 100644 index 000000000..9a9275fb8 --- /dev/null +++ b/artwork/make_graphics.sh @@ -0,0 +1,58 @@ +#!/bin/sh + +# +# Windows +# +inkscape -z -e /tmp/image-0.png wsjtx_globe_128x128.svg +inkscape -z -e /tmp/image-1.png wsjtx_globe_1024x1024.svg +convert '/tmp/image-%d.png[0-1]' -background transparent \ + \( -clone 0 -resize 16 -colors 256 -compress none \) \ + \( -clone 0 -resize 20 -colors 256 -compress none \) \ + \( -clone 0 -resize 24 -colors 256 -compress none \) \ + \( -clone 0 -resize 32 -colors 256 -compress none \) \ + \( -clone 0 -resize 40 -colors 256 -compress none \) \ + \( -clone 1 -resize 48 -colors 256 -compress none \) \ + \( -clone 1 -resize 96 -colors 256 -compress none \) \ + \( -clone 1 -resize 128 -colors 256 -compress none \) \ + \( -clone 0 -resize 16 -compress none \) \ + \( -clone 0 -resize 20 -compress none \) \ + \( -clone 0 -resize 24 -compress none \) \ + \( -clone 0 -resize 32 -compress none \) \ + \( -clone 0 -resize 40 -compress none \) \ + \( -clone 1 -resize 48 -compress none \) \ + \( -clone 1 -resize 64 -compress none \) \ + \( -clone 1 -resize 96 -compress none \) \ + \( -clone 1 -resize 128 -compress none \) \ + \( -clone 1 -resize 256 -compress Zip \) \ + -delete 1 -delete 0 \ + -alpha remove ../icons/windows-icons/wsjtx.ico +rm /tmp/image-0.png /tmp/image-1.png +identify -format '%f %p/%n %m %C/%Q %r %G %A %z\n' ../icons/windows-icons/wsjtx.ico +# +inkscape -z -e /dev/stdout -w 150 -h 57 -b white installer_logo.svg | tail -n +4 | \ + convert png:- -resize 150x57 +matte BMP3:../icons/windows-icons/installer_logo.bmp +identify -format '%f %p/%n %m %C/%Q %r %G %A %z\n' ../icons/windows-icons/installer_logo.bmp + +# +# Mac +# +inkscape -z -e ../icons/Darwin/wsjtx.iconset/icon_16x16.png -w 16 -h 16 wsjtx_globe_128x128.svg +inkscape -z -e ../icons/Darwin/wsjtx.iconset/icon_16x16@2x.png -w 32 -h 32 wsjtx_globe_128x128.svg +inkscape -z -e ../icons/Darwin/wsjtx.iconset/icon_32x32.png -w 32 -h 32 wsjtx_globe_128x128.svg +inkscape -z -e ../icons/Darwin/wsjtx.iconset/icon_32x32@2x.png -w 64 -h 64 wsjtx_globe_128x128.svg +inkscape -z -e ../icons/Darwin/wsjtx.iconset/icon_128x128.png -w 128 -h 128 wsjtx_globe_1024x1024.svg +inkscape -z -e ../icons/Darwin/wsjtx.iconset/icon_128x128@2x.png -w 256 -h 256 wsjtx_globe_1024x1024.svg +inkscape -z -e ../icons/Darwin/wsjtx.iconset/icon_256x256.png -w 256 -h 256 wsjtx_globe_1024x1024.svg +inkscape -z -e ../icons/Darwin/wsjtx.iconset/icon_256x256@2x.png -w 512 -h 512 wsjtx_globe_1024x1024.svg +inkscape -z -e ../icons/Darwin/wsjtx.iconset/icon_512x512.png -w 512 -h 512 wsjtx_globe_1024x1024.svg +inkscape -z -e ../icons/Darwin/wsjtx.iconset/icon_512x512@2x.png -w 1024 -h 1024 wsjtx_globe_1024x1024.svg +identify -format '%f %p/%n %m %C/%Q %r %G %A %z\n' ../icons/Darwin/wsjtx.iconset/* +# +inkscape -z -e "../icons/Darwin/DragNDrop Background.png" -w 640 -h 480 -b white "DragNDrop Background.svg" +identify -format '%f %p/%n %m %C/%Q %r %G %A %z\n' "../icons/Darwin/DragNDrop Background.png" + +# +# KDE & Gnome +# +inkscape -z -e ../icons/Unix/wsjtx_icon.png -w 128 -h 128 wsjtx_globe_1024x1024.svg +identify -format '%f %p/%n %m %C/%Q %r %G %A %z\n' ../icons/Unix/wsjtx_icon.png diff --git a/artwork/wsjtx_globe_1024x1024.svg b/artwork/wsjtx_globe_1024x1024.svg new file mode 100644 index 000000000..e294483f9 --- /dev/null +++ b/artwork/wsjtx_globe_1024x1024.svg @@ -0,0 +1,602 @@ + + + + + + + + Simple globe centered on North America + + + earth globe northamerica + + + + + Open Clip Art Library + + + + + Dan Gerhrads + + + + + Dan Gerhrads + + + May 1, 2005 + image/svg+xml + + + en + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + wmf2svg + + + + + + + + + + + + + + WSJT-XJT65&JT9by K1JT + diff --git a/artwork/wsjtx_globe_128x128.svg b/artwork/wsjtx_globe_128x128.svg new file mode 100644 index 000000000..650324316 --- /dev/null +++ b/artwork/wsjtx_globe_128x128.svg @@ -0,0 +1,839 @@ + + + + + + + + Simple globe centered on North America + + + earth globe northamerica + + + + + Open Clip Art Library + + + + + Dan Gerhrads + + + + + Dan Gerhrads + + + May 1, 2005 + image/svg+xml + + + en + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + wmf2svg + + + + + + + + + + + + + + diff --git a/astro.cpp b/astro.cpp index 13bd9f17a..86416a777 100644 --- a/astro.cpp +++ b/astro.cpp @@ -1,37 +1,101 @@ #include "astro.h" -#include "ui_astro.h" -#include -#include -#include + #include + +#include +#include +#include +#include +#include +#include +#include +#include + #include "commons.h" -Astro::Astro(QWidget *parent) : - QWidget(parent), - ui(new Ui::Astro) +#include "ui_astro.h" + +#include "moc_astro.cpp" + +Astro::Astro(QSettings * settings, QDir const& dataPath, QWidget * parent) : + QWidget {parent}, + settings_ {settings}, + ui_ {new Ui::Astro}, + data_path_ {dataPath} { - ui->setupUi(this); - ui->astroTextBrowser->setStyleSheet( - "QTextBrowser { background-color : cyan; color : black; }"); - ui->astroTextBrowser->clear(); + ui_->setupUi(this); + + setWindowFlags (Qt::Dialog | Qt::WindowCloseButtonHint | Qt::WindowMinimizeButtonHint); + + setWindowTitle(QApplication::applicationName () + " - " + tr ("Astronomical Data")); + + read_settings (); + + ui_->text_label->clear(); } -Astro::~Astro() +Astro::~Astro () { - delete ui; + if (isVisible ()) + { + write_settings (); + } +} + +void Astro::closeEvent (QCloseEvent * e) +{ + write_settings (); + QWidget::closeEvent (e); +} + +void Astro::read_settings () +{ + settings_->beginGroup ("Astro"); + move (settings_->value ("window/pos", pos ()).toPoint ()); + QFont font; + if (font.fromString (settings_->value ("font", ui_->text_label->font ().toString ()).toString ())) + { + ui_->text_label->setFont (font); + adjustSize (); + } + settings_->endGroup (); +} + +void Astro::write_settings () +{ + settings_->beginGroup ("Astro"); + settings_->setValue ("window/pos", pos ()); + settings_->setValue ("font", ui_->text_label->font ().toString ()); + settings_->endGroup (); +} + +void Astro::on_font_push_button_clicked (bool /* checked */) +{ + bool changed; + ui_->text_label->setFont (QFontDialog::getFont (&changed + , ui_->text_label->font () + , this + , tr ("WSJT-X Astro Text Font Chooser") +#if QT_VERSION >= 0x050201 + , QFontDialog::MonospacedFonts +#endif + )); + if (changed) + { + adjustSize (); + } } void Astro::astroUpdate(QDateTime t, QString mygrid, QString hisgrid, - int fQSO, int nsetftx, int ntxFreq, QString azelDir) + int fQSO, int nsetftx, int ntxFreq) { static int ntxFreq0=-99; static bool astroBusy=false; - char cc[300]; double azsun,elsun,azmoon,elmoon,azmoondx,elmoondx; double ramoon,decmoon,dgrd,poloffset,xnr,techo; int ntsky,ndop,ndop00; - QString date = t.date().toString("yyyy MMM dd"); - QString utc = t.time().toString(); + QString date = t.date().toString("yyyy MMM dd").trimmed (); + QString utc = t.time().toString().trimmed (); int nyear=t.date().year(); int month=t.date().month(); int nday=t.date().day(); @@ -40,7 +104,7 @@ void Astro::astroUpdate(QDateTime t, QString mygrid, QString hisgrid, double sec=t.time().second() + 0.001*t.time().msec(); int isec=sec; double uth=nhr + nmin/60.0 + sec/3600.0; -// int nfreq=(int)datcom_.fcenter; + // int nfreq=(int)datcom_.fcenter; int nfreq=10368; if(nfreq<10 or nfreq > 50000) nfreq=144; @@ -48,60 +112,82 @@ void Astro::astroUpdate(QDateTime t, QString mygrid, QString hisgrid, astroBusy=true; astrosub_(&nyear, &month, &nday, &uth, &nfreq, mygrid.toLatin1(), - hisgrid.toLatin1(), &azsun, &elsun, &azmoon, &elmoon, - &azmoondx, &elmoondx, &ntsky, &ndop, &ndop00,&ramoon, &decmoon, - &dgrd, &poloffset, &xnr, &techo, 6, 6); + hisgrid.toLatin1(), &azsun, &elsun, &azmoon, &elmoon, + &azmoondx, &elmoondx, &ntsky, &ndop, &ndop00,&ramoon, &decmoon, + &dgrd, &poloffset, &xnr, &techo, 6, 6); astroBusy=false; } - sprintf(cc, - "Az: %6.1f\n" - "El: %6.1f\n" - "MyDop: %6d\n" - "Delay: %6.2f\n" - "DxAz: %6.1f\n" - "DxEl: %6.1f\n" - "DxDop: %6d\n" - "Dec: %6.1f\n" - "SunAz: %6.1f\n" - "SunEl: %6.1f\n" - "Freq: %6d\n" - "Tsky: %6d\n" - "MNR: %6.1f\n" - "Dgrd: %6.1f", - azmoon,elmoon,ndop00,techo,azmoondx,elmoondx,ndop,decmoon, - azsun,elsun,nfreq,ntsky,xnr,dgrd); - ui->astroTextBrowser->setText(" "+ date + "\nUTC: " + utc + "\n" + cc); + QString message; + { + QTextStream out {&message}; + out + << " " << date << "\n" + "UTC: " << utc << "\n" + << fixed + << qSetFieldWidth (6) + << qSetRealNumberPrecision (1) + << "Az: " << azmoon << "\n" + "El: " << elmoon << "\n" + "MyDop: " << ndop00 << "\n" + << qSetRealNumberPrecision (2) + << "Delay: " << techo << "\n" + << qSetRealNumberPrecision (1) + << "DxAz: " << azmoondx << "\n" + "DxEl: " << elmoondx << "\n" + "DxDop: " << ndop << "\n" + "Dec: " << decmoon << "\n" + "SunAz: " << azsun << "\n" + "SunEl: " << elsun << "\n" + "Freq: " << nfreq << "\n" + "Tsky: " << ntsky << "\n" + "MNR: " << xnr << "\n" + "Dgrd: " << dgrd; + } + ui_->text_label->setText(message); - QString fname=azelDir+"/azel.dat"; - QFile f(fname); + QString fname {"azel.dat"}; + QFile f(data_path_.absoluteFilePath (fname)); if(!f.open(QIODevice::WriteOnly | QIODevice::Text)) { QMessageBox mb; - mb.setText("Cannot open " + fname); + mb.setText("Cannot open \"" + f.fileName () + "\"."); mb.exec(); return; } int ndiff=0; if(ntxFreq != ntxFreq0) ndiff=1; ntxFreq0=ntxFreq; - QTextStream out(&f); - sprintf(cc,"%2.2d:%2.2d:%2.2d,%5.1f,%5.1f,Moon\n" - "%2.2d:%2.2d:%2.2d,%5.1f,%5.1f,Sun\n" - "%2.2d:%2.2d:%2.2d,%5.1f,%5.1f,Source\n" - "%4d,%6d,Doppler\n" - "%3d,%1d,fQSO\n" - "%3d,%1d,fQSO2\n", - nhr,nmin,isec,azmoon,elmoon, - nhr,nmin,isec,azsun,elsun, - nhr,nmin,isec,0.0,0.0, - nfreq,ndop, - fQSO,nsetftx, - ntxFreq,ndiff); - out << cc; + { + QTextStream out {&f}; + out << fixed + << qSetFieldWidth (2) + << qSetRealNumberPrecision (1) + << qSetPadChar ('0') + << right + << nhr << ':' << nmin << ':' << isec + << qSetFieldWidth (5) + << ',' << azmoon << ',' << elmoon << ",Moon\n" + << qSetFieldWidth (2) + << nhr << ':' << nmin << ':' << isec + << qSetFieldWidth (5) + << ',' << azsun << ',' << elsun << ",Sun\n" + << qSetFieldWidth (2) + << nhr << ':' << nmin << ':' << isec + << qSetFieldWidth (5) + << ',' << 0. << ',' << 0. << ",Sun\n" + << qSetPadChar (' ') + << qSetFieldWidth (4) + << nfreq << ',' + << qSetFieldWidth (6) + << ndop << ",Doppler\n" + << qSetFieldWidth (3) + << fQSO << ',' + << qSetFieldWidth (1) + << nsetftx << ",fQSO\n" + << qSetFieldWidth (3) + << ntxFreq << ',' + << qSetFieldWidth (1) + << ndiff << ",fQSO2"; + } f.close(); } - -void Astro::setFontSize(int n) -{ - ui->astroTextBrowser->setFontPointSize(n); -} diff --git a/astro.h b/astro.h index 4a0e45ce9..f0879b1b6 100644 --- a/astro.h +++ b/astro.h @@ -1,36 +1,52 @@ +// -*- Mode: C++ -*- #ifndef ASTRO_H #define ASTRO_H #include -#include +#include + +class QSettings; namespace Ui { class Astro; } -class Astro : public QWidget +class Astro final + : public QWidget { - Q_OBJECT - -public: - explicit Astro(QWidget *parent = 0); - void astroUpdate(QDateTime t, QString mygrid, QString hisgrid, - int fQSO, int nsetftx, int ntxFreq, QString azelDir); - void setFontSize(int n); -// ~Astro(); - virtual ~Astro(); + Q_OBJECT; private: - Ui::Astro *ui; + Q_DISABLE_COPY (Astro); + +public: + explicit Astro(QSettings * settings, QDir const& dataPath, QWidget * parent = nullptr); + ~Astro (); + + void astroUpdate(QDateTime t, QString mygrid, QString hisgrid, + int fQSO, int nsetftx, int ntxFreq); + + Q_SLOT void on_font_push_button_clicked (bool); + +protected: + void closeEvent (QCloseEvent *) override; + +private: + void read_settings (); + void write_settings (); + + QSettings * settings_; + QScopedPointer ui_; + QDir data_path_; }; extern "C" { void astrosub_(int* nyear, int* month, int* nday, double* uth, int* nfreq, - const char* mygrid, const char* hisgrid, double* azsun, - double* elsun, double* azmoon, double* elmoon, double* azmoondx, - double* elmoondx, int* ntsky, int* ndop, int* ndop00, - double* ramoon, double* decmoon, double* dgrd, double* poloffset, - double* xnr, double* techo, int len1, int len2); + const char* mygrid, const char* hisgrid, double* azsun, + double* elsun, double* azmoon, double* elmoon, double* azmoondx, + double* elmoondx, int* ntsky, int* ndop, int* ndop00, + double* ramoon, double* decmoon, double* dgrd, double* poloffset, + double* xnr, double* techo, int len1, int len2); } #endif // ASTRO_H diff --git a/astro.ui b/astro.ui index df1ce80c7..a8c8f044c 100644 --- a/astro.ui +++ b/astro.ui @@ -6,31 +6,100 @@ 0 0 - 262 - 483 + 169 + 79 - - Form + + + 0 + 0 + - - - - 0 - 10 - 256 - 451 - + + QWidget { + background: cyan; +} + + + + 0 - - - Courier New - 20 - 75 - true - + + 0 - + + 0 + + + 9 + + + + + + 0 + 0 + + + + + Courier + 18 + + + + QFrame::Sunken + + + Astro Data + + + Qt::AlignCenter + + + 6 + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Font ... + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + diff --git a/contrib/Commander TCPIP Mesages.pdf b/contrib/Commander TCPIP Mesages.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ca7b42e508ca29c4d2407d2213f60366d138893a GIT binary patch literal 168173 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%0A0>moIwWLs%K9F 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 T^gu?=R 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

WzLcBNd0qn162zF!LLG$MIg%%2d7uwcLYTGxB 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

N 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�T!x^_)1L=pc!Ox(4;i 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