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

mavlink / MAVSDK / 5121034703

pending completion
5121034703

Pull #2056

github

web-flow
Merge 8ab0cda3e into ead0227f4
Pull Request #2056: The bool parameter now automatically creates on/off options.

27 of 27 new or added lines in 1 file covered. (100.0%)

7724 of 24903 relevant lines covered (31.02%)

20.19 hits per line

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

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

4
namespace mavsdk {
5

6
CameraDefinition::CameraDefinition() {}
17✔
7

8
CameraDefinition::~CameraDefinition() {}
17✔
9

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

18
    return parse_xml();
15✔
19
}
20

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

29
    return parse_xml();
2✔
30
}
31

32
std::string CameraDefinition::get_model() const
4✔
33
{
34
    std::lock_guard<std::mutex> lock(_mutex);
8✔
35

36
    return _model;
4✔
37
}
38

39
std::string CameraDefinition::get_vendor() const
4✔
40
{
41
    std::lock_guard<std::mutex> lock(_mutex);
8✔
42

43
    return _vendor;
4✔
44
}
45

46
bool CameraDefinition::parse_xml()
17✔
47
{
48
    std::lock_guard<std::mutex> lock(_mutex);
34✔
49

50
    auto e_mavlinkcamera = _doc.FirstChildElement("mavlinkcamera");
17✔
51
    if (!e_mavlinkcamera) {
17✔
52
        LogErr() << "Tag mavlinkcamera not found";
×
53
        return false;
×
54
    }
55

56
    auto e_definition = e_mavlinkcamera->FirstChildElement("definition");
17✔
57
    if (!e_definition) {
17✔
58
        LogErr() << "definition not found";
×
59
        return false;
×
60
    }
61

62
    auto e_model = e_definition->FirstChildElement("model");
17✔
63
    if (!e_model) {
17✔
64
        LogErr() << "model not found";
×
65
        return false;
×
66
    }
67

68
    _model = e_model->GetText();
17✔
69

70
    auto e_vendor = e_definition->FirstChildElement("vendor");
17✔
71
    if (!e_vendor) {
17✔
72
        LogErr() << "vendor not found";
×
73
        return false;
×
74
    }
75

76
    _vendor = e_vendor->GetText();
17✔
77

78
    auto e_parameters = e_mavlinkcamera->FirstChildElement("parameters");
17✔
79
    if (!e_parameters) {
17✔
80
        LogErr() << "Tag parameters not found";
×
81
        return false;
×
82
    }
83

84
    std::unordered_map<std::string, std::string> type_map{};
34✔
85
    // We need all types first.
86
    for (auto e_parameter = e_parameters->FirstChildElement("parameter"); e_parameter != nullptr;
338✔
87
         e_parameter = e_parameter->NextSiblingElement("parameter")) {
321✔
88
        const char* param_name = e_parameter->Attribute("name");
321✔
89
        if (!param_name) {
321✔
90
            LogErr() << "name attribute missing";
×
91
            return false;
×
92
        }
93

94
        const char* type_str = e_parameter->Attribute("type");
321✔
95
        if (!type_str) {
321✔
96
            LogErr() << "type attribute missing";
×
97
            return false;
×
98
        }
99

100
        type_map[param_name] = type_str;
321✔
101
    }
102

103
    for (auto e_parameter = e_parameters->FirstChildElement("parameter"); e_parameter != nullptr;
338✔
104
         e_parameter = e_parameter->NextSiblingElement("parameter")) {
321✔
105
        auto new_parameter = std::make_shared<Parameter>();
321✔
106

107
        const char* param_name = e_parameter->Attribute("name");
321✔
108
        if (!param_name) {
321✔
109
            LogErr() << "name attribute missing";
×
110
            return false;
×
111
        }
112

113
        const char* type_str_res = e_parameter->Attribute("type");
321✔
114
        if (!type_str_res) {
321✔
115
            LogErr() << "type attribute missing for " << param_name;
×
116
            return false;
×
117
        }
118

119
        auto type_str = std::string(type_str_res);
642✔
120
        if (type_str == "string") {
321✔
121
            LogDebug() << "Ignoring string params: " << param_name;
10✔
122
            continue;
10✔
123
        }
124

125
        if (type_str == "custom") {
311✔
126
            LogDebug() << "Ignoring custom params: " << param_name;
20✔
127
            continue;
20✔
128
        }
129

130
        if (!new_parameter->type.set_empty_type_from_xml(type_str)) {
291✔
131
            LogErr() << "Unknown type attribute: " << type_str;
×
132
            return false;
×
133
        }
134

135
        // By default control is on.
136
        new_parameter->is_control = true;
291✔
137
        const char* control_str = e_parameter->Attribute("control");
291✔
138
        if (control_str) {
291✔
139
            if (std::string(control_str) == "0") {
77✔
140
                new_parameter->is_control = false;
77✔
141
            }
142
        }
143

144
        new_parameter->is_readonly = false;
291✔
145
        const char* readonly_str = e_parameter->Attribute("readonly");
291✔
146
        if (readonly_str) {
291✔
147
            if (std::string(readonly_str) == "1") {
10✔
148
                new_parameter->is_readonly = true;
10✔
149
            }
150
        }
151

152
        new_parameter->is_writeonly = false;
291✔
153
        const char* writeonly_str = e_parameter->Attribute("writeonly");
291✔
154
        if (writeonly_str) {
291✔
155
            if (std::string(writeonly_str) == "1") {
10✔
156
                new_parameter->is_writeonly = true;
10✔
157
            }
158
        }
159

160
        if (new_parameter->is_readonly && new_parameter->is_writeonly) {
291✔
161
            LogErr() << "parameter can't be readonly and writeonly";
×
162
            return false;
×
163
        }
164

165
        // Be definition custom types do not have control.
166
        if (std::string(type_map[param_name]) == "custom") {
291✔
167
            new_parameter->is_control = false;
×
168
        }
169

170
        auto e_description = e_parameter->FirstChildElement("description");
291✔
171
        if (!e_description) {
291✔
172
            LogErr() << "Description missing";
×
173
            return false;
×
174
        }
175

176
        new_parameter->description = e_description->GetText();
291✔
177

178
        // LogDebug() << "Found: " << new_parameter->description
179
        //            << " (" << param_name
180
        //            << ", control: " << (new_parameter->is_control ? "yes" : "no")
181
        //            << ", readonly: " << (new_parameter->is_readonly ? "yes" : "no")
182
        //            << ", writeonly: " << (new_parameter->is_writeonly ? "yes" : "no")
183
        //            << ")";
184

185
        auto e_updates = e_parameter->FirstChildElement("updates");
291✔
186
        if (e_updates) {
291✔
187
            for (auto e_update = e_updates->FirstChildElement("update"); e_update != nullptr;
190✔
188
                 e_update = e_update->NextSiblingElement("update")) {
140✔
189
                // LogDebug() << "Updates: " << e_update->GetText();
190
                new_parameter->updates.push_back(e_update->GetText());
140✔
191
            }
192
        }
193

194
        const char* default_str = e_parameter->Attribute("default");
291✔
195
        if (!default_str) {
291✔
196
            LogWarn() << "Default missing for " << param_name;
10✔
197
            continue;
10✔
198
        }
199

200
        auto get_default_opt = [&]() {
281✔
201
            auto maybe_default = find_default(new_parameter->options, default_str);
780✔
202

203
            if (!maybe_default.first) {
195✔
204
                LogWarn() << "Default not found for " << param_name;
×
205
                return std::optional<Option>{};
×
206
            }
207

208
            return std::optional{maybe_default.second};
195✔
209
        };
281✔
210

211
        auto e_options = e_parameter->FirstChildElement("options");
281✔
212
        if (e_options) {
281✔
213
            auto maybe_options = parse_options(e_options, param_name, type_map);
585✔
214
            if (!maybe_options.first) {
195✔
215
                continue;
×
216
            }
217
            new_parameter->options = maybe_options.second;
195✔
218

219
            if (auto default_option = get_default_opt()) {
195✔
220
                new_parameter->default_option = *default_option;
195✔
221
            } else {
222
                return false;
×
223
            }
224
        } else if (type_str == "bool") {
86✔
225
            // Automaticaly create bool options if the parameter type is bool as per documentation.
226
            Option true_option;
×
227
            true_option.name = "on";
×
228
            true_option.value.set<uint8_t>(true);
×
229
            Option false_option;
×
230
            true_option.name = "off";
×
231
            false_option.value.set<uint8_t>(false);
×
232

233
            new_parameter->options = {
×
234
                std::make_shared<Option>(std::move(true_option)),
×
235
                std::make_shared<Option>(std::move(false_option))};
×
236

237
            if (auto default_option = get_default_opt()) {
×
238
                new_parameter->default_option = *default_option;
×
239
            } else {
240
                return false;
×
241
            }
242
        } else {
243
            auto maybe_range_options = parse_range_options(e_parameter, param_name, type_map);
258✔
244
            if (!std::get<0>(maybe_range_options)) {
86✔
245
                LogWarn() << "Not found: " << param_name;
20✔
246
                continue;
20✔
247
            }
248

249
            new_parameter->options = std::get<1>(maybe_range_options);
66✔
250
            new_parameter->is_range = true;
66✔
251
            new_parameter->default_option = std::get<2>(maybe_range_options);
66✔
252
        }
253

254
        _parameter_map[param_name] = new_parameter;
261✔
255

256
        InternalCurrentSetting empty_setting{};
522✔
257
        empty_setting.needs_updating = true;
261✔
258
        _current_settings[param_name] = empty_setting;
261✔
259
    }
260

261
    return true;
17✔
262
}
263

264
std::pair<bool, std::vector<std::shared_ptr<CameraDefinition::Option>>>
265
CameraDefinition::parse_options(
195✔
266
    const tinyxml2::XMLElement* options_handle,
267
    const std::string& param_name,
268
    std::unordered_map<std::string, std::string>& type_map)
269
{
270
    std::vector<std::shared_ptr<Option>> options{};
390✔
271

272
    for (auto e_option = options_handle->FirstChildElement("option"); e_option != nullptr;
1,392✔
273
         e_option = e_option->NextSiblingElement("option")) {
1,197✔
274
        const char* option_name = e_option->Attribute("name");
1,197✔
275
        if (!option_name) {
1,197✔
276
            LogErr() << "no option name given";
×
277
            return std::make_pair<>(false, options);
×
278
        }
279

280
        const char* option_value = e_option->Attribute("value");
1,197✔
281
        if (!option_value) {
1,197✔
282
            LogErr() << "no option value given";
×
283
            return std::make_pair<>(false, options);
×
284
        }
285

286
        auto new_option = std::make_shared<Option>();
1,197✔
287

288
        new_option->name = option_name;
1,197✔
289

290
        new_option->value.set_from_xml(type_map[param_name], option_value);
1,197✔
291

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

294
        auto e_exclusions = e_option->FirstChildElement("exclusions");
1,197✔
295
        if (e_exclusions) {
1,197✔
296
            for (auto e_exclude = e_exclusions->FirstChildElement("exclude"); e_exclude != nullptr;
302✔
297
                 e_exclude = e_exclude->NextSiblingElement("exclude")) {
181✔
298
                // LogDebug() << "Exclude: " << e_exclude->GetText();
299
                new_option->exclusions.push_back(e_exclude->GetText());
181✔
300
            }
301
        }
302

303
        auto e_parameterranges = e_option->FirstChildElement("parameterranges");
1,197✔
304
        if (e_parameterranges) {
1,197✔
305
            for (auto e_parameterrange = e_parameterranges->FirstChildElement("parameterrange");
680✔
306
                 e_parameterrange != nullptr;
680✔
307
                 e_parameterrange = e_parameterrange->NextSiblingElement("parameterrange")) {
340✔
308
                const char* roption_parameter_str = e_parameterrange->Attribute("parameter");
340✔
309
                if (!roption_parameter_str) {
340✔
310
                    LogErr() << "missing roption parameter name";
×
311
                    return std::make_pair<>(false, options);
×
312
                }
313

314
                ParameterRange new_parameter_range;
340✔
315

316
                for (auto e_roption = e_parameterrange->FirstChildElement("roption");
4,980✔
317
                     e_roption != nullptr;
4,980✔
318
                     e_roption = e_roption->NextSiblingElement("roption")) {
4,640✔
319
                    const char* roption_name_str = e_roption->Attribute("name");
4,640✔
320
                    if (!roption_name_str) {
4,640✔
321
                        LogErr() << "missing roption name attribute";
×
322
                        return std::make_pair<>(false, options);
×
323
                    }
324

325
                    const char* roption_value_str = e_roption->Attribute("value");
4,640✔
326
                    if (!roption_value_str) {
4,640✔
327
                        LogErr() << "missing roption value attribute";
×
328
                        return std::make_pair<>(false, options);
×
329
                    }
330

331
                    if (type_map.find(roption_parameter_str) == type_map.end()) {
4,640✔
332
                        LogErr() << "unknown roption type";
×
333
                        return std::make_pair<>(false, options);
×
334
                    }
335

336
                    ParamValue new_param_value;
9,280✔
337
                    new_param_value.set_from_xml(
13,920✔
338
                        type_map[roption_parameter_str], roption_value_str);
9,280✔
339
                    new_parameter_range[roption_name_str] = new_param_value;
4,640✔
340

341
                    // LogDebug() << "range option: "
342
                    //            << roption_name_str
343
                    //            << " -> "
344
                    //            << new_param_value
345
                    //            << " (" << new_param_value.typestr() << ")";
346
                }
347

348
                new_option->parameter_ranges[roption_parameter_str] = new_parameter_range;
340✔
349

350
                // LogDebug() << "adding to: " << roption_parameter_str;
351
            }
352
        }
353

354
        options.push_back(new_option);
1,197✔
355
    }
356
    return std::make_pair<>(true, options);
195✔
357
}
358

359
std::tuple<bool, std::vector<std::shared_ptr<CameraDefinition::Option>>, CameraDefinition::Option>
360
CameraDefinition::parse_range_options(
86✔
361
    const tinyxml2::XMLElement* param_handle,
362
    const std::string& param_name,
363
    std::unordered_map<std::string, std::string>& type_map)
364
{
365
    std::vector<std::shared_ptr<Option>> options{};
172✔
366
    Option default_option{};
172✔
367

368
    const char* min_str = param_handle->Attribute("min");
86✔
369
    if (!min_str) {
86✔
370
        LogErr() << "min range missing for " << param_name;
20✔
371
        return std::make_tuple<>(false, options, default_option);
20✔
372
    }
373

374
    ParamValue min_value;
132✔
375
    min_value.set_from_xml(type_map[param_name], min_str);
66✔
376

377
    const char* max_str = param_handle->Attribute("max");
66✔
378
    if (!max_str) {
66✔
379
        LogErr() << "max range missing for " << param_name;
×
380
        return std::make_tuple<>(false, options, default_option);
×
381
    }
382

383
    auto min_option = std::make_shared<Option>();
132✔
384
    min_option->name = "min";
66✔
385
    min_option->value = min_value;
66✔
386

387
    ParamValue max_value;
132✔
388
    max_value.set_from_xml(type_map[param_name], max_str);
66✔
389

390
    auto max_option = std::make_shared<Option>();
132✔
391
    max_option->name = "max";
66✔
392
    max_option->value = max_value;
66✔
393

394
    const char* step_str = param_handle->Attribute("step");
66✔
395
    if (!step_str) {
66✔
396
        LogDebug() << "step range missing for " << param_name;
10✔
397
    }
398

399
    if (step_str) {
66✔
400
        ParamValue step_value;
112✔
401
        step_value.set_from_xml(type_map[param_name], step_str);
56✔
402

403
        auto step_option = std::make_shared<Option>();
112✔
404
        step_option->name = "step";
56✔
405
        step_option->value = step_value;
56✔
406

407
        options.push_back(min_option);
56✔
408
        options.push_back(max_option);
56✔
409
        options.push_back(step_option);
56✔
410
    } else {
411
        options.push_back(min_option);
10✔
412
        options.push_back(max_option);
10✔
413
    }
414

415
    const char* default_str = param_handle->Attribute("default");
66✔
416
    if (!default_str) {
66✔
417
        LogDebug() << "default range missing for " << param_name;
×
418
        return std::make_tuple<>(false, options, default_option);
×
419
    }
420

421
    ParamValue default_value;
132✔
422
    default_value.set_from_xml(type_map[param_name], default_str);
66✔
423

424
    default_option.name = default_str;
66✔
425
    default_option.value = default_value;
66✔
426

427
    return std::make_tuple<>(true, options, default_option);
66✔
428
}
429

430
std::pair<bool, CameraDefinition::Option> CameraDefinition::find_default(
195✔
431
    const std::vector<std::shared_ptr<Option>>& options, const std::string& default_str)
432
{
433
    Option default_option{};
390✔
434

435
    bool found_default = false;
195✔
436
    for (auto& option : options) {
1,392✔
437
        if (option->value == default_str) {
1,197✔
438
            if (!found_default) {
195✔
439
                default_option = *option;
195✔
440
                found_default = true;
195✔
441
            } else {
442
                LogErr() << "Found more than one default";
×
443
                return std::make_pair<>(false, default_option);
×
444
            }
445
        }
446
    }
447
    if (!found_default) {
195✔
448
        LogErr() << "No default found";
×
449
        return std::make_pair<>(false, default_option);
×
450
    }
451
    return std::make_pair<>(true, default_option);
195✔
452
}
453

454
void CameraDefinition::assume_default_settings()
6✔
455
{
456
    std::lock_guard<std::mutex> lock(_mutex);
12✔
457

458
    _current_settings.clear();
6✔
459

460
    for (const auto& parameter : _parameter_map) {
100✔
461
        // if (parameter.second->is_range) {
462

463
        InternalCurrentSetting new_setting;
188✔
464
        new_setting.value = parameter.second->default_option.value;
94✔
465
        new_setting.needs_updating = false;
94✔
466
        _current_settings[parameter.first] = new_setting;
94✔
467

468
        //} else {
469

470
        //    for (const auto &option : parameter.second->options) {
471
        //        if (!option->is_default) {
472
        //            //LogDebug() << option->name << " not default";
473
        //            continue;
474
        //        }
475
        //        //LogDebug() << option->name << " default value: " << option->value << " (type: "
476
        //        <<
477
        //        // option->value.typestr() << ")";
478

479
        //        InternalCurrentSetting new_setting;
480
        //        new_setting.value = option->value;
481
        //        new_setting.needs_updating = false;
482
        //        _current_settings[parameter.first] = new_setting;
483
        //    }
484
        //}
485
    }
486
}
6✔
487

488
bool CameraDefinition::get_all_settings(std::unordered_map<std::string, ParamValue>& settings)
2✔
489
{
490
    std::lock_guard<std::mutex> lock(_mutex);
2✔
491

492
    settings.clear();
2✔
493
    for (const auto& current_setting : _current_settings) {
32✔
494
        settings[current_setting.first] = current_setting.second.value;
30✔
495
    }
496

497
    return (settings.size() > 0);
2✔
498
}
499

500
bool CameraDefinition::get_possible_settings(std::unordered_map<std::string, ParamValue>& settings)
4✔
501
{
502
    std::lock_guard<std::mutex> lock(_mutex);
8✔
503

504
    return get_possible_settings_locked(settings);
4✔
505
}
506

507
bool CameraDefinition::get_possible_settings_locked(
9✔
508
    std::unordered_map<std::string, ParamValue>& settings)
509
{
510
    settings.clear();
9✔
511

512
    // Find all exclusions
513
    // TODO: use set instead of vector
514
    std::vector<std::string> exclusions{};
9✔
515

516
    for (const auto& parameter : _parameter_map) {
154✔
517
        for (const auto& option : parameter.second->options) {
1,013✔
518
            if (_current_settings[parameter.first].value == option->value) {
868✔
519
                for (const auto& exclusion : option->exclusions) {
172✔
520
                    // LogDebug() << "found exclusion for " << parameter.first
521
                    //            << "(" << option->value << "): " << exclusion;
522
                    exclusions.push_back(exclusion);
48✔
523
                }
524
            }
525
        }
526
    }
527

528
    for (const auto& setting : _current_settings) {
154✔
529
        bool excluded = false;
145✔
530
        for (const auto& exclusion : exclusions) {
949✔
531
            if (setting.first == exclusion) {
804✔
532
                excluded = true;
48✔
533
            }
534
        }
535
        if (!_parameter_map[setting.first]->is_control) {
145✔
536
            continue;
30✔
537
        }
538

539
        if (excluded) {
115✔
540
            continue;
47✔
541
        }
542
        settings[setting.first] = setting.second.value;
68✔
543
    }
544

545
    return (settings.size() > 0);
9✔
546
}
547

548
bool CameraDefinition::set_setting(const std::string& name, const ParamValue& value)
20✔
549
{
550
    std::lock_guard<std::mutex> lock(_mutex);
40✔
551

552
    if (_parameter_map.find(name) == _parameter_map.end()) {
20✔
553
        LogErr() << "Unknown setting to set: " << name;
×
554
        return false;
×
555
    }
556

557
    // For range params, we need to verify the range.
558
    if (_parameter_map[name]->is_range) {
20✔
559
        // Check against the minimum
560
        if (value < _parameter_map[name]->options[0]->value) {
3✔
561
            LogErr() << "Chosen value smaller than minimum";
1✔
562
            return false;
1✔
563
        }
564

565
        if (value > _parameter_map[name]->options[1]->value) {
2✔
566
            LogErr() << "Chosen value bigger than maximum";
1✔
567
            return false;
1✔
568
        }
569

570
        // TODO: Check step as well, until now we have only seen steps of 1 in the wild though.
571
    }
572

573
    _current_settings[name].value = value;
18✔
574
    _current_settings[name].needs_updating = false;
18✔
575

576
    // Some param changes cause other params to change, so they need to be updated.
577
    // The camera definition just keeps track of these params but the actual param fetching
578
    // needs to happen outside of this class.
579
    for (const auto& update : _parameter_map[name]->updates) {
60✔
580
        if (_current_settings.find(update) == _current_settings.end()) {
42✔
581
            // LogDebug() << "Update to '" << update << "' not understood.";
582
            continue;
8✔
583
        }
584
        _current_settings[update].needs_updating = true;
34✔
585
    }
586

587
    return true;
18✔
588
}
589

590
bool CameraDefinition::get_setting(const std::string& name, ParamValue& value)
6✔
591
{
592
    std::lock_guard<std::mutex> lock(_mutex);
12✔
593

594
    if (_current_settings.find(name) == _current_settings.end()) {
6✔
595
        LogErr() << "Unknown setting to get: " << name;
×
596
        return false;
×
597
    }
598

599
    if (!_current_settings.at(name).needs_updating) {
6✔
600
        value = _current_settings.at(name).value;
6✔
601
        return true;
6✔
602
    } else {
603
        return false;
×
604
    }
605
}
606

607
bool CameraDefinition::get_option_value(
9✔
608
    const std::string& param_name, const std::string& option_value, ParamValue& value)
609
{
610
    std::lock_guard<std::mutex> lock(_mutex);
18✔
611

612
    if (_parameter_map.find(param_name) == _parameter_map.end()) {
9✔
613
        LogErr() << "Unknown parameter to get option: " << param_name;
1✔
614
        return false;
1✔
615
    }
616

617
    for (const auto& option : _parameter_map[param_name]->options) {
59✔
618
        if (option->value == option_value) {
57✔
619
            value = option->value;
6✔
620
            return true;
6✔
621
        }
622
    }
623

624
    return false;
2✔
625
}
626

627
bool CameraDefinition::get_all_options(const std::string& name, std::vector<ParamValue>& values)
2✔
628
{
629
    std::lock_guard<std::mutex> lock(_mutex);
4✔
630

631
    values.clear();
2✔
632

633
    if (_parameter_map.find(name) == _parameter_map.end()) {
2✔
634
        LogErr() << "Unknown parameter to get all options";
×
635
        return false;
×
636
    }
637

638
    for (const auto& option : _parameter_map[name]->options) {
29✔
639
        values.push_back(option->value);
27✔
640
    }
641

642
    return true;
2✔
643
}
644

645
bool CameraDefinition::get_possible_options(
5✔
646
    const std::string& name, std::vector<ParamValue>& values)
647
{
648
    std::lock_guard<std::mutex> lock(_mutex);
10✔
649

650
    values.clear();
5✔
651

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

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

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

671
    for (const auto& parameter : _parameter_map) {
72✔
672
        for (const auto& option : parameter.second->options) {
524✔
673
            if (_current_settings[parameter.first].needs_updating) {
456✔
674
                // LogWarn() << parameter.first << " needs updating";
675
                continue;
180✔
676
            }
677
            if (_current_settings[parameter.first].value == option->value) {
276✔
678
                for (const auto& exclusion : option->exclusions) {
80✔
679
                    // LogDebug() << "found exclusion for " << parameter.first
680
                    //            << "(" << option->value << "): " << exclusion;
681
                    exclusions.push_back(exclusion);
26✔
682
                }
683
            }
684
        }
685
    }
686

687
    // TODO: use set instead of vector for this
688
    std::vector<ParamValue> allowed_ranges{};
4✔
689

690
    // Check allowed ranges.
691
    for (const auto& parameter : _parameter_map) {
72✔
692
        if (!parameter.second->is_control) {
68✔
693
            continue;
16✔
694
        }
695

696
        bool excluded = false;
52✔
697
        for (const auto& exclusion : exclusions) {
390✔
698
            if (parameter.first == exclusion) {
338✔
699
                excluded = true;
26✔
700
            }
701
        }
702
        if (excluded) {
52✔
703
            continue;
26✔
704
        }
705

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

724
    // Intersect
725
    for (const auto& option : _parameter_map[name]->options) {
119✔
726
        bool option_allowed = false;
115✔
727
        for (const auto& allowed_range : allowed_ranges) {
1,175✔
728
            if (option->value == allowed_range) {
1,060✔
729
                option_allowed = true;
38✔
730
            }
731
        }
732
        if (option_allowed || allowed_ranges.size() == 0) {
115✔
733
            values.push_back(option->value);
102✔
734
        }
735
    }
736

737
    return true;
4✔
738
}
739

740
void CameraDefinition::get_unknown_params(std::vector<std::pair<std::string, ParamValue>>& params)
5✔
741
{
742
    std::lock_guard<std::mutex> lock(_mutex);
10✔
743

744
    params.clear();
5✔
745

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

753
void CameraDefinition::set_all_params_unknown()
1✔
754
{
755
    std::lock_guard<std::mutex> lock(_mutex);
2✔
756

757
    for (auto& parameter : _parameter_map) {
18✔
758
        _current_settings[parameter.first].needs_updating = true;
17✔
759
    }
760
}
1✔
761

762
bool CameraDefinition::is_setting_range(const std::string& name)
2✔
763
{
764
    std::lock_guard<std::mutex> lock(_mutex);
4✔
765

766
    if (_parameter_map.find(name) == _parameter_map.end()) {
2✔
767
        LogWarn() << "Setting " << name << " not found.";
×
768
        return false;
×
769
    }
770

771
    return _parameter_map[name]->is_range;
2✔
772
}
773

774
bool CameraDefinition::get_setting_str(const std::string& name, std::string& description)
9✔
775
{
776
    std::lock_guard<std::mutex> lock(_mutex);
18✔
777

778
    description.clear();
9✔
779

780
    if (_parameter_map.find(name) == _parameter_map.end()) {
9✔
781
        LogWarn() << "Setting " << name << " not found.";
1✔
782
        return false;
1✔
783
    }
784

785
    description = _parameter_map[name]->description;
8✔
786
    return true;
8✔
787
}
788

789
bool CameraDefinition::get_option_str(
16✔
790
    const std::string& setting_name, const std::string& option_name, std::string& description)
791
{
792
    std::lock_guard<std::mutex> lock(_mutex);
32✔
793

794
    description.clear();
16✔
795

796
    if (_parameter_map.find(setting_name) == _parameter_map.end()) {
16✔
797
        LogWarn() << "Setting " << setting_name << " not found.";
1✔
798
        return false;
1✔
799
    }
800

801
    for (const auto& option : _parameter_map[setting_name]->options) {
79✔
802
        std::stringstream value_ss{};
78✔
803
        value_ss << option->value;
78✔
804
        if (option->value == option_name) {
78✔
805
            description = option->name;
14✔
806
            return true;
14✔
807
        }
808
    }
809
    LogWarn() << "Option " << option_name << " not found";
1✔
810
    return false;
1✔
811
}
812

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