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

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

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

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

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

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

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

}

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

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

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

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

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

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

            //get next waypoint
            current_wp_id++;

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

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

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

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

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

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

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

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

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

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

239
                    } else {
240 241 242 243
                        waypoints[i]->setCurrent(false);
                    }
                }
            }
244
        }
245 246 247
        emit updateStatusString(QString("New current waypoint %1").arg(wpc->seq));
        //emit update to UI widgets
        emit currentWaypointChanged(wpc->seq);
pixhawk's avatar
pixhawk committed
248
    }
pixhawk's avatar
pixhawk committed
249 250
}

251
void UASWaypointManager::notifyOfChangeEditable(Waypoint* wp)
252
{
253
    // // qDebug() << "WAYPOINT CHANGED: ID:" << wp->getId();
254
    // If only one waypoint was changed, emit only WP signal
255
    if (wp != NULL) {
256
        emit waypointEditableChanged(uas.getUASID(), wp);
257
    } else {
258 259
        emit waypointEditableListChanged();
        emit waypointEditableListChanged(uas.getUASID());
260
    }
261 262
}

263 264 265 266 267 268
//void notifyOfChangeViewOnly(Waypoint* wp)
//{

//}


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

283
            //TODO: signal changed waypoint list
284

285 286 287 288 289 290 291
            //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
292
            current_partner_compid = MAV_COMP_ID_MISSIONPLANNER;
293 294 295 296 297 298 299 300 301 302 303

            sendWaypointSetCurrent(current_wp_id);

            //emit waypointListChanged();

            return 0;
        }
    }
    return -1;
}

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

322 323
        emit waypointEditableListChanged();
        emit waypointEditableListChanged(uas.getUASID());
324
    }
pixhawk's avatar
pixhawk committed
325 326
}

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

342 343
    emit waypointEditableListChanged();
    emit waypointEditableListChanged(uas.getUASID());
344 345 346
    return wp;
}

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

356 357
        for(int i = seq; i < waypoints.size(); i++)
        {
358 359
            waypoints[i]->setId(i);
        }
Alejandro's avatar
Alejandro committed
360

361 362
        emit waypointEditableListChanged();
        emit waypointEditableListChanged(uas.getUASID());
363 364 365 366 367
        return 0;
    }
    return -1;
}

368
void UASWaypointManager::moveWaypoint(quint16 cur_seq, quint16 new_seq)
369
{
370 371
    if (cur_seq != new_seq && cur_seq < waypoints.size() && new_seq < waypoints.size())
    {
372
        Waypoint *t = waypoints[cur_seq];
373
        if (cur_seq < new_seq) {
374 375
            for (int i = cur_seq; i < new_seq; i++)
            {
376 377
                waypoints[i] = waypoints[i+1];
            }
378 379 380 381 382
        }
        else
        {
            for (int i = cur_seq; i > new_seq; i--)
            {
383 384 385 386 387
                waypoints[i] = waypoints[i-1];
            }
        }
        waypoints[new_seq] = t;

388 389
        emit waypointEditableListChanged();
        emit waypointEditableListChanged(uas.getUASID());
390 391 392
    }
}

393
void UASWaypointManager::saveWaypoints(const QString &saveFile)
394 395 396 397 398 399
{
    QFile file(saveFile);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
        return;

    QTextStream out(&file);
400 401

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

404 405
    for (int i = 0; i < waypoints.size(); i++)
    {
406
        waypoints[i]->setId(i);
407 408 409 410 411
        waypoints[i]->save(out);
    }
    file.close();
}

412
void UASWaypointManager::loadWaypoints(const QString &loadFile)
413 414 415 416 417
{
    QFile file(loadFile);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
        return;

418
    while(waypoints.size()>0) {
419 420 421 422 423 424
        Waypoint *t = waypoints[0];
        waypoints.remove(0);
        delete t;
    }

    QTextStream in(&file);
425 426 427

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

428 429
    if (!(version.size() == 3 && version[0] == "QGC" && version[1] == "WPL" && version[2] == "110"))
    {
430
        emit updateStatusString(tr("The waypoint file is not compatible with the current version of QGroundControl."));
431 432 433 434 435
    }
    else
    {
        while (!in.atEnd())
        {
436
            Waypoint *t = new Waypoint();
437 438
            if(t->load(in))
            {
439 440
                t->setId(waypoints.size());
                waypoints.insert(waypoints.size(), t);
441 442 443
            }
            else
            {
444 445
                emit updateStatusString(tr("The waypoint file is corrupted. Load operation only partly succesful."));
                //MainWindow::instance()->showCriticalMessage(tr("Error loading waypoint file"),);
446 447
                break;
            }
448 449
        }
    }
450

451 452
    file.close();

453
    emit loadWPFile();
454 455
    emit waypointEditableListChanged();
    emit waypointEditableListChanged(uas.getUASID());
456 457 458
}

void UASWaypointManager::clearWaypointList()
pixhawk's avatar
pixhawk committed
459
{
460 461
    if(current_state == WP_IDLE)
    {
pixhawk's avatar
pixhawk committed
462
        protocol_timer.start(PROTOCOL_TIMEOUT_MS);
463
        current_retries = PROTOCOL_MAX_RETRIES;
pixhawk's avatar
pixhawk committed
464

465 466
        current_state = WP_CLEARLIST;
        current_wp_id = 0;
467
        current_partner_systemid = uas.getUASID();
lm's avatar
lm committed
468
        current_partner_compid = MAV_COMP_ID_MISSIONPLANNER;
pixhawk's avatar
pixhawk committed
469

470
        sendWaypointClearAll();
471 472 473
    }
}

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

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

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

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

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

    return -1;
}

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

    return -1;
}

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

    return -1;
}

585 586 587 588 589
int UASWaypointManager::getGlobalFrameCount()
{
    // Search through all waypoints,
    // counting only those in global frame
    int i = 0;
590 591
    foreach (Waypoint* p, waypoints)
    {
592 593
        if (p->getFrame() == MAV_FRAME_GLOBAL || p->getFrame() == MAV_FRAME_GLOBAL_RELATIVE_ALT)
        {
594 595 596 597 598 599 600
            i++;
        }
    }

    return i;
}

lm's avatar
lm committed
601 602 603 604 605
int UASWaypointManager::getGlobalFrameAndNavTypeCount()
{
    // Search through all waypoints,
    // counting only those in global frame
    int i = 0;
606
    foreach (Waypoint* p, waypoints) {
607
        if ((p->getFrame() == MAV_FRAME_GLOBAL || p->getFrame() == MAV_FRAME_GLOBAL_RELATIVE_ALT) && p->isNavigationType())
608
        {
lm's avatar
lm committed
609 610 611 612 613 614 615
            i++;
        }
    }

    return i;
}

LM's avatar
LM committed
616 617 618 619 620 621 622 623 624 625 626 627 628 629
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;
}

630 631 632 633 634
int UASWaypointManager::getLocalFrameCount()
{
    // Search through all waypoints,
    // counting only those in global frame
    int i = 0;
lm's avatar
lm committed
635 636
    foreach (Waypoint* p, waypoints)
    {
637
        if (p->getFrame() == MAV_FRAME_LOCAL_NED || p->getFrame() == MAV_FRAME_LOCAL_ENU)
lm's avatar
lm committed
638
        {
639 640 641 642 643 644 645 646 647 648 649 650
            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
651 652 653 654
    foreach (Waypoint* p, waypoints)
    {
        if (p->getFrame() == MAV_FRAME_LOCAL_NED || p->getFrame() == MAV_FRAME_LOCAL_ENU)
        {
655 656
            if (p == wp)
            {
657 658 659 660 661 662 663 664 665 666 667 668 669 670
                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
671 672
    foreach (Waypoint* p, waypoints)
    {
673 674 675 676
        if (p->getFrame() == MAV_FRAME_MISSION)
        {
            if (p == wp)
            {
677 678 679 680 681 682 683 684 685
                return i;
            }
            i++;
        }
    }

    return -1;
}

686 687
void UASWaypointManager::readWaypoints()
{
688
    emit readGlobalWPFromUAS(true);
689 690
    if(current_state == WP_IDLE) {
        while(waypoints.size()>0) {
691
            delete waypoints.back();
692
            waypoints.pop_back();
693

694 695
        }

696 697
        protocol_timer.start(PROTOCOL_TIMEOUT_MS);
        current_retries = PROTOCOL_MAX_RETRIES;
pixhawk's avatar
pixhawk committed
698 699 700 701

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

704
        sendWaypointRequestList();
705

pixhawk's avatar
pixhawk committed
706 707 708
    }
}

709
void UASWaypointManager::writeWaypoints()
pixhawk's avatar
pixhawk committed
710
{
711
    if (current_state == WP_IDLE) {
pixhawk's avatar
pixhawk committed
712
        // Send clear all if count == 0
713
        if (waypoints.count() > 0) {
pixhawk's avatar
pixhawk committed
714
            protocol_timer.start(PROTOCOL_TIMEOUT_MS);
715
            current_retries = PROTOCOL_MAX_RETRIES;
pixhawk's avatar
pixhawk committed
716

717
            current_count = waypoints.count();
pixhawk's avatar
pixhawk committed
718 719 720
            current_state = WP_SENDLIST;
            current_wp_id = 0;
            current_partner_systemid = uas.getUASID();
lm's avatar
lm committed
721
            current_partner_compid = MAV_COMP_ID_MISSIONPLANNER;
pixhawk's avatar
pixhawk committed
722 723

            //clear local buffer
pixhawk's avatar
pixhawk committed
724 725 726
            // 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.
727
            while(!waypoint_buffer.empty()) {
pixhawk's avatar
pixhawk committed
728 729 730
                delete waypoint_buffer.back();
                waypoint_buffer.pop_back();
            }
pixhawk's avatar
pixhawk committed
731

732 733
            bool noCurrent = true;

pixhawk's avatar
pixhawk committed
734
            //copy waypoint data to local buffer
735
            for (int i=0; i < current_count; i++) {
lm's avatar
lm committed
736 737 738
                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
739
                const Waypoint *cur_s = waypoints.at(i);
pixhawk's avatar
pixhawk committed
740 741

                cur_d->autocontinue = cur_s->getAutoContinue();
742
                cur_d->current = cur_s->getCurrent() & noCurrent;   //make sure only one current waypoint is selected, the first selected will be chosen
743 744
                cur_d->param1 = cur_s->getParam1();
                cur_d->param2 = cur_s->getParam2();
lm's avatar
lm committed
745 746
                cur_d->param3 = cur_s->getParam3();
                cur_d->param4 = cur_s->getParam4();
747
                cur_d->frame = cur_s->getFrame();
lm's avatar
lm committed
748
                cur_d->command = cur_s->getAction();
749
                cur_d->seq = i;     // don't read out the sequence number of the waypoint class
pixhawk's avatar
pixhawk committed
750 751 752
                cur_d->x = cur_s->getX();
                cur_d->y = cur_s->getY();
                cur_d->z = cur_s->getZ();
753 754 755

                if (cur_s->getCurrent() && noCurrent)
                    noCurrent = false;
756 757
                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
758
            }
759

760 761 762



pixhawk's avatar
pixhawk committed
763
            //send the waypoint count to UAS (this starts the send transaction)
764
            sendWaypointCount();
pixhawk's avatar
pixhawk committed
765
        }
766
    } else if (waypoints.count() == 0) {
767
        sendWaypointClearAll();
768
    } else {
769
        //we're in another transaction, ignore command
770
        // // qDebug() << "UASWaypointManager::sendWaypoints() doing something else ignoring command";
771
    }
pixhawk's avatar
pixhawk committed
772 773
}

774 775 776
void UASWaypointManager::sendWaypointClearAll()
{
    mavlink_message_t message;
lm's avatar
lm committed
777
    mavlink_mission_clear_all_t wpca;
778 779

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

782
    emit updateStatusString(QString("Clearing waypoint list..."));
783

lm's avatar
lm committed
784
    mavlink_msg_mission_clear_all_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, &wpca);
785
    uas.sendMessage(message);
786
    MG::SLEEP::usleep(PROTOCOL_DELAY_MS * 1000);
787

788
    // // qDebug() << "sent waypoint clear all to ID " << wpca.target_system;
789 790 791 792 793
}

void UASWaypointManager::sendWaypointSetCurrent(quint16 seq)
{
    mavlink_message_t message;
lm's avatar
lm committed
794
    mavlink_mission_set_current_t wpsc;
795 796

    wpsc.target_system = uas.getUASID();
lm's avatar
lm committed
797
    wpsc.target_component = MAV_COMP_ID_MISSIONPLANNER;
798 799
    wpsc.seq = seq;

800
    emit updateStatusString(QString("Updating target waypoint..."));
801

lm's avatar
lm committed
802
    mavlink_msg_mission_set_current_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, &wpsc);
803
    uas.sendMessage(message);
804
    MG::SLEEP::usleep(PROTOCOL_DELAY_MS * 1000);
805

806
    // // qDebug() << "sent waypoint set current (" << wpsc.seq << ") to ID " << wpsc.target_system;
807 808 809 810 811
}

void UASWaypointManager::sendWaypointCount()
{
    mavlink_message_t message;
lm's avatar
lm committed
812
    mavlink_mission_count_t wpc;
813 814

    wpc.target_system = uas.getUASID();
lm's avatar
lm committed
815
    wpc.target_component = MAV_COMP_ID_MISSIONPLANNER;
816 817
    wpc.count = current_count;

818
    // // qDebug() << "sent waypoint count (" << wpc.count << ") to ID " << wpc.target_system;
819
    emit updateStatusString(QString("Starting to transmit waypoints..."));
820

lm's avatar
lm committed
821
    mavlink_msg_mission_count_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, &wpc);
822
    uas.sendMessage(message);
823
    MG::SLEEP::usleep(PROTOCOL_DELAY_MS * 1000);
824

825
    // // qDebug() << "sent waypoint count (" << wpc.count << ") to ID " << wpc.target_system;
826 827 828 829 830
}

void UASWaypointManager::sendWaypointRequestList()
{
    mavlink_message_t message;
lm's avatar
lm committed
831
    mavlink_mission_request_list_t wprl;
832 833

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

836
    emit updateStatusString(QString("Requesting waypoint list..."));
837

lm's avatar
lm committed
838
    mavlink_msg_mission_request_list_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, &wprl);
839
    uas.sendMessage(message);
840
    MG::SLEEP::usleep(PROTOCOL_DELAY_MS * 1000);
841

842
    // // qDebug() << "sent waypoint list request to ID " << wprl.target_system;
843 844


845 846
}

847
void UASWaypointManager::sendWaypointRequest(quint16 seq)
pixhawk's avatar
pixhawk committed
848
{
849
    mavlink_message_t message;
lm's avatar
lm committed
850
    mavlink_mission_request_t wpr;
851 852

    wpr.target_system = uas.getUASID();
lm's avatar
lm committed
853
    wpr.target_component = MAV_COMP_ID_MISSIONPLANNER;
854 855
    wpr.seq = seq;

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

lm's avatar
lm committed
858
    mavlink_msg_mission_request_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, &wpr);
859
    uas.sendMessage(message);
860
    MG::SLEEP::usleep(PROTOCOL_DELAY_MS * 1000);
861

862
    // // qDebug() << "sent waypoint request (" << wpr.seq << ") to ID " << wpr.target_system;
pixhawk's avatar
pixhawk committed
863
}
pixhawk's avatar
pixhawk committed
864

pixhawk's avatar
pixhawk committed
865 866 867
void UASWaypointManager::sendWaypoint(quint16 seq)
{
    mavlink_message_t message;
868
    // // qDebug() <<" WP Buffer count: "<<waypoint_buffer.count();
pixhawk's avatar
pixhawk committed
869

870
    if (seq < waypoint_buffer.count()) {
871

lm's avatar
lm committed
872
        mavlink_mission_item_t *wp;
pixhawk's avatar
pixhawk committed
873

874

pixhawk's avatar
pixhawk committed
875 876
        wp = waypoint_buffer.at(seq);
        wp->target_system = uas.getUASID();
lm's avatar
lm committed
877
        wp->target_component = MAV_COMP_ID_MISSIONPLANNER;
pixhawk's avatar
pixhawk committed
878

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

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

lm's avatar
lm committed
883
        mavlink_msg_mission_item_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, wp);
pixhawk's avatar
pixhawk committed
884
        uas.sendMessage(message);
885
        MG::SLEEP::usleep(PROTOCOL_DELAY_MS * 1000);
pixhawk's avatar
pixhawk committed
886 887

    }
pixhawk's avatar
pixhawk committed
888
}
889 890 891 892

void UASWaypointManager::sendWaypointAck(quint8 type)
{
    mavlink_message_t message;
lm's avatar
lm committed
893
    mavlink_mission_ack_t wpa;
894 895

    wpa.target_system = uas.getUASID();
lm's avatar
lm committed
896
    wpa.target_component = MAV_COMP_ID_MISSIONPLANNER;
897 898
    wpa.type = type;

lm's avatar
lm committed
899
    mavlink_msg_mission_ack_encode(uas.mavlink->getSystemId(), uas.mavlink->getComponentId(), &message, &wpa);
900
    uas.sendMessage(message);
901
    MG::SLEEP::usleep(PROTOCOL_DELAY_MS * 1000);
902

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