Skip to content

Commit

Permalink
camera: added range based parameters
Browse files Browse the repository at this point in the history
This brings initial support in the camera plugin for range based
parameters.

Range based parameters are paramaters without a predefined option list
like an enum but rather a min, max, step size and a type.
  • Loading branch information
julianoes committed Jul 12, 2019
1 parent 9df82ff commit 0bdeb0b
Show file tree
Hide file tree
Showing 6 changed files with 453 additions and 98 deletions.
193 changes: 151 additions & 42 deletions src/plugins/camera/camera_definition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,31 +191,39 @@ bool CameraDefinition::parse_xml()
}
}

auto e_options = e_parameter->FirstChildElement("options");
if (!e_options) {
LogErr() << "No options found";
const char *default_str = e_parameter->Attribute("default");
if (!default_str) {
LogWarn() << "Default missing for " << param_name;
continue;
}

auto maybe_options = parse_options(e_options, param_name, type_map);
if (!maybe_options.first) {
return false;
}
auto e_options = e_parameter->FirstChildElement("options");
if (e_options) {
auto maybe_options = parse_options(e_options, param_name, type_map);
if (!maybe_options.first) {
continue;
}
new_parameter->options = maybe_options.second;

// We only need a default if we have options.
const char *default_str = e_parameter->Attribute("default");
if (!default_str) {
LogErr() << "Default missing for " << param_name;
return false;
}
auto maybe_default = find_default(new_parameter->options, default_str);

new_parameter->options = maybe_options.second;
if (!maybe_default.first) {
LogWarn() << "Default not found for " << param_name;
return false;
}

if (!find_default(new_parameter->options, default_str)) {
LogWarn() << "Default not found for " << param_name;
// TODO: in the future we should fail completely here
// return false;
continue;
new_parameter->default_option = maybe_default.second;

} else {
auto maybe_range_options = parse_range_options(e_parameter, param_name, type_map);
if (!std::get<0>(maybe_range_options)) {
LogWarn() << "Not found: " << param_name;
continue;
}

new_parameter->options = std::get<1>(maybe_range_options);
new_parameter->is_range = true;
new_parameter->default_option = std::get<2>(maybe_range_options);
}

_parameter_map[param_name] = new_parameter;
Expand All @@ -230,8 +238,8 @@ bool CameraDefinition::parse_xml()

std::pair<bool, std::vector<std::shared_ptr<CameraDefinition::Option>>>
CameraDefinition::parse_options(const tinyxml2::XMLElement *options_handle,
const std::string &param_name,
std::map<std::string, std::string> &type_map)
const std::string &param_name,
std::map<std::string, std::string> &type_map)
{
std::vector<std::shared_ptr<Option>> options{};

Expand Down Expand Up @@ -322,26 +330,99 @@ CameraDefinition::parse_options(const tinyxml2::XMLElement *options_handle,
return std::make_pair<>(true, options);
}

bool CameraDefinition::find_default(std::vector<std::shared_ptr<Option>> &options,
const std::string &default_str)
std::tuple<bool, std::vector<std::shared_ptr<CameraDefinition::Option>>, CameraDefinition::Option>
CameraDefinition::parse_range_options(const tinyxml2::XMLElement *param_handle,
const std::string &param_name,
std::map<std::string, std::string> &type_map)
{
std::vector<std::shared_ptr<Option>> options{};
Option default_option{};

const char *min_str = param_handle->Attribute("min");
if (!min_str) {
LogErr() << "min range missing for " << param_name;
return std::make_tuple<>(false, options, default_option);
}

MAVLinkParameters::ParamValue min_value;
min_value.set_from_xml(type_map[param_name], min_str);

const char *max_str = param_handle->Attribute("max");
if (!max_str) {
LogErr() << "max range missing for " << param_name;
return std::make_tuple<>(false, options, default_option);
}

auto min_option = std::make_shared<Option>();
min_option->name = "min";
min_option->value = min_value;

MAVLinkParameters::ParamValue max_value;
max_value.set_from_xml(type_map[param_name], max_str);

auto max_option = std::make_shared<Option>();
max_option->name = "max";
max_option->value = max_value;

const char *step_str = param_handle->Attribute("step");
if (!step_str) {
LogDebug() << "step range missing for " << param_name;
}

if (step_str) {
MAVLinkParameters::ParamValue step_value;
step_value.set_from_xml(type_map[param_name], step_str);

auto step_option = std::make_shared<Option>();
step_option->name = "step";
step_option->value = step_value;

options.push_back(min_option);
options.push_back(max_option);
options.push_back(step_option);
} else {
options.push_back(min_option);
options.push_back(max_option);
}

const char *default_str = param_handle->Attribute("default");
if (!default_str) {
LogDebug() << "default range missing for " << param_name;
return std::make_tuple<>(false, options, default_option);
}

MAVLinkParameters::ParamValue default_value;
default_value.set_from_xml(type_map[param_name], default_str);

default_option.name = default_str;
default_option.value = default_value;

return std::make_tuple<>(true, options, default_option);
}

std::pair<bool, CameraDefinition::Option>
CameraDefinition::find_default(const std::vector<std::shared_ptr<Option>> &options,
const std::string &default_str)
{
Option default_option{};

bool found_default = false;
for (auto &option : options) {
if (option->value == default_str) {
option->is_default = true;
if (!found_default) {
default_option = *option;
found_default = true;
} else {
LogErr() << "Found more than one default";
return false;
return std::make_pair<>(false, default_option);
}
}
}
if (!found_default) {
LogErr() << "No default found";
return false;
return std::make_pair<>(false, default_option);
}
return true;
return std::make_pair<>(true, default_option);
}

void CameraDefinition::assume_default_settings()
Expand All @@ -351,19 +432,30 @@ void CameraDefinition::assume_default_settings()
_current_settings.clear();

for (const auto &parameter : _parameter_map) {
for (const auto &option : parameter.second->options) {
if (!option->is_default) {
// LogDebug() << option->name << " not default";
continue;
}
// LogDebug() << option->name << " default value: " << option->value << " (type: " <<
// option->value.typestr() << ")";

InternalCurrentSetting new_setting;
new_setting.value = option->value;
new_setting.needs_updating = false;
_current_settings[parameter.first] = new_setting;
}
// if (parameter.second->is_range) {

InternalCurrentSetting new_setting;
new_setting.value = parameter.second->default_option.value;
new_setting.needs_updating = false;
_current_settings[parameter.first] = new_setting;

//} else {

// for (const auto &option : parameter.second->options) {
// if (!option->is_default) {
// //LogDebug() << option->name << " not default";
// continue;
// }
// //LogDebug() << option->name << " default value: " << option->value << " (type: "
// <<
// // option->value.typestr() << ")";

// InternalCurrentSetting new_setting;
// new_setting.value = option->value;
// new_setting.needs_updating = false;
// _current_settings[parameter.first] = new_setting;
// }
//}
}
}

Expand Down Expand Up @@ -417,9 +509,10 @@ bool CameraDefinition::get_possible_settings(
continue;
}

if (!excluded) {
settings[setting.first] = setting.second.value;
if (excluded) {
continue;
}
settings[setting.first] = setting.second.value;
}

return (settings.size() > 0);
Expand Down Expand Up @@ -449,6 +542,22 @@ bool CameraDefinition::set_setting(const std::string &name,
}
}

// For range params, we need to verify the range.
if (_parameter_map[name]->is_range) {
// Check against the minimum
if (value < _parameter_map[name]->options[0]->value) {
LogErr() << "Chosen value smaller than minimum";
return false;
}

if (value > _parameter_map[name]->options[1]->value) {
LogErr() << "Chosen value bigger than maximum";
return false;
}

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

// LogDebug() << "Setting " << name << " of type: " << changed_value.typestr();
_current_settings[name].value = changed_value;
_current_settings[name].needs_updating = false;
Expand Down
17 changes: 12 additions & 5 deletions src/plugins/camera/camera_definition.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include <map>
#include <mutex>
#include <string>
#include <tuple>
#include <utility>

namespace mavsdk {

Expand Down Expand Up @@ -62,7 +64,6 @@ class CameraDefinition {
MAVLinkParameters::ParamValue value{};
std::vector<std::string> exclusions{};
std::map<std::string, parameter_range_t> parameter_ranges{};
bool is_default{false};
};

struct Parameter {
Expand All @@ -73,6 +74,8 @@ class CameraDefinition {
MAVLinkParameters::ParamValue type{}; // for type only, doesn't hold a value
std::vector<std::string> updates{};
std::vector<std::shared_ptr<Option>> options{};
Option default_option{};
bool is_range{false};
};

bool parse_xml();
Expand All @@ -81,10 +84,14 @@ class CameraDefinition {
// nothing.
std::pair<bool, std::vector<std::shared_ptr<Option>>>
parse_options(const tinyxml2::XMLElement *options_handle,
const std::string &param_name,
std::map<std::string, std::string> &type_map);
bool find_default(std::vector<std::shared_ptr<Option>> &options,
const std::string &default_str);
const std::string &param_name,
std::map<std::string, std::string> &type_map);
std::tuple<bool, std::vector<std::shared_ptr<Option>>, Option>
parse_range_options(const tinyxml2::XMLElement *param_handle,
const std::string &param_name,
std::map<std::string, std::string> &type_map);
std::pair<bool, Option> find_default(const std::vector<std::shared_ptr<Option>> &options,
const std::string &default_str);

mutable std::recursive_mutex _mutex{};

Expand Down

0 comments on commit 0bdeb0b

Please sign in to comment.