Extend UDP MessageServer client mapping key with the host address

The UDP Example reference applications  now work correctly with WSJT-X
instances with duplicate --rig-name= command line arguments so long as
duplicate instances are run on unique hosts.
This commit is contained in:
Bill Somerville 2020-11-02 21:35:48 +00:00
parent 662ed0fa7a
commit 7b54428a60
No known key found for this signature in database
GPG Key ID: D864B06D1E81618F
11 changed files with 251 additions and 217 deletions

View File

@ -25,10 +25,13 @@ namespace
QFont text_font {"Courier", 10}; QFont text_font {"Courier", 10};
QList<QStandardItem *> make_row (QString const& client_id, QTime time, qint32 snr, float delta_time QList<QStandardItem *> make_row (MessageServer::ClientKey const& key, QTime time, qint32 snr, float delta_time
, Frequency frequency, qint32 drift, QString const& callsign , Frequency frequency, qint32 drift, QString const& callsign
, QString const& grid, qint32 power, bool off_air) , QString const& grid, qint32 power, bool off_air)
{ {
auto client_item = new QStandardItem {QString {"%1(%2)"}.arg (key.second).arg (key.first.toString ())};
client_item->setData (QVariant::fromValue (key));
auto time_item = new QStandardItem {time.toString ("hh:mm")}; auto time_item = new QStandardItem {time.toString ("hh:mm")};
time_item->setData (time); time_item->setData (time);
time_item->setTextAlignment (Qt::AlignRight); time_item->setTextAlignment (Qt::AlignRight);
@ -60,7 +63,7 @@ namespace
live->setTextAlignment (Qt::AlignHCenter); live->setTextAlignment (Qt::AlignHCenter);
QList<QStandardItem *> row { QList<QStandardItem *> row {
new QStandardItem {client_id}, time_item, snr_item, dt, freq, dri, gd, pwr, live, new QStandardItem {callsign}}; client_item, time_item, snr_item, dt, freq, dri, gd, pwr, live, new QStandardItem {callsign}};
Q_FOREACH (auto& item, row) Q_FOREACH (auto& item, row)
{ {
item->setEditable (false); item->setEditable (false);
@ -81,7 +84,7 @@ BeaconsModel::BeaconsModel (QObject * parent)
} }
} }
void BeaconsModel::add_beacon_spot (bool is_new, QString const& client_id, QTime time, qint32 snr, float delta_time void BeaconsModel::add_beacon_spot (bool is_new, ClientKey const& key, QTime time, qint32 snr, float delta_time
, Frequency frequency, qint32 drift, QString const& callsign , Frequency frequency, qint32 drift, QString const& callsign
, QString const& grid, qint32 power, bool off_air) , QString const& grid, qint32 power, bool off_air)
{ {
@ -90,7 +93,7 @@ void BeaconsModel::add_beacon_spot (bool is_new, QString const& client_id, QTime
int target_row {-1}; int target_row {-1};
for (auto row = 0; row < rowCount (); ++row) for (auto row = 0; row < rowCount (); ++row)
{ {
if (data (index (row, 0)).toString () == client_id) if (item (row, 0)->data ().value<ClientKey> () == key)
{ {
auto row_time = item (row, 1)->data ().toTime (); auto row_time = item (row, 1)->data ().toTime ();
if (row_time == time if (row_time == time
@ -113,19 +116,19 @@ void BeaconsModel::add_beacon_spot (bool is_new, QString const& client_id, QTime
} }
if (target_row >= 0) if (target_row >= 0)
{ {
insertRow (target_row + 1, make_row (client_id, time, snr, delta_time, frequency, drift, callsign, grid, power, off_air)); insertRow (target_row + 1, make_row (key, time, snr, delta_time, frequency, drift, callsign, grid, power, off_air));
return; return;
} }
} }
appendRow (make_row (client_id, time, snr, delta_time, frequency, drift, callsign, grid, power, off_air)); appendRow (make_row (key, time, snr, delta_time, frequency, drift, callsign, grid, power, off_air));
} }
void BeaconsModel::decodes_cleared (QString const& client_id) void BeaconsModel::decodes_cleared (ClientKey const& key)
{ {
for (auto row = rowCount () - 1; row >= 0; --row) for (auto row = rowCount () - 1; row >= 0; --row)
{ {
if (data (index (row, 0)).toString () == client_id) if (item (row, 0)->data ().value<ClientKey> () == key)
{ {
removeRow (row); removeRow (row);
} }

View File

@ -26,13 +26,15 @@ class BeaconsModel
{ {
Q_OBJECT; Q_OBJECT;
using ClientKey = MessageServer::ClientKey;
public: public:
explicit BeaconsModel (QObject * parent = nullptr); explicit BeaconsModel (QObject * parent = nullptr);
Q_SLOT void add_beacon_spot (bool is_new, QString const& client_id, QTime time, qint32 snr, float delta_time Q_SLOT void add_beacon_spot (bool is_new, ClientKey const&, QTime time, qint32 snr, float delta_time
, Frequency frequency, qint32 drift, QString const& callsign, QString const& grid , Frequency frequency, qint32 drift, QString const& callsign, QString const& grid
, qint32 power, bool off_air); , qint32 power, bool off_air);
Q_SLOT void decodes_cleared (QString const& client_id); Q_SLOT void decodes_cleared (ClientKey const&);
}; };
#endif #endif

View File

@ -27,9 +27,9 @@ namespace
} }
} }
ClientWidget::IdFilterModel::IdFilterModel (QString const& client_id, QObject * parent) ClientWidget::IdFilterModel::IdFilterModel (ClientKey const& key, QObject * parent)
: QSortFilterProxyModel {parent} : QSortFilterProxyModel {parent}
, client_id_ {client_id} , key_ {key}
, rx_df_ (quint32_max) , rx_df_ (quint32_max)
{ {
} }
@ -73,7 +73,7 @@ bool ClientWidget::IdFilterModel::filterAcceptsRow (int source_row
, QModelIndex const& source_parent) const , QModelIndex const& source_parent) const
{ {
auto source_index_col0 = sourceModel ()->index (source_row, 0, source_parent); auto source_index_col0 = sourceModel ()->index (source_row, 0, source_parent);
return sourceModel ()->data (source_index_col0).toString () == client_id_; return sourceModel ()->data (source_index_col0).value<ClientKey> () == key_;
} }
void ClientWidget::IdFilterModel::de_call (QString const& call) void ClientWidget::IdFilterModel::de_call (QString const& call)
@ -106,9 +106,9 @@ void ClientWidget::IdFilterModel::rx_df (quint32 df)
namespace namespace
{ {
QString make_title (QString const& id, QString const& version, QString const& revision) QString make_title (MessageServer::ClientKey const& key, QString const& version, QString const& revision)
{ {
QString title {id}; QString title {QString {"%1(%2)"}.arg (key.second).arg (key.first.toString ())};
if (version.size ()) if (version.size ())
{ {
title += QString {" v%1"}.arg (version); title += QString {" v%1"}.arg (version);
@ -122,14 +122,14 @@ namespace
} }
ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemModel * beacons_model ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemModel * beacons_model
, QString const& id, QString const& version, QString const& revision , ClientKey const& key, QString const& version, QString const& revision
, QListWidget const * calls_of_interest, QWidget * parent) , QListWidget const * calls_of_interest, QWidget * parent)
: QDockWidget {make_title (id, version, revision), parent} : QDockWidget {make_title (key, version, revision), parent}
, id_ {id} , key_ {key}
, done_ {false} , done_ {false}
, calls_of_interest_ {calls_of_interest} , calls_of_interest_ {calls_of_interest}
, decodes_proxy_model_ {id} , decodes_proxy_model_ {key}
, beacons_proxy_model_ {id} , beacons_proxy_model_ {key}
, erase_action_ {new QAction {tr ("&Erase Band Activity"), this}} , erase_action_ {new QAction {tr ("&Erase Band Activity"), this}}
, erase_rx_frequency_action_ {new QAction {tr ("Erase &Rx Frequency"), this}} , erase_rx_frequency_action_ {new QAction {tr ("Erase &Rx Frequency"), this}}
, erase_both_action_ {new QAction {tr ("Erase &Both"), this}} , erase_both_action_ {new QAction {tr ("Erase &Both"), this}}
@ -209,56 +209,56 @@ ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemMod
horizontal_layout_->addLayout (subform3_layout_); horizontal_layout_->addLayout (subform3_layout_);
connect (message_line_edit_, &QLineEdit::textEdited, [this] (QString const& text) { connect (message_line_edit_, &QLineEdit::textEdited, [this] (QString const& text) {
Q_EMIT do_free_text (id_, text, false); Q_EMIT do_free_text (key_, text, false);
}); });
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 (key_, message_line_edit_->text (), true);
}); });
connect (grid_line_edit_, &QLineEdit::editingFinished, [this] () { connect (grid_line_edit_, &QLineEdit::editingFinished, [this] () {
Q_EMIT location (id_, grid_line_edit_->text ()); Q_EMIT location (key_, grid_line_edit_->text ());
}); });
connect (configuration_line_edit_, &QLineEdit::editingFinished, [this] () { connect (configuration_line_edit_, &QLineEdit::editingFinished, [this] () {
Q_EMIT switch_configuration (id_, configuration_line_edit_->text ()); Q_EMIT switch_configuration (key_, configuration_line_edit_->text ());
}); });
connect (mode_line_edit_, &QLineEdit::editingFinished, [this] () { connect (mode_line_edit_, &QLineEdit::editingFinished, [this] () {
QString empty; QString empty;
Q_EMIT configure (id_, mode_line_edit_->text (), quint32_max, empty, fast_mode () Q_EMIT configure (key_, mode_line_edit_->text (), quint32_max, empty, fast_mode ()
, quint32_max, quint32_max, empty, empty, false); , quint32_max, quint32_max, empty, empty, false);
}); });
connect (frequency_tolerance_spin_box_, static_cast<void (QSpinBox::*) (int)> (&QSpinBox::valueChanged), [this] (int i) { connect (frequency_tolerance_spin_box_, static_cast<void (QSpinBox::*) (int)> (&QSpinBox::valueChanged), [this] (int i) {
QString empty; QString empty;
auto f = frequency_tolerance_spin_box_->specialValueText ().size () ? quint32_max : i; auto f = frequency_tolerance_spin_box_->specialValueText ().size () ? quint32_max : i;
Q_EMIT configure (id_, empty, f, empty, fast_mode () Q_EMIT configure (key_, empty, f, empty, fast_mode ()
, quint32_max, quint32_max, empty, empty, false); , quint32_max, quint32_max, empty, empty, false);
}); });
connect (submode_line_edit_, &QLineEdit::editingFinished, [this] () { connect (submode_line_edit_, &QLineEdit::editingFinished, [this] () {
QString empty; QString empty;
Q_EMIT configure (id_, empty, quint32_max, submode_line_edit_->text (), fast_mode () Q_EMIT configure (key_, empty, quint32_max, submode_line_edit_->text (), fast_mode ()
, quint32_max, quint32_max, empty, empty, false); , quint32_max, quint32_max, empty, empty, false);
}); });
connect (fast_mode_check_box_, &QCheckBox::stateChanged, [this] (int state) { connect (fast_mode_check_box_, &QCheckBox::stateChanged, [this] (int state) {
QString empty; QString empty;
Q_EMIT configure (id_, empty, quint32_max, empty, Qt::Checked == state Q_EMIT configure (key_, empty, quint32_max, empty, Qt::Checked == state
, quint32_max, quint32_max, empty, empty, false); , quint32_max, quint32_max, empty, empty, false);
}); });
connect (tr_period_spin_box_, static_cast<void (QSpinBox::*) (int)> (&QSpinBox::valueChanged), [this] (int i) { connect (tr_period_spin_box_, static_cast<void (QSpinBox::*) (int)> (&QSpinBox::valueChanged), [this] (int i) {
QString empty; QString empty;
Q_EMIT configure (id_, empty, quint32_max, empty, fast_mode () Q_EMIT configure (key_, empty, quint32_max, empty, fast_mode ()
, i, quint32_max, empty, empty, false); , i, quint32_max, empty, empty, false);
}); });
connect (rx_df_spin_box_, static_cast<void (QSpinBox::*) (int)> (&QSpinBox::valueChanged), [this] (int i) { connect (rx_df_spin_box_, static_cast<void (QSpinBox::*) (int)> (&QSpinBox::valueChanged), [this] (int i) {
QString empty; QString empty;
Q_EMIT configure (id_, empty, quint32_max, empty, fast_mode () Q_EMIT configure (key_, empty, quint32_max, empty, fast_mode ()
, quint32_max, i, empty, empty, false); , quint32_max, i, empty, empty, false);
}); });
connect (dx_call_line_edit_, &QLineEdit::editingFinished, [this] () { connect (dx_call_line_edit_, &QLineEdit::editingFinished, [this] () {
QString empty; QString empty;
Q_EMIT configure (id_, empty, quint32_max, empty, fast_mode () Q_EMIT configure (key_, empty, quint32_max, empty, fast_mode ()
, quint32_max, quint32_max, dx_call_line_edit_->text (), empty, false); , quint32_max, quint32_max, dx_call_line_edit_->text (), empty, false);
}); });
connect (dx_grid_line_edit_, &QLineEdit::editingFinished, [this] () { connect (dx_grid_line_edit_, &QLineEdit::editingFinished, [this] () {
QString empty; QString empty;
Q_EMIT configure (id_, empty, quint32_max, empty, fast_mode () Q_EMIT configure (key_, empty, quint32_max, empty, fast_mode ()
, quint32_max, quint32_max, empty, dx_grid_line_edit_->text (), false); , quint32_max, quint32_max, empty, dx_grid_line_edit_->text (), false);
}); });
@ -289,14 +289,14 @@ ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemMod
halt_tx_button_ = control_button_box_->addButton (tr ("&Halt Tx"), QDialogButtonBox::ActionRole); halt_tx_button_ = control_button_box_->addButton (tr ("&Halt Tx"), QDialogButtonBox::ActionRole);
connect (generate_messages_push_button_, &QAbstractButton::clicked, [this] (bool /*checked*/) { connect (generate_messages_push_button_, &QAbstractButton::clicked, [this] (bool /*checked*/) {
QString empty; QString empty;
Q_EMIT configure (id_, empty, quint32_max, empty, fast_mode () Q_EMIT configure (key_, empty, quint32_max, empty, fast_mode ()
, quint32_max, quint32_max, empty, empty, true); , quint32_max, quint32_max, empty, empty, true);
}); });
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 (key_, 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 (key_, false);
}); });
content_layout_->addWidget (control_button_box_); content_layout_->addWidget (control_button_box_);
@ -318,13 +318,13 @@ ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemMod
// connect context menu actions // connect context menu actions
connect (erase_action_, &QAction::triggered, [this] (bool /*checked*/) { connect (erase_action_, &QAction::triggered, [this] (bool /*checked*/) {
Q_EMIT do_clear_decodes (id_); Q_EMIT do_clear_decodes (key_);
}); });
connect (erase_rx_frequency_action_, &QAction::triggered, [this] (bool /*checked*/) { connect (erase_rx_frequency_action_, &QAction::triggered, [this] (bool /*checked*/) {
Q_EMIT do_clear_decodes (id_, 1); Q_EMIT do_clear_decodes (key_, 1);
}); });
connect (erase_both_action_, &QAction::triggered, [this] (bool /*checked*/) { connect (erase_both_action_, &QAction::triggered, [this] (bool /*checked*/) {
Q_EMIT do_clear_decodes (id_, 2); Q_EMIT do_clear_decodes (key_, 2);
}); });
// connect up table view signals // connect up table view signals
@ -335,7 +335,7 @@ ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemMod
// tell new client about calls of interest // tell new client about calls of interest
for (int row = 0; row < calls_of_interest_->count (); ++row) for (int row = 0; row < calls_of_interest_->count (); ++row)
{ {
Q_EMIT highlight_callsign (id_, calls_of_interest_->item (row)->text (), QColor {Qt::blue}, QColor {Qt::yellow}); Q_EMIT highlight_callsign (key_, calls_of_interest_->item (row)->text (), QColor {Qt::blue}, QColor {Qt::yellow});
} }
} }
@ -349,7 +349,7 @@ void ClientWidget::closeEvent (QCloseEvent *e)
{ {
if (!done_) if (!done_)
{ {
Q_EMIT do_close (id_); Q_EMIT do_close (key_);
e->ignore (); // defer closure until client actually closes e->ignore (); // defer closure until client actually closes
} }
else else
@ -363,7 +363,7 @@ ClientWidget::~ClientWidget ()
for (int row = 0; row < calls_of_interest_->count (); ++row) for (int row = 0; row < calls_of_interest_->count (); ++row)
{ {
// tell client to forget calls of interest // tell client to forget calls of interest
Q_EMIT highlight_callsign (id_, calls_of_interest_->item (row)->text ()); Q_EMIT highlight_callsign (key_, calls_of_interest_->item (row)->text ());
} }
} }
@ -395,7 +395,7 @@ namespace
} }
} }
void ClientWidget::update_status (QString const& id, Frequency f, QString const& mode, QString const& dx_call void ClientWidget::update_status (ClientKey const& key, Frequency f, QString const& mode, QString const& dx_call
, QString const& report, QString const& tx_mode, bool tx_enabled , QString const& report, QString const& tx_mode, bool tx_enabled
, bool transmitting, bool decoding, quint32 rx_df, quint32 tx_df , bool transmitting, bool decoding, quint32 rx_df, quint32 tx_df
, QString const& de_call, QString const& de_grid, QString const& dx_grid , QString const& de_call, QString const& de_grid, QString const& dx_grid
@ -403,7 +403,7 @@ void ClientWidget::update_status (QString const& id, Frequency f, QString const&
, quint8 special_op_mode, quint32 frequency_tolerance, quint32 tr_period , quint8 special_op_mode, quint32 frequency_tolerance, quint32 tr_period
, QString const& configuration_name) , QString const& configuration_name)
{ {
if (id == id_) if (key == key_)
{ {
fast_mode_check_box_->setChecked (fast_mode); fast_mode_check_box_->setChecked (fast_mode);
decodes_proxy_model_.de_call (de_call); decodes_proxy_model_.de_call (de_call);
@ -447,11 +447,11 @@ void ClientWidget::update_status (QString const& id, Frequency f, QString const&
} }
} }
void ClientWidget::decode_added (bool /*is_new*/, QString const& client_id, QTime /*time*/, qint32 /*snr*/ void ClientWidget::decode_added (bool /*is_new*/, ClientKey const& key, 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*/, bool /*low_confidence*/, bool /*off_air*/) , QString const& /*message*/, bool /*low_confidence*/, bool /*off_air*/)
{ {
if (client_id == id_ && !columns_resized_) if (key == key_ && !columns_resized_)
{ {
decodes_stack_->setCurrentIndex (0); decodes_stack_->setCurrentIndex (0);
decodes_table_view_->resizeColumnsToContents (); decodes_table_view_->resizeColumnsToContents ();
@ -460,12 +460,12 @@ void ClientWidget::decode_added (bool /*is_new*/, QString const& client_id, QTim
decodes_table_view_->scrollToBottom (); decodes_table_view_->scrollToBottom ();
} }
void ClientWidget::beacon_spot_added (bool /*is_new*/, QString const& client_id, QTime /*time*/, qint32 /*snr*/ void ClientWidget::beacon_spot_added (bool /*is_new*/, ClientKey const& key, QTime /*time*/, qint32 /*snr*/
, float /*delta_time*/, Frequency /*delta_frequency*/, qint32 /*drift*/ , float /*delta_time*/, Frequency /*delta_frequency*/, qint32 /*drift*/
, QString const& /*callsign*/, QString const& /*grid*/, qint32 /*power*/ , QString const& /*callsign*/, QString const& /*grid*/, qint32 /*power*/
, bool /*off_air*/) , bool /*off_air*/)
{ {
if (client_id == id_ && !columns_resized_) if (key == key_ && !columns_resized_)
{ {
decodes_stack_->setCurrentIndex (1); decodes_stack_->setCurrentIndex (1);
beacons_table_view_->resizeColumnsToContents (); beacons_table_view_->resizeColumnsToContents ();
@ -474,9 +474,9 @@ void ClientWidget::beacon_spot_added (bool /*is_new*/, QString const& client_id,
beacons_table_view_->scrollToBottom (); beacons_table_view_->scrollToBottom ();
} }
void ClientWidget::decodes_cleared (QString const& client_id) void ClientWidget::decodes_cleared (ClientKey const& key)
{ {
if (client_id == id_) if (key == key_)
{ {
columns_resized_ = false; columns_resized_ = false;
} }

View File

@ -35,42 +35,44 @@ class ClientWidget
{ {
Q_OBJECT; Q_OBJECT;
using ClientKey = MessageServer::ClientKey;
public: public:
explicit ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemModel * beacons_model explicit ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemModel * beacons_model
, QString const& id, QString const& version, QString const& revision , ClientKey const& key, QString const& version, QString const& revision
, QListWidget const * calls_of_interest, QWidget * parent = nullptr); , QListWidget const * calls_of_interest, QWidget * parent = nullptr);
void dispose (); void dispose ();
~ClientWidget (); ~ClientWidget ();
bool fast_mode () const; bool fast_mode () const;
Q_SLOT void update_status (QString const& id, Frequency f, QString const& mode, QString const& dx_call Q_SLOT void update_status (ClientKey const& key, Frequency f, QString const& mode, QString const& dx_call
, QString const& report, QString const& tx_mode, bool tx_enabled , QString const& report, QString const& tx_mode, bool tx_enabled
, bool transmitting, bool decoding, quint32 rx_df, quint32 tx_df , bool transmitting, bool decoding, quint32 rx_df, quint32 tx_df
, QString const& de_call, QString const& de_grid, QString const& dx_grid , QString const& de_call, QString const& de_grid, QString const& dx_grid
, bool watchdog_timeout, QString const& sub_mode, bool fast_mode , bool watchdog_timeout, QString const& sub_mode, bool fast_mode
, quint8 special_op_mode, quint32 frequency_tolerance, quint32 tr_period , quint8 special_op_mode, quint32 frequency_tolerance, quint32 tr_period
, QString const& configuration_name); , QString const& configuration_name);
Q_SLOT void decode_added (bool is_new, QString const& client_id, QTime, qint32 snr Q_SLOT void decode_added (bool is_new, ClientKey const& key, QTime, qint32 snr
, float delta_time, quint32 delta_frequency, QString const& mode , float delta_time, quint32 delta_frequency, QString const& mode
, QString const& message, bool low_confidence, bool off_air); , QString const& message, bool low_confidence, bool off_air);
Q_SLOT void beacon_spot_added (bool is_new, QString const& client_id, QTime, qint32 snr Q_SLOT void beacon_spot_added (bool is_new, ClientKey const& key, QTime, qint32 snr
, float delta_time, Frequency delta_frequency, qint32 drift , float delta_time, Frequency delta_frequency, qint32 drift
, QString const& callsign, QString const& grid, qint32 power , QString const& callsign, QString const& grid, qint32 power
, bool off_air); , bool off_air);
Q_SLOT void decodes_cleared (QString const& client_id); Q_SLOT void decodes_cleared (ClientKey const& key);
Q_SIGNAL void do_clear_decodes (QString const& id, quint8 window = 0); Q_SIGNAL void do_clear_decodes (ClientKey const& key, quint8 window = 0);
Q_SIGNAL void do_close (QString const& id); Q_SIGNAL void do_close (ClientKey const& key);
Q_SIGNAL void do_reply (QModelIndex const&, quint8 modifier); Q_SIGNAL void do_reply (QModelIndex const&, quint8 modifier);
Q_SIGNAL void do_halt_tx (QString const& id, bool auto_only); Q_SIGNAL void do_halt_tx (ClientKey const& key, bool auto_only);
Q_SIGNAL void do_free_text (QString const& id, QString const& text, bool); Q_SIGNAL void do_free_text (ClientKey const& key, QString const& text, bool);
Q_SIGNAL void location (QString const& id, QString const& text); Q_SIGNAL void location (ClientKey const& key, QString const& text);
Q_SIGNAL void highlight_callsign (QString const& id, QString const& call Q_SIGNAL void highlight_callsign (ClientKey const& key, QString const& call
, QColor const& bg = QColor {}, QColor const& fg = QColor {} , QColor const& bg = QColor {}, QColor const& fg = QColor {}
, bool last_only = false); , bool last_only = false);
Q_SIGNAL void switch_configuration (QString const& id, QString const& configuration_name); Q_SIGNAL void switch_configuration (ClientKey const& key, QString const& configuration_name);
Q_SIGNAL void configure (QString const& id, QString const& mode, quint32 frequency_tolerance Q_SIGNAL void configure (ClientKey const& key, QString const& mode, quint32 frequency_tolerance
, QString const& submode, bool fast_mode, quint32 tr_period, quint32 rx_df , QString const& submode, bool fast_mode, quint32 tr_period, quint32 rx_df
, QString const& dx_call, QString const& dx_grid, bool generate_messages); , QString const& dx_call, QString const& dx_grid, bool generate_messages);
@ -79,7 +81,7 @@ private:
: public QSortFilterProxyModel : public QSortFilterProxyModel
{ {
public: public:
IdFilterModel (QString const& client_id, QObject * = nullptr); IdFilterModel (ClientKey const& key, QObject * = nullptr);
void de_call (QString const&); void de_call (QString const&);
void rx_df (quint32); void rx_df (quint32);
@ -88,7 +90,7 @@ private:
private: private:
bool filterAcceptsRow (int source_row, QModelIndex const& source_parent) const override; bool filterAcceptsRow (int source_row, QModelIndex const& source_parent) const override;
QString client_id_; ClientKey key_;
QString call_; QString call_;
QRegularExpression base_call_re_; QRegularExpression base_call_re_;
quint32 rx_df_; quint32 rx_df_;
@ -96,7 +98,7 @@ private:
void closeEvent (QCloseEvent *) override; void closeEvent (QCloseEvent *) override;
QString id_; ClientKey key_;
bool done_; bool done_;
QListWidget const * calls_of_interest_; QListWidget const * calls_of_interest_;
IdFilterModel decodes_proxy_model_; IdFilterModel decodes_proxy_model_;

View File

@ -2,6 +2,7 @@
#include <QStandardItem> #include <QStandardItem>
#include <QModelIndex> #include <QModelIndex>
#include <QVariant>
#include <QTime> #include <QTime>
#include <QString> #include <QString>
#include <QFont> #include <QFont>
@ -33,10 +34,13 @@ namespace
QFont text_font {"Courier", 10}; QFont text_font {"Courier", 10};
QList<QStandardItem *> make_row (QString const& client_id, QTime time, qint32 snr, float delta_time QList<QStandardItem *> make_row (MessageServer::ClientKey const& key, QTime time, qint32 snr
, quint32 delta_frequency, QString const& mode, QString const& message , float delta_time, quint32 delta_frequency, QString const& mode
, bool low_confidence, bool off_air, bool is_fast) , QString const& message, bool low_confidence, bool off_air, bool is_fast)
{ {
auto client_item = new QStandardItem {QString {"%1(%2)"}.arg (key.second).arg (key.first.toString ())};
client_item->setData (QVariant::fromValue (key));
auto time_item = new QStandardItem {time.toString (is_fast || "~" == mode ? "hh:mm:ss" : "hh:mm")}; auto time_item = new QStandardItem {time.toString (is_fast || "~" == mode ? "hh:mm:ss" : "hh:mm")};
time_item->setData (time); time_item->setData (time);
time_item->setTextAlignment (Qt::AlignRight); time_item->setTextAlignment (Qt::AlignRight);
@ -63,7 +67,7 @@ namespace
live->setTextAlignment (Qt::AlignHCenter); live->setTextAlignment (Qt::AlignHCenter);
QList<QStandardItem *> row { QList<QStandardItem *> row {
new QStandardItem {client_id}, time_item, snr_item, dt, df, md, confidence, live, new QStandardItem {message}}; client_item, time_item, snr_item, dt, df, md, confidence, live, new QStandardItem {message}};
Q_FOREACH (auto& item, row) Q_FOREACH (auto& item, row)
{ {
item->setEditable (false); item->setEditable (false);
@ -84,7 +88,7 @@ DecodesModel::DecodesModel (QObject * parent)
} }
} }
void DecodesModel::add_decode (bool is_new, QString const& client_id, QTime time, qint32 snr, float delta_time void DecodesModel::add_decode (bool is_new, ClientKey const& key, 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
, bool low_confidence, bool off_air, bool is_fast) , bool low_confidence, bool off_air, bool is_fast)
{ {
@ -93,7 +97,7 @@ void DecodesModel::add_decode (bool is_new, QString const& client_id, QTime time
int target_row {-1}; int target_row {-1};
for (auto row = 0; row < rowCount (); ++row) for (auto row = 0; row < rowCount (); ++row)
{ {
if (data (index (row, 0)).toString () == client_id) if (item (row, 0)->data ().value<ClientKey> () == key)
{ {
auto row_time = item (row, 1)->data ().toTime (); auto row_time = item (row, 1)->data ().toTime ();
if (row_time == time if (row_time == time
@ -115,21 +119,21 @@ void DecodesModel::add_decode (bool is_new, QString const& client_id, QTime time
} }
if (target_row >= 0) if (target_row >= 0)
{ {
insertRow (target_row + 1, make_row (client_id, time, snr, delta_time, delta_frequency, mode insertRow (target_row + 1, make_row (key, time, snr, delta_time, delta_frequency, mode
, message, low_confidence, off_air, is_fast)); , message, low_confidence, off_air, is_fast));
return; return;
} }
} }
appendRow (make_row (client_id, time, snr, delta_time, delta_frequency, mode, message, low_confidence appendRow (make_row (key, time, snr, delta_time, delta_frequency, mode, message, low_confidence
, off_air, is_fast)); , off_air, is_fast));
} }
void DecodesModel::decodes_cleared (QString const& client_id) void DecodesModel::decodes_cleared (ClientKey const& key)
{ {
for (auto row = rowCount () - 1; row >= 0; --row) for (auto row = rowCount () - 1; row >= 0; --row)
{ {
if (data (index (row, 0)).toString () == client_id) if (item (row, 0)->data ().value<ClientKey> () == key)
{ {
removeRow (row); removeRow (row);
} }
@ -139,7 +143,7 @@ void DecodesModel::decodes_cleared (QString const& client_id)
void DecodesModel::do_reply (QModelIndex const& source, quint8 modifiers) void DecodesModel::do_reply (QModelIndex const& source, quint8 modifiers)
{ {
auto row = source.row (); auto row = source.row ();
Q_EMIT reply (data (index (row, 0)).toString () Q_EMIT reply (item (row, 0)->data ().value<ClientKey> ()
, item (row, 1)->data ().toTime () , item (row, 1)->data ().toTime ()
, item (row, 2)->data ().toInt () , item (row, 2)->data ().toInt ()
, item (row, 3)->data ().toFloat () , item (row, 3)->data ().toFloat ()

View File

@ -5,8 +5,6 @@
#include "MessageServer.hpp" #include "MessageServer.hpp"
using Frequency = MessageServer::Frequency;
class QTime; class QTime;
class QString; class QString;
class QModelIndex; class QModelIndex;
@ -28,16 +26,18 @@ class DecodesModel
{ {
Q_OBJECT; Q_OBJECT;
using ClientKey = MessageServer::ClientKey;
public: public:
explicit DecodesModel (QObject * parent = nullptr); explicit DecodesModel (QObject * parent = nullptr);
Q_SLOT void add_decode (bool is_new, QString const& client_id, QTime time, qint32 snr, float delta_time Q_SLOT void add_decode (bool is_new, ClientKey const&, QTime, qint32 snr, float delta_time
, quint32 delta_frequency, QString const& mode, QString const& message , quint32 delta_frequency, QString const& mode, QString const& message
, bool low_confidence, bool off_air, bool is_fast); , bool low_confidence, bool off_air, bool is_fast);
Q_SLOT void decodes_cleared (QString const& client_id); Q_SLOT void decodes_cleared (ClientKey const&);
Q_SLOT void do_reply (QModelIndex const& source, quint8 modifiers); Q_SLOT void do_reply (QModelIndex const& source, quint8 modifiers);
Q_SIGNAL void reply (QString const& id, QTime time, qint32 snr, float delta_time, quint32 delta_frequency Q_SIGNAL void reply (ClientKey const&, QTime, qint32 snr, float delta_time, quint32 delta_frequency
, QString const& mode, QString const& message, bool low_confidence, quint8 modifiers); , QString const& mode, QString const& message, bool low_confidence, quint8 modifiers);
}; };

View File

@ -184,13 +184,16 @@ MessageAggregatorMainWindow::MessageAggregatorMainWindow ()
connect (server_, &MessageServer::client_closed, this, &MessageAggregatorMainWindow::remove_client); connect (server_, &MessageServer::client_closed, this, &MessageAggregatorMainWindow::remove_client);
connect (server_, &MessageServer::client_closed, decodes_model_, &DecodesModel::decodes_cleared); connect (server_, &MessageServer::client_closed, decodes_model_, &DecodesModel::decodes_cleared);
connect (server_, &MessageServer::client_closed, beacons_model_, &BeaconsModel::decodes_cleared); connect (server_, &MessageServer::client_closed, beacons_model_, &BeaconsModel::decodes_cleared);
connect (server_, &MessageServer::decode, [this] (bool is_new, QString const& id, QTime time connect (server_, &MessageServer::decode, [this] (bool is_new, ClientKey const& key, QTime time
, qint32 snr, float delta_time , qint32 snr, float delta_time
, quint32 delta_frequency, QString const& mode , quint32 delta_frequency, QString const& mode
, QString const& message, bool low_confidence , QString const& message, bool low_confidence
, bool off_air) { , bool off_air) {
decodes_model_->add_decode (is_new, id, time, snr, delta_time, delta_frequency, mode, message decodes_model_->add_decode (is_new, key, time, snr, delta_time
, low_confidence, off_air, dock_widgets_[id]->fast_mode ());}); , delta_frequency, mode, message
, low_confidence, off_air
, dock_widgets_[key]->fast_mode ());
});
connect (server_, &MessageServer::WSPR_decode, beacons_model_, &BeaconsModel::add_beacon_spot); connect (server_, &MessageServer::WSPR_decode, beacons_model_, &BeaconsModel::add_beacon_spot);
connect (server_, &MessageServer::decodes_cleared, decodes_model_, &DecodesModel::decodes_cleared); connect (server_, &MessageServer::decodes_cleared, decodes_model_, &DecodesModel::decodes_cleared);
connect (server_, &MessageServer::decodes_cleared, beacons_model_, &BeaconsModel::decodes_cleared); connect (server_, &MessageServer::decodes_cleared, beacons_model_, &BeaconsModel::decodes_cleared);
@ -207,7 +210,8 @@ MessageAggregatorMainWindow::MessageAggregatorMainWindow ()
show (); show ();
} }
void MessageAggregatorMainWindow::log_qso (QString const& /*id*/, QDateTime time_off, QString const& dx_call void MessageAggregatorMainWindow::log_qso (ClientKey const& /*key*/, QDateTime time_off
, QString const& dx_call
, QString const& dx_grid, Frequency dial_frequency, QString const& mode , QString const& dx_grid, Frequency dial_frequency, QString const& mode
, QString const& report_sent, QString const& report_received , QString const& report_sent, QString const& report_received
, QString const& tx_power, QString const& comments , QString const& tx_power, QString const& comments
@ -240,9 +244,9 @@ void MessageAggregatorMainWindow::log_qso (QString const& /*id*/, QDateTime time
log_table_view_->scrollToBottom (); log_table_view_->scrollToBottom ();
} }
void MessageAggregatorMainWindow::add_client (QString const& id, QString const& version, QString const& revision) void MessageAggregatorMainWindow::add_client (ClientKey const& key, QString const& version, QString const& revision)
{ {
auto dock = new ClientWidget {decodes_model_, beacons_model_, id, version, revision, calls_of_interest_, this}; auto dock = new ClientWidget {decodes_model_, beacons_model_, key, version, revision, calls_of_interest_, 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);
@ -262,13 +266,13 @@ void MessageAggregatorMainWindow::add_client (QString const& id, QString const&
connect (dock, &ClientWidget::highlight_callsign, server_, &MessageServer::highlight_callsign); connect (dock, &ClientWidget::highlight_callsign, server_, &MessageServer::highlight_callsign);
connect (dock, &ClientWidget::switch_configuration, server_, &MessageServer::switch_configuration); connect (dock, &ClientWidget::switch_configuration, server_, &MessageServer::switch_configuration);
connect (dock, &ClientWidget::configure, server_, &MessageServer::configure); connect (dock, &ClientWidget::configure, server_, &MessageServer::configure);
dock_widgets_[id] = dock; dock_widgets_[key] = dock;
server_->replay (id); // request decodes and status server_->replay (key); // request decodes and status
} }
void MessageAggregatorMainWindow::remove_client (QString const& id) void MessageAggregatorMainWindow::remove_client (ClientKey const& key)
{ {
auto iter = dock_widgets_.find (id); auto iter = dock_widgets_.find (key);
if (iter != std::end (dock_widgets_)) if (iter != std::end (dock_widgets_))
{ {
(*iter)->dispose (); (*iter)->dispose ();
@ -287,9 +291,9 @@ MessageAggregatorMainWindow::~MessageAggregatorMainWindow ()
void MessageAggregatorMainWindow::change_highlighting (QString const& call, QColor const& bg, QColor const& fg void MessageAggregatorMainWindow::change_highlighting (QString const& call, QColor const& bg, QColor const& fg
, bool last_only) , bool last_only)
{ {
for (auto id : dock_widgets_.keys ()) for (auto key : dock_widgets_.keys ())
{ {
server_->highlight_callsign (id, call, bg, fg, last_only); server_->highlight_callsign (key, call, bg, fg, last_only);
} }
} }

View File

@ -24,11 +24,13 @@ class MessageAggregatorMainWindow
{ {
Q_OBJECT; Q_OBJECT;
using ClientKey = MessageServer::ClientKey;
public: public:
MessageAggregatorMainWindow (); MessageAggregatorMainWindow ();
~MessageAggregatorMainWindow (); ~MessageAggregatorMainWindow ();
Q_SLOT void log_qso (QString const& /*id*/, QDateTime time_off, QString const& dx_call, QString const& dx_grid Q_SLOT void log_qso (ClientKey const&, QDateTime time_off, 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
, QString const& name, QDateTime time_on, QString const& operator_call , QString const& name, QDateTime time_on, QString const& operator_call
@ -36,13 +38,13 @@ public:
, QString const& exchange_sent, QString const& exchange_rcvd, QString const& prop_mode); , QString const& exchange_sent, QString const& exchange_rcvd, QString const& prop_mode);
private: private:
void add_client (QString const& id, QString const& version, QString const& revision); void add_client (ClientKey const&, QString const& version, QString const& revision);
void remove_client (QString const& id); void remove_client (ClientKey const&);
void change_highlighting (QString const& call, QColor const& bg = QColor {}, QColor const& fg = QColor {}, void change_highlighting (QString const& call, QColor const& bg = QColor {}, QColor const& fg = QColor {},
bool last_only = false); bool last_only = false);
// maps client id to widgets // maps client id to widgets
using ClientsDictionary = QHash<QString, ClientWidget *>; using ClientsDictionary = QHash<ClientKey, ClientWidget *>;
ClientsDictionary dock_widgets_; ClientsDictionary dock_widgets_;
QStandardItemModel * log_; QStandardItemModel * log_;

View File

@ -83,9 +83,8 @@ public:
struct Client struct Client
{ {
Client () = default; Client () = default;
Client (QHostAddress const& sender_address, port_type const& sender_port) Client (port_type const& sender_port)
: sender_address_ {sender_address} : sender_port_ {sender_port}
, sender_port_ {sender_port}
, negotiated_schema_number_ {2} // not 1 because it's broken , negotiated_schema_number_ {2} // not 1 because it's broken
, last_activity_ {QDateTime::currentDateTime ()} , last_activity_ {QDateTime::currentDateTime ()}
{ {
@ -93,12 +92,11 @@ public:
Client (Client const&) = default; Client (Client const&) = default;
Client& operator= (Client const&) = default; Client& operator= (Client const&) = default;
QHostAddress sender_address_;
port_type sender_port_; port_type sender_port_;
quint32 negotiated_schema_number_; quint32 negotiated_schema_number_;
QDateTime last_activity_; QDateTime last_activity_;
}; };
QHash<QString, Client> clients_; // maps id to Client QHash<ClientKey, Client> clients_; // maps id to Client
QTimer * clock_; QTimer * clock_;
}; };
@ -171,9 +169,10 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
auto id = in.id (); auto id = in.id ();
if (OK == check_status (in)) if (OK == check_status (in))
{ {
if (!clients_.contains (id)) auto client_key = ClientKey {sender, id};
if (!clients_.contains (client_key))
{ {
auto& client = (clients_[id] = {sender, sender_port}); auto& client = (clients_[client_key] = {sender_port});
QByteArray client_version; QByteArray client_version;
QByteArray client_revision; QByteArray client_revision;
@ -194,7 +193,7 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
<< version_.toUtf8 () << revision_.toUtf8 (); << version_.toUtf8 () << revision_.toUtf8 ();
if (impl::OK == check_status (hb)) if (impl::OK == check_status (hb))
{ {
writeDatagram (message, client.sender_address_, client.sender_port_); writeDatagram (message, client_key.first, sender_port);
} }
else else
{ {
@ -204,10 +203,10 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
// we don't care if this fails to read // we don't care if this fails to read
in >> client_version >> client_revision; in >> client_version >> client_revision;
} }
Q_EMIT self_->client_opened (id, QString::fromUtf8 (client_version), Q_EMIT self_->client_opened (client_key, QString::fromUtf8 (client_version),
QString::fromUtf8 (client_revision)); QString::fromUtf8 (client_revision));
} }
clients_[id].last_activity_ = QDateTime::currentDateTime (); clients_[client_key].last_activity_ = QDateTime::currentDateTime ();
// //
// message format is described in NetworkMessage.hpp // message format is described in NetworkMessage.hpp
@ -219,7 +218,7 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
break; break;
case NetworkMessage::Clear: case NetworkMessage::Clear:
Q_EMIT self_->decodes_cleared (id); Q_EMIT self_->decodes_cleared (client_key);
break; break;
case NetworkMessage::Status: case NetworkMessage::Status:
@ -250,7 +249,8 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
>> fast_mode >> special_op_mode >> frequency_tolerance >> tr_period >> configuration_name; >> fast_mode >> special_op_mode >> frequency_tolerance >> tr_period >> configuration_name;
if (check_status (in) != Fail) if (check_status (in) != Fail)
{ {
Q_EMIT self_->status_update (id, f, QString::fromUtf8 (mode), QString::fromUtf8 (dx_call) Q_EMIT self_->status_update (client_key, f, QString::fromUtf8 (mode)
, QString::fromUtf8 (dx_call)
, QString::fromUtf8 (report), QString::fromUtf8 (tx_mode) , QString::fromUtf8 (report), QString::fromUtf8 (tx_mode)
, tx_enabled, transmitting, decoding, rx_df, tx_df , tx_enabled, transmitting, decoding, rx_df, tx_df
, QString::fromUtf8 (de_call), QString::fromUtf8 (de_grid) , QString::fromUtf8 (de_call), QString::fromUtf8 (de_grid)
@ -278,7 +278,7 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
>> message >> low_confidence >> off_air; >> message >> low_confidence >> off_air;
if (check_status (in) != Fail) if (check_status (in) != Fail)
{ {
Q_EMIT self_->decode (is_new, id, time, snr, delta_time, delta_frequency Q_EMIT self_->decode (is_new, client_key, time, snr, delta_time, delta_frequency
, QString::fromUtf8 (mode), QString::fromUtf8 (message) , QString::fromUtf8 (mode), QString::fromUtf8 (message)
, low_confidence, off_air); , low_confidence, off_air);
} }
@ -302,7 +302,7 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
>> off_air; >> off_air;
if (check_status (in) != Fail) if (check_status (in) != Fail)
{ {
Q_EMIT self_->WSPR_decode (is_new, id, time, snr, delta_time, frequency, drift Q_EMIT self_->WSPR_decode (is_new, client_key, time, snr, delta_time, frequency, drift
, QString::fromUtf8 (callsign), QString::fromUtf8 (grid) , QString::fromUtf8 (callsign), QString::fromUtf8 (grid)
, power, off_air); , power, off_air);
} }
@ -333,8 +333,10 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
>> exchange_sent >> exchange_rcvd >> prop_mode; >> exchange_sent >> exchange_rcvd >> prop_mode;
if (check_status (in) != Fail) if (check_status (in) != Fail)
{ {
Q_EMIT self_->qso_logged (id, time_off, QString::fromUtf8 (dx_call), QString::fromUtf8 (dx_grid) Q_EMIT self_->qso_logged (client_key, time_off, QString::fromUtf8 (dx_call)
, dial_frequency, QString::fromUtf8 (mode), QString::fromUtf8 (report_sent) , QString::fromUtf8 (dx_grid)
, dial_frequency, QString::fromUtf8 (mode)
, QString::fromUtf8 (report_sent)
, QString::fromUtf8 (report_received), QString::fromUtf8 (tx_power) , QString::fromUtf8 (report_received), QString::fromUtf8 (tx_power)
, QString::fromUtf8 (comments), QString::fromUtf8 (name), time_on , QString::fromUtf8 (comments), QString::fromUtf8 (name), time_on
, QString::fromUtf8 (operator_call), QString::fromUtf8 (my_call) , QString::fromUtf8 (operator_call), QString::fromUtf8 (my_call)
@ -345,8 +347,8 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
break; break;
case NetworkMessage::Close: case NetworkMessage::Close:
Q_EMIT self_->client_closed (id); Q_EMIT self_->client_closed (client_key);
clients_.remove (id); clients_.remove (client_key);
break; break;
case NetworkMessage::LoggedADIF: case NetworkMessage::LoggedADIF:
@ -355,7 +357,7 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
in >> ADIF; in >> ADIF;
if (check_status (in) != Fail) if (check_status (in) != Fail)
{ {
Q_EMIT self_->logged_ADIF (id, ADIF); Q_EMIT self_->logged_ADIF (client_key, ADIF);
} }
} }
break; break;
@ -388,7 +390,7 @@ void MessageServer::impl::tick ()
{ {
if (now > (*iter).last_activity_.addSecs (NetworkMessage::pulse)) if (now > (*iter).last_activity_.addSecs (NetworkMessage::pulse))
{ {
Q_EMIT self_->clear_decodes (iter.key ()); Q_EMIT self_->decodes_cleared (iter.key ());
Q_EMIT self_->client_closed (iter.key ()); Q_EMIT self_->client_closed (iter.key ());
iter = clients_.erase (iter); // safe while iterating as doesn't rehash iter = clients_.erase (iter); // safe while iterating as doesn't rehash
} }
@ -462,127 +464,127 @@ void MessageServer::start (port_type port, QHostAddress const& multicast_group_a
} }
} }
void MessageServer::clear_decodes (QString const& id, quint8 window) void MessageServer::clear_decodes (ClientKey const& key, quint8 window)
{ {
auto iter = m_->clients_.find (id); auto iter = m_->clients_.find (key);
if (iter != std::end (m_->clients_)) if (iter != std::end (m_->clients_))
{ {
QByteArray message; QByteArray message;
NetworkMessage::Builder out {&message, NetworkMessage::Clear, id, (*iter).negotiated_schema_number_}; NetworkMessage::Builder out {&message, NetworkMessage::Clear, key.second, (*iter).negotiated_schema_number_};
out << window; out << window;
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); m_->send_message (out, message, key.first, (*iter).sender_port_);
} }
} }
void MessageServer::reply (QString const& id, QTime time, qint32 snr, float delta_time void MessageServer::reply (ClientKey const& key, QTime time, qint32 snr, float delta_time
, quint32 delta_frequency, QString const& mode , quint32 delta_frequency, QString const& mode
, QString const& message_text, bool low_confidence, quint8 modifiers) , QString const& message_text, bool low_confidence, quint8 modifiers)
{ {
auto iter = m_->clients_.find (id); auto iter = m_->clients_.find (key);
if (iter != std::end (m_->clients_)) if (iter != std::end (m_->clients_))
{ {
QByteArray message; QByteArray message;
NetworkMessage::Builder out {&message, NetworkMessage::Reply, id, (*iter).negotiated_schema_number_}; NetworkMessage::Builder out {&message, NetworkMessage::Reply, key.second, (*iter).negotiated_schema_number_};
out << time << snr << delta_time << delta_frequency << mode.toUtf8 () out << time << snr << delta_time << delta_frequency << mode.toUtf8 ()
<< message_text.toUtf8 () << low_confidence << modifiers; << message_text.toUtf8 () << low_confidence << modifiers;
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); m_->send_message (out, message, key.first, (*iter).sender_port_);
} }
} }
void MessageServer::replay (QString const& id) void MessageServer::replay (ClientKey const& key)
{ {
auto iter = m_->clients_.find (id); auto iter = m_->clients_.find (key);
if (iter != std::end (m_->clients_)) if (iter != std::end (m_->clients_))
{ {
QByteArray message; QByteArray message;
NetworkMessage::Builder out {&message, NetworkMessage::Replay, id, (*iter).negotiated_schema_number_}; NetworkMessage::Builder out {&message, NetworkMessage::Replay, key.second, (*iter).negotiated_schema_number_};
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); m_->send_message (out, message, key.first, (*iter).sender_port_);
} }
} }
void MessageServer::close (QString const& id) void MessageServer::close (ClientKey const& key)
{ {
auto iter = m_->clients_.find (id); auto iter = m_->clients_.find (key);
if (iter != std::end (m_->clients_)) if (iter != std::end (m_->clients_))
{ {
QByteArray message; QByteArray message;
NetworkMessage::Builder out {&message, NetworkMessage::Close, id, (*iter).negotiated_schema_number_}; NetworkMessage::Builder out {&message, NetworkMessage::Close, key.second, (*iter).negotiated_schema_number_};
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); m_->send_message (out, message, key.first, (*iter).sender_port_);
} }
} }
void MessageServer::halt_tx (QString const& id, bool auto_only) void MessageServer::halt_tx (ClientKey const& key, bool auto_only)
{ {
auto iter = m_->clients_.find (id); auto iter = m_->clients_.find (key);
if (iter != std::end (m_->clients_)) if (iter != std::end (m_->clients_))
{ {
QByteArray message; QByteArray message;
NetworkMessage::Builder out {&message, NetworkMessage::HaltTx, id, (*iter).negotiated_schema_number_}; NetworkMessage::Builder out {&message, NetworkMessage::HaltTx, key.second, (*iter).negotiated_schema_number_};
out << auto_only; out << auto_only;
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); m_->send_message (out, message, key.first, (*iter).sender_port_);
} }
} }
void MessageServer::free_text (QString const& id, QString const& text, bool send) void MessageServer::free_text (ClientKey const& key, QString const& text, bool send)
{ {
auto iter = m_->clients_.find (id); auto iter = m_->clients_.find (key);
if (iter != std::end (m_->clients_)) if (iter != std::end (m_->clients_))
{ {
QByteArray message; QByteArray message;
NetworkMessage::Builder out {&message, NetworkMessage::FreeText, id, (*iter).negotiated_schema_number_}; NetworkMessage::Builder out {&message, NetworkMessage::FreeText, key.second, (*iter).negotiated_schema_number_};
out << text.toUtf8 () << send; out << text.toUtf8 () << send;
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); m_->send_message (out, message, key.first, (*iter).sender_port_);
} }
} }
void MessageServer::location (QString const& id, QString const& loc) void MessageServer::location (ClientKey const& key, QString const& loc)
{ {
auto iter = m_->clients_.find (id); auto iter = m_->clients_.find (key);
if (iter != std::end (m_->clients_)) if (iter != std::end (m_->clients_))
{ {
QByteArray message; QByteArray message;
NetworkMessage::Builder out {&message, NetworkMessage::Location, id, (*iter).negotiated_schema_number_}; NetworkMessage::Builder out {&message, NetworkMessage::Location, key.second, (*iter).negotiated_schema_number_};
out << loc.toUtf8 (); out << loc.toUtf8 ();
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); m_->send_message (out, message, key.first, (*iter).sender_port_);
} }
} }
void MessageServer::highlight_callsign (QString const& id, QString const& callsign void MessageServer::highlight_callsign (ClientKey const& key, QString const& callsign
, QColor const& bg, QColor const& fg, bool last_only) , QColor const& bg, QColor const& fg, bool last_only)
{ {
auto iter = m_->clients_.find (id); auto iter = m_->clients_.find (key);
if (iter != std::end (m_->clients_)) if (iter != std::end (m_->clients_))
{ {
QByteArray message; QByteArray message;
NetworkMessage::Builder out {&message, NetworkMessage::HighlightCallsign, id, (*iter).negotiated_schema_number_}; NetworkMessage::Builder out {&message, NetworkMessage::HighlightCallsign, key.second, (*iter).negotiated_schema_number_};
out << callsign.toUtf8 () << bg << fg << last_only; out << callsign.toUtf8 () << bg << fg << last_only;
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); m_->send_message (out, message, key.first, (*iter).sender_port_);
} }
} }
void MessageServer::switch_configuration (QString const& id, QString const& configuration_name) void MessageServer::switch_configuration (ClientKey const& key, QString const& configuration_name)
{ {
auto iter = m_->clients_.find (id); auto iter = m_->clients_.find (key);
if (iter != std::end (m_->clients_)) if (iter != std::end (m_->clients_))
{ {
QByteArray message; QByteArray message;
NetworkMessage::Builder out {&message, NetworkMessage::SwitchConfiguration, id, (*iter).negotiated_schema_number_}; NetworkMessage::Builder out {&message, NetworkMessage::SwitchConfiguration, key.second, (*iter).negotiated_schema_number_};
out << configuration_name.toUtf8 (); out << configuration_name.toUtf8 ();
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); m_->send_message (out, message, key.first, (*iter).sender_port_);
} }
} }
void MessageServer::configure (QString const& id, QString const& mode, quint32 frequency_tolerance void MessageServer::configure (ClientKey const& key, QString const& mode, quint32 frequency_tolerance
, QString const& submode, bool fast_mode, quint32 tr_period, quint32 rx_df , QString const& submode, bool fast_mode, quint32 tr_period, quint32 rx_df
, QString const& dx_call, QString const& dx_grid, bool generate_messages) , QString const& dx_call, QString const& dx_grid, bool generate_messages)
{ {
auto iter = m_->clients_.find (id); auto iter = m_->clients_.find (key);
if (iter != std::end (m_->clients_)) if (iter != std::end (m_->clients_))
{ {
QByteArray message; QByteArray message;
NetworkMessage::Builder out {&message, NetworkMessage::Configure, id, (*iter).negotiated_schema_number_}; NetworkMessage::Builder out {&message, NetworkMessage::Configure, key.second, (*iter).negotiated_schema_number_};
out << mode.toUtf8 () << frequency_tolerance << submode.toUtf8 () << fast_mode << tr_period << rx_df out << mode.toUtf8 () << frequency_tolerance << submode.toUtf8 () << fast_mode << tr_period << rx_df
<< dx_call.toUtf8 () << dx_grid.toUtf8 () << generate_messages; << dx_call.toUtf8 () << dx_grid.toUtf8 () << generate_messages;
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); m_->send_message (out, message, key.first, (*iter).sender_port_);
} }
} }

View File

@ -2,6 +2,7 @@
#define MESSAGE_SERVER_HPP__ #define MESSAGE_SERVER_HPP__
#include <QObject> #include <QObject>
#include <QPair>
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
#include <QTime> #include <QTime>
@ -33,6 +34,7 @@ class UDP_EXPORT MessageServer
public: public:
using port_type = quint16; using port_type = quint16;
using Frequency = Radio::Frequency; using Frequency = Radio::Frequency;
using ClientKey = QPair<QHostAddress, QString>;
MessageServer (QObject * parent = nullptr, MessageServer (QObject * parent = nullptr,
QString const& version = QString {}, QString const& revision = QString {}); QString const& version = QString {}, QString const& revision = QString {});
@ -45,73 +47,72 @@ public:
, QStringList const& network_interface_names = QStringList {}); , QStringList const& network_interface_names = QStringList {});
// ask the client to clear one or both of the decode windows // ask the client to clear one or both of the decode windows
Q_SLOT void clear_decodes (QString const& id, quint8 window = 0); Q_SLOT void clear_decodes (ClientKey const&, quint8 window = 0);
// ask the client with identification 'id' to make the same action // ask the client with identification 'id' to make the same action
// as a double click on the decode would // as a double click on the decode would
// //
// note that the client is not obliged to take any action and only // note that the client is not obliged to take any action and only
// takes any action if the decode is present and is a CQ or QRZ message // takes any action if the decode is present and is a CQ or QRZ message
Q_SLOT void reply (QString const& id, QTime time, qint32 snr, float delta_time, quint32 delta_frequency Q_SLOT void reply (ClientKey const&, QTime time, qint32 snr, float delta_time, quint32 delta_frequency
, QString const& mode, QString const& message, bool low_confidence, quint8 modifiers); , QString const& mode, QString const& message, bool low_confidence, quint8 modifiers);
// ask the client with identification 'id' to close down gracefully // ask the client to close down gracefully
Q_SLOT void close (QString const& id); Q_SLOT void close (ClientKey const&);
// ask the client with identification 'id' to replay all decodes // ask the client to replay all decodes
Q_SLOT void replay (QString const& id); Q_SLOT void replay (ClientKey const&);
// ask the client with identification 'id' to halt transmitting // ask the client to halt transmitting auto_only just disables auto
// auto_only just disables auto Tx, otherwise halt is immediate // Tx, otherwise halt is immediate
Q_SLOT void halt_tx (QString const& id, bool auto_only); Q_SLOT void halt_tx (ClientKey const&, bool auto_only);
// ask the client with identification 'id' to set the free text // ask the client to set the free text message and optionally send
// message and optionally send it ASAP // it ASAP
Q_SLOT void free_text (QString const& id, QString const& text, bool send); Q_SLOT void free_text (ClientKey const&, QString const& text, bool send);
// ask the client with identification 'id' to set the location provided // ask the client to set the location provided
Q_SLOT void location (QString const& id, QString const& location); Q_SLOT void location (ClientKey const&, QString const& location);
// ask the client with identification 'id' to highlight the callsign // ask the client to highlight the callsign specified with the given
// specified with the given colors // colors
Q_SLOT void highlight_callsign (QString const& id, QString const& callsign Q_SLOT void highlight_callsign (ClientKey const&, QString const& callsign
, QColor const& bg = QColor {}, QColor const& fg = QColor {} , QColor const& bg = QColor {}, QColor const& fg = QColor {}
, bool last_only = false); , bool last_only = false);
// ask the client with identification 'id' to switch to // ask the client to switch to configuration 'configuration_name'
// configuration 'configuration_name' Q_SLOT void switch_configuration (ClientKey const&, QString const& configuration_name);
Q_SLOT void switch_configuration (QString const& id, QString const& configuration_name);
// ask the client with identification 'id' to change configuration // ask the client to change configuration
Q_SLOT void configure (QString const& id, QString const& mode, quint32 frequency_tolerance Q_SLOT void configure (ClientKey const&, QString const& mode, quint32 frequency_tolerance
, QString const& submode, bool fast_mode, quint32 tr_period, quint32 rx_df , QString const& submode, bool fast_mode, quint32 tr_period, quint32 rx_df
, QString const& dx_call, QString const& dx_grid, bool generate_messages); , QString const& dx_call, QString const& dx_grid, bool generate_messages);
// the following signals are emitted when a client broadcasts the // the following signals are emitted when a client broadcasts the
// matching message // matching message
Q_SIGNAL void client_opened (QString const& id, QString const& version, QString const& revision); Q_SIGNAL void client_opened (ClientKey const&, QString const& version, QString const& revision);
Q_SIGNAL void status_update (QString const& id, Frequency, QString const& mode, QString const& dx_call Q_SIGNAL void status_update (ClientKey const&, Frequency, QString const& mode, QString const& dx_call
, QString const& report, QString const& tx_mode, bool tx_enabled , QString const& report, QString const& tx_mode, bool tx_enabled
, bool transmitting, bool decoding, quint32 rx_df, quint32 tx_df , bool transmitting, bool decoding, quint32 rx_df, quint32 tx_df
, QString const& de_call, QString const& de_grid, QString const& dx_grid , QString const& de_call, QString const& de_grid, QString const& dx_grid
, bool watchdog_timeout, QString const& sub_mode, bool fast_mode , bool watchdog_timeout, QString const& sub_mode, bool fast_mode
, quint8 special_op_mode, quint32 frequency_tolerance, quint32 tr_period , quint8 special_op_mode, quint32 frequency_tolerance, quint32 tr_period
, QString const& configuration_name); , QString const& configuration_name);
Q_SIGNAL void client_closed (QString const& id); Q_SIGNAL void client_closed (ClientKey const&);
Q_SIGNAL void decode (bool is_new, QString const& id, QTime time, qint32 snr, float delta_time Q_SIGNAL void decode (bool is_new, ClientKey const&, 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
, bool low_confidence, bool off_air); , bool low_confidence, bool off_air);
Q_SIGNAL void WSPR_decode (bool is_new, QString const& id, QTime time, qint32 snr, float delta_time, Frequency Q_SIGNAL void WSPR_decode (bool is_new, ClientKey const&, QTime time, qint32 snr, float delta_time, Frequency
, qint32 drift, QString const& callsign, QString const& grid, qint32 power , qint32 drift, QString const& callsign, QString const& grid, qint32 power
, bool off_air); , bool off_air);
Q_SIGNAL void qso_logged (QString const& id, QDateTime time_off, QString const& dx_call, QString const& dx_grid Q_SIGNAL void qso_logged (ClientKey const&, QDateTime time_off, 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
, QString const& name, QDateTime time_on, QString const& operator_call , QString const& name, QDateTime time_on, QString const& operator_call
, QString const& my_call, QString const& my_grid , QString const& my_call, QString const& my_grid
, QString const& exchange_sent, QString const& exchange_rcvd, QString const& prop_mode); , QString const& exchange_sent, QString const& exchange_rcvd, QString const& prop_mode);
Q_SIGNAL void decodes_cleared (QString const& id); Q_SIGNAL void decodes_cleared (ClientKey const&);
Q_SIGNAL void logged_ADIF (QString const& id, QByteArray const& ADIF); Q_SIGNAL void logged_ADIF (ClientKey const&, QByteArray const& ADIF);
// this signal is emitted when a network error occurs // this signal is emitted when a network error occurs
Q_SIGNAL void error (QString const&) const; Q_SIGNAL void error (QString const&) const;
@ -121,4 +122,6 @@ private:
pimpl<impl> m_; pimpl<impl> m_;
}; };
Q_DECLARE_METATYPE (MessageServer::ClientKey);
#endif #endif

View File

@ -41,15 +41,17 @@ class Client
{ {
Q_OBJECT Q_OBJECT
using ClientKey = MessageServer::ClientKey;
public: public:
explicit Client (QString const& id, QObject * parent = nullptr) explicit Client (ClientKey const& key, QObject * parent = nullptr)
: QObject {parent} : QObject {parent}
, id_ {id} , key_ {key}
, dial_frequency_ {0u} , dial_frequency_ {0u}
{ {
} }
Q_SLOT void update_status (QString const& id, Frequency f, QString const& mode, QString const& /*dx_call*/ Q_SLOT void update_status (ClientKey const& key, Frequency f, QString const& mode, QString const& /*dx_call*/
, QString const& /*report*/, QString const& /*tx_mode*/, bool /*tx_enabled*/ , QString const& /*report*/, QString const& /*tx_mode*/, bool /*tx_enabled*/
, bool /*transmitting*/, bool /*decoding*/, qint32 /*rx_df*/, qint32 /*tx_df*/ , bool /*transmitting*/, bool /*decoding*/, qint32 /*rx_df*/, qint32 /*tx_df*/
, QString const& /*de_call*/, QString const& /*de_grid*/, QString const& /*dx_grid*/ , QString const& /*de_call*/, QString const& /*de_grid*/, QString const& /*dx_grid*/
@ -57,67 +59,73 @@ public:
, quint8 /*special_op_mode*/, quint32 /*frequency_tolerance*/, quint32 /*tr_period*/ , quint8 /*special_op_mode*/, quint32 /*frequency_tolerance*/, quint32 /*tr_period*/
, QString const& /*configuration_name*/) , QString const& /*configuration_name*/)
{ {
if (id == id_) if (key == key_)
{ {
if (f != dial_frequency_) if (f != dial_frequency_)
{ {
std::cout << tr ("%1: Dial frequency changed to %2").arg (id_).arg (f).toStdString () << std::endl; std::cout << tr ("%1(%2): Dial frequency changed to %3")
.arg (key_.second).arg (key_.first.toString ()).arg (f).toStdString () << std::endl;
dial_frequency_ = f; dial_frequency_ = f;
} }
if (mode + sub_mode != mode_) if (mode + sub_mode != mode_)
{ {
std::cout << tr ("%1: Mode changed to %2").arg (id_).arg (mode + sub_mode).toStdString () << std::endl; std::cout << tr ("%1(%2): Mode changed to %3")
.arg (key_.second).arg (key_.first.toString ()).arg (mode + sub_mode).toStdString () << std::endl;
mode_ = mode + sub_mode; mode_ = mode + sub_mode;
} }
} }
} }
Q_SLOT void decode_added (bool is_new, QString const& client_id, QTime time, qint32 snr Q_SLOT void decode_added (bool is_new, ClientKey const& key, 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, bool low_confidence, bool off_air) , QString const& message, bool low_confidence, bool off_air)
{ {
if (client_id == id_) if (key == key_)
{ {
qDebug () << "new:" << is_new << "t:" << time << "snr:" << snr qDebug () << "new:" << is_new << "t:" << time << "snr:" << snr
<< "Dt:" << delta_time << "Df:" << delta_frequency << "Dt:" << delta_time << "Df:" << delta_frequency
<< "mode:" << mode << "Confidence:" << (low_confidence ? "low" : "high") << "mode:" << mode << "Confidence:" << (low_confidence ? "low" : "high")
<< "On air:" << !off_air; << "On air:" << !off_air;
std::cout << tr ("%1: Decoded %2").arg (id_).arg (message).toStdString () << std::endl; std::cout << tr ("%1(%2): Decoded %3")
.arg (key_.second).arg (key_.first.toString ()).arg (message).toStdString () << std::endl;
} }
} }
Q_SLOT void beacon_spot_added (bool is_new, QString const& client_id, QTime time, qint32 snr Q_SLOT void beacon_spot_added (bool is_new, ClientKey const& key, QTime time, qint32 snr
, float delta_time, Frequency delta_frequency, qint32 drift, QString const& callsign , float delta_time, Frequency delta_frequency, qint32 drift, QString const& callsign
, QString const& grid, qint32 power, bool off_air) , QString const& grid, qint32 power, bool off_air)
{ {
if (client_id == id_) if (key == key_)
{ {
qDebug () << "new:" << is_new << "t:" << time << "snr:" << snr qDebug () << "new:" << is_new << "t:" << time << "snr:" << snr
<< "Dt:" << delta_time << "Df:" << delta_frequency << "Dt:" << delta_time << "Df:" << delta_frequency
<< "drift:" << drift; << "drift:" << drift;
std::cout << tr ("%1: WSPR decode %2 grid %3 power: %4").arg (id_).arg (callsign).arg (grid).arg (power).toStdString () std::cout << tr ("%1(%2): WSPR decode %3 grid %4 power: %5")
.arg (key_.second).arg (key_.first.toString ()).arg (callsign).arg (grid).arg (power).toStdString ()
<< "On air:" << !off_air << std::endl; << "On air:" << !off_air << std::endl;
} }
} }
Q_SLOT void qso_logged (QString const&client_id, QDateTime time_off, QString const& dx_call, QString const& dx_grid Q_SLOT void qso_logged (ClientKey const& key, QDateTime time_off, 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& report_received, QString const& tx_power
, QString const& comments, QString const& name, QDateTime time_on , QString const& comments, QString const& name, QDateTime time_on
, QString const& operator_call, QString const& my_call, QString const& my_grid , QString const& operator_call, QString const& my_call, QString const& my_grid
, QString const& exchange_sent, QString const& exchange_rcvd, QString const& prop_mode) , QString const& exchange_sent, QString const& exchange_rcvd, QString const& prop_mode)
{ {
if (client_id == id_) if (key == key_)
{ {
qDebug () << "time_on:" << time_on << "time_off:" << time_off << "dx_call:" << dx_call << "grid:" << dx_grid qDebug () << "time_on:" << time_on << "time_off:" << time_off << "dx_call:"
<< dx_call << "grid:" << dx_grid
<< "freq:" << dial_frequency << "mode:" << mode << "rpt_sent:" << report_sent << "freq:" << dial_frequency << "mode:" << mode << "rpt_sent:" << report_sent
<< "rpt_rcvd:" << report_received << "Tx_pwr:" << tx_power << "comments:" << comments << "rpt_rcvd:" << report_received << "Tx_pwr:" << tx_power << "comments:" << comments
<< "name:" << name << "operator_call:" << operator_call << "my_call:" << my_call << "name:" << name << "operator_call:" << operator_call << "my_call:" << my_call
<< "my_grid:" << my_grid << "exchange_sent:" << exchange_sent << "my_grid:" << my_grid << "exchange_sent:" << exchange_sent
<< "exchange_rcvd:" << exchange_rcvd << "prop_mode:" << prop_mode; << "exchange_rcvd:" << exchange_rcvd << "prop_mode:" << prop_mode;
std::cout << QByteArray {80, '-'}.data () << '\n'; std::cout << QByteArray {80, '-'}.data () << '\n';
std::cout << tr ("%1: Logged %2 grid: %3 power: %4 sent: %5 recd: %6 freq: %7 time_off: %8 op: %9 my_call: %10 my_grid: %11 exchange_sent: %12 exchange_rcvd: %13 comments: %14 prop_mode: %15") std::cout << tr ("%1(%2): Logged %3 grid: %4 power: %5 sent: %6 recd: %7 freq: %8 time_off: %9 op: %10 my_call: %11 my_grid: %12 exchange_sent: %13 exchange_rcvd: %14 comments: %15 prop_mode: %16")
.arg (id_).arg (dx_call).arg (dx_grid).arg (tx_power).arg (report_sent).arg (report_received) .arg (key_.second).arg (key.first.toString ()).arg (dx_call).arg (dx_grid).arg (tx_power)
.arg (report_sent).arg (report_received)
.arg (dial_frequency).arg (time_off.toString("yyyy-MM-dd hh:mm:ss.z")).arg (operator_call) .arg (dial_frequency).arg (time_off.toString("yyyy-MM-dd hh:mm:ss.z")).arg (operator_call)
.arg (my_call).arg (my_grid).arg (exchange_sent).arg (exchange_rcvd) .arg (my_call).arg (my_grid).arg (exchange_sent).arg (exchange_rcvd)
.arg (comments).arg (prop_mode).toStdString () .arg (comments).arg (prop_mode).toStdString ()
@ -125,9 +133,9 @@ public:
} }
} }
Q_SLOT void logged_ADIF (QString const&client_id, QByteArray const& ADIF) Q_SLOT void logged_ADIF (ClientKey const& key, QByteArray const& ADIF)
{ {
if (client_id == id_) if (key == key_)
{ {
qDebug () << "ADIF:" << ADIF; qDebug () << "ADIF:" << ADIF;
std::cout << QByteArray {80, '-'}.data () << '\n'; std::cout << QByteArray {80, '-'}.data () << '\n';
@ -136,7 +144,7 @@ public:
} }
private: private:
QString id_; ClientKey key_;
Frequency dial_frequency_; Frequency dial_frequency_;
QString mode_; QString mode_;
}; };
@ -146,6 +154,8 @@ class Server
{ {
Q_OBJECT Q_OBJECT
using ClientKey = MessageServer::ClientKey;
public: public:
Server (port_type port, QHostAddress const& multicast_group, QStringList const& network_interface_names) Server (port_type port, QHostAddress const& multicast_group, QStringList const& network_interface_names)
: server_ {new MessageServer {this}} : server_ {new MessageServer {this}}
@ -161,17 +171,18 @@ public:
} }
private: private:
void add_client (QString const& id, QString const& version, QString const& revision) void add_client (ClientKey const& key, QString const& version, QString const& revision)
{ {
auto client = new Client {id}; auto client = new Client {key};
connect (server_, &MessageServer::status_update, client, &Client::update_status); connect (server_, &MessageServer::status_update, client, &Client::update_status);
connect (server_, &MessageServer::decode, client, &Client::decode_added); connect (server_, &MessageServer::decode, client, &Client::decode_added);
connect (server_, &MessageServer::WSPR_decode, client, &Client::beacon_spot_added); connect (server_, &MessageServer::WSPR_decode, client, &Client::beacon_spot_added);
connect (server_, &MessageServer::qso_logged, client, &Client::qso_logged); connect (server_, &MessageServer::qso_logged, client, &Client::qso_logged);
connect (server_, &MessageServer::logged_ADIF, client, &Client::logged_ADIF); connect (server_, &MessageServer::logged_ADIF, client, &Client::logged_ADIF);
clients_[id] = client; clients_[key] = client;
server_->replay (id); server_->replay (key);
std::cout << "Discovered WSJT-X instance: " << id.toStdString (); std::cout << "Discovered WSJT-X instance: " << key.second.toStdString ()
<< '(' << key.first.toString ().toStdString () << ')';
if (version.size ()) if (version.size ())
{ {
std::cout << " v" << version.toStdString (); std::cout << " v" << version.toStdString ();
@ -183,21 +194,22 @@ private:
std::cout << std::endl; std::cout << std::endl;
} }
void remove_client (QString const& id) void remove_client (ClientKey const& key)
{ {
auto iter = clients_.find (id); auto iter = clients_.find (key);
if (iter != std::end (clients_)) if (iter != std::end (clients_))
{ {
clients_.erase (iter); clients_.erase (iter);
(*iter)->deleteLater (); (*iter)->deleteLater ();
} }
std::cout << "Removed WSJT-X instance: " << id.toStdString () << std::endl; std::cout << "Removed WSJT-X instance: " << key.second.toStdString ()
<< '(' << key.first.toString ().toStdString () << ')' << std::endl;
} }
MessageServer * server_; MessageServer * server_;
// maps client id to clients // maps client key to clients
QHash<QString, Client *> clients_; QHash<ClientKey, Client *> clients_;
}; };
#include "UDPDaemon.moc" #include "UDPDaemon.moc"