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

mavlink / MAVSDK / 29462275360

16 Jul 2026 12:44AM UTC coverage: 50.438%. First build
29462275360

Pull #2936

github

web-flow
Merge a1505e5d2 into 23fd28534
Pull Request #2936: Backport various bugfixes to v3

161 of 239 new or added lines in 22 files covered. (67.36%)

19309 of 38283 relevant lines covered (50.44%)

671.19 hits per line

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

45.78
/src/mavsdk/core/system_impl.cpp
1
#include "system.h"
2
#include "mavsdk_impl.h"
3
#include "mavlink_include.h"
4
#include "system_impl.h"
5
#include <mav/MessageSet.h>
6
#include "server_component_impl.h"
7
#include "plugin_impl_base.h"
8
#include "px4_custom_mode.h"
9
#include "ardupilot_custom_mode.h"
10
#include "callback_list.tpp"
11
#include "unused.h"
12
#include "mavsdk_export.h"
13
#include <cassert>
14
#include <cstdlib>
15
#include <functional>
16
#include <future>
17
#include <utility>
18

19
namespace mavsdk {
20

21
template class MAVSDK_TEMPL_INST CallbackList<bool>;
22
template class MAVSDK_TEMPL_INST CallbackList<ComponentType>;
23
template class MAVSDK_TEMPL_INST CallbackList<ComponentType, uint8_t>;
24

25
SystemImpl::SystemImpl(MavsdkImpl& mavsdk_impl) :
172✔
26
    _mavsdk_impl(mavsdk_impl),
172✔
27
    _command_sender(*this),
172✔
28
    _timesync(*this),
172✔
29
    _ping(*this),
172✔
30
    _mission_transfer_client(
344✔
31
        _mavsdk_impl.default_server_component_impl().sender(),
172✔
32
        _mavlink_message_handler,
172✔
33
        _mavsdk_impl.timeout_handler,
172✔
34
        [this]() { return timeout_s(); },
13✔
35
        [this]() { return effective_autopilot(); }),
8✔
36
    _mavlink_request_message(
172✔
37
        *this, _command_sender, _mavlink_message_handler, _mavsdk_impl.timeout_handler),
172✔
38
    _mavlink_ftp_client(*this),
172✔
39
    _mavlink_component_metadata(*this)
344✔
40
{
41
    if (const char* env_p = std::getenv("MAVSDK_MESSAGE_DEBUGGING")) {
172✔
42
        if (std::string(env_p) == "1") {
×
43
            _message_debugging = true;
×
44
        }
45
    }
46

47
    _system_thread = new std::thread(&SystemImpl::system_thread, this);
172✔
48
}
172✔
49

50
SystemImpl::~SystemImpl()
172✔
51
{
52
    _should_exit = true;
172✔
53
    // Use blocking version to ensure any in-flight callbacks complete before destruction.
54
    _mavlink_message_handler.unregister_all_blocking(this);
172✔
55
    // Clear all libmav message callbacks
56
    _libmav_message_callbacks.clear();
172✔
57

58
    unregister_timeout_handler(_heartbeat_timeout_cookie);
172✔
59

60
    if (_system_thread != nullptr) {
172✔
61
        _system_thread->join();
172✔
62
        delete _system_thread;
172✔
63
        _system_thread = nullptr;
172✔
64
    }
65
}
172✔
66

67
void SystemImpl::init(uint8_t system_id, uint8_t comp_id)
172✔
68
{
69
    _target_address.system_id = system_id;
172✔
70
    // We use this as a default.
71
    _target_address.component_id = MAV_COMP_ID_AUTOPILOT1;
172✔
72

73
    _mavlink_message_handler.register_one(
172✔
74
        MAVLINK_MSG_ID_HEARTBEAT,
75
        [this](const mavlink_message_t& message) { process_heartbeat(message); },
484✔
76
        this);
77

78
    _mavlink_message_handler.register_one(
172✔
79
        MAVLINK_MSG_ID_STATUSTEXT,
80
        [this](const mavlink_message_t& message) { process_statustext(message); },
3✔
81
        this);
82

83
    _mavlink_message_handler.register_one(
172✔
84
        MAVLINK_MSG_ID_AUTOPILOT_VERSION,
85
        [this](const mavlink_message_t& message) { process_autopilot_version(message); },
86✔
86
        this);
87

88
    add_new_component(comp_id);
172✔
89
}
172✔
90

91
bool SystemImpl::is_connected() const
84✔
92
{
93
    return _connected;
84✔
94
}
95

96
void SystemImpl::register_mavlink_message_handler(
908✔
97
    uint16_t msg_id, const MavlinkMessageHandler::Callback& callback, const void* cookie)
98
{
99
    _mavlink_message_handler.register_one(msg_id, callback, cookie);
908✔
100
}
908✔
101

102
void SystemImpl::register_mavlink_message_handler_with_compid(
×
103
    uint16_t msg_id,
104
    uint8_t component_id,
105
    const MavlinkMessageHandler::Callback& callback,
106
    const void* cookie)
107
{
108
    _mavlink_message_handler.register_one_with_component_id(msg_id, component_id, callback, cookie);
×
109
}
×
110

111
void SystemImpl::unregister_mavlink_message_handler(uint16_t msg_id, const void* cookie)
×
112
{
113
    _mavlink_message_handler.unregister_one(msg_id, cookie);
×
114
}
×
115

116
void SystemImpl::unregister_all_mavlink_message_handlers(const void* cookie)
688✔
117
{
118
    _mavlink_message_handler.unregister_all(cookie);
688✔
119
}
688✔
120

121
void SystemImpl::unregister_all_mavlink_message_handlers_blocking(const void* cookie)
30✔
122
{
123
    _mavlink_message_handler.unregister_all_blocking(cookie);
30✔
124
}
30✔
125

126
void SystemImpl::update_component_id_messages_handler(
×
127
    uint16_t msg_id, uint8_t component_id, const void* cookie)
128
{
129
    _mavlink_message_handler.update_component_id(msg_id, component_id, cookie);
×
130
}
×
131

132
void SystemImpl::process_libmav_message(const Mavsdk::MavlinkMessage& message)
9,140✔
133
{
134
    if (_message_debugging) {
9,140✔
135
        LogDebug() << "SystemImpl::process_libmav_message: " << message.message_name;
×
136
    }
137

138
    // CallbackList handles thread safety - just call all callbacks and let them filter internally
139
    _libmav_message_callbacks.queue(
9,140✔
140
        message, [this](const std::function<void()>& callback_wrapper) { callback_wrapper(); });
116✔
141
}
9,126✔
142

143
Handle<Mavsdk::MavlinkMessage> SystemImpl::register_libmav_message_handler(
36✔
144
    const std::string& message_name, const LibmavMessageCallback& callback)
145
{
146
    // Create a filtering callback that only calls the user callback for matching messages
147
    auto filtering_callback =
148
        [this, message_name, callback](const Mavsdk::MavlinkMessage& message) {
232✔
149
            if (_message_debugging) {
116✔
150
                LogDebug() << "Checking handler for message: '" << message_name << "' against '"
×
151
                           << message.message_name << "'";
×
152
            }
153

154
            // Check if message name matches (empty string means match all messages)
155
            if (!message_name.empty() && message_name != message.message_name) {
116✔
156
                if (_message_debugging) {
×
157
                    LogDebug() << "Handler message name mismatch, skipping";
×
158
                }
159
                return;
×
160
            }
161

162
            // Call the user callback
163
            if (_message_debugging) {
116✔
164
                LogDebug() << "Calling libmav handler for: " << message.message_name;
×
165
            }
166
            callback(message);
116✔
167
        };
36✔
168

169
    auto handle = _libmav_message_callbacks.subscribe(filtering_callback);
36✔
170

171
    if (_message_debugging) {
36✔
172
        LogDebug() << "Registering libmav handler for message: '" << message_name << "'";
×
173
    }
174

175
    return handle;
72✔
176
}
36✔
177

178
Handle<Mavsdk::MavlinkMessage> SystemImpl::register_libmav_message_handler_with_compid(
×
179
    const std::string& message_name, uint8_t cmp_id, const LibmavMessageCallback& callback)
180
{
181
    // Create a filtering callback that only calls the user callback for matching messages
182
    auto filtering_callback =
183
        [this, message_name, cmp_id, callback](const Mavsdk::MavlinkMessage& message) {
×
184
            if (_message_debugging) {
×
185
                LogDebug() << "Checking handler for message: '" << message_name << "' against '"
×
186
                           << message.message_name
×
187
                           << "' with component ID: " << static_cast<int>(cmp_id);
×
188
            }
189

190
            // Check if message name matches (empty string means match all messages)
191
            if (!message_name.empty() && message_name != message.message_name) {
×
192
                if (_message_debugging) {
×
193
                    LogDebug() << "Handler message name mismatch, skipping";
×
194
                }
195
                return;
×
196
            }
197

198
            // Check if component ID matches
199
            if (cmp_id != message.component_id) {
×
200
                if (_message_debugging) {
×
201
                    LogDebug() << "Handler component ID mismatch, skipping";
×
202
                }
203
                return;
×
204
            }
205

206
            // Call the user callback
207
            if (_message_debugging) {
×
208
                LogDebug() << "Calling libmav handler for: " << message.message_name;
×
209
            }
210
            callback(message);
×
211
        };
×
212

213
    auto handle = _libmav_message_callbacks.subscribe(filtering_callback);
×
214

215
    if (_message_debugging) {
×
216
        LogDebug() << "Registering libmav handler for message: '" << message_name
×
217
                   << "' with component ID: " << static_cast<int>(cmp_id);
×
218
    }
219

220
    return handle;
×
221
}
×
222

223
void SystemImpl::unregister_libmav_message_handler(Handle<Mavsdk::MavlinkMessage> handle)
36✔
224
{
225
    _libmav_message_callbacks.unsubscribe(handle);
36✔
226

227
    if (_message_debugging) {
36✔
228
        LogDebug() << "Unregistered libmav handler";
×
229
    }
230
}
36✔
231

232
TimeoutHandler::Cookie
233
SystemImpl::register_timeout_handler(const std::function<void()>& callback, double duration_s)
1,306✔
234
{
235
    return _mavsdk_impl.timeout_handler.add(callback, duration_s);
1,306✔
236
}
237

238
void SystemImpl::refresh_timeout_handler(TimeoutHandler::Cookie cookie)
307✔
239
{
240
    _mavsdk_impl.timeout_handler.refresh(cookie);
307✔
241
}
306✔
242

243
void SystemImpl::unregister_timeout_handler(TimeoutHandler::Cookie cookie)
1,539✔
244
{
245
    _mavsdk_impl.timeout_handler.remove(cookie);
1,539✔
246
}
1,539✔
247

248
double SystemImpl::timeout_s() const
1,221✔
249
{
250
    return _mavsdk_impl.timeout_s();
1,221✔
251
}
252

253
void SystemImpl::enable_timesync()
×
254
{
255
    _timesync.enable();
×
256
}
×
257

258
System::IsConnectedHandle
259
SystemImpl::subscribe_is_connected(const System::IsConnectedCallback& callback)
×
260
{
261
    return _is_connected_callbacks.subscribe(callback);
×
262
}
263

264
void SystemImpl::unsubscribe_is_connected(System::IsConnectedHandle handle)
×
265
{
266
    _is_connected_callbacks.unsubscribe(handle);
×
267
}
×
268

269
void SystemImpl::process_mavlink_message(mavlink_message_t& message)
9,086✔
270
{
271
    _mavlink_message_handler.process_message(message);
9,086✔
272
}
9,099✔
273

274
CallEveryHandler::Cookie
275
SystemImpl::add_call_every(std::function<void()> callback, float interval_s)
45✔
276
{
277
    return _mavsdk_impl.call_every_handler.add(
90✔
278
        std::move(callback), static_cast<double>(interval_s));
90✔
279
}
280

281
void SystemImpl::change_call_every(float interval_s, CallEveryHandler::Cookie cookie)
×
282
{
283
    _mavsdk_impl.call_every_handler.change(static_cast<double>(interval_s), cookie);
×
284
}
×
285

286
void SystemImpl::reset_call_every(CallEveryHandler::Cookie cookie)
×
287
{
288
    _mavsdk_impl.call_every_handler.reset(cookie);
×
289
}
×
290

291
void SystemImpl::remove_call_every(CallEveryHandler::Cookie cookie)
45✔
292
{
293
    _mavsdk_impl.call_every_handler.remove(cookie);
45✔
294
}
45✔
295

296
void SystemImpl::register_statustext_handler(
12✔
297
    std::function<void(const MavlinkStatustextHandler::Statustext&)> callback, void* cookie)
298
{
299
    std::lock_guard<std::mutex> lock(_statustext_handler_callbacks_mutex);
12✔
300
    _statustext_handler_callbacks.push_back(StatustextCallback{std::move(callback), cookie});
12✔
301
}
12✔
302

303
void SystemImpl::unregister_statustext_handler(void* cookie)
12✔
304
{
305
    std::lock_guard<std::mutex> lock(_statustext_handler_callbacks_mutex);
12✔
306
    _statustext_handler_callbacks.erase(
24✔
307
        std::remove_if(
12✔
308
            _statustext_handler_callbacks.begin(),
309
            _statustext_handler_callbacks.end(),
310
            [&](const auto& entry) { return entry.cookie == cookie; }),
12✔
311
        _statustext_handler_callbacks.end());
12✔
312
}
12✔
313

314
void SystemImpl::process_heartbeat(const mavlink_message_t& message)
484✔
315
{
316
    mavlink_heartbeat_t heartbeat;
317
    mavlink_msg_heartbeat_decode(&message, &heartbeat);
484✔
318

319
    if (heartbeat.autopilot == MAV_AUTOPILOT_PX4) {
482✔
320
        _autopilot = Autopilot::Px4;
×
321
    } else if (heartbeat.autopilot == MAV_AUTOPILOT_ARDUPILOTMEGA) {
482✔
322
        _autopilot = Autopilot::ArduPilot;
5✔
323
    }
324

325
    // Only set the vehicle type if the heartbeat is from an autopilot component
326
    // This check only works if the MAV_TYPE::MAV_TYPE_ENUM_END is actually the
327
    // last enumerator.
328
    if (MAV_TYPE::MAV_TYPE_ENUM_END < heartbeat.type) {
474✔
329
        LogErr() << "type received in HEARTBEAT was not recognized";
×
330
    } else {
331
        const auto new_vehicle_type = static_cast<MAV_TYPE>(heartbeat.type);
474✔
332
        if (heartbeat.autopilot != MAV_AUTOPILOT_INVALID && new_vehicle_type != MAV_TYPE_GENERIC) {
474✔
333
            if (_vehicle_type_set && _vehicle_type != new_vehicle_type) {
5✔
334
                LogWarn() << "Vehicle type changed (new type: "
×
335
                          << static_cast<unsigned>(heartbeat.type)
×
336
                          << ", old type: " << static_cast<unsigned>(_vehicle_type) << ")";
×
337
            }
338
            _vehicle_type = new_vehicle_type;
5✔
339
            _vehicle_type_set = true;
5✔
340
        }
341
    }
342

343
    if (message.compid == MavlinkCommandSender::DEFAULT_COMPONENT_ID_AUTOPILOT) {
474✔
344
        _armed = (heartbeat.base_mode & MAV_MODE_FLAG_SAFETY_ARMED) != 0;
232✔
345
        _hitl_enabled = (heartbeat.base_mode & MAV_MODE_FLAG_HIL_ENABLED) != 0;
232✔
346
    }
347
    if (heartbeat.base_mode & MAV_MODE_FLAG_CUSTOM_MODE_ENABLED) {
484✔
348
        _flight_mode =
5✔
349
            to_flight_mode_from_custom_mode(_autopilot, _vehicle_type, heartbeat.custom_mode);
350
    }
351

352
    set_connected();
484✔
353
}
482✔
354

355
void SystemImpl::process_statustext(const mavlink_message_t& message)
3✔
356
{
357
    mavlink_statustext_t statustext;
358
    mavlink_msg_statustext_decode(&message, &statustext);
3✔
359

360
    const auto maybe_result = _statustext_handler.process(statustext);
3✔
361

362
    if (maybe_result.has_value()) {
3✔
363
        LogDebug() << "MAVLink: "
3✔
364
                   << MavlinkStatustextHandler::severity_str(maybe_result.value().severity) << ": "
6✔
365
                   << maybe_result.value().text;
3✔
366

367
        // Copy the callbacks out under the lock and invoke them afterwards, so a
368
        // callback that (un)registers a handler can't deadlock or invalidate the vector.
369
        std::vector<StatustextCallback> callbacks_copy;
3✔
370
        {
371
            std::lock_guard<std::mutex> lock(_statustext_handler_callbacks_mutex);
3✔
372
            callbacks_copy = _statustext_handler_callbacks;
3✔
373
        }
3✔
374
        for (const auto& entry : callbacks_copy) {
6✔
375
            entry.callback(maybe_result.value());
3✔
376
        }
377
    }
3✔
378
}
3✔
379

380
void SystemImpl::process_autopilot_version(const mavlink_message_t& message)
86✔
381
{
382
    mavlink_autopilot_version_t autopilot_version;
383
    mavlink_msg_autopilot_version_decode(&message, &autopilot_version);
86✔
384

385
    _mission_transfer_client.set_int_messages_supported(
86✔
386
        autopilot_version.capabilities & MAV_PROTOCOL_CAPABILITY_MISSION_INT);
86✔
387
}
86✔
388

389
void SystemImpl::heartbeats_timed_out()
5✔
390
{
391
    LogInfo() << "heartbeats timed out";
5✔
392
    set_disconnected();
5✔
393
}
5✔
394

395
void SystemImpl::system_thread()
172✔
396
{
397
    SteadyTimePoint last_ping_time{};
172✔
398

399
    while (!_should_exit) {
21,199✔
400
        {
401
            std::lock_guard<std::mutex> lock(_mavlink_parameter_clients_mutex);
20,959✔
402
            for (auto& entry : _mavlink_parameter_clients) {
21,995✔
403
                entry.parameter_client->do_work();
1,040✔
404
            }
405
        }
20,870✔
406
        _command_sender.do_work();
20,982✔
407
        _timesync.do_work();
20,971✔
408
        _mission_transfer_client.do_work();
21,000✔
409
        _mavlink_ftp_client.do_work();
20,978✔
410

411
        if (_mavsdk_impl.time.elapsed_since_s(last_ping_time) >= SystemImpl::_ping_interval_s) {
20,921✔
412
            if (_connected && _autopilot != Autopilot::ArduPilot) {
184✔
413
                _ping.run_once();
36✔
414
            }
415
            last_ping_time = _mavsdk_impl.time.steady_time();
184✔
416
        }
417

418
        if (_connected) {
20,849✔
419
            // Work fairly fast if we're connected.
420
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
20,651✔
421
        } else {
422
            // Be less aggressive when unconnected.
423
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
167✔
424
        }
425
    }
426
}
106✔
427

428
std::string SystemImpl::component_name(uint8_t component_id)
175✔
429
{
430
    switch (component_id) {
175✔
431
        case MAV_COMP_ID_AUTOPILOT1:
73✔
432
            return "Autopilot";
73✔
433
        case MAV_COMP_ID_CAMERA:
11✔
434
            return "Camera 1";
11✔
435
        case MAV_COMP_ID_CAMERA2:
×
436
            return "Camera 2";
×
437
        case MAV_COMP_ID_CAMERA3:
×
438
            return "Camera 3";
×
439
        case MAV_COMP_ID_CAMERA4:
×
440
            return "Camera 4";
×
441
        case MAV_COMP_ID_CAMERA5:
×
442
            return "Camera 5";
×
443
        case MAV_COMP_ID_CAMERA6:
×
444
            return "Camera 6";
×
445
        case MAV_COMP_ID_GIMBAL:
×
446
            return "Gimbal";
×
447
        case MAV_COMP_ID_MISSIONPLANNER:
85✔
448
            return "Ground station";
85✔
449
        case MAV_COMP_ID_ONBOARD_COMPUTER:
1✔
450
            return "Companion Computer";
1✔
451
        case MAV_COMP_ID_WINCH:
×
452
            return "Winch";
×
453
        default:
5✔
454
            return "Unsupported component";
5✔
455
    }
456
}
457

458
ComponentType SystemImpl::component_type(uint8_t component_id)
350✔
459
{
460
    switch (component_id) {
350✔
461
        case MAV_COMP_ID_AUTOPILOT1:
146✔
462
            return ComponentType::Autopilot;
146✔
463
        case MAV_COMP_ID_MISSIONPLANNER:
170✔
464
            return ComponentType::GroundStation;
170✔
465
        case MAV_COMP_ID_ONBOARD_COMPUTER:
2✔
466
        case MAV_COMP_ID_ONBOARD_COMPUTER2:
467
        case MAV_COMP_ID_ONBOARD_COMPUTER3:
468
        case MAV_COMP_ID_ONBOARD_COMPUTER4:
469
            return ComponentType::CompanionComputer;
2✔
470
        case MAV_COMP_ID_CAMERA:
22✔
471
        case MAV_COMP_ID_CAMERA2:
472
        case MAV_COMP_ID_CAMERA3:
473
        case MAV_COMP_ID_CAMERA4:
474
        case MAV_COMP_ID_CAMERA5:
475
        case MAV_COMP_ID_CAMERA6:
476
            return ComponentType::Camera;
22✔
477
        case MAV_COMP_ID_GIMBAL:
×
478
            return ComponentType::Gimbal;
×
479
        case MAV_COMP_ID_ODID_TXRX_1:
×
480
        case MAV_COMP_ID_ODID_TXRX_2:
481
        case MAV_COMP_ID_ODID_TXRX_3:
482
            return ComponentType::RemoteId;
×
483
        default:
10✔
484
            return ComponentType::Custom;
10✔
485
    }
486
}
487

488
void SystemImpl::add_new_component(uint8_t component_id)
18,225✔
489
{
490
    if (component_id == 0) {
18,225✔
491
        return;
×
492
    }
493

494
    bool is_new_component = false;
18,225✔
495
    {
496
        std::lock_guard<std::mutex> lock(_components_mutex);
18,225✔
497
        auto res_pair = _components.insert(component_id);
18,233✔
498
        is_new_component = res_pair.second;
18,238✔
499
    }
18,238✔
500

501
    if (is_new_component) {
18,232✔
502
        _component_discovered_callbacks.queue(
175✔
503
            component_type(component_id), [this](const auto& func) { call_user_callback(func); });
×
504
        _component_discovered_id_callbacks.queue(
175✔
505
            component_type(component_id), component_id, [this](const auto& func) {
×
506
                call_user_callback(func);
×
507
            });
×
508
        LogDebug() << "Component " << component_name(component_id)
350✔
509
                   << " (component ID: " << int(component_id) << ") added.";
175✔
510
    }
511
}
512

513
size_t SystemImpl::total_components() const
×
514
{
515
    std::lock_guard<std::mutex> lock(_components_mutex);
×
516
    return _components.size();
×
517
}
×
518

519
System::ComponentDiscoveredHandle
520
SystemImpl::subscribe_component_discovered(const System::ComponentDiscoveredCallback& callback)
×
521
{
522
    const auto handle = _component_discovered_callbacks.subscribe(callback);
×
523

524
    if (total_components() > 0) {
×
525
        std::lock_guard<std::mutex> components_lock(_components_mutex);
×
526
        for (const auto& elem : _components) {
×
527
            _component_discovered_callbacks.queue(
×
528
                component_type(elem), [this](const auto& func) { call_user_callback(func); });
×
529
        }
530
    }
×
531
    return handle;
×
532
}
533

534
void SystemImpl::unsubscribe_component_discovered(System::ComponentDiscoveredHandle handle)
×
535
{
536
    _component_discovered_callbacks.unsubscribe(handle);
×
537
}
×
538

539
System::ComponentDiscoveredIdHandle
540
SystemImpl::subscribe_component_discovered_id(const System::ComponentDiscoveredIdCallback& callback)
×
541
{
542
    const auto handle = _component_discovered_id_callbacks.subscribe(callback);
×
543

544
    if (total_components() > 0) {
×
545
        std::lock_guard<std::mutex> components_lock(_components_mutex);
×
546
        for (const auto& elem : _components) {
×
547
            _component_discovered_id_callbacks.queue(
×
548
                component_type(elem), elem, [this](const auto& func) { call_user_callback(func); });
×
549
        }
550
    }
×
551
    return handle;
×
552
}
553

554
void SystemImpl::unsubscribe_component_discovered_id(System::ComponentDiscoveredIdHandle handle)
×
555
{
556
    _component_discovered_id_callbacks.unsubscribe(handle);
×
557
}
×
558

559
bool SystemImpl::is_standalone() const
×
560
{
561
    return !has_autopilot();
×
562
}
563

564
bool SystemImpl::has_autopilot() const
307✔
565
{
566
    return get_autopilot_id() != uint8_t(0);
307✔
567
}
568

569
bool SystemImpl::is_autopilot(uint8_t comp_id)
×
570
{
571
    return comp_id == MAV_COMP_ID_AUTOPILOT1;
×
572
}
573

574
bool SystemImpl::is_camera(uint8_t comp_id)
11✔
575
{
576
    return (comp_id >= MAV_COMP_ID_CAMERA) && (comp_id <= MAV_COMP_ID_CAMERA6);
11✔
577
}
578

579
bool SystemImpl::has_camera(int camera_id) const
11✔
580
{
581
    std::lock_guard<std::mutex> lock(_components_mutex);
11✔
582
    int camera_comp_id = (camera_id == -1) ? camera_id : (MAV_COMP_ID_CAMERA + camera_id);
11✔
583

584
    if (camera_comp_id == -1) { // Check whether the system has any camera.
11✔
585
        if (std::any_of(_components.begin(), _components.end(), is_camera)) {
11✔
586
            return true;
11✔
587
        }
588
    } else { // Look for the camera whose id is `camera_id`.
589
        for (auto compid : _components) {
×
590
            if (compid == camera_comp_id) {
×
591
                return true;
×
592
            }
593
        }
594
    }
595
    return false;
×
596
}
11✔
597

598
bool SystemImpl::has_gimbal() const
×
599
{
600
    return get_gimbal_id() == MAV_COMP_ID_GIMBAL;
×
601
}
602

603
bool SystemImpl::send_message(mavlink_message_t& message)
×
604
{
605
    return _mavsdk_impl.send_message(message);
×
606
}
607

608
bool SystemImpl::queue_message(
985✔
609
    std::function<mavlink_message_t(MavlinkAddress mavlink_address, uint8_t channel)> fun)
610
{
611
    return _mavsdk_impl.default_server_component_impl().queue_message(fun);
985✔
612
}
613

614
void SystemImpl::send_autopilot_version_request()
74✔
615
{
616
    mavlink_request_message().request(
74✔
617
        MAVLINK_MSG_ID_AUTOPILOT_VERSION, MAV_COMP_ID_AUTOPILOT1, nullptr);
618
}
74✔
619

620
void SystemImpl::set_connected()
481✔
621
{
622
    bool enable_needed = false;
481✔
623
    {
624
        if (!_connected) {
481✔
625
            {
626
                std::lock_guard<std::mutex> lock(_components_mutex);
176✔
627
                if (!_components.empty()) {
176✔
628
                    LogDebug() << "Discovered " << _components.size()
352✔
629
                               << (_components.size() == 1 ? " component" : " components");
176✔
630
                }
631
            }
176✔
632

633
            _connected = true;
176✔
634

635
            // Only send heartbeats if we're not shutting down
636
            if (!_should_exit) {
176✔
637
                // We call this later to avoid deadlocks on creating the server components.
638
                _mavsdk_impl.call_user_callback([this]() {
352✔
639
                    // Send a heartbeat back immediately.
640
                    _mavsdk_impl.start_sending_heartbeats();
641
                });
642
            }
643

644
            _heartbeat_timeout_cookie = register_timeout_handler(
176✔
645
                [this] { heartbeats_timed_out(); }, _mavsdk_impl.heartbeat_timeout_s());
181✔
646

647
            enable_needed = true;
176✔
648

649
            // Queue callbacks without holding any locks to avoid deadlocks
650
            _is_connected_callbacks.queue(
176✔
651
                true, [this](const auto& func) { _mavsdk_impl.call_user_callback(func); });
×
652

653
        } else if (_connected) {
302✔
654
            refresh_timeout_handler(_heartbeat_timeout_cookie);
307✔
655
        }
656
        // If not yet connected there is nothing to do
657
    }
658

659
    if (enable_needed) {
482✔
660
        // Notify about the new system without holding any locks
661
        _mavsdk_impl.notify_on_discover();
176✔
662

663
        if (has_autopilot()) {
176✔
664
            send_autopilot_version_request();
74✔
665
        }
666

667
        // Enable plugins
668
        std::vector<PluginImplBase*> plugin_impls_to_enable;
176✔
669
        {
670
            std::lock_guard<std::mutex> lock(_plugin_impls_mutex);
176✔
671
            plugin_impls_to_enable = _plugin_impls;
176✔
672
        }
176✔
673

674
        for (auto plugin_impl : plugin_impls_to_enable) {
178✔
675
            plugin_impl->enable();
2✔
676
        }
677
    }
176✔
678
}
482✔
679

680
void SystemImpl::set_disconnected()
5✔
681
{
682
    {
683
        // This might not be needed because this is probably called from the triggered
684
        // timeout anyway, but it should also do no harm.
685
        // unregister_timeout_handler(_heartbeat_timeout_cookie);
686
        //_heartbeat_timeout_cookie = nullptr;
687

688
        _connected = false;
5✔
689
        _is_connected_callbacks.queue(
5✔
690
            false, [this](const auto& func) { _mavsdk_impl.call_user_callback(func); });
×
691
    }
692
    _mavsdk_impl.notify_on_timeout();
5✔
693

694
    _mavsdk_impl.stop_sending_heartbeats();
5✔
695

696
    {
697
        std::lock_guard<std::mutex> lock(_plugin_impls_mutex);
5✔
698
        for (auto plugin_impl : _plugin_impls) {
7✔
699
            plugin_impl->disable();
2✔
700
        }
701
    }
5✔
702
}
5✔
703

704
uint8_t SystemImpl::get_system_id() const
903✔
705
{
706
    return _target_address.system_id;
903✔
707
}
708

709
Autopilot SystemImpl::effective_autopilot() const
1,867✔
710
{
711
    return _mavsdk_impl.effective_autopilot(_autopilot);
1,867✔
712
}
713

714
std::vector<uint8_t> SystemImpl::component_ids() const
12✔
715
{
716
    std::lock_guard<std::mutex> lock(_components_mutex);
12✔
717
    return std::vector<uint8_t>{_components.begin(), _components.end()};
12✔
718
}
12✔
719

720
void SystemImpl::set_system_id(uint8_t system_id)
×
721
{
722
    _target_address.system_id = system_id;
×
723
}
×
724

725
uint8_t SystemImpl::get_own_system_id() const
1,540✔
726
{
727
    return _mavsdk_impl.get_own_system_id();
1,540✔
728
}
729

730
uint8_t SystemImpl::get_own_component_id() const
1,514✔
731
{
732
    return _mavsdk_impl.get_own_component_id();
1,514✔
733
}
734

735
MAV_TYPE SystemImpl::get_vehicle_type() const
×
736
{
737
    return _vehicle_type;
×
738
}
739

740
Vehicle SystemImpl::vehicle() const
×
741
{
742
    return to_vehicle_from_mav_type(_vehicle_type);
×
743
}
744

745
uint8_t SystemImpl::get_own_mav_type() const
×
746
{
747
    return _mavsdk_impl.get_mav_type();
×
748
}
749

750
MavlinkParameterClient::Result SystemImpl::set_param(
×
751
    const std::string& name,
752
    ParamValue value,
753
    std::optional<uint8_t> maybe_component_id,
754
    bool extended)
755
{
756
    return param_sender(maybe_component_id ? maybe_component_id.value() : 1, extended)
×
757
        ->set_param(name, value);
×
758
}
759

760
MavlinkParameterClient::Result SystemImpl::set_param_float(
2✔
761
    const std::string& name, float value, std::optional<uint8_t> maybe_component_id, bool extended)
762
{
763
    return param_sender(maybe_component_id ? maybe_component_id.value() : 1, extended)
2✔
764
        ->set_param_float(name, value);
4✔
765
}
766

767
MavlinkParameterClient::Result SystemImpl::set_param_int(
2✔
768
    const std::string& name,
769
    int32_t value,
770
    std::optional<uint8_t> maybe_component_id,
771
    bool extended)
772
{
773
    return param_sender(maybe_component_id ? maybe_component_id.value() : 1, extended)
2✔
774
        ->set_param_int(name, value);
4✔
775
}
776

777
MavlinkParameterClient::Result SystemImpl::set_param_custom(
2✔
778
    const std::string& name, const std::string& value, std::optional<uint8_t> maybe_component_id)
779
{
780
    return param_sender(maybe_component_id.has_value() ? maybe_component_id.value() : 1, true)
4✔
781
        ->set_param_custom(name, value);
4✔
782
}
783

784
std::pair<MavlinkParameterClient::Result, std::map<std::string, ParamValue>>
785
SystemImpl::get_all_params(std::optional<uint8_t> maybe_component_id, bool extended)
5✔
786
{
787
    return param_sender(maybe_component_id ? maybe_component_id.value() : 1, extended)
5✔
788
        ->get_all_params();
10✔
789
}
790

791
void SystemImpl::set_param_async(
3✔
792
    const std::string& name,
793
    ParamValue value,
794
    const SetParamCallback& callback,
795
    const void* cookie,
796
    std::optional<uint8_t> maybe_component_id,
797
    bool extended)
798
{
799
    param_sender(maybe_component_id ? maybe_component_id.value() : 1, extended)
3✔
800
        ->set_param_async(name, value, callback, cookie);
6✔
801
}
3✔
802

803
void SystemImpl::set_param_float_async(
×
804
    const std::string& name,
805
    float value,
806
    const SetParamCallback& callback,
807
    const void* cookie,
808
    std::optional<uint8_t> maybe_component_id,
809
    bool extended)
810
{
811
    param_sender(maybe_component_id ? maybe_component_id.value() : 1, extended)
×
812
        ->set_param_float_async(name, value, callback, cookie);
×
813
}
×
814

815
void SystemImpl::set_param_int_async(
×
816
    const std::string& name,
817
    int32_t value,
818
    const SetParamCallback& callback,
819
    const void* cookie,
820
    std::optional<uint8_t> maybe_component_id,
821
    bool extended)
822
{
823
    param_sender(maybe_component_id ? maybe_component_id.value() : 1, extended)
×
824
        ->set_param_int_async(name, value, callback, cookie);
×
825
}
×
826

827
std::pair<MavlinkParameterClient::Result, float> SystemImpl::get_param_float(
8✔
828
    const std::string& name, std::optional<uint8_t> maybe_component_id, bool extended)
829
{
830
    return param_sender(maybe_component_id ? maybe_component_id.value() : 1, extended)
8✔
831
        ->get_param_float(name);
16✔
832
}
833

834
std::pair<MavlinkParameterClient::Result, int> SystemImpl::get_param_int(
8✔
835
    const std::string& name, std::optional<uint8_t> maybe_component_id, bool extended)
836
{
837
    return param_sender(maybe_component_id ? maybe_component_id.value() : 1, extended)
8✔
838
        ->get_param_int(name);
16✔
839
}
840

841
std::pair<MavlinkParameterClient::Result, std::string>
842
SystemImpl::get_param_custom(const std::string& name, std::optional<uint8_t> maybe_component_id)
4✔
843
{
844
    return param_sender(maybe_component_id ? maybe_component_id.value() : 1, true)
8✔
845
        ->get_param_custom(name);
8✔
846
}
847

848
void SystemImpl::get_param_async(
×
849
    const std::string& name,
850
    ParamValue value,
851
    const GetParamAnyCallback& callback,
852
    const void* cookie,
853
    std::optional<uint8_t> maybe_component_id,
854
    bool extended)
855
{
856
    param_sender(maybe_component_id ? maybe_component_id.value() : 1, extended)
×
857
        ->get_param_async(name, value, callback, cookie);
×
858
}
×
859

860
void SystemImpl::get_param_float_async(
×
861
    const std::string& name,
862
    const GetParamFloatCallback& callback,
863
    const void* cookie,
864
    std::optional<uint8_t> maybe_component_id,
865
    bool extended)
866
{
867
    param_sender(maybe_component_id ? maybe_component_id.value() : 1, extended)
×
868
        ->get_param_float_async(name, callback, cookie);
×
869
}
×
870

871
void SystemImpl::get_param_int_async(
×
872
    const std::string& name,
873
    const GetParamIntCallback& callback,
874
    const void* cookie,
875
    std::optional<uint8_t> maybe_component_id,
876
    bool extended)
877
{
878
    param_sender(maybe_component_id ? maybe_component_id.value() : 1, extended)
×
879
        ->get_param_int_async(name, callback, cookie);
×
880
}
×
881

882
void SystemImpl::get_param_custom_async(
×
883
    const std::string& name, const GetParamCustomCallback& callback, const void* cookie)
884
{
885
    param_sender(1, false)->get_param_custom_async(name, callback, cookie);
×
886
}
×
887

888
void SystemImpl::cancel_all_param(const void* cookie)
11✔
889
{
890
    UNUSED(cookie);
11✔
891
    // FIXME: this currently crashes on destruction
892
    // param_sender(1, false)->cancel_all_param(cookie);
893
}
11✔
894

895
MavlinkCommandSender::Result
896
SystemImpl::set_flight_mode(FlightMode system_mode, uint8_t component_id)
×
897
{
898
    std::pair<MavlinkCommandSender::Result, MavlinkCommandSender::CommandLong> result =
899
        make_command_flight_mode(system_mode, component_id);
×
900

901
    if (result.first != MavlinkCommandSender::Result::Success) {
×
902
        return result.first;
×
903
    }
904

905
    return send_command(result.second);
×
906
}
907

908
void SystemImpl::set_flight_mode_async(
×
909
    FlightMode system_mode, const CommandResultCallback& callback, uint8_t component_id)
910
{
911
    std::pair<MavlinkCommandSender::Result, MavlinkCommandSender::CommandLong> result =
912
        make_command_flight_mode(system_mode, component_id);
×
913

914
    if (result.first != MavlinkCommandSender::Result::Success) {
×
915
        if (callback) {
×
916
            callback(result.first, NAN);
×
917
        }
918
        return;
×
919
    }
920

921
    send_command_async(result.second, callback);
×
922
}
923

924
std::pair<MavlinkCommandSender::Result, MavlinkCommandSender::CommandLong>
925
SystemImpl::make_command_flight_mode(FlightMode flight_mode, uint8_t component_id)
×
926
{
927
    if (_autopilot == Autopilot::ArduPilot) {
×
928
        return make_command_ardupilot_mode(flight_mode, component_id);
×
929
    } else {
930
        return make_command_px4_mode(flight_mode, component_id);
×
931
    }
932
}
933

934
std::pair<MavlinkCommandSender::Result, MavlinkCommandSender::CommandLong>
935
SystemImpl::make_command_ardupilot_mode(FlightMode flight_mode, uint8_t component_id)
×
936
{
937
    const uint8_t flag_safety_armed = is_armed() ? MAV_MODE_FLAG_SAFETY_ARMED : 0;
×
938
    const uint8_t flag_hitl_enabled = _hitl_enabled ? MAV_MODE_FLAG_HIL_ENABLED : 0;
×
939
    const uint8_t mode_type =
×
940
        MAV_MODE_FLAG_CUSTOM_MODE_ENABLED | flag_safety_armed | flag_hitl_enabled;
×
941

942
    MavlinkCommandSender::CommandLong command{};
×
943

944
    command.command = MAV_CMD_DO_SET_MODE;
×
945
    command.params.maybe_param1 = static_cast<float>(mode_type);
×
946

947
    switch (_vehicle_type) {
×
948
        case MAV_TYPE::MAV_TYPE_SURFACE_BOAT:
×
949
        case MAV_TYPE::MAV_TYPE_GROUND_ROVER: {
950
            const auto new_mode = flight_mode_to_ardupilot_rover_mode(flight_mode);
×
951
            if (new_mode == ardupilot::RoverMode::Unknown) {
×
952
                LogErr() << "Cannot translate flight mode to ArduPilot Rover mode.";
×
953
                MavlinkCommandSender::CommandLong empty_command{};
×
954
                return std::make_pair<>(MavlinkCommandSender::Result::UnknownError, empty_command);
×
955
            } else {
956
                command.params.maybe_param2 = static_cast<float>(new_mode);
×
957
            }
958
            break;
×
959
        }
960
        case MAV_TYPE::MAV_TYPE_FIXED_WING:
×
961
        case MAV_TYPE::MAV_TYPE_VTOL_TAILSITTER_DUOROTOR:
962
        case MAV_TYPE::MAV_TYPE_VTOL_TAILSITTER_QUADROTOR:
963
        case MAV_TYPE::MAV_TYPE_VTOL_TILTROTOR:
964
        case MAV_TYPE::MAV_TYPE_VTOL_FIXEDROTOR:
965
        case MAV_TYPE::MAV_TYPE_VTOL_TAILSITTER:
966
        case MAV_TYPE::MAV_TYPE_VTOL_TILTWING: {
967
            const auto new_mode = flight_mode_to_ardupilot_plane_mode(flight_mode);
×
968
            if (new_mode == ardupilot::PlaneMode::Unknown) {
×
969
                LogErr() << "Cannot translate flight mode to ArduPilot Plane mode.";
×
970
                MavlinkCommandSender::CommandLong empty_command{};
×
971
                return std::make_pair<>(MavlinkCommandSender::Result::UnknownError, empty_command);
×
972
            } else {
973
                command.params.maybe_param2 = static_cast<float>(new_mode);
×
974
            }
975
            break;
×
976
        }
977

978
        case MAV_TYPE::MAV_TYPE_QUADROTOR:
×
979
        case MAV_TYPE::MAV_TYPE_COAXIAL:
980
        case MAV_TYPE::MAV_TYPE_HELICOPTER:
981
        case MAV_TYPE::MAV_TYPE_HEXAROTOR:
982
        case MAV_TYPE::MAV_TYPE_OCTOROTOR:
983
        case MAV_TYPE::MAV_TYPE_TRICOPTER:
984
        case MAV_TYPE::MAV_TYPE_DODECAROTOR:
985
        case MAV_TYPE::MAV_TYPE_DECAROTOR: {
986
            const auto new_mode = flight_mode_to_ardupilot_copter_mode(flight_mode);
×
987
            if (new_mode == ardupilot::CopterMode::Unknown) {
×
988
                LogErr() << "Cannot translate flight mode to ArduPilot Copter mode.";
×
989
                MavlinkCommandSender::CommandLong empty_command{};
×
990
                return std::make_pair<>(MavlinkCommandSender::Result::UnknownError, empty_command);
×
991
            } else {
992
                command.params.maybe_param2 = static_cast<float>(new_mode);
×
993
            }
994
            break;
×
995
        }
996

997
        default:
×
998
            LogErr() << "Cannot translate flight mode to ArduPilot mode, for MAV_TYPE: "
×
999
                     << _vehicle_type;
×
1000
            MavlinkCommandSender::CommandLong empty_command{};
×
1001
            return std::make_pair<>(MavlinkCommandSender::Result::UnknownError, empty_command);
×
1002
    }
1003
    command.target_component_id = component_id;
×
1004

1005
    return std::make_pair<>(MavlinkCommandSender::Result::Success, command);
×
1006
}
1007
ardupilot::RoverMode SystemImpl::flight_mode_to_ardupilot_rover_mode(FlightMode flight_mode)
×
1008
{
1009
    switch (flight_mode) {
×
1010
        case FlightMode::Mission:
×
1011
            return ardupilot::RoverMode::Auto;
×
1012
        case FlightMode::Acro:
×
1013
            return ardupilot::RoverMode::Acro;
×
1014
        case FlightMode::Hold:
×
1015
            return ardupilot::RoverMode::Hold;
×
1016
        case FlightMode::ReturnToLaunch:
×
1017
            return ardupilot::RoverMode::RTL;
×
1018
        case FlightMode::Manual:
×
1019
            return ardupilot::RoverMode::Manual;
×
1020
        case FlightMode::FollowMe:
×
1021
            return ardupilot::RoverMode::Follow;
×
1022
        case FlightMode::Offboard:
×
1023
            return ardupilot::RoverMode::Guided;
×
1024
        case FlightMode::Unknown:
×
1025
        case FlightMode::Ready:
1026
        case FlightMode::Takeoff:
1027
        case FlightMode::Land:
1028
        case FlightMode::Altctl:
1029
        case FlightMode::Posctl:
1030
        case FlightMode::Rattitude:
1031
        case FlightMode::Stabilized:
1032
        default:
1033
            return ardupilot::RoverMode::Unknown;
×
1034
    }
1035
}
1036
ardupilot::CopterMode SystemImpl::flight_mode_to_ardupilot_copter_mode(FlightMode flight_mode)
×
1037
{
1038
    switch (flight_mode) {
×
1039
        case FlightMode::Mission:
×
1040
            return ardupilot::CopterMode::Auto;
×
1041
        case FlightMode::Acro:
×
1042
            return ardupilot::CopterMode::Acro;
×
1043
        case FlightMode::Hold:
×
1044
            return ardupilot::CopterMode::Loiter;
×
1045
        case FlightMode::ReturnToLaunch:
×
1046
            return ardupilot::CopterMode::Rtl;
×
1047
        case FlightMode::Land:
×
1048
            return ardupilot::CopterMode::Land;
×
1049
        case FlightMode::Manual:
×
1050
            return ardupilot::CopterMode::Stabilize;
×
1051
        case FlightMode::FollowMe:
×
1052
            return ardupilot::CopterMode::Follow;
×
1053
        case FlightMode::Offboard:
×
1054
            return ardupilot::CopterMode::Guided;
×
1055
        case FlightMode::Altctl:
×
1056
            return ardupilot::CopterMode::AltHold;
×
1057
        case FlightMode::Posctl:
×
1058
            return ardupilot::CopterMode::PosHold;
×
1059
        case FlightMode::Stabilized:
×
1060
            return ardupilot::CopterMode::Stabilize;
×
1061
        case FlightMode::Unknown:
×
1062
        case FlightMode::Ready:
1063
        case FlightMode::Takeoff:
1064
        case FlightMode::Rattitude:
1065
        default:
1066
            return ardupilot::CopterMode::Unknown;
×
1067
    }
1068
}
1069
ardupilot::PlaneMode SystemImpl::flight_mode_to_ardupilot_plane_mode(FlightMode flight_mode)
×
1070
{
1071
    switch (flight_mode) {
×
1072
        case FlightMode::Mission:
×
1073
            return ardupilot::PlaneMode::Auto;
×
1074
        case FlightMode::Acro:
×
1075
            return ardupilot::PlaneMode::Acro;
×
1076
        case FlightMode::Hold:
×
1077
            return ardupilot::PlaneMode::Loiter;
×
1078
        case FlightMode::ReturnToLaunch:
×
1079
            return ardupilot::PlaneMode::Rtl;
×
1080
        case FlightMode::Manual:
×
1081
            return ardupilot::PlaneMode::Manual;
×
1082
        case FlightMode::FBWA:
×
1083
            return ardupilot::PlaneMode::Fbwa;
×
1084
        case FlightMode::FBWB:
×
1085
            return ardupilot::PlaneMode::Fbwb;
×
1086
        case FlightMode::Stabilized:
×
1087
            return ardupilot::PlaneMode::Stabilize;
×
1088
        case FlightMode::Takeoff:
×
1089
            return ardupilot::PlaneMode::Takeoff;
×
1090
        case FlightMode::Offboard:
×
1091
            return ardupilot::PlaneMode::Guided;
×
1092
        case FlightMode::Unknown:
×
1093
            return ardupilot::PlaneMode::Unknown;
×
1094
        default:
×
1095
            return ardupilot::PlaneMode::Unknown;
×
1096
    }
1097
}
1098

1099
std::pair<MavlinkCommandSender::Result, MavlinkCommandSender::CommandLong>
1100
SystemImpl::make_command_px4_mode(FlightMode flight_mode, uint8_t component_id)
×
1101
{
1102
    const uint8_t flag_safety_armed = is_armed() ? MAV_MODE_FLAG_SAFETY_ARMED : 0;
×
1103
    const uint8_t flag_hitl_enabled = _hitl_enabled ? MAV_MODE_FLAG_HIL_ENABLED : 0;
×
1104

1105
    const uint8_t mode = MAV_MODE_FLAG_CUSTOM_MODE_ENABLED | flag_safety_armed | flag_hitl_enabled;
×
1106

1107
    // Note: the safety flag is not needed in future versions of the PX4 Firmware
1108
    //       but want to be rather safe than sorry.
1109
    uint8_t custom_mode = px4::PX4_CUSTOM_MAIN_MODE_AUTO;
×
1110
    uint8_t custom_sub_mode = 0;
×
1111

1112
    switch (flight_mode) {
×
1113
        case FlightMode::Hold:
×
1114
            custom_sub_mode = px4::PX4_CUSTOM_SUB_MODE_AUTO_LOITER;
×
1115
            break;
×
1116
        case FlightMode::ReturnToLaunch:
×
1117
            custom_sub_mode = px4::PX4_CUSTOM_SUB_MODE_AUTO_RTL;
×
1118
            break;
×
1119
        case FlightMode::Takeoff:
×
1120
            custom_sub_mode = px4::PX4_CUSTOM_SUB_MODE_AUTO_TAKEOFF;
×
1121
            break;
×
1122
        case FlightMode::Land:
×
1123
            custom_sub_mode = px4::PX4_CUSTOM_SUB_MODE_AUTO_LAND;
×
1124
            break;
×
1125
        case FlightMode::Mission:
×
1126
            custom_sub_mode = px4::PX4_CUSTOM_SUB_MODE_AUTO_MISSION;
×
1127
            break;
×
1128
        case FlightMode::FollowMe:
×
1129
            custom_sub_mode = px4::PX4_CUSTOM_SUB_MODE_AUTO_FOLLOW_TARGET;
×
1130
            break;
×
1131
        case FlightMode::Offboard:
×
1132
            custom_mode = px4::PX4_CUSTOM_MAIN_MODE_OFFBOARD;
×
1133
            break;
×
1134
        case FlightMode::Manual:
×
1135
            custom_mode = px4::PX4_CUSTOM_MAIN_MODE_MANUAL;
×
1136
            break;
×
1137
        case FlightMode::Posctl:
×
1138
            custom_mode = px4::PX4_CUSTOM_MAIN_MODE_POSCTL;
×
1139
            break;
×
1140
        case FlightMode::Altctl:
×
1141
            custom_mode = px4::PX4_CUSTOM_MAIN_MODE_ALTCTL;
×
1142
            break;
×
1143
        case FlightMode::Rattitude:
×
1144
            custom_mode = px4::PX4_CUSTOM_MAIN_MODE_RATTITUDE;
×
1145
            break;
×
1146
        case FlightMode::Acro:
×
1147
            custom_mode = px4::PX4_CUSTOM_MAIN_MODE_ACRO;
×
1148
            break;
×
1149
        case FlightMode::Stabilized:
×
1150
            custom_mode = px4::PX4_CUSTOM_MAIN_MODE_STABILIZED;
×
1151
            break;
×
1152
        default:
×
1153
            LogErr() << "Unknown Flight mode.";
×
1154
            MavlinkCommandSender::CommandLong empty_command{};
×
1155
            return std::make_pair<>(MavlinkCommandSender::Result::UnknownError, empty_command);
×
1156
    }
1157

1158
    MavlinkCommandSender::CommandLong command{};
×
1159

1160
    command.command = MAV_CMD_DO_SET_MODE;
×
1161
    command.params.maybe_param1 = static_cast<float>(mode);
×
1162
    command.params.maybe_param2 = static_cast<float>(custom_mode);
×
1163
    command.params.maybe_param3 = static_cast<float>(custom_sub_mode);
×
1164
    command.target_component_id = component_id;
×
1165

1166
    return std::make_pair<>(MavlinkCommandSender::Result::Success, command);
×
1167
}
1168

1169
FlightMode SystemImpl::get_flight_mode() const
10✔
1170
{
1171
    return _flight_mode;
10✔
1172
}
1173

1174
void SystemImpl::receive_float_param(
×
1175
    MavlinkParameterClient::Result result, ParamValue value, const GetParamFloatCallback& callback)
1176
{
1177
    if (callback) {
×
1178
        if (result == MavlinkParameterClient::Result::Success) {
×
1179
            callback(result, value.get<float>());
×
1180
        } else {
1181
            callback(result, NAN);
×
1182
        }
1183
    }
1184
}
×
1185

1186
void SystemImpl::receive_int_param(
×
1187
    MavlinkParameterClient::Result result, ParamValue value, const GetParamIntCallback& callback)
1188
{
1189
    if (callback) {
×
1190
        if (result == MavlinkParameterClient::Result::Success) {
×
1191
            callback(result, value.get<int32_t>());
×
1192
        } else {
1193
            callback(result, 0);
×
1194
        }
1195
    }
1196
}
×
1197

1198
uint8_t SystemImpl::get_autopilot_id() const
353✔
1199
{
1200
    std::lock_guard<std::mutex> lock(_components_mutex);
353✔
1201
    for (auto compid : _components)
470✔
1202
        if (compid == MavlinkCommandSender::DEFAULT_COMPONENT_ID_AUTOPILOT) {
360✔
1203
            return compid;
243✔
1204
        }
1205
    // FIXME: Not sure what should be returned if autopilot is not found
1206
    return uint8_t(0);
110✔
1207
}
353✔
1208

1209
std::vector<uint8_t> SystemImpl::get_camera_ids() const
×
1210
{
1211
    std::lock_guard<std::mutex> lock(_components_mutex);
×
1212
    std::vector<uint8_t> camera_ids{};
×
1213

1214
    for (auto compid : _components)
×
1215
        if (compid >= MAV_COMP_ID_CAMERA && compid <= MAV_COMP_ID_CAMERA6) {
×
1216
            camera_ids.push_back(compid);
×
1217
        }
1218
    return camera_ids;
×
1219
}
×
1220

1221
uint8_t SystemImpl::get_gimbal_id() const
×
1222
{
1223
    std::lock_guard<std::mutex> lock(_components_mutex);
×
1224
    for (auto compid : _components)
×
1225
        if (compid == MAV_COMP_ID_GIMBAL) {
×
1226
            return compid;
×
1227
        }
1228
    return uint8_t(0);
×
1229
}
×
1230

1231
MavlinkCommandSender::Result SystemImpl::send_command(MavlinkCommandSender::CommandLong& command)
5✔
1232
{
1233
    {
1234
        std::lock_guard<std::mutex> lock(_components_mutex);
5✔
1235
        if (_target_address.system_id == 0 && _components.empty()) {
5✔
1236
            return MavlinkCommandSender::Result::NoSystem;
×
1237
        }
1238
    }
5✔
1239
    command.target_system_id = get_system_id();
5✔
1240
    return _command_sender.send_command(command);
5✔
1241
}
1242

1243
MavlinkCommandSender::Result SystemImpl::send_command(MavlinkCommandSender::CommandInt& command)
×
1244
{
1245
    {
1246
        std::lock_guard<std::mutex> lock(_components_mutex);
×
1247
        if (_target_address.system_id == 0 && _components.empty()) {
×
1248
            return MavlinkCommandSender::Result::NoSystem;
×
1249
        }
1250
    }
×
1251
    command.target_system_id = get_system_id();
×
1252
    return _command_sender.send_command(command);
×
1253
}
1254

1255
void SystemImpl::send_command_async(
7✔
1256
    MavlinkCommandSender::CommandLong command, const CommandResultCallback& callback)
1257
{
1258
    {
1259
        std::lock_guard<std::mutex> lock(_components_mutex);
7✔
1260
        if (_target_address.system_id == 0 && _components.empty()) {
7✔
1261
            if (callback) {
×
1262
                callback(MavlinkCommandSender::Result::NoSystem, NAN);
×
1263
            }
1264
            return;
×
1265
        }
1266
    }
7✔
1267
    command.target_system_id = get_system_id();
7✔
1268

1269
    _command_sender.queue_command_async(command, callback);
7✔
1270
}
1271

1272
void SystemImpl::send_command_async(
×
1273
    MavlinkCommandSender::CommandInt command, const CommandResultCallback& callback)
1274
{
1275
    {
1276
        std::lock_guard<std::mutex> lock(_components_mutex);
×
1277
        if (_target_address.system_id == 0 && _components.empty()) {
×
1278
            if (callback) {
×
1279
                callback(MavlinkCommandSender::Result::NoSystem, NAN);
×
1280
            }
1281
            return;
×
1282
        }
1283
    }
×
1284
    command.target_system_id = get_system_id();
×
1285

1286
    _command_sender.queue_command_async(command, callback);
×
1287
}
1288

1289
MavlinkCommandSender::Result
1290
SystemImpl::set_msg_rate(uint16_t message_id, double rate_hz, uint8_t component_id)
×
1291
{
1292
    MavlinkCommandSender::CommandLong command =
1293
        make_command_msg_rate(message_id, rate_hz, component_id);
×
1294
    return send_command(command);
×
1295
}
1296

1297
void SystemImpl::set_msg_rate_async(
1✔
1298
    uint16_t message_id,
1299
    double rate_hz,
1300
    const CommandResultCallback& callback,
1301
    uint8_t component_id)
1302
{
1303
    MavlinkCommandSender::CommandLong command =
1304
        make_command_msg_rate(message_id, rate_hz, component_id);
1✔
1305
    send_command_async(command, callback);
1✔
1306
}
1✔
1307

1308
MavlinkCommandSender::CommandLong
1309
SystemImpl::make_command_msg_rate(uint16_t message_id, double rate_hz, uint8_t component_id)
1✔
1310
{
1311
    MavlinkCommandSender::CommandLong command{};
1✔
1312

1313
    // 0 to request default rate, -1 to stop stream
1314

1315
    float interval_us = 0.0f;
1✔
1316

1317
    if (rate_hz > 0) {
1✔
1318
        interval_us = 1e6f / static_cast<float>(rate_hz);
1✔
1319
    } else if (rate_hz < 0) {
×
1320
        interval_us = -1.0f;
×
1321
    }
1322

1323
    command.command = MAV_CMD_SET_MESSAGE_INTERVAL;
1✔
1324
    command.params.maybe_param1 = static_cast<float>(message_id);
1✔
1325
    command.params.maybe_param2 = interval_us;
1✔
1326
    command.target_component_id = component_id;
1✔
1327

1328
    return command;
1✔
1329
}
1330

1331
void SystemImpl::register_plugin(PluginImplBase* plugin_impl)
102✔
1332
{
1333
    assert(plugin_impl);
102✔
1334

1335
    plugin_impl->init();
102✔
1336

1337
    {
1338
        std::lock_guard<std::mutex> lock(_plugin_impls_mutex);
102✔
1339
        _plugin_impls.push_back(plugin_impl);
102✔
1340
    }
102✔
1341

1342
    // If we're connected already, let's enable it straightaway.
1343
    if (_connected) {
102✔
1344
        plugin_impl->enable();
102✔
1345
    }
1346
}
102✔
1347

1348
void SystemImpl::unregister_plugin(PluginImplBase* plugin_impl)
102✔
1349
{
1350
    assert(plugin_impl);
102✔
1351

1352
    plugin_impl->disable();
102✔
1353
    plugin_impl->deinit();
102✔
1354

1355
    // Remove first, so it won't get enabled/disabled anymore.
1356
    {
1357
        std::lock_guard<std::mutex> lock(_plugin_impls_mutex);
102✔
1358
        auto found = std::find(_plugin_impls.begin(), _plugin_impls.end(), plugin_impl);
102✔
1359
        if (found != _plugin_impls.end()) {
102✔
1360
            _plugin_impls.erase(found);
102✔
1361
        }
1362
    }
102✔
1363
}
102✔
1364

1365
void SystemImpl::call_user_callback_located(
1,105✔
1366
    const std::string& filename, const int linenumber, const std::function<void()>& func)
1367
{
1368
    _mavsdk_impl.call_user_callback_located(filename, linenumber, func);
1,105✔
1369
}
1,106✔
1370

1371
void SystemImpl::param_changed(const std::string& name)
×
1372
{
1373
    // Copy the callbacks out under the lock and invoke them afterwards, so a callback
1374
    // that (un)registers a handler can't deadlock or invalidate the map.
NEW
1375
    std::vector<ParamChangedCallback> callbacks_copy;
×
1376
    {
NEW
1377
        std::lock_guard<std::mutex> lock(_param_changed_callbacks_mutex);
×
NEW
1378
        callbacks_copy.reserve(_param_changed_callbacks.size());
×
NEW
1379
        for (const auto& callback : _param_changed_callbacks) {
×
NEW
1380
            callbacks_copy.push_back(callback.second);
×
1381
        }
NEW
1382
    }
×
NEW
1383
    for (const auto& callback : callbacks_copy) {
×
NEW
1384
        callback(name);
×
1385
    }
1386
}
×
1387

1388
void SystemImpl::register_param_changed_handler(
×
1389
    const ParamChangedCallback& callback, const void* cookie)
1390
{
1391
    if (!callback) {
×
1392
        LogErr() << "No callback for param_changed_handler supplied.";
×
1393
        return;
×
1394
    }
1395

1396
    if (!cookie) {
×
1397
        LogErr() << "No callback for param_changed_handler supplied.";
×
1398
        return;
×
1399
    }
1400

NEW
1401
    std::lock_guard<std::mutex> lock(_param_changed_callbacks_mutex);
×
1402
    _param_changed_callbacks[cookie] = callback;
×
1403
}
×
1404

1405
void SystemImpl::unregister_param_changed_handler(const void* cookie)
×
1406
{
NEW
1407
    std::lock_guard<std::mutex> lock(_param_changed_callbacks_mutex);
×
1408
    auto it = _param_changed_callbacks.find(cookie);
×
1409
    if (it == _param_changed_callbacks.end()) {
×
1410
        LogWarn() << "param_changed_handler for cookie not found";
×
1411
        return;
×
1412
    }
1413
    _param_changed_callbacks.erase(it);
×
1414
}
×
1415

1416
Time& SystemImpl::get_time()
641✔
1417
{
1418
    return _mavsdk_impl.time;
641✔
1419
}
1420

1421
void SystemImpl::subscribe_param_float(
×
1422
    const std::string& name,
1423
    const MavlinkParameterClient::ParamFloatChangedCallback& callback,
1424
    const void* cookie)
1425
{
1426
    param_sender(1, false)->subscribe_param_float_changed(name, callback, cookie);
×
1427
}
×
1428

1429
void SystemImpl::subscribe_param_int(
×
1430
    const std::string& name,
1431
    const MavlinkParameterClient::ParamIntChangedCallback& callback,
1432
    const void* cookie)
1433
{
1434
    param_sender(1, false)->subscribe_param_int_changed(name, callback, cookie);
×
1435
}
×
1436
void SystemImpl::subscribe_param_custom(
×
1437
    const std::string& name,
1438
    const MavlinkParameterClient::ParamCustomChangedCallback& callback,
1439
    const void* cookie)
1440
{
1441
    param_sender(1, false)->subscribe_param_custom_changed(name, callback, cookie);
×
1442
}
×
1443

1444
MavlinkParameterClient* SystemImpl::param_sender(uint8_t component_id, bool extended)
162✔
1445
{
1446
    std::lock_guard<std::mutex> lock(_mavlink_parameter_clients_mutex);
162✔
1447

1448
    for (auto& entry : _mavlink_parameter_clients) {
164✔
1449
        if (entry.component_id == component_id && entry.extended == extended) {
150✔
1450
            return entry.parameter_client.get();
148✔
1451
        }
1452
    }
1453

1454
    _mavlink_parameter_clients.push_back(
14✔
1455
        {std::make_unique<MavlinkParameterClient>(
1456
             _mavsdk_impl.default_server_component_impl().sender(),
14✔
1457
             _mavlink_message_handler,
14✔
1458
             _mavsdk_impl.timeout_handler,
14✔
1459
             [this]() { return timeout_s(); },
90✔
1460
             [this]() { return effective_autopilot(); },
42✔
1461
             get_system_id(),
14✔
1462
             component_id,
1463
             extended),
1464
         component_id,
1465
         extended});
1466

1467
    return _mavlink_parameter_clients.back().parameter_client.get();
14✔
1468
}
162✔
1469

1470
std::vector<Connection*> SystemImpl::get_connections() const
×
1471
{
1472
    return _mavsdk_impl.get_connections();
×
1473
}
1474

1475
mav::MessageSet& SystemImpl::get_message_set() const
31✔
1476
{
1477
    return _mavsdk_impl.get_message_set();
31✔
1478
}
1479

1480
bool SystemImpl::load_custom_xml_to_message_set(const std::string& xml_content)
6✔
1481
{
1482
    return _mavsdk_impl.load_custom_xml_to_message_set(xml_content);
6✔
1483
}
1484

1485
} // 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