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

mavlink / MAVSDK / 12385035894

18 Dec 2024 02:13AM UTC coverage: 43.594% (+4.9%) from 38.708%
12385035894

push

github

web-flow
Merge pull request #2386 from mavlink/pr-multiple-cameras

camera: support multiple cameras within one instance

1407 of 2127 new or added lines in 47 files covered. (66.15%)

48 existing lines in 8 files now uncovered.

13974 of 32055 relevant lines covered (43.59%)

290.15 hits per line

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

77.57
/src/mavsdk/plugins/camera/camera_definition.cpp
1
#include "log.h"
2
#include "camera_definition.h"
3

4
namespace mavsdk {
5

6
bool CameraDefinition::load_file(const std::string& filepath)
17✔
7
{
8
    tinyxml2::XMLError xml_error = _doc.LoadFile(filepath.c_str());
17✔
9
    if (xml_error != tinyxml2::XML_SUCCESS) {
17✔
10
        LogErr() << "tinyxml2::LoadFile failed: " << _doc.ErrorStr();
×
11
        return false;
×
12
    }
13

14
    return parse_xml();
17✔
15
}
16

17
bool CameraDefinition::load_string(const std::string& content)
2✔
18
{
19
    tinyxml2::XMLError xml_error = _doc.Parse(content.c_str());
2✔
20
    if (xml_error != tinyxml2::XML_SUCCESS) {
2✔
21
        LogErr() << "tinyxml2::Parse failed: " << _doc.ErrorStr();
×
22
        return false;
×
23
    }
24

25
    return parse_xml();
2✔
26
}
27

28
std::string CameraDefinition::get_model() const
4✔
29
{
30
    return _model;
4✔
31
}
32

33
std::string CameraDefinition::get_vendor() const
4✔
34
{
35
    return _vendor;
4✔
36
}
37

38
bool CameraDefinition::parse_xml()
19✔
39
{
40
    auto e_mavlinkcamera = _doc.FirstChildElement("mavlinkcamera");
19✔
41
    if (!e_mavlinkcamera) {
19✔
42
        LogErr() << "Tag mavlinkcamera not found";
×
43
        return false;
×
44
    }
45

46
    auto e_definition = e_mavlinkcamera->FirstChildElement("definition");
19✔
47
    if (!e_definition) {
19✔
48
        LogErr() << "definition not found";
×
49
        return false;
×
50
    }
51

52
    auto e_model = e_definition->FirstChildElement("model");
19✔
53
    if (!e_model) {
19✔
54
        LogErr() << "model not found";
×
55
        return false;
×
56
    }
57

58
    _model = e_model->GetText();
19✔
59

60
    auto e_vendor = e_definition->FirstChildElement("vendor");
19✔
61
    if (!e_vendor) {
19✔
62
        LogErr() << "vendor not found";
×
63
        return false;
×
64
    }
65

66
    _vendor = e_vendor->GetText();
19✔
67

68
    auto e_parameters = e_mavlinkcamera->FirstChildElement("parameters");
19✔
69
    if (!e_parameters) {
19✔
70
        LogErr() << "Tag parameters not found";
×
71
        return false;
×
72
    }
73

74
    std::unordered_map<std::string, std::string> type_map{};
19✔
75
    // We need all types first.
76
    for (auto e_parameter = e_parameters->FirstChildElement("parameter"); e_parameter != nullptr;
316✔
77
         e_parameter = e_parameter->NextSiblingElement("parameter")) {
297✔
78
        const char* param_name = e_parameter->Attribute("name");
297✔
79
        if (!param_name) {
297✔
80
            LogErr() << "name attribute missing";
×
81
            return false;
×
82
        }
83

84
        const char* type_str = e_parameter->Attribute("type");
297✔
85
        if (!type_str) {
297✔
86
            LogErr() << "type attribute missing";
×
87
            return false;
×
88
        }
89

90
        type_map[param_name] = type_str;
297✔
91
    }
92

93
    for (auto e_parameter = e_parameters->FirstChildElement("parameter"); e_parameter != nullptr;
316✔
94
         e_parameter = e_parameter->NextSiblingElement("parameter")) {
297✔
95
        auto new_parameter = std::make_shared<Parameter>();
297✔
96

97
        const char* param_name = e_parameter->Attribute("name");
297✔
98
        if (!param_name) {
297✔
99
            LogErr() << "name attribute missing";
×
100
            return false;
×
101
        }
102

103
        const char* type_str_res = e_parameter->Attribute("type");
297✔
104
        if (!type_str_res) {
297✔
105
            LogErr() << "type attribute missing for " << param_name;
×
106
            return false;
×
107
        }
108

109
        auto type_str = std::string(type_str_res);
594✔
110
        if (type_str == "string") {
297✔
UNCOV
111
            LogDebug() << "Ignoring string params: " << param_name;
×
UNCOV
112
            continue;
×
113
        }
114

115
        if (type_str == "custom") {
297✔
UNCOV
116
            LogDebug() << "Ignoring custom params: " << param_name;
×
UNCOV
117
            continue;
×
118
        }
119

120
        if (!new_parameter->type.set_empty_type_from_xml(type_str)) {
297✔
121
            LogErr() << "Unknown type attribute: " << type_str;
×
122
            return false;
×
123
        }
124

125
        // By default control is on.
126
        new_parameter->is_control = true;
297✔
127
        const char* control_str = e_parameter->Attribute("control");
297✔
128
        if (control_str) {
297✔
129
            if (std::string(control_str) == "0") {
59✔
130
                new_parameter->is_control = false;
59✔
131
            }
132
        }
133

134
        new_parameter->is_readonly = false;
297✔
135
        const char* readonly_str = e_parameter->Attribute("readonly");
297✔
136
        if (readonly_str) {
297✔
137
            if (std::string(readonly_str) == "1") {
10✔
138
                new_parameter->is_readonly = true;
10✔
139
            }
140
        }
141

142
        new_parameter->is_writeonly = false;
297✔
143
        const char* writeonly_str = e_parameter->Attribute("writeonly");
297✔
144
        if (writeonly_str) {
297✔
UNCOV
145
            if (std::string(writeonly_str) == "1") {
×
UNCOV
146
                new_parameter->is_writeonly = true;
×
147
            }
148
        }
149

150
        if (new_parameter->is_readonly && new_parameter->is_writeonly) {
297✔
151
            LogErr() << "parameter can't be readonly and writeonly";
×
152
            return false;
×
153
        }
154

155
        // Be definition custom types do not have control.
156
        if (std::string(type_map[param_name]) == "custom") {
297✔
157
            new_parameter->is_control = false;
×
158
        }
159

160
        auto e_description = e_parameter->FirstChildElement("description");
297✔
161
        if (!e_description) {
297✔
162
            LogErr() << "Description missing";
×
163
            return false;
×
164
        }
165

166
        new_parameter->description = e_description->GetText();
297✔
167

168
        // LogDebug() << "Found: " << new_parameter->description
169
        //            << " (" << param_name
170
        //            << ", control: " << (new_parameter->is_control ? "yes" : "no")
171
        //            << ", readonly: " << (new_parameter->is_readonly ? "yes" : "no")
172
        //            << ", writeonly: " << (new_parameter->is_writeonly ? "yes" : "no")
173
        //            << ")";
174

175
        auto e_updates = e_parameter->FirstChildElement("updates");
297✔
176
        if (e_updates) {
297✔
177
            for (auto e_update = e_updates->FirstChildElement("update"); e_update != nullptr;
190✔
178
                 e_update = e_update->NextSiblingElement("update")) {
140✔
179
                // LogDebug() << "Updates: " << e_update->GetText();
180
                new_parameter->updates.emplace_back(e_update->GetText());
140✔
181
            }
182
        }
183

184
        const char* default_str = e_parameter->Attribute("default");
297✔
185
        if (!default_str) {
297✔
UNCOV
186
            LogWarn() << "Default missing for " << param_name;
×
UNCOV
187
            continue;
×
188
        }
189

190
        auto get_default_opt = [&]() {
297✔
191
            auto maybe_default = find_default(new_parameter->options, default_str);
642✔
192

193
            if (!maybe_default.first) {
214✔
194
                LogWarn() << "Default not found for " << param_name;
×
195
                return std::optional<Option>{};
×
196
            }
197

198
            return std::optional{maybe_default.second};
214✔
199
        };
214✔
200

201
        auto e_options = e_parameter->FirstChildElement("options");
297✔
202
        if (e_options) {
297✔
203
            auto maybe_options = parse_options(e_options, param_name, type_map);
642✔
204
            if (!maybe_options.first) {
214✔
205
                continue;
×
206
            }
207
            new_parameter->options = maybe_options.second;
214✔
208

209
            if (auto default_option = get_default_opt()) {
214✔
210
                new_parameter->default_option = *default_option;
214✔
211
            } else {
212
                return false;
×
213
            }
214✔
214
        } else if (type_str == "bool") {
297✔
215
            // Automaticaly create bool options if the parameter type is bool as per documentation.
216
            Option true_option;
×
217
            true_option.name = "on";
×
218
            true_option.value.set<uint8_t>(true);
×
219
            Option false_option;
×
220
            true_option.name = "off";
×
221
            false_option.value.set<uint8_t>(false);
×
222

223
            new_parameter->options = {
×
224
                std::make_shared<Option>(std::move(true_option)),
×
225
                std::make_shared<Option>(std::move(false_option))};
×
226

227
            if (auto default_option = get_default_opt()) {
×
228
                new_parameter->default_option = *default_option;
×
229
            } else {
230
                return false;
×
231
            }
×
232
        } else {
×
233
            auto maybe_range_options = parse_range_options(e_parameter, param_name, type_map);
249✔
234
            if (!std::get<0>(maybe_range_options)) {
83✔
NEW
235
                LogWarn() << "Range not found for: " << param_name;
×
UNCOV
236
                continue;
×
237
            }
238

239
            new_parameter->options = std::get<1>(maybe_range_options);
83✔
240
            new_parameter->is_range = true;
83✔
241
            new_parameter->default_option = std::get<2>(maybe_range_options);
83✔
242
        }
83✔
243

244
        _parameter_map[param_name] = new_parameter;
297✔
245

246
        InternalCurrentSetting empty_setting{};
297✔
247
        empty_setting.needs_updating = true;
297✔
248
        _current_settings[param_name] = empty_setting;
297✔
249
    }
297✔
250

251
    return true;
19✔
252
}
19✔
253

254
std::pair<bool, std::vector<std::shared_ptr<CameraDefinition::Option>>>
255
CameraDefinition::parse_options(
214✔
256
    const tinyxml2::XMLElement* options_handle,
257
    const std::string& param_name,
258
    std::unordered_map<std::string, std::string>& type_map)
259
{
260
    std::vector<std::shared_ptr<Option>> options{};
214✔
261

262
    for (auto e_option = options_handle->FirstChildElement("option"); e_option != nullptr;
1,451✔
263
         e_option = e_option->NextSiblingElement("option")) {
1,237✔
264
        const char* option_name = e_option->Attribute("name");
1,237✔
265
        if (!option_name) {
1,237✔
266
            LogErr() << "no option name given";
×
267
            return std::make_pair<>(false, options);
×
268
        }
269

270
        const char* option_value = e_option->Attribute("value");
1,237✔
271
        if (!option_value) {
1,237✔
272
            LogErr() << "no option value given";
×
273
            return std::make_pair<>(false, options);
×
274
        }
275

276
        auto new_option = std::make_shared<Option>();
1,237✔
277

278
        new_option->name = option_name;
1,237✔
279

280
        new_option->value.set_from_xml(type_map[param_name], option_value);
1,237✔
281

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

284
        auto e_exclusions = e_option->FirstChildElement("exclusions");
1,237✔
285
        if (e_exclusions) {
1,237✔
286
            for (auto e_exclude = e_exclusions->FirstChildElement("exclude"); e_exclude != nullptr;
314✔
287
                 e_exclude = e_exclude->NextSiblingElement("exclude")) {
187✔
288
                // LogDebug() << "Exclude: " << e_exclude->GetText();
289
                new_option->exclusions.emplace_back(e_exclude->GetText());
187✔
290
            }
291
        }
292

293
        auto e_parameterranges = e_option->FirstChildElement("parameterranges");
1,237✔
294
        if (e_parameterranges) {
1,237✔
295
            for (auto e_parameterrange = e_parameterranges->FirstChildElement("parameterrange");
340✔
296
                 e_parameterrange != nullptr;
680✔
297
                 e_parameterrange = e_parameterrange->NextSiblingElement("parameterrange")) {
340✔
298
                const char* roption_parameter_str = e_parameterrange->Attribute("parameter");
340✔
299
                if (!roption_parameter_str) {
340✔
300
                    LogErr() << "missing roption parameter name";
×
301
                    return std::make_pair<>(false, options);
×
302
                }
303

304
                ParameterRange new_parameter_range;
340✔
305

306
                for (auto e_roption = e_parameterrange->FirstChildElement("roption");
340✔
307
                     e_roption != nullptr;
4,980✔
308
                     e_roption = e_roption->NextSiblingElement("roption")) {
4,640✔
309
                    const char* roption_name_str = e_roption->Attribute("name");
4,640✔
310
                    if (!roption_name_str) {
4,640✔
311
                        LogErr() << "missing roption name attribute";
×
312
                        return std::make_pair<>(false, options);
×
313
                    }
314

315
                    const char* roption_value_str = e_roption->Attribute("value");
4,640✔
316
                    if (!roption_value_str) {
4,640✔
317
                        LogErr() << "missing roption value attribute";
×
318
                        return std::make_pair<>(false, options);
×
319
                    }
320

321
                    if (type_map.find(roption_parameter_str) == type_map.end()) {
4,640✔
322
                        LogErr() << "unknown roption type";
×
323
                        return std::make_pair<>(false, options);
×
324
                    }
325

326
                    ParamValue new_param_value;
4,640✔
327
                    new_param_value.set_from_xml(
13,920✔
328
                        type_map[roption_parameter_str], roption_value_str);
9,280✔
329
                    new_parameter_range[roption_name_str] = new_param_value;
4,640✔
330

331
                    // LogDebug() << "range option: "
332
                    //            << roption_name_str
333
                    //            << " -> "
334
                    //            << new_param_value
335
                    //            << " (" << new_param_value.typestr() << ")";
336
                }
4,640✔
337

338
                new_option->parameter_ranges[roption_parameter_str] = new_parameter_range;
340✔
339

340
                // LogDebug() << "adding to: " << roption_parameter_str;
341
            }
340✔
342
        }
343

344
        options.push_back(new_option);
1,237✔
345
    }
1,237✔
346
    return std::make_pair<>(true, options);
214✔
347
}
214✔
348

349
std::tuple<bool, std::vector<std::shared_ptr<CameraDefinition::Option>>, CameraDefinition::Option>
350
CameraDefinition::parse_range_options(
83✔
351
    const tinyxml2::XMLElement* param_handle,
352
    const std::string& param_name,
353
    std::unordered_map<std::string, std::string>& type_map)
354
{
355
    std::vector<std::shared_ptr<Option>> options{};
83✔
356
    Option default_option{};
83✔
357

358
    const char* min_str = param_handle->Attribute("min");
83✔
359
    if (!min_str) {
83✔
NEW
360
        LogDebug() << "min range missing for " << param_name;
×
UNCOV
361
        return std::make_tuple<>(false, options, default_option);
×
362
    }
363

364
    ParamValue min_value;
83✔
365
    min_value.set_from_xml(type_map[param_name], min_str);
83✔
366

367
    const char* max_str = param_handle->Attribute("max");
83✔
368
    if (!max_str) {
83✔
NEW
369
        LogDebug() << "max range missing for " << param_name;
×
370
        return std::make_tuple<>(false, options, default_option);
×
371
    }
372

373
    auto min_option = std::make_shared<Option>();
83✔
374
    min_option->name = "min";
83✔
375
    min_option->value = min_value;
83✔
376

377
    ParamValue max_value;
83✔
378
    max_value.set_from_xml(type_map[param_name], max_str);
83✔
379

380
    auto max_option = std::make_shared<Option>();
83✔
381
    max_option->name = "max";
83✔
382
    max_option->value = max_value;
83✔
383

384
    const char* step_str = param_handle->Attribute("step");
83✔
385
    if (!step_str) {
83✔
UNCOV
386
        LogDebug() << "step range missing for " << param_name;
×
387
    }
388

389
    if (step_str) {
83✔
390
        ParamValue step_value;
83✔
391
        step_value.set_from_xml(type_map[param_name], step_str);
83✔
392

393
        auto step_option = std::make_shared<Option>();
83✔
394
        step_option->name = "step";
83✔
395
        step_option->value = step_value;
83✔
396

397
        options.push_back(min_option);
83✔
398
        options.push_back(max_option);
83✔
399
        options.push_back(step_option);
83✔
400
    } else {
83✔
UNCOV
401
        options.push_back(min_option);
×
UNCOV
402
        options.push_back(max_option);
×
403
    }
404

405
    const char* default_str = param_handle->Attribute("default");
83✔
406
    if (!default_str) {
83✔
407
        LogDebug() << "default range missing for " << param_name;
×
408
        return std::make_tuple<>(false, options, default_option);
×
409
    }
410

411
    ParamValue default_value;
83✔
412
    default_value.set_from_xml(type_map[param_name], default_str);
83✔
413

414
    default_option.name = default_str;
83✔
415
    default_option.value = default_value;
83✔
416

417
    return std::make_tuple<>(true, options, default_option);
83✔
418
}
83✔
419

420
std::pair<bool, CameraDefinition::Option> CameraDefinition::find_default(
214✔
421
    const std::vector<std::shared_ptr<Option>>& options, const std::string& default_str)
422
{
423
    Option default_option{};
214✔
424

425
    bool found_default = false;
214✔
426
    for (auto& option : options) {
1,451✔
427
        if (option->value == default_str) {
1,237✔
428
            if (!found_default) {
214✔
429
                default_option = *option;
214✔
430
                found_default = true;
214✔
431
            } else {
432
                LogErr() << "Found more than one default";
×
433
                return std::make_pair<>(false, default_option);
×
434
            }
435
        }
436
    }
437
    if (!found_default) {
214✔
438
        LogErr() << "No default found";
×
439
        return std::make_pair<>(false, default_option);
×
440
    }
441
    return std::make_pair<>(true, default_option);
214✔
442
}
214✔
443

444
void CameraDefinition::assume_default_settings()
6✔
445
{
446
    reset_to_default_settings(false);
6✔
447
}
6✔
448

449
void CameraDefinition::reset_to_default_settings(bool needs_updating)
8✔
450
{
451
    _current_settings.clear();
8✔
452

453
    for (const auto& parameter : _parameter_map) {
132✔
454
        InternalCurrentSetting new_setting;
124✔
455
        new_setting.value = parameter.second->default_option.value;
124✔
456
        new_setting.needs_updating = needs_updating;
124✔
457
        _current_settings[parameter.first] = new_setting;
124✔
458
    }
124✔
459
}
8✔
460

461
bool CameraDefinition::get_all_settings(std::unordered_map<std::string, ParamValue>& settings)
2✔
462
{
463
    settings.clear();
2✔
464
    for (const auto& current_setting : _current_settings) {
33✔
465
        settings[current_setting.first] = current_setting.second.value;
31✔
466
    }
467

468
    return !settings.empty();
2✔
469
}
470

471
bool CameraDefinition::get_possible_settings(std::unordered_map<std::string, ParamValue>& settings)
119✔
472
{
473
    settings.clear();
119✔
474

475
    // Find all exclusions
476
    // TODO: use set instead of vector
477
    std::vector<std::string> exclusions{};
119✔
478

479
    for (const auto& parameter : _parameter_map) {
1,701✔
480
        for (const auto& option : parameter.second->options) {
6,216✔
481
            if (_current_settings[parameter.first].value == option->value) {
4,634✔
482
                for (const auto& exclusion : option->exclusions) {
847✔
483
                    // LogDebug() << "found exclusion for " << parameter.first
484
                    //            << "(" << option->value << "): " << exclusion;
485
                    exclusions.push_back(exclusion);
166✔
486
                }
487
            }
488
        }
489
    }
490

491
    for (const auto& setting : _current_settings) {
1,701✔
492
        bool excluded = false;
1,582✔
493
        for (const auto& exclusion : exclusions) {
3,965✔
494
            if (setting.first == exclusion) {
2,383✔
495
                excluded = true;
166✔
496
            }
497
        }
498
        if (!_parameter_map[setting.first]->is_control) {
1,582✔
499
            continue;
147✔
500
        }
501

502
        if (excluded) {
1,435✔
503
            continue;
165✔
504
        }
505
        settings[setting.first] = setting.second.value;
1,270✔
506
    }
507

508
    return !settings.empty();
119✔
509
}
119✔
510

511
bool CameraDefinition::set_setting(const std::string& name, const ParamValue& value)
61✔
512
{
513
    if (_parameter_map.find(name) == _parameter_map.end()) {
61✔
UNCOV
514
        LogErr() << "Unknown setting to set: " << name;
×
515
        return false;
×
516
    }
517

518
    // For range params, we need to verify the range.
519
    if (_parameter_map[name]->is_range) {
61✔
520
        // Check against the minimum
521
        if (value < _parameter_map[name]->options[0]->value) {
24✔
522
            LogErr() << "Chosen value smaller than minimum";
1✔
523
            return false;
1✔
524
        }
525

526
        if (value > _parameter_map[name]->options[1]->value) {
23✔
527
            LogErr() << "Chosen value bigger than maximum";
1✔
528
            return false;
1✔
529
        }
530

531
        // TODO: Check step as well, until now we have only seen steps of 1 in the wild though.
532
    }
533

534
    _current_settings[name].value = value;
59✔
535
    _current_settings[name].needs_updating = false;
59✔
536

537
    // Some param changes cause other params to change, so they need to be updated.
538
    // The camera definition just keeps track of these params but the actual param fetching
539
    // needs to happen outside of this class.
540
    for (const auto& update : _parameter_map[name]->updates) {
101✔
541
        if (_current_settings.find(update) == _current_settings.end()) {
42✔
NEW
542
            LogDebug() << "Update to '" << update << "' not understood.";
×
UNCOV
543
            continue;
×
544
        }
545
        _current_settings[update].needs_updating = true;
42✔
546
    }
547

548
    return true;
59✔
549
}
550

551
bool CameraDefinition::get_setting(const std::string& name, ParamValue& value)
62✔
552
{
553
    if (_current_settings.find(name) == _current_settings.end()) {
62✔
UNCOV
554
        LogErr() << "Unknown setting to get: " << name;
×
555
        return false;
×
556
    }
557

558
    if (!_current_settings.at(name).needs_updating) {
62✔
559
        value = _current_settings.at(name).value;
62✔
560
        return true;
62✔
561
    } else {
562
        return false;
×
563
    }
564
}
565

566
bool CameraDefinition::get_option_value(
12✔
567
    const std::string& param_name, const std::string& option_value, ParamValue& value)
568
{
569
    if (_parameter_map.find(param_name) == _parameter_map.end()) {
12✔
570
        LogErr() << "Unknown parameter to get option: " << param_name;
1✔
571
        return false;
1✔
572
    }
573

574
    for (const auto& option : _parameter_map[param_name]->options) {
63✔
575
        if (option->value == option_value) {
61✔
576
            value = option->value;
9✔
577
            return true;
9✔
578
        }
579
    }
580

581
    return false;
2✔
582
}
583

584
bool CameraDefinition::get_all_options(const std::string& name, std::vector<ParamValue>& values)
2✔
585
{
586
    values.clear();
2✔
587

588
    if (_parameter_map.find(name) == _parameter_map.end()) {
2✔
589
        LogErr() << "Unknown parameter to get all options";
×
590
        return false;
×
591
    }
592

593
    for (const auto& option : _parameter_map[name]->options) {
29✔
594
        values.push_back(option->value);
27✔
595
    }
596

597
    return true;
2✔
598
}
599

600
bool CameraDefinition::get_possible_options(
106✔
601
    const std::string& name, std::vector<ParamValue>& values)
602
{
603
    values.clear();
106✔
604

605
    if (_parameter_map.find(name) == _parameter_map.end()) {
106✔
606
        LogErr() << "Unknown parameter to get possible options";
×
607
        return false;
×
608
    }
609

610
    std::unordered_map<std::string, ParamValue> settings;
106✔
611
    if (!get_possible_settings(settings)) {
106✔
612
        return false;
×
613
    }
614
    if (settings.find(name) == settings.end()) {
106✔
615
        LogErr() << "Setting " << name << " currently not applicable";
1✔
616
        return false;
1✔
617
    }
618

619
    // Find all exclusions because excluded parameters need to be neglected for range
620
    // check below.
621
    // TODO: use set instead of vector
622
    std::vector<std::string> exclusions{};
105✔
623

624
    for (const auto& parameter : _parameter_map) {
1,490✔
625
        for (const auto& option : parameter.second->options) {
5,291✔
626
            if (_current_settings[parameter.first].needs_updating) {
3,906✔
627
                // LogWarn() << parameter.first << " needs updating";
628
                continue;
186✔
629
            }
630
            if (_current_settings[parameter.first].value == option->value) {
3,720✔
631
                for (const auto& exclusion : option->exclusions) {
695✔
632
                    // LogDebug() << "found exclusion for " << parameter.first
633
                    //            << "(" << option->value << "): " << exclusion;
634
                    exclusions.push_back(exclusion);
134✔
635
                }
636
            }
637
        }
638
    }
639

640
    // TODO: use set instead of vector for this
641
    std::vector<ParamValue> allowed_ranges{};
105✔
642

643
    // Check allowed ranges.
644
    for (const auto& parameter : _parameter_map) {
1,490✔
645
        if (!parameter.second->is_control) {
1,385✔
646
            continue;
121✔
647
        }
648

649
        bool excluded = false;
1,264✔
650
        for (const auto& exclusion : exclusions) {
2,898✔
651
            if (parameter.first == exclusion) {
1,634✔
652
                excluded = true;
134✔
653
            }
654
        }
655
        if (excluded) {
1,264✔
656
            continue;
134✔
657
        }
658

659
        for (const auto& option : parameter.second->options) {
4,334✔
660
            if (_current_settings[parameter.first].needs_updating) {
3,204✔
661
                // LogWarn() << parameter.first << " needs updating";
662
                continue;
180✔
663
            }
664
            // Only look at current set option.
665
            if (_current_settings[parameter.first].value == option->value) {
3,024✔
666
                // Go through parameter ranges but only concerning the parameter that
667
                // we're interested in.
668
                if (option->parameter_ranges.find(name) != option->parameter_ranges.end()) {
521✔
669
                    for (const auto& range : option->parameter_ranges[name]) {
40✔
670
                        allowed_ranges.push_back(range.second);
38✔
671
                    }
672
                }
673
            }
674
        }
675
    }
676

677
    // Intersect
678
    for (const auto& option : _parameter_map[name]->options) {
484✔
679
        bool option_allowed = false;
379✔
680
        for (const auto& allowed_range : allowed_ranges) {
1,439✔
681
            if (option->value == allowed_range) {
1,060✔
682
                option_allowed = true;
38✔
683
            }
684
        }
685
        if (option_allowed || allowed_ranges.empty()) {
379✔
686
            values.push_back(option->value);
366✔
687
        }
688
    }
689

690
    return true;
105✔
691
}
106✔
692

693
void CameraDefinition::get_unknown_params(std::vector<std::pair<std::string, ParamValue>>& params)
10✔
694
{
695
    params.clear();
10✔
696

697
    for (const auto& parameter : _parameter_map) {
165✔
698
        if (_current_settings[parameter.first].needs_updating) {
155✔
699
            params.push_back(std::make_pair<>(parameter.first, parameter.second->type));
84✔
700
        }
701
    }
702
}
10✔
703

704
void CameraDefinition::set_all_params_unknown()
1✔
705
{
706
    for (auto& parameter : _parameter_map) {
19✔
707
        _current_settings[parameter.first].needs_updating = true;
18✔
708
    }
709
}
1✔
710

711
bool CameraDefinition::is_setting_range(const std::string& name)
471✔
712
{
713
    if (_parameter_map.find(name) == _parameter_map.end()) {
471✔
UNCOV
714
        LogWarn() << "Setting " << name << " not found.";
×
715
        return false;
×
716
    }
717

718
    return _parameter_map[name]->is_range;
471✔
719
}
720

721
bool CameraDefinition::get_setting_str(const std::string& name, std::string& description)
161✔
722
{
723
    description.clear();
161✔
724

725
    if (_parameter_map.find(name) == _parameter_map.end()) {
161✔
726
        LogWarn() << "Setting " << name << " not found.";
1✔
727
        return false;
1✔
728
    }
729

730
    description = _parameter_map[name]->description;
160✔
731
    return true;
160✔
732
}
733

734
bool CameraDefinition::get_option_str(
141✔
735
    const std::string& setting_name, const std::string& option_name, std::string& description)
736
{
737
    description.clear();
141✔
738

739
    if (_parameter_map.find(setting_name) == _parameter_map.end()) {
141✔
740
        LogWarn() << "Setting " << setting_name << " not found.";
1✔
741
        return false;
1✔
742
    }
743

744
    for (const auto& option : _parameter_map[setting_name]->options) {
278✔
745
        if (option->value == option_name) {
277✔
746
            description = option->name;
139✔
747
            return true;
139✔
748
        }
749
    }
750
    LogWarn() << "Option " << option_name << " not found";
1✔
751
    return false;
1✔
752
}
753

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