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

mavlink / MAVSDK / 22326225895

23 Feb 2026 09:48PM UTC coverage: 48.96% (-0.02%) from 48.982%
22326225895

push

github

web-flow
Merge pull request #2773 from jazzvaz/patch-3

Add mavsdk server docker with compose

18351 of 37482 relevant lines covered (48.96%)

670.7 hits per line

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

70.07
/cpp/src/mavsdk/core/mavlink_parameter_server.cpp
1
#include "mavlink_parameter_server.h"
2
#include "mavlink_address.h"
3
#include "mavlink_parameter_helper.h"
4
#include "overloaded.h"
5
#include <cassert>
6
#include <limits>
7

8
namespace mavsdk {
9

10
MavlinkParameterServer::MavlinkParameterServer(
149✔
11
    Sender& sender,
12
    MavlinkMessageHandler& message_handler,
13
    std::optional<std::map<std::string, ParamValue>> optional_param_values) :
149✔
14
    _sender(sender),
149✔
15
    _message_handler(message_handler)
149✔
16
{
17
    if (const char* env_p = std::getenv("MAVSDK_PARAMETER_DEBUGGING")) {
149✔
18
        if (std::string(env_p) == "1") {
×
19
            LogDebug() << "Parameter debugging is on.";
×
20
            _parameter_debugging = true;
×
21
        }
22
    }
23

24
    // Populate the parameter set before the first communication, if provided by the user.
25
    if (optional_param_values.has_value()) {
149✔
26
        const auto& param_values = optional_param_values.value();
×
27
        for (const auto& [key, value] : param_values) {
×
28
            const auto result = provide_server_param(key, value);
×
29
            if (result != Result::Ok) {
×
30
                LogDebug() << "Cannot add parameter:" << key << ":" << value << " " << result;
×
31
            }
32
        }
33
    }
34

35
    _message_handler.register_one(
149✔
36
        MAVLINK_MSG_ID_PARAM_SET,
37
        [this](const mavlink_message_t& message) { process_param_set(message); },
4✔
38
        this);
39

40
    _message_handler.register_one(
149✔
41
        MAVLINK_MSG_ID_PARAM_EXT_SET,
42
        [this](const mavlink_message_t& message) { process_param_ext_set(message); },
5✔
43
        this);
44

45
    _message_handler.register_one(
149✔
46
        MAVLINK_MSG_ID_PARAM_REQUEST_READ,
47
        [this](const mavlink_message_t& message) { process_param_request_read(message); },
22✔
48
        this);
49

50
    _message_handler.register_one(
149✔
51
        MAVLINK_MSG_ID_PARAM_REQUEST_LIST,
52
        [this](const mavlink_message_t& message) { process_param_request_list(message); },
3✔
53
        this);
54

55
    _message_handler.register_one(
149✔
56
        MAVLINK_MSG_ID_PARAM_EXT_REQUEST_READ,
57
        [this](const mavlink_message_t& message) { process_param_ext_request_read(message); },
39✔
58
        this);
59

60
    _message_handler.register_one(
149✔
61
        MAVLINK_MSG_ID_PARAM_EXT_REQUEST_LIST,
62
        [this](const mavlink_message_t& message) { process_param_ext_request_list(message); },
2✔
63
        this);
64
}
149✔
65

66
MavlinkParameterServer::~MavlinkParameterServer()
149✔
67
{
68
    _message_handler.unregister_all(this);
149✔
69
}
149✔
70

71
MavlinkParameterServer::Result
72
MavlinkParameterServer::provide_server_param(const std::string& name, const ParamValue& param_value)
71✔
73
{
74
    if (name.size() > PARAM_ID_LEN) {
71✔
75
        LogErr() << "Error: param name too long";
×
76
        return Result::ParamNameTooLong;
×
77
    }
78
    if (param_value.is<std::string>()) {
71✔
79
        const auto s = param_value.get<std::string>();
8✔
80
        if (s.size() > sizeof(mavlink_param_ext_set_t::param_value)) {
8✔
81
            LogErr() << "Error: param value too long";
×
82
            return Result::ParamValueTooLong;
×
83
        }
84
    }
8✔
85
    std::lock_guard<std::mutex> lock(_all_params_mutex);
71✔
86
    // first we try to add it as a new parameter
87
    switch (_param_cache.add_new_param(name, param_value)) {
71✔
88
        case MavlinkParameterCache::AddNewParamResult::Ok:
54✔
89
            return Result::Ok;
54✔
90
        case MavlinkParameterCache::AddNewParamResult::AlreadyExists:
17✔
91
            // then, to not change the public api behaviour, try updating its value.
92
            switch (_param_cache.update_existing_param(name, param_value)) {
17✔
93
                case MavlinkParameterCache::UpdateExistingParamResult::Ok:
17✔
94
                    find_and_call_subscriptions_value_changed(name, param_value);
17✔
95
                    {
96
                        auto new_work = std::make_shared<WorkItem>(
97
                            name,
98
                            param_value,
99
                            WorkItemValue{
34✔
100
                                std::numeric_limits<std::uint16_t>::max(),
101
                                std::numeric_limits<std::uint16_t>::max(),
102
                                _last_extended});
17✔
103
                        _work_queue.push_back(new_work);
17✔
104
                    }
17✔
105
                    return Result::OkExistsAlready;
17✔
106
                case MavlinkParameterCache::UpdateExistingParamResult::MissingParam:
×
107
                    return Result::ParamNotFound;
×
108
                case MavlinkParameterCache::UpdateExistingParamResult::WrongType:
×
109
                    return Result::WrongType;
×
110
                default:
×
111
                    LogErr() << "Unknown update_existing_param result";
×
112
                    assert(false);
×
113
                    return Result::Unknown;
114
            }
115
        case MavlinkParameterCache::AddNewParamResult::TooManyParams:
×
116
            return Result::TooManyParams;
×
117
        default:
×
118
            LogErr() << "Unknown add_new_param result";
×
119
            assert(false);
×
120
            return Result::Unknown;
121
    }
122
}
71✔
123

124
MavlinkParameterServer::Result
125
MavlinkParameterServer::provide_server_param_float(const std::string& name, float value)
11✔
126
{
127
    ParamValue param_value;
11✔
128
    param_value.set(value);
11✔
129
    return provide_server_param(name, param_value);
11✔
130
}
11✔
131

132
MavlinkParameterServer::Result
133
MavlinkParameterServer::provide_server_param_int(const std::string& name, int32_t value)
52✔
134
{
135
    ParamValue param_value;
52✔
136
    param_value.set(value);
52✔
137
    return provide_server_param(name, param_value);
52✔
138
}
52✔
139

140
MavlinkParameterServer::Result MavlinkParameterServer::provide_server_param_custom(
8✔
141
    const std::string& name, const std::string& value)
142
{
143
    ParamValue param_value;
8✔
144
    param_value.set(value);
8✔
145
    return provide_server_param(name, param_value);
8✔
146
}
8✔
147

148
std::map<std::string, ParamValue> MavlinkParameterServer::retrieve_all_server_params()
2✔
149
{
150
    std::lock_guard<std::mutex> lock(_all_params_mutex);
2✔
151
    std::map<std::string, ParamValue> map_copy;
2✔
152
    for (auto entry : _param_cache.all_parameters(true)) {
6✔
153
        map_copy[entry.id] = entry.value;
4✔
154
    }
6✔
155
    return map_copy;
2✔
156
}
2✔
157

158
template<class T>
159
std::pair<MavlinkParameterServer::Result, T>
160
MavlinkParameterServer::retrieve_server_param(const std::string& name)
6✔
161
{
162
    std::lock_guard<std::mutex> lock(_all_params_mutex);
6✔
163
    const auto param_opt = _param_cache.param_by_id(name, true);
6✔
164
    if (!param_opt.has_value()) {
6✔
165
        return {Result::NotFound, {}};
×
166
    }
167
    // This parameter exists, check its type
168
    const auto& param = param_opt.value();
6✔
169
    if (param.value.is<T>()) {
6✔
170
        return {Result::Ok, param.value.get<T>()};
6✔
171
    }
172
    return {Result::WrongType, {}};
×
173
}
6✔
174

175
std::pair<MavlinkParameterServer::Result, float>
176
MavlinkParameterServer::retrieve_server_param_float(const std::string& name)
2✔
177
{
178
    return retrieve_server_param<float>(name);
2✔
179
}
180

181
std::pair<MavlinkParameterServer::Result, std::string>
182
MavlinkParameterServer::retrieve_server_param_custom(const std::string& name)
2✔
183
{
184
    return retrieve_server_param<std::string>(name);
2✔
185
}
186

187
std::pair<MavlinkParameterServer::Result, int32_t>
188
MavlinkParameterServer::retrieve_server_param_int(const std::string& name)
2✔
189
{
190
    return retrieve_server_param<int32_t>(name);
2✔
191
}
192

193
void MavlinkParameterServer::process_param_set_internally(
9✔
194
    const std::string& param_id, const ParamValue& value_to_set, bool extended)
195
{
196
    if (_parameter_debugging) {
9✔
197
        LogDebug() << "Param set request" << (extended ? " extended" : "") << ": " << param_id
×
198
                   << " with " << value_to_set;
×
199
    }
200

201
    std::string error_param_id;
9✔
202
    int16_t error_param_index = -1;
9✔
203
    uint8_t error_code = 0;
9✔
204
    bool send_error = false;
9✔
205

206
    {
207
        std::lock_guard<std::mutex> lock(_all_params_mutex);
9✔
208
        // for checking if the update actually changed the value
209
        const auto opt_before_update = _param_cache.param_by_id(param_id, extended);
9✔
210
        const auto result = _param_cache.update_existing_param(param_id, value_to_set);
9✔
211
        const auto param_count = _param_cache.count(extended);
9✔
212

213
        switch (result) {
9✔
214
            case MavlinkParameterCache::UpdateExistingParamResult::MissingParam: {
×
215
                // We do not allow clients to add a new parameter to the parameter set, only to
216
                // update existing parameters. Send PARAM_ERROR for standard protocol.
217
                LogErr() << "Got param_set for non-existing parameter:" << param_id;
×
218

219
                if (!extended) {
×
220
                    // Prepare to send PARAM_ERROR outside the lock
221
                    error_param_id = param_id;
×
222
                    error_param_index = -1;
×
223
                    error_code = 1; // MAV_PARAM_ERROR_DOES_NOT_EXIST
×
224
                    send_error = true;
×
225
                }
226
                return;
×
227
            }
228
            case MavlinkParameterCache::UpdateExistingParamResult::WrongType: {
×
229
                // Non-extended: send PARAM_ERROR with TYPE_MISMATCH
230
                // Extended: we nack with failed.
231

232
                LogErr() << "Got param_set with wrong type for parameter: " << param_id;
×
233

234
                const auto curr_param = _param_cache.param_by_id(param_id, extended).value();
×
235

236
                if (extended) {
×
237
                    auto new_work = std::make_shared<WorkItem>(
238
                        curr_param.id, curr_param.value, WorkItemAck{PARAM_ACK_FAILED});
×
239
                    _work_queue.push_back(new_work);
×
240

241
                } else {
×
242
                    // Prepare to send PARAM_ERROR outside the lock
243
                    error_param_id = curr_param.id;
×
244
                    error_param_index = static_cast<int16_t>(curr_param.index);
×
245
                    error_code = 7; // MAV_PARAM_ERROR_TYPE_MISMATCH
×
246
                    send_error = true;
×
247
                }
248
                return;
×
249
            }
×
250
            case MavlinkParameterCache::UpdateExistingParamResult::Ok: {
9✔
251
                LogWarn() << "Update existing params!";
9✔
252
                const auto updated_parameter = _param_cache.param_by_id(param_id, extended).value();
9✔
253
                // The param set doesn't differentiate between an update that actually changed the
254
                // value e.g. 0 to 1 and an update that had no effect e.g. 0 to 0.
255
                if (opt_before_update.has_value() &&
18✔
256
                    opt_before_update.value().value == updated_parameter.value) {
9✔
257
                    LogDebug() << "Update had no effect: " << updated_parameter.value;
×
258
                } else {
259
                    LogDebug() << "Updated param to :" << updated_parameter.value;
9✔
260
                    find_and_call_subscriptions_value_changed(
9✔
261
                        updated_parameter.id, updated_parameter.value);
262
                }
263
                if (extended) {
9✔
264
                    auto new_work = std::make_shared<WorkItem>(
265
                        updated_parameter.id,
266
                        updated_parameter.value,
267
                        WorkItemAck{PARAM_ACK_ACCEPTED});
5✔
268
                    _work_queue.push_back(new_work);
5✔
269
                } else {
5✔
270
                    auto new_work = std::make_shared<WorkItem>(
271
                        updated_parameter.id,
272
                        updated_parameter.value,
273
                        WorkItemValue{updated_parameter.index, param_count, extended});
4✔
274
                    _work_queue.push_back(new_work);
4✔
275
                }
4✔
276
            } break;
9✔
277
        }
278
    }
9✔
279

280
    // Send PARAM_ERROR outside the lock if needed
281
    if (send_error) {
9✔
282
        send_param_error(error_param_id, error_param_index, error_code);
×
283
    }
284
}
9✔
285

286
void MavlinkParameterServer::process_param_set(const mavlink_message_t& message)
4✔
287
{
288
    mavlink_param_set_t set_request{};
4✔
289
    mavlink_msg_param_set_decode(&message, &set_request);
4✔
290
    if (!target_matches(set_request.target_system, set_request.target_component, false)) {
4✔
291
        log_target_mismatch(set_request.target_system, set_request.target_component);
×
292
        return;
×
293
    }
294
    const std::string safe_param_id = extract_safe_param_id(set_request.param_id);
4✔
295

296
    if (safe_param_id.empty()) {
4✔
297
        LogWarn() << "Got ill-formed param_set message (param_id empty)";
×
298
        return;
×
299
    }
300

301
    ParamValue value_to_set;
4✔
302
    if (!value_to_set.set_from_mavlink_param_set_bytewise(set_request)) {
4✔
303
        // This should never happen, the type enum in the message is unknown.
304
        LogWarn() << "Invalid Param Set Request: " << safe_param_id;
×
305
        return;
×
306
    }
307
    process_param_set_internally(safe_param_id, value_to_set, false);
4✔
308
}
4✔
309

310
void MavlinkParameterServer::process_param_ext_set(const mavlink_message_t& message)
5✔
311
{
312
    mavlink_param_ext_set_t set_request{};
5✔
313
    mavlink_msg_param_ext_set_decode(&message, &set_request);
5✔
314
    if (!target_matches(set_request.target_system, set_request.target_component, false)) {
5✔
315
        log_target_mismatch(set_request.target_system, set_request.target_component);
×
316
        return;
×
317
    }
318
    const std::string safe_param_id = extract_safe_param_id(set_request.param_id);
5✔
319

320
    if (safe_param_id.empty()) {
5✔
321
        LogWarn() << "Got ill-formed param_ext_set message (param_id empty)";
×
322
        return;
×
323
    }
324

325
    ParamValue value_to_set;
5✔
326
    if (!value_to_set.set_from_mavlink_param_ext_set(set_request)) {
5✔
327
        // This should never happen, the type enum in the message is unknown.
328
        LogWarn() << "Invalid Param Set ext Request: " << safe_param_id;
×
329
        return;
×
330
    }
331

332
    process_param_set_internally(safe_param_id, value_to_set, true);
5✔
333
}
5✔
334

335
void MavlinkParameterServer::process_param_request_read(const mavlink_message_t& message)
22✔
336
{
337
    if (_parameter_debugging) {
22✔
338
        LogDebug() << "process param_request_read";
×
339
    }
340
    mavlink_param_request_read_t read_request{};
22✔
341
    mavlink_msg_param_request_read_decode(&message, &read_request);
22✔
342
    if (!target_matches(read_request.target_system, read_request.target_component, true)) {
22✔
343
        log_target_mismatch(read_request.target_system, read_request.target_component);
×
344
        return;
×
345
    }
346

347
    const auto param_id_or_index =
348
        extract_request_read_param_identifier(read_request.param_index, read_request.param_id);
22✔
349

350
    std::visit(
22✔
351
        overloaded{
22✔
352
            [&](std::monostate) { LogWarn() << "Ill-formed param_request_read message"; },
×
353
            [&](std::uint16_t index) {
1✔
354
                if (_parameter_debugging) {
1✔
355
                    LogDebug() << "found index: " << index;
×
356
                }
357
                internal_process_param_request_read_by_index(index, false);
1✔
358
            },
1✔
359
            [&](const std::string& id) {
21✔
360
                if (_parameter_debugging) {
21✔
361
                    LogDebug() << "found id: " << id;
×
362
                }
363
                internal_process_param_request_read_by_id(id, false);
21✔
364
            }},
21✔
365
        param_id_or_index);
366
}
22✔
367

368
void MavlinkParameterServer::process_param_ext_request_read(const mavlink_message_t& message)
39✔
369
{
370
    mavlink_param_ext_request_read_t read_request{};
39✔
371
    mavlink_msg_param_ext_request_read_decode(&message, &read_request);
39✔
372
    if (!target_matches(read_request.target_system, read_request.target_component, true)) {
39✔
373
        log_target_mismatch(read_request.target_system, read_request.target_component);
×
374
        return;
×
375
    }
376
    const auto param_id_or_index =
377
        extract_request_read_param_identifier(read_request.param_index, read_request.param_id);
39✔
378

379
    std::visit(
39✔
380
        overloaded{
39✔
381
            [&](std::monostate) { LogWarn() << "Ill-formed param_request_read message"; },
×
382
            [&](std::uint16_t index) {
2✔
383
                if (_parameter_debugging) {
2✔
384
                    LogDebug() << "found index: " << index;
×
385
                }
386
                internal_process_param_request_read_by_index(index, true);
2✔
387
            },
2✔
388
            [&](const std::string& id) {
37✔
389
                if (_parameter_debugging) {
37✔
390
                    LogDebug() << "found id: " << id;
×
391
                }
392
                internal_process_param_request_read_by_id(id, true);
37✔
393
            }},
37✔
394
        param_id_or_index);
395
}
39✔
396

397
void MavlinkParameterServer::internal_process_param_request_read_by_id(
58✔
398
    const std::string& id, const bool extended)
399
{
400
    {
401
        std::lock_guard<std::mutex> lock(_all_params_mutex);
58✔
402
        const auto param_opt = _param_cache.param_by_id(id, extended);
58✔
403

404
        if (!param_opt.has_value()) {
58✔
405
            LogWarn() << "Ignoring request_read message " << (extended ? "extended " : "")
8✔
406
                      << "- param name not found: " << id;
4✔
407
            // Release lock before sending PARAM_ERROR
408
        } else {
409
            const auto& param = param_opt.value();
54✔
410
            const auto param_count = _param_cache.count(extended);
54✔
411
            assert(param.index < param_count);
54✔
412
            auto new_work = std::make_shared<WorkItem>(
413
                param.id, param.value, WorkItemValue{param.index, param_count, extended});
54✔
414
            _work_queue.push_back(new_work);
54✔
415

416
            _last_extended = extended;
54✔
417
            return;
54✔
418
        }
54✔
419
    }
112✔
420

421
    // Send PARAM_ERROR outside the lock
422
    if (!extended) {
4✔
423
        send_param_error(id, -1, 1); // MAV_PARAM_ERROR_DOES_NOT_EXIST = 1
4✔
424
    }
425
}
426

427
void MavlinkParameterServer::internal_process_param_request_read_by_index(
3✔
428
    std::uint16_t index, bool extended)
429
{
430
    {
431
        std::lock_guard<std::mutex> lock(_all_params_mutex);
3✔
432
        const auto param_opt = _param_cache.param_by_index(index, extended);
3✔
433

434
        if (!param_opt.has_value()) {
3✔
435
            LogWarn() << "Ignoring request_read message " << (extended ? "extended " : "")
×
436
                      << "- param index not found: " << index;
×
437
            // Release lock before sending PARAM_ERROR
438
        } else {
439
            const auto& param = param_opt.value();
3✔
440
            const auto param_count = _param_cache.count(extended);
3✔
441

442
            assert(param.index < param_count);
3✔
443
            auto new_work = std::make_shared<WorkItem>(
444
                param.id, param.value, WorkItemValue{param.index, param_count, extended});
3✔
445
            _work_queue.push_back(new_work);
3✔
446
            return;
3✔
447
        }
3✔
448
    }
6✔
449

450
    // Send PARAM_ERROR outside the lock
451
    if (!extended) {
×
452
        send_param_error("", static_cast<int16_t>(index), 1); // MAV_PARAM_ERROR_DOES_NOT_EXIST = 1
×
453
    }
454
}
455

456
void MavlinkParameterServer::process_param_request_list(const mavlink_message_t& message)
3✔
457
{
458
    mavlink_param_request_list_t list_request{};
3✔
459
    mavlink_msg_param_request_list_decode(&message, &list_request);
3✔
460
    if (!target_matches(list_request.target_system, list_request.target_component, true)) {
3✔
461
        log_target_mismatch(list_request.target_system, list_request.target_component);
×
462
        return;
×
463
    }
464
    broadcast_all_parameters(false);
3✔
465
}
466

467
void MavlinkParameterServer::process_param_ext_request_list(const mavlink_message_t& message)
2✔
468
{
469
    if (_parameter_debugging) {
2✔
470
        LogDebug() << "process param_ext_request_list";
×
471
    }
472

473
    mavlink_param_ext_request_list_t ext_list_request{};
2✔
474
    mavlink_msg_param_ext_request_list_decode(&message, &ext_list_request);
2✔
475
    if (!target_matches(ext_list_request.target_system, ext_list_request.target_component, true)) {
2✔
476
        log_target_mismatch(ext_list_request.target_system, ext_list_request.target_component);
×
477
        return;
×
478
    }
479
    broadcast_all_parameters(true);
2✔
480
}
481

482
void MavlinkParameterServer::broadcast_all_parameters(const bool extended)
5✔
483
{
484
    std::lock_guard<std::mutex> lock(_all_params_mutex);
5✔
485

486
    // Param used with index, we should no longer change the index
487
    _params_locked_down = true;
5✔
488

489
    const auto all_params = _param_cache.all_parameters(extended);
5✔
490
    if (_parameter_debugging) {
5✔
491
        LogDebug() << "broadcast_all_parameters " << (extended ? "extended" : "") << ": "
×
492
                   << all_params.size();
×
493
    }
494
    for (const auto& parameter : all_params) {
37✔
495
        if (_parameter_debugging) {
32✔
496
            LogDebug() << "sending param:" << parameter.id;
×
497
        }
498
        auto new_work = std::make_shared<WorkItem>(
499
            parameter.id,
32✔
500
            parameter.value,
32✔
501
            WorkItemValue{parameter.index, static_cast<uint16_t>(all_params.size()), extended});
32✔
502
        _work_queue.push_back(new_work);
32✔
503
    }
32✔
504
}
5✔
505

506
void MavlinkParameterServer::do_work()
40,318✔
507
{
508
    LockedQueue<WorkItem>::Guard work_queue_guard(_work_queue);
40,318✔
509
    auto work = work_queue_guard.get_front();
41,391✔
510
    if (!work) {
40,545✔
511
        return;
40,155✔
512
    }
513
    const auto param_id_message_buffer = param_id_to_message_buffer(work->param_id);
115✔
514

515
    std::visit(
115✔
516
        overloaded{
230✔
517
            [&](const WorkItemValue& specific) {
110✔
518
                if (specific.extended) {
110✔
519
                    const auto buf = work->param_value.get_128_bytes();
72✔
520
                    if (!_sender.queue_message(
72✔
521
                            [&](MavlinkAddress mavlink_address, uint8_t channel) {
72✔
522
                                mavlink_message_t message;
523
                                mavlink_msg_param_ext_value_pack_chan(
288✔
524
                                    mavlink_address.system_id,
72✔
525
                                    mavlink_address.component_id,
72✔
526
                                    channel,
527
                                    &message,
528
                                    param_id_message_buffer.data(),
144✔
529
                                    buf.data(),
72✔
530
                                    work->param_value.get_mav_param_ext_type(),
72✔
531
                                    specific.param_count,
72✔
532
                                    specific.param_index);
72✔
533
                                return message;
72✔
534
                            })) {
535
                        LogErr() << "Error: Send message failed";
×
536
                        work_queue_guard.pop_front();
×
537
                        return;
×
538
                    }
539
                } else {
540
                    LogWarn() << "sending not extended message";
38✔
541
                    float param_value;
542
                    if (_sender.compatibility_mode() == CompatibilityMode::ArduPilot) {
38✔
543
                        param_value = work->param_value.get_4_float_bytes_cast();
×
544
                    } else {
545
                        param_value = work->param_value.get_4_float_bytes_bytewise();
38✔
546
                    }
547
                    if (!_sender.queue_message(
38✔
548
                            [&](MavlinkAddress mavlink_address, uint8_t channel) {
38✔
549
                                mavlink_message_t message;
550
                                mavlink_msg_param_value_pack_chan(
114✔
551
                                    mavlink_address.system_id,
38✔
552
                                    mavlink_address.component_id,
38✔
553
                                    channel,
554
                                    &message,
555
                                    param_id_message_buffer.data(),
38✔
556
                                    param_value,
38✔
557
                                    work->param_value.get_mav_param_type(),
38✔
558
                                    specific.param_count,
38✔
559
                                    specific.param_index);
38✔
560
                                return message;
38✔
561
                            })) {
562
                        LogErr() << "Error: Send message failed";
×
563
                        work_queue_guard.pop_front();
×
564
                        return;
×
565
                    }
566
                }
567
                work_queue_guard.pop_front();
110✔
568
            },
569
            [&](const WorkItemAck& specific) {
5✔
570
                auto buf = work->param_value.get_128_bytes();
5✔
571
                if (!_sender.queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
5✔
572
                        mavlink_message_t message;
573
                        mavlink_msg_param_ext_ack_pack_chan(
20✔
574
                            mavlink_address.system_id,
5✔
575
                            mavlink_address.component_id,
5✔
576
                            channel,
577
                            &message,
578
                            param_id_message_buffer.data(),
10✔
579
                            buf.data(),
5✔
580
                            work->param_value.get_mav_param_ext_type(),
5✔
581
                            specific.param_ack);
5✔
582
                        return message;
5✔
583
                    })) {
584
                    LogErr() << "Error: Send message failed";
×
585
                    work_queue_guard.pop_front();
×
586
                    return;
×
587
                }
588
                work_queue_guard.pop_front();
5✔
589
            }},
590
        work->work_item_variant);
115✔
591
}
80,440✔
592

593
void MavlinkParameterServer::send_param_error(
4✔
594
    const std::string& param_id, int16_t param_index, uint8_t error_code)
595
{
596
    if (_parameter_debugging) {
4✔
597
        LogDebug() << "Sending PARAM_ERROR for " << param_id << " (index: " << param_index
×
598
                   << ") with error code: " << (int)error_code;
×
599
    }
600

601
    const auto param_id_buffer = param_id_to_message_buffer(param_id);
4✔
602

603
    if (!_sender.queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
4✔
604
            mavlink_message_t message;
605
            mavlink_msg_param_error_pack_chan(
8✔
606
                mavlink_address.system_id,
4✔
607
                mavlink_address.component_id,
4✔
608
                channel,
609
                &message,
610
                0, // target_system - 0 for broadcast
611
                0, // target_component - 0 for broadcast
612
                param_id_buffer.data(),
4✔
613
                param_index,
4✔
614
                error_code);
4✔
615
            return message;
4✔
616
        })) {
617
        LogErr() << "Error: Send PARAM_ERROR message failed";
×
618
    }
619
}
4✔
620

621
std::ostream& operator<<(std::ostream& str, const MavlinkParameterServer::Result& result)
×
622
{
623
    switch (result) {
×
624
        case MavlinkParameterServer::Result::Ok:
×
625
            return str << "Ok";
×
626
        case MavlinkParameterServer::Result::OkExistsAlready:
×
627
            return str << "OkExistsAlready";
×
628
        case MavlinkParameterServer::Result::WrongType:
×
629
            return str << "WrongType";
×
630
        case MavlinkParameterServer::Result::ParamNameTooLong:
×
631
            return str << "ParamNameTooLong";
×
632
        case MavlinkParameterServer::Result::NotFound:
×
633
            return str << "NotFound";
×
634
        case MavlinkParameterServer::Result::ParamValueTooLong:
×
635
            return str << ":ParamValueTooLong";
×
636
        default:
×
637
            return str << "UnknownError";
×
638
    }
639
}
640

641
bool MavlinkParameterServer::target_matches(
75✔
642
    const uint16_t target_sys_id, const uint16_t target_comp_id, bool is_request)
643
{
644
    // See: https://mavlink.io/en/services/parameter.html#multi-system-and-multi-component-support
645

646
    if (target_sys_id != _sender.get_own_system_id()) {
75✔
647
        return false;
×
648
    }
649
    if (is_request) {
75✔
650
        return target_comp_id == _sender.get_own_component_id() ||
66✔
651
               target_comp_id == MAV_COMP_ID_ALL;
66✔
652
    }
653
    return target_comp_id == _sender.get_own_component_id();
9✔
654
}
655

656
void MavlinkParameterServer::log_target_mismatch(uint16_t target_sys_id, uint16_t target_comp_id)
×
657
{
658
    if (!_parameter_debugging) {
×
659
        return;
×
660
    }
661

662
    LogDebug() << "Ignoring message - wrong target id. Got:" << (int)target_sys_id << ":"
×
663
               << (int)target_comp_id << " Wanted:" << (int)_sender.get_own_system_id() << ":"
×
664
               << (int)_sender.get_own_component_id();
×
665
}
666

667
std::variant<std::monostate, std::string, std::uint16_t>
668
MavlinkParameterServer::extract_request_read_param_identifier(
61✔
669
    int16_t param_index, const char* param_id)
670
{
671
    // Helper for safely handling a request_read or ext_request_read message (which have the exact
672
    // same layout). returns the identifier that should be used or nothing if the message is
673
    // ill-formed. See https://mavlink.io/en/messages/common.html#PARAM_REQUEST_READ and
674
    // https://mavlink.io/en/messages/common.html#PARAM_EXT_REQUEST_READ
675

676
    if (param_index == -1) {
61✔
677
        // use param_id if index == -1
678
        const auto safe_param_id = extract_safe_param_id(param_id);
58✔
679
        if (safe_param_id.empty()) {
58✔
680
            LogErr() << "Message with param_index=-1 but no empty param id";
×
681
            return std::monostate{};
×
682
        }
683
        return {safe_param_id};
58✔
684
    } else {
58✔
685
        // if index is not -1, it should be a valid parameter index (>=0)
686
        if (param_index < 0) {
3✔
687
            LogErr() << "Param_index " << param_index << " is not a valid param index";
×
688
            return std::monostate{};
×
689
        }
690
        return {static_cast<std::uint16_t>(param_index)};
3✔
691
    }
692
}
693

694
bool MavlinkParameterServer::params_locked_down() const
64✔
695
{
696
    std::lock_guard<std::mutex> lock(_all_params_mutex);
64✔
697

698
    return _params_locked_down;
128✔
699
}
64✔
700

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