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

mavlink / MAVSDK / 16158559489

09 Jul 2025 02:03AM UTC coverage: 45.238% (+0.03%) from 45.212%
16158559489

Pull #2609

github

web-flow
Merge 445427e66 into 6c112e71f
Pull Request #2609: Switch from tinyxml2 to rapidxml

100 of 107 new or added lines in 1 file covered. (93.46%)

11 existing lines in 3 files now uncovered.

15448 of 34148 relevant lines covered (45.24%)

142884.26 hits per line

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

78.88
/src/mavsdk/plugins/camera/camera_definition.cpp
1
#include "log.h"
2
#include "camera_definition.h"
3
#include <fstream>
4
#include <sstream>
5

6
// Custom error handler for rapidxml no-exceptions mode
7
namespace rapidxml {
NEW
8
void parse_error_handler(const char* what, void* where)
×
9
{
10
    (void)where; // Suppress unused parameter warning
NEW
11
    mavsdk::LogErr() << "RapidXML parse error: " << what;
×
12
    // In no-exceptions mode, we can't throw, so we just log the error
13
    // The calling code will check for parsing success
NEW
14
}
×
15
} // namespace rapidxml
16

17
namespace mavsdk {
18

19
bool CameraDefinition::load_file(const std::string& filepath)
18✔
20
{
21
    std::ifstream file(filepath);
18✔
22
    if (!file.is_open()) {
18✔
NEW
23
        LogErr() << "Failed to open file: " << filepath;
×
NEW
24
        return false;
×
25
    }
26

27
    std::stringstream buffer;
18✔
28
    buffer << file.rdbuf();
18✔
29
    _xml_content = buffer.str();
18✔
30
    file.close();
18✔
31

32
    _doc.parse<0>(&_xml_content[0]);
18✔
33
    if (_doc.first_node() == nullptr) {
18✔
NEW
34
        LogErr() << "RapidXML parse failed for file: " << filepath;
×
UNCOV
35
        return false;
×
36
    }
37

38
    return parse_xml();
18✔
39
}
18✔
40

41
bool CameraDefinition::load_string(const std::string& content)
2✔
42
{
43
    _xml_content = content;
2✔
44

45
    _doc.parse<0>(&_xml_content[0]);
2✔
46
    if (_doc.first_node() == nullptr) {
2✔
NEW
47
        LogErr() << "RapidXML parse failed for string content";
×
UNCOV
48
        return false;
×
49
    }
50

51
    return parse_xml();
2✔
52
}
53

54
std::string CameraDefinition::get_model() const
4✔
55
{
56
    return _model;
4✔
57
}
58

59
std::string CameraDefinition::get_vendor() const
4✔
60
{
61
    return _vendor;
4✔
62
}
63

64
bool CameraDefinition::parse_xml()
20✔
65
{
66
    auto e_mavlinkcamera = _doc.first_node("mavlinkcamera");
20✔
67
    if (!e_mavlinkcamera) {
20✔
68
        LogErr() << "Tag mavlinkcamera not found";
×
69
        return false;
×
70
    }
71

72
    auto e_definition = e_mavlinkcamera->first_node("definition");
20✔
73
    if (!e_definition) {
20✔
74
        LogErr() << "definition not found";
×
75
        return false;
×
76
    }
77

78
    auto e_model = e_definition->first_node("model");
20✔
79
    if (!e_model) {
20✔
80
        LogErr() << "model not found";
×
81
        return false;
×
82
    }
83

84
    const char* model_text = e_model->value();
20✔
85
    _model = model_text ? model_text : "";
20✔
86

87
    auto e_vendor = e_definition->first_node("vendor");
20✔
88
    if (!e_vendor) {
20✔
89
        LogErr() << "vendor not found";
×
90
        return false;
×
91
    }
92

93
    const char* vendor_text = e_vendor->value();
20✔
94
    _vendor = vendor_text ? vendor_text : "";
20✔
95

96
    auto e_parameters = e_mavlinkcamera->first_node("parameters");
20✔
97
    if (!e_parameters) {
20✔
98
        LogErr() << "Tag parameters not found";
×
99
        return false;
×
100
    }
101

102
    std::unordered_map<std::string, std::string> type_map{};
20✔
103
    // We need all types first.
104
    for (auto e_parameter = e_parameters->first_node("parameter"); e_parameter != nullptr;
321✔
105
         e_parameter = e_parameter->next_sibling("parameter")) {
301✔
106
        auto name_attr = e_parameter->first_attribute("name");
301✔
107
        if (!name_attr) {
301✔
108
            LogErr() << "name attribute missing";
×
109
            return false;
×
110
        }
111
        const char* param_name = name_attr->value();
301✔
112

113
        auto type_attr = e_parameter->first_attribute("type");
301✔
114
        if (!type_attr) {
301✔
115
            LogErr() << "type attribute missing";
×
116
            return false;
×
117
        }
118
        const char* type_str = type_attr->value();
301✔
119

120
        type_map[param_name] = type_str;
301✔
121
    }
122

123
    for (auto e_parameter = e_parameters->first_node("parameter"); e_parameter != nullptr;
321✔
124
         e_parameter = e_parameter->next_sibling("parameter")) {
301✔
125
        auto new_parameter = std::make_shared<Parameter>();
301✔
126

127
        auto name_attr = e_parameter->first_attribute("name");
301✔
128
        if (!name_attr) {
301✔
129
            LogErr() << "name attribute missing";
×
130
            return false;
×
131
        }
132
        const char* param_name = name_attr->value();
301✔
133

134
        auto type_attr = e_parameter->first_attribute("type");
301✔
135
        if (!type_attr) {
301✔
136
            LogErr() << "type attribute missing for " << param_name;
×
137
            return false;
×
138
        }
139
        const char* type_str_res = type_attr->value();
301✔
140

141
        auto type_str = std::string(type_str_res);
602✔
142
        if (type_str == "string") {
301✔
143
            LogDebug() << "Ignoring string params: " << param_name;
×
144
            continue;
×
145
        }
146

147
        if (type_str == "custom") {
301✔
148
            LogDebug() << "Ignoring custom params: " << param_name;
×
149
            continue;
×
150
        }
151

152
        if (!new_parameter->type.set_empty_type_from_xml(type_str)) {
301✔
153
            LogErr() << "Unknown type attribute: " << type_str;
×
154
            return false;
×
155
        }
156

157
        // By default control is on.
158
        new_parameter->is_control = true;
301✔
159
        auto control_attr = e_parameter->first_attribute("control");
301✔
160
        if (control_attr) {
301✔
161
            const char* control_str = control_attr->value();
63✔
162
            if (control_str && std::string(control_str) == "0") {
63✔
163
                new_parameter->is_control = false;
61✔
164
            }
165
        }
166

167
        new_parameter->is_readonly = false;
301✔
168
        auto readonly_attr = e_parameter->first_attribute("readonly");
301✔
169
        if (readonly_attr) {
301✔
170
            const char* readonly_str = readonly_attr->value();
10✔
171
            if (readonly_str && std::string(readonly_str) == "1") {
10✔
172
                new_parameter->is_readonly = true;
10✔
173
            }
174
        }
175

176
        new_parameter->is_writeonly = false;
301✔
177
        auto writeonly_attr = e_parameter->first_attribute("writeonly");
301✔
178
        if (writeonly_attr) {
301✔
179
            const char* writeonly_str = writeonly_attr->value();
1✔
180
            if (writeonly_str && std::string(writeonly_str) == "1") {
1✔
181
                new_parameter->is_writeonly = true;
1✔
182
            }
183
        }
184

185
        if (new_parameter->is_readonly && new_parameter->is_writeonly) {
301✔
186
            LogErr() << "parameter can't be readonly and writeonly";
×
187
            return false;
×
188
        }
189

190
        // Be definition custom types do not have control.
191
        if (std::string(type_map[param_name]) == "custom") {
301✔
192
            new_parameter->is_control = false;
×
193
        }
194

195
        auto e_description = e_parameter->first_node("description");
301✔
196
        if (!e_description) {
301✔
197
            LogErr() << "Description missing";
×
198
            return false;
×
199
        }
200

201
        const char* description_text = e_description->value();
301✔
202
        new_parameter->description = description_text ? description_text : "";
301✔
203

204
        // LogDebug() << "Found: " << new_parameter->description
205
        //            << " (" << param_name
206
        //            << ", control: " << (new_parameter->is_control ? "yes" : "no")
207
        //            << ", readonly: " << (new_parameter->is_readonly ? "yes" : "no")
208
        //            << ", writeonly: " << (new_parameter->is_writeonly ? "yes" : "no")
209
        //            << ")";
210

211
        auto e_updates = e_parameter->first_node("updates");
301✔
212
        if (e_updates) {
301✔
213
            for (auto e_update = e_updates->first_node("update"); e_update != nullptr;
190✔
214
                 e_update = e_update->next_sibling("update")) {
140✔
215
                const char* update_text = e_update->value();
140✔
216
                if (update_text) {
140✔
217
                    new_parameter->updates.emplace_back(update_text);
140✔
218
                }
219
            }
220
        }
221

222
        auto default_attr = e_parameter->first_attribute("default");
301✔
223
        if (!default_attr) {
301✔
224
            LogWarn() << "Default missing for " << param_name;
×
225
            continue;
×
226
        }
227
        const char* default_str = default_attr->value();
301✔
228

229
        auto get_default_opt = [&]() {
301✔
230
            auto maybe_default = find_default(new_parameter->options, default_str);
654✔
231

232
            if (!maybe_default.first) {
218✔
233
                LogWarn() << "Default not found for " << param_name;
×
234
                return std::optional<Option>{};
×
235
            }
236

237
            return std::optional{maybe_default.second};
218✔
238
        };
218✔
239

240
        auto e_options = e_parameter->first_node("options");
301✔
241
        if (e_options) {
301✔
242
            auto maybe_options = parse_options(e_options, param_name, type_map);
654✔
243
            if (!maybe_options.first) {
218✔
244
                continue;
×
245
            }
246
            new_parameter->options = maybe_options.second;
218✔
247

248
            if (auto default_option = get_default_opt()) {
218✔
249
                new_parameter->default_option = *default_option;
218✔
250
            } else {
251
                return false;
×
252
            }
218✔
253
        } else if (type_str == "bool") {
301✔
254
            // Automaticaly create bool options if the parameter type is bool as per documentation.
255
            Option true_option;
×
256
            true_option.name = "on";
×
257
            true_option.value.set<uint8_t>(true);
×
258
            Option false_option;
×
259
            true_option.name = "off";
×
260
            false_option.value.set<uint8_t>(false);
×
261

262
            new_parameter->options = {
×
263
                std::make_shared<Option>(std::move(true_option)),
×
264
                std::make_shared<Option>(std::move(false_option))};
×
265

266
            if (auto default_option = get_default_opt()) {
×
267
                new_parameter->default_option = *default_option;
×
268
            } else {
269
                return false;
×
270
            }
×
271
        } else {
×
272
            auto maybe_range_options = parse_range_options(e_parameter, param_name, type_map);
249✔
273
            if (!std::get<0>(maybe_range_options)) {
83✔
274
                LogWarn() << "Range not found for: " << param_name;
×
275
                continue;
×
276
            }
277

278
            new_parameter->options = std::get<1>(maybe_range_options);
83✔
279
            new_parameter->is_range = true;
83✔
280
            new_parameter->default_option = std::get<2>(maybe_range_options);
83✔
281
        }
83✔
282

283
        _parameter_map[param_name] = new_parameter;
301✔
284

285
        InternalCurrentSetting empty_setting{};
301✔
286
        empty_setting.needs_updating = true;
301✔
287
        _current_settings[param_name] = empty_setting;
301✔
288
    }
301✔
289

290
    return true;
20✔
291
}
20✔
292

293
std::pair<bool, std::vector<std::shared_ptr<CameraDefinition::Option>>>
294
CameraDefinition::parse_options(
218✔
295
    const rapidxml::xml_node<>* options_handle,
296
    const std::string& param_name,
297
    std::unordered_map<std::string, std::string>& type_map)
298
{
299
    std::vector<std::shared_ptr<Option>> options{};
218✔
300

301
    for (auto e_option = options_handle->first_node("option"); e_option != nullptr;
1,522✔
302
         e_option = e_option->next_sibling("option")) {
1,304✔
303
        auto name_attr = e_option->first_attribute("name");
1,304✔
304
        if (!name_attr) {
1,304✔
305
            LogErr() << "no option name given";
×
306
            return std::make_pair<>(false, options);
×
307
        }
308
        const char* option_name = name_attr->value();
1,304✔
309

310
        auto value_attr = e_option->first_attribute("value");
1,304✔
311
        if (!value_attr) {
1,304✔
312
            LogErr() << "no option value given";
×
313
            return std::make_pair<>(false, options);
×
314
        }
315
        const char* option_value = value_attr->value();
1,304✔
316

317
        auto new_option = std::make_shared<Option>();
1,304✔
318

319
        new_option->name = option_name;
1,304✔
320

321
        new_option->value.set_from_xml(type_map[param_name], option_value);
1,304✔
322

323
        // LogDebug() << "Type: " << type_map[param_name] << ", name: " << option_name;
324

325
        auto e_exclusions = e_option->first_node("exclusions");
1,304✔
326
        if (e_exclusions) {
1,304✔
327
            for (auto e_exclude = e_exclusions->first_node("exclude"); e_exclude != nullptr;
314✔
328
                 e_exclude = e_exclude->next_sibling("exclude")) {
187✔
329
                const char* exclude_text = e_exclude->value();
187✔
330
                if (exclude_text) {
187✔
331
                    new_option->exclusions.emplace_back(exclude_text);
187✔
332
                }
333
            }
334
        }
335

336
        auto e_parameterranges = e_option->first_node("parameterranges");
1,304✔
337
        if (e_parameterranges) {
1,304✔
338
            for (auto e_parameterrange = e_parameterranges->first_node("parameterrange");
340✔
339
                 e_parameterrange != nullptr;
680✔
340
                 e_parameterrange = e_parameterrange->next_sibling("parameterrange")) {
340✔
341
                auto param_attr = e_parameterrange->first_attribute("parameter");
340✔
342
                if (!param_attr) {
340✔
343
                    LogErr() << "missing roption parameter name";
×
344
                    return std::make_pair<>(false, options);
×
345
                }
346
                const char* roption_parameter_str = param_attr->value();
340✔
347

348
                ParameterRange new_parameter_range;
340✔
349

350
                for (auto e_roption = e_parameterrange->first_node("roption"); e_roption != nullptr;
4,980✔
351
                     e_roption = e_roption->next_sibling("roption")) {
4,640✔
352
                    auto roption_name_attr = e_roption->first_attribute("name");
4,640✔
353
                    if (!roption_name_attr) {
4,640✔
354
                        LogErr() << "missing roption name attribute";
×
355
                        return std::make_pair<>(false, options);
×
356
                    }
357
                    const char* roption_name_str = roption_name_attr->value();
4,640✔
358

359
                    auto roption_value_attr = e_roption->first_attribute("value");
4,640✔
360
                    if (!roption_value_attr) {
4,640✔
361
                        LogErr() << "missing roption value attribute";
×
362
                        return std::make_pair<>(false, options);
×
363
                    }
364
                    const char* roption_value_str = roption_value_attr->value();
4,640✔
365

366
                    if (type_map.find(roption_parameter_str) == type_map.end()) {
4,640✔
367
                        LogErr() << "unknown roption type";
×
368
                        return std::make_pair<>(false, options);
×
369
                    }
370

371
                    ParamValue new_param_value;
4,640✔
372
                    new_param_value.set_from_xml(
13,920✔
373
                        type_map[roption_parameter_str], roption_value_str);
9,280✔
374
                    new_parameter_range[roption_name_str] = new_param_value;
4,640✔
375

376
                    // LogDebug() << "range option: "
377
                    //            << roption_name_str
378
                    //            << " -> "
379
                    //            << new_param_value
380
                    //            << " (" << new_param_value.typestr() << ")";
381
                }
4,640✔
382

383
                new_option->parameter_ranges[roption_parameter_str] = new_parameter_range;
340✔
384

385
                // LogDebug() << "adding to: " << roption_parameter_str;
386
            }
340✔
387
        }
388

389
        options.push_back(new_option);
1,304✔
390
    }
1,304✔
391
    return std::make_pair<>(true, options);
218✔
392
}
218✔
393

394
std::tuple<bool, std::vector<std::shared_ptr<CameraDefinition::Option>>, CameraDefinition::Option>
395
CameraDefinition::parse_range_options(
83✔
396
    const rapidxml::xml_node<>* param_handle,
397
    const std::string& param_name,
398
    std::unordered_map<std::string, std::string>& type_map)
399
{
400
    std::vector<std::shared_ptr<Option>> options{};
83✔
401
    Option default_option{};
83✔
402

403
    auto min_attr = param_handle->first_attribute("min");
83✔
404
    if (!min_attr) {
83✔
405
        LogDebug() << "min range missing for " << param_name;
×
406
        return std::make_tuple<>(false, options, default_option);
×
407
    }
408
    const char* min_str = min_attr->value();
83✔
409

410
    ParamValue min_value;
83✔
411
    min_value.set_from_xml(type_map[param_name], min_str);
83✔
412

413
    auto max_attr = param_handle->first_attribute("max");
83✔
414
    if (!max_attr) {
83✔
415
        LogDebug() << "max range missing for " << param_name;
×
416
        return std::make_tuple<>(false, options, default_option);
×
417
    }
418
    const char* max_str = max_attr->value();
83✔
419

420
    auto min_option = std::make_shared<Option>();
83✔
421
    min_option->name = "min";
83✔
422
    min_option->value = min_value;
83✔
423

424
    ParamValue max_value;
83✔
425
    max_value.set_from_xml(type_map[param_name], max_str);
83✔
426

427
    auto max_option = std::make_shared<Option>();
83✔
428
    max_option->name = "max";
83✔
429
    max_option->value = max_value;
83✔
430

431
    auto step_attr = param_handle->first_attribute("step");
83✔
432
    const char* step_str = step_attr ? step_attr->value() : nullptr;
83✔
433
    if (!step_str) {
83✔
434
        LogDebug() << "step range missing for " << param_name;
×
435
    }
436

437
    if (step_str) {
83✔
438
        ParamValue step_value;
83✔
439
        step_value.set_from_xml(type_map[param_name], step_str);
83✔
440

441
        auto step_option = std::make_shared<Option>();
83✔
442
        step_option->name = "step";
83✔
443
        step_option->value = step_value;
83✔
444

445
        options.push_back(min_option);
83✔
446
        options.push_back(max_option);
83✔
447
        options.push_back(step_option);
83✔
448
    } else {
83✔
449
        options.push_back(min_option);
×
450
        options.push_back(max_option);
×
451
    }
452

453
    auto default_attr = param_handle->first_attribute("default");
83✔
454
    if (!default_attr) {
83✔
455
        LogDebug() << "default range missing for " << param_name;
×
456
        return std::make_tuple<>(false, options, default_option);
×
457
    }
458
    const char* default_str = default_attr->value();
83✔
459

460
    ParamValue default_value;
83✔
461
    default_value.set_from_xml(type_map[param_name], default_str);
83✔
462

463
    default_option.name = default_str;
83✔
464
    default_option.value = default_value;
83✔
465

466
    return std::make_tuple<>(true, options, default_option);
83✔
467
}
83✔
468

469
std::pair<bool, CameraDefinition::Option> CameraDefinition::find_default(
218✔
470
    const std::vector<std::shared_ptr<Option>>& options, const std::string& default_str)
471
{
472
    Option default_option{};
218✔
473

474
    bool found_default = false;
218✔
475
    for (auto& option : options) {
1,522✔
476
        if (option->value == default_str) {
1,304✔
477
            if (!found_default) {
218✔
478
                default_option = *option;
218✔
479
                found_default = true;
218✔
480
            } else {
481
                LogErr() << "Found more than one default";
×
482
                return std::make_pair<>(false, default_option);
×
483
            }
484
        }
485
    }
486
    if (!found_default) {
218✔
487
        LogErr() << "No default found";
×
488
        return std::make_pair<>(false, default_option);
×
489
    }
490
    return std::make_pair<>(true, default_option);
218✔
491
}
218✔
492

493
void CameraDefinition::assume_default_settings()
7✔
494
{
495
    reset_to_default_settings(false);
7✔
496
}
7✔
497

498
void CameraDefinition::reset_to_default_settings(bool needs_updating)
9✔
499
{
500
    _current_settings.clear();
9✔
501

502
    for (const auto& parameter : _parameter_map) {
137✔
503
        InternalCurrentSetting new_setting;
128✔
504
        new_setting.value = parameter.second->default_option.value;
128✔
505
        new_setting.needs_updating = needs_updating;
128✔
506
        _current_settings[parameter.first] = new_setting;
128✔
507
    }
128✔
508
}
9✔
509

510
bool CameraDefinition::get_all_settings(std::unordered_map<std::string, ParamValue>& settings)
2✔
511
{
512
    settings.clear();
2✔
513
    for (const auto& current_setting : _current_settings) {
33✔
514
        settings[current_setting.first] = current_setting.second.value;
31✔
515
    }
516

517
    return !settings.empty();
2✔
518
}
519

520
bool CameraDefinition::get_possible_settings(std::unordered_map<std::string, ParamValue>& settings)
106✔
521
{
522
    settings.clear();
106✔
523

524
    // Find all exclusions
525
    // TODO: use set instead of vector
526
    std::vector<std::string> exclusions{};
106✔
527

528
    for (const auto& parameter : _parameter_map) {
1,519✔
529
        for (const auto& option : parameter.second->options) {
5,605✔
530
            if (_current_settings[parameter.first].value == option->value) {
4,192✔
531
                for (const auto& exclusion : option->exclusions) {
952✔
532
                    // LogDebug() << "found exclusion for " << parameter.first
533
                    //            << "(" << option->value << "): " << exclusion;
534
                    exclusions.push_back(exclusion);
251✔
535
                }
536
            }
537
        }
538
    }
539

540
    for (const auto& setting : _current_settings) {
1,519✔
541
        bool excluded = false;
1,413✔
542
        for (const auto& exclusion : exclusions) {
4,901✔
543
            if (setting.first == exclusion) {
3,488✔
544
                excluded = true;
166✔
545
            }
546
        }
547
        if (!_parameter_map[setting.first]->is_control) {
1,413✔
548
            continue;
134✔
549
        }
550

551
        if (excluded) {
1,279✔
552
            continue;
165✔
553
        }
554
        settings[setting.first] = setting.second.value;
1,114✔
555
    }
556

557
    return !settings.empty();
106✔
558
}
106✔
559

560
bool CameraDefinition::set_setting(const std::string& name, const ParamValue& value)
72✔
561
{
562
    if (_parameter_map.find(name) == _parameter_map.end()) {
72✔
563
        LogErr() << "Unknown setting to set: " << name;
×
564
        return false;
×
565
    }
566

567
    // For range params, we need to verify the range.
568
    if (_parameter_map[name]->is_range) {
72✔
569
        // Check against the minimum
570
        if (value < _parameter_map[name]->options[0]->value) {
29✔
571
            LogErr() << "Chosen value smaller than minimum";
1✔
572
            return false;
1✔
573
        }
574

575
        if (value > _parameter_map[name]->options[1]->value) {
28✔
576
            LogErr() << "Chosen value bigger than maximum";
1✔
577
            return false;
1✔
578
        }
579

580
        // TODO: Check step as well, until now we have only seen steps of 1 in the wild though.
581
    }
582

583
    _current_settings[name].value = value;
70✔
584
    _current_settings[name].needs_updating = false;
70✔
585

586
    // Some param changes cause other params to change, so they need to be updated.
587
    // The camera definition just keeps track of these params but the actual param fetching
588
    // needs to happen outside of this class.
589
    for (const auto& update : _parameter_map[name]->updates) {
112✔
590
        if (_current_settings.find(update) == _current_settings.end()) {
42✔
591
            LogDebug() << "Update to '" << update << "' not understood.";
×
592
            continue;
×
593
        }
594
        _current_settings[update].needs_updating = true;
42✔
595
    }
596

597
    return true;
70✔
598
}
599

600
bool CameraDefinition::get_setting(const std::string& name, ParamValue& value)
56✔
601
{
602
    if (_current_settings.find(name) == _current_settings.end()) {
56✔
603
        LogErr() << "Unknown setting to get: " << name;
×
604
        return false;
×
605
    }
606

607
    if (!_current_settings.at(name).needs_updating) {
56✔
608
        value = _current_settings.at(name).value;
51✔
609
        return true;
51✔
610
    } else {
611
        return false;
5✔
612
    }
613
}
614

615
bool CameraDefinition::get_option_value(
12✔
616
    const std::string& param_name, const std::string& option_value, ParamValue& value)
617
{
618
    if (_parameter_map.find(param_name) == _parameter_map.end()) {
12✔
619
        LogErr() << "Unknown parameter to get option: " << param_name;
1✔
620
        return false;
1✔
621
    }
622

623
    for (const auto& option : _parameter_map[param_name]->options) {
63✔
624
        if (option->value == option_value) {
61✔
625
            value = option->value;
9✔
626
            return true;
9✔
627
        }
628
    }
629

630
    return false;
2✔
631
}
632

633
bool CameraDefinition::get_all_options(const std::string& name, std::vector<ParamValue>& values)
2✔
634
{
635
    values.clear();
2✔
636

637
    if (_parameter_map.find(name) == _parameter_map.end()) {
2✔
638
        LogErr() << "Unknown parameter to get all options";
×
639
        return false;
×
640
    }
641

642
    for (const auto& option : _parameter_map[name]->options) {
29✔
643
        values.push_back(option->value);
27✔
644
    }
645

646
    return true;
2✔
647
}
648

649
bool CameraDefinition::get_possible_options(
94✔
650
    const std::string& name, std::vector<ParamValue>& values)
651
{
652
    values.clear();
94✔
653

654
    if (_parameter_map.find(name) == _parameter_map.end()) {
94✔
655
        LogErr() << "Unknown parameter to get possible options";
×
656
        return false;
×
657
    }
658

659
    std::unordered_map<std::string, ParamValue> settings;
94✔
660
    if (!get_possible_settings(settings)) {
94✔
661
        return false;
×
662
    }
663
    if (settings.find(name) == settings.end()) {
94✔
664
        LogErr() << "Setting " << name << " currently not applicable";
1✔
665
        return false;
1✔
666
    }
667

668
    // Find all exclusions because excluded parameters need to be neglected for range
669
    // check below.
670
    // TODO: use set instead of vector
671
    std::vector<std::string> exclusions{};
93✔
672

673
    for (const auto& parameter : _parameter_map) {
1,322✔
674
        for (const auto& option : parameter.second->options) {
4,727✔
675
            if (_current_settings[parameter.first].needs_updating) {
3,498✔
676
                // LogWarn() << parameter.first << " needs updating";
677
                continue;
307✔
678
            }
679
            if (_current_settings[parameter.first].value == option->value) {
3,191✔
680
                for (const auto& exclusion : option->exclusions) {
780✔
681
                    // LogDebug() << "found exclusion for " << parameter.first
682
                    //            << "(" << option->value << "): " << exclusion;
683
                    exclusions.push_back(exclusion);
212✔
684
                }
685
            }
686
        }
687
    }
688

689
    // TODO: use set instead of vector for this
690
    std::vector<ParamValue> allowed_ranges{};
93✔
691

692
    // Check allowed ranges.
693
    for (const auto& parameter : _parameter_map) {
1,322✔
694
        if (!parameter.second->is_control) {
1,229✔
695
            continue;
109✔
696
        }
697

698
        bool excluded = false;
1,120✔
699
        for (const auto& exclusion : exclusions) {
3,690✔
700
            if (parameter.first == exclusion) {
2,570✔
701
                excluded = true;
134✔
702
            }
703
        }
704
        if (excluded) {
1,120✔
705
            continue;
134✔
706
        }
707

708
        for (const auto& option : parameter.second->options) {
3,806✔
709
            if (_current_settings[parameter.first].needs_updating) {
2,820✔
710
                // LogWarn() << parameter.first << " needs updating";
711
                continue;
301✔
712
            }
713
            // Only look at current set option.
714
            if (_current_settings[parameter.first].value == option->value) {
2,519✔
715
                // Go through parameter ranges but only concerning the parameter that
716
                // we're interested in.
717
                if (option->parameter_ranges.find(name) != option->parameter_ranges.end()) {
450✔
718
                    for (const auto& range : option->parameter_ranges[name]) {
40✔
719
                        allowed_ranges.push_back(range.second);
38✔
720
                    }
721
                }
722
            }
723
        }
724
    }
725

726
    // Intersect
727
    for (const auto& option : _parameter_map[name]->options) {
440✔
728
        bool option_allowed = false;
347✔
729
        for (const auto& allowed_range : allowed_ranges) {
1,407✔
730
            if (option->value == allowed_range) {
1,060✔
731
                option_allowed = true;
38✔
732
            }
733
        }
734
        if (option_allowed || allowed_ranges.empty()) {
347✔
735
            values.push_back(option->value);
334✔
736
        }
737
    }
738

739
    return true;
93✔
740
}
94✔
741

742
void CameraDefinition::get_unknown_params(std::vector<std::pair<std::string, ParamValue>>& params)
11✔
743
{
744
    params.clear();
11✔
745

746
    for (const auto& parameter : _parameter_map) {
179✔
747
        if (_current_settings[parameter.first].needs_updating) {
168✔
748
            params.push_back(std::make_pair<>(parameter.first, parameter.second->type));
91✔
749
        }
750
    }
751
}
11✔
752

753
void CameraDefinition::set_all_params_unknown()
1✔
754
{
755
    for (auto& parameter : _parameter_map) {
19✔
756
        _current_settings[parameter.first].needs_updating = true;
18✔
757
    }
758
}
1✔
759

760
bool CameraDefinition::is_setting_range(const std::string& name)
395✔
761
{
762
    if (_parameter_map.find(name) == _parameter_map.end()) {
395✔
763
        LogWarn() << "Setting " << name << " not found.";
×
764
        return false;
×
765
    }
766

767
    return _parameter_map[name]->is_range;
395✔
768
}
769

770
bool CameraDefinition::get_setting_str(const std::string& name, std::string& description)
133✔
771
{
772
    description.clear();
133✔
773

774
    if (_parameter_map.find(name) == _parameter_map.end()) {
133✔
775
        LogWarn() << "Setting " << name << " not found.";
1✔
776
        return false;
1✔
777
    }
778

779
    description = _parameter_map[name]->description;
132✔
780
    return true;
132✔
781
}
782

783
bool CameraDefinition::get_option_str(
124✔
784
    const std::string& setting_name, const std::string& option_name, std::string& description)
785
{
786
    description.clear();
124✔
787

788
    if (_parameter_map.find(setting_name) == _parameter_map.end()) {
124✔
789
        LogWarn() << "Setting " << setting_name << " not found.";
1✔
790
        return false;
1✔
791
    }
792

793
    for (const auto& option : _parameter_map[setting_name]->options) {
253✔
794
        if (option->value == option_name) {
252✔
795
            description = option->name;
122✔
796
            return true;
122✔
797
        }
798
    }
799
    LogWarn() << "Option " << option_name << " not found";
1✔
800
    return false;
1✔
801
}
802

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