| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  | #include "MessageServer.hpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-20 17:47:32 +00:00
										 |  |  | #include <stdexcept>
 | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  | #include <limits>
 | 
					
						
							| 
									
										
										
										
											2015-04-20 17:47:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-11 23:17:43 +00:00
										 |  |  | #include <QNetworkInterface>
 | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  | #include <QUdpSocket>
 | 
					
						
							| 
									
										
										
										
											2015-06-18 22:01:40 +00:00
										 |  |  | #include <QString>
 | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  | #include <QTimer>
 | 
					
						
							| 
									
										
										
										
											2015-04-15 19:24:41 +00:00
										 |  |  | #include <QHash>
 | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  | #include "Radio.hpp"
 | 
					
						
							| 
									
										
										
										
											2019-07-02 13:00:32 -05:00
										 |  |  | #include "Network/NetworkMessage.hpp"
 | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  | #include "qt_helpers.hpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "pimpl_impl.hpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "moc_MessageServer.cpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  | namespace | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   auto quint32_max = std::numeric_limits<quint32>::max (); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  | class MessageServer::impl | 
					
						
							|  |  |  |   : public QUdpSocket | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   Q_OBJECT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2016-12-04 00:55:15 +00:00
										 |  |  |   impl (MessageServer * self, QString const& version, QString const& revision) | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |     : self_ {self} | 
					
						
							| 
									
										
										
										
											2016-12-04 00:55:15 +00:00
										 |  |  |     , version_ {version} | 
					
						
							|  |  |  |     , revision_ {revision} | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |     , port_ {0u} | 
					
						
							|  |  |  |     , clock_ {new QTimer {this}} | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  |     // register the required types with Qt
 | 
					
						
							|  |  |  |     Radio::register_types (); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |     connect (this, &QIODevice::readyRead, this, &MessageServer::impl::pending_datagrams); | 
					
						
							| 
									
										
										
										
											2020-06-13 16:04:41 +01:00
										 |  |  | #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
 | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |     connect (this, static_cast<void (impl::*) (SocketError)> (&impl::error) | 
					
						
							|  |  |  |              , [this] (SocketError /* e */) | 
					
						
							|  |  |  |              { | 
					
						
							|  |  |  |                Q_EMIT self_->error (errorString ()); | 
					
						
							|  |  |  |              }); | 
					
						
							| 
									
										
										
										
											2020-06-13 16:04:41 +01:00
										 |  |  | #else
 | 
					
						
							|  |  |  |     connect (this, &impl::errorOccurred, [this] (SocketError /* e */) | 
					
						
							|  |  |  |                                  { | 
					
						
							|  |  |  |                                    Q_EMIT self_->error (errorString ()); | 
					
						
							|  |  |  |                                  }); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |     connect (clock_, &QTimer::timeout, this, &impl::tick); | 
					
						
							|  |  |  |     clock_->start (NetworkMessage::pulse * 1000); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |   enum StreamStatus {Fail, Short, OK}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |   void leave_multicast_group (); | 
					
						
							|  |  |  |   void join_multicast_group (); | 
					
						
							|  |  |  |   void parse_message (QHostAddress const& sender, port_type sender_port, QByteArray const& msg); | 
					
						
							|  |  |  |   void tick (); | 
					
						
							|  |  |  |   void pending_datagrams (); | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |   StreamStatus check_status (QDataStream const&) const; | 
					
						
							| 
									
										
										
										
											2015-11-13 15:44:11 +00:00
										 |  |  |   void send_message (QDataStream const& out, QByteArray const& message, QHostAddress const& address, port_type port) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |       if (OK == check_status (out)) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           writeDatagram (message, address, port); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           Q_EMIT self_->error ("Error creating UDP message"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   MessageServer * self_; | 
					
						
							| 
									
										
										
										
											2016-12-04 00:55:15 +00:00
										 |  |  |   QString version_; | 
					
						
							|  |  |  |   QString revision_; | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |   port_type port_; | 
					
						
							|  |  |  |   QHostAddress multicast_group_address_; | 
					
						
							| 
									
										
										
										
											2016-05-01 00:40:51 +00:00
										 |  |  |   static BindMode constexpr bind_mode_ = ShareAddress | ReuseAddressHint; | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |   struct Client | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2015-10-21 18:56:29 +00:00
										 |  |  |     Client () = default; | 
					
						
							|  |  |  |     Client (QHostAddress const& sender_address, port_type const& sender_port) | 
					
						
							|  |  |  |       : sender_address_ {sender_address} | 
					
						
							|  |  |  |       , sender_port_ {sender_port} | 
					
						
							|  |  |  |       , negotiated_schema_number_ {2} // not 1 because it's broken
 | 
					
						
							|  |  |  |       , last_activity_ {QDateTime::currentDateTime ()} | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     Client (Client const&) = default; | 
					
						
							|  |  |  |     Client& operator= (Client const&) = default; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |     QHostAddress sender_address_; | 
					
						
							|  |  |  |     port_type sender_port_; | 
					
						
							| 
									
										
										
										
											2015-10-21 18:56:29 +00:00
										 |  |  |     quint32 negotiated_schema_number_; | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |     QDateTime last_activity_; | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2015-04-15 19:24:41 +00:00
										 |  |  |   QHash<QString, Client> clients_; // maps id to Client
 | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |   QTimer * clock_; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-01 00:40:51 +00:00
										 |  |  | MessageServer::impl::BindMode constexpr MessageServer::impl::bind_mode_; | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-01 00:40:51 +00:00
										 |  |  | #include "MessageServer.moc"
 | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | void MessageServer::impl::leave_multicast_group () | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-01-11 23:17:43 +00:00
										 |  |  |   if (!multicast_group_address_.isNull () && BoundState == state () | 
					
						
							|  |  |  | #if QT_VERSION >= 0x050600
 | 
					
						
							|  |  |  |       && multicast_group_address_.isMulticast () | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |       ) | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-01-11 23:17:43 +00:00
										 |  |  |       for (auto const& interface : QNetworkInterface::allInterfaces ()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           if (QNetworkInterface::CanMulticast & interface.flags ()) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               leaveMulticastGroup (multicast_group_address_, interface); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MessageServer::impl::join_multicast_group () | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (BoundState == state () | 
					
						
							| 
									
										
										
										
											2019-01-11 23:17:43 +00:00
										 |  |  |       && !multicast_group_address_.isNull () | 
					
						
							|  |  |  | #if QT_VERSION >= 0x050600
 | 
					
						
							|  |  |  |       && multicast_group_address_.isMulticast () | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |       ) | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-01-14 13:41:40 +00:00
										 |  |  |       auto mcast_iface = multicastInterface (); | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |       if (IPv4Protocol == multicast_group_address_.protocol () | 
					
						
							|  |  |  |           && IPv4Protocol != localAddress ().protocol ()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           close (); | 
					
						
							|  |  |  |           bind (QHostAddress::AnyIPv4, port_, bind_mode_); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-01-11 23:17:43 +00:00
										 |  |  |       bool joined {false}; | 
					
						
							|  |  |  |       for (auto const& interface : QNetworkInterface::allInterfaces ()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           if (QNetworkInterface::CanMulticast & interface.flags ()) | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2019-01-14 13:41:40 +00:00
										 |  |  |               // Windows requires outgoing interface to match
 | 
					
						
							|  |  |  |               // interface to be joined while joining, at least for
 | 
					
						
							|  |  |  |               // IPv4 it seems to
 | 
					
						
							|  |  |  |               setMulticastInterface (interface); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-11 23:17:43 +00:00
										 |  |  |               joined |= joinMulticastGroup (multicast_group_address_, interface); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       if (!joined) | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |         { | 
					
						
							|  |  |  |           multicast_group_address_.clear (); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-01-14 13:41:40 +00:00
										 |  |  |       setMulticastInterface (mcast_iface); | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MessageServer::impl::pending_datagrams () | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   while (hasPendingDatagrams ()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       QByteArray datagram; | 
					
						
							|  |  |  |       datagram.resize (pendingDatagramSize ()); | 
					
						
							|  |  |  |       QHostAddress sender_address; | 
					
						
							|  |  |  |       port_type sender_port; | 
					
						
							|  |  |  |       if (0 <= readDatagram (datagram.data (), datagram.size (), &sender_address, &sender_port)) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           parse_message (sender_address, sender_port, datagram); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MessageServer::impl::parse_message (QHostAddress const& sender, port_type sender_port, QByteArray const& msg) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2015-04-20 17:47:32 +00:00
										 |  |  |   try | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2015-04-20 17:47:32 +00:00
										 |  |  |       //
 | 
					
						
							|  |  |  |       // message format is described in NetworkMessage.hpp
 | 
					
						
							|  |  |  |       //
 | 
					
						
							|  |  |  |       NetworkMessage::Reader in {msg}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       auto id = in.id (); | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |       if (OK == check_status (in)) | 
					
						
							| 
									
										
										
										
											2015-04-20 17:47:32 +00:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |           if (!clients_.contains (id)) | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2015-10-21 18:56:29 +00:00
										 |  |  |               auto& client = (clients_[id] = {sender, sender_port}); | 
					
						
							| 
									
										
										
										
											2016-12-04 00:55:15 +00:00
										 |  |  |               QByteArray client_version; | 
					
						
							|  |  |  |               QByteArray client_revision; | 
					
						
							| 
									
										
										
										
											2015-10-21 18:56:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |               if (NetworkMessage::Heartbeat == in.type ()) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                   // negotiate a working schema number
 | 
					
						
							|  |  |  |                   in >> client.negotiated_schema_number_; | 
					
						
							|  |  |  |                   if (OK == check_status (in)) | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                       auto sn = NetworkMessage::Builder::schema_number; | 
					
						
							|  |  |  |                       client.negotiated_schema_number_ = std::min (sn, client.negotiated_schema_number_); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                       // reply to the new client informing it of the
 | 
					
						
							|  |  |  |                       // negotiated schema number
 | 
					
						
							|  |  |  |                       QByteArray message; | 
					
						
							|  |  |  |                       NetworkMessage::Builder hb {&message, NetworkMessage::Heartbeat, id, client.negotiated_schema_number_}; | 
					
						
							| 
									
										
										
										
											2016-12-04 00:55:15 +00:00
										 |  |  |                       hb << NetworkMessage::Builder::schema_number // maximum schema number accepted
 | 
					
						
							|  |  |  |                          << version_.toUtf8 () << revision_.toUtf8 (); | 
					
						
							| 
									
										
										
										
											2015-10-21 18:56:29 +00:00
										 |  |  |                       if (impl::OK == check_status (hb)) | 
					
						
							|  |  |  |                         { | 
					
						
							|  |  |  |                           writeDatagram (message, client.sender_address_, client.sender_port_); | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                       else | 
					
						
							|  |  |  |                         { | 
					
						
							|  |  |  |                           Q_EMIT self_->error ("Error creating UDP message"); | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2016-12-04 00:55:15 +00:00
										 |  |  |                   // we don't care if this fails to read
 | 
					
						
							|  |  |  |                   in >> client_version >> client_revision; | 
					
						
							| 
									
										
										
										
											2015-10-21 18:56:29 +00:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2016-12-04 00:55:15 +00:00
										 |  |  |               Q_EMIT self_->client_opened (id, QString::fromUtf8 (client_version), | 
					
						
							|  |  |  |                                            QString::fromUtf8 (client_revision)); | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2015-10-21 18:56:29 +00:00
										 |  |  |           clients_[id].last_activity_ = QDateTime::currentDateTime (); | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |    | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |           //
 | 
					
						
							|  |  |  |           // message format is described in NetworkMessage.hpp
 | 
					
						
							|  |  |  |           //
 | 
					
						
							|  |  |  |           switch (in.type ()) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |             case NetworkMessage::Heartbeat: | 
					
						
							|  |  |  |               //nothing to do here as time out handling deals with lifetime
 | 
					
						
							|  |  |  |               break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             case NetworkMessage::Clear: | 
					
						
							| 
									
										
										
										
											2019-02-03 00:49:35 +00:00
										 |  |  |               Q_EMIT self_->decodes_cleared (id); | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |               break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             case NetworkMessage::Status: | 
					
						
							| 
									
										
										
										
											2015-04-20 17:47:32 +00:00
										 |  |  |               { | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |                 // unpack message
 | 
					
						
							|  |  |  |                 Frequency f; | 
					
						
							|  |  |  |                 QByteArray mode; | 
					
						
							|  |  |  |                 QByteArray dx_call; | 
					
						
							|  |  |  |                 QByteArray report; | 
					
						
							|  |  |  |                 QByteArray tx_mode; | 
					
						
							|  |  |  |                 bool tx_enabled {false}; | 
					
						
							|  |  |  |                 bool transmitting {false}; | 
					
						
							| 
									
										
										
										
											2015-11-13 15:44:11 +00:00
										 |  |  |                 bool decoding {false}; | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |                 quint32 rx_df {quint32_max}; | 
					
						
							|  |  |  |                 quint32 tx_df {quint32_max}; | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  |                 QByteArray de_call; | 
					
						
							|  |  |  |                 QByteArray de_grid; | 
					
						
							|  |  |  |                 QByteArray dx_grid; | 
					
						
							| 
									
										
										
										
											2016-07-08 10:25:21 +00:00
										 |  |  |                 bool watchdog_timeout {false}; | 
					
						
							| 
									
										
										
										
											2016-12-16 19:36:21 +00:00
										 |  |  |                 QByteArray sub_mode; | 
					
						
							|  |  |  |                 bool fast_mode {false}; | 
					
						
							| 
									
										
										
										
											2018-12-02 23:19:08 +00:00
										 |  |  |                 quint8 special_op_mode {0}; | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |                 quint32 frequency_tolerance {quint32_max}; | 
					
						
							|  |  |  |                 quint32 tr_period {quint32_max}; | 
					
						
							| 
									
										
										
										
											2019-06-13 01:44:28 +01:00
										 |  |  |                 QByteArray configuration_name; | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  |                 in >> f >> mode >> dx_call >> report >> tx_mode >> tx_enabled >> transmitting >> decoding | 
					
						
							| 
									
										
										
										
											2016-12-16 19:36:21 +00:00
										 |  |  |                    >> rx_df >> tx_df >> de_call >> de_grid >> dx_grid >> watchdog_timeout >> sub_mode | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |                    >> fast_mode >> special_op_mode >> frequency_tolerance >> tr_period >> configuration_name; | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |                 if (check_status (in) != Fail) | 
					
						
							|  |  |  |                   { | 
					
						
							|  |  |  |                     Q_EMIT self_->status_update (id, f, QString::fromUtf8 (mode), QString::fromUtf8 (dx_call) | 
					
						
							|  |  |  |                                                  , QString::fromUtf8 (report), QString::fromUtf8 (tx_mode) | 
					
						
							| 
									
										
										
										
											2016-05-24 10:08:35 +00:00
										 |  |  |                                                  , tx_enabled, transmitting, decoding, rx_df, tx_df | 
					
						
							|  |  |  |                                                  , QString::fromUtf8 (de_call), QString::fromUtf8 (de_grid) | 
					
						
							| 
									
										
										
										
											2016-12-16 19:36:21 +00:00
										 |  |  |                                                  , QString::fromUtf8 (dx_grid), watchdog_timeout | 
					
						
							| 
									
										
										
										
											2018-12-02 23:19:08 +00:00
										 |  |  |                                                  , QString::fromUtf8 (sub_mode), fast_mode | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  |                                                  , special_op_mode, frequency_tolerance, tr_period | 
					
						
							|  |  |  |                                                  , QString::fromUtf8 (configuration_name)); | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |                   } | 
					
						
							| 
									
										
										
										
											2015-04-20 17:47:32 +00:00
										 |  |  |               } | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |               break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             case NetworkMessage::Decode: | 
					
						
							| 
									
										
										
										
											2015-04-20 17:47:32 +00:00
										 |  |  |               { | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |                 // unpack message
 | 
					
						
							|  |  |  |                 bool is_new {true}; | 
					
						
							|  |  |  |                 QTime time; | 
					
						
							|  |  |  |                 qint32 snr; | 
					
						
							|  |  |  |                 float delta_time; | 
					
						
							|  |  |  |                 quint32 delta_frequency; | 
					
						
							|  |  |  |                 QByteArray mode; | 
					
						
							|  |  |  |                 QByteArray message; | 
					
						
							| 
									
										
										
										
											2017-09-16 22:20:59 +00:00
										 |  |  |                 bool low_confidence {false}; | 
					
						
							|  |  |  |                 bool off_air {false}; | 
					
						
							| 
									
										
										
										
											2017-07-26 21:18:59 +00:00
										 |  |  |                 in >> is_new >> time >> snr >> delta_time >> delta_frequency >> mode | 
					
						
							| 
									
										
										
										
											2017-09-16 22:20:59 +00:00
										 |  |  |                    >> message >> low_confidence >> off_air; | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |                 if (check_status (in) != Fail) | 
					
						
							|  |  |  |                   { | 
					
						
							|  |  |  |                     Q_EMIT self_->decode (is_new, id, time, snr, delta_time, delta_frequency | 
					
						
							| 
									
										
										
										
											2017-07-26 21:18:59 +00:00
										 |  |  |                                           , QString::fromUtf8 (mode), QString::fromUtf8 (message) | 
					
						
							| 
									
										
										
										
											2017-09-16 22:20:59 +00:00
										 |  |  |                                           , low_confidence, off_air); | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |                   } | 
					
						
							| 
									
										
										
										
											2015-04-20 17:47:32 +00:00
										 |  |  |               } | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |               break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-15 23:03:11 +00:00
										 |  |  |             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; | 
					
						
							| 
									
										
										
										
											2017-09-16 22:20:59 +00:00
										 |  |  |                 bool off_air {false}; | 
					
						
							|  |  |  |                 in >> is_new >> time >> snr >> delta_time >> frequency >> drift >> callsign >> grid >> power | 
					
						
							|  |  |  |                    >> off_air; | 
					
						
							| 
									
										
										
										
											2015-11-15 23:03:11 +00:00
										 |  |  |                 if (check_status (in) != Fail) | 
					
						
							|  |  |  |                   { | 
					
						
							|  |  |  |                     Q_EMIT self_->WSPR_decode (is_new, id, time, snr, delta_time, frequency, drift | 
					
						
							| 
									
										
										
										
											2017-09-16 22:20:59 +00:00
										 |  |  |                                                , QString::fromUtf8 (callsign), QString::fromUtf8 (grid) | 
					
						
							|  |  |  |                                                , power, off_air); | 
					
						
							| 
									
										
										
										
											2015-11-15 23:03:11 +00:00
										 |  |  |                   } | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |               break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |             case NetworkMessage::QSOLogged: | 
					
						
							| 
									
										
										
										
											2015-04-20 17:47:32 +00:00
										 |  |  |               { | 
					
						
							| 
									
										
										
										
											2017-09-16 22:20:59 +00:00
										 |  |  |                 QDateTime time_off; | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |                 QByteArray dx_call; | 
					
						
							|  |  |  |                 QByteArray dx_grid; | 
					
						
							|  |  |  |                 Frequency dial_frequency; | 
					
						
							|  |  |  |                 QByteArray mode; | 
					
						
							|  |  |  |                 QByteArray report_sent; | 
					
						
							|  |  |  |                 QByteArray report_received; | 
					
						
							|  |  |  |                 QByteArray tx_power; | 
					
						
							|  |  |  |                 QByteArray comments; | 
					
						
							|  |  |  |                 QByteArray name; | 
					
						
							| 
									
										
										
										
											2017-09-16 22:20:59 +00:00
										 |  |  |                 QDateTime time_on; // Note: LOTW uses TIME_ON for their +/- 30-minute time window
 | 
					
						
							| 
									
										
										
										
											2018-01-25 21:57:21 +00:00
										 |  |  |                 QByteArray operator_call; | 
					
						
							| 
									
										
										
										
											2018-02-04 22:42:35 +00:00
										 |  |  |                 QByteArray my_call; | 
					
						
							|  |  |  |                 QByteArray my_grid; | 
					
						
							| 
									
										
										
										
											2018-12-02 10:09:37 -05:00
										 |  |  |                 QByteArray exchange_sent; | 
					
						
							|  |  |  |                 QByteArray exchange_rcvd; | 
					
						
							| 
									
										
										
										
											2017-09-16 22:20:59 +00:00
										 |  |  |                 in >> time_off >> dx_call >> dx_grid >> dial_frequency >> mode >> report_sent >> report_received | 
					
						
							| 
									
										
										
										
											2018-12-02 10:09:37 -05:00
										 |  |  |                    >> tx_power >> comments >> name >> time_on >> operator_call >> my_call >> my_grid | 
					
						
							|  |  |  |                    >> exchange_sent >> exchange_rcvd; | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |                 if (check_status (in) != Fail) | 
					
						
							|  |  |  |                   { | 
					
						
							| 
									
										
										
										
											2017-09-16 22:20:59 +00:00
										 |  |  |                     Q_EMIT self_->qso_logged (id, time_off, QString::fromUtf8 (dx_call), QString::fromUtf8 (dx_grid) | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |                                               , dial_frequency, QString::fromUtf8 (mode), QString::fromUtf8 (report_sent) | 
					
						
							|  |  |  |                                               , QString::fromUtf8 (report_received), QString::fromUtf8 (tx_power) | 
					
						
							| 
									
										
										
										
											2018-02-04 22:42:35 +00:00
										 |  |  |                                               , QString::fromUtf8 (comments), QString::fromUtf8 (name), time_on | 
					
						
							|  |  |  |                                               , QString::fromUtf8 (operator_call), QString::fromUtf8 (my_call) | 
					
						
							| 
									
										
										
										
											2018-12-02 10:09:37 -05:00
										 |  |  |                                               , QString::fromUtf8 (my_grid), QString::fromUtf8 (exchange_sent) | 
					
						
							|  |  |  |                                               , QString::fromUtf8 (exchange_rcvd)); | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |                   } | 
					
						
							| 
									
										
										
										
											2015-04-20 17:47:32 +00:00
										 |  |  |               } | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |               break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             case NetworkMessage::Close: | 
					
						
							| 
									
										
										
										
											2015-11-13 15:44:11 +00:00
										 |  |  |               Q_EMIT self_->client_closed (id); | 
					
						
							|  |  |  |               clients_.remove (id); | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |               break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-04 22:42:35 +00:00
										 |  |  |             case NetworkMessage::LoggedADIF: | 
					
						
							|  |  |  |               { | 
					
						
							|  |  |  |                 QByteArray ADIF; | 
					
						
							|  |  |  |                 in >> ADIF; | 
					
						
							|  |  |  |                 if (check_status (in) != Fail) | 
					
						
							|  |  |  |                   { | 
					
						
							|  |  |  |                     Q_EMIT self_->logged_ADIF (id, ADIF); | 
					
						
							|  |  |  |                   } | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |               break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |             default: | 
					
						
							|  |  |  |               // Ignore
 | 
					
						
							|  |  |  |               break; | 
					
						
							| 
									
										
										
										
											2015-04-20 17:47:32 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           Q_EMIT self_->error ("MessageServer warning: invalid UDP message received"); | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2015-04-20 17:47:32 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |   catch (std::exception const& e) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       Q_EMIT self_->error (QString {"MessageServer exception: %1"}.arg (e.what ())); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   catch (...) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       Q_EMIT self_->error ("Unexpected exception in MessageServer"); | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MessageServer::impl::tick () | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   auto now = QDateTime::currentDateTime (); | 
					
						
							| 
									
										
										
										
											2015-10-21 18:56:29 +00:00
										 |  |  |   auto iter = std::begin (clients_); | 
					
						
							|  |  |  |   while (iter != std::end (clients_)) | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2015-04-15 19:24:41 +00:00
										 |  |  |       if (now > (*iter).last_activity_.addSecs (NetworkMessage::pulse)) | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2015-04-15 19:24:41 +00:00
										 |  |  |           Q_EMIT self_->clear_decodes (iter.key ()); | 
					
						
							|  |  |  |           Q_EMIT self_->client_closed (iter.key ()); | 
					
						
							| 
									
										
										
										
											2015-10-21 18:56:29 +00:00
										 |  |  |           iter = clients_.erase (iter); // safe while iterating as doesn't rehash
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           ++iter; | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  | auto MessageServer::impl::check_status (QDataStream const& stream) const -> StreamStatus | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   auto stat = stream.status (); | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |   StreamStatus result {Fail}; | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |   switch (stat) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case QDataStream::ReadPastEnd: | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |       result = Short; | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |       break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case QDataStream::ReadCorruptData: | 
					
						
							|  |  |  |       Q_EMIT self_->error ("Message serialization error: read corrupt data"); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case QDataStream::WriteFailed: | 
					
						
							|  |  |  |       Q_EMIT self_->error ("Message serialization error: write error"); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     default: | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |       result = OK; | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-05-07 11:31:24 +00:00
										 |  |  |   return result; | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-04 00:55:15 +00:00
										 |  |  | MessageServer::MessageServer (QObject * parent, QString const& version, QString const& revision) | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |   : QObject {parent} | 
					
						
							| 
									
										
										
										
											2016-12-04 00:55:15 +00:00
										 |  |  |   , m_ {this, version, revision} | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MessageServer::start (port_type port, QHostAddress const& multicast_group_address) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (port != m_->port_ | 
					
						
							|  |  |  |       || multicast_group_address != m_->multicast_group_address_) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       m_->leave_multicast_group (); | 
					
						
							|  |  |  |       if (impl::BoundState == m_->state ()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           m_->close (); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       m_->multicast_group_address_ = multicast_group_address; | 
					
						
							|  |  |  |       auto address = m_->multicast_group_address_.isNull () | 
					
						
							|  |  |  |         || impl::IPv4Protocol != m_->multicast_group_address_.protocol () ? QHostAddress::Any : QHostAddress::AnyIPv4; | 
					
						
							|  |  |  |       if (port && m_->bind (address, port, m_->bind_mode_)) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           m_->port_ = port; | 
					
						
							|  |  |  |           m_->join_multicast_group (); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           m_->port_ = 0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-03 00:49:35 +00:00
										 |  |  | void MessageServer::clear_decodes (QString const& id, quint8 window) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   auto iter = m_->clients_.find (id); | 
					
						
							|  |  |  |   if (iter != std::end (m_->clients_)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       QByteArray message; | 
					
						
							|  |  |  |       NetworkMessage::Builder out {&message, NetworkMessage::Clear, id, (*iter).negotiated_schema_number_}; | 
					
						
							|  |  |  |       out << window; | 
					
						
							|  |  |  |       m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-22 15:36:24 +00:00
										 |  |  | void MessageServer::reply (QString const& id, QTime time, qint32 snr, float delta_time | 
					
						
							|  |  |  |                            , quint32 delta_frequency, QString const& mode | 
					
						
							|  |  |  |                            , QString const& message_text, bool low_confidence, quint8 modifiers) | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   auto iter = m_->clients_.find (id); | 
					
						
							|  |  |  |   if (iter != std::end (m_->clients_)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       QByteArray message; | 
					
						
							| 
									
										
										
										
											2015-10-21 18:56:29 +00:00
										 |  |  |       NetworkMessage::Builder out {&message, NetworkMessage::Reply, id, (*iter).negotiated_schema_number_}; | 
					
						
							| 
									
										
										
										
											2017-07-26 21:18:59 +00:00
										 |  |  |       out << time << snr << delta_time << delta_frequency << mode.toUtf8 () | 
					
						
							| 
									
										
										
										
											2017-09-22 15:36:24 +00:00
										 |  |  |           << message_text.toUtf8 () << low_confidence << modifiers; | 
					
						
							| 
									
										
										
										
											2015-11-13 15:44:11 +00:00
										 |  |  |       m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MessageServer::replay (QString const& id) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   auto iter = m_->clients_.find (id); | 
					
						
							|  |  |  |   if (iter != std::end (m_->clients_)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       QByteArray message; | 
					
						
							| 
									
										
										
										
											2015-10-21 18:56:29 +00:00
										 |  |  |       NetworkMessage::Builder out {&message, NetworkMessage::Replay, id, (*iter).negotiated_schema_number_}; | 
					
						
							| 
									
										
										
										
											2015-11-13 15:44:11 +00:00
										 |  |  |       m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); | 
					
						
							| 
									
										
										
										
											2015-04-15 16:40:49 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-05-06 20:30:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  | void MessageServer::close (QString const& id) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   auto iter = m_->clients_.find (id); | 
					
						
							|  |  |  |   if (iter != std::end (m_->clients_)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       QByteArray message; | 
					
						
							|  |  |  |       NetworkMessage::Builder out {&message, NetworkMessage::Close, id, (*iter).negotiated_schema_number_}; | 
					
						
							|  |  |  |       m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-06 22:25:56 +00:00
										 |  |  | void MessageServer::halt_tx (QString const& id, bool auto_only) | 
					
						
							| 
									
										
										
										
											2015-05-06 20:30:29 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   auto iter = m_->clients_.find (id); | 
					
						
							|  |  |  |   if (iter != std::end (m_->clients_)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       QByteArray message; | 
					
						
							| 
									
										
										
										
											2015-10-21 18:56:29 +00:00
										 |  |  |       NetworkMessage::Builder out {&message, NetworkMessage::HaltTx, id, (*iter).negotiated_schema_number_}; | 
					
						
							| 
									
										
										
										
											2015-05-06 22:25:56 +00:00
										 |  |  |       out << auto_only; | 
					
						
							| 
									
										
										
										
											2015-11-13 15:44:11 +00:00
										 |  |  |       m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); | 
					
						
							| 
									
										
										
										
											2015-05-06 20:30:29 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-28 17:33:39 +00:00
										 |  |  | void MessageServer::free_text (QString const& id, QString const& text, bool send) | 
					
						
							| 
									
										
										
										
											2015-05-06 20:30:29 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   auto iter = m_->clients_.find (id); | 
					
						
							|  |  |  |   if (iter != std::end (m_->clients_)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       QByteArray message; | 
					
						
							| 
									
										
										
										
											2015-10-21 18:56:29 +00:00
										 |  |  |       NetworkMessage::Builder out {&message, NetworkMessage::FreeText, id, (*iter).negotiated_schema_number_}; | 
					
						
							| 
									
										
										
										
											2015-05-28 17:33:39 +00:00
										 |  |  |       out << text.toUtf8 () << send; | 
					
						
							| 
									
										
										
										
											2015-11-13 15:44:11 +00:00
										 |  |  |       m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); | 
					
						
							| 
									
										
										
										
											2015-05-06 20:30:29 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-02-04 22:42:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | void MessageServer::location (QString const& id, QString const& loc) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   auto iter = m_->clients_.find (id); | 
					
						
							|  |  |  |   if (iter != std::end (m_->clients_)) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     QByteArray message; | 
					
						
							|  |  |  |     NetworkMessage::Builder out {&message, NetworkMessage::Location, id, (*iter).negotiated_schema_number_}; | 
					
						
							|  |  |  |     out << loc.toUtf8 (); | 
					
						
							|  |  |  |     m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-03-28 22:25:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | void MessageServer::highlight_callsign (QString const& id, QString const& callsign | 
					
						
							|  |  |  |                                         , QColor const& bg, QColor const& fg, bool last_only) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   auto iter = m_->clients_.find (id); | 
					
						
							|  |  |  |   if (iter != std::end (m_->clients_)) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     QByteArray message; | 
					
						
							|  |  |  |     NetworkMessage::Builder out {&message, NetworkMessage::HighlightCallsign, id, (*iter).negotiated_schema_number_}; | 
					
						
							|  |  |  |     out << callsign.toUtf8 () << bg << fg << last_only; | 
					
						
							|  |  |  |     m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-06-13 01:44:28 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | void MessageServer::switch_configuration (QString const& id, QString const& configuration_name) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   auto iter = m_->clients_.find (id); | 
					
						
							|  |  |  |   if (iter != std::end (m_->clients_)) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     QByteArray message; | 
					
						
							|  |  |  |     NetworkMessage::Builder out {&message, NetworkMessage::SwitchConfiguration, id, (*iter).negotiated_schema_number_}; | 
					
						
							|  |  |  |     out << configuration_name.toUtf8 (); | 
					
						
							|  |  |  |     m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-06-25 14:35:58 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | void MessageServer::configure (QString const& id, QString const& mode, quint32 frequency_tolerance | 
					
						
							|  |  |  |                                , QString const& submode, bool fast_mode, quint32 tr_period, quint32 rx_df | 
					
						
							|  |  |  |                                , QString const& dx_call, QString const& dx_grid, bool generate_messages) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   auto iter = m_->clients_.find (id); | 
					
						
							|  |  |  |   if (iter != std::end (m_->clients_)) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     QByteArray message; | 
					
						
							|  |  |  |     NetworkMessage::Builder out {&message, NetworkMessage::Configure, id, (*iter).negotiated_schema_number_}; | 
					
						
							|  |  |  |     out << mode.toUtf8 () << frequency_tolerance << submode.toUtf8 () << fast_mode << tr_period << rx_df | 
					
						
							|  |  |  |         << dx_call.toUtf8 () << dx_grid.toUtf8 () << generate_messages; | 
					
						
							|  |  |  |     m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |