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

mavlink / MAVSDK / 11962955425

21 Nov 2024 10:45PM UTC coverage: 43.573% (+4.9%) from 38.691%
11962955425

Pull #2386

github

web-flow
Merge b41070aab into c963c5161
Pull Request #2386: camera: support multiple cameras within one instance

1353 of 2024 new or added lines in 47 files covered. (66.85%)

47 existing lines in 7 files now uncovered.

13858 of 31804 relevant lines covered (43.57%)

289.11 hits per line

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

58.2
/src/mavsdk/core/mavlink_parameter_client.cpp
1
#include "mavlink_parameter_helper.h"
2
#include "mavlink_parameter_client.h"
3
#include "mavlink_message_handler.h"
4
#include "system_impl.h"
5
#include "plugin_base.h"
6
#include <algorithm>
7
#include <future>
8
#include <utility>
9

10
namespace mavsdk {
11

12
MavlinkParameterClient::MavlinkParameterClient(
10✔
13
    Sender& sender,
14
    MavlinkMessageHandler& message_handler,
15
    TimeoutHandler& timeout_handler,
16
    TimeoutSCallback timeout_s_callback,
17
    AutopilotCallback autopilot_callback,
18
    uint8_t target_system_id,
19
    uint8_t target_component_id,
20
    bool use_extended) :
10✔
21
    _sender(sender),
10✔
22
    _message_handler(message_handler),
10✔
23
    _timeout_handler(timeout_handler),
10✔
24
    _timeout_s_callback(std::move(timeout_s_callback)),
10✔
25
    _autopilot_callback(std::move(autopilot_callback)),
10✔
26
    _target_system_id(target_system_id),
10✔
27
    _target_component_id(target_component_id),
10✔
28
    _use_extended(use_extended)
20✔
29
{
30
    if (const char* env_p = std::getenv("MAVSDK_PARAMETER_DEBUGGING")) {
10✔
31
        if (std::string(env_p) == "1") {
×
32
            LogDebug() << "Parameter debugging is on.";
×
33
            _parameter_debugging = true;
×
34
        }
35
    }
36

37
    if (_parameter_debugging) {
10✔
38
        LogDebug() << "MavlinkParameterClient created for target compid: "
×
39
                   << (int)_target_component_id << " and "
×
40
                   << (_use_extended ? "extended" : "not extended");
×
41
    }
42

43
    if (_use_extended) {
10✔
44
        _message_handler.register_one(
6✔
45
            MAVLINK_MSG_ID_PARAM_EXT_VALUE,
46
            [this](const mavlink_message_t& message) { process_param_ext_value(message); },
61✔
47
            this);
48

49
        _message_handler.register_one(
6✔
50
            MAVLINK_MSG_ID_PARAM_EXT_ACK,
51
            [this](const mavlink_message_t& message) { process_param_ext_ack(message); },
5✔
52
            this);
53
    } else {
54
        _message_handler.register_one(
4✔
55
            MAVLINK_MSG_ID_PARAM_VALUE,
56
            [this](const mavlink_message_t& message) { process_param_value(message); },
26✔
57
            this);
58
    }
59
}
10✔
60

61
MavlinkParameterClient::~MavlinkParameterClient()
10✔
62
{
63
    if (_parameter_debugging) {
10✔
64
        LogDebug() << "MavlinkParameterClient destructed for target compid: "
×
65
                   << (int)_target_component_id << " and "
×
66
                   << (_use_extended ? "extended" : "not extended");
×
67
    }
68

69
    _message_handler.unregister_all(this);
10✔
70
}
10✔
71

72
MavlinkParameterClient::Result
73
MavlinkParameterClient::set_param(const std::string& name, const ParamValue& value)
×
74
{
75
    auto prom = std::promise<Result>();
×
76
    auto res = prom.get_future();
×
77
    set_param_async(name, value, [&prom](Result result) { prom.set_value(result); }, this);
×
78
    return res.get();
×
79
}
×
80

81
void MavlinkParameterClient::set_param_async(
9✔
82
    const std::string& name,
83
    const ParamValue& value,
84
    const SetParamCallback& callback,
85
    const void* cookie)
86
{
87
    if (name.size() > PARAM_ID_LEN) {
9✔
88
        LogErr() << "Param name too long";
×
89
        if (callback) {
×
90
            callback(Result::ParamNameTooLong);
×
91
        }
92
        return;
×
93
    }
94
    if (value.is<std::string>() && !_use_extended) {
9✔
95
        LogErr() << "String needs extended parameter protocol";
×
96
        if (callback) {
×
97
            callback(Result::StringTypeUnsupported);
×
98
        }
99
        return;
×
100
    }
101
    auto new_work = std::make_shared<WorkItem>(WorkItemSet{name, value, callback}, cookie);
18✔
102
    _work_queue.push_back(new_work);
9✔
103
}
9✔
104

105
void MavlinkParameterClient::set_param_int_async(
2✔
106
    const std::string& name, int32_t value, const SetParamCallback& callback, const void* cookie)
107
{
108
    if (name.size() > PARAM_ID_LEN) {
2✔
109
        LogErr() << "Param name too long";
×
110
        if (callback) {
×
111
            callback(Result::ParamNameTooLong);
×
112
        }
113
        return;
×
114
    }
115

116
    // PX4 only uses int32_t, so we can be sure and don't need to check the exact type first
117
    // by getting the param, or checking the cache.
118
    if (_autopilot_callback() == Autopilot::Px4) {
2✔
119
        ParamValue value_to_set;
×
120
        value_to_set.set(static_cast<int32_t>(value));
×
121
        set_param_async(name, value_to_set, callback, cookie);
×
122
    } else {
×
123
        // We don't know which exact int type the server wants, so we have to get the param
124
        // first to see the type before setting it.
125
        auto param_opt = _param_cache.param_by_id(name, false);
2✔
126
        if (param_opt.has_value()) {
2✔
127
            // we have the parameter cached
128
            auto param = param_opt.value();
×
129
            if (param.value.set_int(value)) {
×
130
                // we have successfully written whatever int the user provided into the int type
131
                // that is actually stored
132
                set_param_async(name, param.value, callback, cookie);
×
133
            } else {
134
                // We didn't find compatibility and give up.
135
                LogErr() << "Wrong type for int in cache";
×
136
                if (callback) {
×
137
                    callback(Result::WrongType);
×
138
                }
139
                return;
×
140
            }
141
        } else {
×
142
            // parameter is not cached. Request it and then perform the appropriate action once we
143
            // know it
144
            auto send_message_once_type_is_known = [this, name, value, callback, cookie](
2✔
145
                                                       Result result,
146
                                                       ParamValue fetched_param_value) {
4✔
147
                if (result == Result::Success) {
2✔
148
                    if (fetched_param_value.set_int(value)) {
2✔
149
                        // Since the callback itself is called with the work queue locked, we have
150
                        // to make sure that the work queue guard is removed before we call the
151
                        // finalizing callback of a work item.
152
                        set_param_async(name, fetched_param_value, callback, cookie);
2✔
153
                    } else {
154
                        // The param type returned does is not compatible with an int, give up.
155
                        LogErr() << "Wrong type for int returned";
×
156
                        if (callback) {
×
157
                            callback(Result::WrongType);
×
158
                        }
159
                    }
160
                } else {
161
                    // Failed to get the param to get the type, pass on the error.
162
                    callback(result);
×
163
                }
164
            };
2✔
165
            get_param_async(name, send_message_once_type_is_known, cookie);
2✔
166
        }
2✔
167
    }
2✔
168
}
169

170
MavlinkParameterClient::Result
171
MavlinkParameterClient::set_param_int(const std::string& name, int32_t value)
2✔
172
{
173
    auto prom = std::promise<Result>();
2✔
174
    auto res = prom.get_future();
2✔
175
    set_param_int_async(name, value, [&prom](Result result) { prom.set_value(result); }, this);
4✔
176
    return res.get();
2✔
177
}
2✔
178

179
void MavlinkParameterClient::set_param_float_async(
2✔
180
    const std::string& name, float value, const SetParamCallback& callback, const void* cookie)
181
{
182
    ParamValue value_to_set;
2✔
183
    value_to_set.set_float(value);
2✔
184
    set_param_async(name, value_to_set, callback, cookie);
2✔
185
}
2✔
186

187
MavlinkParameterClient::Result
188
MavlinkParameterClient::set_param_float(const std::string& name, float value)
2✔
189
{
190
    auto prom = std::promise<Result>();
2✔
191
    auto res = prom.get_future();
2✔
192

193
    set_param_float_async(name, value, [&prom](Result result) { prom.set_value(result); }, this);
4✔
194

195
    return res.get();
2✔
196
}
2✔
197

198
void MavlinkParameterClient::set_param_custom_async(
2✔
199
    const std::string& name,
200
    const std::string& value,
201
    const SetParamCallback& callback,
202
    const void* cookie)
203
{
204
    if (name.size() > PARAM_ID_LEN) {
2✔
205
        LogErr() << "Param name too long";
×
206
        if (callback) {
×
207
            callback(Result::ParamNameTooLong);
×
208
        }
209
        return;
×
210
    }
211

212
    if (value.size() > sizeof(mavlink_param_ext_set_t::param_value)) {
2✔
213
        LogErr() << "Param value too long";
×
214
        if (callback) {
×
215
            callback(Result::ParamValueTooLong);
×
216
        }
217
        return;
×
218
    }
219
    ParamValue value_to_set;
2✔
220
    value_to_set.set_custom(value);
2✔
221
    set_param_async(name, value_to_set, callback, cookie);
2✔
222
}
2✔
223

224
MavlinkParameterClient::Result
225
MavlinkParameterClient::set_param_custom(const std::string& name, const std::string& value)
2✔
226
{
227
    auto prom = std::promise<Result>();
2✔
228
    auto res = prom.get_future();
2✔
229
    set_param_custom_async(name, value, [&prom](Result result) { prom.set_value(result); }, this);
4✔
230
    return res.get();
2✔
231
}
2✔
232

233
void MavlinkParameterClient::get_param_async(
42✔
234
    const std::string& name, const GetParamAnyCallback& callback, const void* cookie)
235
{
236
    if (_parameter_debugging) {
42✔
237
        LogDebug() << "Getting param " << name << ", extended: " << (_use_extended ? "yes" : "no");
×
238
    }
239
    if (name.size() > PARAM_ID_LEN) {
42✔
240
        LogErr() << "Param name too long";
×
241
        if (callback) {
×
242
            callback(Result::ParamNameTooLong, {});
×
243
        }
244
        return;
×
245
    }
246

247
    auto new_work = std::make_shared<WorkItem>(WorkItemGet{name, callback}, cookie);
84✔
248
    _work_queue.push_back(new_work);
42✔
249
}
42✔
250

251
void MavlinkParameterClient::get_param_async(
26✔
252
    const std::string& name,
253
    const ParamValue& value_type,
254
    const GetParamAnyCallback& callback,
255
    const void* cookie)
256
{
257
    // We need to delay the type checking until we get a response from the server.
258
    GetParamAnyCallback callback_future_result = [callback,
26✔
259
                                                  value_type](Result result, ParamValue value) {
260
        if (result == Result::Success) {
26✔
261
            if (value.is_same_type(value_type)) {
26✔
262
                callback(Result::Success, std::move(value));
26✔
263
            } else {
264
                callback(Result::WrongType, {});
×
265
            }
266
        } else {
267
            callback(result, {});
×
268
        }
269
    };
52✔
270
    get_param_async(name, callback_future_result, cookie);
26✔
271
}
26✔
272

273
template<class T>
274
void MavlinkParameterClient::get_param_async_typesafe(
9✔
275
    const std::string& name, const GetParamTypesafeCallback<T> callback, const void* cookie)
276
{
277
    // We need to delay the type checking until we get a response from the server.
278
    GetParamAnyCallback callback_future_result = [callback](Result result, ParamValue value) {
36✔
279
        if (result == Result::Success) {
9✔
280
            if (value.is<T>()) {
8✔
281
                callback(Result::Success, value.get<T>());
8✔
282
            } else {
283
                callback(Result::WrongType, {});
×
284
            }
285
        } else {
286
            callback(result, {});
1✔
287
        }
288
    };
289
    get_param_async(name, callback_future_result, cookie);
9✔
290
}
9✔
291

292
template<>
293
void MavlinkParameterClient::get_param_async_typesafe(
5✔
294
    const std::string& name, const GetParamTypesafeCallback<int32_t> callback, const void* cookie)
295
{
296
    // We need to delay the type checking until we get a response from the server.
297
    GetParamAnyCallback callback_future_result = [callback](Result result, ParamValue value) {
5✔
298
        if (result == Result::Success) {
5✔
299
            if (value.is<int32_t>()) {
4✔
300
                callback(Result::Success, value.get<int32_t>());
4✔
301
            } else if (value.is<int16_t>()) {
×
302
                callback(Result::Success, value.get<int16_t>());
×
303
            } else if (value.is<int8_t>()) {
×
304
                callback(Result::Success, value.get<int8_t>());
×
305
            } else {
306
                callback(Result::WrongType, {});
×
307
            }
308
        } else {
309
            callback(result, {});
1✔
310
        }
311
    };
10✔
312
    get_param_async(name, callback_future_result, cookie);
5✔
313
}
5✔
314

315
void MavlinkParameterClient::get_param_float_async(
5✔
316
    const std::string& name, const GetParamFloatCallback& callback, const void* cookie)
317
{
318
    get_param_async_typesafe<float>(name, callback, cookie);
5✔
319
}
5✔
320

321
void MavlinkParameterClient::get_param_int_async(
5✔
322
    const std::string& name, const GetParamIntCallback& callback, const void* cookie)
323
{
324
    get_param_async_typesafe<int32_t>(name, callback, cookie);
5✔
325
}
5✔
326

327
void MavlinkParameterClient::get_param_custom_async(
4✔
328
    const std::string& name, const GetParamCustomCallback& callback, const void* cookie)
329
{
330
    get_param_async_typesafe<std::string>(name, callback, cookie);
4✔
331
}
4✔
332

333
std::pair<MavlinkParameterClient::Result, ParamValue>
334
MavlinkParameterClient::get_param(const std::string& name)
×
335
{
336
    auto prom = std::promise<std::pair<Result, ParamValue>>();
×
337
    auto res = prom.get_future();
×
338
    get_param_async(
×
339
        name,
340
        [&prom](Result result, ParamValue new_value) {
×
341
            prom.set_value(std::make_pair<>(result, std::move(new_value)));
×
342
        },
×
343
        this);
344
    return res.get();
×
345
}
×
346

347
std::pair<MavlinkParameterClient::Result, int32_t>
348
MavlinkParameterClient::get_param_int(const std::string& name)
5✔
349
{
350
    auto prom = std::promise<std::pair<Result, int32_t>>();
5✔
351
    auto res = prom.get_future();
5✔
352
    get_param_int_async(
5✔
353
        name,
354
        [&prom](Result result, int32_t value) { prom.set_value(std::make_pair<>(result, value)); },
5✔
355
        this);
356
    return res.get();
5✔
357
}
5✔
358

359
std::pair<MavlinkParameterClient::Result, float>
360
MavlinkParameterClient::get_param_float(const std::string& name)
5✔
361
{
362
    auto prom = std::promise<std::pair<Result, float>>();
5✔
363
    auto res = prom.get_future();
5✔
364
    get_param_float_async(
5✔
365
        name,
366
        [&prom](Result result, float value) { prom.set_value(std::make_pair<>(result, value)); },
5✔
367
        this);
368
    return res.get();
5✔
369
}
5✔
370

371
std::pair<MavlinkParameterClient::Result, std::string>
372
MavlinkParameterClient::get_param_custom(const std::string& name)
4✔
373
{
374
    auto prom = std::promise<std::pair<Result, std::string>>();
4✔
375
    auto res = prom.get_future();
4✔
376
    get_param_custom_async(
4✔
377
        name,
378
        [&prom](Result result, const std::string& value) {
4✔
379
            prom.set_value(std::make_pair<>(result, value));
4✔
380
        },
4✔
381
        this);
382
    return res.get();
4✔
383
}
4✔
384

385
void MavlinkParameterClient::get_all_params_async(GetAllParamsCallback callback, void* cookie)
4✔
386
{
387
    if (_parameter_debugging) {
4✔
388
        LogDebug() << "Getting all params, extended: " << (_use_extended ? "yes" : "no");
×
389
    }
390

391
    auto new_work =
4✔
392
        std::make_shared<WorkItem>(WorkItemGetAll{std::move(callback), 0, false}, cookie);
8✔
393
    _work_queue.push_back(new_work);
4✔
394
}
4✔
395

396
std::pair<MavlinkParameterClient::Result, std::map<std::string, ParamValue>>
397
MavlinkParameterClient::get_all_params()
4✔
398
{
399
    std::promise<std::pair<MavlinkParameterClient::Result, std::map<std::string, ParamValue>>> prom;
4✔
400
    auto res = prom.get_future();
4✔
401
    get_all_params_async(
4✔
402
        // Make sure to NOT use a reference for all_params here, pass by value.
403
        // Since for example on a timeout, the empty all_params result is constructed in-place and
404
        // then goes out of scope when the callback returns.
405
        [&prom](Result result, std::map<std::string, ParamValue> set) {
4✔
406
            prom.set_value({result, std::move(set)});
4✔
407
        },
4✔
408
        this);
409
    auto ret = res.get();
4✔
410
    return ret;
4✔
411
}
4✔
412

413
void MavlinkParameterClient::cancel_all_param(const void* cookie)
×
414
{
415
    LockedQueue<WorkItem>::Guard work_queue_guard(_work_queue);
×
416

417
    // We don't call any callbacks before erasing them as this is just used on destruction
418
    // where we don't care anymore.
419
    _work_queue.erase(std::remove_if(_work_queue.begin(), _work_queue.end(), [&](auto&& item) {
×
420
        return (item->cookie == cookie);
×
421
    }));
422
}
×
423

424
void MavlinkParameterClient::clear_cache()
×
425
{
426
    _param_cache.clear();
×
427
}
×
428

429
void MavlinkParameterClient::do_work()
571✔
430
{
431
    auto work_queue_guard = std::make_unique<LockedQueue<WorkItem>::Guard>(_work_queue);
571✔
432
    auto work = work_queue_guard->get_front();
571✔
433

434
    if (!work) {
571✔
435
        return;
279✔
436
    }
437

438
    if (work->already_requested) {
292✔
439
        return;
237✔
440
    }
441

442
    std::visit(
110✔
443
        overloaded{
55✔
444
            [&](WorkItemSet& item) {
9✔
445
                if (!send_set_param_message(item)) {
9✔
446
                    LogErr() << "Send message failed";
×
447
                    work_queue_guard->pop_front();
×
448
                    if (item.callback) {
×
449
                        auto callback = item.callback;
×
450
                        work_queue_guard.reset();
×
451
                        callback(Result::ConnectionError);
×
452
                    }
×
453
                    return;
×
454
                }
455
                work->already_requested = true;
9✔
456
                // We want to get notified if a timeout happens
457
                _timeout_cookie =
9✔
458
                    _timeout_handler.add([this] { receive_timeout(); }, _timeout_s_callback());
19✔
459
            },
460
            [&](WorkItemGet& item) {
42✔
461
                if (!send_get_param_message(item)) {
42✔
462
                    LogErr() << "Send message failed";
×
463
                    work_queue_guard->pop_front();
×
464
                    if (item.callback) {
×
465
                        auto callback = item.callback;
×
466
                        work_queue_guard.reset();
×
467
                        item.callback(Result::ConnectionError, ParamValue{});
×
468
                    }
×
469
                    return;
×
470
                }
471
                work->already_requested = true;
42✔
472
                // We want to get notified if a timeout happens
473
                _timeout_cookie =
42✔
474
                    _timeout_handler.add([this] { receive_timeout(); }, _timeout_s_callback());
89✔
475
            },
476
            [&](WorkItemGetAll& item) {
4✔
477
                if (!send_request_list_message()) {
4✔
478
                    LogErr() << "Send message failed";
×
479
                    work_queue_guard->pop_front();
×
480
                    if (item.callback) {
×
481
                        auto callback = item.callback;
×
482
                        work_queue_guard.reset();
×
483
                        item.callback(Result::ConnectionError, {});
×
484
                    }
×
485
                    return;
×
486
                }
487
                work->already_requested = true;
4✔
488
                // We want to get notified if a timeout happens
489
                _timeout_cookie =
4✔
490
                    _timeout_handler.add([this] { receive_timeout(); }, _timeout_s_callback());
10✔
491
            }},
492
        work->work_item_variant);
55✔
493
}
1,087✔
494

495
bool MavlinkParameterClient::send_set_param_message(WorkItemSet& work_item)
10✔
496
{
497
    auto param_id = param_id_to_message_buffer(work_item.param_name);
10✔
498

499
    mavlink_message_t message;
10✔
500
    if (_use_extended) {
10✔
501
        const auto param_value_buf = work_item.param_value.get_128_bytes();
6✔
502
        return _sender.queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
12✔
503
            if (_parameter_debugging) {
6✔
504
                LogDebug() << "Sending param_ext_set to:" << (int)mavlink_address.system_id << ":"
×
505
                           << (int)mavlink_address.component_id;
×
506
            }
507

508
            mavlink_msg_param_ext_set_pack_chan(
12✔
509
                mavlink_address.system_id,
6✔
510
                mavlink_address.component_id,
6✔
511
                channel,
512
                &message,
12✔
513
                _target_system_id,
6✔
514
                _target_component_id,
6✔
515
                param_id.data(),
6✔
516
                param_value_buf.data(),
6✔
517
                work_item.param_value.get_mav_param_ext_type());
6✔
518

519
            return message;
6✔
520
        });
6✔
521
    } else {
522
        const float value_set = (_autopilot_callback() == Autopilot::ArduPilot) ?
4✔
523
                                    work_item.param_value.get_4_float_bytes_cast() :
×
524
                                    work_item.param_value.get_4_float_bytes_bytewise();
4✔
525

526
        return _sender.queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
8✔
527
            if (_parameter_debugging) {
4✔
528
                LogDebug() << "Sending param_set to:" << (int)mavlink_address.system_id << ":"
×
529
                           << (int)mavlink_address.component_id;
×
530
            }
531
            mavlink_msg_param_set_pack_chan(
8✔
532
                mavlink_address.system_id,
4✔
533
                mavlink_address.component_id,
4✔
534
                channel,
535
                &message,
8✔
536
                _target_system_id,
4✔
537
                _target_component_id,
4✔
538
                param_id.data(),
4✔
539
                value_set,
4✔
540
                work_item.param_value.get_mav_param_type());
4✔
541
            return message;
4✔
542
        });
4✔
543
    }
544
}
545

546
bool MavlinkParameterClient::send_get_param_message(WorkItemGet& work_item)
55✔
547
{
548
    std::array<char, PARAM_ID_LEN> param_id_buff{};
55✔
549
    int16_t param_index = -1;
55✔
550
    if (auto str = std::get_if<std::string>(&work_item.param_identifier)) {
55✔
551
        param_id_buff = param_id_to_message_buffer(*str);
55✔
552
    } else {
553
        // param_id_buff doesn't matter
554
        param_index = std::get<int16_t>(work_item.param_identifier);
×
555
    }
556

557
    return send_get_param_message(param_id_buff, param_index);
55✔
558
}
559

560
bool MavlinkParameterClient::send_get_param_message(
60✔
561
    const std::array<char, PARAM_ID_LEN>& param_id_buff, int16_t param_index)
562
{
563
    mavlink_message_t message;
60✔
564

565
    if (_use_extended) {
60✔
566
        return _sender.queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
66✔
567
            if (_parameter_debugging) {
33✔
568
                LogDebug() << "Send param_ext_request_read: " << (int)mavlink_address.system_id
×
569
                           << ":" << (int)mavlink_address.component_id << " to "
×
570
                           << (int)_target_system_id << ":" << (int)_target_component_id;
×
571
            }
572
            mavlink_msg_param_ext_request_read_pack_chan(
66✔
573
                mavlink_address.system_id,
33✔
574
                mavlink_address.component_id,
33✔
575
                channel,
576
                &message,
66✔
577
                _target_system_id,
33✔
578
                _target_component_id,
33✔
579
                param_id_buff.data(),
33✔
580
                param_index);
33✔
581
            return message;
33✔
582
        });
33✔
583

584
    } else {
585
        return _sender.queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
54✔
586
            if (_parameter_debugging) {
27✔
587
                LogDebug() << "Send param_request_read: " << (int)mavlink_address.system_id << ":"
×
588
                           << (int)mavlink_address.component_id << " to " << (int)_target_system_id
×
589
                           << ":" << (int)_target_component_id;
×
590
            }
591
            mavlink_msg_param_request_read_pack_chan(
54✔
592
                mavlink_address.system_id,
27✔
593
                mavlink_address.component_id,
27✔
594
                channel,
595
                &message,
54✔
596
                _target_system_id,
27✔
597
                _target_component_id,
27✔
598
                param_id_buff.data(),
27✔
599
                param_index);
27✔
600
            return message;
27✔
601
        });
27✔
602
    }
603
}
604

605
bool MavlinkParameterClient::send_request_list_message()
4✔
606
{
607
    if (_use_extended) {
4✔
608
        return _sender.queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
4✔
609
            if (_parameter_debugging) {
2✔
610
                LogDebug() << "Sending param_ext_request_list to:" << (int)mavlink_address.system_id
×
611
                           << ":" << (int)mavlink_address.component_id;
×
612
            }
613
            mavlink_message_t message;
614
            mavlink_msg_param_ext_request_list_pack_chan(
2✔
615
                mavlink_address.system_id,
2✔
616
                mavlink_address.component_id,
2✔
617
                channel,
618
                &message,
619
                _target_system_id,
2✔
620
                _target_component_id);
2✔
621
            return message;
2✔
622
        });
2✔
623
    } else {
624
        return _sender.queue_message([&](MavlinkAddress mavlink_address, uint8_t channel) {
4✔
625
            if (_parameter_debugging) {
2✔
626
                LogDebug() << "Sending param_request_list to:" << (int)mavlink_address.system_id
×
627
                           << ":" << (int)mavlink_address.component_id;
×
628
            }
629
            mavlink_message_t message;
630
            mavlink_msg_param_request_list_pack_chan(
2✔
631
                mavlink_address.system_id,
2✔
632
                mavlink_address.component_id,
2✔
633
                channel,
634
                &message,
635
                _target_system_id,
2✔
636
                _target_component_id);
2✔
637
            return message;
2✔
638
        });
2✔
639
    }
640
}
641

642
void MavlinkParameterClient::process_param_value(const mavlink_message_t& message)
26✔
643
{
644
    mavlink_param_value_t param_value;
26✔
645
    mavlink_msg_param_value_decode(&message, &param_value);
26✔
646
    const std::string safe_param_id = extract_safe_param_id(param_value.param_id);
26✔
647
    if (safe_param_id.empty()) {
26✔
648
        LogWarn() << "Got ill-formed param_value message (param_id empty)";
×
649
        return;
×
650
    }
651

652
    ParamValue received_value;
26✔
653
    const bool set_value_success = received_value.set_from_mavlink_param_value(
26✔
654
        param_value,
655
        (_autopilot_callback() == Autopilot::ArduPilot) ? ParamValue::Conversion::Cast :
26✔
656
                                                          ParamValue::Conversion::Bitwise);
26✔
657
    if (!set_value_success) {
26✔
658
        LogWarn() << "Got ill-formed param_ext_value message (param_type unknown)";
×
659
        return;
×
660
    }
661

662
    if (_parameter_debugging) {
26✔
663
        LogDebug() << "process_param_value: " << safe_param_id << " " << received_value;
×
664
    }
665

666
    // We need to use a unique pointer here to remove the lock from the work queue manually "early"
667
    // before calling the (perhaps user-provided) callback. Otherwise, we might end up in a deadlock
668
    // if the callback wants to push another work item onto the queue. By using a unique ptr there
669
    // is no risk of forgetting to remove the lock - it is destroyed (if still valid) after going
670
    // out of scope.
671
    auto work_queue_guard = std::make_unique<LockedQueue<WorkItem>::Guard>(_work_queue);
26✔
672
    const auto work = work_queue_guard->get_front();
26✔
673

674
    if (!work) {
26✔
675
        // update existing param
NEW
676
        find_and_call_subscriptions_value_changed(safe_param_id, received_value);
×
UNCOV
677
        return;
×
678
    }
679

680
    if (!work->already_requested) {
26✔
681
        return;
×
682
    }
683

684
    std::visit(
52✔
685
        overloaded{
26✔
686
            [&](WorkItemSet& item) {
4✔
687
                if (item.param_name != safe_param_id) {
4✔
688
                    // No match, let's just return the borrowed work item.
689
                    return;
×
690
                }
691

692
                if (_parameter_debugging) {
4✔
693
                    LogDebug() << "Item value is: " << item.param_value
×
694
                               << ", received: " << received_value;
×
695
                }
696

697
                if (item.param_value == received_value) {
4✔
698
                    // This was successful. Inform the caller.
699
                    _timeout_handler.remove(_timeout_cookie);
4✔
700
                    // LogDebug() << "time taken: " <<
701
                    // _sender.get_time().elapsed_since_s(_last_request_time);
702
                    work_queue_guard->pop_front();
4✔
703
                    if (item.callback) {
4✔
704
                        auto callback = item.callback;
4✔
705
                        work_queue_guard.reset();
4✔
706
                        callback(MavlinkParameterClient::Result::Success);
4✔
707
                    }
4✔
708
                } else {
709
                    // We might be receiving stale param_value messages, let's just
710
                    // try again. This can happen if the timeout is chosen low and we
711
                    // get out of sync when doing a param_get just before the param_set.
712
                    // In that case we have stale param_value messages in flux and
713
                    // receive them here.
714
                    if (work->retries_to_do > 0) {
×
715
                        LogWarn() << "sending again, retries to do: " << work->retries_to_do
×
716
                                  << "  (" << item.param_name << ").";
×
717

718
                        if (!send_set_param_message(item)) {
×
719
                            LogErr() << "connection send error in retransmit (" << item.param_name
×
720
                                     << ").";
×
721
                            work_queue_guard->pop_front();
×
722

723
                            if (item.callback) {
×
724
                                auto callback = item.callback;
×
725
                                work_queue_guard.reset();
×
726
                                callback(Result::ConnectionError);
×
727
                            }
×
728
                            _timeout_handler.refresh(_timeout_cookie);
×
729
                        } else {
730
                            --work->retries_to_do;
×
731
                            _timeout_handler.refresh(_timeout_cookie);
×
732
                        }
733
                    } else {
734
                        // We have tried retransmitting, giving up now.
735
                        LogErr() << "Error: Retrying failed set param failed: " << item.param_name;
×
736
                        work_queue_guard->pop_front();
×
737
                        if (item.callback) {
×
738
                            auto callback = item.callback;
×
739
                            work_queue_guard.reset();
×
740
                            callback(Result::Timeout);
×
741
                        }
×
742
                    }
743
                }
744
            },
745
            [&](WorkItemGet& item) {
10✔
746
                if (!validate_id_or_index(
10✔
747
                        item.param_identifier,
10✔
748
                        safe_param_id,
10✔
749
                        static_cast<int16_t>(param_value.param_index))) {
10✔
750
                    LogWarn() << "Got unexpected response on work item";
×
751
                    // No match, let's just return the borrowed work item.
752
                    return;
×
753
                }
754
                _timeout_handler.remove(_timeout_cookie);
10✔
755
                // LogDebug() << "time taken: " <<
756
                // _sender.get_time().elapsed_since_s(_last_request_time);
757
                work_queue_guard->pop_front();
10✔
758
                if (item.callback) {
10✔
759
                    auto callback = item.callback;
10✔
760
                    work_queue_guard.reset();
10✔
761
                    callback(Result::Success, received_value);
10✔
762
                }
10✔
763
            },
764
            [&](WorkItemGetAll& item) {
12✔
765
                switch (_param_cache.add_new_param(
12✔
766
                    safe_param_id, received_value, param_value.param_index)) {
12✔
767
                    case MavlinkParameterCache::AddNewParamResult::AlreadyExists:
12✔
768
                        // FALLTHROUGH
769
                        // We don't care if it already exists, just overwrite it and carry on.
770
                        // The reason is that this can likely happen if the very first
771
                        // request_list is sent twice and hence we get a bunch of duplicate
772
                        // params.
773
                    case MavlinkParameterCache::AddNewParamResult::Ok:
774

775
                        item.count = param_value.param_count;
12✔
776
                        if (_parameter_debugging) {
12✔
777
                            LogDebug() << "Count is now " << item.count;
×
778
                        }
779
                        if (_param_cache.count(_use_extended) == param_value.param_count) {
12✔
780
                            _timeout_handler.remove(_timeout_cookie);
2✔
781
                            if (_parameter_debugging) {
2✔
782
                                LogDebug() << "Param set complete: "
×
783
                                           << (_use_extended ? "extended" : "not extended");
×
784
                            }
785
                            work_queue_guard->pop_front();
2✔
786
                            if (item.callback) {
2✔
787
                                auto callback = item.callback;
2✔
788
                                work_queue_guard.reset();
2✔
789
                                callback(
4✔
790
                                    Result::Success,
791
                                    _param_cache.all_parameters_map(_use_extended));
4✔
792
                            }
2✔
793
                        } else {
794
                            if (_parameter_debugging) {
10✔
795
                                LogDebug() << "Count expected " << _param_cache.count(_use_extended)
×
796
                                           << " so far " << param_value.param_count;
×
797
                            }
798
                            if (item.rerequesting) {
10✔
799
                                auto maybe_next_missing_index =
×
800
                                    _param_cache.next_missing_index(item.count);
×
801
                                if (!maybe_next_missing_index.has_value()) {
×
802
                                    LogErr() << "logic error, there should a missing index";
×
803
                                    assert(false);
×
804
                                }
805

806
                                if (_parameter_debugging) {
×
807
                                    LogDebug() << "Requesting missing parameter "
×
808
                                               << (int)maybe_next_missing_index.value();
×
809
                                }
810

811
                                std::array<char, PARAM_ID_LEN> param_id_buff{};
×
812
                                if (!send_get_param_message(
×
813
                                        param_id_buff, maybe_next_missing_index.value())) {
×
814
                                    LogErr() << "Send message failed";
×
815
                                    work_queue_guard->pop_front();
×
816
                                    if (item.callback) {
×
817
                                        auto callback = item.callback;
×
818
                                        work_queue_guard.reset();
×
819
                                        callback(Result::ConnectionError, {});
×
820
                                    }
×
821
                                    return;
×
822
                                }
823
                            } else {
824
                                // update the timeout handler, messages are still coming in.
825
                            }
826
                            _timeout_handler.refresh(_timeout_cookie);
10✔
827
                        }
828
                        break;
12✔
829
                    case MavlinkParameterCache::AddNewParamResult::TooManyParams:
×
830
                        // We shouldn't be able to get here as the incoming type is only an
831
                        // uint16_t.
832
                        LogErr() << "Too many params received";
×
833
                        assert(false);
×
834
                        break;
835
                    default:
×
836
                        LogErr() << "Unknown AddNewParamResult";
×
837
                        assert(false);
×
838
                        break;
839
                }
840
            }},
841
        work->work_item_variant);
26✔
842
}
26✔
843

844
void MavlinkParameterClient::process_param_ext_value(const mavlink_message_t& message)
61✔
845
{
846
    mavlink_param_ext_value_t param_ext_value;
61✔
847
    mavlink_msg_param_ext_value_decode(&message, &param_ext_value);
61✔
848
    const auto safe_param_id = extract_safe_param_id(param_ext_value.param_id);
61✔
849
    if (safe_param_id.empty()) {
61✔
850
        LogWarn() << "Got ill-formed param_ext_value message (param_id empty)";
×
851
        return;
×
852
    }
853
    ParamValue received_value;
61✔
854
    if (!received_value.set_from_mavlink_param_ext_value(param_ext_value)) {
61✔
855
        LogWarn() << "Got ill-formed param_ext_value message (param_type unknown)";
×
856
        return;
×
857
    }
858

859
    if (_parameter_debugging) {
61✔
860
        LogDebug() << "process param_ext_value: " << safe_param_id << " " << received_value;
×
861
    }
862

863
    // See comments on process_param_value for use of unique_ptr
864
    auto work_queue_guard = std::make_unique<LockedQueue<WorkItem>::Guard>(_work_queue);
61✔
865
    auto work = work_queue_guard->get_front();
61✔
866

867
    if (!work) {
61✔
868
        // update existing param
869
        find_and_call_subscriptions_value_changed(safe_param_id, received_value);
13✔
870
        return;
13✔
871
    }
872

873
    if (!work->already_requested) {
48✔
874
        return;
×
875
    }
876

877
    std::visit(
96✔
878
        overloaded{
48✔
879
            [&](WorkItemSet&) {
×
880
                if (_parameter_debugging) {
×
881
                    LogDebug() << "Unexpected ParamExtValue response.";
×
882
                }
883
            },
×
884
            [&](WorkItemGet& item) {
30✔
885
                if (!validate_id_or_index(
30✔
886
                        item.param_identifier,
30✔
887
                        safe_param_id,
30✔
888
                        static_cast<int16_t>(param_ext_value.param_index))) {
30✔
889
                    LogWarn() << "Got unexpected response on work item";
×
890
                    // No match, let's just return the borrowed work item.
891
                    return;
×
892
                }
893
                _timeout_handler.remove(_timeout_cookie);
30✔
894
                // LogDebug() << "time taken: " <<
895
                // _sender.get_time().elapsed_since_s(_last_request_time);
896
                work_queue_guard->pop_front();
30✔
897
                if (item.callback) {
30✔
898
                    auto callback = item.callback;
30✔
899
                    work_queue_guard.reset();
30✔
900
                    callback(Result::Success, received_value);
30✔
901
                }
30✔
902
            },
903
            [&](WorkItemGetAll& item) {
18✔
904
                switch (_param_cache.add_new_param(
18✔
905
                    safe_param_id, received_value, param_ext_value.param_index)) {
18✔
906
                    case MavlinkParameterCache::AddNewParamResult::AlreadyExists:
18✔
907
                        // PASSTHROUGH.
908
                    case MavlinkParameterCache::AddNewParamResult::Ok:
909
                        item.count = param_ext_value.param_count;
18✔
910
                        if (_parameter_debugging) {
18✔
911
                            LogDebug() << "Count is now " << item.count;
×
912
                        }
913

914
                        if (_param_cache.count(_use_extended) == param_ext_value.param_count) {
18✔
915
                            _timeout_handler.remove(_timeout_cookie);
2✔
916
                            if (_parameter_debugging) {
2✔
917
                                LogDebug() << "Param set complete: "
×
918
                                           << (_use_extended ? "extended" : "not extended");
×
919
                            }
920
                            work_queue_guard->pop_front();
2✔
921
                            if (item.callback) {
2✔
922
                                auto callback = item.callback;
2✔
923
                                work_queue_guard.reset();
2✔
924
                                callback(
4✔
925
                                    Result::Success,
926
                                    _param_cache.all_parameters_map(_use_extended));
4✔
927
                            }
2✔
928
                        } else {
929
                            if (_parameter_debugging) {
16✔
930
                                LogDebug() << "Count expected " << _param_cache.count(_use_extended)
×
931
                                           << " but is " << param_ext_value.param_count;
×
932
                            }
933
                            // update the timeout handler, messages are still coming in.
934
                            _timeout_handler.refresh(_timeout_cookie);
16✔
935
                        }
936
                        break;
18✔
937
                    case MavlinkParameterCache::AddNewParamResult::TooManyParams:
×
938
                        // We shouldn't be able to get here as the incoming type is only an
939
                        // uint16_t.
940
                        LogErr() << "Too many params received";
×
941
                        assert(false);
×
942
                        break;
943
                    default:
×
944
                        LogErr() << "Unknown AddNewParamResult";
×
945
                        assert(false);
×
946
                        break;
947
                }
948
            },
18✔
949
        },
950
        work->work_item_variant);
48✔
951
}
100✔
952

953
void MavlinkParameterClient::process_param_ext_ack(const mavlink_message_t& message)
5✔
954
{
955
    mavlink_param_ext_ack_t param_ext_ack;
5✔
956
    mavlink_msg_param_ext_ack_decode(&message, &param_ext_ack);
5✔
957
    const auto safe_param_id = extract_safe_param_id(param_ext_ack.param_id);
5✔
958

959
    if (_parameter_debugging) {
5✔
960
        LogDebug() << "process param_ext_ack: " << safe_param_id << " "
×
961
                   << (int)param_ext_ack.param_result;
×
962
    }
963

964
    // See comments on process_param_value for use of unique_ptr
965
    auto work_queue_guard = std::make_unique<LockedQueue<WorkItem>::Guard>(_work_queue);
5✔
966
    auto work = work_queue_guard->get_front();
5✔
967
    if (!work) {
5✔
968
        return;
×
969
    }
970
    if (!work->already_requested) {
5✔
971
        return;
×
972
    }
973

974
    std::visit(
10✔
975
        overloaded{
5✔
976
            [&](WorkItemSet& item) {
5✔
977
                if (item.param_name != safe_param_id) {
5✔
978
                    // No match, let's just return the borrowed work item.
979
                    return;
×
980
                }
981
                if (param_ext_ack.param_result == PARAM_ACK_ACCEPTED) {
5✔
982
                    _timeout_handler.remove(_timeout_cookie);
5✔
983
                    // LogDebug() << "time taken: " <<
984
                    // _sender.get_time().elapsed_since_s(_last_request_time);
985
                    work_queue_guard->pop_front();
5✔
986
                    if (item.callback) {
5✔
987
                        auto callback = item.callback;
5✔
988
                        // We are done, inform caller and go back to idle
989
                        work_queue_guard.reset();
5✔
990
                        callback(Result::Success);
5✔
991
                    }
5✔
992
                } else if (param_ext_ack.param_result == PARAM_ACK_IN_PROGRESS) {
×
993
                    // Reset timeout and wait again.
994
                    _timeout_handler.refresh(_timeout_cookie);
×
995

996
                } else {
997
                    LogWarn() << "Somehow we did not get an ack, we got: "
×
998
                              << int(param_ext_ack.param_result);
×
999
                    _timeout_handler.remove(_timeout_cookie);
×
1000
                    // LogDebug() << "time taken: " <<
1001
                    // _sender.get_time().elapsed_since_s(_last_request_time);
1002
                    work_queue_guard->pop_front();
×
1003
                    work_queue_guard.reset();
×
1004
                    if (item.callback) {
×
1005
                        auto callback = item.callback;
×
1006
                        auto result = [&]() {
×
1007
                            switch (param_ext_ack.param_result) {
×
1008
                                case PARAM_ACK_FAILED:
×
1009
                                    return Result::Failed;
×
1010
                                case PARAM_ACK_VALUE_UNSUPPORTED:
×
1011
                                    return Result::ValueUnsupported;
×
1012
                                default:
×
1013
                                    return Result::UnknownError;
×
1014
                            }
1015
                        }();
×
1016
                        work_queue_guard.reset();
×
1017
                        callback(result);
×
1018
                    }
×
1019
                }
1020
            },
1021
            [&](WorkItemGet&) { LogWarn() << "Unexpected ParamExtAck response."; },
×
1022
            [&](WorkItemGetAll&) { LogWarn() << "Unexpected ParamExtAck response."; }},
×
1023
        work->work_item_variant);
5✔
1024
}
5✔
1025

1026
void MavlinkParameterClient::receive_timeout()
21✔
1027
{
1028
    // See comments on process_param_value for use of unique_ptr
1029
    auto work_queue_guard = std::make_unique<LockedQueue<WorkItem>::Guard>(_work_queue);
21✔
1030

1031
    auto work = work_queue_guard->get_front();
21✔
1032
    if (!work) {
21✔
1033
        LogErr() << "Received timeout without work";
×
1034
        return;
×
1035
    }
1036
    if (!work->already_requested) {
21✔
1037
        LogErr() << "Received timeout without already having work requested";
×
1038
        return;
×
1039
    }
1040

1041
    std::visit(
42✔
1042
        overloaded{
21✔
1043
            [&](WorkItemSet& item) {
1✔
1044
                if (work->retries_to_do > 0) {
1✔
1045
                    // We're not sure the command arrived, let's retransmit.
1046
                    LogWarn() << "sending again, retries to do: " << work->retries_to_do << "  ("
2✔
1047
                              << item.param_name << ").";
2✔
1048

1049
                    if (!send_set_param_message(item)) {
1✔
1050
                        LogErr() << "connection send error in retransmit (" << item.param_name
×
1051
                                 << ").";
×
1052
                        work_queue_guard->pop_front();
×
1053

1054
                        if (item.callback) {
×
1055
                            auto callback = item.callback;
×
1056
                            work_queue_guard.reset();
×
1057
                            callback(Result::ConnectionError);
×
1058
                        }
×
1059
                    } else {
1060
                        --work->retries_to_do;
1✔
1061
                        _timeout_cookie = _timeout_handler.add(
1✔
1062
                            [this] { receive_timeout(); }, _timeout_s_callback());
×
1063
                    }
1064
                } else {
1065
                    // We have tried retransmitting, giving up now.
1066
                    LogErr() << "Error: Retrying failed set param timeout: " << item.param_name;
×
1067
                    work_queue_guard->pop_front();
×
1068
                    if (item.callback) {
×
1069
                        auto callback = item.callback;
×
1070
                        work_queue_guard.reset();
×
1071
                        callback(Result::Timeout);
×
1072
                    }
×
1073
                }
1074
            },
1✔
1075
            [&](WorkItemGet& item) {
15✔
1076
                if (work->retries_to_do > 0) {
15✔
1077
                    // We're not sure the command arrived, let's retransmit.
1078
                    LogWarn() << "sending again, retries to do: " << work->retries_to_do;
13✔
1079
                    if (!send_get_param_message(item)) {
13✔
1080
                        LogErr() << "connection send error in retransmit ";
×
1081
                        work_queue_guard->pop_front();
×
1082
                        if (item.callback) {
×
1083
                            auto callback = item.callback;
×
1084
                            work_queue_guard.reset();
×
1085
                            callback(Result::ConnectionError, {});
×
1086
                        }
×
1087
                    } else {
1088
                        --work->retries_to_do;
13✔
1089
                        _timeout_cookie = _timeout_handler.add(
13✔
1090
                            [this] { receive_timeout(); }, _timeout_s_callback());
10✔
1091
                    }
1092
                } else {
1093
                    // We have tried retransmitting, giving up now.
1094
                    LogErr() << "retrying failed";
2✔
1095
                    work_queue_guard->pop_front();
2✔
1096
                    if (item.callback) {
2✔
1097
                        auto callback = item.callback;
2✔
1098
                        work_queue_guard.reset();
2✔
1099
                        callback(Result::Timeout, {});
2✔
1100
                    }
2✔
1101
                }
1102
            },
15✔
1103
            [&](WorkItemGetAll& item) {
5✔
1104
                // Request missing parameters.
1105
                // If retries are exceeded, give up with timeout.
1106

1107
                if (_parameter_debugging) {
5✔
1108
                    LogDebug() << "All params receive timeout with";
×
1109
                }
1110

1111
                if (item.count == 0) {
5✔
1112
                    // We got 0 messages back from the server (param count unknown). Most likely the
1113
                    // "list request" got lost before making it to the server,
1114
                    if (work->retries_to_do > 0) {
×
1115
                        --work->retries_to_do;
×
1116

1117
                        if (!send_request_list_message()) {
×
1118
                            LogErr() << "Send message failed";
×
1119
                            work_queue_guard->pop_front();
×
1120
                            if (item.callback) {
×
1121
                                auto callback = item.callback;
×
1122
                                work_queue_guard.reset();
×
1123
                                item.callback(Result::ConnectionError, {});
×
1124
                            }
×
1125
                            return;
×
1126
                        }
1127

1128
                        // We want to get notified if a timeout happens
1129
                        _timeout_cookie = _timeout_handler.add(
×
1130
                            [this] { receive_timeout(); }, _timeout_s_callback());
×
1131
                    } else {
1132
                        if (item.callback) {
×
1133
                            auto callback = item.callback;
×
1134
                            work_queue_guard.reset();
×
1135
                            item.callback(Result::Timeout, {});
×
1136
                        }
×
1137
                        return;
×
1138
                    }
1139

1140
                } else {
1141
                    item.rerequesting = true;
5✔
1142
                    auto maybe_next_missing_index = _param_cache.next_missing_index(item.count);
5✔
1143
                    if (!maybe_next_missing_index.has_value()) {
5✔
1144
                        LogErr() << "logic error, there should a missing index";
×
1145
                        assert(false);
×
1146
                    }
1147

1148
                    if (_parameter_debugging) {
5✔
1149
                        LogDebug() << "Requesting missing parameter "
×
1150
                                   << (int)maybe_next_missing_index.value();
×
1151
                    }
1152

1153
                    std::array<char, PARAM_ID_LEN> param_id_buff{};
5✔
1154

1155
                    if (!send_get_param_message(param_id_buff, maybe_next_missing_index.value())) {
5✔
1156
                        LogErr() << "Send message failed";
×
1157
                        work_queue_guard->pop_front();
×
1158
                        if (item.callback) {
×
1159
                            auto callback = item.callback;
×
1160
                            work_queue_guard.reset();
×
1161
                            callback(Result::ConnectionError, {});
×
1162
                        }
×
1163
                        return;
×
1164
                    }
1165
                    _timeout_cookie =
5✔
1166
                        _timeout_handler.add([this] { receive_timeout(); }, _timeout_s_callback());
13✔
1167
                }
1168
            }},
1169
        work->work_item_variant);
21✔
1170
}
21✔
1171

1172
std::ostream& operator<<(std::ostream& str, const MavlinkParameterClient::Result& result)
×
1173
{
1174
    switch (result) {
×
1175
        case MavlinkParameterClient::Result::Success:
×
1176
            return str << "Success";
×
1177
        case MavlinkParameterClient::Result::Timeout:
×
1178
            return str << "Timeout";
×
1179
        case MavlinkParameterClient::Result::ConnectionError:
×
1180
            return str << "ConnectionError";
×
1181
        case MavlinkParameterClient::Result::WrongType:
×
1182
            return str << "WrongType";
×
1183
        case MavlinkParameterClient::Result::ParamNameTooLong:
×
1184
            return str << "ParamNameTooLong";
×
1185
        case MavlinkParameterClient::Result::NotFound:
×
1186
            return str << "NotFound";
×
1187
        case MavlinkParameterClient::Result::ValueUnsupported:
×
1188
            return str << "ValueUnsupported";
×
1189
        case MavlinkParameterClient::Result::Failed:
×
1190
            return str << "Failed";
×
1191
        case MavlinkParameterClient::Result::UnknownError:
×
1192
            // Fallthrough
1193
        default:
1194
            return str << "UnknownError";
×
1195
    }
1196
}
1197

1198
bool MavlinkParameterClient::validate_id_or_index(
40✔
1199
    const std::variant<std::string, int16_t>& original,
1200
    const std::string& param_id,
1201
    const int16_t param_index)
1202
{
1203
    if (const auto str = std::get_if<std::string>(&original)) {
40✔
1204
        if (param_id != *str) {
40✔
1205
            // We requested by string id, but response doesn't match
1206
            return false;
×
1207
        }
1208
    } else {
1209
        const auto tmp = std::get<int16_t>(original);
×
1210
        if (param_index != tmp) {
×
1211
            // We requested by index, but response doesn't match
1212
            return false;
×
1213
        }
1214
    }
1215
    return true;
40✔
1216
}
1217

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

© 2025 Coveralls, Inc