UASWaypointManager.cc 27.2 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
37
#define PROTOCOL_DELAY_MS 40        ///< minimum delay between sent messages
38
#define PROTOCOL_MAX_RETRIES 3      ///< maximum number of send retries (after timeout)
pixhawk's avatar
pixhawk committed
39

40
UASWaypointManager::UASWaypointManager(UAS &_uas)
41 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),
      protocol_timer(this)
pixhawk's avatar
pixhawk committed
49 50 51 52 53
{
    connect(&protocol_timer, SIGNAL(timeout()), this, SLOT(timeout()));
}

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

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

78
        emit updateStatusString("Operation timed out.");
pixhawk's avatar
pixhawk committed
79

80 81 82 83 84 85
        current_state = WP_IDLE;
        current_count = 0;
        current_wp_id = 0;
        current_partner_systemid = 0;
        current_partner_compid = 0;
    }
86 87 88 89
}

void UASWaypointManager::handleWaypointCount(quint8 systemId, quint8 compId, quint16 count)
{
90
    if (current_state == WP_GETLIST && systemId == current_partner_systemid && compId == current_partner_compid) {
91 92 93
        protocol_timer.start(PROTOCOL_TIMEOUT_MS);
        current_retries = PROTOCOL_MAX_RETRIES;

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

96
        if (count > 0) {
pixhawk's avatar
pixhawk committed
97 98 99
            current_count = count;
            current_wp_id = 0;
            current_state = WP_GETLIST_GETWPS;
100

pixhawk's avatar
pixhawk committed
101
            sendWaypointRequest(current_wp_id);
102
        } else {
103
            protocol_timer.stop();
pixhawk's avatar
pixhawk committed
104
            emit updateStatusString("done.");
105
            // qDebug() << "No waypoints on UAS " << systemId;
106 107 108 109 110
            current_state = WP_IDLE;
            current_count = 0;
            current_wp_id = 0;
            current_partner_systemid = 0;
            current_partner_compid = 0;
pixhawk's avatar
pixhawk committed
111
        }
112 113
    } 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);
114
    }
115 116
}

lm's avatar
lm committed
117
void UASWaypointManager::handleWaypoint(quint8 systemId, quint8 compId, mavlink_mission_item_t *wp)
pixhawk's avatar
pixhawk committed
118
{
119
    if (systemId == current_partner_systemid && compId == current_partner_compid && current_state == WP_GETLIST_GETWPS && wp->seq == current_wp_id) {
120 121 122
        protocol_timer.start(PROTOCOL_TIMEOUT_MS);
        current_retries = PROTOCOL_MAX_RETRIES;

123
        if(wp->seq == current_wp_id) {
124
            //// 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
125
            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
126
            addWaypoint(lwp, false);
pixhawk's avatar
pixhawk committed
127 128 129 130

            //get next waypoint
            current_wp_id++;

131
            if(current_wp_id < current_count) {
132
                sendWaypointRequest(current_wp_id);
133
            } else {
134 135
                sendWaypointAck(0);

pixhawk's avatar
pixhawk committed
136
                // all waypoints retrieved, change state to idle
pixhawk's avatar
pixhawk committed
137 138 139 140 141
                current_state = WP_IDLE;
                current_count = 0;
                current_wp_id = 0;
                current_partner_systemid = 0;
                current_partner_compid = 0;
142

pixhawk's avatar
pixhawk committed
143
                protocol_timer.stop();
144
                emit readGlobalWPFromUAS(false);
145 146
                emit updateStatusString("done.");

147
                // qDebug() << "got all waypoints from ID " << systemId;
pixhawk's avatar
pixhawk committed
148
            }
149
        } else {
150
            emit updateStatusString(tr("Waypoint ID mismatch, rejecting waypoint"));
pixhawk's avatar
pixhawk committed
151
        }
152 153
    } 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);
154
    }
pixhawk's avatar
pixhawk committed
155 156
}

lm's avatar
lm committed
157
void UASWaypointManager::handleWaypointAck(quint8 systemId, quint8 compId, mavlink_mission_ack_t *wpa)
158
{
159 160
    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)) {
161 162
            //all waypoints sent and ack received
            protocol_timer.stop();
163
            current_state = WP_IDLE;
164
            emit updateStatusString("done.");
165
            // qDebug() << "sent all waypoints to ID " << systemId;
166
        } else if(current_state == WP_CLEARLIST) {
167 168 169
            protocol_timer.stop();
            current_state = WP_IDLE;
            emit updateStatusString("done.");
170
            // qDebug() << "cleared waypoint list of ID " << systemId;
171
        }
172 173 174
    }
}

lm's avatar
lm committed
175
void UASWaypointManager::handleWaypointRequest(quint8 systemId, quint8 compId, mavlink_mission_request_t *wpr)
176
{
177
    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)))) {
178 179
        protocol_timer.start(PROTOCOL_TIMEOUT_MS);
        current_retries = PROTOCOL_MAX_RETRIES;
180

181
        if (wpr->seq < waypoint_buffer.count()) {
pixhawk's avatar
pixhawk committed
182 183 184
            current_state = WP_SENDLIST_SENDWPS;
            current_wp_id = wpr->seq;
            sendWaypoint(current_wp_id);
185
        } else {
pixhawk's avatar
pixhawk committed
186 187
            //TODO: Error message or something
        }
188 189
    } 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);
190
    }
191 192
}

lm's avatar
lm committed
193
void UASWaypointManager::handleWaypointReached(quint8 systemId, quint8 compId, mavlink_mission_item_reached_t *wpr)
194
{
lm's avatar
lm committed
195
    if (systemId == uas.getUASID()) {
pixhawk's avatar
pixhawk committed
196 197
        emit updateStatusString(QString("Reached waypoint %1").arg(wpr->seq));
    }
pixhawk's avatar
pixhawk committed
198 199
}

lm's avatar
lm committed
200
void UASWaypointManager::handleWaypointCurrent(quint8 systemId, quint8 compId, mavlink_mission_current_t *wpc)
pixhawk's avatar
pixhawk committed
201
{
lm's avatar
lm committed
202
    if (systemId == uas.getUASID()) {
203
        // FIXME Petri
204
        if (current_state == WP_SETCURRENT) {
205 206
            protocol_timer.stop();
            current_state = WP_IDLE;
207 208

            // update the local main storage
209 210 211
            if (wpc->seq < waypoints.size()) {
                for(int i = 0; i < waypoints.size(); i++) {
                    if (waypoints[i]->getId() == wpc->seq) {
212
                        waypoints[i]->setCurrent(true);
213
                    } else {
214 215 216 217 218
                        waypoints[i]->setCurrent(false);
                    }
                }
            }

219
            //// qDebug() << "Updated waypoints list";
220
        }
221 222 223
        emit updateStatusString(QString("New current waypoint %1").arg(wpc->seq));
        //emit update to UI widgets
        emit currentWaypointChanged(wpc->seq);
224
        //// qDebug() << "new current waypoint" << wpc->seq;
pixhawk's avatar
pixhawk committed
225
    }
pixhawk's avatar
pixhawk committed
226 227
}

228 229
void UASWaypointManager::notifyOfChange(Waypoint* wp)
{
230
    // qDebug() << "WAYPOINT CHANGED: ID:" << wp->getId();
231
    // If only one waypoint was changed, emit only WP signal
232
    if (wp != NULL) {
233
        emit waypointChanged(uas.getUASID(), wp);
234
    } else {
235 236 237
        emit waypointListChanged();
        emit waypointListChanged(uas.getUASID());
    }
238 239
}

240
int UASWaypointManager::setCurrentWaypoint(quint16 seq)
pixhawk's avatar
pixhawk committed
241
{
242 243
    if (seq < waypoints.size()) {
        if(current_state == WP_IDLE) {
244
            //update local main storage
245 246
            for(int i = 0; i < waypoints.size(); i++) {
                if (waypoints[i]->getId() == seq) {
247
                    waypoints[i]->setCurrent(true);
248
                } else {
249 250 251
                    waypoints[i]->setCurrent(false);
                }
            }
252

253
            //TODO: signal changed waypoint list
254

255 256 257 258 259 260 261
            //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();
lm's avatar
lm committed
262
            current_partner_compid = MAV_COMP_ID_MISSIONPLANNER;
263 264 265 266 267 268 269 270 271 272 273

            sendWaypointSetCurrent(current_wp_id);

            //emit waypointListChanged();

            return 0;
        }
    }
    return -1;
}

pixhawk's avatar
pixhawk committed
274
/**
275
 * @warning Make sure the waypoint stays valid for the whole application lifecycle!
pixhawk's avatar
pixhawk committed
276
 * @param enforceFirstActive Enforces that the first waypoint is set as active
277
 * @see createWaypoint() is more suitable for most use cases
pixhawk's avatar
pixhawk committed
278 279
 */
void UASWaypointManager::addWaypoint(Waypoint *wp, bool enforceFirstActive)
280
{
281
    if (wp) {
282
        wp->setId(waypoints.size());
pixhawk's avatar
pixhawk committed
283
        if (enforceFirstActive && waypoints.size() == 0) wp->setCurrent(true);
284
        waypoints.insert(waypoints.size(), wp);
285
        connect(wp, SIGNAL(changed(Waypoint*)), this, SLOT(notifyOfChange(Waypoint*)));
286

287
        emit waypointListChanged();
288
        emit waypointListChanged(uas.getUASID());
289
    }
pixhawk's avatar
pixhawk committed
290 291
}

292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
/**
 * @param enforceFirstActive Enforces that the first waypoint is set as active
 */
Waypoint* UASWaypointManager::createWaypoint(bool enforceFirstActive)
{
    Waypoint* wp = new Waypoint();
    wp->setId(waypoints.size());
    if (enforceFirstActive && waypoints.size() == 0) wp->setCurrent(true);
    waypoints.insert(waypoints.size(), wp);
    connect(wp, SIGNAL(changed(Waypoint*)), this, SLOT(notifyOfChange(Waypoint*)));

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

308
int UASWaypointManager::removeWaypoint(quint16 seq)
309
{
310
    if (seq < waypoints.size()) {
311 312 313
        Waypoint *t = waypoints[seq];
        waypoints.remove(seq);
        delete t;
314
        t = NULL;
315

316
        for(int i = seq; i < waypoints.size(); i++) {
317 318
            waypoints[i]->setId(i);
        }
Alejandro's avatar
Alejandro committed
319

320
        emit waypointListChanged();
321
        emit waypointListChanged(uas.getUASID());
322 323 324 325 326
        return 0;
    }
    return -1;
}

327
void UASWaypointManager::moveWaypoint(quint16 cur_seq, quint16 new_seq)
328
{
329
    if (cur_seq != new_seq && cur_seq < waypoints.size() && new_seq < waypoints.size()) {
330
        Waypoint *t = waypoints[cur_seq];
331 332
        if (cur_seq < new_seq) {
            for (int i = cur_seq; i < new_seq; i++) {
333 334 335
                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
            }
336 337
        } else {
            for (int i = cur_seq; i > new_seq; i--) {
338
                waypoints[i] = waypoints[i-1];
339
                // waypoints[i]->setId(i);
340 341 342 343 344 345
            }
        }
        waypoints[new_seq] = t;
        //waypoints[new_seq]->setId(new_seq);

        emit waypointListChanged();
346
        emit waypointListChanged(uas.getUASID());
347 348 349
    }
}

350
void UASWaypointManager::saveWaypoints(const QString &saveFile)
351 352 353 354 355 356
{
    QFile file(saveFile);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
        return;

    QTextStream out(&file);
357 358

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

361
    for (int i = 0; i < waypoints.size(); i++) {
362
        waypoints[i]->setId(i);
363 364 365 366 367
        waypoints[i]->save(out);
    }
    file.close();
}

368
void UASWaypointManager::loadWaypoints(const QString &loadFile)
369 370 371 372 373
{
    QFile file(loadFile);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
        return;

374
    while(waypoints.size()>0) {
375 376 377 378 379 380
        Waypoint *t = waypoints[0];
        waypoints.remove(0);
        delete t;
    }

    QTextStream in(&file);
381 382 383

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

384
    if (!(version.size() == 3 && version[0] == "QGC" && version[1] == "WPL" && version[2] == "110")) {
385 386
        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."));
387 388
    } else {
        while (!in.atEnd()) {
389
            Waypoint *t = new Waypoint();
390
            if(t->load(in)) {
391 392
                t->setId(waypoints.size());
                waypoints.insert(waypoints.size(), t);
393
            } else {
394 395
                emit updateStatusString(tr("The waypoint file is corrupted. Load operation only partly succesful."));
                //MainWindow::instance()->showCriticalMessage(tr("Error loading waypoint file"),);
396 397
                break;
            }
398 399
        }
    }
400

401 402
    file.close();

403
    emit loadWPFile();
404
    emit waypointListChanged();
405
    emit waypointListChanged(uas.getUASID());
406 407
}

408

409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
//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
427

428
void UASWaypointManager::clearWaypointList()
pixhawk's avatar
pixhawk committed
429
{
430
    if(current_state == WP_IDLE) {
pixhawk's avatar
pixhawk committed
431
        protocol_timer.start(PROTOCOL_TIMEOUT_MS);
432
        current_retries = PROTOCOL_MAX_RETRIES;
pixhawk's avatar
pixhawk committed
433

434 435
        current_state = WP_CLEARLIST;
        current_wp_id = 0;
436
        current_partner_systemid = uas.getUASID();
lm's avatar
lm committed
437
        current_partner_compid = MAV_COMP_ID_MISSIONPLANNER;
pixhawk's avatar
pixhawk committed
438

439
        sendWaypointClearAll();
440 441 442
    }
}

443 444 445 446 447 448
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;
449 450
    foreach (Waypoint* wp, waypoints) {
        if (wp->getFrame() == MAV_FRAME_GLOBAL) {
451 452 453 454 455 456
            wps.append(wp);
        }
    }
    return wps;
}

lm's avatar
lm committed
457 458 459 460 461 462
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;
463 464
    foreach (Waypoint* wp, waypoints) {
        if (wp->getFrame() == MAV_FRAME_GLOBAL && wp->isNavigationType()) {
lm's avatar
lm committed
465 466 467 468 469 470
            wps.append(wp);
        }
    }
    return wps;
}

LM's avatar
LM committed
471 472 473 474 475 476 477 478 479 480 481 482 483 484
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;
}

485 486 487 488 489
int UASWaypointManager::getIndexOf(Waypoint* wp)
{
    return waypoints.indexOf(wp);
}

490 491 492 493 494
int UASWaypointManager::getGlobalFrameIndexOf(Waypoint* wp)
{
    // Search through all waypoints,
    // counting only those in global frame
    int i = 0;
495 496 497
    foreach (Waypoint* p, waypoints) {
        if (p->getFrame() == MAV_FRAME_GLOBAL) {
            if (p == wp) {
498 499 500 501 502 503 504 505 506
                return i;
            }
            i++;
        }
    }

    return -1;
}

lm's avatar
lm committed
507 508 509 510 511
int UASWaypointManager::getGlobalFrameAndNavTypeIndexOf(Waypoint* wp)
{
    // Search through all waypoints,
    // counting only those in global frame
    int i = 0;
512 513 514
    foreach (Waypoint* p, waypoints) {
        if (p->getFrame() == MAV_FRAME_GLOBAL && p->isNavigationType()) {
            if (p == wp) {
lm's avatar
lm committed
515 516 517 518 519 520 521 522 523
                return i;
            }
            i++;
        }
    }

    return -1;
}

LM's avatar
LM committed
524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
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;
}

541 542 543 544 545
int UASWaypointManager::getGlobalFrameCount()
{
    // Search through all waypoints,
    // counting only those in global frame
    int i = 0;
546 547
    foreach (Waypoint* p, waypoints) {
        if (p->getFrame() == MAV_FRAME_GLOBAL) {
548 549 550 551 552 553 554
            i++;
        }
    }

    return i;
}

lm's avatar
lm committed
555 556 557 558 559
int UASWaypointManager::getGlobalFrameAndNavTypeCount()
{
    // Search through all waypoints,
    // counting only those in global frame
    int i = 0;
560 561
    foreach (Waypoint* p, waypoints) {
        if (p->getFrame() == MAV_FRAME_GLOBAL && p->isNavigationType()) {
lm's avatar
lm committed
562 563 564 565 566 567 568
            i++;
        }
    }

    return i;
}

LM's avatar
LM committed
569 570 571 572 573 574 575 576 577 578 579 580 581 582
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;
}

583 584 585 586 587
int UASWaypointManager::getLocalFrameCount()
{
    // Search through all waypoints,
    // counting only those in global frame
    int i = 0;
lm's avatar
lm committed
588 589 590 591
    foreach (Waypoint* p, waypoints)
    {
        if (p->getFrame() == MAV_FRAME_GLOBAL)
        {
592 593 594 595 596 597 598 599 600 601 602 603
            i++;
        }
    }

    return i;
}

int UASWaypointManager::getLocalFrameIndexOf(Waypoint* wp)
{
    // Search through all waypoints,
    // counting only those in local frame
    int i = 0;
lm's avatar
lm committed
604 605 606 607
    foreach (Waypoint* p, waypoints)
    {
        if (p->getFrame() == MAV_FRAME_LOCAL_NED || p->getFrame() == MAV_FRAME_LOCAL_ENU)
        {
608
            if (p == wp) {
609 610 611 612 613 614 615 616 617 618 619 620 621 622
                return i;
            }
            i++;
        }
    }

    return -1;
}

int UASWaypointManager::getMissionFrameIndexOf(Waypoint* wp)
{
    // Search through all waypoints,
    // counting only those in mission frame
    int i = 0;
lm's avatar
lm committed
623 624
    foreach (Waypoint* p, waypoints)
    {
625 626
        if (p->getFrame() == MAV_FRAME_MISSION) {
            if (p == wp) {
627 628 629 630 631 632 633 634 635
                return i;
            }
            i++;
        }
    }

    return -1;
}

636 637
void UASWaypointManager::readWaypoints()
{
638
    emit readGlobalWPFromUAS(true);
639 640
    if(current_state == WP_IDLE) {
        while(waypoints.size()>0) {
641
            delete waypoints.back();
642
            waypoints.pop_back();
643

644 645
        }

646 647
        protocol_timer.start(PROTOCOL_TIMEOUT_MS);
        current_retries = PROTOCOL_MAX_RETRIES;
pixhawk's avatar
pixhawk committed
648 649 650 651

        current_state = WP_GETLIST;
        current_wp_id = 0;
        current_partner_systemid = uas.getUASID();
lm's avatar
lm committed
652
        current_partner_compid = MAV_COMP_ID_MISSIONPLANNER;
pixhawk's avatar
pixhawk committed
653

654
        sendWaypointRequestList();
655

pixhawk's avatar
pixhawk committed
656 657 658
    }
}

659
void UASWaypointManager::writeWaypoints()
pixhawk's avatar
pixhawk committed
660
{
661
    if (current_state == WP_IDLE) {
pixhawk's avatar
pixhawk committed
662
        // Send clear all if count == 0
663
        if (waypoints.count() > 0) {
pixhawk's avatar
pixhawk committed
664
            protocol_timer.start(PROTOCOL_TIMEOUT_MS);
665
            current_retries = PROTOCOL_MAX_RETRIES;
pixhawk's avatar
pixhawk committed
666

667
            current_count = waypoints.count();
pixhawk's avatar
pixhawk committed
668 669 670
            current_state = WP_SENDLIST;
            current_wp_id = 0;
            current_partner_systemid = uas.getUASID();
lm's avatar
lm committed
671
            current_partner_compid = MAV_COMP_ID_MISSIONPLANNER;
pixhawk's avatar
pixhawk committed
672 673

            //clear local buffer
pixhawk's avatar
pixhawk committed
674 675 676
            // 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.
677
            while(!waypoint_buffer.empty()) {
pixhawk's avatar
pixhawk committed
678 679 680
                delete waypoint_buffer.back();
                waypoint_buffer.pop_back();
            }
pixhawk's avatar
pixhawk committed
681

682 683
            bool noCurrent = true;

pixhawk's avatar
pixhawk committed
684
            //copy waypoint data to local buffer
685
            for (int i=0; i < current_count; i++) {
lm's avatar
lm committed
686 687 688
                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
689
                const Waypoint *cur_s = waypoints.at(i);
pixhawk's avatar
pixhawk committed
690 691

                cur_d->autocontinue = cur_s->getAutoContinue();
692
                cur_d->current = cur_s->getCurrent() & noCurrent;   //make sure only one current waypoint is selected, the first selected will be chosen
693 694
                cur_d->param1 = cur_s->getParam1();
                cur_d->param2 = cur_s->getParam2();
lm's avatar
lm committed
695 696
                cur_d->param3 = cur_s->getParam3();
                cur_d->param4 = cur_s->getParam4();
697
                cur_d->frame = cur_s->getFrame();
lm's avatar
lm committed
698
                cur_d->command = cur_s->getAction();
699
                cur_d->seq = i;     // don't read out the sequence number of the waypoint class
pixhawk's avatar
pixhawk committed
700 701 702
                cur_d->x = cur_s->getX();
                cur_d->y = cur_s->getY();
                cur_d->z = cur_s->getZ();
703 704 705

                if (cur_s->getCurrent() && noCurrent)
                    noCurrent = false;
706 707
                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
708
            }
709

710 711 712



pixhawk's avatar
pixhawk committed
713
            //send the waypoint count to UAS (this starts the send transaction)
714
            sendWaypointCount();
pixhawk's avatar
pixhawk committed
715
        }
716
    } else if (waypoints.count() == 0) {
717
        sendWaypointClearAll();
718
    } else {
719
        //we're in another transaction, ignore command
720
        // qDebug() << "UASWaypointManager::sendWaypoints() doing something else ignoring command";
721
    }
pixhawk's avatar
pixhawk committed
722 723
}

724 725 726
void UASWaypointManager::sendWaypointClearAll()
{
    mavlink_message_t message;
lm's avatar
lm committed
727
    mavlink_mission_clear_all_t wpca;
728 729

    wpca.target_system = uas.getUASID();
lm's avatar
lm committed
730
    wpca.target_component = MAV_COMP_ID_MISSIONPLANNER;
731

732
    emit updateStatusString(QString("Clearing waypoint list..."));
733

lm's avatar
lm committed
734
    mavlink_msg_mission_clear_all_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, &wpca);
735
    uas.sendMessage(message);
736
    MG::SLEEP::usleep(PROTOCOL_DELAY_MS * 1000);
737

738
    // qDebug() << "sent waypoint clear all to ID " << wpca.target_system;
739 740 741 742 743
}

void UASWaypointManager::sendWaypointSetCurrent(quint16 seq)
{
    mavlink_message_t message;
lm's avatar
lm committed
744
    mavlink_mission_set_current_t wpsc;
745 746

    wpsc.target_system = uas.getUASID();
lm's avatar
lm committed
747
    wpsc.target_component = MAV_COMP_ID_MISSIONPLANNER;
748 749
    wpsc.seq = seq;

750
    emit updateStatusString(QString("Updating target waypoint..."));
751

lm's avatar
lm committed
752
    mavlink_msg_mission_set_current_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, &wpsc);
753
    uas.sendMessage(message);
754
    MG::SLEEP::usleep(PROTOCOL_DELAY_MS * 1000);
755

756
    // qDebug() << "sent waypoint set current (" << wpsc.seq << ") to ID " << wpsc.target_system;
757 758 759 760 761
}

void UASWaypointManager::sendWaypointCount()
{
    mavlink_message_t message;
lm's avatar
lm committed
762
    mavlink_mission_count_t wpc;
763 764

    wpc.target_system = uas.getUASID();
lm's avatar
lm committed
765
    wpc.target_component = MAV_COMP_ID_MISSIONPLANNER;
766 767
    wpc.count = current_count;

768
    // qDebug() << "sent waypoint count (" << wpc.count << ") to ID " << wpc.target_system;
769
    emit updateStatusString(QString("Starting to transmit waypoints..."));
770

lm's avatar
lm committed
771
    mavlink_msg_mission_count_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, &wpc);
772
    uas.sendMessage(message);
773
    MG::SLEEP::usleep(PROTOCOL_DELAY_MS * 1000);
774

775
    // qDebug() << "sent waypoint count (" << wpc.count << ") to ID " << wpc.target_system;
776 777 778 779 780
}

void UASWaypointManager::sendWaypointRequestList()
{
    mavlink_message_t message;
lm's avatar
lm committed
781
    mavlink_mission_request_list_t wprl;
782 783

    wprl.target_system = uas.getUASID();
lm's avatar
lm committed
784
    wprl.target_component = MAV_COMP_ID_MISSIONPLANNER;
785

786
    emit updateStatusString(QString("Requesting waypoint list..."));
787

lm's avatar
lm committed
788
    mavlink_msg_mission_request_list_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, &wprl);
789
    uas.sendMessage(message);
790
    MG::SLEEP::usleep(PROTOCOL_DELAY_MS * 1000);
791

792
    // qDebug() << "sent waypoint list request to ID " << wprl.target_system;
793 794


795 796
}

797
void UASWaypointManager::sendWaypointRequest(quint16 seq)
pixhawk's avatar
pixhawk committed
798
{
799
    mavlink_message_t message;
lm's avatar
lm committed
800
    mavlink_mission_request_t wpr;
801 802

    wpr.target_system = uas.getUASID();
lm's avatar
lm committed
803
    wpr.target_component = MAV_COMP_ID_MISSIONPLANNER;
804 805
    wpr.seq = seq;

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

lm's avatar
lm committed
808
    mavlink_msg_mission_request_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, &wpr);
809
    uas.sendMessage(message);
810
    MG::SLEEP::usleep(PROTOCOL_DELAY_MS * 1000);
811

812
    // qDebug() << "sent waypoint request (" << wpr.seq << ") to ID " << wpr.target_system;
pixhawk's avatar
pixhawk committed
813
}
pixhawk's avatar
pixhawk committed
814

pixhawk's avatar
pixhawk committed
815 816 817
void UASWaypointManager::sendWaypoint(quint16 seq)
{
    mavlink_message_t message;
818
    // qDebug() <<" WP Buffer count: "<<waypoint_buffer.count();
pixhawk's avatar
pixhawk committed
819

820
    if (seq < waypoint_buffer.count()) {
821

lm's avatar
lm committed
822
        mavlink_mission_item_t *wp;
pixhawk's avatar
pixhawk committed
823

824

pixhawk's avatar
pixhawk committed
825 826
        wp = waypoint_buffer.at(seq);
        wp->target_system = uas.getUASID();
lm's avatar
lm committed
827
        wp->target_component = MAV_COMP_ID_MISSIONPLANNER;
pixhawk's avatar
pixhawk committed
828

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

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

lm's avatar
lm committed
833
        mavlink_msg_mission_item_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, wp);
pixhawk's avatar
pixhawk committed
834
        uas.sendMessage(message);
835
        MG::SLEEP::usleep(PROTOCOL_DELAY_MS * 1000);
pixhawk's avatar
pixhawk committed
836 837

    }
pixhawk's avatar
pixhawk committed
838
}
839 840 841 842

void UASWaypointManager::sendWaypointAck(quint8 type)
{
    mavlink_message_t message;
lm's avatar
lm committed
843
    mavlink_mission_ack_t wpa;
844 845

    wpa.target_system = uas.getUASID();
lm's avatar
lm committed
846
    wpa.target_component = MAV_COMP_ID_MISSIONPLANNER;
847 848
    wpa.type = type;

lm's avatar
lm committed
849
    mavlink_msg_mission_ack_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, &wpa);
850
    uas.sendMessage(message);
851
    MG::SLEEP::usleep(PROTOCOL_DELAY_MS * 1000);
852

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