From 58fab3474d7c3c2c19d1c376b4697666404fee90 Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Sun, 15 Nov 2015 23:03:11 +0000 Subject: [PATCH] Add WSPR decodes to UDP message protocol The message_aggregator (MessageAggregator.cpp) has been updated to do something with WSPR decodes. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@6101 ab8295b8-cf94-4d9e-aec4-7959e3be5d79 --- MessageAggregator.cpp | 224 +++++++++++++++++++++++++++++++++++++----- MessageClient.cpp | 24 ++++- MessageClient.hpp | 6 +- MessageServer.cpp | 21 ++++ MessageServer.hpp | 2 + NetworkMessage.hpp | 23 ++++- mainwindow.cpp | 51 ++++++++-- mainwindow.h | 1 + 8 files changed, 313 insertions(+), 39 deletions(-) diff --git a/MessageAggregator.cpp b/MessageAggregator.cpp index 6313afcb1..85ca48ba0 100644 --- a/MessageAggregator.cpp +++ b/MessageAggregator.cpp @@ -184,17 +184,148 @@ private: QFont text_font_; }; +// +// Beacons Model - simple data model for all beacon spots +// +// The model is a basic table with uniform row format. Rows consist of +// QStandardItem instances containing the string representation of the +// column data and if the underlying field is not a string then the +// UserRole+1 role contains the underlying data item. +// +// Two slots are provided to add a new decode and remove all spots for +// a client. +// +class BeaconsModel + : public QStandardItemModel +{ + Q_OBJECT; + +public: + BeaconsModel (QObject * parent = nullptr) + : QStandardItemModel {0, 9, parent} + , text_font_ {"Courier", 10} + { + setHeaderData (0, Qt::Horizontal, tr ("Client")); + setHeaderData (1, Qt::Horizontal, tr ("Time")); + setHeaderData (2, Qt::Horizontal, tr ("Snr")); + setHeaderData (3, Qt::Horizontal, tr ("DT")); + setHeaderData (4, Qt::Horizontal, tr ("Frequency")); + setHeaderData (5, Qt::Horizontal, tr ("Drift")); + setHeaderData (6, Qt::Horizontal, tr ("Callsign")); + setHeaderData (7, Qt::Horizontal, tr ("Grid")); + setHeaderData (8, Qt::Horizontal, tr ("Power")); + } + + Q_SLOT void add_beacon_spot (bool is_new, QString const& client_id, QTime time, qint32 snr, float delta_time + , Frequency frequency, qint32 drift, QString const& callsign, QString const& grid + , qint32 power) + { + if (!is_new) + { + int target_row {-1}; + for (auto row = 0; row < rowCount (); ++row) + { + if (data (index (row, 0)).toString () == client_id) + { + auto row_time = item (row, 1)->data ().toTime (); + if (row_time == time + && item (row, 2)->data ().toInt () == snr + && item (row, 3)->data ().toFloat () == delta_time + && item (row, 4)->data ().value () == frequency + && data (index (row, 5)).toInt () == drift + && data (index (row, 6)).toString () == callsign + && data (index (row, 7)).toString () == grid + && data (index (row, 8)).toInt () == power) + { + return; + } + if (time <= row_time) + { + target_row = row; // last row with same time + } + } + } + if (target_row >= 0) + { + insertRow (target_row + 1, make_row (client_id, time, snr, delta_time, frequency, drift, callsign, grid, power)); + return; + } + } + + appendRow (make_row (client_id, time, snr, delta_time, frequency, drift, callsign, grid, power)); + } + + QList make_row (QString const& client_id, QTime time, qint32 snr, float delta_time + , Frequency frequency, qint32 drift, QString const& callsign + , QString const& grid, qint32 power) const + { + auto time_item = new QStandardItem {time.toString ("hh:mm")}; + time_item->setData (time); + time_item->setTextAlignment (Qt::AlignRight); + + auto snr_item = new QStandardItem {QString::number (snr)}; + snr_item->setData (snr); + snr_item->setTextAlignment (Qt::AlignRight); + + auto dt = new QStandardItem {QString::number (delta_time)}; + dt->setData (delta_time); + dt->setTextAlignment (Qt::AlignRight); + + auto freq = new QStandardItem {Radio::pretty_frequency_MHz_string (frequency)}; + freq->setData (frequency); + freq->setTextAlignment (Qt::AlignRight); + + auto dri = new QStandardItem {QString::number (drift)}; + dri->setData (drift); + dri->setTextAlignment (Qt::AlignRight); + + auto gd = new QStandardItem {grid}; + gd->setTextAlignment (Qt::AlignRight); + + auto pwr = new QStandardItem {QString::number (power)}; + pwr->setData (power); + pwr->setTextAlignment (Qt::AlignRight); + + QList row { + new QStandardItem {client_id}, time_item, snr_item, dt, freq, dri, new QStandardItem {callsign}, gd, pwr}; + Q_FOREACH (auto& item, row) + { + item->setEditable (false); + item->setFont (text_font_); + item->setTextAlignment (item->textAlignment () | Qt::AlignVCenter); + } + return row; + } + + Q_SLOT void clear_decodes (QString const& client_id) + { + for (auto row = rowCount () - 1; row >= 0; --row) + { + if (data (index (row, 0)).toString () == client_id) + { + removeRow (row); + } + } + } + +private: + QFont text_font_; +}; + class ClientWidget : public QDockWidget { Q_OBJECT; public: - explicit ClientWidget (QAbstractItemModel * decodes_model, QString const& id, QWidget * parent = 0) + explicit ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemModel * beacons_model + , QString const& id, QWidget * parent = 0) : QDockWidget {id, parent} , id_ {id} , decodes_table_view_ {new QTableView} + , beacons_table_view_ {new QTableView} , message_line_edit_ {new QLineEdit} + , decodes_stack_ {new QStackedLayout} , auto_off_button_ {new QPushButton {tr ("&Auto Off")}} , halt_tx_button_ {new QPushButton {tr ("&Halt Tx")}} , mode_label_ {new QLabel} @@ -202,19 +333,14 @@ public: , frequency_label_ {new QLabel} , report_label_ {new QLabel} { - auto content_layout = new QVBoxLayout; - content_layout->setContentsMargins (QMargins {2, 2, 2, 2}); - - // set up table - auto proxy_model = new DecodesFilterModel {id, this}; - proxy_model->setSourceModel (decodes_model); - decodes_table_view_->setModel (proxy_model); + // set up widgets + auto decodes_proxy_model = new IdFilterModel {id, this}; + decodes_proxy_model->setSourceModel (decodes_model); + decodes_table_view_->setModel (decodes_proxy_model); decodes_table_view_->verticalHeader ()->hide (); decodes_table_view_->hideColumn (0); - content_layout->addWidget (decodes_table_view_); + decodes_table_view_->horizontalHeader ()->setStretchLastSection (true); - // set up controls - auto control_layout = new QHBoxLayout; auto form_layout = new QFormLayout; form_layout->addRow (tr ("Free text:"), message_line_edit_); message_line_edit_->setValidator (new QRegExpValidator {message_alphabet, this}); @@ -224,16 +350,44 @@ public: connect (message_line_edit_, &QLineEdit::editingFinished, [this] () { Q_EMIT do_free_text (id_, message_line_edit_->text (), true); }); - control_layout->addLayout (form_layout); - control_layout->addWidget (auto_off_button_); - control_layout->addWidget (halt_tx_button_); + + auto decodes_page = new QWidget; + auto decodes_layout = new QVBoxLayout {decodes_page}; + decodes_layout->setContentsMargins (QMargins {2, 2, 2, 2}); + decodes_layout->addWidget (decodes_table_view_); + decodes_layout->addLayout (form_layout); + + auto beacons_proxy_model = new IdFilterModel {id, this}; + beacons_proxy_model->setSourceModel (beacons_model); + beacons_table_view_->setModel (beacons_proxy_model); + beacons_table_view_->verticalHeader ()->hide (); + beacons_table_view_->hideColumn (0); + beacons_table_view_->horizontalHeader ()->setStretchLastSection (true); + + auto beacons_page = new QWidget; + auto beacons_layout = new QVBoxLayout {beacons_page}; + beacons_layout->setContentsMargins (QMargins {2, 2, 2, 2}); + beacons_layout->addWidget (beacons_table_view_); + + decodes_stack_->addWidget (decodes_page); + decodes_stack_->addWidget (beacons_page); + + // stack alternative views + auto content_layout = new QVBoxLayout; + content_layout->setContentsMargins (QMargins {2, 2, 2, 2}); + content_layout->addLayout (decodes_stack_); + + // set up controls + auto control_button_box = new QDialogButtonBox; + control_button_box->addButton (auto_off_button_, QDialogButtonBox::ActionRole); + control_button_box->addButton (halt_tx_button_, QDialogButtonBox::ActionRole); connect (auto_off_button_, &QAbstractButton::clicked, [this] (bool /* checked */) { Q_EMIT do_halt_tx (id_, true); }); connect (halt_tx_button_, &QAbstractButton::clicked, [this] (bool /* checked */) { Q_EMIT do_halt_tx (id_, false); }); - content_layout->addLayout (control_layout); + content_layout->addWidget (control_button_box); // set up status area auto status_bar = new QStatusBar; @@ -254,8 +408,8 @@ public: setAllowedAreas (Qt::BottomDockWidgetArea); // connect up table view signals - connect (decodes_table_view_, &QTableView::doubleClicked, this, [this, proxy_model] (QModelIndex const& index) { - Q_EMIT do_reply (proxy_model->mapToSource (index)); + connect (decodes_table_view_, &QTableView::doubleClicked, this, [this, decodes_proxy_model] (QModelIndex const& index) { + Q_EMIT do_reply (decodes_proxy_model->mapToSource (index)); }); } @@ -265,7 +419,9 @@ public: { if (id == id_) { - mode_label_->setText (QString {"Mode: %1%2"}.arg (mode).arg (tx_mode.isEmpty () ? tx_mode : '(' + tx_mode + ')')); + mode_label_->setText (QString {"Mode: %1%2"} + .arg (mode) + .arg (tx_mode.isEmpty () || tx_mode == mode ? "" : '(' + tx_mode + ')')); dx_call_label_->setText ("DX CALL: " + dx_call); frequency_label_->setText ("QRG: " + Radio::pretty_frequency_MHz_string (f)); report_label_->setText ("SNR: " + report); @@ -277,27 +433,39 @@ public: } Q_SLOT void decode_added (bool /*is_new*/, QString const& client_id, QTime /*time*/, qint32 /*snr*/ - , float /*delta_time*/, quint32 /*delta_frequency*/, QString const& /*mode*/ - , QString const& /*message*/) + , float /*delta_time*/, quint32 /*delta_frequency*/, QString const& /*mode*/ + , QString const& /*message*/) { if (client_id == id_) { + decodes_stack_->setCurrentIndex (0); decodes_table_view_->resizeColumnsToContents (); - decodes_table_view_->horizontalHeader ()->setStretchLastSection (true); decodes_table_view_->scrollToBottom (); } } + Q_SLOT void beacon_spot_added (bool /*is_new*/, QString const& client_id, QTime /*time*/, qint32 /*snr*/ + , float /*delta_time*/, Frequency /*delta_frequency*/, qint32 /*drift*/, QString const& /*callsign*/ + , QString const& /*grid*/, qint32 /*power*/) + { + if (client_id == id_) + { + decodes_stack_->setCurrentIndex (1); + beacons_table_view_->resizeColumnsToContents (); + beacons_table_view_->scrollToBottom (); + } + } + Q_SIGNAL void do_reply (QModelIndex const&); Q_SIGNAL void do_halt_tx (QString const& id, bool auto_only); Q_SIGNAL void do_free_text (QString const& id, QString const& text, bool); private: - class DecodesFilterModel final + class IdFilterModel final : public QSortFilterProxyModel { public: - DecodesFilterModel (QString const& id, QObject * parent = nullptr) + IdFilterModel (QString const& id, QObject * parent = nullptr) : QSortFilterProxyModel {parent} , id_ {id} {} @@ -315,7 +483,9 @@ private: QString id_; QTableView * decodes_table_view_; + QTableView * beacons_table_view_; QLineEdit * message_line_edit_; + QStackedLayout * decodes_stack_; QAbstractButton * auto_off_button_; QAbstractButton * halt_tx_button_; QLabel * mode_label_; @@ -333,6 +503,7 @@ public: MainWindow () : log_ {new QStandardItemModel {0, 10, this}} , decodes_model_ {new DecodesModel {this}} + , beacons_model_ {new BeaconsModel {this}} , server_ {new MessageServer {this}} , multicast_group_line_edit_ {new QLineEdit} , log_table_view_ {new QTableView} @@ -395,8 +566,11 @@ public: connect (server_, &MessageServer::client_opened, this, &MainWindow::add_client); connect (server_, &MessageServer::client_closed, this, &MainWindow::remove_client); connect (server_, &MessageServer::client_closed, decodes_model_, &DecodesModel::clear_decodes); + connect (server_, &MessageServer::client_closed, beacons_model_, &BeaconsModel::clear_decodes); connect (server_, &MessageServer::decode, decodes_model_, &DecodesModel::add_decode); + connect (server_, &MessageServer::WSPR_decode, beacons_model_, &BeaconsModel::add_beacon_spot); connect (server_, &MessageServer::clear_decodes, decodes_model_, &DecodesModel::clear_decodes); + connect (server_, &MessageServer::clear_decodes, beacons_model_, &BeaconsModel::clear_decodes); connect (decodes_model_, &DecodesModel::reply, server_, &MessageServer::reply); // UI behaviour @@ -435,7 +609,7 @@ public: private: void add_client (QString const& id) { - auto dock = new ClientWidget {decodes_model_, id, this}; + auto dock = new ClientWidget {decodes_model_, beacons_model_, id, this}; dock->setAttribute (Qt::WA_DeleteOnClose); auto view_action = dock->toggleViewAction (); view_action->setEnabled (true); @@ -443,6 +617,7 @@ private: addDockWidget (Qt::BottomDockWidgetArea, dock); connect (server_, &MessageServer::status_update, dock, &ClientWidget::update_status); connect (server_, &MessageServer::decode, dock, &ClientWidget::decode_added); + connect (server_, &MessageServer::WSPR_decode, dock, &ClientWidget::beacon_spot_added); connect (dock, &ClientWidget::do_reply, decodes_model_, &DecodesModel::do_reply); connect (dock, &ClientWidget::do_halt_tx, server_, &MessageServer::halt_tx); connect (dock, &ClientWidget::do_free_text, server_, &MessageServer::free_text); @@ -464,6 +639,7 @@ private: QStandardItemModel * log_; QMenu * view_menu_; DecodesModel * decodes_model_; + BeaconsModel * beacons_model_; MessageServer * server_; QLineEdit * multicast_group_line_edit_; QTableView * log_table_view_; diff --git a/MessageClient.cpp b/MessageClient.cpp index f29856a4f..a84c721ef 100644 --- a/MessageClient.cpp +++ b/MessageClient.cpp @@ -272,9 +272,16 @@ MessageClient::MessageClient (QString const& id, QString const& server, port_typ , m_ {id, server_port, this} { connect (&*m_, static_cast (&impl::error) - , [this] (impl::SocketError /* e */) + , [this] (impl::SocketError e) { - Q_EMIT error (m_->errorString ()); +#if defined (Q_OS_WIN) && QT_VERSION >= 0x050500 + if (e != impl::NetworkError) // take this out when Qt 5.5 + // stops doing this + // spuriously +#endif + { + Q_EMIT error (m_->errorString ()); + } }); set_server (server); } @@ -340,6 +347,19 @@ void MessageClient::decode (bool is_new, QTime time, qint32 snr, float delta_tim } } +void MessageClient::WSPR_decode (bool is_new, QTime time, qint32 snr, float delta_time, Frequency frequency + , qint32 drift, QString const& callsign, QString const& grid, qint32 power) +{ + if (m_->server_port_ && !m_->server_string_.isEmpty ()) + { + QByteArray message; + NetworkMessage::Builder out {&message, NetworkMessage::WSPRDecode, m_->id_, m_->schema_}; + out << is_new << time << snr << delta_time << frequency << drift << callsign.toUtf8 () + << grid.toUtf8 () << power; + m_->send_message (out, message); + } +} + void MessageClient::clear_decodes () { if (m_->server_port_ && !m_->server_string_.isEmpty ()) diff --git a/MessageClient.hpp b/MessageClient.hpp index f35b57d0e..75efa9cbf 100644 --- a/MessageClient.hpp +++ b/MessageClient.hpp @@ -14,8 +14,8 @@ class QHostAddress; // // MessageClient - Manage messages sent and replies received from a -// matching server (MessageServer) at the other end of -// the wire +// matching server (MessageServer) at the other end of +// the wire // // // Each outgoing message type is a Qt slot @@ -50,6 +50,8 @@ public: , QString const& tx_mode, bool tx_enabled, bool transmitting, bool decoding); Q_SLOT void decode (bool is_new, QTime time, qint32 snr, float delta_time, quint32 delta_frequency , QString const& mode, QString const& message); + Q_SLOT void WSPR_decode (bool is_new, QTime time, qint32 snr, float delta_time, Frequency + , qint32 drift, QString const& callsign, QString const& grid, qint32 power); Q_SLOT void clear_decodes (); Q_SLOT void qso_logged (QDateTime time, QString const& dx_call, QString const& dx_grid , Frequency dial_frequency, QString const& mode, QString const& report_sent diff --git a/MessageServer.cpp b/MessageServer.cpp index 4feb0cc4f..b6f59bb87 100644 --- a/MessageServer.cpp +++ b/MessageServer.cpp @@ -223,6 +223,27 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s } break; + case NetworkMessage::WSPRDecode: + { + // unpack message + bool is_new {true}; + QTime time; + qint32 snr; + float delta_time; + Frequency frequency; + qint32 drift; + QByteArray callsign; + QByteArray grid; + qint32 power; + in >> is_new >> time >> snr >> delta_time >> frequency >> drift >> callsign >> grid >> power; + if (check_status (in) != Fail) + { + Q_EMIT self_->WSPR_decode (is_new, id, time, snr, delta_time, frequency, drift + , QString::fromUtf8 (callsign), QString::fromUtf8 (grid), power); + } + } + break; + case NetworkMessage::QSOLogged: { QDateTime time; diff --git a/MessageServer.hpp b/MessageServer.hpp index da6a81683..846df5005 100644 --- a/MessageServer.hpp +++ b/MessageServer.hpp @@ -65,6 +65,8 @@ public: Q_SIGNAL void client_closed (QString const& id); Q_SIGNAL void decode (bool is_new, QString const& id, QTime time, qint32 snr, float delta_time , quint32 delta_frequency, QString const& mode, QString const& message); + Q_SIGNAL void WSPR_decode (bool is_new, QString const& id, QTime time, qint32 snr, float delta_time, Frequency + , qint32 drift, QString const& callsign, QString const& grid, qint32 power); Q_SIGNAL void qso_logged (QString const& id, QDateTime time, QString const& dx_call, QString const& dx_grid , Frequency dial_frequency, QString const& mode, QString const& report_sent , QString const& report_received, QString const& tx_power, QString const& comments diff --git a/NetworkMessage.hpp b/NetworkMessage.hpp index a96357166..c638dadfc 100644 --- a/NetworkMessage.hpp +++ b/NetworkMessage.hpp @@ -137,7 +137,7 @@ * Mode utf8 * Message utf8 * - * The decode message is send when a new decode is completed, in + * The decode message is sent when a new decode is completed, in * this case the 'New' field is true. It is also used in response * to a "Replay" message where each old decode in the "Band * activity" window, that has not been erased, is sent in order @@ -260,6 +260,26 @@ * command to determine the contents of the current free text * message. * + * WSPRDecode Out 10 quint32 + * Id (unique key) utf8 + * New bool + * Time QTime + * snr qint32 + * Delta time (S) float (serialized as double) + * Frequency (Hz) quint64 + * Drift (Hz) qint32 + * Callsign utf8 + * Grid utf8 + * Power (dBm) qint32 + * + * The decode message is sent when a new decode is completed, in + * this case the 'New' field is true. It is also used in response + * to a "Replay" message where each old decode in the "Band + * activity" window, that has not been erased, is sent in order + * as a one of these messages with the 'New' field set to + * false. See the "Replay" message below for details of usage. + * + * */ #include @@ -285,6 +305,7 @@ namespace NetworkMessage Replay, HaltTx, FreeText, + WSPRDecode, maximum_message_type_ // ONLY add new message types // immediately before here }; diff --git a/mainwindow.cpp b/mainwindow.cpp index db34af0f3..939437d85 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -870,6 +870,10 @@ void MainWindow::dataSink(qint64 frames) cmnd=t3.mid(0,i1+7) + t3.mid(i1+7); ui->DecodeButton->setChecked (true); p1.start(QDir::toNativeSeparators(cmnd)); + m_messageClient->status_update (m_dialFreq, m_mode, m_hisCall, + QString::number (ui->rptSpinBox->value ()), + m_modeTx, ui->autoButton->isChecked (), + m_transmitting, (m_decoderBusy = true)); } m_rxDone=true; } @@ -1012,7 +1016,7 @@ void MainWindow::keyPressEvent( QKeyEvent *e ) //keyPressEvent switch(e->key()) { case Qt::Key_D: - if(e->modifiers() & Qt::ShiftModifier) { + if(m_mode != "WSPR-2" && e->modifiers() & Qt::ShiftModifier) { if(!m_decoderBusy) { jt9com_.newdat=0; jt9com_.nagain=0; @@ -1463,7 +1467,7 @@ void MainWindow::on_actionSpecial_mouse_commands_triggered() void MainWindow::on_DecodeButton_clicked (bool /* checked */) //Decode request { - if(!m_decoderBusy) { + if(m_mode != "WSPR-2" && !m_decoderBusy) { jt9com_.newdat=0; jt9com_.nagain=1; m_blankLine=false; // don't insert the separator again @@ -3925,17 +3929,27 @@ void MainWindow::replayDecodes () { // we accept this request even if the setting to accept UDP requests // is not checked + + // attempt to parse the decoded text Q_FOREACH (auto const& message, ui->decodedTextBrowser->toPlainText ().split ('\n', QString::SkipEmptyParts)) { if (message.size() >= 4 && message.left (4) != "----") { - auto eom_pos = message.indexOf (' ', 35); - // we always want at least the characters to position 35 - if (eom_pos < 35) + auto const& parts = message.split (' ', QString::SkipEmptyParts); + if (parts.size () >= 5 && parts[3].contains ('.')) // WSPR { - eom_pos = message.size () - 1; + postWSPRDecode (false, parts); + } + else + { + auto eom_pos = message.indexOf (' ', 35); + // we always want at least the characters to position 35 + if (eom_pos < 35) + { + eom_pos = message.size () - 1; + } + postDecode (false, message.left (eom_pos + 1)); } - postDecode (false, message.left (eom_pos + 1)); } } statusChanged (); @@ -3943,8 +3957,8 @@ void MainWindow::replayDecodes () void MainWindow::postDecode (bool is_new, QString const& message) { - auto decode = message.trimmed (); - auto parts = decode.left (21).split (' ', QString::SkipEmptyParts); + auto const& decode = message.trimmed (); + auto const& parts = decode.left (21).split (' ', QString::SkipEmptyParts); if (parts.size () >= 5) { m_messageClient->decode (is_new, QTime::fromString (parts[0], "hhmm"), parts[1].toInt () @@ -3952,6 +3966,18 @@ void MainWindow::postDecode (bool is_new, QString const& message) } } +void MainWindow::postWSPRDecode (bool is_new, QStringList parts) +{ + if (parts.size () < 8) + { + parts.insert (6, ""); + } + m_messageClient->WSPR_decode (is_new, QTime::fromString (parts[0], "hhmm"), parts[1].toInt () + , parts[2].toFloat (), Radio::frequency (parts[3].toFloat (), 6) + , parts[4].toInt (), parts[5].remove ("<").remove (">") + , parts[6], parts[7].toInt ()); +} + void MainWindow::networkError (QString const& e) { if (QMessageBox::Retry == QMessageBox::warning (this, tr ("Network Error") @@ -4016,7 +4042,10 @@ void MainWindow::p1ReadFromStdout() //p1readFromStdout m_RxLog=0; m_startAnother=m_loopall; m_blankLine=true; - return; + m_messageClient->status_update (m_dialFreq, m_mode, m_hisCall, + QString::number (ui->rptSpinBox->value ()), + m_modeTx, ui->autoButton->isChecked (), + m_transmitting, (m_decoderBusy = false)); } else { int n=t.length(); @@ -4035,6 +4064,7 @@ void MainWindow::p1ReadFromStdout() //p1readFromStdout .arg(rxFields.at(5).leftJustified (12).replace ('<', "<").replace ('>', ">")) .arg(rxFields.at(6), -6) .arg(rxFields.at(7), 3); + postWSPRDecode (true, rxFields); grid = rxFields.at(6); } else if ( rxFields.count() == 7 ) { // Type 2 message rxLine = QString("%1 %2 %3 %4 %5 %6 %7 %8") @@ -4046,6 +4076,7 @@ void MainWindow::p1ReadFromStdout() //p1readFromStdout .arg(rxFields.at(5).leftJustified (12).replace ('<', "<").replace ('>', ">")) .arg("", -6) .arg(rxFields.at(6), 3); + postWSPRDecode (true, rxFields); } else { rxLine = t; } diff --git a/mainwindow.h b/mainwindow.h index 9fd107f12..4bba8819f 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -501,6 +501,7 @@ private: void replyToCQ (QTime, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode, QString const& message_text); void replayDecodes (); void postDecode (bool is_new, QString const& message); + void postWSPRDecode (bool is_new, QStringList message_parts); void enable_DXCC_entity (bool on); void switch_mode (Mode); void WSPR_scheduling ();