mirror of https://github.com/saitohirga/WSJT-X.git
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
This commit is contained in:
parent
63de88d66f
commit
58fab3474d
|
@ -184,17 +184,148 @@ private:
|
||||||
QFont text_font_;
|
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> () == 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<QStandardItem *> 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<QStandardItem *> 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
|
class ClientWidget
|
||||||
: public QDockWidget
|
: public QDockWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT;
|
Q_OBJECT;
|
||||||
|
|
||||||
public:
|
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}
|
: QDockWidget {id, parent}
|
||||||
, id_ {id}
|
, id_ {id}
|
||||||
, decodes_table_view_ {new QTableView}
|
, decodes_table_view_ {new QTableView}
|
||||||
|
, beacons_table_view_ {new QTableView}
|
||||||
, message_line_edit_ {new QLineEdit}
|
, message_line_edit_ {new QLineEdit}
|
||||||
|
, decodes_stack_ {new QStackedLayout}
|
||||||
, auto_off_button_ {new QPushButton {tr ("&Auto Off")}}
|
, auto_off_button_ {new QPushButton {tr ("&Auto Off")}}
|
||||||
, halt_tx_button_ {new QPushButton {tr ("&Halt Tx")}}
|
, halt_tx_button_ {new QPushButton {tr ("&Halt Tx")}}
|
||||||
, mode_label_ {new QLabel}
|
, mode_label_ {new QLabel}
|
||||||
|
@ -202,19 +333,14 @@ public:
|
||||||
, frequency_label_ {new QLabel}
|
, frequency_label_ {new QLabel}
|
||||||
, report_label_ {new QLabel}
|
, report_label_ {new QLabel}
|
||||||
{
|
{
|
||||||
auto content_layout = new QVBoxLayout;
|
// set up widgets
|
||||||
content_layout->setContentsMargins (QMargins {2, 2, 2, 2});
|
auto decodes_proxy_model = new IdFilterModel {id, this};
|
||||||
|
decodes_proxy_model->setSourceModel (decodes_model);
|
||||||
// set up table
|
decodes_table_view_->setModel (decodes_proxy_model);
|
||||||
auto proxy_model = new DecodesFilterModel {id, this};
|
|
||||||
proxy_model->setSourceModel (decodes_model);
|
|
||||||
decodes_table_view_->setModel (proxy_model);
|
|
||||||
decodes_table_view_->verticalHeader ()->hide ();
|
decodes_table_view_->verticalHeader ()->hide ();
|
||||||
decodes_table_view_->hideColumn (0);
|
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;
|
auto form_layout = new QFormLayout;
|
||||||
form_layout->addRow (tr ("Free text:"), message_line_edit_);
|
form_layout->addRow (tr ("Free text:"), message_line_edit_);
|
||||||
message_line_edit_->setValidator (new QRegExpValidator {message_alphabet, this});
|
message_line_edit_->setValidator (new QRegExpValidator {message_alphabet, this});
|
||||||
|
@ -224,16 +350,44 @@ public:
|
||||||
connect (message_line_edit_, &QLineEdit::editingFinished, [this] () {
|
connect (message_line_edit_, &QLineEdit::editingFinished, [this] () {
|
||||||
Q_EMIT do_free_text (id_, message_line_edit_->text (), true);
|
Q_EMIT do_free_text (id_, message_line_edit_->text (), true);
|
||||||
});
|
});
|
||||||
control_layout->addLayout (form_layout);
|
|
||||||
control_layout->addWidget (auto_off_button_);
|
auto decodes_page = new QWidget;
|
||||||
control_layout->addWidget (halt_tx_button_);
|
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 */) {
|
connect (auto_off_button_, &QAbstractButton::clicked, [this] (bool /* checked */) {
|
||||||
Q_EMIT do_halt_tx (id_, true);
|
Q_EMIT do_halt_tx (id_, true);
|
||||||
});
|
});
|
||||||
connect (halt_tx_button_, &QAbstractButton::clicked, [this] (bool /* checked */) {
|
connect (halt_tx_button_, &QAbstractButton::clicked, [this] (bool /* checked */) {
|
||||||
Q_EMIT do_halt_tx (id_, false);
|
Q_EMIT do_halt_tx (id_, false);
|
||||||
});
|
});
|
||||||
content_layout->addLayout (control_layout);
|
content_layout->addWidget (control_button_box);
|
||||||
|
|
||||||
// set up status area
|
// set up status area
|
||||||
auto status_bar = new QStatusBar;
|
auto status_bar = new QStatusBar;
|
||||||
|
@ -254,8 +408,8 @@ public:
|
||||||
setAllowedAreas (Qt::BottomDockWidgetArea);
|
setAllowedAreas (Qt::BottomDockWidgetArea);
|
||||||
|
|
||||||
// connect up table view signals
|
// connect up table view signals
|
||||||
connect (decodes_table_view_, &QTableView::doubleClicked, this, [this, proxy_model] (QModelIndex const& index) {
|
connect (decodes_table_view_, &QTableView::doubleClicked, this, [this, decodes_proxy_model] (QModelIndex const& index) {
|
||||||
Q_EMIT do_reply (proxy_model->mapToSource (index));
|
Q_EMIT do_reply (decodes_proxy_model->mapToSource (index));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,7 +419,9 @@ public:
|
||||||
{
|
{
|
||||||
if (id == id_)
|
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);
|
dx_call_label_->setText ("DX CALL: " + dx_call);
|
||||||
frequency_label_->setText ("QRG: " + Radio::pretty_frequency_MHz_string (f));
|
frequency_label_->setText ("QRG: " + Radio::pretty_frequency_MHz_string (f));
|
||||||
report_label_->setText ("SNR: " + report);
|
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*/
|
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*/
|
, float /*delta_time*/, quint32 /*delta_frequency*/, QString const& /*mode*/
|
||||||
, QString const& /*message*/)
|
, QString const& /*message*/)
|
||||||
{
|
{
|
||||||
if (client_id == id_)
|
if (client_id == id_)
|
||||||
{
|
{
|
||||||
|
decodes_stack_->setCurrentIndex (0);
|
||||||
decodes_table_view_->resizeColumnsToContents ();
|
decodes_table_view_->resizeColumnsToContents ();
|
||||||
decodes_table_view_->horizontalHeader ()->setStretchLastSection (true);
|
|
||||||
decodes_table_view_->scrollToBottom ();
|
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_reply (QModelIndex const&);
|
||||||
Q_SIGNAL void do_halt_tx (QString const& id, bool auto_only);
|
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);
|
Q_SIGNAL void do_free_text (QString const& id, QString const& text, bool);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class DecodesFilterModel final
|
class IdFilterModel final
|
||||||
: public QSortFilterProxyModel
|
: public QSortFilterProxyModel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DecodesFilterModel (QString const& id, QObject * parent = nullptr)
|
IdFilterModel (QString const& id, QObject * parent = nullptr)
|
||||||
: QSortFilterProxyModel {parent}
|
: QSortFilterProxyModel {parent}
|
||||||
, id_ {id}
|
, id_ {id}
|
||||||
{}
|
{}
|
||||||
|
@ -315,7 +483,9 @@ private:
|
||||||
|
|
||||||
QString id_;
|
QString id_;
|
||||||
QTableView * decodes_table_view_;
|
QTableView * decodes_table_view_;
|
||||||
|
QTableView * beacons_table_view_;
|
||||||
QLineEdit * message_line_edit_;
|
QLineEdit * message_line_edit_;
|
||||||
|
QStackedLayout * decodes_stack_;
|
||||||
QAbstractButton * auto_off_button_;
|
QAbstractButton * auto_off_button_;
|
||||||
QAbstractButton * halt_tx_button_;
|
QAbstractButton * halt_tx_button_;
|
||||||
QLabel * mode_label_;
|
QLabel * mode_label_;
|
||||||
|
@ -333,6 +503,7 @@ public:
|
||||||
MainWindow ()
|
MainWindow ()
|
||||||
: log_ {new QStandardItemModel {0, 10, this}}
|
: log_ {new QStandardItemModel {0, 10, this}}
|
||||||
, decodes_model_ {new DecodesModel {this}}
|
, decodes_model_ {new DecodesModel {this}}
|
||||||
|
, beacons_model_ {new BeaconsModel {this}}
|
||||||
, server_ {new MessageServer {this}}
|
, server_ {new MessageServer {this}}
|
||||||
, multicast_group_line_edit_ {new QLineEdit}
|
, multicast_group_line_edit_ {new QLineEdit}
|
||||||
, log_table_view_ {new QTableView}
|
, log_table_view_ {new QTableView}
|
||||||
|
@ -395,8 +566,11 @@ public:
|
||||||
connect (server_, &MessageServer::client_opened, this, &MainWindow::add_client);
|
connect (server_, &MessageServer::client_opened, this, &MainWindow::add_client);
|
||||||
connect (server_, &MessageServer::client_closed, this, &MainWindow::remove_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, 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::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, decodes_model_, &DecodesModel::clear_decodes);
|
||||||
|
connect (server_, &MessageServer::clear_decodes, beacons_model_, &BeaconsModel::clear_decodes);
|
||||||
connect (decodes_model_, &DecodesModel::reply, server_, &MessageServer::reply);
|
connect (decodes_model_, &DecodesModel::reply, server_, &MessageServer::reply);
|
||||||
|
|
||||||
// UI behaviour
|
// UI behaviour
|
||||||
|
@ -435,7 +609,7 @@ public:
|
||||||
private:
|
private:
|
||||||
void add_client (QString const& id)
|
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);
|
dock->setAttribute (Qt::WA_DeleteOnClose);
|
||||||
auto view_action = dock->toggleViewAction ();
|
auto view_action = dock->toggleViewAction ();
|
||||||
view_action->setEnabled (true);
|
view_action->setEnabled (true);
|
||||||
|
@ -443,6 +617,7 @@ private:
|
||||||
addDockWidget (Qt::BottomDockWidgetArea, dock);
|
addDockWidget (Qt::BottomDockWidgetArea, dock);
|
||||||
connect (server_, &MessageServer::status_update, dock, &ClientWidget::update_status);
|
connect (server_, &MessageServer::status_update, dock, &ClientWidget::update_status);
|
||||||
connect (server_, &MessageServer::decode, dock, &ClientWidget::decode_added);
|
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_reply, decodes_model_, &DecodesModel::do_reply);
|
||||||
connect (dock, &ClientWidget::do_halt_tx, server_, &MessageServer::halt_tx);
|
connect (dock, &ClientWidget::do_halt_tx, server_, &MessageServer::halt_tx);
|
||||||
connect (dock, &ClientWidget::do_free_text, server_, &MessageServer::free_text);
|
connect (dock, &ClientWidget::do_free_text, server_, &MessageServer::free_text);
|
||||||
|
@ -464,6 +639,7 @@ private:
|
||||||
QStandardItemModel * log_;
|
QStandardItemModel * log_;
|
||||||
QMenu * view_menu_;
|
QMenu * view_menu_;
|
||||||
DecodesModel * decodes_model_;
|
DecodesModel * decodes_model_;
|
||||||
|
BeaconsModel * beacons_model_;
|
||||||
MessageServer * server_;
|
MessageServer * server_;
|
||||||
QLineEdit * multicast_group_line_edit_;
|
QLineEdit * multicast_group_line_edit_;
|
||||||
QTableView * log_table_view_;
|
QTableView * log_table_view_;
|
||||||
|
|
|
@ -272,9 +272,16 @@ MessageClient::MessageClient (QString const& id, QString const& server, port_typ
|
||||||
, m_ {id, server_port, this}
|
, m_ {id, server_port, this}
|
||||||
{
|
{
|
||||||
connect (&*m_, static_cast<void (impl::*) (impl::SocketError)> (&impl::error)
|
connect (&*m_, static_cast<void (impl::*) (impl::SocketError)> (&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);
|
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 ()
|
void MessageClient::clear_decodes ()
|
||||||
{
|
{
|
||||||
if (m_->server_port_ && !m_->server_string_.isEmpty ())
|
if (m_->server_port_ && !m_->server_string_.isEmpty ())
|
||||||
|
|
|
@ -14,8 +14,8 @@ class QHostAddress;
|
||||||
|
|
||||||
//
|
//
|
||||||
// MessageClient - Manage messages sent and replies received from a
|
// MessageClient - Manage messages sent and replies received from a
|
||||||
// matching server (MessageServer) at the other end of
|
// matching server (MessageServer) at the other end of
|
||||||
// the wire
|
// the wire
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// Each outgoing message type is a Qt slot
|
// Each outgoing message type is a Qt slot
|
||||||
|
@ -50,6 +50,8 @@ public:
|
||||||
, QString const& tx_mode, bool tx_enabled, bool transmitting, bool decoding);
|
, 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
|
Q_SLOT void decode (bool is_new, QTime time, qint32 snr, float delta_time, quint32 delta_frequency
|
||||||
, QString const& mode, QString const& message);
|
, 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 clear_decodes ();
|
||||||
Q_SLOT void qso_logged (QDateTime time, QString const& dx_call, QString const& dx_grid
|
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
|
, Frequency dial_frequency, QString const& mode, QString const& report_sent
|
||||||
|
|
|
@ -223,6 +223,27 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
|
||||||
}
|
}
|
||||||
break;
|
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:
|
case NetworkMessage::QSOLogged:
|
||||||
{
|
{
|
||||||
QDateTime time;
|
QDateTime time;
|
||||||
|
|
|
@ -65,6 +65,8 @@ public:
|
||||||
Q_SIGNAL void client_closed (QString const& id);
|
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
|
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);
|
, 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
|
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
|
, Frequency dial_frequency, QString const& mode, QString const& report_sent
|
||||||
, QString const& report_received, QString const& tx_power, QString const& comments
|
, QString const& report_received, QString const& tx_power, QString const& comments
|
||||||
|
|
|
@ -137,7 +137,7 @@
|
||||||
* Mode utf8
|
* Mode utf8
|
||||||
* Message 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
|
* this case the 'New' field is true. It is also used in response
|
||||||
* to a "Replay" message where each old decode in the "Band
|
* to a "Replay" message where each old decode in the "Band
|
||||||
* activity" window, that has not been erased, is sent in order
|
* 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
|
* command to determine the contents of the current free text
|
||||||
* message.
|
* 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 <QDataStream>
|
#include <QDataStream>
|
||||||
|
@ -285,6 +305,7 @@ namespace NetworkMessage
|
||||||
Replay,
|
Replay,
|
||||||
HaltTx,
|
HaltTx,
|
||||||
FreeText,
|
FreeText,
|
||||||
|
WSPRDecode,
|
||||||
maximum_message_type_ // ONLY add new message types
|
maximum_message_type_ // ONLY add new message types
|
||||||
// immediately before here
|
// immediately before here
|
||||||
};
|
};
|
||||||
|
|
|
@ -870,6 +870,10 @@ void MainWindow::dataSink(qint64 frames)
|
||||||
cmnd=t3.mid(0,i1+7) + t3.mid(i1+7);
|
cmnd=t3.mid(0,i1+7) + t3.mid(i1+7);
|
||||||
ui->DecodeButton->setChecked (true);
|
ui->DecodeButton->setChecked (true);
|
||||||
p1.start(QDir::toNativeSeparators(cmnd));
|
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;
|
m_rxDone=true;
|
||||||
}
|
}
|
||||||
|
@ -1012,7 +1016,7 @@ void MainWindow::keyPressEvent( QKeyEvent *e ) //keyPressEvent
|
||||||
switch(e->key())
|
switch(e->key())
|
||||||
{
|
{
|
||||||
case Qt::Key_D:
|
case Qt::Key_D:
|
||||||
if(e->modifiers() & Qt::ShiftModifier) {
|
if(m_mode != "WSPR-2" && e->modifiers() & Qt::ShiftModifier) {
|
||||||
if(!m_decoderBusy) {
|
if(!m_decoderBusy) {
|
||||||
jt9com_.newdat=0;
|
jt9com_.newdat=0;
|
||||||
jt9com_.nagain=0;
|
jt9com_.nagain=0;
|
||||||
|
@ -1463,7 +1467,7 @@ void MainWindow::on_actionSpecial_mouse_commands_triggered()
|
||||||
|
|
||||||
void MainWindow::on_DecodeButton_clicked (bool /* checked */) //Decode request
|
void MainWindow::on_DecodeButton_clicked (bool /* checked */) //Decode request
|
||||||
{
|
{
|
||||||
if(!m_decoderBusy) {
|
if(m_mode != "WSPR-2" && !m_decoderBusy) {
|
||||||
jt9com_.newdat=0;
|
jt9com_.newdat=0;
|
||||||
jt9com_.nagain=1;
|
jt9com_.nagain=1;
|
||||||
m_blankLine=false; // don't insert the separator again
|
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
|
// we accept this request even if the setting to accept UDP requests
|
||||||
// is not checked
|
// is not checked
|
||||||
|
|
||||||
|
// attempt to parse the decoded text
|
||||||
Q_FOREACH (auto const& message, ui->decodedTextBrowser->toPlainText ().split ('\n', QString::SkipEmptyParts))
|
Q_FOREACH (auto const& message, ui->decodedTextBrowser->toPlainText ().split ('\n', QString::SkipEmptyParts))
|
||||||
{
|
{
|
||||||
if (message.size() >= 4 && message.left (4) != "----")
|
if (message.size() >= 4 && message.left (4) != "----")
|
||||||
{
|
{
|
||||||
auto eom_pos = message.indexOf (' ', 35);
|
auto const& parts = message.split (' ', QString::SkipEmptyParts);
|
||||||
// we always want at least the characters to position 35
|
if (parts.size () >= 5 && parts[3].contains ('.')) // WSPR
|
||||||
if (eom_pos < 35)
|
|
||||||
{
|
{
|
||||||
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 ();
|
statusChanged ();
|
||||||
|
@ -3943,8 +3957,8 @@ void MainWindow::replayDecodes ()
|
||||||
|
|
||||||
void MainWindow::postDecode (bool is_new, QString const& message)
|
void MainWindow::postDecode (bool is_new, QString const& message)
|
||||||
{
|
{
|
||||||
auto decode = message.trimmed ();
|
auto const& decode = message.trimmed ();
|
||||||
auto parts = decode.left (21).split (' ', QString::SkipEmptyParts);
|
auto const& parts = decode.left (21).split (' ', QString::SkipEmptyParts);
|
||||||
if (parts.size () >= 5)
|
if (parts.size () >= 5)
|
||||||
{
|
{
|
||||||
m_messageClient->decode (is_new, QTime::fromString (parts[0], "hhmm"), parts[1].toInt ()
|
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)
|
void MainWindow::networkError (QString const& e)
|
||||||
{
|
{
|
||||||
if (QMessageBox::Retry == QMessageBox::warning (this, tr ("Network Error")
|
if (QMessageBox::Retry == QMessageBox::warning (this, tr ("Network Error")
|
||||||
|
@ -4016,7 +4042,10 @@ void MainWindow::p1ReadFromStdout() //p1readFromStdout
|
||||||
m_RxLog=0;
|
m_RxLog=0;
|
||||||
m_startAnother=m_loopall;
|
m_startAnother=m_loopall;
|
||||||
m_blankLine=true;
|
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 {
|
} else {
|
||||||
|
|
||||||
int n=t.length();
|
int n=t.length();
|
||||||
|
@ -4035,6 +4064,7 @@ void MainWindow::p1ReadFromStdout() //p1readFromStdout
|
||||||
.arg(rxFields.at(5).leftJustified (12).replace ('<', "<").replace ('>', ">"))
|
.arg(rxFields.at(5).leftJustified (12).replace ('<', "<").replace ('>', ">"))
|
||||||
.arg(rxFields.at(6), -6)
|
.arg(rxFields.at(6), -6)
|
||||||
.arg(rxFields.at(7), 3);
|
.arg(rxFields.at(7), 3);
|
||||||
|
postWSPRDecode (true, rxFields);
|
||||||
grid = rxFields.at(6);
|
grid = rxFields.at(6);
|
||||||
} else if ( rxFields.count() == 7 ) { // Type 2 message
|
} else if ( rxFields.count() == 7 ) { // Type 2 message
|
||||||
rxLine = QString("%1 %2 %3 %4 %5 %6 %7 %8")
|
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(rxFields.at(5).leftJustified (12).replace ('<', "<").replace ('>', ">"))
|
||||||
.arg("", -6)
|
.arg("", -6)
|
||||||
.arg(rxFields.at(6), 3);
|
.arg(rxFields.at(6), 3);
|
||||||
|
postWSPRDecode (true, rxFields);
|
||||||
} else {
|
} else {
|
||||||
rxLine = t;
|
rxLine = t;
|
||||||
}
|
}
|
||||||
|
|
|
@ -501,6 +501,7 @@ private:
|
||||||
void replyToCQ (QTime, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode, QString const& message_text);
|
void replyToCQ (QTime, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode, QString const& message_text);
|
||||||
void replayDecodes ();
|
void replayDecodes ();
|
||||||
void postDecode (bool is_new, QString const& message);
|
void postDecode (bool is_new, QString const& message);
|
||||||
|
void postWSPRDecode (bool is_new, QStringList message_parts);
|
||||||
void enable_DXCC_entity (bool on);
|
void enable_DXCC_entity (bool on);
|
||||||
void switch_mode (Mode);
|
void switch_mode (Mode);
|
||||||
void WSPR_scheduling ();
|
void WSPR_scheduling ();
|
||||||
|
|
Loading…
Reference in New Issue