UASWaypointManager.cc 28.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
//#include "MainWindow.h"
36

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

41
UASWaypointManager::UASWaypointManager(UAS &_uas)
42 43 44 45 46 47 48
    : uas(_uas),
      current_retries(0),
      current_wp_id(0),
      current_count(0),
      current_state(WP_IDLE),
      current_partner_systemid(0),
      current_partner_compid(0),
49 50
      protocol_timer(this),
      currentWaypoint(NULL)
pixhawk's avatar
pixhawk committed
51 52
{
    connect(&protocol_timer, SIGNAL(timeout()), this, SLOT(timeout()));
53 54
    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)));
pixhawk's avatar
pixhawk committed
55 56 57
}

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

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

82
        emit updateStatusString("Operation timed out.");
pixhawk's avatar
pixhawk committed
83

84 85 86 87 88 89
        current_state = WP_IDLE;
        current_count = 0;
        current_wp_id = 0;
        current_partner_systemid = 0;
        current_partner_compid = 0;
    }
90 91
}

92 93 94 95
void UASWaypointManager::handleLocalPositionChanged(UASInterface* mav, double x, double y, double z, quint64 time)
{
    Q_UNUSED(mav);
    Q_UNUSED(time);
96
    if (waypoints.count() > 0 && currentWaypoint && (currentWaypoint->getFrame() == MAV_FRAME_LOCAL || currentWaypoint->getFrame() == MAV_FRAME_LOCAL_ENU))
97
    {
98 99 100
        double xdiff = x-currentWaypoint->getX();
        double ydiff = y-currentWaypoint->getY();
        double zdiff = z-currentWaypoint->getZ();
101 102 103 104 105 106 107 108 109 110
        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)
{

}

111 112
void UASWaypointManager::handleWaypointCount(quint8 systemId, quint8 compId, quint16 count)
{
113
    if (current_state == WP_GETLIST && systemId == current_partner_systemid && compId == current_partner_compid) {
114 115 116
        protocol_timer.start(PROTOCOL_TIMEOUT_MS);
        current_retries = PROTOCOL_MAX_RETRIES;

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

119
        if (count > 0) {
pixhawk's avatar
pixhawk committed
120 121 122
            current_count = count;
            current_wp_id = 0;
            current_state = WP_GETLIST_GETWPS;
123

pixhawk's avatar
pixhawk committed
124
            sendWaypointRequest(current_wp_id);
125
        } else {
126
            protocol_timer.stop();
pixhawk's avatar
pixhawk committed
127
            emit updateStatusString("done.");
128
            // qDebug() << "No waypoints on UAS " << systemId;
129 130 131 132 133
            current_state = WP_IDLE;
            current_count = 0;
            current_wp_id = 0;
            current_partner_systemid = 0;
            current_partner_compid = 0;
pixhawk's avatar
pixhawk committed
134
        }
135 136
    } 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);
137
    }
138 139
}

pixhawk's avatar
pixhawk committed
140 141
void UASWaypointManager::handleWaypoint(quint8 systemId, quint8 compId, mavlink_waypoint_t *wp)
{
142
    if (systemId == current_partner_systemid && compId == current_partner_compid && current_state == WP_GETLIST_GETWPS && wp->seq == current_wp_id) {
143 144 145
        protocol_timer.start(PROTOCOL_TIMEOUT_MS);
        current_retries = PROTOCOL_MAX_RETRIES;

146
        if(wp->seq == current_wp_id) {
147
            //// 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;
lm's avatar
lm committed
148
            Waypoint *lwp = 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);
pixhawk's avatar
pixhawk committed
149
            addWaypoint(lwp, false);
150
            if (wp->current == 1) currentWaypoint = lwp;
pixhawk's avatar
pixhawk committed
151 152 153 154

            //get next waypoint
            current_wp_id++;

155
            if(current_wp_id < current_count) {
156
                sendWaypointRequest(current_wp_id);
157
            } else {
158 159
                sendWaypointAck(0);

pixhawk's avatar
pixhawk committed
160
                // all waypoints retrieved, change state to idle
pixhawk's avatar
pixhawk committed
161 162 163 164 165
                current_state = WP_IDLE;
                current_count = 0;
                current_wp_id = 0;
                current_partner_systemid = 0;
                current_partner_compid = 0;
166

pixhawk's avatar
pixhawk committed
167
                protocol_timer.stop();
168
                emit readGlobalWPFromUAS(false);
169
                if (currentWaypoint) emit currentWaypointChanged(currentWaypoint->getId());
170 171
                emit updateStatusString("done.");

172
                // qDebug() << "got all waypoints from ID " << systemId;
pixhawk's avatar
pixhawk committed
173
            }
174
        } else {
175
            emit updateStatusString(tr("Waypoint ID mismatch, rejecting waypoint"));
pixhawk's avatar
pixhawk committed
176
        }
177 178
    } 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);
179
    }
pixhawk's avatar
pixhawk committed
180 181
}

182 183
void UASWaypointManager::handleWaypointAck(quint8 systemId, quint8 compId, mavlink_waypoint_ack_t *wpa)
{
184 185
    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)) {
186 187
            //all waypoints sent and ack received
            protocol_timer.stop();
188
            current_state = WP_IDLE;
189
            emit updateStatusString("done.");
190
            // qDebug() << "sent all waypoints to ID " << systemId;
191
        } else if(current_state == WP_CLEARLIST) {
192 193 194
            protocol_timer.stop();
            current_state = WP_IDLE;
            emit updateStatusString("done.");
195
            // qDebug() << "cleared waypoint list of ID " << systemId;
196
        }
197 198 199
    }
}

pixhawk's avatar
pixhawk committed
200
void UASWaypointManager::handleWaypointRequest(quint8 systemId, quint8 compId, mavlink_waypoint_request_t *wpr)
201
{
202
    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)))) {
203 204
        protocol_timer.start(PROTOCOL_TIMEOUT_MS);
        current_retries = PROTOCOL_MAX_RETRIES;
205

206
        if (wpr->seq < waypoint_buffer.count()) {
pixhawk's avatar
pixhawk committed
207 208 209
            current_state = WP_SENDLIST_SENDWPS;
            current_wp_id = wpr->seq;
            sendWaypoint(current_wp_id);
210
        } else {
pixhawk's avatar
pixhawk committed
211 212
            //TODO: Error message or something
        }
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
    }
216 217
}

pixhawk's avatar
pixhawk committed
218
void UASWaypointManager::handleWaypointReached(quint8 systemId, quint8 compId, mavlink_waypoint_reached_t *wpr)
219
{
220
    if (systemId == uas.getUASID() && compId == MAV_COMP_ID_WAYPOINTPLANNER) {
pixhawk's avatar
pixhawk committed
221 222
        emit updateStatusString(QString("Reached waypoint %1").arg(wpr->seq));
    }
pixhawk's avatar
pixhawk committed
223 224
}

225
void UASWaypointManager::handleWaypointCurrent(quint8 systemId, quint8 compId, mavlink_waypoint_current_t *wpc)
pixhawk's avatar
pixhawk committed
226
{
227
    if (systemId == uas.getUASID() && compId == MAV_COMP_ID_WAYPOINTPLANNER) {
228
        // FIXME Petri
229
        if (current_state == WP_SETCURRENT) {
230 231
            protocol_timer.stop();
            current_state = WP_IDLE;
232 233

            // update the local main storage
234 235 236
            if (wpc->seq < waypoints.size()) {
                for(int i = 0; i < waypoints.size(); i++) {
                    if (waypoints[i]->getId() == wpc->seq) {
237
                        waypoints[i]->setCurrent(true);
238 239
                        currentWaypoint = waypoints[i];

240
                    } else {
241 242 243 244 245
                        waypoints[i]->setCurrent(false);
                    }
                }
            }

246
            //// qDebug() << "Updated waypoints list";
247
        }
248 249 250
        emit updateStatusString(QString("New current waypoint %1").arg(wpc->seq));
        //emit update to UI widgets
        emit currentWaypointChanged(wpc->seq);
251
        //// qDebug() << "new current waypoint" << wpc->seq;
pixhawk's avatar
pixhawk committed
252
    }
pixhawk's avatar
pixhawk committed
253 254
}

255 256
void UASWaypointManager::notifyOfChange(Waypoint* wp)
{
257
    // qDebug() << "WAYPOINT CHANGED: ID:" << wp->getId();
258
    // If only one waypoint was changed, emit only WP signal
259
    if (wp != NULL) {
260
        emit waypointChanged(uas.getUASID(), wp);
261
    } else {
262 263 264
        emit waypointListChanged();
        emit waypointListChanged(uas.getUASID());
    }
265 266
}

267
int UASWaypointManager::setCurrentWaypoint(quint16 seq)
pixhawk's avatar
pixhawk committed
268
{
269 270
    if (seq < waypoints.size()) {
        if(current_state == WP_IDLE) {
271
            //update local main storage
272 273
            for(int i = 0; i < waypoints.size(); i++) {
                if (waypoints[i]->getId() == seq) {
274
                    waypoints[i]->setCurrent(true);
275
                    currentWaypoint = waypoints[i];
276
                } else {
277 278 279
                    waypoints[i]->setCurrent(false);
                }
            }
280

281
            //TODO: signal changed waypoint list
282

283 284 285 286 287 288 289 290 291 292 293 294 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;
            current_partner_systemid = uas.getUASID();
            current_partner_compid = MAV_COMP_ID_WAYPOINTPLANNER;

            sendWaypointSetCurrent(current_wp_id);

            //emit waypointListChanged();

            return 0;
        }
    }
    return -1;
}

pixhawk's avatar
pixhawk committed
302
/**
303
 * @warning Make sure the waypoint stays valid for the whole application lifecycle!
pixhawk's avatar
pixhawk committed
304
 * @param enforceFirstActive Enforces that the first waypoint is set as active
305
 * @see createWaypoint() is more suitable for most use cases
pixhawk's avatar
pixhawk committed
306 307
 */
void UASWaypointManager::addWaypoint(Waypoint *wp, bool enforceFirstActive)
308
{
309
    if (wp) {
310
        wp->setId(waypoints.size());
311 312 313 314 315
        if (enforceFirstActive && waypoints.size() == 0)
        {
            wp->setCurrent(true);
            currentWaypoint = wp;
        }
316
        waypoints.insert(waypoints.size(), wp);
317
        connect(wp, SIGNAL(changed(Waypoint*)), this, SLOT(notifyOfChange(Waypoint*)));
318

319
        emit waypointListChanged();
320
        emit waypointListChanged(uas.getUASID());
321
    }
pixhawk's avatar
pixhawk committed
322 323
}

324 325 326 327 328 329 330
/**
 * @param enforceFirstActive Enforces that the first waypoint is set as active
 */
Waypoint* UASWaypointManager::createWaypoint(bool enforceFirstActive)
{
    Waypoint* wp = new Waypoint();
    wp->setId(waypoints.size());
331 332 333 334 335
    if (enforceFirstActive && waypoints.size() == 0)
    {
        wp->setCurrent(true);
        currentWaypoint = wp;
    }
336 337 338 339 340 341 342 343
    waypoints.insert(waypoints.size(), wp);
    connect(wp, SIGNAL(changed(Waypoint*)), this, SLOT(notifyOfChange(Waypoint*)));

    emit waypointListChanged();
    emit waypointListChanged(uas.getUASID());
    return wp;
}

344
int UASWaypointManager::removeWaypoint(quint16 seq)
345
{
346
    if (seq < waypoints.size()) {
347 348 349
        Waypoint *t = waypoints[seq];
        waypoints.remove(seq);
        delete t;
350
        t = NULL;
351

352
        for(int i = seq; i < waypoints.size(); i++) {
353 354
            waypoints[i]->setId(i);
        }
Alejandro's avatar
Alejandro committed
355

356
        emit waypointListChanged();
357
        emit waypointListChanged(uas.getUASID());
358 359 360 361 362
        return 0;
    }
    return -1;
}

363
void UASWaypointManager::moveWaypoint(quint16 cur_seq, quint16 new_seq)
364
{
365
    if (cur_seq != new_seq && cur_seq < waypoints.size() && new_seq < waypoints.size()) {
366
        Waypoint *t = waypoints[cur_seq];
367 368
        if (cur_seq < new_seq) {
            for (int i = cur_seq; i < new_seq; i++) {
369 370 371
                waypoints[i] = waypoints[i+1];
                //waypoints[i]->setId(i);       // let the local IDs stay the same so that they can be found more easily by the user
            }
372 373
        } else {
            for (int i = cur_seq; i > new_seq; i--) {
374
                waypoints[i] = waypoints[i-1];
375
                // waypoints[i]->setId(i);
376 377 378 379 380 381
            }
        }
        waypoints[new_seq] = t;
        //waypoints[new_seq]->setId(new_seq);

        emit waypointListChanged();
382
        emit waypointListChanged(uas.getUASID());
383 384 385
    }
}

386
void UASWaypointManager::saveWaypoints(const QString &saveFile)
387 388 389 390 391 392
{
    QFile file(saveFile);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
        return;

    QTextStream out(&file);
393 394

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

397
    for (int i = 0; i < waypoints.size(); i++) {
398
        waypoints[i]->setId(i);
399 400 401 402 403
        waypoints[i]->save(out);
    }
    file.close();
}

404
void UASWaypointManager::loadWaypoints(const QString &loadFile)
405 406 407 408 409
{
    QFile file(loadFile);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
        return;

410
    while(waypoints.size()>0) {
411 412 413 414 415 416
        Waypoint *t = waypoints[0];
        waypoints.remove(0);
        delete t;
    }

    QTextStream in(&file);
417 418 419

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

420
    if (!(version.size() == 3 && version[0] == "QGC" && version[1] == "WPL" && version[2] == "110")) {
421 422
        emit updateStatusString(tr("The waypoint file is not compatible with the current version of QGroundControl."));
        //MainWindow::instance()->showCriticalMessage(tr("Error loading waypoint file"),tr("The waypoint file is not compatible with the current version of QGroundControl."));
423 424
    } else {
        while (!in.atEnd()) {
425
            Waypoint *t = new Waypoint();
426
            if(t->load(in)) {
427 428
                t->setId(waypoints.size());
                waypoints.insert(waypoints.size(), t);
429
            } else {
430 431
                emit updateStatusString(tr("The waypoint file is corrupted. Load operation only partly succesful."));
                //MainWindow::instance()->showCriticalMessage(tr("Error loading waypoint file"),);
432 433
                break;
            }
434 435
        }
    }
436

437 438
    file.close();

439
    emit loadWPFile();
440
    emit waypointListChanged();
441
    emit waypointListChanged(uas.getUASID());
442 443
}

444

445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
//void UASWaypointManager::globalAddWaypoint(Waypoint *wp)
//{
//    // FIXME Will be removed
//    Q_UNUSED(wp);
//}

//int UASWaypointManager::globalRemoveWaypoint(quint16 seq)
//{
//    // FIXME Will be removed
//    Q_UNUSED(seq);
//    return 0;
//}

//void UASWaypointManager::waypointUpdated(Waypoint*)
//{
//    // FIXME Add rate limiter
//    emit waypointListChanged(uas.getUASID());
//}
pixhawk's avatar
pixhawk committed
463

464
void UASWaypointManager::clearWaypointList()
pixhawk's avatar
pixhawk committed
465
{
466
    if(current_state == WP_IDLE) {
pixhawk's avatar
pixhawk committed
467
        protocol_timer.start(PROTOCOL_TIMEOUT_MS);
468
        current_retries = PROTOCOL_MAX_RETRIES;
pixhawk's avatar
pixhawk committed
469

470 471
        current_state = WP_CLEARLIST;
        current_wp_id = 0;
472 473
        current_partner_systemid = uas.getUASID();
        current_partner_compid = MAV_COMP_ID_WAYPOINTPLANNER;
pixhawk's avatar
pixhawk committed
474

475
        sendWaypointClearAll();
476 477 478
    }
}

479 480 481 482 483 484
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;
485 486
    foreach (Waypoint* wp, waypoints) {
        if (wp->getFrame() == MAV_FRAME_GLOBAL) {
487 488 489 490 491 492
            wps.append(wp);
        }
    }
    return wps;
}

lm's avatar
lm committed
493 494 495 496 497 498
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;
499 500
    foreach (Waypoint* wp, waypoints) {
        if (wp->getFrame() == MAV_FRAME_GLOBAL && wp->isNavigationType()) {
lm's avatar
lm committed
501 502 503 504 505 506
            wps.append(wp);
        }
    }
    return wps;
}

LM's avatar
LM committed
507 508 509 510 511 512 513 514 515 516 517 518 519 520
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;
    foreach (Waypoint* wp, waypoints) {
        if (wp->isNavigationType()) {
            wps.append(wp);
        }
    }
    return wps;
}

521 522 523 524 525
int UASWaypointManager::getIndexOf(Waypoint* wp)
{
    return waypoints.indexOf(wp);
}

526 527 528 529 530
int UASWaypointManager::getGlobalFrameIndexOf(Waypoint* wp)
{
    // Search through all waypoints,
    // counting only those in global frame
    int i = 0;
531 532 533
    foreach (Waypoint* p, waypoints) {
        if (p->getFrame() == MAV_FRAME_GLOBAL) {
            if (p == wp) {
534 535 536 537 538 539 540 541 542
                return i;
            }
            i++;
        }
    }

    return -1;
}

lm's avatar
lm committed
543 544 545 546 547
int UASWaypointManager::getGlobalFrameAndNavTypeIndexOf(Waypoint* wp)
{
    // Search through all waypoints,
    // counting only those in global frame
    int i = 0;
548 549 550
    foreach (Waypoint* p, waypoints) {
        if (p->getFrame() == MAV_FRAME_GLOBAL && p->isNavigationType()) {
            if (p == wp) {
lm's avatar
lm committed
551 552 553 554 555 556 557 558 559
                return i;
            }
            i++;
        }
    }

    return -1;
}

LM's avatar
LM committed
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
int UASWaypointManager::getNavTypeIndexOf(Waypoint* wp)
{
    // Search through all waypoints,
    // counting only those in global frame
    int i = 0;
    foreach (Waypoint* p, waypoints) {
        if (p->isNavigationType()) {
            if (p == wp) {
                return i;
            }
            i++;
        }
    }

    return -1;
}

577 578 579 580 581
int UASWaypointManager::getGlobalFrameCount()
{
    // Search through all waypoints,
    // counting only those in global frame
    int i = 0;
582 583
    foreach (Waypoint* p, waypoints) {
        if (p->getFrame() == MAV_FRAME_GLOBAL) {
584 585 586 587 588 589 590
            i++;
        }
    }

    return i;
}

lm's avatar
lm committed
591 592 593 594 595
int UASWaypointManager::getGlobalFrameAndNavTypeCount()
{
    // Search through all waypoints,
    // counting only those in global frame
    int i = 0;
596 597
    foreach (Waypoint* p, waypoints) {
        if (p->getFrame() == MAV_FRAME_GLOBAL && p->isNavigationType()) {
lm's avatar
lm committed
598 599 600 601 602 603 604
            i++;
        }
    }

    return i;
}

LM's avatar
LM committed
605 606 607 608 609 610 611 612 613 614 615 616 617 618
int UASWaypointManager::getNavTypeCount()
{
    // Search through all waypoints,
    // counting only those in global frame
    int i = 0;
    foreach (Waypoint* p, waypoints) {
        if (p->isNavigationType()) {
            i++;
        }
    }

    return i;
}

619 620 621 622 623
int UASWaypointManager::getLocalFrameCount()
{
    // Search through all waypoints,
    // counting only those in global frame
    int i = 0;
624 625
    foreach (Waypoint* p, waypoints) {
        if (p->getFrame() == MAV_FRAME_GLOBAL) {
626 627 628 629 630 631 632 633 634 635 636 637
            i++;
        }
    }

    return i;
}

int UASWaypointManager::getLocalFrameIndexOf(Waypoint* wp)
{
    // Search through all waypoints,
    // counting only those in local frame
    int i = 0;
638 639 640
    foreach (Waypoint* p, waypoints) {
        if (p->getFrame() == MAV_FRAME_LOCAL) {
            if (p == wp) {
641 642 643 644 645 646 647 648 649 650 651 652 653 654
                return i;
            }
            i++;
        }
    }

    return -1;
}

int UASWaypointManager::getMissionFrameIndexOf(Waypoint* wp)
{
    // Search through all waypoints,
    // counting only those in mission frame
    int i = 0;
655 656 657
    foreach (Waypoint* p, waypoints) {
        if (p->getFrame() == MAV_FRAME_MISSION) {
            if (p == wp) {
658 659 660 661 662 663 664 665 666
                return i;
            }
            i++;
        }
    }

    return -1;
}

667 668
void UASWaypointManager::readWaypoints()
{
669
    emit readGlobalWPFromUAS(true);
670 671
    if(current_state == WP_IDLE) {
        while(waypoints.size()>0) {
672
            delete waypoints.back();
673
            waypoints.pop_back();
674

675 676
        }

677 678
        protocol_timer.start(PROTOCOL_TIMEOUT_MS);
        current_retries = PROTOCOL_MAX_RETRIES;
pixhawk's avatar
pixhawk committed
679 680 681 682 683 684

        current_state = WP_GETLIST;
        current_wp_id = 0;
        current_partner_systemid = uas.getUASID();
        current_partner_compid = MAV_COMP_ID_WAYPOINTPLANNER;

685
        sendWaypointRequestList();
686

pixhawk's avatar
pixhawk committed
687 688 689
    }
}

690
void UASWaypointManager::writeWaypoints()
pixhawk's avatar
pixhawk committed
691
{
692
    if (current_state == WP_IDLE) {
pixhawk's avatar
pixhawk committed
693
        // Send clear all if count == 0
694
        if (waypoints.count() > 0) {
pixhawk's avatar
pixhawk committed
695
            protocol_timer.start(PROTOCOL_TIMEOUT_MS);
696
            current_retries = PROTOCOL_MAX_RETRIES;
pixhawk's avatar
pixhawk committed
697

698
            current_count = waypoints.count();
pixhawk's avatar
pixhawk committed
699 700 701 702 703 704
            current_state = WP_SENDLIST;
            current_wp_id = 0;
            current_partner_systemid = uas.getUASID();
            current_partner_compid = MAV_COMP_ID_WAYPOINTPLANNER;

            //clear local buffer
pixhawk's avatar
pixhawk committed
705 706 707
            // 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.
708
            while(!waypoint_buffer.empty()) {
pixhawk's avatar
pixhawk committed
709 710 711
                delete waypoint_buffer.back();
                waypoint_buffer.pop_back();
            }
pixhawk's avatar
pixhawk committed
712

713 714
            bool noCurrent = true;

pixhawk's avatar
pixhawk committed
715
            //copy waypoint data to local buffer
716
            for (int i=0; i < current_count; i++) {
pixhawk's avatar
pixhawk committed
717 718 719
                waypoint_buffer.push_back(new mavlink_waypoint_t);
                mavlink_waypoint_t *cur_d = waypoint_buffer.back();
                memset(cur_d, 0, sizeof(mavlink_waypoint_t));   //initialize with zeros
720
                const Waypoint *cur_s = waypoints.at(i);
pixhawk's avatar
pixhawk committed
721 722

                cur_d->autocontinue = cur_s->getAutoContinue();
723
                cur_d->current = cur_s->getCurrent() & noCurrent;   //make sure only one current waypoint is selected, the first selected will be chosen
724 725
                cur_d->param1 = cur_s->getParam1();
                cur_d->param2 = cur_s->getParam2();
lm's avatar
lm committed
726 727
                cur_d->param3 = cur_s->getParam3();
                cur_d->param4 = cur_s->getParam4();
728
                cur_d->frame = cur_s->getFrame();
lm's avatar
lm committed
729
                cur_d->command = cur_s->getAction();
730
                cur_d->seq = i;     // don't read out the sequence number of the waypoint class
pixhawk's avatar
pixhawk committed
731 732 733
                cur_d->x = cur_s->getX();
                cur_d->y = cur_s->getY();
                cur_d->z = cur_s->getZ();
734 735 736

                if (cur_s->getCurrent() && noCurrent)
                    noCurrent = false;
737 738
                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
739
            }
740

741 742 743



pixhawk's avatar
pixhawk committed
744
            //send the waypoint count to UAS (this starts the send transaction)
745
            sendWaypointCount();
pixhawk's avatar
pixhawk committed
746
        }
747
    } else if (waypoints.count() == 0) {
748
        sendWaypointClearAll();
749
    } else {
750
        //we're in another transaction, ignore command
751
        // qDebug() << "UASWaypointManager::sendWaypoints() doing something else ignoring command";
752
    }
pixhawk's avatar
pixhawk committed
753 754
}

755 756 757 758 759 760 761 762
void UASWaypointManager::sendWaypointClearAll()
{
    mavlink_message_t message;
    mavlink_waypoint_clear_all_t wpca;

    wpca.target_system = uas.getUASID();
    wpca.target_component = MAV_COMP_ID_WAYPOINTPLANNER;

763
    emit updateStatusString(QString("Clearing waypoint list..."));
764 765 766

    mavlink_msg_waypoint_clear_all_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, &wpca);
    uas.sendMessage(message);
767
    MG::SLEEP::usleep(PROTOCOL_DELAY_MS * 1000);
768

769
    // qDebug() << "sent waypoint clear all to ID " << wpca.target_system;
770 771 772 773 774 775 776 777 778 779 780
}

void UASWaypointManager::sendWaypointSetCurrent(quint16 seq)
{
    mavlink_message_t message;
    mavlink_waypoint_set_current_t wpsc;

    wpsc.target_system = uas.getUASID();
    wpsc.target_component = MAV_COMP_ID_WAYPOINTPLANNER;
    wpsc.seq = seq;

781
    emit updateStatusString(QString("Updating target waypoint..."));
782 783 784

    mavlink_msg_waypoint_set_current_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, &wpsc);
    uas.sendMessage(message);
785
    MG::SLEEP::usleep(PROTOCOL_DELAY_MS * 1000);
786

787
    // qDebug() << "sent waypoint set current (" << wpsc.seq << ") to ID " << wpsc.target_system;
788 789 790 791 792 793 794 795 796 797 798
}

void UASWaypointManager::sendWaypointCount()
{
    mavlink_message_t message;
    mavlink_waypoint_count_t wpc;

    wpc.target_system = uas.getUASID();
    wpc.target_component = MAV_COMP_ID_WAYPOINTPLANNER;
    wpc.count = current_count;

799
    // qDebug() << "sent waypoint count (" << wpc.count << ") to ID " << wpc.target_system;
800
    emit updateStatusString(QString("Starting to transmit waypoints..."));
801 802 803

    mavlink_msg_waypoint_count_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, &wpc);
    uas.sendMessage(message);
804
    MG::SLEEP::usleep(PROTOCOL_DELAY_MS * 1000);
805

806
    // qDebug() << "sent waypoint count (" << wpc.count << ") to ID " << wpc.target_system;
807 808 809 810 811 812 813 814 815 816
}

void UASWaypointManager::sendWaypointRequestList()
{
    mavlink_message_t message;
    mavlink_waypoint_request_list_t wprl;

    wprl.target_system = uas.getUASID();
    wprl.target_component = MAV_COMP_ID_WAYPOINTPLANNER;

817
    emit updateStatusString(QString("Requesting waypoint list..."));
818 819 820

    mavlink_msg_waypoint_request_list_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, &wprl);
    uas.sendMessage(message);
821
    MG::SLEEP::usleep(PROTOCOL_DELAY_MS * 1000);
822

823
    // qDebug() << "sent waypoint list request to ID " << wprl.target_system;
824 825


826 827
}

828
void UASWaypointManager::sendWaypointRequest(quint16 seq)
pixhawk's avatar
pixhawk committed
829
{
830 831 832 833 834 835 836
    mavlink_message_t message;
    mavlink_waypoint_request_t wpr;

    wpr.target_system = uas.getUASID();
    wpr.target_component = MAV_COMP_ID_WAYPOINTPLANNER;
    wpr.seq = seq;

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

839 840
    mavlink_msg_waypoint_request_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, &wpr);
    uas.sendMessage(message);
841
    MG::SLEEP::usleep(PROTOCOL_DELAY_MS * 1000);
842

843
    // qDebug() << "sent waypoint request (" << wpr.seq << ") to ID " << wpr.target_system;
pixhawk's avatar
pixhawk committed
844
}
pixhawk's avatar
pixhawk committed
845

pixhawk's avatar
pixhawk committed
846 847 848
void UASWaypointManager::sendWaypoint(quint16 seq)
{
    mavlink_message_t message;
849
    // qDebug() <<" WP Buffer count: "<<waypoint_buffer.count();
pixhawk's avatar
pixhawk committed
850

851
    if (seq < waypoint_buffer.count()) {
852

pixhawk's avatar
pixhawk committed
853 854
        mavlink_waypoint_t *wp;

855

pixhawk's avatar
pixhawk committed
856 857 858 859
        wp = waypoint_buffer.at(seq);
        wp->target_system = uas.getUASID();
        wp->target_component = MAV_COMP_ID_WAYPOINTPLANNER;

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

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

pixhawk's avatar
pixhawk committed
864 865
        mavlink_msg_waypoint_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, wp);
        uas.sendMessage(message);
866
        MG::SLEEP::usleep(PROTOCOL_DELAY_MS * 1000);
pixhawk's avatar
pixhawk committed
867 868

    }
pixhawk's avatar
pixhawk committed
869
}
870 871 872 873 874 875 876 877 878 879 880 881

void UASWaypointManager::sendWaypointAck(quint8 type)
{
    mavlink_message_t message;
    mavlink_waypoint_ack_t wpa;

    wpa.target_system = uas.getUASID();
    wpa.target_component = MAV_COMP_ID_WAYPOINTPLANNER;
    wpa.type = type;

    mavlink_msg_waypoint_ack_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, &wpa);
    uas.sendMessage(message);
882
    MG::SLEEP::usleep(PROTOCOL_DELAY_MS * 1000);
883

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