UDPLink.h 6.11 KB
Newer Older
1 2
/****************************************************************************
 *
Gus Grubba's avatar
Gus Grubba committed
3
 * (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
4 5 6 7 8
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/
pixhawk's avatar
pixhawk committed
9 10


11
/*!
pixhawk's avatar
pixhawk committed
12 13 14 15 16 17
 * @file
 *   @brief UDP connection (server) for unmanned vehicles
 *   @author Lorenz Meier <mavteam@student.ethz.ch>
 *
 */

18
#pragma once
pixhawk's avatar
pixhawk committed
19 20 21 22 23 24

#include <QString>
#include <QList>
#include <QMap>
#include <QMutex>
#include <QUdpSocket>
25 26 27
#include <QMutexLocker>
#include <QQueue>
#include <QByteArray>
28

29 30 31 32
#if defined(QGC_ZEROCONF_ENABLED)
#include <dns_sd.h>
#endif

33
#include "QGCConfig.h"
34 35
#include "LinkManager.h"

Gus Grubba's avatar
Gus Grubba committed
36 37 38 39 40 41 42 43 44 45 46 47 48 49
class UDPCLient {
public:
    UDPCLient(const QHostAddress& address_, quint16 port_)
        : address(address_)
        , port(port_)
    {}
    UDPCLient(const UDPCLient* other)
        : address(other->address)
        , port(other->port)
    {}
    QHostAddress    address;
    quint16         port;
};

50 51
class UDPConfiguration : public LinkConfiguration
{
Don Gagne's avatar
Don Gagne committed
52
    Q_OBJECT
53 54
public:

55 56 57
    Q_PROPERTY(quint16      localPort   READ localPort  WRITE setLocalPort  NOTIFY localPortChanged)
    Q_PROPERTY(QStringList  hostList    READ hostList                       NOTIFY  hostListChanged)

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
    /*!
     * @brief Regular constructor
     *
     * @param[in] name Configuration (user friendly) name
     */
    UDPConfiguration(const QString& name);

    /*!
     * @brief Copy contructor
     *
     * When manipulating data, you create a copy of the configuration, edit it
     * and then transfer its content to the original (using copyFrom() below). Use this
     * contructor to create an editable copy.
     *
     * @param[in] source Original configuration
     */
    UDPConfiguration(UDPConfiguration* source);

Gus Grubba's avatar
Gus Grubba committed
76
    ~UDPConfiguration();
77 78 79 80 81 82 83 84 85 86 87 88 89

    /*!
     * @brief The UDP port we bind to
     *
     * @return Port number
     */
    quint16 localPort   () { return _localPort; }

    /*!
     * @brief Add a target host
     *
     * @param[in] host Host name in standard formatt, e.g. localhost:14551 or 192.168.1.1:14551
     */
90
    Q_INVOKABLE void addHost (const QString host);
91 92 93 94 95 96 97

    /*!
     * @brief Add a target host
     *
     * @param[in] host Host name, e.g. localhost or 192.168.1.1
     * @param[in] port Port number
     */
Gus Grubba's avatar
Gus Grubba committed
98
    void addHost        (const QString& host, quint16 port);
99 100 101 102 103 104

    /*!
     * @brief Remove a target host from the list
     *
     * @param[in] host Host name, e.g. localhost or 192.168.1.1
     */
105
    Q_INVOKABLE void removeHost  (const QString host);
106 107 108 109 110 111 112 113

    /*!
     * @brief Set the UDP port we bind to
     *
     * @param[in] port Port number
     */
    void setLocalPort   (quint16 port);

114 115 116 117 118 119 120 121
    /*!
     * @brief Set the UDP port to be transmit only. Receive buffer is set to zero.
     *
     */
    void setTransmitOnly (bool state) { _transmitOnly = state; }

    bool isTransmitOnly () { return _transmitOnly; }

122 123 124 125 126
    /*!
     * @brief QML Interface
     */
    QStringList hostList    () { return _hostList; }

Gus Grubba's avatar
Gus Grubba committed
127 128
    const QList<UDPCLient*> targetHosts() { return _targetHosts; }

129
    /// From LinkConfiguration
130 131 132 133 134 135
    LinkType    type                 () { return LinkConfiguration::TypeUdp; }
    void        copyFrom             (LinkConfiguration* source);
    void        loadSettings         (QSettings& settings, const QString& root);
    void        saveSettings         (QSettings& settings, const QString& root);
    void        updateSettings       ();
    bool        isAutoConnectAllowed () { return true; }
136
    bool        isHighLatencyAllowed () { return true; }
137
    QString     settingsURL          () { return "UdpSettings.qml"; }
138
    QString     settingsTitle        () { return tr("UDP Link Settings"); }
139

140 141 142 143 144 145
signals:
    void localPortChanged   ();
    void hostListChanged    ();

private:
    void _updateHostList    ();
Gus Grubba's avatar
Gus Grubba committed
146 147
    void _clearTargetHosts  ();
    void _copyFrom          (LinkConfiguration *source);
148

149
private:
Gus Grubba's avatar
Gus Grubba committed
150 151 152
    QList<UDPCLient*>   _targetHosts;
    QStringList         _hostList;      ///< Exposed to QML
    quint16             _localPort;
153
    bool                _transmitOnly;
154
};
pixhawk's avatar
pixhawk committed
155 156 157 158

class UDPLink : public LinkInterface
{
    Q_OBJECT
159

160
    friend class UDPConfiguration;
161
    friend class LinkManager;
162

pixhawk's avatar
pixhawk committed
163
public:
Gus Grubba's avatar
Gus Grubba committed
164 165 166
    void    requestReset            () override { }
    bool    isConnected             () const override;
    QString getName                 () const override;
pixhawk's avatar
pixhawk committed
167

168
    // Extensive statistics for scientific purposes
Gus Grubba's avatar
Gus Grubba committed
169 170 171
    qint64  getConnectionSpeed      () const override;
    qint64  getCurrentInDataRate    () const;
    qint64  getCurrentOutDataRate   () const;
pixhawk's avatar
pixhawk committed
172

Gus Grubba's avatar
Gus Grubba committed
173 174
    // Thread
    void    run                     () override;
175

176 177
    // These are left unimplemented in order to cause linker errors which indicate incorrect usage of
    // connect/disconnect on link directly. All connect/disconnect calls should be made through LinkManager.
Gus Grubba's avatar
Gus Grubba committed
178 179
    bool    connect                 (void);
    bool    disconnect              (void);
pixhawk's avatar
pixhawk committed
180 181

public slots:
Gus Grubba's avatar
Gus Grubba committed
182
    void    readBytes               ();
183

184
private slots:
Gus Grubba's avatar
Gus Grubba committed
185
    void    _writeBytes             (const QByteArray data) override;
pixhawk's avatar
pixhawk committed
186

oberion's avatar
oberion committed
187
private:
188
    // Links are only created/destroyed by LinkManager so constructor/destructor is not public
189
    UDPLink(SharedLinkConfigurationPointer& config);
190
    ~UDPLink();
191

192
    // From LinkInterface
Gus Grubba's avatar
Gus Grubba committed
193 194
    bool    _connect                (void) override;
    void    _disconnect             (void) override;
195

196
    bool    _isIpLocal              (const QHostAddress& add);
Gus Grubba's avatar
Gus Grubba committed
197 198 199 200 201
    bool    _hardwareConnect        ();
    void    _restartConnection      ();
    void    _registerZeroconf       (uint16_t port, const std::string& regType);
    void    _deregisterZeroconf     ();
    void    _writeDataGram          (const QByteArray data, const UDPCLient* target);
Gus Grubba's avatar
Gus Grubba committed
202 203

#if defined(QGC_ZEROCONF_ENABLED)
204 205 206
    DNSServiceRef  _dnssServiceRef;
#endif

207 208 209 210 211
    bool                    _running;
    QUdpSocket*             _socket;
    UDPConfiguration*       _udpConfig;
    bool                    _connectState;
    QList<UDPCLient*>       _sessionTargets;
212 213
    QMutex                  _sessionTargetsMutex;
    QList<QHostAddress>     _localAddresses;
pixhawk's avatar
pixhawk committed
214 215
};