AirMapManager.h 9.31 KB
Newer Older
1 2
/****************************************************************************
 *
3
 *   (c) 2017 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
4 5 6 7 8 9
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

10
#pragma once
11 12 13 14

#include "QGCToolbox.h"
#include "QGCLoggingCategory.h"
#include "QmlObjectListModel.h"
15
#include "MissionItem.h"
16
#include "MultiVehicleManager.h"
17
#include "AirspaceManagement.h"
18 19 20

#include <QGeoCoordinate>
#include <QList>
21
#include <QQueue>
22
#include <QTimer>
23

24 25 26
#include <cstdint>
#include <functional>
#include <memory>
27

28 29 30 31
#include <airmap/qt/client.h>
#include <airmap/qt/logger.h>
#include <airmap/qt/types.h>
#include <airmap/traffic.h>
32

33
Q_DECLARE_LOGGING_CATEGORY(AirMapManagerLog)
34

35
/**
36 37
 * @class AirMapSharedState
 * contains state & settings that need to be shared (such as login)
38
 */
39
class AirMapSharedState : public QObject
40 41 42
{
    Q_OBJECT
public:
43 44
    struct Settings {
        QString apiKey;
45

46 47 48 49
        // login credentials
        QString clientID;
        QString userName; ///< use anonymous login if empty
        QString password;
50 51
    };

52 53
    void setSettings(const Settings& settings);
    const Settings& settings() const { return _settings; }
54

55
    void setClient(airmap::qt::Client* client) { _client = client; }
56 57

    /**
58 59
     * Get the current client instance. It can be NULL. If not NULL, it implies
     * there's an API key set.
60
     */
61 62 63
    airmap::qt::Client* client() const { return _client; }

    bool hasAPIKey() const { return _settings.apiKey != ""; }
64

65
    bool isLoggedIn() const { return _loginToken != ""; }
66

67
    using Callback = std::function<void(const QString& /* login_token */)>;
68

69
    /**
70 71
     * Do a request that requires user login: if not yet logged in, the request is queued and
     * processed after successful login, otherwise it's executed directly.
72
     */
73
    void doRequestWithLogin(const Callback& callback);
74

75 76 77 78 79
    void login();

    void logout();

    const QString& loginToken() const { return _loginToken; }
80

81
signals:
82
    void error(const QString& what, const QString& airmapdMessage, const QString& airmapdDetails);
83 84

private:
85
    void _processPendingRequests();
86

87 88 89 90 91 92
    bool _isLoginInProgress = false;
    QString _loginToken; ///< login token: empty when not logged in

    airmap::qt::Client* _client = nullptr;

    Settings _settings;
93

94
    QQueue<Callback> _pendingRequests; ///< pending requests that are processed after a successful login
95 96 97 98
};


/// class to download polygons from AirMap
99
class AirMapRestrictionManager : public AirspaceRestrictionProvider
100 101 102
{
    Q_OBJECT
public:
103
    AirMapRestrictionManager(AirMapSharedState& shared);
104

105
    void setROI(const QGeoCoordinate& center, double radiusMeters) override;
106 107

signals:
108 109
    void error(const QString& what, const QString& airmapdMessage, const QString& airmapdDetails);

110 111 112 113 114 115 116 117
private:

    enum class State {
        Idle,
        RetrieveItems,
    };

    State                   _state = State::Idle;
118
    AirMapSharedState&      _shared;
119 120
};

121

122 123 124 125 126
/// class to upload a flight
class AirMapFlightManager : public QObject
{
    Q_OBJECT
public:
127
    AirMapFlightManager(AirMapSharedState& shared);
128 129 130 131

    /// Send flight path to AirMap
    void createFlight(const QList<MissionItem*>& missionItems);

132 133 134 135
    AirspaceAuthorization::PermitStatus flightPermitStatus() const { return _flightPermitStatus; }

    const QString& flightID() const { return _currentFlightId; }

136 137 138
public slots:
    void endFlight();

139
signals:
140
    void error(const QString& what, const QString& airmapdMessage, const QString& airmapdDetails);
141 142
    void flightPermitStatusChanged();

143
private slots:
144
    void _pollBriefing();
145

146
private:
147 148 149 150 151 152

    /**
     * upload flight stored in _flight
     */
    void _uploadFlight();

153 154 155 156 157
    /**
     * query the active flights and end the first one (because only a single flight can be active at a time).
     */
    void _endFirstFlight();

158 159 160 161 162
    /**
     * implementation of endFlight()
     */
    void _endFlight(const QString& flightID);

163 164 165 166 167 168 169
    /**
     * check if the briefing response is valid and call _submitPendingFlightPlan() if it is.
     */
    void _checkForValidBriefing();

    void _submitPendingFlightPlan();

170 171
    enum class State {
        Idle,
172
        GetPilotID,
173
        FlightUpload,
174 175 176
        FlightBrief,
        FlightSubmit,
        FlightPolling, // poll & check for approval
177
        FlightEnd,
178 179 180 181 182 183 184 185 186 187 188
        EndFirstFlight, // get a list of open flights & end the first one (because there can only be 1 active at a time)
    };
    struct Flight {
        QList<QGeoCoordinate> coords;
        QGeoCoordinate takeoffCoord;
        float maxAltitude = 0;

        void reset() {
            coords.clear();
            maxAltitude = 0;
        }
189
    };
190
    Flight                              _flight; ///< flight pending to be uploaded
191

192
    State                               _state = State::Idle;
193
    AirMapSharedState&                  _shared;
194
    QString                             _currentFlightId; ///< Flight ID, empty if there is none
195 196
    QString                             _pendingFlightId; ///< current flight ID, not necessarily accepted yet (once accepted, it's equal to _currentFlightId)
    QString                             _pendingFlightPlan; ///< current flight plan, waiting to be submitted
197
    AirspaceAuthorization::PermitStatus _flightPermitStatus = AirspaceAuthorization::PermitUnknown;
198 199 200
    QString                             _pilotID; ///< Pilot ID in the form "auth0|abc123"
    bool                                _noFlightCreatedYet = true;
    QTimer                              _pollTimer; ///< timer to poll for approval check
201 202 203 204 205 206 207
};

/// class to send telemetry data to AirMap
class AirMapTelemetry : public QObject
{
    Q_OBJECT
public:
208 209
    AirMapTelemetry(AirMapSharedState& shared);
    virtual ~AirMapTelemetry() = default;
210 211 212 213 214 215 216 217

    /**
     * Setup the connection to start sending telemetry
     */
    void startTelemetryStream(const QString& flightID);

    void stopTelemetryStream();

218 219
    bool isTelemetryStreaming() const;

220
signals:
221
    void error(const QString& what, const QString& airmapdMessage, const QString& airmapdDetails);
222 223 224 225 226 227 228

public slots:
    void vehicleMavlinkMessageReceived(const mavlink_message_t& message);

private:

    void _handleGlobalPositionInt(const mavlink_message_t& message);
229 230
    void _handleGPSRawInt(const mavlink_message_t& message);

231 232 233 234 235 236 237
    enum class State {
        Idle,
        StartCommunication,
        EndCommunication,
        Streaming,
    };

238
    State                   _state = State::Idle;
239

240 241
    AirMapSharedState&      _shared;
    std::string              _key; ///< key for AES encryption (16 bytes)
242
    QString                 _flightID;
243 244

    float                   _lastHdop = 1.f;
245 246
};

247

248
class AirMapTrafficMonitor : public QObject
249 250 251
{
    Q_OBJECT
public:
252 253
    AirMapTrafficMonitor(AirMapSharedState& shared)
    : _shared(shared)
254 255
    {
    }
256 257 258
    virtual ~AirMapTrafficMonitor();

    void startConnection(const QString& flightID);
259

260
    void stop();
261 262 263 264

signals:
    void trafficUpdate(QString traffic_id, QString vehicle_id, QGeoCoordinate location, float heading);

265 266
private:
    void _update(airmap::Traffic::Update::Type type, const std::vector<airmap::Traffic::Update>& update);
267 268

private:
269 270 271 272
    QString                                               _flightID;
    AirMapSharedState&                                    _shared;
    std::shared_ptr<airmap::Traffic::Monitor>             _monitor;
    std::shared_ptr<airmap::Traffic::Monitor::Subscriber> _subscriber;
273 274 275 276
};



277 278
/// AirMap per vehicle management class.
class AirMapManagerPerVehicle : public AirspaceManagerPerVehicle
279 280 281
{
    Q_OBJECT
public:
282
    AirMapManagerPerVehicle(AirMapSharedState& shared, const Vehicle& vehicle, QGCToolbox& toolbox);
283
    virtual ~AirMapManagerPerVehicle() = default;
284 285


286
    void createFlight(const QList<MissionItem*>& missionItems) override;
287

288
    AirspaceAuthorization::PermitStatus flightPermitStatus() const override;
289

290
    void startTelemetryStream() override;
291

292
    void stopTelemetryStream() override;
293

294
    bool isTelemetryStreaming() const override;
295 296

signals:
297
    void networkError(QNetworkReply::NetworkError code, const QString& errorString, const QString& serverErrorMessage);
298

299 300
public slots:
    void endFlight() override;
301

302 303 304
protected slots:
    virtual void vehicleMavlinkMessageReceived(const mavlink_message_t& message) override;
private slots:
305
    void _flightPermitStatusChanged();
306
private:
307
    AirMapSharedState&           _shared;
308

309
    AirMapFlightManager          _flightManager;
310
    AirMapTelemetry              _telemetry;
311
    AirMapTrafficMonitor         _trafficMonitor;
312

313 314 315
    QGCToolbox&                  _toolbox;
};

316

317 318 319 320 321 322
class AirMapManager : public AirspaceManager
{
    Q_OBJECT
    
public:
    AirMapManager(QGCApplication* app, QGCToolbox* toolbox);
323
    virtual ~AirMapManager();
324 325 326 327 328 329 330 331

    void setToolbox(QGCToolbox* toolbox) override;

    AirspaceManagerPerVehicle* instantiateVehicle(const Vehicle& vehicle) override;

    AirspaceRestrictionProvider* instantiateRestrictionProvider() override;

    QString name() const override { return "AirMap"; }
332

333
private slots:
334
    void _error(const QString& what, const QString& airmapdMessage, const QString& airmapdDetails);
335 336 337 338

    void _settingsChanged();
private:

339 340 341 342
    AirMapSharedState _shared;

    std::shared_ptr<airmap::qt::Logger> _logger;
    std::shared_ptr<airmap::qt::DispatchingLogger> _dispatchingLogger;
343 344
};

345