UASWaypointManager.cc 31 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
#include "UASWaypointManager.h"
LM's avatar
LM committed
33
#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
      protocol_timer(this),
lm's avatar
lm committed
49
      currentWaypointEditable(NULL)
pixhawk's avatar
pixhawk committed
50
{
lm's avatar
lm committed
51 52 53 54 55 56 57 58 59 60 61
    if (uas)
    {
        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;
    }
62 63
}

pixhawk's avatar
pixhawk committed
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 115 116 117
        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)
{

}

118 119
void UASWaypointManager::handleWaypointCount(quint8 systemId, quint8 compId, quint16 count)
{
120
    if (current_state == WP_GETLIST && systemId == current_partner_systemid && compId == current_partner_compid) {
121 122 123
        protocol_timer.start(PROTOCOL_TIMEOUT_MS);
        current_retries = PROTOCOL_MAX_RETRIES;

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

126
        if (count > 0) {
pixhawk's avatar
pixhawk committed
127 128 129
            current_count = count;
            current_wp_id = 0;
            current_state = WP_GETLIST_GETWPS;
130

pixhawk's avatar
pixhawk committed
131
            sendWaypointRequest(current_wp_id);
132
        } else {
133
            protocol_timer.stop();
pixhawk's avatar
pixhawk committed
134
            emit updateStatusString("done.");
135
            // // qDebug() << "No waypoints on UAS " << systemId;
136 137 138 139 140
            current_state = WP_IDLE;
            current_count = 0;
            current_wp_id = 0;
            current_partner_systemid = 0;
            current_partner_compid = 0;
pixhawk's avatar
pixhawk committed
141
        }
142 143
    } 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);
144
    }
145 146
}

lm's avatar
lm committed
147
void UASWaypointManager::handleWaypoint(quint8 systemId, quint8 compId, mavlink_mission_item_t *wp)
pixhawk's avatar
pixhawk committed
148
{
149
    if (systemId == current_partner_systemid && compId == current_partner_compid && current_state == WP_GETLIST_GETWPS && wp->seq == current_wp_id) {
150 151 152
        protocol_timer.start(PROTOCOL_TIMEOUT_MS);
        current_retries = PROTOCOL_MAX_RETRIES;

153
        if(wp->seq == current_wp_id) {
154
            //// // 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
155 156 157 158 159 160 161 162 163 164 165

            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
166 167 168 169

            //get next waypoint
            current_wp_id++;

170
            if(current_wp_id < current_count) {
171
                sendWaypointRequest(current_wp_id);
172
            } else {
173 174
                sendWaypointAck(0);

pixhawk's avatar
pixhawk committed
175
                // all waypoints retrieved, change state to idle
pixhawk's avatar
pixhawk committed
176 177 178 179 180
                current_state = WP_IDLE;
                current_count = 0;
                current_wp_id = 0;
                current_partner_systemid = 0;
                current_partner_compid = 0;
181

pixhawk's avatar
pixhawk committed
182
                protocol_timer.stop();
183
                emit readGlobalWPFromUAS(false);
184
                //if (currentWaypointEditable) emit currentWaypointChanged(currentWaypointEditable->getId());
185 186
                emit updateStatusString("done.");

187
                // // qDebug() << "got all waypoints from ID " << systemId;
pixhawk's avatar
pixhawk committed
188
            }
189
        } else {
190
            emit updateStatusString(tr("Waypoint ID mismatch, rejecting waypoint"));
pixhawk's avatar
pixhawk committed
191
        }
192 193
    } 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);
194
    }
pixhawk's avatar
pixhawk committed
195 196
}

lm's avatar
lm committed
197
void UASWaypointManager::handleWaypointAck(quint8 systemId, quint8 compId, mavlink_mission_ack_t *wpa)
198
{
199 200
    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)) {
201 202
            //all waypoints sent and ack received
            protocol_timer.stop();
203
            current_state = WP_IDLE;
204
            emit updateStatusString("done.");
205
            // // qDebug() << "sent all waypoints to ID " << systemId;
206
        } else if(current_state == WP_CLEARLIST) {
207 208 209
            protocol_timer.stop();
            current_state = WP_IDLE;
            emit updateStatusString("done.");
210
            // // qDebug() << "cleared waypoint list of ID " << systemId;
211
        }
212 213 214
    }
}

lm's avatar
lm committed
215
void UASWaypointManager::handleWaypointRequest(quint8 systemId, quint8 compId, mavlink_mission_request_t *wpr)
216
{
217
    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)))) {
218 219
        protocol_timer.start(PROTOCOL_TIMEOUT_MS);
        current_retries = PROTOCOL_MAX_RETRIES;
220

221
        if (wpr->seq < waypoint_buffer.count()) {
pixhawk's avatar
pixhawk committed
222 223 224
            current_state = WP_SENDLIST_SENDWPS;
            current_wp_id = wpr->seq;
            sendWaypoint(current_wp_id);
225
        } else {
pixhawk's avatar
pixhawk committed
226 227
            //TODO: Error message or something
        }
228 229
    } 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);
230
    }
231 232
}

lm's avatar
lm committed
233
void UASWaypointManager::handleWaypointReached(quint8 systemId, quint8 compId, mavlink_mission_item_reached_t *wpr)
234
{
lm's avatar
lm committed
235
    if (!uas) return;
236
    if (systemId == uasid) {
pixhawk's avatar
pixhawk committed
237 238
        emit updateStatusString(QString("Reached waypoint %1").arg(wpr->seq));
    }
pixhawk's avatar
pixhawk committed
239 240
}

lm's avatar
lm committed
241
void UASWaypointManager::handleWaypointCurrent(quint8 systemId, quint8 compId, mavlink_mission_current_t *wpc)
pixhawk's avatar
pixhawk committed
242
{
lm's avatar
lm committed
243
    if (!uas) return;
244
    if (systemId == uasid) {
245
        // FIXME Petri
246
        if (current_state == WP_SETCURRENT) {
247 248
            protocol_timer.stop();
            current_state = WP_IDLE;
249 250

            // update the local main storage
pixhawk's avatar
pixhawk committed
251 252 253 254 255
            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];
256
                    } else {
pixhawk's avatar
pixhawk committed
257
                        waypointsViewOnly[i]->setCurrent(false);
258 259 260
                    }
                }
            }
261
        }
262 263 264
        emit updateStatusString(QString("New current waypoint %1").arg(wpc->seq));
        //emit update to UI widgets
        emit currentWaypointChanged(wpc->seq);
pixhawk's avatar
pixhawk committed
265
    }
pixhawk's avatar
pixhawk committed
266 267
}

268
void UASWaypointManager::notifyOfChangeEditable(Waypoint* wp)
269
{
270
    // // qDebug() << "WAYPOINT CHANGED: ID:" << wp->getId();
271
    // If only one waypoint was changed, emit only WP signal
272
    if (wp != NULL) {
273
        emit waypointEditableChanged(uasid, wp);
274
    } else {
275
        emit waypointEditableListChanged();
276
        emit waypointEditableListChanged(uasid);
277
    }
278 279
}

280 281 282
void UASWaypointManager::notifyOfChangeViewOnly(Waypoint* wp)
{
    if (wp != NULL) {
283
        emit waypointViewOnlyChanged(uasid, wp);
284 285
    } else {
        emit waypointViewOnlyListChanged();
286
        emit waypointViewOnlyListChanged(uasid);
287 288
    }
}
289 290


291
int UASWaypointManager::setCurrentWaypoint(quint16 seq)
pixhawk's avatar
pixhawk committed
292
{
pixhawk's avatar
pixhawk committed
293
    if (seq < waypointsViewOnly.size()) {
294
        if(current_state == WP_IDLE) {
295

296 297 298 299 300 301
            //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;
302
            current_partner_systemid = uasid;
lm's avatar
lm committed
303
            current_partner_compid = MAV_COMP_ID_MISSIONPLANNER;
304 305 306 307 308 309 310 311 312 313 314

            sendWaypointSetCurrent(current_wp_id);

            //emit waypointListChanged();

            return 0;
        }
    }
    return -1;
}

315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
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
334 335 336 337

void UASWaypointManager::addWaypointViewOnly(Waypoint *wp)
{
    if (wp)
338
    {        
pixhawk's avatar
pixhawk committed
339 340 341 342
        waypointsViewOnly.insert(waypointsViewOnly.size(), wp);
        connect(wp, SIGNAL(changed(Waypoint*)), this, SLOT(notifyOfChangeViewOnly(Waypoint*)));

        emit waypointViewOnlyListChanged();
343
        emit waypointViewOnlyListChanged(uasid);
pixhawk's avatar
pixhawk committed
344 345 346 347
    }
}


pixhawk's avatar
pixhawk committed
348
/**
349
 * @warning Make sure the waypoint stays valid for the whole application lifecycle!
pixhawk's avatar
pixhawk committed
350
 * @param enforceFirstActive Enforces that the first waypoint is set as active
351
 * @see createWaypoint() is more suitable for most use cases
pixhawk's avatar
pixhawk committed
352
 */
353
void UASWaypointManager::addWaypointEditable(Waypoint *wp, bool enforceFirstActive)
354
{
lm's avatar
lm committed
355 356
    if (wp)
    {
pixhawk's avatar
pixhawk committed
357 358
        wp->setId(waypointsEditable.size());
        if (enforceFirstActive && waypointsEditable.size() == 0)
359 360
        {
            wp->setCurrent(true);
pixhawk's avatar
pixhawk committed
361
            currentWaypointEditable = wp;
362
        }
pixhawk's avatar
pixhawk committed
363
        waypointsEditable.insert(waypointsEditable.size(), wp);
364
        connect(wp, SIGNAL(changed(Waypoint*)), this, SLOT(notifyOfChangeEditable(Waypoint*)));
365

366
        emit waypointEditableListChanged();
367
        emit waypointEditableListChanged(uasid);
368
    }
pixhawk's avatar
pixhawk committed
369 370
}

371 372 373 374 375 376
/**
 * @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
377 378
    wp->setId(waypointsEditable.size());
    if (enforceFirstActive && waypointsEditable.size() == 0)
379 380
    {
        wp->setCurrent(true);
pixhawk's avatar
pixhawk committed
381
        currentWaypointEditable = wp;
382
    }
pixhawk's avatar
pixhawk committed
383
    waypointsEditable.insert(waypointsEditable.size(), wp);
384
    connect(wp, SIGNAL(changed(Waypoint*)), this, SLOT(notifyOfChangeEditable(Waypoint*)));
385

386
    emit waypointEditableListChanged();
387
    emit waypointEditableListChanged(uasid);
388 389 390
    return wp;
}

391
int UASWaypointManager::removeWaypoint(quint16 seq)
392
{
pixhawk's avatar
pixhawk committed
393
    if (seq < waypointsEditable.size())
394
    {
pixhawk's avatar
pixhawk committed
395 396
        Waypoint *t = waypointsEditable[seq];
        waypointsEditable.remove(seq);
397
        delete t;
398
        t = NULL;
399

pixhawk's avatar
pixhawk committed
400
        for(int i = seq; i < waypointsEditable.size(); i++)
401
        {
pixhawk's avatar
pixhawk committed
402
            waypointsEditable[i]->setId(i);
403
        }
Alejandro's avatar
Alejandro committed
404

405
        emit waypointEditableListChanged();
406
        emit waypointEditableListChanged(uasid);
407 408 409 410 411
        return 0;
    }
    return -1;
}

412
void UASWaypointManager::moveWaypoint(quint16 cur_seq, quint16 new_seq)
413
{
pixhawk's avatar
pixhawk committed
414
    if (cur_seq != new_seq && cur_seq < waypointsEditable.size() && new_seq < waypointsEditable.size())
415
    {
pixhawk's avatar
pixhawk committed
416
        Waypoint *t = waypointsEditable[cur_seq];
417
        if (cur_seq < new_seq) {
418 419
            for (int i = cur_seq; i < new_seq; i++)
            {
pixhawk's avatar
pixhawk committed
420
                waypointsEditable[i] = waypointsEditable[i+1];
421
            }
422 423 424 425 426
        }
        else
        {
            for (int i = cur_seq; i > new_seq; i--)
            {
pixhawk's avatar
pixhawk committed
427
                waypointsEditable[i] = waypointsEditable[i-1];
428 429
            }
        }
pixhawk's avatar
pixhawk committed
430
        waypointsEditable[new_seq] = t;
431

432
        emit waypointEditableListChanged();
433
        emit waypointEditableListChanged(uasid);
434 435 436
    }
}

437
void UASWaypointManager::saveWaypoints(const QString &saveFile)
438 439 440 441 442 443
{
    QFile file(saveFile);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
        return;

    QTextStream out(&file);
444 445

    //write the waypoint list version to the first line for compatibility check
lm's avatar
lm committed
446
    out << "QGC WPL 110\r\n";
447

pixhawk's avatar
pixhawk committed
448
    for (int i = 0; i < waypointsEditable.size(); i++)
449
    {
pixhawk's avatar
pixhawk committed
450 451
        waypointsEditable[i]->setId(i);
        waypointsEditable[i]->save(out);
452 453 454 455
    }
    file.close();
}

456
void UASWaypointManager::loadWaypoints(const QString &loadFile)
457 458 459 460 461
{
    QFile file(loadFile);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
        return;

pixhawk's avatar
pixhawk committed
462 463 464
    while(waypointsEditable.size()>0) {
        Waypoint *t = waypointsEditable[0];
        waypointsEditable.remove(0);
465 466 467 468
        delete t;
    }

    QTextStream in(&file);
469 470 471

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

472 473
    if (!(version.size() == 3 && version[0] == "QGC" && version[1] == "WPL" && version[2] == "110"))
    {
474
        emit updateStatusString(tr("The waypoint file is not compatible with the current version of QGroundControl."));
475 476 477 478 479
    }
    else
    {
        while (!in.atEnd())
        {
480
            Waypoint *t = new Waypoint();
481 482
            if(t->load(in))
            {
pixhawk's avatar
pixhawk committed
483 484
                t->setId(waypointsEditable.size());
                waypointsEditable.insert(waypointsEditable.size(), t);
485 486 487
            }
            else
            {
488 489
                emit updateStatusString(tr("The waypoint file is corrupted. Load operation only partly succesful."));
                //MainWindow::instance()->showCriticalMessage(tr("Error loading waypoint file"),);
490 491
                break;
            }
492 493
        }
    }
494

495 496
    file.close();

497
    emit loadWPFile();
498
    emit waypointEditableListChanged();
499
    emit waypointEditableListChanged(uasid);
500 501 502
}

void UASWaypointManager::clearWaypointList()
pixhawk's avatar
pixhawk committed
503
{
504 505
    if(current_state == WP_IDLE)
    {
pixhawk's avatar
pixhawk committed
506
        protocol_timer.start(PROTOCOL_TIMEOUT_MS);
507
        current_retries = PROTOCOL_MAX_RETRIES;
pixhawk's avatar
pixhawk committed
508

509 510
        current_state = WP_CLEARLIST;
        current_wp_id = 0;
511
        current_partner_systemid = uasid;
lm's avatar
lm committed
512
        current_partner_compid = MAV_COMP_ID_MISSIONPLANNER;
pixhawk's avatar
pixhawk committed
513

514
        sendWaypointClearAll();
515 516 517
    }
}

518 519 520 521 522 523
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
524
    foreach (Waypoint* wp, waypointsEditable)
525 526 527
    {
        if (wp->getFrame() == MAV_FRAME_GLOBAL || wp->getFrame() == MAV_FRAME_GLOBAL_RELATIVE_ALT)
        {
528 529 530 531 532 533
            wps.append(wp);
        }
    }
    return wps;
}

lm's avatar
lm committed
534 535 536 537 538 539
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
540
    foreach (Waypoint* wp, waypointsEditable)
541 542 543
    {
        if ((wp->getFrame() == MAV_FRAME_GLOBAL || wp->getFrame() == MAV_FRAME_GLOBAL_RELATIVE_ALT) && wp->isNavigationType())
        {
lm's avatar
lm committed
544 545 546 547 548 549
            wps.append(wp);
        }
    }
    return wps;
}

LM's avatar
LM committed
550 551 552 553 554 555
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
556
    foreach (Waypoint* wp, waypointsEditable)
557 558 559
    {
        if (wp->isNavigationType())
        {
LM's avatar
LM committed
560 561 562 563 564 565
            wps.append(wp);
        }
    }
    return wps;
}

566 567
int UASWaypointManager::getIndexOf(Waypoint* wp)
{
pixhawk's avatar
pixhawk committed
568
    return waypointsEditable.indexOf(wp);
569 570
}

571 572
int UASWaypointManager::getGlobalFrameIndexOf(Waypoint* wp)
{
pixhawk's avatar
pixhawk committed
573
    // Search through all waypointsEditable,
574 575
    // counting only those in global frame
    int i = 0;
pixhawk's avatar
pixhawk committed
576
    foreach (Waypoint* p, waypointsEditable) {
577 578 579 580
        if (p->getFrame() == MAV_FRAME_GLOBAL || wp->getFrame() == MAV_FRAME_GLOBAL_RELATIVE_ALT)
        {
            if (p == wp)
            {
581 582 583 584 585 586 587 588 589
                return i;
            }
            i++;
        }
    }

    return -1;
}

lm's avatar
lm committed
590 591
int UASWaypointManager::getGlobalFrameAndNavTypeIndexOf(Waypoint* wp)
{
pixhawk's avatar
pixhawk committed
592
    // Search through all waypointsEditable,
lm's avatar
lm committed
593 594
    // counting only those in global frame
    int i = 0;
pixhawk's avatar
pixhawk committed
595
    foreach (Waypoint* p, waypointsEditable) {
596
        if ((p->getFrame() == MAV_FRAME_GLOBAL || wp->getFrame() == MAV_FRAME_GLOBAL_RELATIVE_ALT) && p->isNavigationType())
597 598 599
        {
            if (p == wp)
            {
lm's avatar
lm committed
600 601 602 603 604 605 606 607 608
                return i;
            }
            i++;
        }
    }

    return -1;
}

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

    return -1;
}

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

    return i;
}

lm's avatar
lm committed
645 646
int UASWaypointManager::getGlobalFrameAndNavTypeCount()
{
pixhawk's avatar
pixhawk committed
647
    // Search through all waypointsEditable,
lm's avatar
lm committed
648 649
    // counting only those in global frame
    int i = 0;
pixhawk's avatar
pixhawk committed
650
    foreach (Waypoint* p, waypointsEditable) {
651
        if ((p->getFrame() == MAV_FRAME_GLOBAL || p->getFrame() == MAV_FRAME_GLOBAL_RELATIVE_ALT) && p->isNavigationType())
652
        {
lm's avatar
lm committed
653 654 655 656 657 658 659
            i++;
        }
    }

    return i;
}

LM's avatar
LM committed
660 661
int UASWaypointManager::getNavTypeCount()
{
pixhawk's avatar
pixhawk committed
662
    // Search through all waypointsEditable,
LM's avatar
LM committed
663 664
    // counting only those in global frame
    int i = 0;
pixhawk's avatar
pixhawk committed
665
    foreach (Waypoint* p, waypointsEditable) {
LM's avatar
LM committed
666 667 668 669 670 671 672 673
        if (p->isNavigationType()) {
            i++;
        }
    }

    return i;
}

674 675
int UASWaypointManager::getLocalFrameCount()
{
pixhawk's avatar
pixhawk committed
676
    // Search through all waypointsEditable,
677 678
    // counting only those in global frame
    int i = 0;
pixhawk's avatar
pixhawk committed
679
    foreach (Waypoint* p, waypointsEditable)
lm's avatar
lm committed
680
    {
681
        if (p->getFrame() == MAV_FRAME_LOCAL_NED || p->getFrame() == MAV_FRAME_LOCAL_ENU)
lm's avatar
lm committed
682
        {
683 684 685 686 687 688 689 690 691
            i++;
        }
    }

    return i;
}

int UASWaypointManager::getLocalFrameIndexOf(Waypoint* wp)
{
pixhawk's avatar
pixhawk committed
692
    // Search through all waypointsEditable,
693 694
    // counting only those in local frame
    int i = 0;
pixhawk's avatar
pixhawk committed
695
    foreach (Waypoint* p, waypointsEditable)
lm's avatar
lm committed
696 697 698
    {
        if (p->getFrame() == MAV_FRAME_LOCAL_NED || p->getFrame() == MAV_FRAME_LOCAL_ENU)
        {
699 700
            if (p == wp)
            {
701 702 703 704 705 706 707 708 709 710 711
                return i;
            }
            i++;
        }
    }

    return -1;
}

int UASWaypointManager::getMissionFrameIndexOf(Waypoint* wp)
{
pixhawk's avatar
pixhawk committed
712
    // Search through all waypointsEditable,
713 714
    // counting only those in mission frame
    int i = 0;
pixhawk's avatar
pixhawk committed
715
    foreach (Waypoint* p, waypointsEditable)
lm's avatar
lm committed
716
    {
717 718 719 720
        if (p->getFrame() == MAV_FRAME_MISSION)
        {
            if (p == wp)
            {
721 722 723 724 725 726 727 728 729
                return i;
            }
            i++;
        }
    }

    return -1;
}

pixhawk's avatar
pixhawk committed
730 731 732 733 734

/**
 * @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)
735
{
pixhawk's avatar
pixhawk committed
736
    read_to_edit = readToEdit;
737
    emit readGlobalWPFromUAS(true);
738
    if(current_state == WP_IDLE) {
739

740 741 742 743 744 745 746 747 748 749 750 751
        //Clear the old view-list before receiving the new one
        while(waypointsViewOnly.size()>0) {
            delete waypointsViewOnly.back();
            waypointsViewOnly.pop_back();
        }

        //Clear the old edit-list before receiving the new one
        if (read_to_edit == true){
            while(waypointsEditable.size()>0) {
                delete waypointsEditable.back();
                waypointsEditable.pop_back();
            }
752 753
        }

754 755
        protocol_timer.start(PROTOCOL_TIMEOUT_MS);
        current_retries = PROTOCOL_MAX_RETRIES;
pixhawk's avatar
pixhawk committed
756 757 758

        current_state = WP_GETLIST;
        current_wp_id = 0;
759
        current_partner_systemid = uasid;
lm's avatar
lm committed
760
        current_partner_compid = MAV_COMP_ID_MISSIONPLANNER;
pixhawk's avatar
pixhawk committed
761

762
        sendWaypointRequestList();
763

pixhawk's avatar
pixhawk committed
764 765 766
    }
}

767
void UASWaypointManager::writeWaypoints()
pixhawk's avatar
pixhawk committed
768
{
769
    if (current_state == WP_IDLE) {
pixhawk's avatar
pixhawk committed
770
        // Send clear all if count == 0
pixhawk's avatar
pixhawk committed
771
        if (waypointsEditable.count() > 0) {
pixhawk's avatar
pixhawk committed
772
            protocol_timer.start(PROTOCOL_TIMEOUT_MS);
773
            current_retries = PROTOCOL_MAX_RETRIES;
pixhawk's avatar
pixhawk committed
774

pixhawk's avatar
pixhawk committed
775
            current_count = waypointsEditable.count();
pixhawk's avatar
pixhawk committed
776 777
            current_state = WP_SENDLIST;
            current_wp_id = 0;
778
            current_partner_systemid = uasid;
lm's avatar
lm committed
779
            current_partner_compid = MAV_COMP_ID_MISSIONPLANNER;
pixhawk's avatar
pixhawk committed
780 781

            //clear local buffer
pixhawk's avatar
pixhawk committed
782 783 784
            // 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.
785
            while(!waypoint_buffer.empty()) {
pixhawk's avatar
pixhawk committed
786 787 788
                delete waypoint_buffer.back();
                waypoint_buffer.pop_back();
            }
pixhawk's avatar
pixhawk committed
789

790 791
            bool noCurrent = true;

pixhawk's avatar
pixhawk committed
792
            //copy waypoint data to local buffer
793
            for (int i=0; i < current_count; i++) {
lm's avatar
lm committed
794 795 796
                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
797
                const Waypoint *cur_s = waypointsEditable.at(i);
pixhawk's avatar
pixhawk committed
798 799

                cur_d->autocontinue = cur_s->getAutoContinue();
800
                cur_d->current = cur_s->getCurrent() & noCurrent;   //make sure only one current waypoint is selected, the first selected will be chosen
801 802
                cur_d->param1 = cur_s->getParam1();
                cur_d->param2 = cur_s->getParam2();
lm's avatar
lm committed
803 804
                cur_d->param3 = cur_s->getParam3();
                cur_d->param4 = cur_s->getParam4();
805
                cur_d->frame = cur_s->getFrame();
lm's avatar
lm committed
806
                cur_d->command = cur_s->getAction();
807
                cur_d->seq = i;     // don't read out the sequence number of the waypoint class
pixhawk's avatar
pixhawk committed
808 809 810
                cur_d->x = cur_s->getX();
                cur_d->y = cur_s->getY();
                cur_d->z = cur_s->getZ();
811 812 813

                if (cur_s->getCurrent() && noCurrent)
                    noCurrent = false;
814 815
                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
816
            }
817

818 819 820



pixhawk's avatar
pixhawk committed
821
            //send the waypoint count to UAS (this starts the send transaction)
822
            sendWaypointCount();
pixhawk's avatar
pixhawk committed
823
        }
pixhawk's avatar
pixhawk committed
824
    } else if (waypointsEditable.count() == 0) {
825
        sendWaypointClearAll();
826
    } else {
827
        //we're in another transaction, ignore command
828
        qDebug() << "UASWaypointManager::sendWaypoints() doing something else ignoring command";
829
    }
pixhawk's avatar
pixhawk committed
830 831
}

832 833
void UASWaypointManager::sendWaypointClearAll()
{
lm's avatar
lm committed
834
    if (!uas) return;
835
    mavlink_message_t message;
lm's avatar
lm committed
836
    mavlink_mission_clear_all_t wpca;
837

838
    wpca.target_system = uasid;
lm's avatar
lm committed
839
    wpca.target_component = MAV_COMP_ID_MISSIONPLANNER;
840

841
    emit updateStatusString(QString("Clearing waypoint list..."));
842

lm's avatar
lm committed
843 844 845
    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);
846

847
    // // qDebug() << "sent waypoint clear all to ID " << wpca.target_system;
848 849 850 851
}

void UASWaypointManager::sendWaypointSetCurrent(quint16 seq)
{
lm's avatar
lm committed
852
    if (!uas) return;
853
    mavlink_message_t message;
lm's avatar
lm committed
854
    mavlink_mission_set_current_t wpsc;
855

856
    wpsc.target_system = uasid;
lm's avatar
lm committed
857
    wpsc.target_component = MAV_COMP_ID_MISSIONPLANNER;
858 859
    wpsc.seq = seq;

860
    emit updateStatusString(QString("Updating target waypoint..."));
861

lm's avatar
lm committed
862 863 864
    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);
865

866
    // // qDebug() << "sent waypoint set current (" << wpsc.seq << ") to ID " << wpsc.target_system;
867 868 869 870
}

void UASWaypointManager::sendWaypointCount()
{
lm's avatar
lm committed
871
    if (!uas) return;
872
    mavlink_message_t message;
lm's avatar
lm committed
873
    mavlink_mission_count_t wpc;
874

875
    wpc.target_system = uasid;
lm's avatar
lm committed
876
    wpc.target_component = MAV_COMP_ID_MISSIONPLANNER;
877 878
    wpc.count = current_count;

879
    // // qDebug() << "sent waypoint count (" << wpc.count << ") to ID " << wpc.target_system;
880
    emit updateStatusString(QString("Starting to transmit waypoints..."));
881

lm's avatar
lm committed
882 883 884
    mavlink_msg_mission_count_encode(uas->mavlink->getSystemId(), uas->mavlink->getComponentId(), &message, &wpc);
    if (uas) uas->sendMessage(message);
    QGC::SLEEP::msleep(PROTOCOL_DELAY_MS);
885

886
    // // qDebug() << "sent waypoint count (" << wpc.count << ") to ID " << wpc.target_system;
887 888 889 890
}

void UASWaypointManager::sendWaypointRequestList()
{
lm's avatar
lm committed
891
    if (!uas) return;
892
    mavlink_message_t message;
lm's avatar
lm committed
893
    mavlink_mission_request_list_t wprl;
894

895
    wprl.target_system = uasid;
lm's avatar
lm committed
896
    wprl.target_component = MAV_COMP_ID_MISSIONPLANNER;
897

898
    emit updateStatusString(QString("Requesting waypoint list..."));
899

lm's avatar
lm committed
900 901 902
    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);
903

904
    // // qDebug() << "sent waypoint list request to ID " << wprl.target_system;
905 906


907 908
}

909
void UASWaypointManager::sendWaypointRequest(quint16 seq)
pixhawk's avatar
pixhawk committed
910
{
lm's avatar
lm committed
911
    if (!uas) return;
912
    mavlink_message_t message;
lm's avatar
lm committed
913
    mavlink_mission_request_t wpr;
914

915
    wpr.target_system = uasid;
lm's avatar
lm committed
916
    wpr.target_component = MAV_COMP_ID_MISSIONPLANNER;
917 918
    wpr.seq = seq;

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

lm's avatar
lm committed
921 922 923
    mavlink_msg_mission_request_encode(uas->mavlink->getSystemId(), uas->mavlink->getComponentId(), &message, &wpr);
    if (uas) uas->sendMessage(message);
    QGC::SLEEP::msleep(PROTOCOL_DELAY_MS);
924

925
    // // qDebug() << "sent waypoint request (" << wpr.seq << ") to ID " << wpr.target_system;
pixhawk's avatar
pixhawk committed
926
}
pixhawk's avatar
pixhawk committed
927

pixhawk's avatar
pixhawk committed
928 929
void UASWaypointManager::sendWaypoint(quint16 seq)
{
lm's avatar
lm committed
930
    if (!uas) return;
pixhawk's avatar
pixhawk committed
931
    mavlink_message_t message;
932
    // // qDebug() <<" WP Buffer count: "<<waypoint_buffer.count();
pixhawk's avatar
pixhawk committed
933

934
    if (seq < waypoint_buffer.count()) {
935

lm's avatar
lm committed
936
        mavlink_mission_item_t *wp;
pixhawk's avatar
pixhawk committed
937

938

pixhawk's avatar
pixhawk committed
939
        wp = waypoint_buffer.at(seq);
940
        wp->target_system = uasid;
lm's avatar
lm committed
941
        wp->target_component = MAV_COMP_ID_MISSIONPLANNER;
pixhawk's avatar
pixhawk committed
942

943
        emit updateStatusString(QString("Sending waypoint ID %1 of %2 total").arg(wp->seq).arg(current_count));
pixhawk's avatar
pixhawk committed
944

945
        // // qDebug() << "sent waypoint (" << wp->seq << ") to ID " << wp->target_system<<" WP Buffer count: "<<waypoint_buffer.count();
946

lm's avatar
lm committed
947 948 949
        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
950
    }
pixhawk's avatar
pixhawk committed
951
}
952 953 954

void UASWaypointManager::sendWaypointAck(quint8 type)
{
lm's avatar
lm committed
955
    if (!uas) return;
956
    mavlink_message_t message;
lm's avatar
lm committed
957
    mavlink_mission_ack_t wpa;
958

959
    wpa.target_system = uasid;
lm's avatar
lm committed
960
    wpa.target_component = MAV_COMP_ID_MISSIONPLANNER;
961 962
    wpa.type = type;

lm's avatar
lm committed
963 964 965
    mavlink_msg_mission_ack_encode(uas->mavlink->getSystemId(), uas->mavlink->getComponentId(), &message, &wpa);
    if (uas) uas->sendMessage(message);
    QGC::SLEEP::msleep(PROTOCOL_DELAY_MS);
966

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