• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mavlink / MAVSDK / 18289523387

06 Oct 2025 05:41PM UTC coverage: 47.597% (+0.02%) from 47.58%
18289523387

push

github

web-flow
Merge pull request #2667 from irajkovic/fix-mission-progress-total

Fix updating mission item total

4 of 8 new or added lines in 1 file covered. (50.0%)

23 existing lines in 7 files now uncovered.

17035 of 35790 relevant lines covered (47.6%)

452.46 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

31.55
/src/mavsdk/plugins/mission_raw/mission_raw_impl.cpp
1
#include "mission_raw_impl.h"
2
#include "mission_import.h"
3
#include "system.h"
4
#include "callback_list.tpp"
5

6
#include <fstream> // for `std::ifstream`
7
#include <sstream> // for `std::stringstream`
8

9
namespace mavsdk {
10

11
template class CallbackList<MissionRaw::MissionProgress>;
12
template class CallbackList<bool>;
13

14
// This is an empty item that can be sent to ArduPilot to mimic clearing of mission.
15
constexpr MissionRaw::MissionItem empty_item{0, 3, 16, 1};
16

17
MissionRawImpl::MissionRawImpl(System& system) : PluginImplBase(system)
×
18
{
19
    _system_impl->register_plugin(this);
×
20
}
×
21

22
MissionRawImpl::MissionRawImpl(std::shared_ptr<System> system) : PluginImplBase(std::move(system))
1✔
23
{
24
    _system_impl->register_plugin(this);
1✔
25
}
1✔
26

27
MissionRawImpl::~MissionRawImpl()
2✔
28
{
29
    _system_impl->unregister_plugin(this);
1✔
30
}
2✔
31

32
void MissionRawImpl::init()
1✔
33
{
34
    _system_impl->register_mavlink_message_handler(
1✔
35
        MAVLINK_MSG_ID_MISSION_ACK,
36
        [this](const mavlink_message_t& message) { process_mission_ack(message); },
1✔
37
        this);
38

39
    _system_impl->register_mavlink_message_handler(
1✔
40
        MAVLINK_MSG_ID_MISSION_CURRENT,
41
        [this](const mavlink_message_t& message) { process_mission_current(message); },
1✔
42
        this);
43

44
    _system_impl->register_mavlink_message_handler(
1✔
45
        MAVLINK_MSG_ID_MISSION_ITEM_REACHED,
46
        [this](const mavlink_message_t& message) { process_mission_item_reached(message); },
×
47
        this);
48
}
1✔
49

50
void MissionRawImpl::enable() {}
1✔
51

52
void MissionRawImpl::disable()
1✔
53
{
54
    reset_mission_progress();
1✔
55
}
1✔
56

57
void MissionRawImpl::deinit()
1✔
58
{
59
    _system_impl->unregister_all_mavlink_message_handlers(this);
1✔
60
}
1✔
61

62
void MissionRawImpl::reset_mission_progress()
2✔
63
{
64
    std::lock_guard<std::mutex> lock(_mission_progress.mutex);
2✔
65
    _mission_progress.last.current = -1;
2✔
66
    _mission_progress.last.total = -1;
2✔
67
    _mission_progress.last_reported.current = -1;
2✔
68
    _mission_progress.last_reported.total = -1;
2✔
69
    _mission_progress.last_reached = -1;
2✔
70
}
2✔
71

72
void MissionRawImpl::process_mission_ack(const mavlink_message_t& message)
1✔
73
{
74
    mavlink_mission_ack_t mission_ack;
75
    mavlink_msg_mission_ack_decode(&message, &mission_ack);
1✔
76

77
    if (mission_ack.type != MAV_MISSION_ACCEPTED ||
1✔
78
        mission_ack.mission_type != MAV_MISSION_TYPE_MISSION) {
1✔
79
        return;
×
80
    }
81

82
    // We assume that if the vehicle sends an ACCEPTED ack, we might have received
83
    // a new mission. In that case we can notify our user.
84
    // However, with the (opaque) mission_id, we can determine this properly using
85
    // the id. Therefore, we only do the notification if the opaque ID is 0 and
86
    // therefore not yet supported. This way we stay backwards compatible with
87
    // previous autopilot versions.
88
    if (mission_ack.opaque_id == 0) {
1✔
89
        std::lock_guard<std::mutex> lock(_mission_changed.mutex);
1✔
90
        _mission_changed.callbacks.queue(
1✔
91
            true, [this](const auto& func) { _system_impl->call_user_callback(func); });
×
92
    }
1✔
93
}
94

95
void MissionRawImpl::process_mission_current(const mavlink_message_t& message)
1✔
96
{
97
    mavlink_mission_current_t mission_current;
98
    mavlink_msg_mission_current_decode(&message, &mission_current);
1✔
99

100
    {
101
        std::lock_guard<std::mutex> lock(_mission_progress.mutex);
1✔
102

103
        // When the last waypoint is reached mission_current_seq does not increase
104
        // so we need to ignore that case.
105
        if (mission_current.seq != _mission_progress.last_reached) {
1✔
106
            _mission_progress.last.current = mission_current.seq;
1✔
107
        }
108
        _mission_progress.mission_state = mission_current.mission_state;
1✔
109
    }
1✔
110
    {
111
        std::lock_guard<std::mutex> lock(_mission_changed.mutex);
1✔
112
        if (_mission_changed.last_mission_id != mission_current.mission_id) {
1✔
113
            _mission_changed.last_mission_id = mission_current.mission_id;
×
114

115
            _mission_changed.callbacks.queue(
×
116
                true, [this](const auto& func) { _system_impl->call_user_callback(func); });
×
117
            LogDebug() << "Mission changed";
×
118
        }
119
    }
1✔
120

121
    report_progress_current();
1✔
122
}
1✔
123

124
void MissionRawImpl::process_mission_item_reached(const mavlink_message_t& message)
×
125
{
126
    mavlink_mission_item_reached_t mission_item_reached;
127
    mavlink_msg_mission_item_reached_decode(&message, &mission_item_reached);
×
128

129
    {
130
        std::lock_guard<std::mutex> lock(_mission_progress.mutex);
×
131
        _mission_progress.last.current = mission_item_reached.seq + 1;
×
132
        _mission_progress.last_reached = mission_item_reached.seq;
×
133
    }
×
134

135
    report_progress_current();
×
136
}
×
137

138
MissionRaw::Result MissionRawImpl::upload_mission_items(
1✔
139
    std::vector<MissionRaw::MissionItem> mission_items, uint8_t type)
140
{
141
    auto prom = std::promise<MissionRaw::Result>();
1✔
142
    auto fut = prom.get_future();
1✔
143

144
    upload_mission_items_async(
1✔
145
        mission_items, type, [&prom](MissionRaw::Result result) { prom.set_value(result); });
1✔
146
    return fut.get();
1✔
147
}
1✔
148

149
void MissionRawImpl::upload_mission_items_async(
1✔
150
    const std::vector<MissionRaw::MissionItem>& mission_raw,
151
    uint8_t type,
152
    const MissionRaw::ResultCallback& callback)
153
{
154
    auto work_item = _last_upload.lock();
1✔
155
    if (work_item && !work_item->is_done()) {
1✔
156
        _system_impl->call_user_callback([callback]() {
×
157
            if (callback) {
158
                callback(MissionRaw::Result::Busy);
159
            }
160
        });
161
        return;
×
162
    }
163

164
    reset_mission_progress();
1✔
165

166
    const auto int_items = convert_to_int_items(mission_raw);
1✔
167

168
    _last_upload = _system_impl->mission_transfer_client().upload_items_async(
3✔
169
        type,
170
        _system_impl->get_system_id(),
1✔
171
        int_items,
172
        [this, callback, int_items](MavlinkMissionTransferClient::Result result) {
5✔
173
            auto converted_result = convert_result(result);
1✔
174
            auto converted_items = convert_items(int_items);
1✔
175

176
            if (converted_result == MissionRaw::Result::Success) {
1✔
177
                std::lock_guard<std::mutex> lock(_mission_progress.mutex);
1✔
178
                _mission_progress.last.total = int_items.size();
1✔
179
            }
1✔
180

181
            _system_impl->call_user_callback([callback, converted_result, converted_items]() {
2✔
182
                if (callback) {
183
                    callback(converted_result);
184
                }
185
            });
186
        });
2✔
187
}
1✔
188

189
MissionRaw::Result
190
MissionRawImpl::upload_mission(std::vector<MissionRaw::MissionItem> mission_items)
1✔
191
{
192
    return upload_mission_items(mission_items, MAV_MISSION_TYPE_MISSION);
1✔
193
}
194

195
void MissionRawImpl::upload_mission_async(
×
196
    const std::vector<MissionRaw::MissionItem>& mission_raw,
197
    const MissionRaw::ResultCallback& callback)
198
{
199
    upload_mission_items_async(mission_raw, MAV_MISSION_TYPE_MISSION, callback);
×
200
}
×
201

202
MissionRaw::Result
203
MissionRawImpl::upload_geofence(std::vector<MissionRaw::MissionItem> mission_items)
×
204
{
205
    return upload_mission_items(mission_items, MAV_MISSION_TYPE_FENCE);
×
206
}
207

208
void MissionRawImpl::upload_geofence_async(
×
209
    const std::vector<MissionRaw::MissionItem>& mission_raw,
210
    const MissionRaw::ResultCallback& callback)
211
{
212
    upload_mission_items_async(mission_raw, MAV_MISSION_TYPE_FENCE, callback);
×
213
}
×
214

215
MissionRaw::Result
216
MissionRawImpl::upload_rally_points(std::vector<MissionRaw::MissionItem> mission_items)
×
217
{
218
    return upload_mission_items(mission_items, MAV_MISSION_TYPE_RALLY);
×
219
}
220

221
void MissionRawImpl::upload_rally_points_async(
×
222
    const std::vector<MissionRaw::MissionItem>& mission_raw,
223
    const MissionRaw::ResultCallback& callback)
224
{
225
    upload_mission_items_async(mission_raw, MAV_MISSION_TYPE_RALLY, callback);
×
226
}
×
227

228
MissionRaw::Result MissionRawImpl::cancel_mission_upload()
×
229
{
230
    auto ptr = _last_upload.lock();
×
231
    if (ptr) {
×
232
        ptr->cancel();
×
233
        return MissionRaw::Result::Success;
×
234
    } else {
235
        return MissionRaw::Result::Error;
×
236
    }
237
}
×
238

239
std::pair<MissionRaw::Result, std::vector<MissionRaw::MissionItem>>
240
MissionRawImpl::download_mission()
×
241
{
242
    auto prom = std::promise<std::pair<MissionRaw::Result, std::vector<MissionRaw::MissionItem>>>();
×
243
    auto fut = prom.get_future();
×
244

245
    download_mission_async(
×
246
        [&prom](MissionRaw::Result result, std::vector<MissionRaw::MissionItem> mission_items) {
×
247
            prom.set_value(std::make_pair<>(result, mission_items));
×
248
        });
×
249
    return fut.get();
×
250
}
×
251

252
std::pair<MissionRaw::Result, std::vector<MissionRaw::MissionItem>>
253
MissionRawImpl::download_geofence()
×
254
{
255
    auto prom = std::promise<std::pair<MissionRaw::Result, std::vector<MissionRaw::MissionItem>>>();
×
256
    auto fut = prom.get_future();
×
257

258
    download_geofence_async(
×
259
        [&prom](MissionRaw::Result result, std::vector<MissionRaw::MissionItem> geofence) {
×
260
            prom.set_value(std::make_pair<>(result, geofence));
×
261
        });
×
262
    return fut.get();
×
263
}
×
264

265
std::pair<MissionRaw::Result, std::vector<MissionRaw::MissionItem>>
266
MissionRawImpl::download_rallypoints()
×
267
{
268
    auto prom = std::promise<std::pair<MissionRaw::Result, std::vector<MissionRaw::MissionItem>>>();
×
269
    auto fut = prom.get_future();
×
270

271
    download_rallypoints_async(
×
272
        [&prom](MissionRaw::Result result, std::vector<MissionRaw::MissionItem> rallypoints) {
×
273
            prom.set_value(std::make_pair<>(result, rallypoints));
×
274
        });
×
275
    return fut.get();
×
276
}
×
277

278
void MissionRawImpl::download_mission_async(const MissionRaw::DownloadMissionCallback& callback)
×
279
{
280
    auto work_item = _last_download.lock();
×
281
    if (work_item && !work_item->is_done()) {
×
282
        _system_impl->call_user_callback([callback]() {
×
283
            if (callback) {
284
                std::vector<MissionRaw::MissionItem> empty_items;
285
                callback(MissionRaw::Result::Busy, empty_items);
286
            }
287
        });
288
        return;
×
289
    }
290

291
    _last_download = _system_impl->mission_transfer_client().download_items_async(
×
292
        MAV_MISSION_TYPE_MISSION,
293
        _system_impl->get_system_id(),
×
294
        [this, callback](
×
295
            MavlinkMissionTransferClient::Result result,
296
            std::vector<MavlinkMissionTransferClient::ItemInt> items) {
×
297
            auto converted_result = convert_result(result);
×
298
            auto converted_items = convert_items(items);
×
299

NEW
300
            if (converted_result == MissionRaw::Result::Success) {
×
NEW
301
                std::lock_guard<std::mutex> lock(_mission_progress.mutex);
×
NEW
302
                _mission_progress.last.total = items.size();
×
NEW
303
            }
×
304

UNCOV
305
            _system_impl->call_user_callback([callback, converted_result, converted_items]() {
×
306
                callback(converted_result, converted_items);
307
            });
308
        });
×
309
}
×
310

311
void MissionRawImpl::download_geofence_async(const MissionRaw::DownloadGeofenceCallback& callback)
×
312
{
313
    auto work_item = _last_download.lock();
×
314
    if (work_item && !work_item->is_done()) {
×
315
        _system_impl->call_user_callback([callback]() {
×
316
            if (callback) {
317
                std::vector<MissionRaw::MissionItem> empty_items;
318
                callback(MissionRaw::Result::Busy, empty_items);
319
            }
320
        });
321
        return;
×
322
    }
323

324
    _last_download = _system_impl->mission_transfer_client().download_items_async(
×
325
        MAV_MISSION_TYPE_FENCE,
326
        _system_impl->get_system_id(),
×
327
        [this, callback](
×
328
            MavlinkMissionTransferClient::Result result,
329
            std::vector<MavlinkMissionTransferClient::ItemInt> items) {
×
330
            auto converted_result = convert_result(result);
×
331
            auto converted_items = convert_items(items);
×
332
            _system_impl->call_user_callback([callback, converted_result, converted_items]() {
×
333
                callback(converted_result, converted_items);
334
            });
335
        });
×
336
}
×
337

338
void MissionRawImpl::download_rallypoints_async(
×
339
    const MissionRaw::DownloadRallypointsCallback& callback)
340
{
341
    auto work_item = _last_download.lock();
×
342
    if (work_item && !work_item->is_done()) {
×
343
        _system_impl->call_user_callback([callback]() {
×
344
            if (callback) {
345
                std::vector<MissionRaw::MissionItem> empty_items;
346
                callback(MissionRaw::Result::Busy, empty_items);
347
            }
348
        });
349
        return;
×
350
    }
351

352
    _last_download = _system_impl->mission_transfer_client().download_items_async(
×
353
        MAV_MISSION_TYPE_RALLY,
354
        _system_impl->get_system_id(),
×
355
        [this, callback](
×
356
            MavlinkMissionTransferClient::Result result,
357
            std::vector<MavlinkMissionTransferClient::ItemInt> items) {
×
358
            auto converted_result = convert_result(result);
×
359
            auto converted_items = convert_items(items);
×
360
            _system_impl->call_user_callback([callback, converted_result, converted_items]() {
×
361
                callback(converted_result, converted_items);
362
            });
363
        });
×
364
}
×
365

366
MissionRaw::Result MissionRawImpl::cancel_mission_download()
×
367
{
368
    auto ptr = _last_download.lock();
×
369
    if (ptr) {
×
370
        ptr->cancel();
×
371
        return MissionRaw::Result::Success;
×
372
    } else {
373
        return MissionRaw::Result::Error;
×
374
    }
375
}
×
376

377
MavlinkMissionTransferClient::ItemInt
378
MissionRawImpl::convert_mission_raw(const MissionRaw::MissionItem transfer_mission_raw)
6✔
379
{
380
    MavlinkMissionTransferClient::ItemInt new_item_int;
381

382
    new_item_int.seq = transfer_mission_raw.seq;
6✔
383
    new_item_int.frame = transfer_mission_raw.frame;
6✔
384
    new_item_int.command = transfer_mission_raw.command;
6✔
385
    new_item_int.current = transfer_mission_raw.current;
6✔
386
    new_item_int.autocontinue = transfer_mission_raw.autocontinue;
6✔
387
    new_item_int.param1 = transfer_mission_raw.param1;
6✔
388
    new_item_int.param2 = transfer_mission_raw.param2;
6✔
389
    new_item_int.param3 = transfer_mission_raw.param3;
6✔
390
    new_item_int.param4 = transfer_mission_raw.param4;
6✔
391
    new_item_int.x = transfer_mission_raw.x;
6✔
392
    new_item_int.y = transfer_mission_raw.y;
6✔
393
    new_item_int.z = transfer_mission_raw.z;
6✔
394
    new_item_int.mission_type = transfer_mission_raw.mission_type;
6✔
395

396
    return new_item_int;
6✔
397
}
398

399
std::vector<MavlinkMissionTransferClient::ItemInt>
400
MissionRawImpl::convert_to_int_items(const std::vector<MissionRaw::MissionItem>& mission_raw)
1✔
401
{
402
    std::vector<MavlinkMissionTransferClient::ItemInt> int_items;
1✔
403

404
    for (const auto& item : mission_raw) {
7✔
405
        int_items.push_back(convert_mission_raw(item));
6✔
406
    }
407

408
    std::lock_guard<std::mutex> lock(_mission_progress.mutex);
1✔
409
    _mission_progress.last.total = int_items.size();
1✔
410

411
    return int_items;
1✔
412
}
1✔
413

414
MissionRaw::MissionItem
415
MissionRawImpl::convert_item(const MavlinkMissionTransferClient::ItemInt& transfer_item)
6✔
416
{
417
    MissionRaw::MissionItem new_item;
6✔
418

419
    new_item.seq = transfer_item.seq;
6✔
420
    new_item.frame = transfer_item.frame;
6✔
421
    new_item.command = transfer_item.command;
6✔
422
    new_item.current = transfer_item.current;
6✔
423
    new_item.autocontinue = transfer_item.autocontinue;
6✔
424
    new_item.param1 = transfer_item.param1;
6✔
425
    new_item.param2 = transfer_item.param2;
6✔
426
    new_item.param3 = transfer_item.param3;
6✔
427
    new_item.param4 = transfer_item.param4;
6✔
428
    new_item.x = transfer_item.x;
6✔
429
    new_item.y = transfer_item.y;
6✔
430
    new_item.z = transfer_item.z;
6✔
431
    new_item.mission_type = transfer_item.mission_type;
6✔
432

433
    return new_item;
6✔
434
}
435

436
std::vector<MissionRaw::MissionItem> MissionRawImpl::convert_items(
1✔
437
    const std::vector<MavlinkMissionTransferClient::ItemInt>& transfer_items)
438
{
439
    std::vector<MissionRaw::MissionItem> new_items;
1✔
440
    new_items.reserve(transfer_items.size());
1✔
441

442
    for (const auto& transfer_item : transfer_items) {
7✔
443
        new_items.push_back(convert_item(transfer_item));
6✔
444
    }
445

446
    return new_items;
1✔
447
}
448

449
MissionRaw::Result MissionRawImpl::start_mission()
×
450
{
451
    auto prom = std::promise<MissionRaw::Result>();
×
452
    auto fut = prom.get_future();
×
453

454
    start_mission_async([&prom](MissionRaw::Result result) { prom.set_value(result); });
×
455
    return fut.get();
×
456
}
×
457

458
void MissionRawImpl::start_mission_async(const MissionRaw::ResultCallback& callback)
×
459
{
460
    _system_impl->set_flight_mode_async(
×
461
        FlightMode::Mission, [this, callback](MavlinkCommandSender::Result result, float) {
×
462
            report_flight_mode_change(callback, result);
×
463
        });
×
464
}
×
465

466
MissionRaw::Result MissionRawImpl::pause_mission()
×
467
{
468
    auto prom = std::promise<MissionRaw::Result>();
×
469
    auto fut = prom.get_future();
×
470

471
    pause_mission_async([&prom](MissionRaw::Result result) { prom.set_value(result); });
×
472
    return fut.get();
×
473
}
×
474

475
void MissionRawImpl::pause_mission_async(const MissionRaw::ResultCallback& callback)
×
476
{
477
    _system_impl->set_flight_mode_async(
×
478
        FlightMode::Hold, [this, callback](MavlinkCommandSender::Result result, float) {
×
479
            report_flight_mode_change(callback, result);
×
480
        });
×
481
}
×
482

483
void MissionRawImpl::report_flight_mode_change(
×
484
    MissionRaw::ResultCallback callback, MavlinkCommandSender::Result result)
485
{
486
    if (!callback) {
×
487
        return;
×
488
    }
489

490
    _system_impl->call_user_callback(
×
491
        [callback, result]() { callback(command_result_to_mission_result(result)); });
492
}
493

494
MissionRaw::Result
495
MissionRawImpl::command_result_to_mission_result(MavlinkCommandSender::Result result)
×
496
{
497
    switch (result) {
×
498
        case MavlinkCommandSender::Result::Success:
×
499
            return MissionRaw::Result::Success;
×
500
        case MavlinkCommandSender::Result::NoSystem:
×
501
            return MissionRaw::Result::NoSystem;
×
502
        case MavlinkCommandSender::Result::ConnectionError:
×
503
            return MissionRaw::Result::Error;
×
504
        case MavlinkCommandSender::Result::Busy:
×
505
            return MissionRaw::Result::Busy;
×
506
        case MavlinkCommandSender::Result::Denied:
×
507
            // FALLTHROUGH
508
        case MavlinkCommandSender::Result::TemporarilyRejected:
509
            return MissionRaw::Result::Denied;
×
510
        case MavlinkCommandSender::Result::Timeout:
×
511
            return MissionRaw::Result::Timeout;
×
512
        case MavlinkCommandSender::Result::InProgress:
×
513
            return MissionRaw::Result::Busy;
×
514
        case MavlinkCommandSender::Result::UnknownError:
×
515
            return MissionRaw::Result::Unknown;
×
516
        default:
×
517
            return MissionRaw::Result::Unknown;
×
518
    }
519
}
520

521
MissionRaw::Result MissionRawImpl::clear_mission()
×
522
{
523
    auto prom = std::promise<MissionRaw::Result>();
×
524
    auto fut = prom.get_future();
×
525

526
    clear_mission_async([&prom](MissionRaw::Result result) { prom.set_value(result); });
×
527
    return fut.get();
×
528
}
×
529

530
void MissionRawImpl::clear_mission_async(const MissionRaw::ResultCallback& callback)
×
531
{
532
    reset_mission_progress();
×
533

534
    // For ArduPilot to clear a mission we need to upload an empty mission.
535
    if (_system_impl->autopilot() == Autopilot::ArduPilot) {
×
536
        std::vector<MissionRaw::MissionItem> mission_items{empty_item};
×
537
        upload_mission_async(mission_items, callback);
×
538
    } else {
×
539
        _system_impl->mission_transfer_client().clear_items_async(
×
540
            MAV_MISSION_TYPE_MISSION,
541
            _system_impl->get_system_id(),
×
542
            [this, callback](MavlinkMissionTransferClient::Result result) {
×
543
                auto converted_result = convert_result(result);
×
544
                _system_impl->call_user_callback([callback, converted_result]() {
×
545
                    if (callback) {
546
                        callback(converted_result);
547
                    }
548
                });
549
            });
×
550
    }
551
}
×
552

553
MissionRaw::Result MissionRawImpl::set_current_mission_item(int index)
×
554
{
555
    auto prom = std::promise<MissionRaw::Result>();
×
556
    auto fut = prom.get_future();
×
557

558
    set_current_mission_item_async(
×
559
        index, [&prom](MissionRaw::Result result) { prom.set_value(result); });
×
560
    return fut.get();
×
561
}
×
562

563
void MissionRawImpl::set_current_mission_item_async(
×
564
    int index, const MissionRaw::ResultCallback& callback)
565
{
566
    if (index < 0 || index >= _mission_progress.last.total) {
×
567
        _system_impl->call_user_callback([callback]() {
×
568
            if (callback) {
569
                callback(MissionRaw::Result::InvalidArgument);
570
            }
571
        });
572
        return;
×
573
    }
574

575
    _system_impl->mission_transfer_client().set_current_item_async(
×
576
        index,
577
        _system_impl->get_system_id(),
×
578
        [this, callback](MavlinkMissionTransferClient::Result result) {
×
579
            auto converted_result = convert_result(result);
×
580
            _system_impl->call_user_callback([callback, converted_result]() {
×
581
                if (callback) {
582
                    callback(converted_result);
583
                }
584
            });
585
        });
×
586
}
587

588
void MissionRawImpl::report_progress_current()
1✔
589
{
590
    std::lock_guard<std::mutex> lock(_mission_progress.mutex);
1✔
591

592
    if (_mission_progress.callbacks.empty()) {
1✔
593
        return;
1✔
594
    }
595

596
    bool should_report = false;
×
597
    {
598
        if (_mission_progress.last_reported.current != _mission_progress.last.current) {
×
599
            _mission_progress.last_reported.current = _mission_progress.last.current;
×
600
            should_report = true;
×
601
        }
602
        if (_mission_progress.last_reported.total != _mission_progress.last.total) {
×
603
            _mission_progress.last_reported.total = _mission_progress.last.total;
×
604
            should_report = true;
×
605
        }
606
    }
607

608
    if (should_report) {
×
609
        _mission_progress.callbacks.queue(_mission_progress.last, [this](const auto& func) {
×
610
            _system_impl->call_user_callback(func);
×
611
        });
×
612
    }
613
}
1✔
614

615
MissionRaw::MissionProgressHandle
616
MissionRawImpl::subscribe_mission_progress(const MissionRaw::MissionProgressCallback& callback)
×
617
{
618
    std::lock_guard<std::mutex> lock(_mission_progress.mutex);
×
619
    return _mission_progress.callbacks.subscribe(callback);
×
620
}
×
621

622
void MissionRawImpl::unsubscribe_mission_progress(MissionRaw::MissionProgressHandle handle)
×
623
{
624
    std::lock_guard<std::mutex> lock(_mission_progress.mutex);
×
625
    _mission_progress.callbacks.unsubscribe(handle);
×
626
}
×
627

628
MissionRaw::MissionProgress MissionRawImpl::mission_progress()
×
629
{
630
    std::lock_guard<std::mutex> lock(_mission_progress.mutex);
×
631
    return _mission_progress.last;
×
632
}
×
633

634
MissionRaw::MissionChangedHandle
635
MissionRawImpl::subscribe_mission_changed(const MissionRaw::MissionChangedCallback& callback)
×
636
{
637
    std::lock_guard<std::mutex> lock(_mission_changed.mutex);
×
638
    return _mission_changed.callbacks.subscribe(callback);
×
639
}
×
640

641
void MissionRawImpl::unsubscribe_mission_changed(MissionRaw::MissionChangedHandle handle)
×
642
{
643
    std::lock_guard<std::mutex> lock(_mission_changed.mutex);
×
644
    _mission_changed.callbacks.unsubscribe(handle);
×
645
}
×
646

647
std::pair<MissionRaw::Result, MissionRaw::MissionImportData>
648
MissionRawImpl::import_qgroundcontrol_mission(std::string qgc_plan_path)
1✔
649
{
650
    std::ifstream file(qgc_plan_path);
1✔
651
    if (!file) {
1✔
652
        return std::make_pair<MissionRaw::Result, MissionRaw::MissionImportData>(
653
            MissionRaw::Result::FailedToOpenQgcPlan, {});
×
654
    }
655

656
    std::stringstream buf;
1✔
657
    buf << file.rdbuf();
1✔
658
    file.close();
1✔
659

660
    return MissionImport::parse_json(buf.str(), _system_impl->autopilot());
1✔
661
}
1✔
662

663
std::pair<MissionRaw::Result, MissionRaw::MissionImportData>
664
MissionRawImpl::import_qgroundcontrol_mission_from_string(const std::string& qgc_plan)
×
665
{
666
    return MissionImport::parse_json(qgc_plan, _system_impl->autopilot());
×
667
}
668

669
std::pair<MissionRaw::Result, MissionRaw::MissionImportData>
670
MissionRawImpl::import_mission_planner_mission(std::string mission_planner_path)
×
671
{
672
    std::ifstream file(mission_planner_path);
×
673
    if (!file) {
×
674
        return std::make_pair<MissionRaw::Result, MissionRaw::MissionImportData>(
675
            MissionRaw::Result::FailedToOpenMissionPlannerPlan, {});
×
676
    }
677

678
    std::stringstream buf;
×
679
    buf << file.rdbuf();
×
680
    file.close();
×
681

682
    return MissionImport::parse_mission_planner(buf.str(), _system_impl->autopilot());
×
683
}
×
684

685
std::pair<MissionRaw::Result, MissionRaw::MissionImportData>
686
MissionRawImpl::import_mission_planner_mission_from_string(
×
687
    const std::string& mission_planner_mission)
688
{
689
    return MissionImport::parse_mission_planner(mission_planner_mission, _system_impl->autopilot());
×
690
}
691

692
MissionRaw::Result MissionRawImpl::convert_result(MavlinkMissionTransferClient::Result result)
1✔
693
{
694
    switch (result) {
1✔
695
        case MavlinkMissionTransferClient::Result::Success:
1✔
696
            return MissionRaw::Result::Success;
1✔
697
        case MavlinkMissionTransferClient::Result::ConnectionError:
×
698
            return MissionRaw::Result::Error;
×
699
        case MavlinkMissionTransferClient::Result::Denied:
×
700
            return MissionRaw::Result::Denied;
×
701
        case MavlinkMissionTransferClient::Result::TooManyMissionItems:
×
702
            return MissionRaw::Result::TooManyMissionItems;
×
703
        case MavlinkMissionTransferClient::Result::Timeout:
×
704
            return MissionRaw::Result::Timeout;
×
705
        case MavlinkMissionTransferClient::Result::Unsupported:
×
706
            return MissionRaw::Result::Unsupported;
×
707
        case MavlinkMissionTransferClient::Result::UnsupportedFrame:
×
708
            return MissionRaw::Result::Unsupported;
×
709
        case MavlinkMissionTransferClient::Result::NoMissionAvailable:
×
710
            return MissionRaw::Result::NoMissionAvailable;
×
711
        case MavlinkMissionTransferClient::Result::Cancelled:
×
712
            return MissionRaw::Result::TransferCancelled;
×
713
        case MavlinkMissionTransferClient::Result::MissionTypeNotConsistent:
×
714
            return MissionRaw::Result::MissionTypeNotConsistent;
×
715
        case MavlinkMissionTransferClient::Result::InvalidSequence:
×
716
            return MissionRaw::Result::InvalidSequence;
×
717
        case MavlinkMissionTransferClient::Result::CurrentInvalid:
×
718
            return MissionRaw::Result::CurrentInvalid;
×
719
        case MavlinkMissionTransferClient::Result::ProtocolError:
×
720
            return MissionRaw::Result::ProtocolError;
×
721
        case MavlinkMissionTransferClient::Result::InvalidParam:
×
722
            return MissionRaw::Result::InvalidArgument;
×
723
        case MavlinkMissionTransferClient::Result::IntMessagesNotSupported:
×
724
            return MissionRaw::Result::IntMessagesNotSupported;
×
725
        default:
×
726
            return MissionRaw::Result::Unknown;
×
727
    }
728
}
729

730
std::pair<MissionRaw::Result, bool> MissionRawImpl::is_mission_finished() const
×
731
{
732
    std::lock_guard<std::mutex> lock(_mission_progress.mutex);
×
733

734
    if (_mission_progress.last.current < 0) {
×
735
        return std::make_pair<MissionRaw::Result, bool>(MissionRaw::Result::Success, false);
×
736
    }
737

738
    if (_mission_progress.last_reached < 0) {
×
739
        return std::make_pair<MissionRaw::Result, bool>(MissionRaw::Result::Success, false);
×
740
    }
741

742
    if (_mission_progress.last.total <= 0) {
×
743
        return std::make_pair<MissionRaw::Result, bool>(MissionRaw::Result::Success, false);
×
744
    }
745

746
    // If mission_state is Unknown, fall back to the previous behavior
747
    if (_mission_progress.mission_state == MISSION_STATE_UNKNOWN) {
×
748
        return std::make_pair<MissionRaw::Result, bool>(
×
749
            MissionRaw::Result::Success,
×
750
            _mission_progress.last_reached == _mission_progress.last.total - 1);
×
751
    }
752

753
    // If mission_state is Completed, the mission is finished
754
    if (_mission_progress.mission_state == MISSION_STATE_COMPLETE) {
×
755
        return std::make_pair<MissionRaw::Result, bool>(MissionRaw::Result::Success, true);
×
756
    }
757

758
    // If mission_state is NotCompleted, the mission is not finished
759
    return std::make_pair<MissionRaw::Result, bool>(MissionRaw::Result::Success, false);
×
760
}
×
761
} // namespace mavsdk
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc