Merge branch 'support-2.3.1' into release-2.4.0

This commit is contained in:
Bill Somerville 2021-03-03 23:58:39 +00:00
commit 22f1ba6a6d
No known key found for this signature in database
GPG Key ID: D864B06D1E81618F
56 changed files with 764 additions and 616 deletions

View File

@ -16,11 +16,15 @@ namespace
DecodedText::DecodedText (QString const& the_string)
: string_ {the_string.left (the_string.indexOf (QChar::Nbsp))} // discard appended info
, clean_string_ {string_}
, padding_ {string_.indexOf (" ") > 4 ? 2 : 0} // allow for
// seconds
, message_ {string_.mid (column_qsoText + padding_).trimmed ()}
, is_standard_ {false}
{
// discard appended AP info
clean_string_.replace (QRegularExpression {R"(^(.*)(?:(?:\?\s)?a[0-9].*)$)"}, "\\1");
// qDebug () << "DecodedText: the_string:" << the_string << "Nbsp pos:" << the_string.indexOf (QChar::Nbsp);
if (message_.length() >= 1)
{

View File

@ -32,6 +32,7 @@ public:
explicit DecodedText (QString const& message);
QString string() const { return string_; };
QString clean_string() const { return clean_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); };
@ -76,6 +77,7 @@ private:
column_qsoText = 22 };
QString string_;
QString clean_string_;
int padding_;
QString message_;
QString message0_;

View File

@ -576,20 +576,28 @@ void MultiSettings::impl::select_configuration (QString const& target_name)
{
if (main_window_ && target_name != current_)
{
bool changed {false};
{
auto const& current_group = settings_.group ();
if (current_group.size ()) settings_.endGroup ();
// position to the alternative settings
SettingsGroup alternatives {&settings_, multi_settings_root_group};
// save the target settings
SettingsGroup target_group {&settings_, target_name};
new_settings_ = get_settings ();
if (settings_.childGroups ().contains (target_name))
{
changed = true;
// save the target settings
SettingsGroup target_group {&settings_, target_name};
new_settings_ = get_settings ();
}
if (current_group.size ()) settings_.beginGroup (current_group);
}
// and set up the restart
current_ = target_name;
Q_EMIT parent_->configurationNameChanged (unescape_ampersands (current_));
restart (RepositionType::save_and_replace);
if (changed)
{
// and set up the restart
current_ = target_name;
Q_EMIT parent_->configurationNameChanged (unescape_ampersands (current_));
restart (RepositionType::save_and_replace);
}
}
}

View File

@ -117,7 +117,7 @@ SampleDownloader::impl::impl (QSettings * settings
main_layout_.addLayout (&left_layout_, 0, 0);
main_layout_.addWidget (&button_box_, 0, 1);
main_layout_.addWidget (&details_widget_, 1, 0, 1, 2);
main_layout_.setRowStretch (1, 2);
main_layout_.setRowStretch (0, 2);
setLayout (&main_layout_);
connect (&button_box_, &QDialogButtonBox::clicked, this, &SampleDownloader::impl::button_clicked);

View File

@ -49,6 +49,8 @@ Directory::Directory (Configuration const * configuration
setColumnCount (2);
setHeaderLabels ({tr ("File"), tr ("Progress")});
headerItem ()->setTextAlignment (0, Qt::AlignHCenter);
headerItem ()->setTextAlignment (1, Qt::AlignHCenter);
header ()->setSectionResizeMode (QHeaderView::ResizeToContents);
setItemDelegate (&item_delegate_);
@ -294,14 +296,15 @@ void Directory::update (QTreeWidgetItem * item)
int counted {0};
// get the count, progress and size of children
int items {recurse_children (item, &counted, &bytes, &max)};
// int items {recurse_children (item, &counted, &bytes, &max)};
recurse_children (item, &counted, &bytes, &max);
// estimate size of items not yet downloaded as average of
// those actually present
if (counted)
{
max += (items - counted) * max / counted;
}
// if (counted)
// {
// max += (items - counted) * max / counted;
// }
// save as our progress
item->setData (1, Qt::UserRole, max);

View File

@ -14,28 +14,42 @@ void DirectoryDelegate::paint (QPainter * painter, QStyleOptionViewItem const& o
{
if (1 == index.column ())
{
QStyleOptionProgressBar progress_bar_option;
progress_bar_option.rect = option.rect;
progress_bar_option.state = QStyle::State_Enabled;
progress_bar_option.direction = QApplication::layoutDirection ();
progress_bar_option.fontMetrics = QApplication::fontMetrics ();
progress_bar_option.minimum = 0;
progress_bar_option.maximum = 100;
auto progress = index.data ().toLongLong ();
qint64 percent;
if (progress > 0)
{
auto percent = int (progress * 100 / index.data (Qt::UserRole).toLongLong ());
progress_bar_option.progress = percent;
progress_bar_option.text = QString::number (percent) + '%';
progress_bar_option.textVisible = true;
progress_bar_option.textAlignment = Qt::AlignCenter;
percent = int (progress * 100 / index.data (Qt::UserRole).toLongLong ());
}
#if !defined (Q_OS_DARWIN)
QStyleOptionProgressBar progress_option;
auto control_element = QStyle::CE_ProgressBar;
progress_option.minimum = 0;
progress_option.maximum = 100;
progress_option.textAlignment = Qt::AlignCenter;
if (progress > 0)
{
progress_option.progress = percent;
progress_option.textVisible = true;
}
else
{
// not started
progress_bar_option.progress = -1;
progress_option.progress = -1;
}
QApplication::style ()->drawControl (QStyle::CE_ProgressBar, &progress_bar_option, painter);
#else
// workaround for broken QProgressBar item delegates on macOS
QStyleOptionViewItem progress_option;
auto control_element = QStyle::CE_ItemViewItem;
progress_option.displayAlignment = Qt::AlignHCenter;
progress_option.index = index;
progress_option.features = QStyleOptionViewItem::HasDisplay;
#endif
progress_option.rect = option.rect;
progress_option.state = QStyle::State_Enabled;
progress_option.direction = QApplication::layoutDirection ();
progress_option.fontMetrics = QApplication::fontMetrics ();
progress_option.text = QString::number (progress > 0 ? percent : 0) + '%';
QApplication::style ()->drawControl (control_element, &progress_option, painter);
}
else
{

View File

@ -27,7 +27,12 @@ FileNode::FileNode (QTreeWidgetItem * parent
void FileNode::error (QString const& title, QString const& message)
{
MessageBox::warning_message (treeWidget (), title, message);
if (MessageBox::Retry == MessageBox::warning_message (treeWidget (), title, message
, QString {}, MessageBox::Cancel | MessageBox::Retry
, MessageBox::Cancel))
{
sync (true);
}
}
bool FileNode::sync (bool local)

View File

@ -436,7 +436,11 @@ HamlibTransceiver::HamlibTransceiver (logger_type * logger,
{
m_->set_conf ("ptt_type", "RTS");
}
set_conf ("ptt_share", "1");
}
// do this late to allow any configuration option to be overriden
load_user_settings ();
}
HamlibTransceiver::HamlibTransceiver (logger_type * logger,
@ -453,52 +457,7 @@ HamlibTransceiver::HamlibTransceiver (logger_type * logger,
// m_->rig_->state.obj = this;
//
// user defined Hamlib settings
//
auto settings_file_name = QStandardPaths::locate (QStandardPaths::AppConfigLocation
, "hamlib_settings.json");
if (!settings_file_name.isEmpty ())
{
QFile settings_file {settings_file_name};
qDebug () << "Using Hamlib settings file:" << settings_file_name;
if (settings_file.open (QFile::ReadOnly))
{
QJsonParseError status;
auto settings_doc = QJsonDocument::fromJson (settings_file.readAll (), &status);
if (status.error)
{
throw error {tr ("Hamlib settings file error: %1 at character offset %2")
.arg (status.errorString ()).arg (status.offset)};
}
qDebug () << "Hamlib settings JSON:" << settings_doc.toJson ();
if (!settings_doc.isObject ())
{
throw error {tr ("Hamlib settings file error: top level must be a JSON object")};
}
auto const& settings = settings_doc.object ();
//
// configuration settings
//
auto const& config = settings["config"];
if (!config.isUndefined ())
{
if (!config.isObject ())
{
throw error {tr ("Hamlib settings file error: config must be a JSON object")};
}
auto const& config_list = config.toObject ();
for (auto item = config_list.constBegin (); item != config_list.constEnd (); ++item)
{
m_->set_conf (item.key ().toLocal8Bit ().constData ()
, (*item).toVariant ().toString ().toLocal8Bit ().constData ());
}
}
}
}
if (!m_->is_dummy_)
if (!is_dummy_)
{
switch (rig_get_caps_int (m_->model_, RIG_CAPS_PORT_TYPE))
{
@ -592,17 +551,69 @@ HamlibTransceiver::HamlibTransceiver (logger_type * logger,
{
m_->set_conf ("ptt_type", "RTS");
}
set_conf ("ptt_share", "1");
}
// Make Icom CAT split commands less glitchy
m_->set_conf ("no_xchg", "1");
// do this late to allow any configuration option to be overriden
load_user_settings ();
// would be nice to get events but not supported on Windows and also not on a lot of rigs
// rig_set_freq_callback (m_->rig_.data (), &frequency_change_callback, this);
}
HamlibTransceiver::~HamlibTransceiver () = default;
void HamlibTransceiver::load_user_settings ()
{
//
// user defined Hamlib settings
//
auto settings_file_name = QStandardPaths::locate (QStandardPaths::AppConfigLocation
, "hamlib_settings.json");
if (!settings_file_name.isEmpty ())
{
QFile settings_file {settings_file_name};
qDebug () << "Using Hamlib settings file:" << settings_file_name;
if (settings_file.open (QFile::ReadOnly))
{
QJsonParseError status;
auto settings_doc = QJsonDocument::fromJson (settings_file.readAll (), &status);
if (status.error)
{
throw error {tr ("Hamlib settings file error: %1 at character offset %2")
.arg (status.errorString ()).arg (status.offset)};
}
qDebug () << "Hamlib settings JSON:" << settings_doc.toJson ();
if (!settings_doc.isObject ())
{
throw error {tr ("Hamlib settings file error: top level must be a JSON object")};
}
auto const& settings = settings_doc.object ();
//
// configuration settings
//
auto const& config = settings["config"];
if (!config.isUndefined ())
{
if (!config.isObject ())
{
throw error {tr ("Hamlib settings file error: config must be a JSON object")};
}
auto const& config_list = config.toObject ();
for (auto item = config_list.constBegin (); item != config_list.constEnd (); ++item)
{
set_conf (item.key ().toLocal8Bit ().constData ()
, (*item).toVariant ().toString ().toLocal8Bit ().constData ());
}
}
}
}
}
int HamlibTransceiver::do_start ()
{
CAT_TRACE ("starting: " << rig_get_caps_cptr (m_->model_, RIG_CAPS_MFG_NAME_CPTR)

View File

@ -24,6 +24,7 @@ public:
~HamlibTransceiver ();
private:
void load_user_settings ();
int do_start () override;
void do_stop () override;
void do_frequency (Frequency, MODE, bool no_ignore) override;

View File

@ -192,7 +192,7 @@ WSJTXLogging::WSJTXLogging ()
(
sinks::file::make_collector
(
keywords::max_size = 40 * 1024 * 1024
keywords::max_size = 5 * 1024 * 1024
, keywords::min_free_space = 1024 * 1024 * 1024
, keywords::max_files = 12
, keywords::target = app_data.absoluteFilePath ("logs").toStdWString ()

842
cty.dat

File diff suppressed because it is too large Load Diff

View File

@ -166,9 +166,9 @@ function (document)
COMMAND ${ASCIIDOCTOR_EXECUTABLE} ${_args_ASCIIDOCTOR_OPTIONS}
-b html5
-a nofooter
-a VERSION_MAJOR=${WSJTX_VERSION_MAJOR}
-a VERSION_MINOR=${WSJTX_VERSION_MINOR}
-a VERSION_PATCH=${WSJTX_VERSION_PATCH}
-a VERSION_MAJOR=${PROJECT_VERSION_MAJOR}
-a VERSION_MINOR=${PROJECT_VERSION_MINOR}
-a VERSION_PATCH=${PROJECT_VERSION_PATCH}
-a VERSION=${wsjtx_VERSION}
--out-file=${_html_file} ${_source_name}
DEPENDS ${_args_DEPENDS}
@ -195,9 +195,9 @@ function (document)
COMMAND ${ASCIIDOCTOR_EXECUTABLE} ARGS ${_args_ASCIIDOCTOR_OPTIONS}
-b docbook
-a data-uri!
-a VERSION_MAJOR=${WSJTX_VERSION_MAJOR}
-a VERSION_MINOR=${WSJTX_VERSION_MINOR}
-a VERSION_PATCH=${WSJTX_VERSION_PATCH}${BUILD_TYPE_REVISION}
-a VERSION_MAJOR=${wsjtx_VERSION_MAJOR}
-a VERSION_MINOR=${wsjtx_VERSION_MINOR}
-a VERSION_PATCH=${wsjtx_VERSION_PATCH}${BUILD_TYPE_REVISION}
-a VERSION=${wsjtx_VERSION}
-D ${CMAKE_CURRENT_BINARY_DIR}
-o ${_docbook_file} ${_source_name}

View File

@ -94,8 +94,8 @@ d). Edit lines as needed. Keeping them in alphabetic order help see dupes.
:sourceforge-jtsdk: https://sourceforge.net/projects/jtsdk[SourceForge JTSDK]
:ubuntu_sdk: https://launchpad.net/~ubuntu-sdk-team/+archive/ppa[Ubuntu SDK Notice]
:win_openssl_packages: https://slproweb.com/products/Win32OpenSSL.html[Windows OpenSSL Packages]
:win32_openssl: https://slproweb.com/download/Win32OpenSSL_Light-1_1_1h.msi[Win32 OpenSSL Light Package]
:win64_openssl: https://slproweb.com/download/Win64OpenSSL_Light-1_1_1h.msi[Win64 OpenSSL Light Package]
:win32_openssl: https://slproweb.com/download/Win32OpenSSL_Light-1_1_1j.msi[Win32 OpenSSL Light Package]
:win64_openssl: https://slproweb.com/download/Win64OpenSSL_Light-1_1_1j.msi[Win64 OpenSSL Light Package]
:writelog: https://writelog.com/[Writelog]
:wsjtx_group: https://groups.io/g/WSJTX[WSJTX Group]
:wsjtx: https://physics.princeton.edu/pulsar/K1JT/wsjtx.html[WSJT-X]

View File

@ -37,6 +37,12 @@ examples for configurations `FT8` and `Echo`:
==== View Menu
image::view-menu.png[align="left",alt="View Menu"]
The *SWL Mode* action reduces the _WSJT-X_ main window to a minimum
size with just the menus, decodes windows, and status bar visible. You
may find this useful when running multiple instances of the
application. Both size and location of the main window are saved and
recalled independently for this view.
[[MODE_MENU]]
==== Mode Menu
image::mode-menu.png[align="left",alt="Mode Menu"]

View File

@ -1,11 +1,10 @@
// Status=edited
Two arrangements of controls are provided for generating and selecting
Tx messages. Controls familiar to users of program _WSJT_
appear on *Tab 1*, providing six fields for message entry.
Pre-formatted messages for the standard minimal QSO are generated when
you click *Generate Std Msgs* or double-click on an appropriate line
in one of the decoded text windows.
Controls familiar to users of program _WSJT_ appear on *Tab 1*,
providing six fields for message entry. Pre-formatted messages for
the standard minimal QSO are generated when you click *Generate Std
Msgs* or double-click on an appropriate line in one of the decoded
text windows.
//.Traditional Message Menu
image::traditional-msg-box.png[align="center",alt="Traditional Message Menu"]
@ -28,31 +27,12 @@ stored messages entered on the *Files -> Settings -> Tx Macros* tab.
Pressing *Enter* on a modified message #5 automatically adds that
message to the stored macros.
* In some circumstances it may be desirable to make your QSOs as
short as possible. To configure the program to start contacts with
message #2, disable message #1 by double-clicking its radio-button in the *Next* column or *Tx 1* button in the *Now* column. Similarly, to send RR73
rather than RRR for message #4, double-click one of its buttons.
The second arrangement of controls for generating and selecting
Tx messages appears on *Tab 2* of the Message Control Panel:
//.New Message Menu
image::new-msg-box.png[align="center",alt="New Message Menu"]
With this setup you normally follow a top-to-bottom sequence of
transmissions from the left column if you are calling CQ, or the right
column if answering a CQ.
* Clicking a button puts the appropriate message in the *Gen Msg* box.
If you are already transmitting, the Tx message is changed
immediately.
* You can enter and transmit anything (up to 13 characters, including
spaces) in the *Free Msg* box.
* Click the pull-down arrow in the *Free Msg* box to select a
stored macro. Pressing *Enter* on a modified message here
automatically adds that message to the table of stored macros.
* In some circumstances it may be desirable to make your QSOs as short
as possible. To configure the program to start contacts with message
#2, disable message #1 by double-clicking its radio-button in the
*Next* column or *Tx 1* button in the *Now* column. Similarly, to
send RR73 rather than RRR for message #4, double-click one of its
buttons.
+

View File

@ -2,12 +2,12 @@
=== AP Decoding
The _WSJT-X_ decoders for FT4, FT8, JT65, QRA64, include
The _WSJT-X_ decoders for FST4, FT4, FT8, JT65, and QRA64 include
procedures that use naturally accumulating information during a
minimal QSO. This _a priori_ (AP) information increases sensitivity
of the decoder by up to 4 dB, at the cost of a slightly higher rate of
false decodes. AP is optional in FT8, JT65, and QRA64, but is always
enabled for FT4.
enabled for FT4 and FST4 when decode depth is Normal or Deep.
For example: when you decide to answer a CQ, you already know your own
callsign and that of your potential QSO partner. The software
@ -27,7 +27,7 @@ example, `a2` indicates that the successful decode used MyCall as
hypothetically known information.
[[FT8_AP_INFO_TABLE]]
.FT4 and FT8 AP information types
.FST4, FT4, and FT8 AP information types
[width="35%",cols="h10,<m20",frame=topbot,options="header"]
|===============================================
|aP | Message components
@ -47,7 +47,9 @@ forwarded to {pskreporter}.
Table 2 lists the six possible QSO states that are tracked by the
_WSJT-X_ auto-sequencer, along with the type of AP decoding that would
be attempted in each state.
be attempted in each state in FT4 or FT8. The FST4 table (not shown)
is the same except that it omits the decoding attempts for AP types
4 and 5 to save time.
[[FT8_AP_DECODING_TYPES_TABLE]]
.FT4 and FT8 AP decoding types for each QSO state
@ -109,13 +111,15 @@ summarized in the following Table:
[width="50%",cols="h,3*^",frame=topbot,options="header"]
|===========================================
|Mode |Mode character|Sync character|End of line information
|FST4 | ` | | ? &#160; aP
|FT4 | ~ | | ? &#160; aP
|FT8 | ~ | | ? &#160; aP
|JT4 | $ | *, # | f, fN, dCN
|JT9 | @ | |
|JT65 | # | |
|JT65 VHF| # | *, # | f, fN, dCN
|QRA64 | : | * | R
|QRA64 | : | * | R:w
|ISCAT | | * | M N C T
|MSK144 | & | |
|===========================================

Binary file not shown.

Before

Width:  |  Height:  |  Size: 230 KiB

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 KiB

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -160,7 +160,7 @@ guidelines for contest logging with FT4, FT8, and MSK144:
[[COMP-CALL]]
=== Nonstandard Callsigns
*FT4, FT8, and MSK144*
*FT4, FT8, FST4, and MSK144*
Compound callsigns like xx/K1ABC or K1ABC/x and special event
callsigns like YW18FIFA are supported for normal QSOs but not for

View File

@ -31,4 +31,9 @@ synchronization symbols.
for making 2-way QSOs, and FST4W should replace WSPR for propagation
tests*. Operating conventions on these LF and MF bands will
eventually determine the most useful T/R sequence lengths for each
type of operation.
type of operation. We also expect that the 60 second variant of FST4
(FST4-60) will outperform JT9 for DX QSOs on HF bands due, in part,
to the FST4 decoder's ability to use AP decoding for messages received
from a QSO partner. In addition, FST4 provides the added benefits
associated with 77-bit messages and auto-sequencing.

View File

@ -18,6 +18,13 @@ image::colors.png[align="center",alt="Colors Screen"]
* Check *Highlight by Mode* if you wish worked before status to be per
<<INTRO,mode>>.
* Check *Only grid Fields sought* if you are only interested in the
leading two character grid locator Fields rather than teh four
character grid locator Squares.
* Check *Include extra WAE entities* if you are interested in the
extra entities defined for DARC WAE and CQ Marathon awards.
* Worked before status is calculated from your _WSJT-X_ ADIF
<<LOGGING, Logging>> file, you may replace ADIF log file with one
exported from your station logging application, *Rescan ADIF Log*

View File

@ -96,5 +96,6 @@ green to indicate that proper communication has been established.
Failure of the CAT-control test turns the button red and displays an
error message. After a successful CAT test, toggle the *Test PTT*
button to confirm that your selected method of T/R control is working
properly. (If you selected *VOX* for _PTT Method_, you can test T/R
properly, the button turns red if the rig has been successfully
keyed. (If you selected *VOX* for _PTT Method_, you can test T/R
switching later by using the *Tune* button on the main window.)

View File

@ -19,6 +19,10 @@ QRZ messages. Full details of the protocol can be found in comments
at the top of this file in our source code repository:
https://sourceforge.net/p/wsjt/wsjtx/ci/master/tree/Network/NetworkMessage.hpp
NOTE: The *Outgoing interfaces* and *Multicast TTL* fields are only
present when a multicast group IP address has been entered in
the *UDP Server* field.
Programs like _JTAlert_ use the _UDP Server_ feature to obtain
information about running _WSJT-X_ instances. If you are using
_JTAlert_ to control _WSJT-X_, be sure to check the

View File

@ -16,6 +16,5 @@ characters) in the entry field at top, then click *Add*.
- You can reorder your macro messages by using drag-and-drop. The
new order will be preserved when _WSJT-X_ is restarted.
- Messages can also be added from the main window's *Tx5* field on Tab
1 or the *Free msg* field on Tab 2. Simply hit [Enter] after the
message has been entered.
- Messages can also be added from the main window's *Tx5*
field. Simply hit [Enter] after the message has been entered.

View File

@ -1,5 +1,19 @@
Do not confuse FST4 with FT4, which has a very different purpose!
FST4 is is designed for making 2-way QSOs on the LF and MF bands.
FST4 is designed primarily for making weak-signal 2-way QSOs on the
LF and MF bands. T/R periods from 15 s up to 1800 s are
available. Longer T/R periods provide better sensitivity only if
Tx and Rx frequency instability and channel Doppler spread
are small enough so that received signals
remain phase coherent over periods spanning several transmitted symbols.
Generally speaking, Rx and Tx frequency changes
during the transmission and channel Doppler spread should each be small compared
to the symbol keying rate shown for each T/R duration in Table 7 within section
<<PROTOCOL_OVERVIEW,Protocol Specifications>>. For example, the keying rate for
the 1800 s T/R period is 0.089 Baud, so
successful operation using this T/R length requires Tx and Rx frequency
stability better than 0.089 Hz over the duration of the 1800 s transmission in
addition to channel Doppler spread smaller than 0.089 Hz.
Operation with FST4 is similar to that with other _WSJT-X_ modes: most
on-screen controls, auto-sequencing, and other features behave in
familiar ways. However, operating conventions on the 2200 and 630 m
@ -21,3 +35,26 @@ decoding process (and of course will be undecodable). By checking
further limit the decoding range to the setting of *F Tol* on
either side of *Rx Freq*.
A noise blanker can be enabled by setting the *NB* percentage to a non-zero value.
This setting determines how many of the largest-amplitude samples will be
blanked (zeroed) before the data is submitted to the decoder. Most users find
that settings between 0% (no blanking) and 10% work best. If the noise
blanker percentage is set to -1%, then the decoder will try 0, 5, 10, 15, and 20 %
in succession. Similarly, a setting of -2% causes the decoder to loop over
blanking percentages 0, 2, 4, ... 20 %. To save time, the multiple blanking
percentages triggered by negative *NB* settings are tried only for signal
candidates located near (within +/- 20 Hz) of the *Rx* frequency setting.
.Open a sample Wave File:
- Select *FST4* on the *Mode* menu. Set *T/R* to 60 s and *Decode | Deep*.
- Set *NB* (noise blanker) to 0%.
- Set up the Wide Graph display with settings appropriate for the FST4-60 mode.
For example, try *Bins/Pixel* 2 and *N Avg* 4. Set the *Start* frequency and the width of
the Wide Graph to include the frequency range that you want to decode. For this
example, make sure that *Start* is less than 1000 Hz and that the Wide Graph extends to above 1400 Hz.
- Set *F Low* 1000, *F High* 1400. These settings define the decoder's frequency search range.
- Open a sample Wave file using *File | Open* and select the file
...\save\samples\FST4+FST4W\210115_0058.wav. After _WSJT-X_ has processed the file you should see something similar to the following screen shot:
image::FST4-1.png[align="left"]

View File

@ -1,5 +1,5 @@
FST4W is used in the same way as WSPR, but FST4W has significant
advantages for use on the 2200 and 630 m bands. By default the
advantages for use on the 2200 m and 630 m bands. By default the
central *Rx Freq* is 1500 Hz and *F Tol* is 100 Hz, so the active
decoding range is 1400 to 1600 Hz. However, for added flexibility you
can select different center frequencies and *F Tol* values. We expect
@ -16,3 +16,19 @@ If three operators agree in advance to select the options *1/3*,
a fixed sequence with no two stations transmitting simultaneously.
Sequence 1 is the first sequence after 00:00 UTC. For WSPR-like
scheduling behavior, you should select *Random* with this control.
.Open a Wave File:
- Select *FST4W* on the *Mode* menu. Set *T/R* to 1800 s and *Decode | Deep*.
- Set *NB* to 0%.
- Select appropriate wide graph settings. For example, try *Bins/Pixel* 1,
*Start* 1200 Hz and *N Avg* 150.
- Open a sample Wave file using *File | Open* and select the file
...\save\samples\FST4+FST4W\201230_0300.wav.
When it is finished you should see a single decode as shown in the
screenshot:
image::FST4W-1.png[align="left"]
Note that the weak signal associated with the single decode is all but invisible on the
widegraph spectrogram.

View File

@ -13,9 +13,6 @@ and *Page Up/Down* key presses, with the *Page* keys moving the
controls in larger steps. You can also type numbers directly into
the spinner controls or use the mouse wheel.
- Select *Tab 2* (below the *Decode* button) to choose the alternative
set of controls for generating and selecting Tx messages.
[[DOWNLOAD_SAMPLES]]
=== Download Samples

View File

@ -381,7 +381,7 @@ decode*, *Decode after EME delay*
.Wide Graph:
- *Bins/Pixel* = 3, *N Avg* = 10
- *Bins/Pixel* = 4, *N Avg* = 10
- Adjust the width of the window so that the frequency range extends
up to at least 2400 Hz.

View File

@ -119,6 +119,15 @@ In macOS, enter the following command from a terminal:
open /Applications/wsjtx.app --args -stylesheet :/qdarkstyle/style.qss
In Linux using the Unity or GNOME GUI the following commands will
update the _WSJT-X_ start up:
....
sed '/Exec=wsjtx/ s/$/ -stylesheet :\/qdarkstyle\/style.qss/' \
/usr/share/applications/wsjtx.desktop >~/.local/share/applications/wsjtx.desktop
update-desktop-database ~/.local/share/applications/
....
Depending on your operating system, the main _WSJT-X_ window will look
something like this:
@ -193,7 +202,7 @@ include::wspr.adoc[]
include::controls-functions-menus.adoc[]
[[CONTROLS_MAIN]]
=== Button Row
=== Button Row
include::controls-functions-main-window.adoc[]
[[CONTROLS_LEFT]]

View File

@ -7,7 +7,7 @@ TargetFileName="${AppLocalDataLocation}/logs/wsjtx_syslog_%Y-%m.log"
RotationTimePoint="01 00:00:00"
Append=true
EnableFinalRotation=false
MaxSize=41943040
MaxSize=52428800
MinFreeSpace=1073741824
MaxFiles=12
Target="${AppLocalDataLocation}/logs"

View File

@ -614,7 +614,7 @@ contains
endif
call this%callback(nutc,smax1,nsnr,xdt,fsig,msg, &
iaptype,qual,ntrperiod,lwspr,fmid,w50)
if(iwspr.eq.0 .and. nb.lt.0) go to 900
! if(iwspr.eq.0 .and. nb.lt.0) go to 900
goto 800
endif
enddo ! metrics

View File

@ -65,7 +65,8 @@ program ft4code
if(i3.eq.2) msgtype="EU VHF Contest"
if(i3.eq.3) msgtype="ARRL RTTY Roundup"
if(i3.eq.4) msgtype="Nonstandard calls"
if(i3.ge.5) msgtype="Undefined msg type"
if(i3.eq.5) msgtype="EU VHF Contest"
if(i3.ge.6) msgtype="Undefined msg type"
if(i3.ge.1) n3=-1
bad=" "
comment=' '

View File

@ -64,7 +64,8 @@ program ft8code
if(i3.eq.2) msgtype="EU VHF Contest"
if(i3.eq.3) msgtype="ARRL RTTY Roundup"
if(i3.eq.4) msgtype="Nonstandard call"
if(i3.ge.5) msgtype="Undefined type"
if(i3.eq.5) msgtype="EU VHF Contest"
if(i3.ge.6) msgtype="Undefined type"
if(i3.ge.1) n3=-1
bad=" "
comment=' '

View File

@ -51,7 +51,8 @@ program msk144code
if(i3.eq.2) msgtype="EU VHF Contest"
if(i3.eq.3) msgtype="ARRL RTTY Roundup"
if(i3.eq.4) msgtype="Nonstandard calls"
if(i3.ge.5) msgtype="Undefined msg type"
if(i3.eq.5) msgtype="EU VHF Contest"
if(i3.ge.6) msgtype="Undefined msg type"
if(i3.ge.1) n3=-1
if(i4tone(41).lt.0) then
msgtype="Sh msg"

View File

@ -100,7 +100,7 @@ subroutine msk144decodeframe(c,softbits,msgreceived,nsuccess)
nsuccess=1
write(c77,'(77i1)') decoded77
read(c77(72:77),'(2b3)') n3,i3
if( (i3.eq.0.and.(n3.eq.1 .or. n3.eq.3 .or. n3.eq.4 .or. n3.gt.5)) .or. i3.eq.3 .or. i3.gt.4 ) then
if( (i3.eq.0.and.(n3.eq.1 .or. n3.eq.3 .or. n3.eq.4 .or. n3.gt.5)) .or. i3.eq.3 .or. i3.gt.5 ) then
nsuccess=0
else
call unpack77(c77,1,msgreceived,unpk77_success)

View File

@ -225,8 +225,7 @@ int main(int argc, char *argv[])
// disallow multiple instances with same instance key
QLockFile instance_lock {temp_dir.absoluteFilePath (a.applicationName () + ".lock")};
instance_lock.setStaleLockTime (0);
bool lock_ok {false};
while (!(lock_ok = instance_lock.tryLock ()))
while (!instance_lock.tryLock ())
{
if (QLockFile::LockFailedError == instance_lock.error ())
{
@ -249,6 +248,10 @@ int main(int argc, char *argv[])
throw std::runtime_error {"Multiple instances must have unique rig names"};
}
}
else
{
throw std::runtime_error {"Failed to access lock file"};
}
}
// load UI translations

View File

@ -1,6 +1,10 @@
set (SAMPLE_FILES
FT4/000000_000002.wav
FT8/181201_180245.wav
FST4+FST4W/210115_0058.wav
FST4+FST4W/201230_0300.wav
MSK144/181211_120500.wav
MSK144/181211_120800.wav
ISCAT/ISCAT-A/VK7MO_110401_235515.wav
ISCAT/ISCAT-B/K0AWU_100714_115000.wav
JT4/JT4A/DF2ZC_070926_040700.WAV
@ -17,6 +21,7 @@ set (SAMPLE_FILES
JT9/130418_1742.wav
MSK144/181211_120500.wav
MSK144/181211_120800.wav
QRA64/QRA64C/161113_0111.wav
WSPR/150426_0918.wav
Q65/30A_Ionoscatter_6m/201203_022700.wav
Q65/30A_Ionoscatter_6m/201203_022800.wav

Binary file not shown.

Binary file not shown.

View File

@ -64,7 +64,10 @@ void AbstractLogWindow::impl::delete_QSOs ()
, tr ("Confirm Delete")
, tr ("Are you sure you want to delete the %n "
"selected QSO(s) from the log?", ""
, row_indexes.size ())))
, row_indexes.size ())
, QString {}
, MessageBox::Yes | MessageBox::No
, MessageBox::No))
{
// We must work with source model indexes because we don't want row
// removes to invalidate model indexes we haven't yet processed. We

View File

@ -3633,7 +3633,7 @@ void MainWindow::auto_sequence (DecodedText const& message, unsigned start_toler
auto const& message_words = message.messageWords ();
auto is_73 = message_words.filter (QRegularExpression {"^(73|RR73)$"}).size();
bool is_OK=false;
if(m_mode=="MSK144" and message.string().indexOf(ui->dxCallEntry->text()+" R ")>0) is_OK=true;
if(m_mode=="MSK144" and message.clean_string ().indexOf(ui->dxCallEntry->text()+" R ")>0) is_OK=true;
if (message_words.size () > 2 && (message.isStandardMessage() || (is_73 or is_OK))) {
auto df = message.frequencyOffset ();
auto within_tolerance = (qAbs (ui->RxFreqSpinBox->value () - df) <= int (start_tolerance)
@ -3648,7 +3648,7 @@ void MainWindow::auto_sequence (DecodedText const& message, unsigned start_toler
|| message_words.contains ("DE")))
|| !message.isStandardMessage ()); // free text 73/RR73
QStringList w=message.string().mid(22).remove("<").remove(">").split(" ",SkipEmptyParts);
QStringList w=message.clean_string ().mid(22).remove("<").remove(">").split(" ",SkipEmptyParts);
QString w2;
int nrpt=0;
if (w.size () > 2)
@ -3660,8 +3660,8 @@ void MainWindow::auto_sequence (DecodedText const& message, unsigned start_toler
}
}
bool bEU_VHF=(nrpt>=520001 and nrpt<=594000);
if(bEU_VHF and message.string().contains("<"+m_config.my_callsign() + "> ")) {
m_xRcvd=message.string().trimmed().right(13);
if(bEU_VHF and message.clean_string ().contains("<"+m_config.my_callsign() + "> ")) {
m_xRcvd=message.clean_string ().trimmed().right(13);
}
if (m_auto
&& (m_QSOProgress==REPLYING or (!ui->tx1->isEnabled () and m_QSOProgress==REPORT))
@ -4180,7 +4180,7 @@ void MainWindow::guiUpdate()
statusUpdate ();
}
}
m_bCallingCQ = CALLING == m_QSOProgress
m_bCallingCQ = 6 == m_ntx
|| m_currentMessage.contains (QRegularExpression {"^(CQ|QRZ) "});
if(m_mode=="FT8" or m_mode=="FT4") {
if(m_bCallingCQ && ui->cbFirst->isVisible () && ui->cbFirst->isChecked ()) {
@ -4212,16 +4212,15 @@ void MainWindow::guiUpdate()
msg_parts[1].remove (QChar {'<'});
msg_parts[1].remove (QChar {'>'});
}
auto is_73 = m_QSOProgress >= ROGER_REPORT
&& message_is_73 (m_currentMessageType, msg_parts);
auto is_73 = message_is_73 (m_currentMessageType, msg_parts);
m_sentFirst73 = is_73
&& !message_is_73 (m_lastMessageType, m_lastMessageSent.split (' ', SkipEmptyParts));
if (m_sentFirst73) {
if (m_sentFirst73 || (is_73 && CALLING == m_QSOProgress)) {
m_qsoStop=t2;
if(m_config.id_after_73 ()) {
icw[0] = m_ncw;
}
if((m_config.prompt_to_log() or m_config.autoLog()) && !m_tune) logQSOTimer.start(0);
if((m_config.prompt_to_log() or m_config.autoLog()) && !m_tune && CALLING != m_QSOProgress) logQSOTimer.start(0);
}
bool b=(m_mode=="FT8" or m_mode=="FT4") and ui->cbAutoSeq->isChecked();
@ -4778,7 +4777,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
auto ctrl = modifiers.testFlag (Qt::ControlModifier);
// auto alt = modifiers.testFlag (Qt::AltModifier);
// basic mode sanity checks
auto const& parts = message.string ().split (' ', SkipEmptyParts);
auto const& parts = message.clean_string ().split (' ', SkipEmptyParts);
if (parts.size () < 5) return;
auto const& mode = parts.at (4).left (1);
if (("JT65" == m_mode && mode != "#")
@ -4827,16 +4826,16 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
QString hisgrid;
message.deCallAndGrid(/*out*/hiscall,hisgrid);
if(message.string().contains(hiscall+"/R")) {
if(message.clean_string ().contains(hiscall+"/R")) {
hiscall+="/R";
ui->dxCallEntry->setText(hiscall);
}
if(message.string().contains(hiscall+"/P")) {
if(message.clean_string ().contains(hiscall+"/P")) {
hiscall+="/P";
ui->dxCallEntry->setText(hiscall);
}
QStringList w=message.string().mid(22).remove("<").remove(">").split(" ",SkipEmptyParts);
QStringList w=message.clean_string ().mid(22).remove("<").remove(">").split(" ",SkipEmptyParts);
int nw=w.size();
if(nw>=4) {
if(message_words.size()<3) return;
@ -4848,9 +4847,9 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
}
bool is_73 = message_words.filter (QRegularExpression {"^(73|RR73)$"}).size ();
if (!is_73 and !message.isStandardMessage() and !message.string().contains("<")) {
if (!is_73 and !message.isStandardMessage() and !message.clean_string ().contains("<")) {
qDebug () << "Not processing message - hiscall:" << hiscall << "hisgrid:" << hisgrid
<< message.string() << message.isStandardMessage();
<< message.clean_string () << message.isStandardMessage();
return;
}
@ -4892,7 +4891,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
auto base_call = Radio::base_callsign (hiscall);
// Determine appropriate response to received message
auto dtext = " " + message.string () + " ";
auto dtext = " " + message.clean_string () + " ";
dtext=dtext.remove("<").remove(">");
if(dtext.contains (" " + m_baseCall + " ")
|| dtext.contains ("<" + m_baseCall + "> ")
@ -4920,7 +4919,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
MessageBox::information_message (this, msg);
}
QStringList t=message.string().split(' ', SkipEmptyParts);
QStringList t=message.clean_string ().split(' ', SkipEmptyParts);
int n=t.size();
QString t0=t.at(n-2);
QString t1=t0.right(1);
@ -4996,11 +4995,11 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
}
} else { // no grid on end of msg
auto const& word_3 = message_words.at (3);
bool word_3_is_int;
auto word_3_as_number = word_3.toInt (&word_3_is_int);
if(m_QSOProgress >= ROGER_REPORT && ("RRR" == word_3
|| (word_3_is_int && word_3_as_number == 73)
|| "RR73" == word_3)) {
auto word_3_as_number = word_3.toInt ();
if (("RRR" == word_3
|| word_3_as_number == 73
|| "RR73" == word_3
|| ("R" == word_3 && m_QSOProgress != REPORT))) {
if(m_mode=="FT4" and "RR73" == word_3) m_dateTimeRcvdRR73=QDateTime::currentDateTimeUtc();
m_bTUmsg=false;
m_nextCall=""; //### Temporary: disable use of "TU;" message
@ -5013,16 +5012,30 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
ui->tx3->setText(t);
m_bTUmsg=true;
} else {
if(SpecOp::RTTY == m_config.special_op_id()) {
logQSOTimer.start(0);
m_ntx=6;
ui->txrb6->setChecked(true);
} else {
m_ntx=5;
ui->txrb5->setChecked(true);
}
if (m_QSOProgress > CALLING && m_QSOProgress < SIGNOFF
&& SpecOp::NONE < m_config.special_op_id () && SpecOp::FOX > m_config.special_op_id ()
&& ("RR73" == word_3 || 73 == word_3_as_number))
{
logQSOTimer.start(0);
m_ntx=6;
ui->txrb6->setChecked(true);
}
else if (word_3.contains (QRegularExpression {"^R(?!R73|RR)"})
&& m_QSOProgress != ROGER_REPORT)
{
m_ntx=4;
ui->txrb4->setChecked(true);
}
else
{
m_ntx=5;
ui->txrb5->setChecked(true);
}
}
m_QSOProgress = SIGNOFF;
if (m_QSOProgress >= ROGER_REPORT)
{
m_QSOProgress = SIGNOFF;
}
} else if((m_QSOProgress >= REPORT
|| (m_QSOProgress >= REPLYING &&
(m_mode=="MSK144" or m_mode=="FT8" or m_mode=="FT4")))
@ -5037,30 +5050,35 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
ui->txrb4->setChecked(true);
} else if (m_QSOProgress >= CALLING)
{
if (word_3_is_int
&& ((word_3_as_number >= -50 && word_3_as_number <= 49)
|| (word_3_as_number >= 529 && word_3_as_number <= 599))) {
if(SpecOp::EU_VHF==m_config.special_op_id() or
SpecOp::FIELD_DAY==m_config.special_op_id() or
SpecOp::RTTY==m_config.special_op_id()) {
setTxMsg(2);
m_QSOProgress=REPORT;
if ((word_3_as_number >= -50 && word_3_as_number <= 49)
|| (word_3_as_number >= 529 && word_3_as_number <= 599))
{
if(SpecOp::EU_VHF==m_config.special_op_id() or
SpecOp::FIELD_DAY==m_config.special_op_id() or
SpecOp::RTTY==m_config.special_op_id())
{
setTxMsg(2);
m_QSOProgress=REPORT;
}
else
{
if (word_3.startsWith ("R-") || word_3.startsWith ("R+"))
{
setTxMsg(4);
m_QSOProgress=ROGERS;
}
else
{
setTxMsg (3);
m_QSOProgress = ROGER_REPORT;
}
}
}
else {
setTxMsg (3);
m_QSOProgress = ROGER_REPORT;
}
} else {
if (word_3.startsWith ("R-") || word_3.startsWith ("R+")) {
setTxMsg(4);
m_QSOProgress=ROGERS;
}
}
}
else
{ // nothing for us
return;
}
else
{ // nothing for us
return;
}
}
}
else if (m_QSOProgress >= ROGERS
@ -5138,7 +5156,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
}
QString s1 = m_QSOText.trimmed ();
QString s2 = message.string ().trimmed();
QString s2 = message.clean_string ().trimmed();
if (s1!=s2 and !message.isTX()) {
if (!s2.contains(m_baseCall) or m_mode=="MSK144") { // Taken care of elsewhere if for_us and slow mode
ui->decodedTextBrowser2->displayDecodedText(message, m_baseCall,m_mode,m_config.DXCC(),
@ -5711,7 +5729,7 @@ void MainWindow::msgtype(QString t, QLineEdit* tx) //msgtype()
p.setColor(QPalette::Base,"#66ffff"); //light blue
} else {
p.setColor(QPalette::Base,Qt::transparent);
if(m_mode=="MSK144" and t.mid(0,1)=="<") {
if ("MSK144" == m_mode && t.count ('<') == 1) {
p.setColor(QPalette::Base,"#00ffff"); //another light blue
}
}
@ -6488,6 +6506,7 @@ void MainWindow::on_actionMSK144_triggered()
} else {
ui->labDXped->setVisible(true);
ui->labDXped->setText(t0);
on_contest_log_action_triggered();
}
}