diff --git a/MessageClient.cpp b/MessageClient.cpp index 94d5cdf19..c7106762d 100644 --- a/MessageClient.cpp +++ b/MessageClient.cpp @@ -21,9 +21,12 @@ class MessageClient::impl Q_OBJECT; public: - impl (QString const& id, port_type server_port, MessageClient * self) + impl (QString const& id, QString const& version, QString const& revision, + port_type server_port, MessageClient * self) : self_ {self} , id_ {id} + , version_ {version} + , revision_ {revision} , server_port_ {server_port} , schema_ {2} // use 2 prior to negotiation not 1 which is broken , heartbeat_timer_ {new QTimer {this}} @@ -66,6 +69,8 @@ public: MessageClient * self_; QString id_; + QString version_; + QString revision_; QString server_string_; port_type server_port_; QHostAddress server_; @@ -188,6 +193,11 @@ void MessageClient::impl::parse_message (QByteArray const& msg) default: // Ignore + // + // Note that although server heartbeat messages are not + // parsed here they are still partially parsed in the + // message reader class to negotiate the maximum schema + // number being used on the network. break; } } @@ -208,7 +218,8 @@ void MessageClient::impl::heartbeat () { QByteArray message; NetworkMessage::Builder hb {&message, NetworkMessage::Heartbeat, id_, schema_}; - hb << NetworkMessage::Builder::schema_number; // maximum schema number accepted + hb << NetworkMessage::Builder::schema_number // maximum schema number accepted + << version_.toUtf8 () << revision_.toUtf8 (); if (OK == check_status (hb)) { writeDatagram (message, server_, server_port_); @@ -273,9 +284,10 @@ auto MessageClient::impl::check_status (QDataStream const& stream) const -> Stre return result; } -MessageClient::MessageClient (QString const& id, QString const& server, port_type server_port, QObject * self) +MessageClient::MessageClient (QString const& id, QString const& version, QString const& revision, + QString const& server, port_type server_port, QObject * self) : QObject {self} - , m_ {id, server_port, this} + , m_ {id, version, revision, server_port, this} { connect (&*m_, static_cast (&impl::error) , [this] (impl::SocketError e) diff --git a/MessageClient.hpp b/MessageClient.hpp index bd59a71ba..d3db02f2e 100644 --- a/MessageClient.hpp +++ b/MessageClient.hpp @@ -32,7 +32,8 @@ public: // instantiate and initiate a host lookup on the server // // messages will be silently dropped until a server host lookup is complete - MessageClient (QString const& id, QString const& server, port_type server_port, QObject * parent = nullptr); + MessageClient (QString const& id, QString const& version, QString const& revision, + QString const& server, port_type server_port, QObject * parent = nullptr); // query server details QHostAddress server_address () const; diff --git a/MessageServer.cpp b/MessageServer.cpp index 5ba04fc35..6d1c6007a 100644 --- a/MessageServer.cpp +++ b/MessageServer.cpp @@ -21,8 +21,10 @@ class MessageServer::impl Q_OBJECT; public: - impl (MessageServer * self) + impl (MessageServer * self, QString const& version, QString const& revision) : self_ {self} + , version_ {version} + , revision_ {revision} , port_ {0u} , clock_ {new QTimer {this}} { @@ -60,6 +62,8 @@ public: } MessageServer * self_; + QString version_; + QString revision_; port_type port_; QHostAddress multicast_group_address_; static BindMode constexpr bind_mode_ = ShareAddress | ReuseAddressHint; @@ -145,6 +149,8 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s if (!clients_.contains (id)) { auto& client = (clients_[id] = {sender, sender_port}); + QByteArray client_version; + QByteArray client_revision; if (NetworkMessage::Heartbeat == in.type ()) { @@ -159,7 +165,8 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s // negotiated schema number QByteArray message; NetworkMessage::Builder hb {&message, NetworkMessage::Heartbeat, id, client.negotiated_schema_number_}; - hb << NetworkMessage::Builder::schema_number; // maximum schema number accepted + hb << NetworkMessage::Builder::schema_number // maximum schema number accepted + << version_.toUtf8 () << revision_.toUtf8 (); if (impl::OK == check_status (hb)) { writeDatagram (message, client.sender_address_, client.sender_port_); @@ -169,8 +176,11 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s Q_EMIT self_->error ("Error creating UDP message"); } } + // we don't care if this fails to read + in >> client_version >> client_revision; } - Q_EMIT self_->client_opened (id); + Q_EMIT self_->client_opened (id, QString::fromUtf8 (client_version), + QString::fromUtf8 (client_revision)); } clients_[id].last_activity_ = QDateTime::currentDateTime (); @@ -350,9 +360,9 @@ auto MessageServer::impl::check_status (QDataStream const& stream) const -> Stre return result; } -MessageServer::MessageServer (QObject * parent) +MessageServer::MessageServer (QObject * parent, QString const& version, QString const& revision) : QObject {parent} - , m_ {this} + , m_ {this, version, revision} { } diff --git a/MessageServer.hpp b/MessageServer.hpp index c0f2a802d..a2da57241 100644 --- a/MessageServer.hpp +++ b/MessageServer.hpp @@ -31,12 +31,14 @@ public: using port_type = quint16; using Frequency = Radio::Frequency; - MessageServer (QObject * parent = nullptr); + MessageServer (QObject * parent = nullptr, + QString const& version = QString {}, QString const& revision = QString {}); // start or restart the server, if the multicast_group_address // argument is given it is assumed to be a multicast group address // which the server will join - Q_SLOT void start (port_type port, QHostAddress const& multicast_group_address = QHostAddress {}); + Q_SLOT void start (port_type port, + QHostAddress const& multicast_group_address = QHostAddress {}); // ask the client with identification 'id' to make the same action // as a double click on the decode would @@ -59,7 +61,7 @@ public: // the following signals are emitted when a client broadcasts the // matching message - Q_SIGNAL void client_opened (QString const& id); + Q_SIGNAL void client_opened (QString const& id, QString const& version, QString const& revision); Q_SIGNAL void status_update (QString const& id, Frequency, QString const& mode, QString const& dx_call , QString const& report, QString const& tx_mode, bool tx_enabled , bool transmitting, bool decoding, qint32 rx_df, qint32 tx_df diff --git a/NetworkMessage.hpp b/NetworkMessage.hpp index 34e0d18b9..bc16a7b92 100644 --- a/NetworkMessage.hpp +++ b/NetworkMessage.hpp @@ -78,6 +78,8 @@ * Heartbeat Out/In 0 quint32 * Id (unique key) utf8 * Maximum schema number quint32 + * version utf8 + * revision utf8 * * The heartbeat message shall be sent on a periodic basis every * NetworkMessage::pulse seconds (see below), the WSJT-X diff --git a/UDPExamples/ClientWidget.cpp b/UDPExamples/ClientWidget.cpp index f542448f2..36a64796b 100644 --- a/UDPExamples/ClientWidget.cpp +++ b/UDPExamples/ClientWidget.cpp @@ -94,9 +94,27 @@ void ClientWidget::IdFilterModel::rx_df (int df) } } +namespace +{ + QString make_title (QString const& id, QString const& version, QString const& revision) + { + QString title {id}; + if (version.size ()) + { + title += QString {" v%1"}.arg (version); + } + if (revision.size ()) + { + title += QString {" (%1)"}.arg (revision); + } + return title; + } +} + ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemModel * beacons_model - , QString const& id, QWidget * parent) - : QDockWidget {id, parent} + , QString const& id, QString const& version, QString const& revision + , QWidget * parent) + : QDockWidget {make_title (id, version, revision), parent} , id_ {id} , decodes_proxy_model_ {id_} , decodes_table_view_ {new QTableView} diff --git a/UDPExamples/ClientWidget.hpp b/UDPExamples/ClientWidget.hpp index 6ffd3f085..3fc1bb35c 100644 --- a/UDPExamples/ClientWidget.hpp +++ b/UDPExamples/ClientWidget.hpp @@ -21,7 +21,8 @@ class ClientWidget public: explicit ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemModel * beacons_model - , QString const& id, QWidget * parent = nullptr); + , QString const& id, QString const& version, QString const& revision + , QWidget * parent = nullptr); Q_SLOT void update_status (QString const& id, Frequency f, QString const& mode, QString const& dx_call , QString const& report, QString const& tx_mode, bool tx_enabled diff --git a/UDPExamples/MessageAggregatorMainWindow.cpp b/UDPExamples/MessageAggregatorMainWindow.cpp index 64be884cd..660af08d6 100644 --- a/UDPExamples/MessageAggregatorMainWindow.cpp +++ b/UDPExamples/MessageAggregatorMainWindow.cpp @@ -126,9 +126,9 @@ void MessageAggregatorMainWindow::log_qso (QString const& /*id*/, QDateTime time log_table_view_->scrollToBottom (); } -void MessageAggregatorMainWindow::add_client (QString const& id) +void MessageAggregatorMainWindow::add_client (QString const& id, QString const& version, QString const& revision) { - auto dock = new ClientWidget {decodes_model_, beacons_model_, id, this}; + auto dock = new ClientWidget {decodes_model_, beacons_model_, id, version, revision, this}; dock->setAttribute (Qt::WA_DeleteOnClose); auto view_action = dock->toggleViewAction (); view_action->setEnabled (true); diff --git a/UDPExamples/MessageAggregatorMainWindow.hpp b/UDPExamples/MessageAggregatorMainWindow.hpp index b15feb9a0..4e86c9a55 100644 --- a/UDPExamples/MessageAggregatorMainWindow.hpp +++ b/UDPExamples/MessageAggregatorMainWindow.hpp @@ -32,7 +32,7 @@ public: , QString const& name); private: - void add_client (QString const& id); + void add_client (QString const& id, QString const& version, QString const& revision); void remove_client (QString const& id); QStandardItemModel * log_; diff --git a/UDPExamples/UDPDaemon.cpp b/UDPExamples/UDPDaemon.cpp index b25c12b5e..e11b28a18 100644 --- a/UDPExamples/UDPDaemon.cpp +++ b/UDPExamples/UDPDaemon.cpp @@ -112,7 +112,7 @@ public: } private: - void add_client (QString const& id) + void add_client (QString const& id, QString const& version, QString const& revision) { auto client = new Client {id}; connect (server_, &MessageServer::status_update, client, &Client::update_status); @@ -120,7 +120,16 @@ private: connect (server_, &MessageServer::WSPR_decode, client, &Client::beacon_spot_added); clients_[id] = client; server_->replay (id); - std::cout << "Discovered WSJT-X instance: " << id.toStdString () << std::endl; + std::cout << "Discovered WSJT-X instance: " << id.toStdString (); + if (version.size ()) + { + std::cout << " v" << version.toStdString (); + } + if (revision.size ()) + { + std::cout << " (" << revision.toStdString () << ")"; + } + std::cout << std::endl; } void remove_client (QString const& id) diff --git a/mainwindow.cpp b/mainwindow.cpp index 6bae14703..03f28947c 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -332,8 +332,9 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, "Please be patient,\n" "this may take a few minutes", QString {}, 0, 1, this}, m_messageClient {new MessageClient {QApplication::applicationName (), - m_config.udp_server_name (), m_config.udp_server_port (), - this}}, + version (), revision (), + m_config.udp_server_name (), m_config.udp_server_port (), + this}}, psk_Reporter {new PSK_Reporter {m_messageClient, this}}, m_manual {network_manager} {