Compare commits
149 Commits
55261b6149
...
v0.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
| c0c4693782 | |||
| 9223d3da40 | |||
| 83e3f5ddbc | |||
| 0f4057aa97 | |||
| 591629e369 | |||
| 4a96ab3b13 | |||
| e955cff24f | |||
| fe405cfba8 | |||
| 92117aa791 | |||
| d4c2d9a871 | |||
| b2e2b91d31 | |||
| fa864c50cd | |||
| 1c6d1babe6 | |||
| ac27d1a9b6 | |||
| 28eb082655 | |||
| 9a945c156d | |||
| 83c742f7ec | |||
| 7a788c05c8 | |||
| 7b409a6ff4 | |||
| 87a631f5f0 | |||
| efd6b54ba7 | |||
| 553f2400e5 | |||
| 5c84e79e5b | |||
| 052b81ec8f | |||
| 7ecc550bc2 | |||
| b8267372e4 | |||
| 512dffabf4 | |||
| 50a3a56d2d | |||
| deb228948d | |||
| 58032b6ae4 | |||
| 7845736c05 | |||
| 77eb65d6b3 | |||
| 252c21b818 | |||
| 82c3b23e44 | |||
| 5764170975 | |||
| a2c85256e8 | |||
| 9419383ab0 | |||
| 4c63129876 | |||
| f2b876df49 | |||
| f229019ef5 | |||
| 3260bb7b89 | |||
| 2832572741 | |||
| 28df33b218 | |||
| 6ee0820659 | |||
| 2c73ccde9b | |||
| 90ce372081 | |||
| 15d75f7397 | |||
| f47c1a5024 | |||
| c74ed5135b | |||
| b08ecd21e6 | |||
| 1c98d47718 | |||
| 46e11f8d00 | |||
| 1e0a93e076 | |||
| f77f139abb | |||
| 2ae74d8cde | |||
| 369b5fd73a | |||
| 4de968d2f0 | |||
| 09b12701b5 | |||
| d00eee440c | |||
| c1df21f940 | |||
| 9117ad5381 | |||
| a96216e2f8 | |||
| 4140114d8d | |||
| bd34bf104f | |||
| 6a265efe48 | |||
| 983790a3ff | |||
| 43b65d5ca9 | |||
| 8bc61902ac | |||
| 4e0326ad6d | |||
| 808782b965 | |||
| 707f577f31 | |||
| 705244786e | |||
| 4e66e92671 | |||
| 283e7fae77 | |||
| 441936111a | |||
| f81a954d1d | |||
| 23c1730148 | |||
| 05257d287f | |||
| 64b5ebbdd2 | |||
| 91d6836fa5 | |||
| dd3613b214 | |||
| c96522c11b | |||
| 564b93f307 | |||
| 04eaf61c13 | |||
| b800dac9ce | |||
| 2cb78f5414 | |||
| 494459ee11 | |||
| 1cddbdf91e | |||
| 74ea603801 | |||
| 16854627d9 | |||
| 495c16892f | |||
| c596f23a05 | |||
| b69e042f21 | |||
| ec568966c8 | |||
| eb062fb0b8 | |||
| 9907a80136 | |||
| cd9079e7ff | |||
| 42a8338d1c | |||
| f44b1154b7 | |||
| 722f2f10ae | |||
| 2a7f38b187 | |||
| f9ab37530c | |||
| 442ff4b21d | |||
| ecacddb165 | |||
| 6aab2276ed | |||
| 5c9f9e8141 | |||
| 60563a7dc3 | |||
| 7255728049 | |||
| 50094fd8a9 | |||
| c45f4c137a | |||
| 16b46176a6 | |||
| 0df4bbcd29 | |||
| 3bbea95955 | |||
| fa0baad9a0 | |||
| 7b7493d560 | |||
| dc6de6d819 | |||
| b7a51a5764 | |||
| 145bc8d292 | |||
| f58ce3aec0 | |||
| 27b45a26d9 | |||
| 0653f81a0d | |||
| 1134cd5782 | |||
| aa1871dc66 | |||
| 56869d16a9 | |||
| ccf00dc460 | |||
| 57ad5fd0bc | |||
| 7d9553dd7c | |||
| cad3f43752 | |||
| 2605fb1a8f | |||
| 130b749dfe | |||
| 04bdf8574a | |||
| 0dfc805a49 | |||
| 022866b52b | |||
| 9ed0fe80d2 | |||
| 7837ff5d74 | |||
| bee42d1762 | |||
| 26c76662ac | |||
| e3a9762179 | |||
| d048f5a2ab | |||
| 0a95c79f3a | |||
| 762f0fb3e1 | |||
| 812b11a53d | |||
| c517b555d8 | |||
| f610e946fc | |||
| cb71c3dcf4 | |||
| 5c8ff568c3 | |||
| 87cdc7f7e7 | |||
| e694d862aa | |||
| 4df7aae11a |
BIN
Binary file not shown.
@@ -2,13 +2,15 @@
|
||||
# To pass variables to cpack from cmake, they must be configured
|
||||
# in this file.
|
||||
|
||||
set (CPACK_SET_DESTDIR true)
|
||||
|
||||
set (CPACK_PACKAGE_VENDOR "@PROJECT_VENDOR@")
|
||||
set (CPACK_PACKAGE_CONTACT "@PROJECT_CONTACT@")
|
||||
set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "@PROJECT_SUMMARY_DESCRIPTION@")
|
||||
set (CPACK_RESOURCE_FILE_LICENSE "@PROJECT_SOURCE_DIR@/COPYING")
|
||||
set (CPACK_PACKAGE_INSTALL_DIRECTORY ${CPACK_PACKAGE_NAME})
|
||||
set (CPACK_PACKAGE_EXECUTABLES wsjtx "@PROJECT_NAME@")
|
||||
set (CPACK_CREATE_DESKTOP_LINKS wsjtx)
|
||||
set (CPACK_PACKAGE_EXECUTABLES ft8call "@PROJECT_NAME@")
|
||||
set (CPACK_CREATE_DESKTOP_LINKS ft8call)
|
||||
set (CPACK_STRIP_FILES TRUE)
|
||||
|
||||
#
|
||||
@@ -19,9 +21,10 @@ set (CPACK_STRIP_FILES TRUE)
|
||||
#set (CPACK_COMPONENT_RUNTIME_DESCRIPTION "@WSJTX_DESCRIPTION_SUMMARY@")
|
||||
|
||||
if (CPACK_GENERATOR MATCHES "NSIS")
|
||||
set (CPACK_SET_DESTDIR FALSE)
|
||||
set (CPACK_STRIP_FILES FALSE) # breaks Qt packaging on Windows
|
||||
|
||||
set (CPACK_NSIS_INSTALL_ROOT "C:\\WSJT")
|
||||
set (CPACK_NSIS_INSTALL_ROOT "C:\\FT8Call")
|
||||
|
||||
# set the install/unistall icon used for the installer itself
|
||||
# There is a bug in NSI that does not handle full unix paths properly.
|
||||
@@ -35,13 +38,13 @@ if (CPACK_GENERATOR MATCHES "NSIS")
|
||||
"@PROJECT_HOMEPAGE@" "@PROJECT_NAME@ Web Site"
|
||||
)
|
||||
# Use the icon from wsjtx for add-remove programs
|
||||
set (CPACK_NSIS_INSTALLED_ICON_NAME "bin\\\\wsjtx.exe")
|
||||
set (CPACK_NSIS_INSTALLED_ICON_NAME "bin\\\\ft8call.exe")
|
||||
|
||||
set (CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_DESCRIPTION_SUMMARY}")
|
||||
set (CPACK_NSIS_HELP_LINK "@PROJECT_MANUAL_DIRECTORY_URL@/@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_MUI_FINISHPAGE_RUN "ft8call.exe")
|
||||
set (CPACK_NSIS_MODIFY_PATH ON)
|
||||
endif ()
|
||||
|
||||
@@ -65,9 +68,9 @@ 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}")
|
||||
"${CPACK_PACKAGE_NAME}-@ft8call_VERSION@-${CPACK_SYSTEM_NAME}")
|
||||
set (CPACK_SOURCE_PACKAGE_FILE_NAME
|
||||
"${CPACK_PACKAGE_NAME}-@wsjtx_VERSION@-Source")
|
||||
"${CPACK_PACKAGE_NAME}-@ft8call_VERSION@-Source")
|
||||
|
||||
if (NOT CPACK_WIX_SIZEOF_VOID_P)
|
||||
set (CPACK_WIX_SIZEOF_VOID_P "@CMAKE_SIZEOF_VOID_P@")
|
||||
|
||||
+25
-24
@@ -22,7 +22,7 @@ Change this to the newest SDK available that you can install on your system (10.
|
||||
Do not override this if you intend to build an official deployable installer.")
|
||||
endif (APPLE)
|
||||
|
||||
project (wsjtx C CXX Fortran)
|
||||
project (ft8call C CXX Fortran)
|
||||
|
||||
#
|
||||
# CMake policies
|
||||
@@ -45,10 +45,10 @@ message (STATUS "Building ${CMAKE_PROJECT_NAME}-${wsjtx_VERSION}")
|
||||
#
|
||||
# project information
|
||||
#
|
||||
set (PROJECT_NAME "WSJT-X")
|
||||
set (PROJECT_VENDOR "Joe Taylor, K1JT")
|
||||
set (PROJECT_CONTACT "Joe Taylor <k1jt@arrl.net>")
|
||||
set (PROJECT_COPYRIGHT "Copyright (C) 2001-2018 by Joe Taylor, K1JT")
|
||||
set (PROJECT_NAME "FT8Call")
|
||||
set (PROJECT_VENDOR "Jordan Sherer, KN4CRD")
|
||||
set (PROJECT_CONTACT "Jordan Sherer <kn4crd@gmail.com>")
|
||||
set (PROJECT_COPYRIGHT "Copyright (C) 2001-2018 by Joe Taylor, K1JT, (C) 2018 by Jordan Sherer, KN4CRD")
|
||||
set (PROJECT_HOMEPAGE http://www.physics.princeton.edu/pulsar/K1JT/wsjtx.html)
|
||||
set (PROJECT_MANUAL wsjtx-main)
|
||||
set (PROJECT_MANUAL_DIRECTORY_URL http://www.physics.princeton.edu/pulsar/K1JT/wsjtx-doc/)
|
||||
@@ -303,6 +303,7 @@ set (wsjtx_CXXSRCS
|
||||
astro.cpp
|
||||
messageaveraging.cpp
|
||||
WsprTxScheduler.cpp
|
||||
varicode.cpp
|
||||
mainwindow.cpp
|
||||
Configuration.cpp
|
||||
main.cpp
|
||||
@@ -1298,7 +1299,7 @@ else (${OPENMP_FOUND} OR APPLE)
|
||||
endif (${OPENMP_FOUND} OR APPLE)
|
||||
|
||||
# build the main application
|
||||
add_executable (wsjtx MACOSX_BUNDLE
|
||||
add_executable (ft8call MACOSX_BUNDLE
|
||||
${wsjtx_CXXSRCS}
|
||||
${wsjtx_GENUISRCS}
|
||||
wsjtx.rc
|
||||
@@ -1307,10 +1308,10 @@ add_executable (wsjtx MACOSX_BUNDLE
|
||||
)
|
||||
|
||||
if (WSJT_CREATE_WINMAIN)
|
||||
set_target_properties (wsjtx PROPERTIES WIN32_EXECUTABLE ON)
|
||||
set_target_properties (ft8call PROPERTIES WIN32_EXECUTABLE ON)
|
||||
endif (WSJT_CREATE_WINMAIN)
|
||||
|
||||
set_target_properties (wsjtx PROPERTIES
|
||||
set_target_properties (ft8call PROPERTIES
|
||||
MACOSX_BUNDLE_INFO_STRING "${WSJTX_DESCRIPTION_SUMMARY}"
|
||||
MACOSX_BUNDLE_ICON_FILE "${WSJTX_ICON_FILE}"
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION ${wsjtx_VERSION}
|
||||
@@ -1321,27 +1322,27 @@ set_target_properties (wsjtx PROPERTIES
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER "org.k1jt.wsjtx"
|
||||
)
|
||||
|
||||
target_include_directories (wsjtx PRIVATE ${FFTW3_INCLUDE_DIRS})
|
||||
target_include_directories (ft8call PRIVATE ${FFTW3_INCLUDE_DIRS})
|
||||
if (APPLE)
|
||||
target_link_libraries (wsjtx wsjt_fort wsjt_cxx wsjt_qt wsjt_qtmm ${hamlib_LIBRARIES} ${FFTW3_LIBRARIES})
|
||||
target_link_libraries (ft8call wsjt_fort wsjt_cxx wsjt_qt wsjt_qtmm ${hamlib_LIBRARIES} ${FFTW3_LIBRARIES})
|
||||
else ()
|
||||
target_link_libraries (wsjtx wsjt_fort_omp wsjt_cxx wsjt_qt wsjt_qtmm ${hamlib_LIBRARIES} ${FFTW3_LIBRARIES})
|
||||
target_link_libraries (ft8call wsjt_fort_omp wsjt_cxx wsjt_qt wsjt_qtmm ${hamlib_LIBRARIES} ${FFTW3_LIBRARIES})
|
||||
if (OpenMP_C_FLAGS)
|
||||
set_target_properties (wsjtx PROPERTIES
|
||||
set_target_properties (ft8call PROPERTIES
|
||||
COMPILE_FLAGS "${OpenMP_C_FLAGS}"
|
||||
LINK_FLAGS "${OpenMP_C_FLAGS}"
|
||||
)
|
||||
endif ()
|
||||
set_target_properties (wsjtx PROPERTIES
|
||||
set_target_properties (ft8call PROPERTIES
|
||||
Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/fortran_modules_omp
|
||||
)
|
||||
if (WIN32)
|
||||
set_target_properties (wsjtx PROPERTIES
|
||||
set_target_properties (ft8call PROPERTIES
|
||||
LINK_FLAGS -Wl,--stack,16777216
|
||||
)
|
||||
endif ()
|
||||
endif ()
|
||||
qt5_use_modules (wsjtx SerialPort) # not sure why the interface link library syntax above doesn't work
|
||||
qt5_use_modules (ft8call SerialPort) # not sure why the interface link library syntax above doesn't work
|
||||
|
||||
# make a library for WSJT-X UDP servers
|
||||
# add_library (wsjtx_udp SHARED ${UDP_library_CXXSRCS})
|
||||
@@ -1386,18 +1387,18 @@ endif (WSJT_CREATE_WINMAIN)
|
||||
if (UNIX)
|
||||
if (NOT WSJT_SKIP_MANPAGES)
|
||||
add_subdirectory (manpages)
|
||||
add_dependencies (wsjtx manpages)
|
||||
add_dependencies (ft8call manpages)
|
||||
endif (NOT WSJT_SKIP_MANPAGES)
|
||||
if (NOT APPLE)
|
||||
add_subdirectory (debian)
|
||||
add_dependencies (wsjtx debian)
|
||||
add_dependencies (ft8call debian)
|
||||
endif (NOT APPLE)
|
||||
endif (UNIX)
|
||||
|
||||
#
|
||||
# installation
|
||||
#
|
||||
install (TARGETS wsjtx
|
||||
install (TARGETS ft8call
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
BUNDLE DESTINATION . COMPONENT runtime
|
||||
)
|
||||
@@ -1487,11 +1488,11 @@ add_custom_target (uninstall
|
||||
|
||||
|
||||
# creates svnversion.h using cmake script
|
||||
add_custom_target (revisiontag
|
||||
COMMAND ${CMAKE_COMMAND} -D SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} -D OUTPUT_DIR=${PROJECT_BINARY_DIR} -P ${CMAKE_CURRENT_SOURCE_DIR}/CMake/getsvn.cmake
|
||||
COMMENT "Generating Subversion revision information"
|
||||
VERBATIM
|
||||
)
|
||||
# add_custom_target (revisiontag
|
||||
# COMMAND ${CMAKE_COMMAND} -D SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} -D OUTPUT_DIR=${PROJECT_BINARY_DIR} -P ${CMAKE_CURRENT_SOURCE_DIR}/CMake/getsvn.cmake
|
||||
# COMMENT "Generating Subversion revision information"
|
||||
# VERBATIM
|
||||
# )
|
||||
# explicitly say that the wsjt_qt depends on custom target, this is
|
||||
# done indirectly so that the revisiontag target gets built exactly
|
||||
# once per build
|
||||
@@ -1511,7 +1512,7 @@ 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 message_aggregator.desktop
|
||||
FILES ft8call.desktop message_aggregator.desktop
|
||||
DESTINATION share/applications
|
||||
#COMPONENT runtime
|
||||
)
|
||||
|
||||
+79
-3
@@ -140,6 +140,7 @@
|
||||
#include <QSettings>
|
||||
#include <QAudioDeviceInfo>
|
||||
#include <QAudioInput>
|
||||
#include <QDebug>
|
||||
#include <QDialog>
|
||||
#include <QAction>
|
||||
#include <QFileDialog>
|
||||
@@ -160,7 +161,6 @@
|
||||
#include <QColorDialog>
|
||||
#include <QSerialPortInfo>
|
||||
#include <QScopedPointer>
|
||||
#include <QDebug>
|
||||
|
||||
#include "pimpl_impl.hpp"
|
||||
#include "qt_helpers.hpp"
|
||||
@@ -430,6 +430,8 @@ private:
|
||||
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_station_message_line_edit_textChanged(QString const&);
|
||||
Q_SLOT void on_qth_message_line_edit_textChanged(QString const&);
|
||||
Q_SLOT void on_add_macro_line_edit_editingFinished ();
|
||||
Q_SLOT void delete_macro ();
|
||||
void delete_selected_macros (QModelIndexList);
|
||||
@@ -529,6 +531,10 @@ private:
|
||||
// configuration fields that we publish
|
||||
QString my_callsign_;
|
||||
QString my_grid_;
|
||||
QString my_station_;
|
||||
QString my_qth_;
|
||||
int callsign_aging_;
|
||||
int activity_aging_;
|
||||
QColor color_CQ_;
|
||||
QColor next_color_CQ_;
|
||||
QColor color_MyCall_;
|
||||
@@ -560,6 +566,7 @@ private:
|
||||
bool miles_;
|
||||
bool quick_call_;
|
||||
bool disable_TX_on_73_;
|
||||
int beacon_;
|
||||
int watchdog_;
|
||||
bool TX_messages_;
|
||||
bool enable_VHF_features_;
|
||||
@@ -649,6 +656,14 @@ bool Configuration::spot_to_psk_reporter () const
|
||||
// rig must be open and working to spot externally
|
||||
return is_transceiver_online () && m_->spot_to_psk_reporter_;
|
||||
}
|
||||
void Configuration::set_spot_to_psk_reporter (bool spot)
|
||||
{
|
||||
if(m_->spot_to_psk_reporter_ != spot){
|
||||
m_->spot_to_psk_reporter_ = spot;
|
||||
m_->write_settings();
|
||||
}
|
||||
}
|
||||
|
||||
bool Configuration::monitor_off_at_startup () const {return m_->monitor_off_at_startup_;}
|
||||
bool Configuration::monitor_last_used () const {return m_->rig_is_dummy_ || m_->monitor_last_used_;}
|
||||
bool Configuration::log_as_RTTY () const {return m_->log_as_RTTY_;}
|
||||
@@ -661,6 +676,7 @@ 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_;}
|
||||
int Configuration::beacon () const {return m_->beacon_;}
|
||||
int Configuration::watchdog () const {return m_->watchdog_;}
|
||||
bool Configuration::TX_messages () const {return m_->TX_messages_;}
|
||||
bool Configuration::enable_VHF_features () const {return m_->enable_VHF_features_;}
|
||||
@@ -807,6 +823,26 @@ QString Configuration::my_grid() const
|
||||
return the_grid;
|
||||
}
|
||||
|
||||
QString Configuration::my_station() const
|
||||
{
|
||||
return m_->my_station_;
|
||||
}
|
||||
|
||||
QString Configuration::my_qth() const
|
||||
{
|
||||
return m_->my_qth_;
|
||||
}
|
||||
|
||||
int Configuration::callsign_aging() const
|
||||
{
|
||||
return m_->callsign_aging_;
|
||||
}
|
||||
|
||||
int Configuration::activity_aging() const
|
||||
{
|
||||
return m_->activity_aging_;
|
||||
}
|
||||
|
||||
void Configuration::set_location (QString const& grid_descriptor)
|
||||
{
|
||||
// change the dynamic grid
|
||||
@@ -945,6 +981,8 @@ Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
|
||||
ui_->callsign_line_edit->setValidator (new CallsignValidator {this});
|
||||
ui_->grid_line_edit->setValidator (new MaidenheadLocatorValidator {this});
|
||||
ui_->add_macro_line_edit->setValidator (new QRegExpValidator {message_alphabet, this});
|
||||
ui_->station_message_line_edit->setValidator (new QRegExpValidator {message_alphabet, this});
|
||||
ui_->qth_message_line_edit->setValidator (new QRegExpValidator {message_alphabet, this});
|
||||
|
||||
ui_->udp_server_port_spin_box->setMinimum (1);
|
||||
ui_->udp_server_port_spin_box->setMaximum (std::numeric_limits<port_type>::max ());
|
||||
@@ -1119,6 +1157,10 @@ void Configuration::impl::initialize_models ()
|
||||
ui_->grid_line_edit->setPalette (pal);
|
||||
ui_->callsign_line_edit->setText (my_callsign_);
|
||||
ui_->grid_line_edit->setText (my_grid_);
|
||||
ui_->callsign_aging_spin_box->setValue(callsign_aging_);
|
||||
ui_->activity_aging_spin_box->setValue(activity_aging_);
|
||||
ui_->station_message_line_edit->setText (my_station_.toUpper());
|
||||
ui_->qth_message_line_edit->setText (my_qth_.toUpper());
|
||||
ui_->use_dynamic_grid->setChecked(use_dynamic_grid_);
|
||||
ui_->labCQ->setStyleSheet(QString("background: %1").arg(color_CQ_.name()));
|
||||
ui_->labMyCall->setStyleSheet(QString("background: %1").arg(color_MyCall_.name()));
|
||||
@@ -1149,6 +1191,7 @@ void Configuration::impl::initialize_models ()
|
||||
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_->beacon_spin_box->setValue (beacon_);
|
||||
ui_->tx_watchdog_spin_box->setValue (watchdog_);
|
||||
ui_->TX_messages_check_box->setChecked (TX_messages_);
|
||||
ui_->enable_VHF_features_check_box->setChecked(enable_VHF_features_);
|
||||
@@ -1236,6 +1279,10 @@ void Configuration::impl::read_settings ()
|
||||
|
||||
my_callsign_ = settings_->value ("MyCall", QString {}).toString ();
|
||||
my_grid_ = settings_->value ("MyGrid", QString {}).toString ();
|
||||
my_station_ = settings_->value("MyStation", QString {}).toString();
|
||||
callsign_aging_ = settings_->value ("CallsignAging", 0).toInt ();
|
||||
activity_aging_ = settings_->value ("ActivityAging", 2).toInt ();
|
||||
my_qth_ = settings_->value("MyQTH", QString {}).toString();
|
||||
next_color_CQ_ = color_CQ_ = settings_->value("colorCQ","#66ff66").toString();
|
||||
next_color_MyCall_ = color_MyCall_ = settings_->value("colorMyCall","#ff6666").toString();
|
||||
next_color_TxMsg_ = color_TxMsg_ = settings_->value("colorTxMsg","#ffff00").toString();
|
||||
@@ -1336,7 +1383,9 @@ void Configuration::impl::read_settings ()
|
||||
tx_QSY_allowed_ = settings_->value ("TxQSYAllowed", false).toBool ();
|
||||
use_dynamic_grid_ = settings_->value ("AutoGrid", false).toBool ();
|
||||
|
||||
macros_.setStringList (settings_->value ("Macros", QStringList {"TNX 73 GL"}).toStringList ());
|
||||
auto loadedMacros = settings_->value ("Macros", QStringList {"TNX 73 GL"}).toStringList();
|
||||
|
||||
macros_.setStringList (loadedMacros);
|
||||
|
||||
region_ = settings_->value ("Region", QVariant::fromValue (IARURegions::ALL)).value<IARURegions::Region> ();
|
||||
|
||||
@@ -1386,7 +1435,8 @@ void Configuration::impl::read_settings ()
|
||||
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 ("TxWatchdog", 6).toInt ();
|
||||
beacon_ = settings_->value ("TxBeacon", 5).toInt ();
|
||||
watchdog_ = settings_->value ("TxWatchdog", 0).toInt ();
|
||||
TX_messages_ = settings_->value ("Tx2QSO", true).toBool ();
|
||||
enable_VHF_features_ = settings_->value("VHFUHF",false).toBool ();
|
||||
decode_at_52s_ = settings_->value("Decode52",false).toBool ();
|
||||
@@ -1419,6 +1469,10 @@ void Configuration::impl::write_settings ()
|
||||
|
||||
settings_->setValue ("MyCall", my_callsign_);
|
||||
settings_->setValue ("MyGrid", my_grid_);
|
||||
settings_->setValue ("MyStation", my_station_);
|
||||
settings_->setValue ("MyQTH", my_qth_);
|
||||
settings_->setValue ("CallsignAging", callsign_aging_);
|
||||
settings_->setValue ("ActivityAging", activity_aging_);
|
||||
settings_->setValue("colorCQ",color_CQ_);
|
||||
settings_->setValue("colorMyCall",color_MyCall_);
|
||||
settings_->setValue("colorTxMsg",color_TxMsg_);
|
||||
@@ -1484,6 +1538,7 @@ void Configuration::impl::write_settings ()
|
||||
settings_->setValue ("Miles", miles_);
|
||||
settings_->setValue ("QuickCall", quick_call_);
|
||||
settings_->setValue ("73TxDisable", disable_TX_on_73_);
|
||||
settings_->setValue ("TxBeacon", beacon_);
|
||||
settings_->setValue ("TxWatchdog", watchdog_);
|
||||
settings_->setValue ("Tx2QSO", TX_messages_);
|
||||
settings_->setValue ("CATForceDTR", rig_params_.force_dtr);
|
||||
@@ -1869,6 +1924,10 @@ void Configuration::impl::accept ()
|
||||
|
||||
my_callsign_ = ui_->callsign_line_edit->text ();
|
||||
my_grid_ = ui_->grid_line_edit->text ();
|
||||
my_station_ = ui_->station_message_line_edit->text().toUpper();
|
||||
my_qth_ = ui_->qth_message_line_edit->text().toUpper();
|
||||
callsign_aging_ = ui_->callsign_aging_spin_box->value();
|
||||
activity_aging_ = ui_->activity_aging_spin_box->value();
|
||||
spot_to_psk_reporter_ = ui_->psk_reporter_check_box->isChecked ();
|
||||
id_interval_ = ui_->CW_id_interval_spin_box->value ();
|
||||
ntrials_ = ui_->sbNtrials->value ();
|
||||
@@ -1891,6 +1950,7 @@ void Configuration::impl::accept ()
|
||||
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 ();
|
||||
beacon_ = ui_->beacon_spin_box->value ();
|
||||
watchdog_ = ui_->tx_watchdog_spin_box->value ();
|
||||
TX_messages_ = ui_->TX_messages_check_box->isChecked ();
|
||||
data_mode_ = static_cast<DataMode> (ui_->TX_mode_button_group->checkedId ());
|
||||
@@ -2151,6 +2211,22 @@ void Configuration::impl::on_sound_output_combo_box_currentTextChanged (QString
|
||||
default_audio_output_device_selected_ = QAudioDeviceInfo::defaultOutputDevice ().deviceName () == text;
|
||||
}
|
||||
|
||||
void Configuration::impl::on_station_message_line_edit_textChanged(QString const &text)
|
||||
{
|
||||
QString upper = text.toUpper();
|
||||
if(text != upper){
|
||||
ui_->station_message_line_edit->setText (upper);
|
||||
}
|
||||
}
|
||||
|
||||
void Configuration::impl::on_qth_message_line_edit_textChanged(QString const &text)
|
||||
{
|
||||
QString upper = text.toUpper();
|
||||
if(text != upper){
|
||||
ui_->qth_message_line_edit->setText (upper);
|
||||
}
|
||||
}
|
||||
|
||||
void Configuration::impl::on_add_macro_line_edit_editingFinished ()
|
||||
{
|
||||
ui_->add_macro_line_edit->setText (ui_->add_macro_line_edit->text ().toUpper ());
|
||||
|
||||
@@ -96,6 +96,10 @@ public:
|
||||
|
||||
QString my_callsign () const;
|
||||
QString my_grid () const;
|
||||
QString my_station () const;
|
||||
int activity_aging() const;
|
||||
int callsign_aging() const;
|
||||
QString my_qth () const;
|
||||
QFont text_font () const;
|
||||
QFont decoded_text_font () const;
|
||||
qint32 id_interval () const;
|
||||
@@ -107,6 +111,7 @@ public:
|
||||
bool id_after_73 () const;
|
||||
bool tx_QSY_allowed () const;
|
||||
bool spot_to_psk_reporter () const;
|
||||
void set_spot_to_psk_reporter (bool);
|
||||
bool monitor_off_at_startup () const;
|
||||
bool monitor_last_used () const;
|
||||
bool log_as_RTTY () const;
|
||||
@@ -119,6 +124,7 @@ public:
|
||||
bool miles () const;
|
||||
bool quick_call () const;
|
||||
bool disable_TX_on_73 () const;
|
||||
int beacon () const;
|
||||
int watchdog () const;
|
||||
bool TX_messages () const;
|
||||
bool split_mode () const;
|
||||
|
||||
+684
-407
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,8 @@ namespace
|
||||
"MSK144",
|
||||
"QRA64",
|
||||
"FreqCal",
|
||||
"FT8"
|
||||
"FT8",
|
||||
"FT8Free"
|
||||
};
|
||||
std::size_t constexpr mode_names_size = sizeof (mode_names) / sizeof (mode_names[0]);
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ public:
|
||||
QRA64,
|
||||
FreqCal,
|
||||
FT8,
|
||||
FT8Free,
|
||||
MODES_END_SENTINAL_AND_COUNT // this must be last
|
||||
};
|
||||
Q_ENUM (Mode)
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
# Version number components
|
||||
set (WSJTX_VERSION_MAJOR 1)
|
||||
set (WSJTX_VERSION_MINOR 9)
|
||||
set (WSJTX_VERSION_MAJOR 0)
|
||||
set (WSJTX_VERSION_MINOR 2)
|
||||
set (WSJTX_VERSION_PATCH 0)
|
||||
set (WSJTX_RC 2) # release candidate number, comment out or zero for development versions
|
||||
set (WSJTX_RC 0) # release candidate number, comment out or zero for development versions
|
||||
set (WSJTX_VERSION_IS_RELEASE 0) # set to 1 for final release build
|
||||
|
||||
+67
-1
@@ -4,6 +4,8 @@
|
||||
#include <QRegularExpression>
|
||||
#include <QDebug>
|
||||
|
||||
#include <varicode.h>
|
||||
|
||||
extern "C" {
|
||||
bool stdmsg_(char const * msg, bool contest_mode, char const * mygrid, fortran_charlen_t, fortran_charlen_t);
|
||||
}
|
||||
@@ -50,8 +52,72 @@ DecodedText::DecodedText (QString const& the_string, bool contest_mode, QString
|
||||
, contest_mode_
|
||||
, grid_c_string.constData ()
|
||||
, 22, 6);
|
||||
|
||||
// We're only going to unpack standard messages for CQs && beacons...
|
||||
// TODO: jsherer - this is a hack for now...
|
||||
if(is_standard_){
|
||||
is_standard_ = QRegularExpression("^(CQ|DE|QRZ)\\s").match(message_).hasMatch();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if(!is_standard_){
|
||||
bool unpacked = false;
|
||||
|
||||
if(!unpacked){
|
||||
unpacked = tryUnpackDirected();
|
||||
}
|
||||
if(!unpacked){
|
||||
unpacked = tryUnpackData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DecodedText::tryUnpackDirected(){
|
||||
QString m = message().trimmed();
|
||||
|
||||
// directed calls will always be 12+ chars and contain no spaces.
|
||||
if(m.length() < 12 || m.contains(' ')){
|
||||
return false;
|
||||
}
|
||||
|
||||
QStringList parts = Varicode::unpackDirectedMessage(m);
|
||||
|
||||
if(parts.isEmpty()){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(parts.length() == 3){
|
||||
// replace it with the correct unpacked (directed)
|
||||
message_ = QString("%1: %2%3").arg(parts.at(0), parts.at(1), parts.at(2));
|
||||
} else if(parts.length() == 4){
|
||||
// replace it with the correct unpacked (directed numeric)
|
||||
message_ = QString("%1: %2%3 %4").arg(parts.at(0), parts.at(1), parts.at(2), parts.at(3));
|
||||
} else {
|
||||
// replace it with the correct unpacked (freetext)
|
||||
message_ = QString(parts.join(QChar()));
|
||||
}
|
||||
|
||||
directed_ = parts;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DecodedText::tryUnpackData(){
|
||||
QString m = message().trimmed();
|
||||
|
||||
// data frames calls will always be 12+ chars and contain no spaces.
|
||||
if(m.length() < 12 || m.contains(' ')){
|
||||
return false;
|
||||
}
|
||||
|
||||
QString data = Varicode::unpackDataMessage(m);
|
||||
|
||||
if(data.isEmpty()){
|
||||
return false;
|
||||
}
|
||||
|
||||
message_ = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
QStringList DecodedText::messageWords () const
|
||||
{
|
||||
|
||||
+18
-7
@@ -10,6 +10,7 @@
|
||||
#define DECODEDTEXT_H
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
|
||||
|
||||
@@ -31,14 +32,21 @@ class DecodedText
|
||||
public:
|
||||
explicit DecodedText (QString const& message, bool, QString const& my_grid);
|
||||
|
||||
QString string() const { return string_; };
|
||||
QStringList messageWords () const;
|
||||
int indexOf(QString s) const { return string_.indexOf(s); };
|
||||
int indexOf(QString s, int i) const { return string_.indexOf(s,i); };
|
||||
QString mid(int f, int t) const { return string_.mid(f,t); };
|
||||
QString left(int i) const { return string_.left(i); };
|
||||
bool tryUnpackDirected();
|
||||
bool tryUnpackData();
|
||||
|
||||
void clear() { string_.clear(); };
|
||||
QStringList directedMessage() const { return directed_; }
|
||||
bool isDirectedMessage() const { return !directed_.isEmpty(); }
|
||||
|
||||
QString string() const { return string_; }
|
||||
QString message() const { return message_; }
|
||||
QStringList messageWords () const;
|
||||
int indexOf(QString s) const { return string_.indexOf(s); }
|
||||
int indexOf(QString s, int i) const { return string_.indexOf(s,i); }
|
||||
QString mid(int f, int t) const { return string_.mid(f,t); }
|
||||
QString left(int i) const { return string_.left(i); }
|
||||
|
||||
void clear() { string_.clear(); }
|
||||
|
||||
QString CQersCall() const;
|
||||
|
||||
@@ -49,6 +57,8 @@ public:
|
||||
bool isLowConfidence () const;
|
||||
int frequencyOffset() const; // hertz offset from the tuned dial or rx frequency, aka audio frequency
|
||||
int snr() const;
|
||||
bool hasBits() const { return !string_.right(5).trimmed().isEmpty(); }
|
||||
int bits() const { return string_.right(5).trimmed().toShort(); }
|
||||
float dt() const;
|
||||
|
||||
// find and extract any report. Returns true if this is a standard message
|
||||
@@ -75,6 +85,7 @@ private:
|
||||
column_mode = 19,
|
||||
column_qsoText = 22 };
|
||||
|
||||
QStringList directed_;
|
||||
QString string_;
|
||||
int padding_;
|
||||
bool contest_mode_;
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
[Desktop Entry]
|
||||
Version=1.0
|
||||
Name=ft8call
|
||||
Comment=Amateur Radio Weak Signal Operating
|
||||
Exec=ft8call
|
||||
Icon=wsjtx_icon
|
||||
Terminal=false
|
||||
X-MultipleArgs=false
|
||||
Type=Application
|
||||
Categories=AudioVideo;Audio;HamRadio;
|
||||
StartupNotify=true
|
||||
@@ -380,6 +380,7 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
|
||||
if(i3bit.eq.1) decoded(57:)=0
|
||||
call extractmessage174(decoded,message,ncrcflag)
|
||||
decoded=decoded0
|
||||
|
||||
! This needs fixing for messages with i3bit=1:
|
||||
call genft8(message,mygrid6,bcontest,i3bit,msgsent,msgbits,itone)
|
||||
if(lsubtract) call subtractft8(dd0,itone,f1,xdt2)
|
||||
@@ -397,6 +398,7 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
|
||||
if(.not.nagain) xsnr=xsnr2
|
||||
if(xsnr .lt. -24.0) xsnr=-24.0
|
||||
|
||||
|
||||
if(i3bit.eq.1) then
|
||||
do i=1,12
|
||||
i1hiscall(i)=ichar(hiscall12(i:i))
|
||||
@@ -431,6 +433,10 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
|
||||
else
|
||||
msg37=message//' '
|
||||
endif
|
||||
|
||||
if(i3bit.gt.1) then
|
||||
msg37(22:22) = char(48 + i3bit)
|
||||
endif
|
||||
|
||||
return
|
||||
endif
|
||||
|
||||
+3
-1
@@ -423,7 +423,9 @@ subroutine packbits(dbits,nsymd,m0,sym)
|
||||
|
||||
itype=1
|
||||
if(bcontest) then
|
||||
call to_contest_msg(msg0,msg)
|
||||
!call to_contest_msg(msg0,msg)
|
||||
! this causes problems with freetext ala, KN4CRD DE KN4CRD -13 R
|
||||
msg=msg0
|
||||
else
|
||||
msg=msg0
|
||||
end if
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>377</width>
|
||||
<height>257</height>
|
||||
<width>600</width>
|
||||
<height>285</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
||||
@@ -105,7 +105,8 @@ int main(int argc, char *argv[])
|
||||
// that GUI has correct l18n
|
||||
|
||||
// Override programs executable basename as application name.
|
||||
a.setApplicationName ("WSJT-X");
|
||||
//a.setApplicationName ("WSJT-X");
|
||||
a.setApplicationName("FT8Call");
|
||||
a.setApplicationVersion (version ());
|
||||
|
||||
#if QT_VERSION >= 0x050200
|
||||
@@ -259,7 +260,7 @@ int main(int argc, char *argv[])
|
||||
multi_settings.set_common_value (splash_flag_name, false);
|
||||
splash.close ();
|
||||
});
|
||||
splash.show ();
|
||||
//splash.show ();
|
||||
a.processEvents ();
|
||||
}
|
||||
}
|
||||
@@ -295,8 +296,12 @@ int main(int argc, char *argv[])
|
||||
mem_jt9.setKey(a.applicationName ());
|
||||
|
||||
if(!mem_jt9.attach()) {
|
||||
std::cerr << QString("memory attach error: %1").arg(mem_jt9.error()).toLocal8Bit ().data () << std::endl;
|
||||
|
||||
if (!mem_jt9.create(sizeof(struct dec_data))) {
|
||||
splash.hide ();
|
||||
std::cerr << QString("memory create error: %1").arg(mem_jt9.error()).toLocal8Bit ().data () << std::endl;
|
||||
|
||||
MessageBox::critical_message (nullptr, a.translate ("main", "Shared memory error"),
|
||||
a.translate ("main", "Unable to create shared memory segment"));
|
||||
throw std::runtime_error {"Shared memory error"};
|
||||
@@ -324,7 +329,7 @@ int main(int argc, char *argv[])
|
||||
// run the application UI
|
||||
MainWindow w(temp_dir, multiple, &multi_settings, &mem_jt9, downSampleFactor, &splash);
|
||||
w.show();
|
||||
splash.raise ();
|
||||
//splash.raise ();
|
||||
QObject::connect (&a, SIGNAL (lastWindowClosed()), &a, SLOT (quit()));
|
||||
result = a.exec();
|
||||
}
|
||||
|
||||
+1787
-47
File diff suppressed because it is too large
Load Diff
+136
-1
@@ -16,6 +16,7 @@
|
||||
#include <QProgressDialog>
|
||||
#include <QAbstractSocket>
|
||||
#include <QHostAddress>
|
||||
#include <QPair>
|
||||
#include <QPointer>
|
||||
#include <QSet>
|
||||
#include <QVector>
|
||||
@@ -37,6 +38,8 @@
|
||||
#include "astro.h"
|
||||
#include "MessageBox.hpp"
|
||||
#include "NetworkAccessManager.hpp"
|
||||
#include "qorderedmap.h"
|
||||
#include "varicode.h"
|
||||
|
||||
#define NUM_JT4_SYMBOLS 206 //(72+31)*2, embedded sync
|
||||
#define NUM_JT65_SYMBOLS 126 //63 data + 63 sync
|
||||
@@ -117,6 +120,15 @@ public slots:
|
||||
void msgAvgDecode2();
|
||||
void fastPick(int x0, int x1, int y);
|
||||
|
||||
void clearActivity();
|
||||
int logRxTxMessageText(QDateTime date, bool isFree, QString text, int freq, bool tx, int block=-1);
|
||||
void addMessageText(QString text, bool clear=false);
|
||||
void resetMessage();
|
||||
void resetMessageUI();
|
||||
void createMessage(QString const& text);
|
||||
void createMessageTransmitQueue(QString const& text);
|
||||
void resetMessageTransmitQueue();
|
||||
QString popMessageFrame();
|
||||
protected:
|
||||
void keyPressEvent (QKeyEvent *) override;
|
||||
void closeEvent(QCloseEvent *) override;
|
||||
@@ -132,9 +144,13 @@ private slots:
|
||||
void on_tx5_currentTextChanged (QString const&);
|
||||
void on_tx6_editingFinished();
|
||||
void on_actionSettings_triggered();
|
||||
void preparePSKReporter();
|
||||
void on_spotButton_clicked(bool checked);
|
||||
void on_monitorButton_clicked (bool);
|
||||
void on_actionAbout_triggered();
|
||||
void on_autoButton_clicked (bool);
|
||||
void on_labDialFreq_clicked();
|
||||
void on_monitorTxButton_clicked();
|
||||
void on_stopTxButton_clicked();
|
||||
void on_stopButton_clicked();
|
||||
void on_actionRelease_Notes_triggered ();
|
||||
@@ -180,6 +196,9 @@ private slots:
|
||||
void on_txb5_clicked();
|
||||
void on_txb5_doubleClicked ();
|
||||
void on_txb6_clicked();
|
||||
void on_startTxButton_toggled(bool checked);
|
||||
void splitAndSendNextMessage();
|
||||
void on_rbNextFreeTextMsg_toggled (bool status);
|
||||
void on_lookupButton_clicked();
|
||||
void on_addButton_clicked();
|
||||
void on_dxCallEntry_textChanged (QString const&);
|
||||
@@ -201,8 +220,10 @@ private slots:
|
||||
void on_actionErase_ALL_TXT_triggered();
|
||||
void on_actionErase_FoxQSO_txt_triggered();
|
||||
void on_actionErase_wsjtx_log_adi_triggered();
|
||||
void startTx();
|
||||
void startTx2();
|
||||
void startP1();
|
||||
void continueTx();
|
||||
void stopTx();
|
||||
void stopTx2();
|
||||
void on_pbCallCQ_clicked();
|
||||
@@ -213,12 +234,41 @@ private slots:
|
||||
void on_pbSend73_clicked();
|
||||
void on_rbGenMsg_clicked(bool checked);
|
||||
void on_rbFreeText_clicked(bool checked);
|
||||
void on_clearAction_triggered(QObject * sender);
|
||||
void on_cqMacroButton_clicked();
|
||||
void on_qtcMacroButton_clicked();
|
||||
void on_replyMacroButton_clicked();
|
||||
void on_qthMacroButton_clicked();
|
||||
void on_snrMacroButton_clicked();
|
||||
void buildQueryMenu(QMenu *);
|
||||
void on_queryButton_pressed();
|
||||
void on_macrosMacroButton_pressed();
|
||||
void on_tableWidgetRXAll_cellClicked(int row, int col);
|
||||
void on_tableWidgetRXAll_cellDoubleClicked(int row, int col);
|
||||
void on_tableWidgetRXAll_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
|
||||
void on_tableWidgetCalls_cellClicked(int row, int col);
|
||||
void on_tableWidgetCalls_cellDoubleClicked(int row, int col);
|
||||
void on_tableWidgetCalls_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
|
||||
void on_freeTextMsg_currentTextChanged (QString const&);
|
||||
void on_nextFreeTextMsg_currentTextChanged (QString const&);
|
||||
void on_extFreeTextMsg_currentTextChanged (QString const&);
|
||||
void on_extFreeTextMsgEdit_currentTextChanged (QString const&);
|
||||
int currentFreq();
|
||||
QPair<QStringList, QStringList> buildFT8MessageFrames(QString const& text);
|
||||
QString parseFT8Message(QString input, bool *isFree);
|
||||
bool prepareNextMessageFrame();
|
||||
bool isFreqOffsetFree(int f, int bw);
|
||||
int findFreeFreqOffset(int fmin, int fmax, int bw);
|
||||
void scheduleBeacon(bool first=false);
|
||||
void setBeaconTimer(QDateTime timestamp);
|
||||
void prepareBeacon();
|
||||
QString calculateDistance(QString const& grid);
|
||||
void on_rptSpinBox_valueChanged(int n);
|
||||
void killFile();
|
||||
void on_tuneButton_clicked (bool);
|
||||
void on_pbR2T_clicked();
|
||||
void on_pbT2R_clicked();
|
||||
void on_beaconButton_clicked();
|
||||
void acceptQSO (QDateTime const&, QString const& call, QString const& grid
|
||||
, Frequency dial_freq, QString const& mode
|
||||
, QString const& rpt_sent, QString const& rpt_received
|
||||
@@ -285,7 +335,7 @@ private slots:
|
||||
void on_actionMSK144_triggered();
|
||||
void on_actionQRA64_triggered();
|
||||
void on_actionFreqCal_triggered();
|
||||
void splash_done ();
|
||||
void splash_done ();
|
||||
void on_measure_check_box_stateChanged (int);
|
||||
void on_sbNlist_valueChanged(int n);
|
||||
void on_sbNslots_valueChanged(int n);
|
||||
@@ -498,6 +548,7 @@ private:
|
||||
}
|
||||
m_QSOProgress;
|
||||
|
||||
int m_extFreeTxtPos;
|
||||
int m_ihsym;
|
||||
int m_nzap;
|
||||
int m_npts8;
|
||||
@@ -545,6 +596,7 @@ private:
|
||||
QTimer minuteTimer;
|
||||
QTimer splashTimer;
|
||||
QTimer p1Timer;
|
||||
QTimer beaconTimer;
|
||||
|
||||
QString m_path;
|
||||
QString m_baseCall;
|
||||
@@ -583,6 +635,62 @@ private:
|
||||
qint32 ncall;
|
||||
};
|
||||
|
||||
struct CallDetail
|
||||
{
|
||||
QString call;
|
||||
QString grid;
|
||||
int freq;
|
||||
QDateTime utcTimestamp;
|
||||
int snr;
|
||||
};
|
||||
|
||||
struct CommandDetail
|
||||
{
|
||||
QString from;
|
||||
QString to;
|
||||
QString cmd;
|
||||
int freq;
|
||||
QDateTime utcTimestamp;
|
||||
int snr;
|
||||
};
|
||||
|
||||
struct ActivityDetail
|
||||
{
|
||||
bool isFree;
|
||||
bool isLowConfidence;
|
||||
int bits;
|
||||
QString firstCall;
|
||||
QString secondCall;
|
||||
int freq;
|
||||
QString text;
|
||||
QDateTime utcTimestamp;
|
||||
int snr;
|
||||
};
|
||||
|
||||
struct RXDetail
|
||||
{
|
||||
bool isFree;
|
||||
bool isLowConfidence;
|
||||
int bits;
|
||||
int freq;
|
||||
QString text;
|
||||
QDateTime utcTimestamp;
|
||||
};
|
||||
|
||||
bool m_rxDirty;
|
||||
int m_txFrameCount;
|
||||
QDateTime m_lastTxTime;
|
||||
QQueue<QString> m_txFrameQueue;
|
||||
QQueue<RXDetail> m_rxFrameQueue;
|
||||
QQueue<CommandDetail> m_rxCommandQueue;
|
||||
QCache<QString, QDateTime> m_txAllcallCommandCache; // callsign -> last tx
|
||||
QCache<int, QDateTime> m_rxRecentCache; // freq -> last rx
|
||||
QCache<int, QDateTime> m_rxDirectedCache; // freq -> last directed rx
|
||||
QCache<QString, int> m_rxCallCache; // call -> last freq seen
|
||||
QMap<int, int> m_rxFrameBlockNumbers; // freq -> block
|
||||
QMap<int, QList<ActivityDetail>> m_bandActivity; // freq -> [(text, last timestamp), ...]
|
||||
QMap<QString, CallDetail> m_callActivity; // call -> (last freq, last timestamp)
|
||||
QSet<QString> m_callSeenBeacon; // call
|
||||
QMap<QString,FoxQSO> m_foxQSO;
|
||||
QMap<QString,QString> m_loggedByFox;
|
||||
|
||||
@@ -591,6 +699,7 @@ private:
|
||||
QQueue<QString> m_foxRR73Queue;
|
||||
QQueue<qint64> m_foxRateQueue;
|
||||
|
||||
QDateTime m_nextBeacon;
|
||||
QDateTime m_dateTimeQSOOn;
|
||||
QDateTime m_dateTimeLastTX;
|
||||
|
||||
@@ -646,6 +755,7 @@ private:
|
||||
void rigFailure (QString const& reason);
|
||||
void pskSetLocal ();
|
||||
void pskPost(DecodedText const& decodedtext);
|
||||
void pskLogReport(QString mode, int offset, int snr, QString callsign, QString grid);
|
||||
void displayDialFrequency ();
|
||||
void transmitDisplay (bool);
|
||||
void processMessage(DecodedText const&, Qt::KeyboardModifiers = 0);
|
||||
@@ -653,6 +763,14 @@ private:
|
||||
void locationChange(QString const& location);
|
||||
void replayDecodes ();
|
||||
void postDecode (bool is_new, QString const& message);
|
||||
void displayTransmit();
|
||||
void updateButtonDisplay();
|
||||
bool isMyCallIncluded(QString const &text);
|
||||
bool isAllCallIncluded(QString const &text);
|
||||
QString callsignSelected();
|
||||
bool isRecentOffset(int offset);
|
||||
bool isDirectedOffset(int offset);
|
||||
void displayActivity(bool force=false);
|
||||
void postWSPRDecode (bool is_new, QStringList message_parts);
|
||||
void enable_DXCC_entity (bool on);
|
||||
void switch_mode (Mode);
|
||||
@@ -700,6 +818,23 @@ private:
|
||||
void writeFoxQSO(QString msg);
|
||||
};
|
||||
|
||||
class EscapeKeyPressEater : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event){
|
||||
if (event->type() == QEvent::KeyPress) {
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
||||
if(keyEvent->key() == Qt::Key_Escape){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// standard event processing
|
||||
return QObject::eventFilter(obj, event);
|
||||
}
|
||||
};
|
||||
|
||||
extern int killbyname(const char* progName);
|
||||
extern void getDev(int* numDevices,char hostAPI_DeviceName[][50],
|
||||
int minChan[], int maxChan[],
|
||||
|
||||
+3652
-2166
File diff suppressed because it is too large
Load Diff
Executable
+3
@@ -0,0 +1,3 @@
|
||||
echo make
|
||||
echo cp wsjtx ft8call
|
||||
echo linuxdeployqt ./ft8call -appimage -bundle-non-qt-libs -no-strip -no-translations
|
||||
+8
-4
@@ -57,12 +57,14 @@ void MeterWidget::paintEvent (QPaintEvent * event)
|
||||
auto const& target = contentsRect ();
|
||||
QRect r {QPoint {target.left (), static_cast<int> (target.top () + target.height () - m_signal / (double)MAXDB * target.height ())}
|
||||
, QPoint {target.right (), target.bottom ()}};
|
||||
p.setBrush (QColor(85,170,85));
|
||||
//p.setBrush (QColor(85,170,85));
|
||||
p.setBrush (Qt::green);
|
||||
if (m_sigPeak > 85) {
|
||||
p.setBrush(Qt::red);
|
||||
}
|
||||
else if (m_noisePeak < 15) {
|
||||
p.setBrush(QColor(232,81,0));
|
||||
//p.setBrush(QColor(232,81,0));
|
||||
p.setBrush(Qt::yellow);
|
||||
}
|
||||
p.drawRect (r);
|
||||
|
||||
@@ -70,9 +72,11 @@ void MeterWidget::paintEvent (QPaintEvent * event)
|
||||
{
|
||||
// Draw peak hold indicator
|
||||
auto peak = static_cast<int> (target.top () + target.height () - m_noisePeak / (double)MAXDB * target.height ());
|
||||
p.setBrush (Qt::black);
|
||||
//p.setBrush (Qt::black);
|
||||
p.setBrush (Qt::white);
|
||||
p.translate (target.left (), peak);
|
||||
p.drawPolygon (QPolygon {{{0, -4}, {0, 4}, {target.width (), 0}}});
|
||||
//p.drawPolygon (QPolygon {{{0, -4}, {0, 4}, {target.width (), 0}}});
|
||||
p.drawPolygon (QPolygon { { {target.width (), -4}, {target.width (), 4}, {0, 0} } });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ CPlotter::CPlotter(QWidget *parent) : //CPlotter Constructor
|
||||
m_line {0},
|
||||
m_fSample {12000},
|
||||
m_nsps {6912},
|
||||
m_Percent2DScreen {30}, //percent of screen used for 2D display
|
||||
m_Percent2DScreen {0}, //percent of screen used for 2D display
|
||||
m_Percent2DScreen0 {0},
|
||||
m_rxFreq {1020},
|
||||
m_txFreq {0},
|
||||
|
||||
+611
@@ -0,0 +1,611 @@
|
||||
#ifndef ORDEREDMAP_H
|
||||
#define ORDEREDMAP_H
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QHash>
|
||||
#include <QLinkedList>
|
||||
#include <QList>
|
||||
#include <QPair>
|
||||
|
||||
template <typename Key> inline bool oMHashEqualToKey(const Key &key1, const Key &key2)
|
||||
{
|
||||
// Key type must provide '==' operator
|
||||
return key1 == key2;
|
||||
}
|
||||
|
||||
template <typename Ptr> inline bool oMHashEqualToKey(Ptr *key1, Ptr *key2)
|
||||
{
|
||||
Q_ASSERT(sizeof(quintptr) == sizeof(Ptr *));
|
||||
return quintptr(key1) == quintptr(key2);
|
||||
}
|
||||
|
||||
template <typename Ptr> inline bool oMHashEqualToKey(const Ptr *key1, const Ptr *key2)
|
||||
{
|
||||
Q_ASSERT(sizeof(quintptr) == sizeof(const Ptr *));
|
||||
return quintptr(key1) == quintptr(key2);
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
class OrderedMap
|
||||
{
|
||||
class OMHash;
|
||||
|
||||
typedef typename QLinkedList<Key>::iterator QllIterator;
|
||||
typedef typename QLinkedList<Key>::const_iterator QllConstIterator;
|
||||
typedef QPair<Value, QllIterator> OMHashValue;
|
||||
|
||||
typedef typename OMHash::iterator OMHashIterator;
|
||||
typedef typename OMHash::const_iterator OMHashConstIterator;
|
||||
|
||||
public:
|
||||
|
||||
class iterator;
|
||||
class const_iterator;
|
||||
|
||||
typedef typename OrderedMap<Key, Value>::iterator Iterator;
|
||||
typedef typename OrderedMap<Key, Value>::const_iterator ConstIterator;
|
||||
|
||||
explicit OrderedMap();
|
||||
|
||||
OrderedMap(const OrderedMap<Key, Value>& other);
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
|
||||
OrderedMap(OrderedMap<Key, Value>&& other);
|
||||
#endif
|
||||
|
||||
void clear();
|
||||
|
||||
bool contains(const Key &key) const;
|
||||
|
||||
int count() const;
|
||||
|
||||
bool empty() const;
|
||||
|
||||
iterator insert(const Key &key, const Value &value);
|
||||
|
||||
bool isEmpty() const;
|
||||
|
||||
QList<Key> keys() const;
|
||||
|
||||
int remove(const Key &key);
|
||||
|
||||
int size() const;
|
||||
|
||||
Value take(const Key &key);
|
||||
|
||||
Value value(const Key &key) const;
|
||||
|
||||
Value value(const Key &key, const Value &defaultValue) const;
|
||||
|
||||
QList<Value> values() const;
|
||||
|
||||
OrderedMap<Key, Value> & operator=(const OrderedMap<Key, Value>& other);
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
|
||||
OrderedMap<Key, Value> & operator=(OrderedMap<Key, Value>&& other);
|
||||
#endif
|
||||
|
||||
bool operator==(const OrderedMap<Key, Value> &other) const;
|
||||
|
||||
bool operator!=(const OrderedMap<Key, Value> &other) const;
|
||||
|
||||
Value& operator[](const Key &key);
|
||||
|
||||
const Value operator[](const Key &key) const;
|
||||
|
||||
iterator begin();
|
||||
|
||||
const_iterator begin() const;
|
||||
|
||||
iterator end();
|
||||
|
||||
const_iterator end() const;
|
||||
|
||||
iterator erase(iterator pos);
|
||||
|
||||
iterator find(const Key& key);
|
||||
|
||||
const_iterator find(const Key& key) const;
|
||||
|
||||
class const_iterator;
|
||||
|
||||
class iterator
|
||||
{
|
||||
QllIterator qllIter;
|
||||
OMHash *data;
|
||||
friend class const_iterator;
|
||||
friend class OrderedMap;
|
||||
|
||||
public:
|
||||
iterator() : data(NULL) {}
|
||||
|
||||
iterator(const QllIterator &qllIter, OMHash *data) :
|
||||
qllIter(qllIter), data(data) {}
|
||||
|
||||
const Key & key() const
|
||||
{
|
||||
return *qllIter;
|
||||
}
|
||||
|
||||
Value & value() const
|
||||
{
|
||||
OMHashIterator hit = data->find(*qllIter);
|
||||
OMHashValue &pair = hit.value();
|
||||
return pair.first;
|
||||
}
|
||||
|
||||
Value & operator*() const
|
||||
{
|
||||
return value();
|
||||
}
|
||||
|
||||
iterator operator+(int i) const
|
||||
{
|
||||
QllIterator q = qllIter;
|
||||
q += i;
|
||||
|
||||
return iterator(q, data);
|
||||
}
|
||||
|
||||
iterator operator-(int i) const
|
||||
{
|
||||
return operator +(- i);
|
||||
}
|
||||
|
||||
iterator& operator+=(int i)
|
||||
{
|
||||
qllIter += i;
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator& operator-=(int i)
|
||||
{
|
||||
qllIter -= i;
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator& operator++()
|
||||
{
|
||||
++qllIter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator++(int)
|
||||
{
|
||||
iterator it = *this;
|
||||
qllIter++;
|
||||
return it;
|
||||
}
|
||||
|
||||
iterator operator--()
|
||||
{
|
||||
--qllIter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator--(int)
|
||||
{
|
||||
iterator it = *this;
|
||||
qllIter--;
|
||||
return it;
|
||||
}
|
||||
|
||||
bool operator ==(const iterator &other) const
|
||||
{
|
||||
return (qllIter == other.qllIter);
|
||||
}
|
||||
|
||||
bool operator !=(const iterator &other) const
|
||||
{
|
||||
return (qllIter != other.qllIter);
|
||||
}
|
||||
};
|
||||
|
||||
class const_iterator
|
||||
{
|
||||
|
||||
QllConstIterator qllConstIter;
|
||||
const OMHash *data;
|
||||
|
||||
public:
|
||||
const_iterator() : data(NULL) {}
|
||||
|
||||
const_iterator(const iterator &i) :
|
||||
qllConstIter(i.qllIter), data(i.data) {}
|
||||
|
||||
const_iterator(const QllConstIterator &qllConstIter, const OMHash* data) :
|
||||
qllConstIter(qllConstIter), data(data) {}
|
||||
|
||||
const Key & key() const
|
||||
{
|
||||
return *qllConstIter;
|
||||
}
|
||||
|
||||
const Value & value() const
|
||||
{
|
||||
OMHashConstIterator hit = data->find(*qllConstIter);
|
||||
const OMHashValue &pair = hit.value();
|
||||
return pair.first;
|
||||
}
|
||||
|
||||
const Value & operator*() const
|
||||
{
|
||||
return value();
|
||||
}
|
||||
|
||||
const_iterator operator+(int i) const
|
||||
{
|
||||
QllConstIterator q = qllConstIter;
|
||||
q += i;
|
||||
|
||||
return const_iterator(q, data);
|
||||
}
|
||||
|
||||
const_iterator operator-(int i) const
|
||||
{
|
||||
return operator +(- i);
|
||||
}
|
||||
|
||||
const_iterator& operator+=(int i)
|
||||
{
|
||||
qllConstIter += i;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator& operator-=(int i)
|
||||
{
|
||||
qllConstIter -= i;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator& operator++()
|
||||
{
|
||||
++qllConstIter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator operator++(int)
|
||||
{
|
||||
const_iterator it = *this;
|
||||
qllConstIter++;
|
||||
return it;
|
||||
}
|
||||
|
||||
const_iterator operator--()
|
||||
{
|
||||
--qllConstIter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator operator--(int)
|
||||
{
|
||||
const_iterator it = *this;
|
||||
qllConstIter--;
|
||||
return it;
|
||||
}
|
||||
|
||||
bool operator ==(const const_iterator &other) const
|
||||
{
|
||||
return (qllConstIter == other.qllConstIter);
|
||||
}
|
||||
|
||||
bool operator !=(const const_iterator &other) const
|
||||
{
|
||||
return (qllConstIter != other.qllConstIter);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
class OMHash : public QHash<Key, OMHashValue >
|
||||
{
|
||||
public:
|
||||
bool operator == (const OMHash &other) const
|
||||
{
|
||||
if (size() != other.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (QHash<Key, OMHashValue >::operator ==(other)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
typename QHash<Key, OMHashValue >::const_iterator it1 = this->constBegin();
|
||||
typename QHash<Key, OMHashValue >::const_iterator it2 = other.constBegin();
|
||||
|
||||
while(it1 != this->end()) {
|
||||
OMHashValue v1 = it1.value();
|
||||
OMHashValue v2 = it2.value();
|
||||
|
||||
if ((v1.first != v2.first) || !oMHashEqualToKey<Key>(it1.key(), it2.key())) {
|
||||
return false;
|
||||
}
|
||||
++it1;
|
||||
++it2;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
void copy(const OrderedMap<Key, Value> &other);
|
||||
|
||||
OMHash data;
|
||||
QLinkedList<Key> insertOrder;
|
||||
};
|
||||
|
||||
template <typename Key, typename Value>
|
||||
OrderedMap<Key, Value>::OrderedMap() {}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
OrderedMap<Key, Value>::OrderedMap(const OrderedMap<Key, Value>& other)
|
||||
{
|
||||
copy(other);
|
||||
}
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
|
||||
template <typename Key, typename Value>
|
||||
OrderedMap<Key, Value>::OrderedMap(OrderedMap<Key, Value>&& other)
|
||||
{
|
||||
data = std::move(other.data);
|
||||
insertOrder = std::move(other.insertOrder);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename Key, typename Value>
|
||||
void OrderedMap<Key, Value>::clear()
|
||||
{
|
||||
data.clear();
|
||||
insertOrder.clear();
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
bool OrderedMap<Key, Value>::contains(const Key &key) const
|
||||
{
|
||||
return data.contains(key);
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
int OrderedMap<Key, Value>::count() const
|
||||
{
|
||||
return data.count();
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
bool OrderedMap<Key, Value>::empty() const
|
||||
{
|
||||
return data.empty();
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
typename OrderedMap<Key, Value>::iterator OrderedMap<Key, Value>::insert(const Key &key, const Value &value)
|
||||
{
|
||||
OMHashIterator it = data.find(key);
|
||||
|
||||
if (it == data.end()) {
|
||||
// New key
|
||||
QllIterator ioIter = insertOrder.insert(insertOrder.end(), key);
|
||||
OMHashValue pair(value, ioIter);
|
||||
data.insert(key, pair);
|
||||
return iterator(ioIter, &data);
|
||||
}
|
||||
|
||||
OMHashValue pair = it.value();
|
||||
// remove old reference
|
||||
insertOrder.erase(pair.second);
|
||||
// Add new reference
|
||||
QllIterator ioIter = insertOrder.insert(insertOrder.end(), key);
|
||||
pair.first = value;
|
||||
pair.second = ioIter;
|
||||
return iterator(ioIter, &data);
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
bool OrderedMap<Key, Value>::isEmpty() const
|
||||
{
|
||||
return data.isEmpty();
|
||||
}
|
||||
|
||||
template<typename Key, typename Value>
|
||||
QList<Key> OrderedMap<Key, Value>::keys() const
|
||||
{
|
||||
return QList<Key>::fromStdList(insertOrder.toStdList());
|
||||
}
|
||||
|
||||
template<typename Key, typename Value>
|
||||
int OrderedMap<Key, Value>::remove(const Key &key)
|
||||
{
|
||||
OMHashIterator it = data.find(key);
|
||||
if (it == data.end()) {
|
||||
return 0;
|
||||
}
|
||||
OMHashValue pair = it.value();
|
||||
insertOrder.erase(pair.second);
|
||||
data.erase(it);
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<typename Key, typename Value>
|
||||
int OrderedMap<Key, Value>::size() const
|
||||
{
|
||||
return data.size();
|
||||
}
|
||||
|
||||
template<typename Key, typename Value>
|
||||
void OrderedMap<Key, Value>::copy(const OrderedMap<Key, Value> &other)
|
||||
{
|
||||
/* Since I'm storing iterators of QLinkedList, I simply cannot make
|
||||
* a trivial copy of the linked list. This is a limitation due to implicit
|
||||
* sharing used in Qt containers, due to which iterator active on one
|
||||
* QLL can change the data of another QLL even after creating a copy.
|
||||
*
|
||||
* Because of this, the old iterators have to be invalidated and new ones
|
||||
* have to be generated.
|
||||
*/
|
||||
insertOrder.clear();
|
||||
// Copy hash
|
||||
data = other.data;
|
||||
|
||||
QllConstIterator cit = other.insertOrder.begin();
|
||||
for (; cit != other.insertOrder.end(); ++cit) {
|
||||
Key key = *cit;
|
||||
QllIterator ioIter = insertOrder.insert(insertOrder.end(), key);
|
||||
OMHashIterator it = data.find(key);
|
||||
(*it).second = ioIter;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Key, typename Value>
|
||||
Value OrderedMap<Key, Value>::take(const Key &key)
|
||||
{
|
||||
OMHashIterator it = data.find(key);
|
||||
if (it == data.end()) {
|
||||
return Value();
|
||||
}
|
||||
OMHashValue pair = it.value();
|
||||
insertOrder.erase(pair.second);
|
||||
data.erase(it);
|
||||
return pair.first;
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
Value OrderedMap<Key, Value>::value(const Key &key) const
|
||||
{
|
||||
return data.value(key).first;
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
Value OrderedMap<Key, Value>::value(const Key &key, const Value &defaultValue) const
|
||||
{
|
||||
OMHashConstIterator it = data.constFind(key);
|
||||
if (it == data.end()) {
|
||||
return defaultValue;
|
||||
}
|
||||
OMHashValue pair = it.value();
|
||||
return pair.first;
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
QList<Value> OrderedMap<Key, Value>::values() const
|
||||
{
|
||||
QList<Value> values;
|
||||
foreach (const Key &key, insertOrder.toStdList()) {
|
||||
OMHashValue v = data.value(key);
|
||||
values.append(v.first);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
OrderedMap<Key, Value> & OrderedMap<Key, Value>::operator=(const OrderedMap<Key, Value>& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
copy(other);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
|
||||
template <typename Key, typename Value>
|
||||
OrderedMap<Key, Value> & OrderedMap<Key, Value>::operator=(OrderedMap<Key, Value>&& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
data = other.data;
|
||||
insertOrder = other.insertOrder;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename Key, typename Value>
|
||||
bool OrderedMap<Key, Value>::operator==(const OrderedMap<Key, Value> &other) const
|
||||
{
|
||||
// 2 Ordered maps are equal if they have the same contents in the same order
|
||||
return ((data == other.data) && (insertOrder == other.insertOrder));
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
bool OrderedMap<Key, Value>::operator!=(const OrderedMap<Key, Value> &other) const
|
||||
{
|
||||
return ((data != other.data) || (insertOrder != other.insertOrder));
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
Value& OrderedMap<Key, Value>::operator[](const Key &key)
|
||||
{
|
||||
OMHashIterator it = data.find(key);
|
||||
if (it == data.end()) {
|
||||
insert(key, Value());
|
||||
it = data.find(key);
|
||||
}
|
||||
OMHashValue &pair = it.value();
|
||||
return pair.first;
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
const Value OrderedMap<Key, Value>::operator[](const Key &key) const
|
||||
{
|
||||
return value(key);
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
typename OrderedMap<Key, Value>::iterator OrderedMap<Key, Value>::begin()
|
||||
{
|
||||
return iterator(insertOrder.begin(), &data);
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
typename OrderedMap<Key, Value>::const_iterator OrderedMap<Key, Value>::begin() const
|
||||
{
|
||||
return const_iterator(insertOrder.begin(), &data);
|
||||
}
|
||||
|
||||
|
||||
template <typename Key, typename Value>
|
||||
typename OrderedMap<Key, Value>::iterator OrderedMap<Key, Value>::end()
|
||||
{
|
||||
return iterator(insertOrder.end(), &data);
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
typename OrderedMap<Key, Value>::const_iterator OrderedMap<Key, Value>::end() const
|
||||
{
|
||||
return const_iterator(insertOrder.end(), &data);
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
typename OrderedMap<Key, Value>::iterator OrderedMap<Key, Value>::erase(iterator pos)
|
||||
{
|
||||
OMHashIterator hit = data.find(*(pos.qllIter));
|
||||
if (hit == data.end()) {
|
||||
return pos;
|
||||
}
|
||||
data.erase(hit);
|
||||
QllIterator ioIter = insertOrder.erase(pos.qllIter);
|
||||
|
||||
return iterator(ioIter, &data);
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
typename OrderedMap<Key, Value>::iterator OrderedMap<Key, Value>::find(const Key& key)
|
||||
{
|
||||
OMHashIterator hit = data.find(key);
|
||||
if (hit == data.end()) {
|
||||
return end();
|
||||
}
|
||||
|
||||
return iterator(hit.value().second, &data);
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
typename OrderedMap<Key, Value>::const_iterator OrderedMap<Key, Value>::find(const Key& key) const
|
||||
{
|
||||
OMHashConstIterator hit = data.find(key);
|
||||
if (hit == data.end()) {
|
||||
return end();
|
||||
}
|
||||
|
||||
return const_iterator(hit.value().second, &data);
|
||||
}
|
||||
|
||||
#endif // ORDEREDMAP_H
|
||||
@@ -0,0 +1,253 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 Corentin Chary <corentin.chary@gmail.cm>
|
||||
**
|
||||
** This file could be part of the QtCore module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QPRIORITY_QUEUE_H
|
||||
#define QPRIORITY_QUEUE_H
|
||||
|
||||
#include <QtCore/qalgorithms.h>
|
||||
|
||||
QT_BEGIN_HEADER
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QT_MODULE(Core)
|
||||
|
||||
template <class T> class QList;
|
||||
|
||||
#ifndef QT_NO_STL
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
#else
|
||||
/* Fallback class used when stl is not available */
|
||||
template <class T, typename LessThan = qLess < T > >
|
||||
class QPriorityQueuePrivate {
|
||||
public:
|
||||
inline QPriorityQueuePrivate(LessThan l) : lessThan(l), d() {}
|
||||
inline ~QPriorityQueuePrivate() {}
|
||||
|
||||
inline void clear() { return d.clear(); }
|
||||
inline int size() const { return d.size(); }
|
||||
inline bool empty() const { return d.empty(); }
|
||||
|
||||
inline T &top() { return d.front(); }
|
||||
|
||||
void pop();
|
||||
void push(const T &value);
|
||||
private:
|
||||
inline int parent(int i) {
|
||||
return (i - 1) / 2;
|
||||
}
|
||||
inline int leftChild(int i) {
|
||||
return 2 * i + 1;
|
||||
}
|
||||
inline int rightChild(int i) {
|
||||
return 2 * i + 2;
|
||||
}
|
||||
|
||||
LessThan lessThan;
|
||||
QList < T > d;
|
||||
};
|
||||
#endif
|
||||
|
||||
template <class T, typename LessThan = qLess < T > >
|
||||
class Q_CORE_EXPORT QPriorityQueue
|
||||
{
|
||||
public:
|
||||
inline QPriorityQueue(LessThan l = qLess < T >())
|
||||
: lessThan(l), d(lessThan) { }
|
||||
inline QPriorityQueue(const QPriorityQueue<T> &q)
|
||||
: lessThan(q.lessThan), d(q.d) { }
|
||||
inline ~QPriorityQueue() { }
|
||||
|
||||
QPriorityQueue<T> &operator=(const QPriorityQueue<T> &q) {
|
||||
d = q.d; return *this;
|
||||
}
|
||||
|
||||
inline int size() const { return d.size(); }
|
||||
inline bool isEmpty() const { return empty(); }
|
||||
|
||||
// like qlist
|
||||
void clear();
|
||||
void append(const T &t) { return enqueue(t); }
|
||||
void append(const QList<T> &t);
|
||||
T takeFirst() { return dequeue(); }
|
||||
inline int length() const { return size(); } // Same as count()
|
||||
inline T& first() { return head(); }
|
||||
inline const T& first() const { return head(); }
|
||||
inline void removeFirst() { pop(); }
|
||||
inline bool startsWith(const T &t) const
|
||||
{ return !isEmpty() && first() == t; }
|
||||
|
||||
// like qqueue
|
||||
inline void enqueue(const T &t) { push(t); }
|
||||
inline T dequeue() { T t = d.top(); d.pop(); return t; }
|
||||
inline T &head() { top(); }
|
||||
inline const T &head() const { top(); }
|
||||
|
||||
// stl compatibility
|
||||
typedef int size_type;
|
||||
typedef T value_type;
|
||||
|
||||
inline bool empty() const { return d.empty(); }
|
||||
inline const value_type& top() { Q_ASSERT(!isEmpty()); return d.top(); }
|
||||
inline void push(const value_type& x) { return d.push(x); }
|
||||
inline void pop() { Q_ASSERT(!isEmpty()); d.pop(); }
|
||||
|
||||
// comfort
|
||||
inline QPriorityQueue<T> &operator+=(const T &t) {
|
||||
enqueue(t); return *this;
|
||||
}
|
||||
inline QPriorityQueue<T> &operator<< (const T &t) {
|
||||
enqueue(t); return *this;
|
||||
}
|
||||
inline QPriorityQueue<T> &operator>> (T &t) {
|
||||
t = d.top(); d.pop(); return *this;
|
||||
}
|
||||
|
||||
#ifndef QT_NO_STL
|
||||
static inline QPriorityQueue<T>fromStdPriorityQueue(
|
||||
const std::priority_queue<T> &q) {
|
||||
QPriorityQueue<T> tmp; tmp.d = q; return tmp;
|
||||
}
|
||||
inline std::priority_queue<T> toStdPriorityQueue() const {
|
||||
return d;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
LessThan lessThan;
|
||||
#ifndef QT_NO_STL
|
||||
std::priority_queue <T, std::vector < T >, LessThan> d;
|
||||
#else
|
||||
QPriorityQueuePrivate <T> d;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef QT_NO_STL
|
||||
|
||||
template <typename T, typename LessThan>
|
||||
Q_INLINE_TEMPLATE void QPriorityQueue<T, LessThan>::clear()
|
||||
{
|
||||
d = std::priority_queue<T>(lessThan);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <typename T, typename LessThan>
|
||||
Q_INLINE_TEMPLATE void QPriorityQueue<T, LessThan>::clear()
|
||||
{
|
||||
d.clear();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template <typename T, typename LessThan>
|
||||
Q_OUTOFLINE_TEMPLATE void QPriorityQueue<T, LessThan>::append(const QList<T> &t)
|
||||
{
|
||||
foreach (T & e, t)
|
||||
push(e);
|
||||
}
|
||||
|
||||
// Re-implement std::priority_queue if STL not available, probably
|
||||
// less efficient.
|
||||
#ifdef QT_NO_STL
|
||||
/*!
|
||||
* Pop an element from the queue and reorder it using an
|
||||
* inlined binary heap.
|
||||
*
|
||||
* \internal
|
||||
*/
|
||||
template <typename T, typename LessThan>
|
||||
Q_OUTOFLINE_TEMPLATE void QPriorityQueuePrivate<T, LessThan>::pop()
|
||||
{
|
||||
int i = 0;
|
||||
ssize_t size = d.size();;
|
||||
|
||||
if(!size)
|
||||
return;
|
||||
if(size == 1)
|
||||
return d.clear();
|
||||
|
||||
d[0] = d.takeLast();
|
||||
|
||||
while(i < size - 1) {
|
||||
int left = leftChild(i);
|
||||
int right = rightChild(i);
|
||||
bool validLeft = left < size;
|
||||
bool validRight = right < size;
|
||||
|
||||
if(validLeft && lessThan(d.at(i), d.at(left)))
|
||||
if(validRight && !lessThan(d.at(right), d.at(left))) {
|
||||
d.swap(i, right);
|
||||
i = right;
|
||||
} else {
|
||||
d.swap(i, left);
|
||||
i = left;
|
||||
}
|
||||
else if(validRight && lessThan(d.at(i), d.at(right))) {
|
||||
d.swap(i, right);
|
||||
i = right;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Push an element with a given priority to the right place.
|
||||
*
|
||||
* \internal
|
||||
*/
|
||||
template <typename T, typename LessThan>
|
||||
Q_OUTOFLINE_TEMPLATE void QPriorityQueuePrivate<T, LessThan>::push(const T &value)
|
||||
{
|
||||
int i = d.size();
|
||||
d.append(value);
|
||||
while(i != 0 && !lessThan(d.at(i), d.at(parent(i)))) {
|
||||
d.swap(i, parent(i));
|
||||
i = parent(i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
QT_END_HEADER
|
||||
|
||||
#endif // QPRIORITY_QUEUE_H
|
||||
+6
-56
@@ -5,62 +5,9 @@
|
||||
#include <QCoreApplication>
|
||||
#include <QRegularExpression>
|
||||
|
||||
#include "svnversion.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
QString revision_extract_number (QString const& s)
|
||||
{
|
||||
QString revision;
|
||||
|
||||
// try and match a number
|
||||
QRegularExpression re {R"(^[$:]\w+: (\d+[^$]*)\$$)"};
|
||||
auto match = re.match (s);
|
||||
if (match.hasMatch ())
|
||||
{
|
||||
revision = 'r' + match.captured (1);
|
||||
}
|
||||
return revision;
|
||||
}
|
||||
}
|
||||
|
||||
QString revision (QString const& svn_rev_string)
|
||||
{
|
||||
QString result;
|
||||
auto revision_from_svn = revision_extract_number (svn_rev_string);
|
||||
|
||||
#if defined (CMAKE_BUILD)
|
||||
QString svn_info {":Rev: " WSJTX_STRINGIZE (SVNVERSION) " $"};
|
||||
|
||||
auto revision_from_svn_info = revision_extract_number (svn_info);
|
||||
if (!revision_from_svn_info.isEmpty ())
|
||||
{
|
||||
// we managed to get the revision number from svn info etc.
|
||||
result = revision_from_svn_info;
|
||||
}
|
||||
else if (!revision_from_svn.isEmpty ())
|
||||
{
|
||||
// fall back to revision passed in if any
|
||||
result = revision_from_svn;
|
||||
}
|
||||
else
|
||||
{
|
||||
// match anything
|
||||
QRegularExpression re {R"(^[$:]\w+: ([^$]*)\$$)"};
|
||||
auto match = re.match (svn_info);
|
||||
if (match.hasMatch ())
|
||||
{
|
||||
result = match.captured (1);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (!revision_from_svn.isEmpty ())
|
||||
{
|
||||
// not CMake build so all we have is revision passed
|
||||
result = revision_from_svn;
|
||||
}
|
||||
#endif
|
||||
return result.trimmed ();
|
||||
return "";
|
||||
}
|
||||
|
||||
QString version (bool include_patch)
|
||||
@@ -70,19 +17,22 @@ QString version (bool include_patch)
|
||||
if (include_patch)
|
||||
{
|
||||
v += "." WSJTX_STRINGIZE (WSJTX_VERSION_PATCH)
|
||||
#if 0
|
||||
# if defined (WSJTX_RC)
|
||||
+ "-rc" WSJTX_STRINGIZE (WSJTX_RC)
|
||||
# endif
|
||||
#endif
|
||||
;
|
||||
}
|
||||
#else
|
||||
QString v {"Not for Release"};
|
||||
#endif
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
QString program_title (QString const& revision)
|
||||
{
|
||||
QString id {QCoreApplication::applicationName () + " v" + QCoreApplication::applicationVersion ()};
|
||||
return id + " " + revision + " by K1JT";
|
||||
QString id {"FT8Call de KN4CRD (v%1) a derivative of WSJT-X by K1JT"};
|
||||
return id.arg(QCoreApplication::applicationVersion ());
|
||||
}
|
||||
|
||||
+8
-1
@@ -44,6 +44,7 @@ protected:
|
||||
QWidget::paintEvent (event);
|
||||
|
||||
QPainter p {this};
|
||||
p.setPen(Qt::white);
|
||||
auto const& target = contentsRect ();
|
||||
QFontMetrics font_metrics {p.font (), this};
|
||||
auto font_offset = font_metrics.ascent () / 2;
|
||||
@@ -82,12 +83,18 @@ SignalMeter::SignalMeter (QWidget * parent)
|
||||
|
||||
m_meter = new MeterWidget;
|
||||
m_meter->setSizePolicy (QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
inner_layout->addWidget (m_meter);
|
||||
//inner_layout->addWidget (m_meter);
|
||||
|
||||
m_scale = new Scale;
|
||||
inner_layout->addWidget (m_scale);
|
||||
|
||||
// add this second...
|
||||
inner_layout->addWidget (m_meter);
|
||||
|
||||
m_reading = new QLabel(this);
|
||||
auto p = m_reading->palette();
|
||||
p.setColor(m_reading->foregroundRole(), Qt::white);
|
||||
m_reading->setPalette(p);
|
||||
|
||||
outer_layout->addLayout (inner_layout);
|
||||
outer_layout->addWidget (m_reading);
|
||||
|
||||
+765
@@ -0,0 +1,765 @@
|
||||
/**
|
||||
* This file is part of FT8Call.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* (C) 2018 Jordan Sherer <kn4crd@gmail.com> - All Rights Reserved
|
||||
*
|
||||
**/
|
||||
|
||||
#include <QDebug>
|
||||
#include <QMap>
|
||||
#include <QSet>
|
||||
|
||||
#define CRCPP_INCLUDE_ESOTERIC_CRC_DEFINITIONS
|
||||
#include "crc.h"
|
||||
|
||||
#include "varicode.h"
|
||||
|
||||
const int nalphabet = 41;
|
||||
QString alphabet = {"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-./?"};
|
||||
QString grid_pattern = {R"((?<grid>[A-R]{2}[0-9]{2})+)"};
|
||||
QString callsign_pattern1 = {R"((?<callsign>[A-Z0-9/]{2,}))"};
|
||||
QString callsign_pattern2 = {R"((?<callsign>(\d|[A-Z])+\/?((\d|[A-Z]){3,})(\/(\d|[A-Z])+)?(\/(\d|[A-Z])+)?))"};
|
||||
QString callsign_pattern3 = {R"(([0-9A-Z ])([0-9A-Z])([0-9])([A-Z ])([A-Z ])([A-Z ]))"};
|
||||
QString callsign_alphabet = {"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ "};
|
||||
|
||||
QMap<QString, int> directed_cmds = {
|
||||
// any changes here need to be made also in the directed regular xpression for parsing
|
||||
|
||||
// directed queries
|
||||
{"?", 0 }, // query snr
|
||||
{"@", 1 }, // query qth
|
||||
{"&", 2 }, // query station message
|
||||
{"$", 3 }, // query station(s) heard
|
||||
{"|", 4 }, // relay message
|
||||
|
||||
// directed responses
|
||||
{" PWR", 24 }, // power level
|
||||
{" SNR", 25 }, // seen a station at the provided snr
|
||||
{" NO", 26 }, // negative confirm
|
||||
{" YES", 27 }, // confirm
|
||||
{" 73", 28 }, // best regards, end of contact
|
||||
{" RR", 29 }, // confirm message
|
||||
{" AGN?", 30 }, // repeat message
|
||||
{" ", 31 }, // send freetext
|
||||
};
|
||||
|
||||
QSet<int> allowed_cmds = {0, 1, 2, 24, 25, 26, 27, 28, 29, 30, 31};
|
||||
|
||||
QRegularExpression directed_re("^"
|
||||
"(?<to>[A-Z0-9/]+)"
|
||||
"(?<cmd>\\s?(?:AGN[?]|RR|73|YES|NO|SNR|PWR|[?$@&| ]))"
|
||||
"(?<pwr>\\s?\\d+\\s?[KM]?W)?"
|
||||
"(?<num>\\s?[-+]?(?:3[01]|[0-2]?[0-9]))?"
|
||||
);
|
||||
|
||||
QMap<QChar, QString> huff = {
|
||||
// char code weight
|
||||
{' ' , "000" }, // 1300
|
||||
{'E' , "001" }, // 1270.2
|
||||
{'T' , "1100" }, // 905.6
|
||||
{'A' , "1010" }, // 816.7
|
||||
{'O' , "0111" }, // 750.7
|
||||
{'I' , "0101" }, // 696.6
|
||||
{'N' , "0100" }, // 674.9
|
||||
{'S' , "11111" }, // 632.7
|
||||
{'H' , "11110" }, // 609.4
|
||||
{'R' , "11101" }, // 598.7
|
||||
{'D' , "10111" }, // 425.3
|
||||
{'L' , "10110" }, // 402.5
|
||||
{'C' , "111001" }, // 278.2
|
||||
{'U' , "111000" }, // 275.8
|
||||
{'M' , "110111" }, // 240.6
|
||||
{'W' , "110110" }, // 236.0
|
||||
{'F' , "110100" }, // 222.8
|
||||
{'G' , "100111" }, // 201.5
|
||||
{'Q' , "100110" }, // 200
|
||||
{'Y' , "011010" }, // 197.4
|
||||
{'P' , "011001" }, // 192.9
|
||||
{'B' , "011000" }, // 149.2
|
||||
{'!' , "0110111" }, // 100
|
||||
{'.' , "1000000" }, // 100
|
||||
{'0' , "1000001" }, // 100
|
||||
{'1' , "1000010" }, // 100
|
||||
{'2' , "1000011" }, // 100
|
||||
{'3' , "1000100" }, // 100
|
||||
{'4' , "1000101" }, // 100
|
||||
{'5' , "1000110" }, // 100
|
||||
{'6' , "1000111" }, // 100
|
||||
{'7' , "1001000" }, // 100
|
||||
{'8' , "1001001" }, // 100
|
||||
{'9' , "1001010" }, // 100
|
||||
{'?' , "1001011" }, // 100
|
||||
{'^' , "1101010" }, // 100 <- shift
|
||||
{'V' , "0110110" }, // 97.8
|
||||
{'K' , "11010111" }, // 77.2
|
||||
{'J' , "1101011010" }, // 15.3
|
||||
{'X' , "1101011001" }, // 15.0
|
||||
{'Z' , "11010110110" }, // 7.4
|
||||
{':' , "11010110000" }, // 5
|
||||
{'+' , "110101100011" }, // 5
|
||||
{'-' , "110101101110" }, // 5
|
||||
{'/' , "110101101111" }, // 5
|
||||
{'\x04' , "110101100010" }, // 1 <- eot
|
||||
};
|
||||
|
||||
QChar huffeot = '\x04';
|
||||
|
||||
quint32 nbasecall = 37 * 36 * 10 * 27 * 27 * 27;
|
||||
|
||||
QMap<QString, quint32> basecalls = {
|
||||
{ "CQCQCQ", nbasecall + 1 },
|
||||
{ "ALLCALL", nbasecall + 3 },
|
||||
};
|
||||
|
||||
QMap<int, int> dbm2mw = {
|
||||
{0 , 1},
|
||||
{3 , 2},
|
||||
{7 , 5},
|
||||
{10 , 10},
|
||||
{13 , 20},
|
||||
{17 , 50},
|
||||
{20 , 100},
|
||||
{23 , 200},
|
||||
{27 , 500},
|
||||
{30 , 1000}, // 1W
|
||||
{33 , 2000}, // 2W
|
||||
{37 , 5000}, // 5W
|
||||
{40 , 10000}, // 10W
|
||||
{43 , 20000}, // 20W
|
||||
{47 , 50000}, // 50W
|
||||
{50 , 100000}, // 100W
|
||||
{53 , 200000}, // 200W
|
||||
{57 , 500000}, // 500W
|
||||
{60 , 1000000}, // 1000W
|
||||
};
|
||||
|
||||
int mwattsToDbm(int mwatts){
|
||||
int dbm = 0;
|
||||
auto values = dbm2mw.values();
|
||||
qSort(values);
|
||||
foreach(auto mw, values){
|
||||
if(mw < mwatts){ continue; }
|
||||
dbm = dbm2mw.key(mw);
|
||||
break;
|
||||
}
|
||||
|
||||
return dbm;
|
||||
}
|
||||
|
||||
int dbmTomwatts(int dbm){
|
||||
if(dbm2mw.contains(dbm)){
|
||||
return dbm2mw[dbm];
|
||||
}
|
||||
auto iter = dbm2mw.lowerBound(dbm);
|
||||
if(iter == dbm2mw.end()){
|
||||
return dbm2mw.last();
|
||||
}
|
||||
return iter.value();
|
||||
}
|
||||
|
||||
QString Varicode::formatSNR(int snr){
|
||||
if(snr < -60 || snr > 60){
|
||||
return QString();
|
||||
}
|
||||
|
||||
return QString("%1%2").arg(snr >= 0 ? "+" : "").arg(snr, snr < 0 ? 3 : 2, 10, QChar('0'));
|
||||
}
|
||||
|
||||
QString Varicode::formatPWR(int dbm){
|
||||
if(dbm < 0 || dbm > 60){
|
||||
return QString();
|
||||
}
|
||||
|
||||
int mwatts = dbmTomwatts(dbm);
|
||||
if(mwatts < 1000){
|
||||
return QString("%1MW").arg(mwatts);
|
||||
}
|
||||
|
||||
return QString("%1W").arg(mwatts/1000);
|
||||
}
|
||||
|
||||
QStringList Varicode::parseCallsigns(QString const &input){
|
||||
QStringList callsigns;
|
||||
QRegularExpression re(callsign_pattern2);
|
||||
QRegularExpressionMatchIterator iter = re.globalMatch(input);
|
||||
while(iter.hasNext()){
|
||||
QRegularExpressionMatch match = iter.next();
|
||||
if(!match.hasMatch()){
|
||||
continue;
|
||||
}
|
||||
QString callsign = match.captured("callsign");
|
||||
QRegularExpression m(grid_pattern);
|
||||
if(m.match(callsign).hasMatch()){
|
||||
continue;
|
||||
}
|
||||
callsigns.append(callsign);
|
||||
}
|
||||
return callsigns;
|
||||
}
|
||||
|
||||
QStringList Varicode::parseGrids(const QString &input){
|
||||
QStringList grids;
|
||||
QRegularExpression re(grid_pattern);
|
||||
QRegularExpressionMatchIterator iter = re.globalMatch(input);
|
||||
while(iter.hasNext()){
|
||||
QRegularExpressionMatch match = iter.next();
|
||||
if(!match.hasMatch()){
|
||||
continue;
|
||||
}
|
||||
auto grid = match.captured("grid");
|
||||
if(grid == "RR73"){
|
||||
continue;
|
||||
}
|
||||
grids.append(grid);
|
||||
}
|
||||
return grids;
|
||||
}
|
||||
|
||||
QList<QVector<bool>> Varicode::huffEncode(QString const& text){
|
||||
QList<QVector<bool>> out;
|
||||
|
||||
foreach(auto ch, text){
|
||||
if(!huff.contains(ch)){
|
||||
continue;
|
||||
}
|
||||
out.append(strToBits(huff[ch]));
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
QVector<bool> Varicode::huffFlatten(QList<QVector<bool>> &list){
|
||||
QVector<bool> out;
|
||||
foreach(auto vec, list){
|
||||
out += vec;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
QString Varicode::huffDecode(QVector<bool> const& bitvec, int pad){
|
||||
QString out;
|
||||
|
||||
QString bits = bitsToStr(bitvec).mid(0, bitvec.length()-pad);
|
||||
|
||||
// TODO: jsherer - this is naive...
|
||||
while(bits.length() > 0){
|
||||
bool found = false;
|
||||
foreach(auto key, huff.keys()){
|
||||
if(bits.startsWith(huff[key])){
|
||||
if(key == huffeot){
|
||||
out.append(" ");
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
out.append(key);
|
||||
bits = bits.mid(huff[key].length());
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if(!found){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
// convert char* array of 0 bytes and 1 bytes to bool vector
|
||||
QVector<bool> Varicode::bytesToBits(char *bitvec, int n){
|
||||
QVector<bool> bits;
|
||||
for(int i = 0; i < n; i++){
|
||||
bits.append(bitvec[i] == 0x01);
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
// convert string of 0s and 1s to bool vector
|
||||
QVector<bool> Varicode::strToBits(QString const& bitvec){
|
||||
QVector<bool> bits;
|
||||
foreach(auto ch, bitvec){
|
||||
bits.append(ch == '1');
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
QString Varicode::bitsToStr(QVector<bool> const& bitvec){
|
||||
QString bits;
|
||||
foreach(auto bit, bitvec){
|
||||
bits.append(bit ? "1" : "0");
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
QVector<bool> Varicode::intToBits(quint64 value, int expected){
|
||||
QVector<bool> bits;
|
||||
|
||||
while(value){
|
||||
bits.prepend((bool)(value & 1));
|
||||
value = value >> 1;
|
||||
}
|
||||
|
||||
if(expected){
|
||||
while(bits.count() < expected){
|
||||
bits.prepend((bool) 0);
|
||||
}
|
||||
}
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
quint64 Varicode::bitsToInt(QVector<bool> const value){
|
||||
quint64 v = 0;
|
||||
foreach(bool bit, value){
|
||||
v = (v << 1) + (int)(bit);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
quint64 Varicode::bitsToInt(QVector<bool>::ConstIterator start, int n){
|
||||
quint64 v = 0;
|
||||
for(int i = 0; i < n; i++){
|
||||
int bit = (int)(*start);
|
||||
v = (v << 1) + (int)(bit);
|
||||
start++;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
quint8 Varicode::unpack5bits(QString const& value){
|
||||
return alphabet.indexOf(value.at(0));
|
||||
}
|
||||
|
||||
QString Varicode::pack5bits(quint8 packed){
|
||||
return alphabet.at(packed % nalphabet);
|
||||
}
|
||||
|
||||
quint16 Varicode::unpack16bits(QString const& value){
|
||||
int a = alphabet.indexOf(value.at(0));
|
||||
int b = alphabet.indexOf(value.at(1));
|
||||
int c = alphabet.indexOf(value.at(2));
|
||||
return (nalphabet*nalphabet) * a + nalphabet*b + c;
|
||||
}
|
||||
|
||||
QString Varicode::pack16bits(quint16 packed){
|
||||
QString out;
|
||||
quint16 tmp = packed / (nalphabet*nalphabet);
|
||||
|
||||
out.append(alphabet.at(tmp));
|
||||
|
||||
tmp = (packed - (tmp * (nalphabet*nalphabet))) / nalphabet;
|
||||
out.append(alphabet.at(tmp));
|
||||
|
||||
tmp = packed % nalphabet;
|
||||
out.append(alphabet.at(tmp));
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
quint32 Varicode::unpack32bits(QString const& value){
|
||||
return (quint32)(unpack16bits(value.left(3))) << 16 | unpack16bits(value.right(3));
|
||||
}
|
||||
|
||||
QString Varicode::pack32bits(quint32 packed){
|
||||
quint16 a = (packed & 0xFFFF0000) >> 16;
|
||||
quint16 b = packed & 0xFFFF;
|
||||
return pack16bits(a) + pack16bits(b);
|
||||
}
|
||||
|
||||
quint64 Varicode::unpack64bits(QString const& value){
|
||||
return (quint64)(unpack32bits(value.left(6))) << 32 | unpack32bits(value.right(6));
|
||||
}
|
||||
|
||||
QString Varicode::pack64bits(quint64 packed){
|
||||
quint32 a = (packed & 0xFFFFFFFF00000000) >> 32;
|
||||
quint32 b = packed & 0xFFFFFFFF;
|
||||
return pack32bits(a) + pack32bits(b);
|
||||
}
|
||||
|
||||
quint32 Varicode::packCallsign(QString const& value){
|
||||
quint32 packed = 0;
|
||||
|
||||
QString callsign = value.toUpper().trimmed();
|
||||
|
||||
if(basecalls.contains(callsign)){
|
||||
return basecalls[callsign];
|
||||
}
|
||||
|
||||
// workaround for swaziland
|
||||
if(callsign.startsWith("3DA0")){
|
||||
callsign = "3D0" + callsign.mid(4);
|
||||
}
|
||||
|
||||
// workaround for guinea
|
||||
if(callsign.startsWith("3X") && 'A' <= callsign.at(2) && callsign.at(2) <= 'Z'){
|
||||
callsign = "Q" + callsign.mid(2);
|
||||
}
|
||||
|
||||
int slen = callsign.length();
|
||||
if(slen < 2){
|
||||
return packed;
|
||||
}
|
||||
|
||||
if(slen > 6){
|
||||
return packed;
|
||||
}
|
||||
|
||||
QStringList permutations = { callsign };
|
||||
if(slen == 2){
|
||||
permutations.append(" " + callsign + " ");
|
||||
}
|
||||
if(slen == 3){
|
||||
permutations.append(" " + callsign + " ");
|
||||
permutations.append(callsign + " ");
|
||||
}
|
||||
if(slen == 4){
|
||||
permutations.append(" " + callsign + " ");
|
||||
permutations.append(callsign + " ");
|
||||
}
|
||||
if(slen == 5){
|
||||
permutations.append(" " + callsign);
|
||||
permutations.append(callsign + " ");
|
||||
}
|
||||
|
||||
QString matched;
|
||||
QRegularExpression m(callsign_pattern3);
|
||||
foreach(auto permutation, permutations){
|
||||
auto match = m.match(permutation);
|
||||
if(match.hasMatch()){
|
||||
matched = match.captured(0);
|
||||
}
|
||||
}
|
||||
if(matched.isEmpty()){
|
||||
return packed;
|
||||
}
|
||||
if(matched.length() < 6){
|
||||
return packed;
|
||||
}
|
||||
|
||||
packed = callsign_alphabet.indexOf(matched.at(0));
|
||||
packed = 36*packed + callsign_alphabet.indexOf(matched.at(1));
|
||||
packed = 10*packed + callsign_alphabet.indexOf(matched.at(2));
|
||||
packed = 27*packed + callsign_alphabet.indexOf(matched.at(3)) - 10;
|
||||
packed = 27*packed + callsign_alphabet.indexOf(matched.at(4)) - 10;
|
||||
packed = 27*packed + callsign_alphabet.indexOf(matched.at(5)) - 10;
|
||||
|
||||
return packed;
|
||||
}
|
||||
|
||||
QString Varicode::unpackCallsign(quint32 value){
|
||||
foreach(auto key, basecalls.keys()){
|
||||
if(basecalls[key] == value){
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
QChar word[6];
|
||||
quint32 tmp = value % 27 + 10;
|
||||
word[5] = callsign_alphabet.at(tmp);
|
||||
value = value/27;
|
||||
|
||||
tmp = value % 27 + 10;
|
||||
word[4] = callsign_alphabet.at(tmp);
|
||||
value = value/27;
|
||||
|
||||
tmp = value % 27 + 10;
|
||||
word[3] = callsign_alphabet.at(tmp);
|
||||
value = value/27;
|
||||
|
||||
tmp = value % 10;
|
||||
word[2] = callsign_alphabet.at(tmp);
|
||||
value = value/10;
|
||||
|
||||
tmp = value % 36;
|
||||
word[1] = callsign_alphabet.at(tmp);
|
||||
value = value/36;
|
||||
|
||||
tmp = value;
|
||||
word[0] = callsign_alphabet.at(tmp);
|
||||
|
||||
QString callsign(word, 6);
|
||||
if(callsign.startsWith("3D0")){
|
||||
callsign = "3DA0" + callsign.mid(3);
|
||||
}
|
||||
|
||||
if(callsign.startsWith("Q") and 'A' <= callsign.at(1) && callsign.at(1) <= 'Z'){
|
||||
callsign = "3X" + callsign.mid(1);
|
||||
}
|
||||
|
||||
return callsign;
|
||||
}
|
||||
|
||||
QString deg2grid(float dlong, float dlat){
|
||||
QChar grid[6];
|
||||
|
||||
if(dlong < -180){
|
||||
dlong += 360;
|
||||
}
|
||||
if(dlong > 180){
|
||||
dlong -= 360;
|
||||
}
|
||||
|
||||
int nlong = int(60.0*(180.0-dlong)/5);
|
||||
|
||||
int n1 = nlong/240;
|
||||
int n2 = (nlong-240*n1)/24;
|
||||
int n3 = (nlong-240*n1-24*n2);
|
||||
|
||||
grid[0] = QChar('A' + n1);
|
||||
grid[2] = QChar('0' + n2);
|
||||
grid[4] = QChar('a' + n3);
|
||||
|
||||
int nlat=int(60.0*(dlat+90)/2.5);
|
||||
|
||||
n1 = nlat/240;
|
||||
n2 = (nlat-240*n1)/24;
|
||||
n3 = (nlat-240*n1-24*n2);
|
||||
|
||||
grid[1] = QChar('A' + n1);
|
||||
grid[3] = QChar('0' + n2);
|
||||
grid[5] = QChar('a' + n3);
|
||||
|
||||
return QString(grid, 6);
|
||||
}
|
||||
|
||||
QPair<float, float> grid2deg(QString const &grid){
|
||||
QPair<float, float> longLat;
|
||||
|
||||
QString g = grid;
|
||||
if(g.length() < 6){
|
||||
g = grid.left(4) + "mm";
|
||||
}
|
||||
|
||||
g = g.left(4).toUpper() + g.right(2).toLower();
|
||||
|
||||
int nlong = 180 - 20 * (g.at(0).toLatin1() - 'A');
|
||||
int n20d = 2 * (g.at(2).toLatin1() - '0');
|
||||
float xminlong = 5 * (g.at(4).toLatin1() - 'a' + 0.5);
|
||||
float dlong = nlong - n20d - xminlong/60.0;
|
||||
|
||||
int nlat = -90 + 10*(g.at(1).toLatin1() - 'A') + g.at(3).toLatin1() - '0';
|
||||
float xminlat = 2.5 * (g.at(5).toLatin1() - 'a' + 0.5);
|
||||
float dlat = nlat + xminlat/60.0;
|
||||
|
||||
longLat.first = dlong;
|
||||
longLat.second = dlat;
|
||||
|
||||
return longLat;
|
||||
}
|
||||
|
||||
quint16 Varicode::packGrid(QString const& grid){
|
||||
// TODO: validate grid...
|
||||
|
||||
// TODO: encode non-grid data...
|
||||
|
||||
auto pair = grid2deg(grid.left(4));
|
||||
int ilong = pair.first;
|
||||
int ilat = pair.second + 90;
|
||||
|
||||
return ((ilong + 180)/2) * 180 + ilat;
|
||||
}
|
||||
|
||||
QString Varicode::unpackGrid(quint16 value){
|
||||
if(value > 180*180){
|
||||
// TODO: decode non-grid data...
|
||||
return "";
|
||||
}
|
||||
|
||||
float dlat = value % 180 - 90;
|
||||
float dlong = value / 180 * 2 - 180 + 2;
|
||||
|
||||
return deg2grid(dlong, dlat).left(4);
|
||||
}
|
||||
|
||||
bool Varicode::isCommandAllowed(const QString &cmd){
|
||||
return directed_cmds.contains(cmd) && allowed_cmds.contains(directed_cmds[cmd]);
|
||||
}
|
||||
|
||||
QString Varicode::packDirectedMessage(const QString &text, const QString &callsign, int *n){
|
||||
QString frame;
|
||||
|
||||
auto match = directed_re.match(text);
|
||||
if(match.hasMatch()){
|
||||
QString from = callsign;
|
||||
QString to = match.captured("to");
|
||||
QString cmd = match.captured("cmd");
|
||||
QString num = match.captured("num").trimmed();
|
||||
QString pwr = match.captured("pwr").trimmed();
|
||||
|
||||
int inum = -31;
|
||||
bool hasnum = false;
|
||||
if(!num.isEmpty()){
|
||||
inum = qMax(-30, qMin(num.toInt(&hasnum, 10), 30));
|
||||
}
|
||||
|
||||
// if we are packing a PWR command, pack pwr into dbm
|
||||
int ipwr = -31;
|
||||
if(!pwr.isEmpty() && cmd.trimmed() == "PWR"){
|
||||
int factor = 1000;
|
||||
if(pwr.endsWith("KW")){
|
||||
factor = 1000000;
|
||||
}
|
||||
else if(pwr.endsWith("MW")){
|
||||
factor = 1;
|
||||
}
|
||||
ipwr = pwr.replace(QRegExp("[KM]?W"), "").toInt() * factor;
|
||||
inum = mwattsToDbm(ipwr) - 30;
|
||||
}
|
||||
|
||||
if(to == callsign){
|
||||
*n = 0;
|
||||
return frame;
|
||||
}
|
||||
|
||||
bool validToCallsign = basecalls.contains(to) || QRegularExpression(callsign_pattern2).match(to).hasMatch();
|
||||
if(!validToCallsign || !Varicode::isCommandAllowed(cmd)){
|
||||
*n = 0;
|
||||
return frame;
|
||||
}
|
||||
|
||||
// TODO: jsherer - we don't need this CRC... the FT8 msg already has a 12 bit CRC...
|
||||
//auto fromBytes = from.toLocal8Bit();
|
||||
//auto fromCRC = CRC::Calculate(fromBytes.data(), fromBytes.length(), CRC::CRC_5_ITU());
|
||||
|
||||
quint8 packed_is_data = 0;
|
||||
quint8 packed_flag = inum < 0 ? 1 : 0;
|
||||
quint32 packed_from = Varicode::packCallsign(from);
|
||||
quint32 packed_to = Varicode::packCallsign(to);
|
||||
|
||||
if(packed_from == 0 || packed_to == 0){
|
||||
*n = 0;
|
||||
return frame;
|
||||
}
|
||||
|
||||
quint8 packed_cmd = directed_cmds[cmd];
|
||||
quint8 packed_extra = qAbs(inum);
|
||||
|
||||
// [1][2][28][28][5],[5] = 69
|
||||
auto bits = (
|
||||
Varicode::intToBits(packed_is_data, 1) +
|
||||
Varicode::intToBits(packed_flag, 2) +
|
||||
Varicode::intToBits(packed_from, 28) +
|
||||
Varicode::intToBits(packed_to, 28) +
|
||||
Varicode::intToBits(packed_cmd & 31, 5)
|
||||
);
|
||||
frame = Varicode::pack64bits(Varicode::bitsToInt(bits)) + Varicode::pack5bits(packed_extra & 31);
|
||||
*n = match.captured(0).length();
|
||||
return frame;
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
QStringList Varicode::unpackDirectedMessage(const QString &text){
|
||||
QStringList unpacked;
|
||||
|
||||
if(text.length() < 13){
|
||||
return unpacked;
|
||||
}
|
||||
|
||||
// [1][2][28][28][5],[5] = 69
|
||||
auto bits = Varicode::bitsToStr(Varicode::intToBits(Varicode::unpack64bits(text.left(12)), 64));
|
||||
quint8 extra = Varicode::unpack5bits(text.right(1));
|
||||
|
||||
quint8 is_data = Varicode::bitsToInt(Varicode::strToBits(bits.left(1)));
|
||||
if(is_data != 0){
|
||||
return unpacked;
|
||||
}
|
||||
quint8 flag = Varicode::bitsToInt(Varicode::strToBits(bits.mid(1,2)));
|
||||
quint32 packed_from = Varicode::bitsToInt(Varicode::strToBits(bits.mid(3, 28)));
|
||||
quint32 packed_to = Varicode::bitsToInt(Varicode::strToBits(bits.mid(31, 28)));
|
||||
quint8 packed_cmd = Varicode::bitsToInt(Varicode::strToBits(bits.mid(59, 5)));
|
||||
|
||||
QString from = Varicode::unpackCallsign(packed_from).trimmed();
|
||||
|
||||
// TODO: jsherer - we don't need this CRC... the FT8 msg already has a 12 bit CRC...
|
||||
//auto fromBytes = from.toLocal8Bit();
|
||||
//auto fromCRC = CRC::Calculate(fromBytes.data(), fromBytes.length(), CRC::CRC_5_ITU());
|
||||
//if(fromCRC != extra){
|
||||
// return unpacked;
|
||||
//}
|
||||
|
||||
unpacked.append(from);
|
||||
unpacked.append(Varicode::unpackCallsign(packed_to).trimmed());
|
||||
unpacked.append(directed_cmds.key(packed_cmd & 31));
|
||||
|
||||
int num = (flag ? -1 : 1) * extra;
|
||||
if(num != -31){
|
||||
// TODO: jsherer - should we decide which format to use on the command, or something else?
|
||||
if(packed_cmd == directed_cmds[" PWR"]){
|
||||
unpacked.append(Varicode::formatPWR(num + 30));
|
||||
} else if(packed_cmd == directed_cmds[" SNR"]) {
|
||||
unpacked.append(Varicode::formatSNR(num));
|
||||
} else {
|
||||
unpacked.append(QString("%1").arg(num));
|
||||
}
|
||||
}
|
||||
|
||||
return unpacked;
|
||||
}
|
||||
|
||||
QString Varicode::packDataMessage(const QString &text, int *n){
|
||||
QString frame;
|
||||
|
||||
// [1][63],[5] = 69
|
||||
quint8 is_data = 1;
|
||||
auto frameBits = (
|
||||
Varicode::intToBits(is_data, 1)
|
||||
);
|
||||
|
||||
int i = 0;
|
||||
foreach(auto charBits, Varicode::huffEncode(text)){
|
||||
if(frameBits.length() + charBits.length() < 63){
|
||||
frameBits += charBits;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
int pad = 64 - frameBits.length();
|
||||
if(pad){
|
||||
frameBits += Varicode::intToBits(0, pad);
|
||||
}
|
||||
|
||||
frame = Varicode::pack64bits(Varicode::bitsToInt(frameBits)) + Varicode::pack5bits(pad & 31);
|
||||
*n = i;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
QString Varicode::unpackDataMessage(const QString &text){
|
||||
QString unpacked;
|
||||
|
||||
if(text.length() < 13){
|
||||
return unpacked;
|
||||
}
|
||||
|
||||
auto bits = Varicode::intToBits(Varicode::unpack64bits(text.left(12)), 64);
|
||||
quint8 pad = Varicode::unpack5bits(text.right(1));
|
||||
|
||||
quint8 is_data = (int)bits.at(0);
|
||||
if(is_data != 1){
|
||||
return unpacked;
|
||||
}
|
||||
|
||||
// pop off the is_data bit
|
||||
bits.removeAt(0);
|
||||
|
||||
unpacked = Varicode::huffDecode(bits, pad);
|
||||
|
||||
return unpacked;
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
#ifndef VARICODE_H
|
||||
#define VARICODE_H
|
||||
|
||||
/**
|
||||
* (C) 2018 Jordan Sherer <kn4crd@gmail.com> - All Rights Reserved
|
||||
**/
|
||||
|
||||
#include <QBitArray>
|
||||
#include <QRegularExpression>
|
||||
#include <QRegExp>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
|
||||
class Varicode
|
||||
{
|
||||
public:
|
||||
enum FrameType{
|
||||
FT8 = 0, // [000]
|
||||
FT8Fox = 1, // [001]
|
||||
FT8Call = 2, // [010]
|
||||
FT8CallLast = 3, // [011] <- used to indicate last frame in transmission
|
||||
FT8CallReservedA = 4, // [100]
|
||||
FT8CallReservedB = 5, // [101]
|
||||
FT8CallReservedC = 6, // [110]
|
||||
FT8CallReservedD = 7, // [111]
|
||||
};
|
||||
|
||||
//Varicode();
|
||||
|
||||
static QString formatSNR(int snr);
|
||||
static QString formatPWR(int dbm);
|
||||
|
||||
static QStringList parseCallsigns(QString const &input);
|
||||
static QStringList parseGrids(QString const &input);
|
||||
|
||||
static QList<QVector<bool>> huffEncode(QString const& text);
|
||||
static QVector<bool> huffFlatten(QList<QVector<bool>> &list);
|
||||
static QString huffDecode(QVector<bool> const& bitvec, int pad=0);
|
||||
|
||||
static QVector<bool> bytesToBits(char * bitvec, int n);
|
||||
static QVector<bool> strToBits(QString const& bitvec);
|
||||
static QString bitsToStr(QVector<bool> const& bitvec);
|
||||
|
||||
static QVector<bool> intToBits(quint64 value, int expected=0);
|
||||
static quint64 bitsToInt(QVector<bool> const value);
|
||||
static quint64 bitsToInt(QVector<bool>::ConstIterator start, int n);
|
||||
|
||||
static quint8 unpack5bits(QString const& value);
|
||||
static QString pack5bits(quint8 packed);
|
||||
|
||||
static quint16 unpack16bits(QString const& value);
|
||||
static QString pack16bits(quint16 packed);
|
||||
|
||||
static quint32 unpack32bits(QString const& value);
|
||||
static QString pack32bits(quint32 packed);
|
||||
|
||||
static quint64 unpack64bits(QString const& value);
|
||||
static QString pack64bits(quint64 packed);
|
||||
|
||||
static quint32 packCallsign(QString const& value);
|
||||
static QString unpackCallsign(quint32 value);
|
||||
|
||||
static quint16 packGrid(QString const& value);
|
||||
static QString unpackGrid(quint16 value);
|
||||
|
||||
static bool isCommandAllowed(const QString &cmd);
|
||||
static QString packDirectedMessage(QString const& text, QString const& callsign, int *n);
|
||||
static QStringList unpackDirectedMessage(QString const& text);
|
||||
|
||||
static QString packDataMessage(QString const& text, int *n);
|
||||
static QString unpackDataMessage(QString const& text);
|
||||
};
|
||||
|
||||
#endif // VARICODE_H
|
||||
+6
-5
@@ -64,8 +64,8 @@ WideGraph::WideGraph(QSettings * settings, QWidget *parent) :
|
||||
ui->bppSpinBox->setValue(n);
|
||||
m_nsmo=m_settings->value("SmoothYellow",1).toInt();
|
||||
ui->smoSpinBox->setValue(m_nsmo);
|
||||
m_Percent2DScreen=m_settings->value("Percent2D",30).toInt();
|
||||
m_waterfallAvg = m_settings->value("WaterfallAvg",5).toInt();
|
||||
m_Percent2DScreen=m_settings->value("Percent2D", 0).toInt();
|
||||
m_waterfallAvg = m_settings->value("WaterfallAvg", 1).toInt();
|
||||
ui->waterfallAvgSpinBox->setValue(m_waterfallAvg);
|
||||
ui->widePlot->setWaterfallAvg(m_waterfallAvg);
|
||||
ui->widePlot->setCurrent(m_settings->value("Current",false).toBool());
|
||||
@@ -76,17 +76,18 @@ WideGraph::WideGraph(QSettings * settings, QWidget *parent) :
|
||||
if(ui->widePlot->cumulative()) ui->spec2dComboBox->setCurrentIndex(1);
|
||||
if(ui->widePlot->linearAvg()) ui->spec2dComboBox->setCurrentIndex(2);
|
||||
if(ui->widePlot->Reference()) ui->spec2dComboBox->setCurrentIndex(3);
|
||||
int nbpp=m_settings->value("BinsPerPixel",2).toInt();
|
||||
int nbpp=m_settings->value("BinsPerPixel", 4).toInt();
|
||||
ui->widePlot->setBinsPerPixel(nbpp);
|
||||
ui->sbPercent2dPlot->setValue(m_Percent2DScreen);
|
||||
ui->widePlot->SetPercent2DScreen(m_Percent2DScreen);
|
||||
ui->widePlot->setStartFreq(m_settings->value("StartFreq",0).toInt());
|
||||
ui->fStartSpinBox->setValue(ui->widePlot->startFreq());
|
||||
m_waterfallPalette=m_settings->value("WaterfallPalette","Default").toString();
|
||||
m_userPalette = WFPalette {m_settings->value("UserPalette").value<WFPalette::Colours> ()};
|
||||
m_fMinPerBand = m_settings->value ("FminPerBand").toHash ();
|
||||
setRxRange ();
|
||||
ui->controls_widget->setVisible(!m_settings->value("HideControls",false).toBool());
|
||||
ui->cbControls->setChecked(!m_settings->value("HideControls",false).toBool());
|
||||
ui->controls_widget->setVisible(!m_settings->value("HideControls", true).toBool());
|
||||
ui->cbControls->setChecked(!m_settings->value("HideControls", true).toBool());
|
||||
}
|
||||
|
||||
int index=0;
|
||||
|
||||
+4
-4
@@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>799</width>
|
||||
<width>942</width>
|
||||
<height>337</height>
|
||||
</rect>
|
||||
</property>
|
||||
@@ -68,7 +68,7 @@
|
||||
<string>Controls</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
@@ -219,7 +219,7 @@
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>30</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -293,7 +293,7 @@
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>2</number>
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -67,7 +67,8 @@ SOURCES += \
|
||||
echoplot.cpp echograph.cpp fastgraph.cpp fastplot.cpp Modes.cpp \
|
||||
WSPRBandHopping.cpp MessageAggregator.cpp SampleDownloader.cpp qt_helpers.cpp\
|
||||
MultiSettings.cpp PhaseEqualizationDialog.cpp IARURegions.cpp MessageBox.cpp \
|
||||
EqualizationToolsDialog.cpp
|
||||
EqualizationToolsDialog.cpp \
|
||||
varicode.cpp
|
||||
|
||||
HEADERS += qt_helpers.hpp \
|
||||
pimpl_h.hpp pimpl_impl.hpp \
|
||||
@@ -83,7 +84,11 @@ HEADERS += qt_helpers.hpp \
|
||||
logbook/logbook.h logbook/countrydat.h logbook/countriesworked.h logbook/adif.h \
|
||||
messageaveraging.h echoplot.h echograph.h fastgraph.h fastplot.h Modes.hpp WSPRBandHopping.hpp \
|
||||
WsprTxScheduler.h SampleDownloader.hpp MultiSettings.hpp PhaseEqualizationDialog.hpp \
|
||||
IARURegions.hpp MessageBox.hpp EqualizationToolsDialog.hpp
|
||||
IARURegions.hpp MessageBox.hpp EqualizationToolsDialog.hpp \
|
||||
qorderedmap.h \
|
||||
varicode.h \
|
||||
qpriorityqueue.h \
|
||||
crc.h
|
||||
|
||||
|
||||
INCLUDEPATH += qmake_only
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 3.5.1, 2018-02-02T18:34:55. -->
|
||||
<!-- Written by QtCreator 3.5.1, 2018-03-10T16:32:07. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
|
||||
Reference in New Issue
Block a user