UASWaypointManager.cc 32.7 KB
Newer Older
pixhawk's avatar
pixhawk committed
1 2
/*=====================================================================

lm's avatar
lm committed
3
QGroundControl Open Source Ground Control Station
pixhawk's avatar
pixhawk committed
4

lm's avatar
lm committed
5
(c) 2009, 2010 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
pixhawk's avatar
pixhawk committed
6

lm's avatar
lm committed
7
This file is part of the QGROUNDCONTROL project
pixhawk's avatar
pixhawk committed
8

lm's avatar
lm committed
9
    QGROUNDCONTROL is free software: you can redistribute it and/or modify
pixhawk's avatar
pixhawk committed
10 11 12 13
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

lm's avatar
lm committed
14
    QGROUNDCONTROL is distributed in the hope that it will be useful,
pixhawk's avatar
pixhawk committed
15 16 17 18 19
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
lm's avatar
lm committed
20
    along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
pixhawk's avatar
pixhawk committed
21 22 23 24 25 26 27 28 29 30 31

======================================================================*/

/**
 * @file
 *   @brief Implementation of the waypoint protocol handler
 *
 *   @author Petri Tanskanen <mavteam@student.ethz.ch>
 *
 */

32 33
#include "UASWaypointManager.h"
#include "UAS.h"
34
#include "mavlink_types.h"
35

36
#define PROTOCOL_TIMEOUT_MS 2000    ///< maximum time to wait for pending messages until timeout
lm's avatar
lm committed
37 38
#define PROTOCOL_DELAY_MS 20        ///< minimum delay between sent messages
#define PROTOCOL_MAX_RETRIES 5      ///< maximum number of send retries (after timeout)
pixhawk's avatar
pixhawk committed
39

lm's avatar
lm committed
40
UASWaypointManager::UASWaypointManager(UAS* _uas)
41 42 43 44 45 46 47
    : uas(_uas),
      current_retries(0),
      current_wp_id(0),
      current_count(0),
      current_state(WP_IDLE),
      current_partner_systemid(0),
      current_partner_compid(0),
48 49
      currentWaypointEditable(NULL),
      protocol_timer(this)
pixhawk's avatar
pixhawk committed
50
{
51 52
    if (uas)
    {
lm's avatar
lm committed
53 54 55 56 57 58 59 60
        uasid = uas->getUASID();
        connect(&protocol_timer, SIGNAL(timeout()), this, SLOT(timeout()));
        connect(uas, SIGNAL(localPositionChanged(UASInterface*,double,double,double,quint64)), this, SLOT(handleLocalPositionChanged(UASInterface*,double,double,double,quint64)));
        connect(uas, SIGNAL(globalPositionChanged(UASInterface*,double,double,double,quint64)), this, SLOT(handleGlobalPositionChanged(UASInterface*,double,double,double,quint64)));
    }
    else
    {
        uasid = 0;
61
    }
pixhawk's avatar
pixhawk committed
62 63 64
}

void UASWaypointManager::timeout()
65
{
66
    if (current_retries > 0) {
67 68
        protocol_timer.start(PROTOCOL_TIMEOUT_MS);
        current_retries--;
69
        emit updateStatusString(tr("Timeout, retrying (retries left: %1)").arg(current_retries));
70
        // // qDebug() << "Timeout, retrying (retries left:" << current_retries << ")";
71
        if (current_state == WP_GETLIST) {
72
            sendWaypointRequestList();
73
        } else if (current_state == WP_GETLIST_GETWPS) {
74
            sendWaypointRequest(current_wp_id);
75
        } else if (current_state == WP_SENDLIST) {
76
            sendWaypointCount();
77
        } else if (current_state == WP_SENDLIST_SENDWPS) {
78
            sendWaypoint(current_wp_id);
79
        } else if (current_state == WP_CLEARLIST) {
80
            sendWaypointClearAll();
81
        } else if (current_state == WP_SETCURRENT) {
82 83
            sendWaypointSetCurrent(current_wp_id);
        }
84
    } else {
85
        protocol_timer.stop();
pixhawk's avatar
pixhawk committed
86

87
        // // qDebug() << "Waypoint transaction (state=" << current_state << ") timed out going to state WP_IDLE";
pixhawk's avatar
pixhawk committed
88

89
        emit updateStatusString("Operation timed out.");
pixhawk's avatar
pixhawk committed
90

91 92 93 94 95 96
        current_state = WP_IDLE;
        current_count = 0;
        current_wp_id = 0;
        current_partner_systemid = 0;
        current_partner_compid = 0;
    }
97 98
}

99 100 101 102
void UASWaypointManager::handleLocalPositionChanged(UASInterface* mav, double x, double y, double z, quint64 time)
{
    Q_UNUSED(mav);
    Q_UNUSED(time);
pixhawk's avatar
pixhawk committed
103
    if (waypointsEditable.count() > 0 && currentWaypointEditable && (currentWaypointEditable->getFrame() == MAV_FRAME_LOCAL_NED || currentWaypointEditable->getFrame() == MAV_FRAME_LOCAL_ENU))
104
    {
pixhawk's avatar
pixhawk committed
105 106 107
        double xdiff = x-currentWaypointEditable->getX();
        double ydiff = y-currentWaypointEditable->getY();
        double zdiff = z-currentWaypointEditable->getZ();
108 109 110 111 112 113 114
        double dist = sqrt(xdiff*xdiff + ydiff*ydiff + zdiff*zdiff);
        emit waypointDistanceChanged(dist);
    }
}

void UASWaypointManager::handleGlobalPositionChanged(UASInterface* mav, double lat, double lon, double alt, quint64 time)
{
115 116
    Q_UNUSED(mav);
    Q_UNUSED(time);
117 118 119
	Q_UNUSED(alt);
	Q_UNUSED(lon);
	Q_UNUSED(lat);
120 121 122 123 124 125
    if (waypointsEditable.count() > 0 && currentWaypointEditable && (currentWaypointEditable->getFrame() == MAV_FRAME_GLOBAL || currentWaypointEditable->getFrame() == MAV_FRAME_GLOBAL_RELATIVE_ALT))
    {
        // TODO FIXME Calculate distance
        double dist = 0;
        emit waypointDistanceChanged(dist);
    }
126 127
}

128 129
void UASWaypointManager::handleWaypointCount(quint8 systemId, quint8 compId, quint16 count)
{
130
    if (current_state == WP_GETLIST && systemId == current_partner_systemid && compId == current_partner_compid) {
131 132 133
        protocol_timer.start(PROTOCOL_TIMEOUT_MS);
        current_retries = PROTOCOL_MAX_RETRIES;

134
        // // qDebug() << "got waypoint count (" << count << ") from ID " << systemId;
pixhawk's avatar
pixhawk committed
135

136 137 138 139 140 141 142 143 144 145
        //Clear the old edit-list before receiving the new one
        if (read_to_edit == true){
            while(waypointsEditable.size()>0) {
                Waypoint *t = waypointsEditable[0];
                waypointsEditable.remove(0);
                delete t;
            }
            emit waypointEditableListChanged();
        }

146
        if (count > 0) {
pixhawk's avatar
pixhawk committed
147 148 149 150
            current_count = count;
            current_wp_id = 0;
            current_state = WP_GETLIST_GETWPS;
            sendWaypointRequest(current_wp_id);
151
        } else {
152
            protocol_timer.stop();
pixhawk's avatar
pixhawk committed
153
            emit updateStatusString("done.");
154
            // // qDebug() << "No waypoints on UAS " << systemId;
155 156 157 158 159
            current_state = WP_IDLE;
            current_count = 0;
            current_wp_id = 0;
            current_partner_systemid = 0;
            current_partner_compid = 0;
pixhawk's avatar
pixhawk committed
160
        }
161 162


163 164
    } else {
        qDebug("Rejecting message, check mismatch: current_state: %d == %d, system id %d == %d, comp id %d == %d", current_state, WP_GETLIST, current_partner_systemid, systemId, current_partner_compid, compId);
165
    }
166 167
}

lm's avatar
lm committed
168
void UASWaypointManager::handleWaypoint(quint8 systemId, quint8 compId, mavlink_mission_item_t *wp)
pixhawk's avatar
pixhawk committed
169
{
170
    if (systemId == current_partner_systemid && compId == current_partner_compid && current_state == WP_GETLIST_GETWPS && wp->seq == current_wp_id) {
171 172 173
        protocol_timer.start(PROTOCOL_TIMEOUT_MS);
        current_retries = PROTOCOL_MAX_RETRIES;

174
        if(wp->seq == current_wp_id) {
175
            //// // qDebug() << "Got WP: " << wp->seq << wp->x <<  wp->y << wp->z << wp->param4 << "auto:" << wp->autocontinue << "curr:" << wp->current << wp->param1 << wp->param2 << "Frame:"<< (MAV_FRAME) wp->frame << "Command:" << (MAV_CMD) wp->command;
pixhawk's avatar
pixhawk committed
176 177 178 179 180 181 182 183 184 185 186

            Waypoint *lwp_vo = new Waypoint(wp->seq, wp->x, wp->y, wp->z, wp->param1, wp->param2, wp->param3, wp->param4, wp->autocontinue, wp->current, (MAV_FRAME) wp->frame, (MAV_CMD) wp->command);
            addWaypointViewOnly(lwp_vo);


            if (read_to_edit == true) {
                Waypoint *lwp_ed = new Waypoint(wp->seq, wp->x, wp->y, wp->z, wp->param1, wp->param2, wp->param3, wp->param4, wp->autocontinue, wp->current, (MAV_FRAME) wp->frame, (MAV_CMD) wp->command);
                addWaypointEditable(lwp_ed, false);
                if (wp->current == 1) currentWaypointEditable = lwp_ed;
            }

pixhawk's avatar
pixhawk committed
187 188 189 190

            //get next waypoint
            current_wp_id++;

191
            if(current_wp_id < current_count) {
192
                sendWaypointRequest(current_wp_id);
193
            } else {
194 195
                sendWaypointAck(0);

pixhawk's avatar
pixhawk committed
196
                // all waypoints retrieved, change state to idle
pixhawk's avatar
pixhawk committed
197 198 199 200 201
                current_state = WP_IDLE;
                current_count = 0;
                current_wp_id = 0;
                current_partner_systemid = 0;
                current_partner_compid = 0;
202

pixhawk's avatar
pixhawk committed
203
                protocol_timer.stop();
204
                emit readGlobalWPFromUAS(false);
205
                //if (currentWaypointEditable) emit currentWaypointChanged(currentWaypointEditable->getId());
206 207
                emit updateStatusString("done.");

208
                // // qDebug() << "got all waypoints from ID " << systemId;
pixhawk's avatar
pixhawk committed
209
            }
210
        } else {
211
            emit updateStatusString(tr("Waypoint ID mismatch, rejecting waypoint"));
pixhawk's avatar
pixhawk committed
212
        }
213 214
    } else {
        qDebug("Rejecting message, check mismatch: current_state: %d == %d, system id %d == %d, comp id %d == %d", current_state, WP_GETLIST, current_partner_systemid, systemId, current_partner_compid, compId);
215
    }
pixhawk's avatar
pixhawk committed
216 217
}

lm's avatar
lm committed
218
void UASWaypointManager::handleWaypointAck(quint8 systemId, quint8 compId, mavlink_mission_ack_t *wpa)
219
{
220 221
    if (systemId == current_partner_systemid && compId == current_partner_compid) {
        if((current_state == WP_SENDLIST || current_state == WP_SENDLIST_SENDWPS) && (current_wp_id == waypoint_buffer.count()-1 && wpa->type == 0)) {
222 223
            //all waypoints sent and ack received
            protocol_timer.stop();
224
            current_state = WP_IDLE;
225
            readWaypoints(false); //Update "Onboard Waypoints"-tab immidiately after the waypoint list has been sent.
226
            emit updateStatusString("done.");
227
            // // qDebug() << "sent all waypoints to ID " << systemId;
228
        } else if(current_state == WP_CLEARLIST) {
229 230 231
            protocol_timer.stop();
            current_state = WP_IDLE;
            emit updateStatusString("done.");
232
            // // qDebug() << "cleared waypoint list of ID " << systemId;
233
        }
234 235 236
    }
}

lm's avatar
lm committed
237
void UASWaypointManager::handleWaypointRequest(quint8 systemId, quint8 compId, mavlink_mission_request_t *wpr)
238
{
239
    if (systemId == current_partner_systemid && compId == current_partner_compid && ((current_state == WP_SENDLIST && wpr->seq == 0) || (current_state == WP_SENDLIST_SENDWPS && (wpr->seq == current_wp_id || wpr->seq == current_wp_id + 1)))) {
240 241
        protocol_timer.start(PROTOCOL_TIMEOUT_MS);
        current_retries = PROTOCOL_MAX_RETRIES;
242

243
        if (wpr->seq < waypoint_buffer.count()) {
pixhawk's avatar
pixhawk committed
244 245 246
            current_state = WP_SENDLIST_SENDWPS;
            current_wp_id = wpr->seq;
            sendWaypoint(current_wp_id);
247
        } else {
pixhawk's avatar
pixhawk committed
248 249
            //TODO: Error message or something
        }
250 251
    } else {
        qDebug("Rejecting message, check mismatch: current_state: %d == %d, system id %d == %d, comp id %d == %d", current_state, WP_GETLIST, current_partner_systemid, systemId, current_partner_compid, compId);
252
    }
253 254
}

lm's avatar
lm committed
255
void UASWaypointManager::handleWaypointReached(quint8 systemId, quint8 compId, mavlink_mission_item_reached_t *wpr)
256
{
257
	Q_UNUSED(compId);
lm's avatar
lm committed
258
    if (!uas) return;
259
    if (systemId == uasid) {
pixhawk's avatar
pixhawk committed
260 261
        emit updateStatusString(QString("Reached waypoint %1").arg(wpr->seq));
    }
pixhawk's avatar
pixhawk committed
262 263
}

lm's avatar
lm committed
264
void UASWaypointManager::handleWaypointCurrent(quint8 systemId, quint8 compId, mavlink_mission_current_t *wpc)
pixhawk's avatar
pixhawk committed
265
{
266
    Q_UNUSED(compId);
lm's avatar
lm committed
267
    if (!uas) return;
268
    if (systemId == uasid) {
269
        // FIXME Petri
270
        if (current_state == WP_SETCURRENT) {
271 272
            protocol_timer.stop();
            current_state = WP_IDLE;
273 274

            // update the local main storage
pixhawk's avatar
pixhawk committed
275 276 277 278 279
            if (wpc->seq < waypointsViewOnly.size()) {
                for(int i = 0; i < waypointsViewOnly.size(); i++) {
                    if (waypointsViewOnly[i]->getId() == wpc->seq) {
                        waypointsViewOnly[i]->setCurrent(true);
                        //currentWaypointEditable = waypoints[i];
280
                    } else {
pixhawk's avatar
pixhawk committed
281
                        waypointsViewOnly[i]->setCurrent(false);
282 283 284
                    }
                }
            }
285
        }
286 287 288
        emit updateStatusString(QString("New current waypoint %1").arg(wpc->seq));
        //emit update to UI widgets
        emit currentWaypointChanged(wpc->seq);
pixhawk's avatar
pixhawk committed
289
    }
pixhawk's avatar
pixhawk committed
290 291
}

292
void UASWaypointManager::notifyOfChangeEditable(Waypoint* wp)
293
{
294
    // // qDebug() << "WAYPOINT CHANGED: ID:" << wp->getId();
295
    // If only one waypoint was changed, emit only WP signal
296
    if (wp != NULL) {
297
        emit waypointEditableChanged(uasid, wp);
298
    } else {
299
        emit waypointEditableListChanged();
300
        emit waypointEditableListChanged(uasid);
301
    }
302 303
}

304 305 306
void UASWaypointManager::notifyOfChangeViewOnly(Waypoint* wp)
{
    if (wp != NULL) {
307
        emit waypointViewOnlyChanged(uasid, wp);
308 309
    } else {
        emit waypointViewOnlyListChanged();
310
        emit waypointViewOnlyListChanged(uasid);
311 312
    }
}
313 314


315
int UASWaypointManager::setCurrentWaypoint(quint16 seq)
pixhawk's avatar
pixhawk committed
316
{
pixhawk's avatar
pixhawk committed
317
    if (seq < waypointsViewOnly.size()) {
318
        if(current_state == WP_IDLE) {
319

320 321 322 323 324 325
            //send change to UAS - important to note: if the transmission fails, we have inconsistencies
            protocol_timer.start(PROTOCOL_TIMEOUT_MS);
            current_retries = PROTOCOL_MAX_RETRIES;

            current_state = WP_SETCURRENT;
            current_wp_id = seq;
326
            current_partner_systemid = uasid;
lm's avatar
lm committed
327
            current_partner_compid = MAV_COMP_ID_MISSIONPLANNER;
328 329 330 331 332 333 334 335 336 337 338

            sendWaypointSetCurrent(current_wp_id);

            //emit waypointListChanged();

            return 0;
        }
    }
    return -1;
}

339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
int UASWaypointManager::setCurrentEditable(quint16 seq)
{
    if (seq < waypointsEditable.size()) {
        if(current_state == WP_IDLE) {
            //update local main storage
            for(int i = 0; i < waypointsEditable.size(); i++) {
                if (waypointsEditable[i]->getId() == seq) {
                    waypointsEditable[i]->setCurrent(true);
                    //currentWaypointEditable = waypoints[i];
                } else {
                    waypointsEditable[i]->setCurrent(false);
                }
            }

            return 0;
        }
    }
    return -1;
}
pixhawk's avatar
pixhawk committed
358 359 360 361

void UASWaypointManager::addWaypointViewOnly(Waypoint *wp)
{
    if (wp)
362
    {
pixhawk's avatar
pixhawk committed
363 364 365 366
        waypointsViewOnly.insert(waypointsViewOnly.size(), wp);
        connect(wp, SIGNAL(changed(Waypoint*)), this, SLOT(notifyOfChangeViewOnly(Waypoint*)));

        emit waypointViewOnlyListChanged();
367
        emit waypointViewOnlyListChanged(uasid);
pixhawk's avatar
pixhawk committed
368 369 370 371
    }
}


pixhawk's avatar
pixhawk committed
372
/**
373
 * @warning Make sure the waypoint stays valid for the whole application lifecycle!
pixhawk's avatar
pixhawk committed
374
 * @param enforceFirstActive Enforces that the first waypoint is set as active
375
 * @see createWaypoint() is more suitable for most use cases
pixhawk's avatar
pixhawk committed
376
 */
377
void UASWaypointManager::addWaypointEditable(Waypoint *wp, bool enforceFirstActive)
378
{
lm's avatar
lm committed
379 380
    if (wp)
    {
pixhawk's avatar
pixhawk committed
381 382
        wp->setId(waypointsEditable.size());
        if (enforceFirstActive && waypointsEditable.size() == 0)
383 384
        {
            wp->setCurrent(true);
pixhawk's avatar
pixhawk committed
385
            currentWaypointEditable = wp;
386
        }
pixhawk's avatar
pixhawk committed
387
        waypointsEditable.insert(waypointsEditable.size(), wp);
388
        connect(wp, SIGNAL(changed(Waypoint*)), this, SLOT(notifyOfChangeEditable(Waypoint*)));
389

390
        emit waypointEditableListChanged();
391
        emit waypointEditableListChanged(uasid);
392
    }
pixhawk's avatar
pixhawk committed
393 394
}

395 396 397 398 399 400
/**
 * @param enforceFirstActive Enforces that the first waypoint is set as active
 */
Waypoint* UASWaypointManager::createWaypoint(bool enforceFirstActive)
{
    Waypoint* wp = new Waypoint();
pixhawk's avatar
pixhawk committed
401 402
    wp->setId(waypointsEditable.size());
    if (enforceFirstActive && waypointsEditable.size() == 0)
403 404
    {
        wp->setCurrent(true);
pixhawk's avatar
pixhawk committed
405
        currentWaypointEditable = wp;
406
    }
pixhawk's avatar
pixhawk committed
407
    waypointsEditable.insert(waypointsEditable.size(), wp);
408
    connect(wp, SIGNAL(changed(Waypoint*)), this, SLOT(notifyOfChangeEditable(Waypoint*)));
409

410
    emit waypointEditableListChanged();
411
    emit waypointEditableListChanged(uasid);
412 413 414
    return wp;
}

415
int UASWaypointManager::removeWaypoint(quint16 seq)
416
{
pixhawk's avatar
pixhawk committed
417
    if (seq < waypointsEditable.size())
418
    {
pixhawk's avatar
pixhawk committed
419
        Waypoint *t = waypointsEditable[seq];
420 421 422 423 424 425 426 427 428 429 430 431 432

        if (t->getCurrent() == true) //trying to remove the current waypoint
        {
            if (seq+1 < waypointsEditable.size()) // setting the next waypoint as current
            {
                waypointsEditable[seq+1]->setCurrent(true);
            }
            else if (seq-1 >= 0) //if deleting the last on the list, then setting the previous waypoint as current
            {
                waypointsEditable[seq-1]->setCurrent(true);
            }
        }

pixhawk's avatar
pixhawk committed
433
        waypointsEditable.remove(seq);
434
        delete t;
435
        t = NULL;
436

pixhawk's avatar
pixhawk committed
437
        for(int i = seq; i < waypointsEditable.size(); i++)
438
        {
pixhawk's avatar
pixhawk committed
439
            waypointsEditable[i]->setId(i);
440
        }
Alejandro's avatar
Alejandro committed
441

442
        emit waypointEditableListChanged();
443
        emit waypointEditableListChanged(uasid);
444 445 446 447 448
        return 0;
    }
    return -1;
}

449
void UASWaypointManager::moveWaypoint(quint16 cur_seq, quint16 new_seq)
450
{
pixhawk's avatar
pixhawk committed
451
    if (cur_seq != new_seq && cur_seq < waypointsEditable.size() && new_seq < waypointsEditable.size())
452
    {
pixhawk's avatar
pixhawk committed
453
        Waypoint *t = waypointsEditable[cur_seq];
454
        if (cur_seq < new_seq) {
455 456
            for (int i = cur_seq; i < new_seq; i++)
            {
pixhawk's avatar
pixhawk committed
457
                waypointsEditable[i] = waypointsEditable[i+1];
458
                waypointsEditable[i]->setId(i);
459
            }
460 461 462 463 464
        }
        else
        {
            for (int i = cur_seq; i > new_seq; i--)
            {
pixhawk's avatar
pixhawk committed
465
                waypointsEditable[i] = waypointsEditable[i-1];
466
                waypointsEditable[i]->setId(i);
467 468
            }
        }
pixhawk's avatar
pixhawk committed
469
        waypointsEditable[new_seq] = t;
470
        waypointsEditable[new_seq]->setId(new_seq);
471

472
        emit waypointEditableListChanged();
473
        emit waypointEditableListChanged(uasid);
474 475 476
    }
}

477
void UASWaypointManager::saveWaypoints(const QString &saveFile)
478 479 480 481 482 483
{
    QFile file(saveFile);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
        return;

    QTextStream out(&file);
484 485

    //write the waypoint list version to the first line for compatibility check
486
    out << "QGC WPL 120\r\n";
487

pixhawk's avatar
pixhawk committed
488
    for (int i = 0; i < waypointsEditable.size(); i++)
489
    {
pixhawk's avatar
pixhawk committed
490 491
        waypointsEditable[i]->setId(i);
        waypointsEditable[i]->save(out);
492 493 494 495
    }
    file.close();
}

496
void UASWaypointManager::loadWaypoints(const QString &loadFile)
497 498 499 500 501
{
    QFile file(loadFile);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
        return;

pixhawk's avatar
pixhawk committed
502 503 504
    while(waypointsEditable.size()>0) {
        Waypoint *t = waypointsEditable[0];
        waypointsEditable.remove(0);
505 506 507 508
        delete t;
    }

    QTextStream in(&file);
509 510 511

    const QStringList &version = in.readLine().split(" ");

512
    if (!(version.size() == 3 && version[0] == "QGC" && version[1] == "WPL" && version[2] == "120"))
513
    {
514
        emit updateStatusString(tr("The waypoint file is not compatible with the current version of QGroundControl."));
515 516 517 518 519
    }
    else
    {
        while (!in.atEnd())
        {
520
            Waypoint *t = new Waypoint();
521 522
            if(t->load(in))
            {
pixhawk's avatar
pixhawk committed
523 524
                t->setId(waypointsEditable.size());
                waypointsEditable.insert(waypointsEditable.size(), t);
525 526 527
            }
            else
            {
528 529
                emit updateStatusString(tr("The waypoint file is corrupted. Load operation only partly succesful."));
                //MainWindow::instance()->showCriticalMessage(tr("Error loading waypoint file"),);
530 531
                break;
            }
532 533
        }
    }
534

535 536
    file.close();

537
    emit loadWPFile();
538
    emit waypointEditableListChanged();
539
    emit waypointEditableListChanged(uasid);
540 541 542
}

void UASWaypointManager::clearWaypointList()
pixhawk's avatar
pixhawk committed
543
{
544 545
    if(current_state == WP_IDLE)
    {
pixhawk's avatar
pixhawk committed
546
        protocol_timer.start(PROTOCOL_TIMEOUT_MS);
547
        current_retries = PROTOCOL_MAX_RETRIES;
pixhawk's avatar
pixhawk committed
548

549 550
        current_state = WP_CLEARLIST;
        current_wp_id = 0;
551
        current_partner_systemid = uasid;
lm's avatar
lm committed
552
        current_partner_compid = MAV_COMP_ID_MISSIONPLANNER;
pixhawk's avatar
pixhawk committed
553

554
        sendWaypointClearAll();
555 556 557
    }
}

558 559 560 561 562 563
const QVector<Waypoint *> UASWaypointManager::getGlobalFrameWaypointList()
{
    // TODO Keep this global frame list up to date
    // with complete waypoint list
    // instead of filtering on each request
    QVector<Waypoint*> wps;
pixhawk's avatar
pixhawk committed
564
    foreach (Waypoint* wp, waypointsEditable)
565 566 567
    {
        if (wp->getFrame() == MAV_FRAME_GLOBAL || wp->getFrame() == MAV_FRAME_GLOBAL_RELATIVE_ALT)
        {
568 569 570 571 572 573
            wps.append(wp);
        }
    }
    return wps;
}

lm's avatar
lm committed
574 575 576 577 578 579
const QVector<Waypoint *> UASWaypointManager::getGlobalFrameAndNavTypeWaypointList()
{
    // TODO Keep this global frame list up to date
    // with complete waypoint list
    // instead of filtering on each request
    QVector<Waypoint*> wps;
pixhawk's avatar
pixhawk committed
580
    foreach (Waypoint* wp, waypointsEditable)
581 582 583
    {
        if ((wp->getFrame() == MAV_FRAME_GLOBAL || wp->getFrame() == MAV_FRAME_GLOBAL_RELATIVE_ALT) && wp->isNavigationType())
        {
lm's avatar
lm committed
584 585 586 587 588 589
            wps.append(wp);
        }
    }
    return wps;
}

LM's avatar
LM committed
590 591 592 593 594 595
const QVector<Waypoint *> UASWaypointManager::getNavTypeWaypointList()
{
    // TODO Keep this global frame list up to date
    // with complete waypoint list
    // instead of filtering on each request
    QVector<Waypoint*> wps;
pixhawk's avatar
pixhawk committed
596
    foreach (Waypoint* wp, waypointsEditable)
597 598 599
    {
        if (wp->isNavigationType())
        {
LM's avatar
LM committed
600 601 602 603 604 605
            wps.append(wp);
        }
    }
    return wps;
}

606 607
int UASWaypointManager::getIndexOf(Waypoint* wp)
{
pixhawk's avatar
pixhawk committed
608
    return waypointsEditable.indexOf(wp);
609 610
}

611 612
int UASWaypointManager::getGlobalFrameIndexOf(Waypoint* wp)
{
pixhawk's avatar
pixhawk committed
613
    // Search through all waypointsEditable,
614 615
    // counting only those in global frame
    int i = 0;
pixhawk's avatar
pixhawk committed
616
    foreach (Waypoint* p, waypointsEditable) {
617 618 619 620
        if (p->getFrame() == MAV_FRAME_GLOBAL || wp->getFrame() == MAV_FRAME_GLOBAL_RELATIVE_ALT)
        {
            if (p == wp)
            {
621 622 623 624 625 626 627 628 629
                return i;
            }
            i++;
        }
    }

    return -1;
}

lm's avatar
lm committed
630 631
int UASWaypointManager::getGlobalFrameAndNavTypeIndexOf(Waypoint* wp)
{
pixhawk's avatar
pixhawk committed
632
    // Search through all waypointsEditable,
lm's avatar
lm committed
633 634
    // counting only those in global frame
    int i = 0;
pixhawk's avatar
pixhawk committed
635
    foreach (Waypoint* p, waypointsEditable) {
636
        if ((p->getFrame() == MAV_FRAME_GLOBAL || wp->getFrame() == MAV_FRAME_GLOBAL_RELATIVE_ALT) && p->isNavigationType())
637 638 639
        {
            if (p == wp)
            {
lm's avatar
lm committed
640 641 642 643 644 645 646 647 648
                return i;
            }
            i++;
        }
    }

    return -1;
}

LM's avatar
LM committed
649 650
int UASWaypointManager::getNavTypeIndexOf(Waypoint* wp)
{
pixhawk's avatar
pixhawk committed
651
    // Search through all waypointsEditable,
LM's avatar
LM committed
652 653
    // counting only those in global frame
    int i = 0;
pixhawk's avatar
pixhawk committed
654
    foreach (Waypoint* p, waypointsEditable)
655 656 657 658 659
    {
        if (p->isNavigationType())
        {
            if (p == wp)
            {
LM's avatar
LM committed
660 661 662 663 664 665 666 667 668
                return i;
            }
            i++;
        }
    }

    return -1;
}

669 670
int UASWaypointManager::getGlobalFrameCount()
{
pixhawk's avatar
pixhawk committed
671
    // Search through all waypointsEditable,
672 673
    // counting only those in global frame
    int i = 0;
pixhawk's avatar
pixhawk committed
674
    foreach (Waypoint* p, waypointsEditable)
675
    {
676 677
        if (p->getFrame() == MAV_FRAME_GLOBAL || p->getFrame() == MAV_FRAME_GLOBAL_RELATIVE_ALT)
        {
678 679 680 681 682 683 684
            i++;
        }
    }

    return i;
}

lm's avatar
lm committed
685 686
int UASWaypointManager::getGlobalFrameAndNavTypeCount()
{
pixhawk's avatar
pixhawk committed
687
    // Search through all waypointsEditable,
lm's avatar
lm committed
688 689
    // counting only those in global frame
    int i = 0;
pixhawk's avatar
pixhawk committed
690
    foreach (Waypoint* p, waypointsEditable) {
691
        if ((p->getFrame() == MAV_FRAME_GLOBAL || p->getFrame() == MAV_FRAME_GLOBAL_RELATIVE_ALT) && p->isNavigationType())
692
        {
lm's avatar
lm committed
693 694 695 696 697 698 699
            i++;
        }
    }

    return i;
}

LM's avatar
LM committed
700 701
int UASWaypointManager::getNavTypeCount()
{
pixhawk's avatar
pixhawk committed
702
    // Search through all waypointsEditable,
LM's avatar
LM committed
703 704
    // counting only those in global frame
    int i = 0;
pixhawk's avatar
pixhawk committed
705
    foreach (Waypoint* p, waypointsEditable) {
LM's avatar
LM committed
706 707 708 709 710 711 712 713
        if (p->isNavigationType()) {
            i++;
        }
    }

    return i;
}

714 715
int UASWaypointManager::getLocalFrameCount()
{
pixhawk's avatar
pixhawk committed
716
    // Search through all waypointsEditable,
717 718
    // counting only those in global frame
    int i = 0;
pixhawk's avatar
pixhawk committed
719
    foreach (Waypoint* p, waypointsEditable)
lm's avatar
lm committed
720
    {
721
        if (p->getFrame() == MAV_FRAME_LOCAL_NED || p->getFrame() == MAV_FRAME_LOCAL_ENU)
lm's avatar
lm committed
722
        {
723 724 725 726 727 728 729 730 731
            i++;
        }
    }

    return i;
}

int UASWaypointManager::getLocalFrameIndexOf(Waypoint* wp)
{
pixhawk's avatar
pixhawk committed
732
    // Search through all waypointsEditable,
733 734
    // counting only those in local frame
    int i = 0;
pixhawk's avatar
pixhawk committed
735
    foreach (Waypoint* p, waypointsEditable)
lm's avatar
lm committed
736 737 738
    {
        if (p->getFrame() == MAV_FRAME_LOCAL_NED || p->getFrame() == MAV_FRAME_LOCAL_ENU)
        {
739 740
            if (p == wp)
            {
741 742 743 744 745 746 747 748 749 750 751
                return i;
            }
            i++;
        }
    }

    return -1;
}

int UASWaypointManager::getMissionFrameIndexOf(Waypoint* wp)
{
pixhawk's avatar
pixhawk committed
752
    // Search through all waypointsEditable,
753 754
    // counting only those in mission frame
    int i = 0;
pixhawk's avatar
pixhawk committed
755
    foreach (Waypoint* p, waypointsEditable)
lm's avatar
lm committed
756
    {
757 758 759 760
        if (p->getFrame() == MAV_FRAME_MISSION)
        {
            if (p == wp)
            {
761 762 763 764 765 766 767 768 769
                return i;
            }
            i++;
        }
    }

    return -1;
}

pixhawk's avatar
pixhawk committed
770 771 772 773 774

/**
 * @param readToEdit If true, incoming waypoints will be copied both to "edit"-tab and "view"-tab. Otherwise, only to "view"-tab.
 */
void UASWaypointManager::readWaypoints(bool readToEdit)
775
{
pixhawk's avatar
pixhawk committed
776
    read_to_edit = readToEdit;
777
    emit readGlobalWPFromUAS(true);
778
    if(current_state == WP_IDLE) {
779

780

781 782
        //Clear the old view-list before receiving the new one
        while(waypointsViewOnly.size()>0) {
783 784 785
            Waypoint *t = waypointsViewOnly[0];
            waypointsViewOnly.remove(0);
            delete t;
786
        }
787 788
        emit waypointViewOnlyListChanged();
        /* THIS PART WAS MOVED TO handleWaypointCount. THE EDIT-LIST SHOULD NOT BE CLEARED UNLESS THERE IS A RESPONSE FROM UAV.
789 790 791
        //Clear the old edit-list before receiving the new one
        if (read_to_edit == true){
            while(waypointsEditable.size()>0) {
792 793 794
                Waypoint *t = waypointsEditable[0];
                waypointsEditable.remove(0);
                delete t;
795
            }
796
            emit waypointEditableListChanged();
797
        }
798
        */
799 800
        protocol_timer.start(PROTOCOL_TIMEOUT_MS);
        current_retries = PROTOCOL_MAX_RETRIES;
pixhawk's avatar
pixhawk committed
801 802 803

        current_state = WP_GETLIST;
        current_wp_id = 0;
804
        current_partner_systemid = uasid;
lm's avatar
lm committed
805
        current_partner_compid = MAV_COMP_ID_MISSIONPLANNER;
pixhawk's avatar
pixhawk committed
806

807
        sendWaypointRequestList();
808

pixhawk's avatar
pixhawk committed
809 810 811
    }
}

812
void UASWaypointManager::writeWaypoints()
pixhawk's avatar
pixhawk committed
813
{
814
    if (current_state == WP_IDLE) {
pixhawk's avatar
pixhawk committed
815
        // Send clear all if count == 0
pixhawk's avatar
pixhawk committed
816
        if (waypointsEditable.count() > 0) {
pixhawk's avatar
pixhawk committed
817
            protocol_timer.start(PROTOCOL_TIMEOUT_MS);
818
            current_retries = PROTOCOL_MAX_RETRIES;
pixhawk's avatar
pixhawk committed
819

pixhawk's avatar
pixhawk committed
820
            current_count = waypointsEditable.count();
pixhawk's avatar
pixhawk committed
821 822
            current_state = WP_SENDLIST;
            current_wp_id = 0;
823
            current_partner_systemid = uasid;
lm's avatar
lm committed
824
            current_partner_compid = MAV_COMP_ID_MISSIONPLANNER;
pixhawk's avatar
pixhawk committed
825 826

            //clear local buffer
pixhawk's avatar
pixhawk committed
827 828 829
            // Why not replace with waypoint_buffer.clear() ?
            // because this will lead to memory leaks, the waypoint-structs
            // have to be deleted, clear() would only delete the pointers.
830
            while(!waypoint_buffer.empty()) {
pixhawk's avatar
pixhawk committed
831 832 833
                delete waypoint_buffer.back();
                waypoint_buffer.pop_back();
            }
pixhawk's avatar
pixhawk committed
834

835 836
            bool noCurrent = true;

pixhawk's avatar
pixhawk committed
837
            //copy waypoint data to local buffer
838
            for (int i=0; i < current_count; i++) {
lm's avatar
lm committed
839 840 841
                waypoint_buffer.push_back(new mavlink_mission_item_t);
                mavlink_mission_item_t *cur_d = waypoint_buffer.back();
                memset(cur_d, 0, sizeof(mavlink_mission_item_t));   //initialize with zeros
pixhawk's avatar
pixhawk committed
842
                const Waypoint *cur_s = waypointsEditable.at(i);
pixhawk's avatar
pixhawk committed
843 844

                cur_d->autocontinue = cur_s->getAutoContinue();
845
                cur_d->current = cur_s->getCurrent() & noCurrent;   //make sure only one current waypoint is selected, the first selected will be chosen
846 847
                cur_d->param1 = cur_s->getParam1();
                cur_d->param2 = cur_s->getParam2();
lm's avatar
lm committed
848 849
                cur_d->param3 = cur_s->getParam3();
                cur_d->param4 = cur_s->getParam4();
850
                cur_d->frame = cur_s->getFrame();
lm's avatar
lm committed
851
                cur_d->command = cur_s->getAction();
852
                cur_d->seq = i;     // don't read out the sequence number of the waypoint class
pixhawk's avatar
pixhawk committed
853 854 855
                cur_d->x = cur_s->getX();
                cur_d->y = cur_s->getY();
                cur_d->z = cur_s->getZ();
856 857 858

                if (cur_s->getCurrent() && noCurrent)
                    noCurrent = false;
859 860
                if (i == (current_count - 1) && noCurrent == true) //not a single waypoint was set as "current"
                    cur_d->current = true; // set the last waypoint as current. Or should it better be the first waypoint ?
pixhawk's avatar
pixhawk committed
861
            }
862

863 864 865



pixhawk's avatar
pixhawk committed
866
            //send the waypoint count to UAS (this starts the send transaction)
867
            sendWaypointCount();
pixhawk's avatar
pixhawk committed
868
        }
pixhawk's avatar
pixhawk committed
869
    } else if (waypointsEditable.count() == 0) {
870
        sendWaypointClearAll();
871
    } else {
872
        //we're in another transaction, ignore command
873
        qDebug() << "UASWaypointManager::sendWaypoints() doing something else ignoring command";
874
    }
pixhawk's avatar
pixhawk committed
875 876
}

877 878
void UASWaypointManager::sendWaypointClearAll()
{
lm's avatar
lm committed
879
    if (!uas) return;
880
    mavlink_message_t message;
lm's avatar
lm committed
881
    mavlink_mission_clear_all_t wpca;
882

883
    wpca.target_system = uasid;
lm's avatar
lm committed
884
    wpca.target_component = MAV_COMP_ID_MISSIONPLANNER;
885

886
    emit updateStatusString(QString("Clearing waypoint list..."));
887

lm's avatar
lm committed
888 889 890
    mavlink_msg_mission_clear_all_encode(uas->mavlink->getSystemId(), uas->mavlink->getComponentId(), &message, &wpca);
    if (uas) uas->sendMessage(message);
    QGC::SLEEP::msleep(PROTOCOL_DELAY_MS);
891

892
    // // qDebug() << "sent waypoint clear all to ID " << wpca.target_system;
893 894 895 896
}

void UASWaypointManager::sendWaypointSetCurrent(quint16 seq)
{
lm's avatar
lm committed
897
    if (!uas) return;
898
    mavlink_message_t message;
lm's avatar
lm committed
899
    mavlink_mission_set_current_t wpsc;
900

901
    wpsc.target_system = uasid;
lm's avatar
lm committed
902
    wpsc.target_component = MAV_COMP_ID_MISSIONPLANNER;
903 904
    wpsc.seq = seq;

905
    emit updateStatusString(QString("Updating target waypoint..."));
906

lm's avatar
lm committed
907 908 909
    mavlink_msg_mission_set_current_encode(uas->mavlink->getSystemId(), uas->mavlink->getComponentId(), &message, &wpsc);
    if (uas) uas->sendMessage(message);
    QGC::SLEEP::msleep(PROTOCOL_DELAY_MS);
910

911
    // // qDebug() << "sent waypoint set current (" << wpsc.seq << ") to ID " << wpsc.target_system;
912 913 914 915
}

void UASWaypointManager::sendWaypointCount()
{
lm's avatar
lm committed
916
    if (!uas) return;
917
    mavlink_message_t message;
lm's avatar
lm committed
918
    mavlink_mission_count_t wpc;
919

920
    wpc.target_system = uasid;
lm's avatar
lm committed
921
    wpc.target_component = MAV_COMP_ID_MISSIONPLANNER;
922 923
    wpc.count = current_count;

924
    // // qDebug() << "sent waypoint count (" << wpc.count << ") to ID " << wpc.target_system;
925
    emit updateStatusString(QString("Starting to transmit waypoints..."));
926

lm's avatar
lm committed
927 928 929
    mavlink_msg_mission_count_encode(uas->mavlink->getSystemId(), uas->mavlink->getComponentId(), &message, &wpc);
    if (uas) uas->sendMessage(message);
    QGC::SLEEP::msleep(PROTOCOL_DELAY_MS);
930

931
    // // qDebug() << "sent waypoint count (" << wpc.count << ") to ID " << wpc.target_system;
932 933 934 935
}

void UASWaypointManager::sendWaypointRequestList()
{
lm's avatar
lm committed
936
    if (!uas) return;
937
    mavlink_message_t message;
lm's avatar
lm committed
938
    mavlink_mission_request_list_t wprl;
939

940
    wprl.target_system = uasid;
lm's avatar
lm committed
941
    wprl.target_component = MAV_COMP_ID_MISSIONPLANNER;
942

943
    emit updateStatusString(QString("Requesting waypoint list..."));
944

lm's avatar
lm committed
945 946 947
    mavlink_msg_mission_request_list_encode(uas->mavlink->getSystemId(), uas->mavlink->getComponentId(), &message, &wprl);
    if (uas) uas->sendMessage(message);
    QGC::SLEEP::msleep(PROTOCOL_DELAY_MS);
948

949
    // // qDebug() << "sent waypoint list request to ID " << wprl.target_system;
950 951


952 953
}

954
void UASWaypointManager::sendWaypointRequest(quint16 seq)
pixhawk's avatar
pixhawk committed
955
{
lm's avatar
lm committed
956
    if (!uas) return;
957
    mavlink_message_t message;
lm's avatar
lm committed
958
    mavlink_mission_request_t wpr;
959

960
    wpr.target_system = uasid;
lm's avatar
lm committed
961
    wpr.target_component = MAV_COMP_ID_MISSIONPLANNER;
962 963
    wpr.seq = seq;

964
    emit updateStatusString(QString("Retrieving waypoint ID %1 of %2 total").arg(wpr.seq).arg(current_count));
pixhawk's avatar
pixhawk committed
965

lm's avatar
lm committed
966 967 968
    mavlink_msg_mission_request_encode(uas->mavlink->getSystemId(), uas->mavlink->getComponentId(), &message, &wpr);
    if (uas) uas->sendMessage(message);
    QGC::SLEEP::msleep(PROTOCOL_DELAY_MS);
969

970
    // // qDebug() << "sent waypoint request (" << wpr.seq << ") to ID " << wpr.target_system;
pixhawk's avatar
pixhawk committed
971
}
pixhawk's avatar
pixhawk committed
972

pixhawk's avatar
pixhawk committed
973 974
void UASWaypointManager::sendWaypoint(quint16 seq)
{
lm's avatar
lm committed
975
    if (!uas) return;
pixhawk's avatar
pixhawk committed
976
    mavlink_message_t message;
977
    // // qDebug() <<" WP Buffer count: "<<waypoint_buffer.count();
978

979
    if (seq < waypoint_buffer.count()) {
pixhawk's avatar
pixhawk committed
980

lm's avatar
lm committed
981
        mavlink_mission_item_t *wp;
982

pixhawk's avatar
pixhawk committed
983 984

        wp = waypoint_buffer.at(seq);
985
        wp->target_system = uasid;
lm's avatar
lm committed
986
        wp->target_component = MAV_COMP_ID_MISSIONPLANNER;
pixhawk's avatar
pixhawk committed
987

988
        emit updateStatusString(QString("Sending waypoint ID %1 of %2 total").arg(wp->seq).arg(current_count));
989

990
        // // qDebug() << "sent waypoint (" << wp->seq << ") to ID " << wp->target_system<<" WP Buffer count: "<<waypoint_buffer.count();
pixhawk's avatar
pixhawk committed
991

lm's avatar
lm committed
992 993 994
        mavlink_msg_mission_item_encode(uas->mavlink->getSystemId(), uas->mavlink->getComponentId(), &message, wp);
        if (uas) uas->sendMessage(message);
        QGC::SLEEP::msleep(PROTOCOL_DELAY_MS);
pixhawk's avatar
pixhawk committed
995
    }
pixhawk's avatar
pixhawk committed
996
}
997 998 999

void UASWaypointManager::sendWaypointAck(quint8 type)
{
lm's avatar
lm committed
1000
    if (!uas) return;
1001
    mavlink_message_t message;
lm's avatar
lm committed
1002
    mavlink_mission_ack_t wpa;
1003

1004
    wpa.target_system = uasid;
lm's avatar
lm committed
1005
    wpa.target_component = MAV_COMP_ID_MISSIONPLANNER;
1006 1007
    wpa.type = type;

lm's avatar
lm committed
1008 1009 1010
    mavlink_msg_mission_ack_encode(uas->mavlink->getSystemId(), uas->mavlink->getComponentId(), &message, &wpa);
    if (uas) uas->sendMessage(message);
    QGC::SLEEP::msleep(PROTOCOL_DELAY_MS);
1011

1012
    // // qDebug() << "sent waypoint ack (" << wpa.type << ") to ID " << wpa.target_system;
1013
}