[{"id":2103,"web_url":"https://patchwork.libcamera.org/comment/2103/","msgid":"<20190701235903.GE9228@bigcity.dyn.berto.se>","date":"2019-07-01T23:59:03","subject":"Re: [libcamera-devel] [PATCH v4 03/13] libcamera: controls:\n\tIntroduce control-related data types","submitter":{"id":5,"url":"https://patchwork.libcamera.org/api/people/5/","name":"Niklas Söderlund","email":"niklas.soderlund@ragnatech.se"},"content":"Hi Kieran,\n\nThanks for your work.\n\nOn 2019-07-01 23:14:54 +0300, Laurent Pinchart wrote:\n> From: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> \n> Add a set of data types to support controls:\n> \n> - ControlValue stores a control type and value in a generic way\n> - ControlId enumerates all the control identifiers\n> - ControlIdentifier declares the types of a control and map their names\n> - ControlInfo stores runtime information for controls\n> - ControlList contains a set of control info and value pairs\n> \n> The control definitions map is generated from the controls documentation\n> to ensure that the two will always be synchronised.\n> \n> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\nI tested the awk script, it works but my awk is too week to properly \nreview it. So I will blindly trust you on that no backdoors exists in it \n(much the same way I would review perl...) ;-P\n\nReviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n\n> ---\n> Changes since v3:\n> \n> - Typo fixes\n> - Optimized the contains() implementation\n> - Various documentation updates\n> \n> Changes since v2:\n> \n> - Squashed \"Provide ControlValue class\"\n> - Renamed Value to ControlValue\n> - Removed operator<<()\n> - Added control table generation\n> - Moved control definitions to control_definitions.h\n> - Renamed ControlTypes to controlTypes and make it const\n> - Moved the initial controls list to a separate patch\n> - Renamed control_definitions.h to control_ids.h and\n>   control_definitions.cpp to control_types.cpp to match the contained\n>   enum and variable name respectively\n> - Indexed ControlList by ControlInfo pointer instead of value\n> - Replaced ControlInfoHash with std::hash specialisation\n> - Added automatic conversion between 32- and 64-bit integer values\n> \n> The automatic conversion between integer types was prompted by an\n> assertion failure due to the use of getInt() on the min() and max()\n> value of an Integer control. The min and max ControlValue instances are\n> create as Integer64, due to the V4L2ControlInfo class returning the\n> range as int64_t. This may need to be reworked.\n> ---\n>  Documentation/Doxyfile.in       |   3 +-\n>  include/libcamera/control_ids.h |  35 +++\n>  include/libcamera/controls.h    | 134 ++++++++++\n>  include/libcamera/meson.build   |   2 +\n>  src/libcamera/controls.cpp      | 451 ++++++++++++++++++++++++++++++++\n>  src/libcamera/gen-controls.awk  | 106 ++++++++\n>  src/libcamera/meson.build       |  11 +\n>  7 files changed, 741 insertions(+), 1 deletion(-)\n>  create mode 100644 include/libcamera/control_ids.h\n>  create mode 100644 include/libcamera/controls.h\n>  create mode 100644 src/libcamera/controls.cpp\n>  create mode 100755 src/libcamera/gen-controls.awk\n> \n> diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in\n> index c58631200dd5..9ca32241b895 100644\n> --- a/Documentation/Doxyfile.in\n> +++ b/Documentation/Doxyfile.in\n> @@ -868,7 +868,8 @@ EXCLUDE_SYMBOLS        = libcamera::SignalBase \\\n>                           libcamera::SlotArgs \\\n>                           libcamera::SlotBase \\\n>                           libcamera::SlotMember \\\n> -                         libcamera::SlotStatic\n> +                         libcamera::SlotStatic \\\n> +                         std::*\n>  \n>  # The EXAMPLE_PATH tag can be used to specify one or more files or directories\n>  # that contain example code fragments that are included (see the \\include\n> diff --git a/include/libcamera/control_ids.h b/include/libcamera/control_ids.h\n> new file mode 100644\n> index 000000000000..d0e700da9844\n> --- /dev/null\n> +++ b/include/libcamera/control_ids.h\n> @@ -0,0 +1,35 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2019, Google Inc.\n> + *\n> + * control_ids.h : Control ID list\n> + */\n> +\n> +#ifndef __LIBCAMERA_CONTROL_IDS_H__\n> +#define __LIBCAMERA_CONTROL_IDS_H__\n> +\n> +#include <functional>\n> +\n> +namespace libcamera {\n> +\n> +enum ControlId {\n> +};\n> +\n> +} /* namespace libcamera */\n> +\n> +namespace std {\n> +\n> +template<>\n> +struct hash<libcamera::ControlId> {\n> +\tusing argument_type = libcamera::ControlId;\n> +\tusing result_type = std::size_t;\n> +\n> +\tresult_type operator()(const argument_type &key) const noexcept\n> +\t{\n> +\t\treturn std::hash<std::underlying_type<argument_type>::type>()(key);\n> +\t}\n> +};\n> +\n> +} /* namespace std */\n> +\n> +#endif // __LIBCAMERA_CONTROL_IDS_H__\n> diff --git a/include/libcamera/controls.h b/include/libcamera/controls.h\n> new file mode 100644\n> index 000000000000..2206155909ca\n> --- /dev/null\n> +++ b/include/libcamera/controls.h\n> @@ -0,0 +1,134 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2019, Google Inc.\n> + *\n> + * controls.h - Control handling\n> + */\n> +\n> +#ifndef __LIBCAMERA_CONTROLS_H__\n> +#define __LIBCAMERA_CONTROLS_H__\n> +\n> +#include <stdint.h>\n> +#include <string>\n> +#include <unordered_map>\n> +\n> +#include <libcamera/control_ids.h>\n> +\n> +namespace libcamera {\n> +\n> +class Camera;\n> +\n> +enum ControlValueType {\n> +\tControlValueNone,\n> +\tControlValueBool,\n> +\tControlValueInteger,\n> +\tControlValueInteger64,\n> +};\n> +\n> +class ControlValue\n> +{\n> +public:\n> +\tControlValue();\n> +\tControlValue(bool value);\n> +\tControlValue(int value);\n> +\tControlValue(int64_t value);\n> +\n> +\tControlValueType type() const { return type_; };\n> +\tbool isNone() const { return type_ == ControlValueNone; };\n> +\n> +\tvoid set(bool value);\n> +\tvoid set(int value);\n> +\tvoid set(int64_t value);\n> +\n> +\tbool getBool() const;\n> +\tint getInt() const;\n> +\tint64_t getInt64() const;\n> +\n> +\tstd::string toString() const;\n> +\n> +private:\n> +\tControlValueType type_;\n> +\n> +\tunion {\n> +\t\tbool bool_;\n> +\t\tint integer_;\n> +\t\tint64_t integer64_;\n> +\t};\n> +};\n> +\n> +struct ControlIdentifier {\n> +\tControlId id;\n> +\tconst char *name;\n> +\tControlValueType type;\n> +};\n> +\n> +class ControlInfo\n> +{\n> +public:\n> +\texplicit ControlInfo(ControlId id, const ControlValue &min = 0,\n> +\t\t\t     const ControlValue &max = 0);\n> +\n> +\tControlId id() const { return ident_->id; }\n> +\tconst char *name() const { return ident_->name; }\n> +\tControlValueType type() const { return ident_->type; }\n> +\n> +\tconst ControlValue &min() const { return min_; }\n> +\tconst ControlValue &max() const { return max_; }\n> +\n> +\tstd::string toString() const;\n> +\n> +private:\n> +\tconst struct ControlIdentifier *ident_;\n> +\tControlValue min_;\n> +\tControlValue max_;\n> +};\n> +\n> +bool operator==(const ControlInfo &lhs, const ControlInfo &rhs);\n> +bool operator==(const ControlId &lhs, const ControlInfo &rhs);\n> +bool operator==(const ControlInfo &lhs, const ControlId &rhs);\n> +static inline bool operator!=(const ControlInfo &lhs, const ControlInfo &rhs)\n> +{\n> +\treturn !(lhs == rhs);\n> +}\n> +static inline bool operator!=(const ControlId &lhs, const ControlInfo &rhs)\n> +{\n> +\treturn !(lhs == rhs);\n> +}\n> +static inline bool operator!=(const ControlInfo &lhs, const ControlId &rhs)\n> +{\n> +\treturn !(lhs == rhs);\n> +}\n> +\n> +class ControlList\n> +{\n> +private:\n> +\tusing ControlListMap = std::unordered_map<const ControlInfo *, ControlValue>;\n> +\n> +public:\n> +\tControlList(Camera *camera);\n> +\n> +\tusing iterator = ControlListMap::iterator;\n> +\tusing const_iterator = ControlListMap::const_iterator;\n> +\n> +\titerator begin() { return controls_.begin(); }\n> +\titerator end() { return controls_.end(); }\n> +\tconst_iterator begin() const { return controls_.begin(); }\n> +\tconst_iterator end() const { return controls_.end(); }\n> +\n> +\tbool contains(const ControlInfo *info) const;\n> +\tbool empty() const { return controls_.empty(); }\n> +\tstd::size_t size() const { return controls_.size(); }\n> +\tvoid clear() { controls_.clear(); }\n> +\n> +\tControlValue &operator[](const ControlInfo *info) { return controls_[info]; }\n> +\n> +\tvoid update(const ControlList &list);\n> +\n> +private:\n> +\tCamera *camera_;\n> +\tControlListMap controls_;\n> +};\n> +\n> +} /* namespace libcamera */\n> +\n> +#endif /* __LIBCAMERA_CONTROLS_H__ */\n> diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build\n> index 15484724df01..3067120a1598 100644\n> --- a/include/libcamera/meson.build\n> +++ b/include/libcamera/meson.build\n> @@ -2,6 +2,8 @@ libcamera_api = files([\n>      'buffer.h',\n>      'camera.h',\n>      'camera_manager.h',\n> +    'control_ids.h',\n> +    'controls.h',\n>      'event_dispatcher.h',\n>      'event_notifier.h',\n>      'geometry.h',\n> diff --git a/src/libcamera/controls.cpp b/src/libcamera/controls.cpp\n> new file mode 100644\n> index 000000000000..7fac1169cbfd\n> --- /dev/null\n> +++ b/src/libcamera/controls.cpp\n> @@ -0,0 +1,451 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2019, Google Inc.\n> + *\n> + * controls.cpp - Control handling\n> + */\n> +\n> +#include <libcamera/controls.h>\n> +\n> +#include <sstream>\n> +#include <string>\n> +\n> +#include \"log.h\"\n> +#include \"utils.h\"\n> +\n> +/**\n> + * \\file controls.h\n> + * \\brief Describes control framework and controls supported by a camera\n> + */\n> +\n> +namespace libcamera {\n> +\n> +LOG_DEFINE_CATEGORY(Controls)\n> +\n> +/**\n> + * \\enum ControlValueType\n> + * \\brief Define the data type of value represented by a ControlValue\n> + * \\var ControlValueNone\n> + * Identifies an unset control value\n> + * \\var ControlValueBool\n> + * Identifies controls storing a boolean value\n> + * \\var ControlValueInteger\n> + * Identifies controls storing an integer value\n> + * \\var ControlValueInteger64\n> + * Identifies controls storing a 64-bit integer value\n> + */\n> +\n> +/**\n> + * \\class ControlValue\n> + * \\brief Abstract type representing the value of a control\n> + */\n> +\n> +/**\n> + * \\brief Construct an empty ControlValue.\n> + */\n> +ControlValue::ControlValue()\n> +\t: type_(ControlValueNone)\n> +{\n> +}\n> +\n> +/**\n> + * \\brief Construct a Boolean ControlValue\n> + * \\param[in] value Boolean value to store\n> + */\n> +ControlValue::ControlValue(bool value)\n> +\t: type_(ControlValueBool), bool_(value)\n> +{\n> +}\n> +\n> +/**\n> + * \\brief Construct an integer ControlValue\n> + * \\param[in] value Integer value to store\n> + */\n> +ControlValue::ControlValue(int value)\n> +\t: type_(ControlValueInteger), integer_(value)\n> +{\n> +}\n> +\n> +/**\n> + * \\brief Construct a 64 bit integer ControlValue\n> + * \\param[in] value Integer value to store\n> + */\n> +ControlValue::ControlValue(int64_t value)\n> +\t: type_(ControlValueInteger64), integer64_(value)\n> +{\n> +}\n> +\n> +/**\n> + * \\fn ControlValue::type()\n> + * \\brief Retrieve the data type of the value\n> + * \\return The value data type\n> + */\n> +\n> +/**\n> + * \\fn ControlValue::isNone()\n> + * \\brief Determine if the value is not initialised\n> + * \\return True if the value type is ControlValueNone, false otherwise\n> + */\n> +\n> +/**\n> + * \\brief Set the value with a boolean\n> + * \\param[in] value Boolean value to store\n> + */\n> +void ControlValue::set(bool value)\n> +{\n> +\ttype_ = ControlValueBool;\n> +\tbool_ = value;\n> +}\n> +\n> +/**\n> + * \\brief Set the value with an integer\n> + * \\param[in] value Integer value to store\n> + */\n> +void ControlValue::set(int value)\n> +{\n> +\ttype_ = ControlValueInteger;\n> +\tinteger_ = value;\n> +}\n> +\n> +/**\n> + * \\brief Set the value with a 64 bit integer\n> + * \\param[in] value 64 bit integer value to store\n> + */\n> +void ControlValue::set(int64_t value)\n> +{\n> +\ttype_ = ControlValueInteger64;\n> +\tinteger64_ = value;\n> +}\n> +\n> +/**\n> + * \\brief Get the boolean value\n> + *\n> + * The value type must be Boolean.\n> + *\n> + * \\return The boolean value\n> + */\n> +bool ControlValue::getBool() const\n> +{\n> +\tASSERT(type_ == ControlValueBool);\n> +\n> +\treturn bool_;\n> +}\n> +\n> +/**\n> + * \\brief Get the integer value\n> + *\n> + * The value type must be Integer or Integer64.\n> + *\n> + * \\return The integer value\n> + */\n> +int ControlValue::getInt() const\n> +{\n> +\tASSERT(type_ == ControlValueInteger || type_ == ControlValueInteger64);\n> +\n> +\treturn integer_;\n> +}\n> +\n> +/**\n> + * \\brief Get the 64-bit integer value\n> + *\n> + * The value type must be Integer or Integer64.\n> + *\n> + * \\return The 64-bit integer value\n> + */\n> +int64_t ControlValue::getInt64() const\n> +{\n> +\tASSERT(type_ == ControlValueInteger || type_ == ControlValueInteger64);\n> +\n> +\treturn integer64_;\n> +}\n> +\n> +/**\n> + * \\brief Assemble and return a string describing the value\n> + * \\return A string describing the ControlValue\n> + */\n> +std::string ControlValue::toString() const\n> +{\n> +\tswitch (type_) {\n> +\tcase ControlValueNone:\n> +\t\treturn \"<None>\";\n> +\tcase ControlValueBool:\n> +\t\treturn bool_ ? \"True\" : \"False\";\n> +\tcase ControlValueInteger:\n> +\t\treturn std::to_string(integer_);\n> +\tcase ControlValueInteger64:\n> +\t\treturn std::to_string(integer64_);\n> +\t}\n> +\n> +\treturn \"<ValueType Error>\";\n> +}\n> +\n> +/**\n> + * \\enum ControlId\n> + * \\brief Numerical control ID\n> + */\n> +\n> +/**\n> + * \\struct ControlIdentifier\n> + * \\brief Describe a ControlId with control specific constant meta-data\n> + *\n> + * Defines a Control with a unique ID, a name, and a type.\n> + * This structure is used as static part of the auto-generated control\n> + * definitions, which are generated from the ControlId documentation.\n> + *\n> + * \\var ControlIdentifier::id\n> + * The unique ID for a control\n> + * \\var ControlIdentifier::name\n> + * The string representation of the control\n> + * \\var ControlIdentifier::type\n> + * The ValueType required to represent the control value\n> + */\n> +\n> +/*\n> + * The controlTypes are automatically generated to produce a control_types.cpp\n> + * output. This file is not for public use, and so no suitable header exists\n> + * for this sole usage of the controlTypes reference. As such the extern is\n> + * only defined here for use during the ControlInfo constructor and should not\n> + * be referenced directly elsewhere.\n> + */\n> +extern const std::unordered_map<ControlId, ControlIdentifier> controlTypes;\n> +\n> +/**\n> + * \\class ControlInfo\n> + * \\brief Describe the information and capabilities of a Control\n> + *\n> + * The ControlInfo represents control specific meta-data which is constant on a\n> + * per camera basis. ControlInfo classes are constructed by pipeline handlers\n> + * to expose the controls they support and the metadata needed to utilise those\n> + * controls.\n> + */\n> +\n> +/**\n> + * \\brief Construct a ControlInfo with minimum and maximum range parameters\n> + * \\param[in] id The control ID\n> + * \\param[in] min The control minimum value\n> + * \\param[in] max The control maximum value\n> + */\n> +ControlInfo::ControlInfo(ControlId id, const ControlValue &min,\n> +\t\t\t const ControlValue &max)\n> +\t: min_(min), max_(max)\n> +{\n> +\tauto iter = controlTypes.find(id);\n> +\tif (iter == controlTypes.end()) {\n> +\t\tLOG(Controls, Fatal) << \"Attempt to create invalid ControlInfo\";\n> +\t\treturn;\n> +\t}\n> +\n> +\tident_ = &iter->second;\n> +}\n> +\n> +/**\n> + * \\fn ControlInfo::id()\n> + * \\brief Retrieve the control ID\n> + * \\return The control ID\n> + */\n> +\n> +/**\n> + * \\fn ControlInfo::name()\n> + * \\brief Retrieve the control name string\n> + * \\return The control name string\n> + */\n> +\n> +/**\n> + * \\fn ControlInfo::type()\n> + * \\brief Retrieve the control data type\n> + * \\return The control data type\n> + */\n> +\n> +/**\n> + * \\fn ControlInfo::min()\n> + * \\brief Retrieve the minimum value of the control\n> + * \\return A ControlValue with the minimum value for the control\n> + */\n> +\n> +/**\n> + * \\fn ControlInfo::max()\n> + * \\brief Retrieve the maximum value of the control\n> + * \\return A ControlValue with the maximum value for the control\n> + */\n> +\n> +/**\n> + * \\brief Provide a string representation of the ControlInfo\n> + */\n> +std::string ControlInfo::toString() const\n> +{\n> +\tstd::stringstream ss;\n> +\n> +\tss << name() << \"[\" << min_.toString() << \"..\" << max_.toString() << \"]\";\n> +\n> +\treturn ss.str();\n> +}\n> +\n> +/**\n> + * \\brief Compare control information for equality\n> + * \\param[in] lhs Left-hand side control information\n> + * \\param[in] rhs Right-hand side control information\n> + *\n> + * Control information is compared based on the ID only, as a camera may not\n> + * have two separate controls with the same ID.\n> + *\n> + * \\return True if \\a lhs and \\a rhs are equal, false otherwise\n> + */\n> +bool operator==(const ControlInfo &lhs, const ControlInfo &rhs)\n> +{\n> +\treturn lhs.id() == rhs.id();\n> +}\n> +\n> +/**\n> + * \\brief Compare control ID and information for equality\n> + * \\param[in] lhs Left-hand side control identifier\n> + * \\param[in] rhs Right-hand side control information\n> + *\n> + * Control information is compared based on the ID only, as a camera may not\n> + * have two separate controls with the same ID.\n> + *\n> + * \\return True if \\a lhs and \\a rhs are equal, false otherwise\n> + */\n> +bool operator==(const ControlId &lhs, const ControlInfo &rhs)\n> +{\n> +\treturn lhs == rhs.id();\n> +}\n> +\n> +/**\n> + * \\brief Compare control information and ID for equality\n> + * \\param[in] lhs Left-hand side control information\n> + * \\param[in] rhs Right-hand side control identifier\n> + *\n> + * Control information is compared based on the ID only, as a camera may not\n> + * have two separate controls with the same ID.\n> + *\n> + * \\return True if \\a lhs and \\a rhs are equal, false otherwise\n> + */\n> +bool operator==(const ControlInfo &lhs, const ControlId &rhs)\n> +{\n> +\treturn lhs.id() == rhs;\n> +}\n> +\n> +/**\n> + * \\class ControlList\n> + * \\brief Associate a list of ControlId with their values for a camera\n> + *\n> + * A ControlList wraps a map of ControlId to ControlValue and provide\n> + * additional validation against the control information exposed by a Camera.\n> + *\n> + * A list is only valid for as long as the camera it refers to is valid. After\n> + * that calling any method of the ControlList class other than its destructor\n> + * will cause undefined behaviour.\n> + */\n> +\n> +/**\n> + * \\brief Construct a ControlList with a reference to the Camera it applies on\n> + * \\param[in] camera The camera\n> + */\n> +ControlList::ControlList(Camera *camera)\n> +\t: camera_(camera)\n> +{\n> +}\n> +\n> +/**\n> + * \\typedef ControlList::iterator\n> + * \\brief Iterator for the controls contained within the list\n> + */\n> +\n> +/**\n> + * \\typedef ControlList::const_iterator\n> + * \\brief Const iterator for the controls contained within the list\n> + */\n> +\n> +/**\n> + * \\fn iterator ControlList::begin()\n> + * \\brief Retrieve an iterator to the first Control in the list\n> + * \\return An iterator to the first Control in the list\n> + */\n> +\n> +/**\n> + * \\fn const_iterator ControlList::begin() const\n> + * \\brief Retrieve a const_iterator to the first Control in the list\n> + * \\return A const_iterator to the first Control in the list\n> + */\n> +\n> +/**\n> + * \\fn iterator ControlList::end()\n> + * \\brief Retrieve an iterator pointing to the past-the-end control in the list\n> + * \\return An iterator to the element following the last control in the list\n> + */\n> +\n> +/**\n> + * \\fn const_iterator ControlList::end() const\n> + * \\brief Retrieve a const iterator pointing to the past-the-end control in the\n> + * list\n> + * \\return A const iterator to the element following the last control in the\n> + * list\n> + */\n> +\n> +/**\n> + * \\brief Check if the list contains a control with the specified \\a info\n> + * \\param[in] info The control info\n> + * \\return True if the list contains a matching control, false otherwise\n> + */\n> +bool ControlList::contains(const ControlInfo *info) const\n> +{\n> +\treturn controls_.find(info) != controls_.end();\n> +}\n> +\n> +/**\n> + * \\fn ControlList::empty()\n> + * \\brief Identify if the list is empty\n> + * \\return True if the list does not contain any control, false otherwise\n> + */\n> +\n> +/**\n> + * \\fn ControlList::size()\n> + * \\brief Retrieve the number of controls in the list\n> + * \\return The number of Control entries stored in the list\n> + */\n> +\n> +/**\n> + * \\fn ControlList::clear()\n> + * \\brief Removes all controls from the list\n> + */\n> +\n> +/**\n> + * \\fn ControlList::operator[](const ControlInfo *info)\n> + * \\brief Access or insert the control specified by \\a info\n> + * \\param[in] info The control info\n> + *\n> + * This method returns a reference to the control identified by \\a info,\n> + * inserting it in the list if the info is not already present.\n> + *\n> + * \\return A reference to the value of the control identified by \\a info\n> + */\n> +\n> +/**\n> + * \\brief Update the list with a union of itself and \\a other\n> + * \\param other The other list\n> + *\n> + * Update the control list to include all values from the \\a other list.\n> + * Elements in the list whose control IDs are contained in \\a other are updated\n> + * with the value from \\a other. Elements in the \\a other list that have no\n> + * corresponding element in the list are added to the list with their value.\n> + *\n> + * The behaviour is undefined if the two lists refer to different Camera\n> + * instances.\n> + */\n> +void ControlList::update(const ControlList &other)\n> +{\n> +\tif (other.camera_ != camera_) {\n> +\t\tLOG(Controls, Error)\n> +\t\t\t<< \"Can't update ControlList from a different camera\";\n> +\t\treturn;\n> +\t}\n> +\n> +\tfor (auto it : other) {\n> +\t\tconst ControlInfo *info = it.first;\n> +\t\tconst ControlValue &value = it.second;\n> +\n> +\t\tcontrols_[info] = value;\n> +\t}\n> +}\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/libcamera/gen-controls.awk b/src/libcamera/gen-controls.awk\n> new file mode 100755\n> index 000000000000..f3d068123012\n> --- /dev/null\n> +++ b/src/libcamera/gen-controls.awk\n> @@ -0,0 +1,106 @@\n> +#!/usr/bin/awk -f\n> +\n> +# SPDX-License-Identifier: LGPL-2.1-or-later\n> +\n> +# Controls are documented using Doxygen in the main controls.cpp source.\n> +#\n> +# Generate control tables directly from the documentation, creating enumerations\n> +# to support the IDs and static type information regarding each control.\n> +\n> +BEGIN {\n> +\tid=0\n> +\tinput=ARGV[1]\n> +\tmode=ARGV[2]\n> +\toutput=ARGV[3]\n> +}\n> +\n> +# Detect Doxygen style comment blocks and ignore other lines\n> +/^\\/\\*\\*$/ { in_doxygen=1; first_line=1; next }\n> +// { if (!in_doxygen) next }\n> +\n> +# Entry point for the Control Documentation\n> +/ * \\\\enum ControlId$/ { in_controls=1; first_line=0; next }\n> +// { if (!in_controls) next }\n> +\n> +# Extract control information\n> +/ \\* \\\\var/ { names[++id]=$3; first_line=0; next }\n> +/ \\* ControlType:/ { types[id] = $3 }\n> +\n> +# End of comment blocks\n> +/^ \\*\\// { in_doxygen=0 }\n> +\n> +# Identify the end of controls\n> +/^ \\* \\\\/ { if (first_line) exit }\n> +// { first_line=0 }\n> +\n> +################################\n> +# Support output file generation\n> +\n> +function basename(file) {\n> +\tsub(\".*/\", \"\", file)\n> +\treturn file\n> +}\n> +\n> +function Header(file, description) {\n> +\tprint \"/* SPDX-License-Identifier: LGPL-2.1-or-later */\" > file\n> +\tprint \"/*\" > file\n> +\tprint \" * Copyright (C) 2019, Google Inc.\" > file\n> +\tprint \" *\" > file\n> +\tprint \" * \" basename(file) \" - \" description > file\n> +\tprint \" *\" > file\n> +\tprint \" * This file is auto-generated. Do not edit.\" > file\n> +\tprint \" */\" > file\n> +\tprint \"\" > file\n> +}\n> +\n> +function EnterNameSpace(file) {\n> +\tprint \"namespace libcamera {\" > file\n> +\tprint \"\" > file\n> +}\n> +\n> +function ExitNameSpace(file) {\n> +\tprint \"\" > file\n> +\tprint \"} /* namespace libcamera */\" > file\n> +}\n> +\n> +function GenerateHeader(file) {\n> +\tHeader(file, \"Control ID list\")\n> +\n> +\tprint \"#ifndef __LIBCAMERA_CONTROL_IDS_H__\" > file\n> +\tprint \"#define __LIBCAMERA_CONTROL_IDS_H__\" > file\n> +\tprint \"\" > file\n> +\n> +\tEnterNameSpace(file)\n> +\tprint \"enum ControlId {\" > file\n> +\tfor (i=1; i <= id; ++i) {\n> +\t\tprintf \"\\t%s,\\n\", names[i] > file\n> +\t}\n> +\tprint \"};\" > file\n> +\tExitNameSpace(file)\n> +\n> +\tprint \"\" > file\n> +\tprint \"#endif // __LIBCAMERA_CONTROL_IDS_H__\" > file\n> +}\n> +\n> +function GenerateTable(file) {\n> +\tHeader(file, \"Control types\")\n> +\tprint \"#include <libcamera/controls.h>\" > file\n> +\tprint \"\" > file\n> +\n> +\tEnterNameSpace(file)\n> +\n> +\tprint \"extern const std::unordered_map<ControlId, ControlIdentifier>\" > file\n> +\tprint \"controlTypes {\" > file\n> +\tfor (i=1; i <= id; ++i) {\n> +\t\tprintf \"\\t{ %s, { %s, \\\"%s\\\", ControlValue%s } },\\n\", names[i], names[i], names[i], types[i] > file\n> +\t}\n> +\tprint \"};\" > file\n> +\tExitNameSpace(file)\n> +}\n> +\n> +END {\n> +\tif (mode == \"--header\")\n> +\t\tGenerateHeader(output)\n> +\telse\n> +\t\tGenerateTable(output)\n> +}\n> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\n> index 985aa7e8ab0e..b1ee92735e41 100644\n> --- a/src/libcamera/meson.build\n> +++ b/src/libcamera/meson.build\n> @@ -3,6 +3,7 @@ libcamera_sources = files([\n>      'camera.cpp',\n>      'camera_manager.cpp',\n>      'camera_sensor.cpp',\n> +    'controls.cpp',\n>      'device_enumerator.cpp',\n>      'device_enumerator_sysfs.cpp',\n>      'event_dispatcher.cpp',\n> @@ -66,6 +67,16 @@ if libudev.found()\n>      ])\n>  endif\n>  \n> +gen_controls = files('gen-controls.awk')\n> +\n> +control_types_cpp = custom_target('control_types_cpp',\n> +                                  input : files('controls.cpp'),\n> +                                  output : 'control_types.cpp',\n> +                                  depend_files : gen_controls,\n> +                                  command : [gen_controls, '@INPUT@', '--code', '@OUTPUT@'])\n> +\n> +libcamera_sources += control_types_cpp\n> +\n>  libcamera_deps = [\n>      cc.find_library('dl'),\n>      libudev,\n> -- \n> Regards,\n> \n> Laurent Pinchart\n> \n> _______________________________________________\n> libcamera-devel mailing list\n> libcamera-devel@lists.libcamera.org\n> https://lists.libcamera.org/listinfo/libcamera-devel","headers":{"Return-Path":"<niklas.soderlund@ragnatech.se>","Received":["from mail-lj1-x242.google.com (mail-lj1-x242.google.com\n\t[IPv6:2a00:1450:4864:20::242])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 1D7ED6157D\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue,  2 Jul 2019 01:59:05 +0200 (CEST)","by mail-lj1-x242.google.com with SMTP id k18so14985007ljc.11\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 01 Jul 2019 16:59:05 -0700 (PDT)","from localhost (customer-145-14-112-32.stosn.net. [145.14.112.32])\n\tby smtp.gmail.com with ESMTPSA id\n\tu13sm8580lfu.37.2019.07.01.16.59.03\n\t(version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256);\n\tMon, 01 Jul 2019 16:59:03 -0700 (PDT)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=ragnatech-se.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:content-transfer-encoding:in-reply-to\n\t:user-agent; bh=DwkveMYqAfaPbZhzBK8B/rEXU2EkarQNRFU1A+cVKXM=;\n\tb=ZzdY1zTcQLih9fro9suFcTIikKbF+ESzg3YTohCuhD78Zs1lsFbAFCB3t4sH06gyjW\n\tDyWnzGSDEuTUqmMTfC/vt30jnWTbLjAL4yD3FvmrJU/2Lw/eVubwo2JmQ4IA00VZxn04\n\tvdNNiUeq3iInkijwk0XxKKQ94oSiteUcPf0gE8DFS5mFtp4uTKdhEg0KUCHcIUx8T1UU\n\tjxMJsj3EbAiHgxQU5lASvmELBC+ZaR7JEotKiRSsDtNSIRTkpLXD61Ha45PfaQTZE4Vt\n\tdOW8v5nmCEop1ng29KuMUpIAQedZWkmJLbSeg9Yey/qyeijjpt+4bge5e9nsFv8hNR8Z\n\t8GJQ==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:content-transfer-encoding\n\t:in-reply-to:user-agent;\n\tbh=DwkveMYqAfaPbZhzBK8B/rEXU2EkarQNRFU1A+cVKXM=;\n\tb=SEk+UCfROUgUVzssLnA/fbmC0gXVqj1pj+1zbedH9BP0DrJi5BaAFucBqIhPRgdkX4\n\tHgjQvGBbw0CEL7PyMJKpOhQCLGeOGrSiKU6njKC7DwZccimTxAQwrOy3q2qodaPVAq0E\n\tsDZVAM5Ar42vj8xwKa0VRVz+NLbVwqAOyeq8UA1ofRzU9I+ndGyGeUQxJccQ7AQRX/7G\n\tYCJayfmhMHMnCPZU3MLLvm99t28SktvF+lOTni9I5sbt94ETn/7eNg5C0eFCCV1o2mFy\n\t2JDWAEbzQzfb2fvqGyTHf0AmiMEq4iQgKjXMnaBUZlra+U7BYTGXxW/fahhhq18Kkds6\n\td4og==","X-Gm-Message-State":"APjAAAVziaCa0Z5MSDzOtidW5ms83WwDCxfBXMnB14TR2rhyW6ssDzDk\n\tMCdq6sgkqfkdGdJqkkhDTaeGSA==","X-Google-Smtp-Source":"APXvYqwYSFgTTUAeEdyjItDG75jkTHXYNtxjV6puDdRrvustiXVX/gcr2sikdkjjfFiH2yTw6cSDEA==","X-Received":"by 2002:a2e:9f57:: with SMTP id\n\tv23mr16536107ljk.138.1562025544440; \n\tMon, 01 Jul 2019 16:59:04 -0700 (PDT)","Date":"Tue, 2 Jul 2019 01:59:03 +0200","From":"Niklas =?iso-8859-1?q?S=F6derlund?= <niklas.soderlund@ragnatech.se>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190701235903.GE9228@bigcity.dyn.berto.se>","References":"<20190701201504.28487-1-laurent.pinchart@ideasonboard.com>\n\t<20190701201504.28487-4-laurent.pinchart@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=iso-8859-1","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20190701201504.28487-4-laurent.pinchart@ideasonboard.com>","User-Agent":"Mutt/1.12.1 (2019-06-15)","Subject":"Re: [libcamera-devel] [PATCH v4 03/13] libcamera: controls:\n\tIntroduce control-related data types","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Mon, 01 Jul 2019 23:59:05 -0000"}}]