LinkInterface.h 11.6 KB
Newer Older
1
2
/****************************************************************************
 *
3
 *   (c) 2009-2018 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.
 *
 ****************************************************************************/
9

10
#pragma once
pixhawk's avatar
pixhawk committed
11
12

#include <QThread>
13
14
15
#include <QDateTime>
#include <QMutex>
#include <QMutexLocker>
Lorenz Meier's avatar
Lorenz Meier committed
16
#include <QMetaType>
17
#include <QSharedPointer>
18
#include <QDebug>
19
#include <QTimer>
pixhawk's avatar
pixhawk committed
20

Don Gagne's avatar
Don Gagne committed
21
#include "QGCMAVLink.h"
22
#include "LinkConfiguration.h"
23
#include "MavlinkMessagesTimer.h"
Don Gagne's avatar
Don Gagne committed
24

25
26
class LinkManager;

pixhawk's avatar
pixhawk committed
27
/**
28
29
30
31
* The link interface defines the interface for all links used to communicate
* with the groundstation application.
*
**/
32
33
class LinkInterface : public QThread
{
34
    Q_OBJECT
35

36
    // Only LinkManager is allowed to create/delete or _connect/_disconnect a link
37
    friend class LinkManager;
38

39
public:    
40
    virtual ~LinkInterface() {
41
        stopMavlinkMessagesTimer();
murata's avatar
murata committed
42
        _config->setLink(nullptr);
43
    }
44

DonLakeFlyer's avatar
DonLakeFlyer committed
45
46
    Q_PROPERTY(bool active      READ active     NOTIFY activeChanged)
    Q_PROPERTY(bool isPX4Flow   READ isPX4Flow  CONSTANT)
Don Gagne's avatar
Don Gagne committed
47

acfloria's avatar
acfloria committed
48
49
    Q_INVOKABLE bool link_active(int vehicle_id) const;
    Q_INVOKABLE bool getHighLatency(void) const { return _highLatency; }
Don Gagne's avatar
Don Gagne committed
50

DonLakeFlyer's avatar
DonLakeFlyer committed
51
52
53
54
    // Property accessors
    bool active() const;
    bool isPX4Flow(void) const { return _isPX4Flow; }

55
    LinkConfiguration* getLinkConfiguration(void) { return _config.data(); }
56

57
58
59
60
61
    /* Connection management */

    /**
     * @brief Get the human readable name of this link
     */
acfloria's avatar
acfloria committed
62
    Q_INVOKABLE virtual QString getName() const = 0;
63

64
65
    virtual void requestReset() = 0;

66
67
68
69
70
    /**
     * @brief Determine the connection status
     *
     * @return True if the connection is established, false otherwise
     **/
71
    virtual bool isConnected() const = 0;
72
73
74
75

    /* Connection characteristics */

    /**
76
     * @Brief Get the maximum connection speed for this interface.
77
78
79
80
81
82
83
     *
     * The nominal data rate is the theoretical maximum data rate of the
     * interface. For 100Base-T Ethernet this would be 100 Mbit/s (100'000'000
     * Bit/s, NOT 104'857'600 Bit/s).
     *
     * @return The nominal data rate of the interface in bit per second, 0 if unknown
     **/
84
    virtual qint64 getConnectionSpeed() const = 0;
Don Gagne's avatar
Don Gagne committed
85
86
87
    
    /// @return true: This link is replaying a log file, false: Normal two-way communication link
    virtual bool isLogReplay(void) { return false; }
88

dogmaphobic's avatar
dogmaphobic committed
89
90
91
92
93
94
95
96
    /**
     * @Enable/Disable data rate collection
     **/
    void enableDataRate(bool enable)
    {
        _enableRateCollection = enable;
    }

97
98
99
100
101
102
103
104
    /**
     * @Brief Get the current incoming data rate.
     *
     * This should be over a short timespan, something like 100ms. A precise value isn't necessary,
     * and this can be filtered, but should be a reasonable estimate of current data rate.
     *
     * @return The data rate of the interface in bits per second, 0 if unknown
     **/
105
    qint64 getCurrentInputDataRate() const
106
    {
107
        return _getCurrentDataRate(_inDataIndex, _inDataWriteTimes, _inDataWriteAmounts);
108
    }
109
110
111
112
113
114
115
116
117

    /**
     * @Brief Get the current outgoing data rate.
     *
     * This should be over a short timespan, something like 100ms. A precise value isn't necessary,
     * and this can be filtered, but should be a reasonable estimate of current data rate.
     *
     * @return The data rate of the interface in bits per second, 0 if unknown
     **/
118
    qint64 getCurrentOutputDataRate() const
119
    {
120
        return _getCurrentDataRate(_outDataIndex, _outDataWriteTimes, _outDataWriteAmounts);
121
    }
122
123
124
    
    /// mavlink channel to use for this link, as used by mavlink_parse_char. The mavlink channel is only
    /// set into the link when it is added to LinkManager
125
    uint8_t mavlinkChannel(void) const;
126

Don Gagne's avatar
Don Gagne committed
127
128
129
130
131
    /// Returns whether this link is high latency or not. High latency links should only perform
    /// minimal communication with vehicle.
    ///     signals: highLatencyChanged
    bool highLatency(void) const { return _highLatency; }

Don Gagne's avatar
Don Gagne committed
132
133
134
    bool decodedFirstMavlinkPacket(void) const { return _decodedFirstMavlinkPacket; }
    bool setDecodedFirstMavlinkPacket(bool decodedFirstMavlinkPacket) { return _decodedFirstMavlinkPacket = decodedFirstMavlinkPacket; }

Don Gagne's avatar
Don Gagne committed
135
136
137
138
    // 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.
    bool connect(void);
    bool disconnect(void);
139

pixhawk's avatar
pixhawk committed
140
141
public slots:

142
143
144
145
146
    /**
     * @brief This method allows to write bytes to the interface.
     *
     * If the underlying communication is packet oriented,
     * one write command equals a datagram. In case of serial
147
148
     * communication arbitrary byte lengths can be written. The method ensures
     * thread safety regardless of the underlying LinkInterface implementation.
149
150
151
152
     *
     * @param bytes The pointer to the byte array containing the data
     * @param length The length of the data array
     **/
153
154
155
156
157
158
    void writeBytesSafe(const char *bytes, int length)
    {
        emit _invokeWriteBytes(QByteArray(bytes, length));
    }

private slots:
159
    virtual void _writeBytes(const QByteArray) = 0;
160

161
    void _activeChanged(bool active, int vehicle_id);
162
    
pixhawk's avatar
pixhawk committed
163
signals:
Don Gagne's avatar
Don Gagne committed
164
    void autoconnectChanged(bool autoconnect);
165
    void activeChanged(LinkInterface* link, bool active, int vehicle_id);
166
    void _invokeWriteBytes(QByteArray);
Don Gagne's avatar
Don Gagne committed
167
    void highLatencyChanged(bool highLatency);
168

Don Gagne's avatar
Don Gagne committed
169
170
171
    /// Signalled when a link suddenly goes away due to it being removed by for example pulling the cable to the connection.
    void connectionRemoved(LinkInterface* link);

172
173
174
175
176
177
178
179
180
181
182
183
    /**
     * @brief New data arrived
     *
     * The new data is contained in the QByteArray data. The data is copied for each
     * receiving protocol. For high-speed links like image transmission this might
     * affect performance, for control links it is however desirable to directly
     * forward the link data.
     *
     * @param data the new bytes
     */
    void bytesReceived(LinkInterface* link, QByteArray data);

Pierre TILAK's avatar
Pierre TILAK committed
184
185
186
187
188
189
190
191
192
193
    /**
     * @brief New data has been sent
     * *
     * The new data is contained in the QByteArray data.
     * The data is logged into telemetry logging system
     *
     * @param data the new bytes
     */
    void bytesSent(LinkInterface* link, QByteArray data);

194
195
196
197
198
199
200
201
202
203
204
205
206
207
    /**
     * @brief This signal is emitted instantly when the link is connected
     **/
    void connected();

    /**
     * @brief This signal is emitted instantly when the link is disconnected
     **/
    void disconnected();

    /**
     * @brief This signal is emitted if the human readable name of this link changes
     */
    void nameChanged(QString name);
pixhawk's avatar
pixhawk committed
208

Ricardo de Almeida Gonzaga's avatar
Ricardo de Almeida Gonzaga committed
209
    /** @brief Communication error occurred */
210
    void communicationError(const QString& title, const QString& error);
211

212
213
    void communicationUpdate(const QString& linkname, const QString& text);

pixhawk's avatar
pixhawk committed
214
protected:
215
    // Links are only created by LinkManager so constructor is not public
DonLakeFlyer's avatar
DonLakeFlyer committed
216
    LinkInterface(SharedLinkConfigurationPointer& config, bool isPX4Flow = false);
217

218
219
220
    /// This function logs the send times and amounts of datas for input. Data is used for calculating
    /// the transmission rate.
    ///     @param byteCount Number of bytes received
Ricardo de Almeida Gonzaga's avatar
Ricardo de Almeida Gonzaga committed
221
    ///     @param time Time in ms send occurred
222
    void _logInputDataRate(quint64 byteCount, qint64 time);
223
224
225
226
    
    /// This function logs the send times and amounts of datas for output. Data is used for calculating
    /// the transmission rate.
    ///     @param byteCount Number of bytes sent
Ricardo de Almeida Gonzaga's avatar
Ricardo de Almeida Gonzaga committed
227
    ///     @param time Time in ms receive occurred
228
229
230
    void _logOutputDataRate(quint64 byteCount, qint64 time);

    SharedLinkConfigurationPointer _config;
Don Gagne's avatar
Don Gagne committed
231
232
    bool _highLatency;

233
private:
234
235
236
237
238
239
240
241
242
243
244
245
    /**
     * @brief logDataRateToBuffer Stores transmission times/amounts for statistics
     *
     * This function logs the send times and amounts of datas to the given circular buffers.
     * This data is used for calculating the transmission rate.
     *
     * @param bytesBuffer[out] The buffer to write the bytes value into.
     * @param timeBuffer[out] The buffer to write the time value into
     * @param writeIndex[out] The write index used for this buffer.
     * @param bytes The amount of bytes transmit.
     * @param time The time (in ms) this transmission occurred.
     */
246
    void _logDataRateToBuffer(quint64 *bytesBuffer, qint64 *timeBuffer, int *writeIndex, quint64 bytes, qint64 time);
247
248
249
250
251
252

    /**
     * @brief getCurrentDataRate Get the current data rate given a data rate buffer.
     *
     * This function attempts to use the times and number of bytes transmit into a current data rate
     * estimation. Since it needs to use timestamps to get the timeperiods over when the data was sent,
253
     * this is effectively a global data rate over the last _dataRateBufferSize - 1 data points. Also note
254
255
256
257
258
259
260
     * that data points older than NOW - dataRateCurrentTimespan are ignored.
     *
     * @param index The first valid sample in the data rate buffer. Refers to the oldest time sample.
     * @param dataWriteTimes The time, in ms since epoch, that each data sample took place.
     * @param dataWriteAmounts The amount of data (in bits) that was transferred.
     * @return The bits per second of data transferrence of the interface over the last [-statsCurrentTimespan, 0] timespan.
     */
261
    qint64 _getCurrentDataRate(int index, const qint64 dataWriteTimes[], const quint64 dataWriteAmounts[]) const;
262

263
264
265
266
267
268
    /**
     * @brief Connect this interface logically
     *
     * @return True if connection could be established, false otherwise
     **/
    virtual bool _connect(void) = 0;
269

Don Gagne's avatar
Don Gagne committed
270
    virtual void _disconnect(void) = 0;
271

272
    /// Sets the mavlink channel to use for this link
273
    void _setMavlinkChannel(uint8_t channel);
274
    
275
    /**
276
     * @brief startMavlinkMessagesTimer
277
     *
278
     * Start/restart the mavlink messages timer for the specific vehicle.
acfloria's avatar
acfloria committed
279
     * If no timer exists an instance is allocated.
280
     */
281
    void startMavlinkMessagesTimer(int vehicle_id);
282
283

    /**
284
     * @brief stopMavlinkMessagesTimer
285
     *
286
     * Stop and deallocate the mavlink messages timers for all vehicles if any exists.
287
     */
288
    void stopMavlinkMessagesTimer();
289

290
291
    bool _mavlinkChannelSet;    ///< true: _mavlinkChannel has been set
    uint8_t _mavlinkChannel;    ///< mavlink channel to use for this link, as used by mavlink_parse_char
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
    
    static const int _dataRateBufferSize = 20; ///< Specify how many data points to capture for data rate calculations.
    
    static const qint64 _dataRateCurrentTimespan = 500; ///< Set the maximum age of samples to use for data calculations (ms).
    
    // Implement a simple circular buffer for storing when and how much data was received.
    // Used for calculating the incoming data rate. Use with *StatsBuffer() functions.
    int     _inDataIndex;
    quint64 _inDataWriteAmounts[_dataRateBufferSize]; // In bytes
    qint64  _inDataWriteTimes[_dataRateBufferSize]; // in ms
    
    // Implement a simple circular buffer for storing when and how much data was transmit.
    // Used for calculating the outgoing data rate. Use with *StatsBuffer() functions.
    int     _outDataIndex;
    quint64 _outDataWriteAmounts[_dataRateBufferSize]; // In bytes
    qint64  _outDataWriteTimes[_dataRateBufferSize]; // in ms
    
    mutable QMutex _dataRateMutex; // Mutex for accessing the data rate member variables
Don Gagne's avatar
Don Gagne committed
310

dogmaphobic's avatar
dogmaphobic committed
311
    bool _enableRateCollection;
Don Gagne's avatar
Don Gagne committed
312
    bool _decodedFirstMavlinkPacket;    ///< true: link has correctly decoded it's first mavlink packet
DonLakeFlyer's avatar
DonLakeFlyer committed
313
    bool _isPX4Flow;
314

315
    QMap<int /* vehicle id */, MavlinkMessagesTimer*> _mavlinkMessagesTimers;
pixhawk's avatar
pixhawk committed
316
317
};

318
typedef QSharedPointer<LinkInterface> SharedLinkInterfacePointer;
319