{"id":2630,"url":"https://patchwork.libcamera.org/api/1.1/patches/2630/?format=json","web_url":"https://patchwork.libcamera.org/patch/2630/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20200113164245.52535-16-jacopo@jmondi.org>","date":"2020-01-13T16:42:37","name":"[libcamera-devel,15/23] libcamera: controls: Support compound controls in ControlValue","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"f521856949094258fed329e255cca2e440b3b0ba","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/1.1/people/3/?format=json","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"delegate":{"id":15,"url":"https://patchwork.libcamera.org/api/1.1/users/15/?format=json","username":"jmondi","first_name":"Jacopo","last_name":"Mondi","email":"jacopo@jmondi.org"},"mbox":"https://patchwork.libcamera.org/patch/2630/mbox/","series":[{"id":618,"url":"https://patchwork.libcamera.org/api/1.1/series/618/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=618","date":"2020-01-13T16:42:22","name":"Properties and compound controls","version":1,"mbox":"https://patchwork.libcamera.org/series/618/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/2630/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/2630/checks/","tags":{},"headers":{"Return-Path":"<jacopo@jmondi.org>","Received":["from relay11.mail.gandi.net (relay11.mail.gandi.net\n\t[217.70.178.231])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id EA66A60728\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 13 Jan 2020 17:40:35 +0100 (CET)","from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101])\n\t(Authenticated sender: jacopo@jmondi.org)\n\tby relay11.mail.gandi.net (Postfix) with ESMTPSA id 757CB100005;\n\tMon, 13 Jan 2020 16:40:35 +0000 (UTC)"],"From":"Jacopo Mondi <jacopo@jmondi.org>","To":"libcamera-devel@lists.libcamera.org","Date":"Mon, 13 Jan 2020 17:42:37 +0100","Message-Id":"<20200113164245.52535-16-jacopo@jmondi.org>","X-Mailer":"git-send-email 2.24.0","In-Reply-To":"<20200113164245.52535-1-jacopo@jmondi.org>","References":"<20200113164245.52535-1-jacopo@jmondi.org>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","Subject":"[libcamera-devel] [PATCH 15/23] libcamera: controls: Support\n\tcompound controls in ControlValue","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","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, 13 Jan 2020 16:40:37 -0000"},"content":"Add compound controls support to the ControlValue class. The polymorphic class\ncan now store more than a single element and supports access and\ncreation through the use of Span<>.\n\nSigned-off-by: Jacopo Mondi <jacopo@jmondi.org>\n---\n include/libcamera/controls.h |  37 +++-\n src/libcamera/controls.cpp   | 329 ++++++++++++++++++++++++++++++++---\n 2 files changed, 333 insertions(+), 33 deletions(-)","diff":"diff --git a/include/libcamera/controls.h b/include/libcamera/controls.h\nindex 8fa33d93b088..bdbdb213528d 100644\n--- a/include/libcamera/controls.h\n+++ b/include/libcamera/controls.h\n@@ -11,6 +11,8 @@\n #include <string>\n #include <unordered_map>\n \n+#include <libcamera/span.h>\n+\n namespace libcamera {\n \n class ControlValidator;\n@@ -21,6 +23,10 @@ enum ControlType {\n \tControlTypeInteger32,\n \tControlTypeInteger64,\n \tControlTypeFloat,\n+\tControlTypeCompoundBool,\n+\tControlTypeCompoundInt32,\n+\tControlTypeCompoundInt64,\n+\tControlTypeCompoundFloat,\n };\n \n class ControlValue\n@@ -31,12 +37,18 @@ public:\n \tControlValue(int32_t value);\n \tControlValue(int64_t value);\n \tControlValue(float value);\n+\tControlValue(Span<bool> &values);\n+\tControlValue(Span<int32_t> &values);\n+\tControlValue(Span<int64_t> &values);\n+\tControlValue(Span<float> &values);\n+\t~ControlValue();\n \n \tControlType type() const { return type_; }\n \tbool isNone() const { return type_ == ControlTypeNone; }\n+\tstd::size_t numElements() const { return numElements_; }\n \n \ttemplate<typename T>\n-\tconst T &get() const;\n+\tT get() const;\n \ttemplate<typename T>\n \tvoid set(const T &value);\n \n@@ -57,6 +69,21 @@ private:\n \t\tint64_t integer64_;\n \t\tfloat float_;\n \t};\n+\n+\tunion {\n+\t\tvoid *pvoid_;\n+\t\tbool *pbool_;\n+\t\tint32_t *p32_;\n+\t\tint64_t *p64_;\n+\t\tfloat *pfloat_;\n+\t};\n+\n+\tstd::size_t numElements_;\n+\n+\tvoid release();\n+\tbool compareElement(const ControlValue &other) const;\n+\tbool compareElement(const ControlValue &other, unsigned int i) const;\n+\tstd::string elemToString(unsigned int i) const;\n };\n \n class ControlId\n@@ -215,13 +242,11 @@ public:\n \tbool contains(unsigned int id) const;\n \n \ttemplate<typename T>\n-\tconst T &get(const Control<T> &ctrl) const\n+\tconst T get(const Control<T> &ctrl) const\n \t{\n \t\tconst ControlValue *val = find(ctrl.id());\n-\t\tif (!val) {\n-\t\t\tstatic T t(0);\n-\t\t\treturn t;\n-\t\t}\n+\t\tif (!val)\n+\t\t\treturn T{};\n \n \t\treturn val->get<T>();\n \t}\ndiff --git a/src/libcamera/controls.cpp b/src/libcamera/controls.cpp\nindex 74ce5d0ba4f1..7718a53911e6 100644\n--- a/src/libcamera/controls.cpp\n+++ b/src/libcamera/controls.cpp\n@@ -9,7 +9,9 @@\n \n #include <iomanip>\n #include <sstream>\n-#include <string>\n+#include <string.h>\n+\n+#include <libcamera/span.h>\n \n #include \"control_validator.h\"\n #include \"log.h\"\n@@ -60,6 +62,14 @@ LOG_DEFINE_CATEGORY(Controls)\n  * The control stores a 64-bit integer value\n  * \\var ControlTypeFloat\n  * The control stores a 32-bit floating point value\n+ * \\var ControlTypeCompoundBool\n+ * The control stores an array of boolean values\n+ * \\var ControlTypeCompoundInt32\n+ * The control stores an array of 32-bit integer values\n+ * \\var ControlTypeCompoundInt64\n+ * The control stores an array of 64-bit integer values\n+ * \\var ControlTypeCompoundFloat\n+ * The control stores an array of 32-bit floating values\n  */\n \n /**\n@@ -71,7 +81,7 @@ LOG_DEFINE_CATEGORY(Controls)\n  * \\brief Construct an empty ControlValue.\n  */\n ControlValue::ControlValue()\n-\t: type_(ControlTypeNone)\n+\t: type_(ControlTypeNone), pvoid_(nullptr), numElements_(0)\n {\n }\n \n@@ -80,7 +90,8 @@ ControlValue::ControlValue()\n  * \\param[in] value Boolean value to store\n  */\n ControlValue::ControlValue(bool value)\n-\t: type_(ControlTypeBool), bool_(value)\n+\t: type_(ControlTypeBool), bool_(value), pvoid_(nullptr),\n+\t  numElements_(1)\n {\n }\n \n@@ -89,7 +100,8 @@ ControlValue::ControlValue(bool value)\n  * \\param[in] value Integer value to store\n  */\n ControlValue::ControlValue(int32_t value)\n-\t: type_(ControlTypeInteger32), integer32_(value)\n+\t: type_(ControlTypeInteger32), integer32_(value), pvoid_(nullptr),\n+\t  numElements_(1)\n {\n }\n \n@@ -98,7 +110,8 @@ ControlValue::ControlValue(int32_t value)\n  * \\param[in] value Integer value to store\n  */\n ControlValue::ControlValue(int64_t value)\n-\t: type_(ControlTypeInteger64), integer64_(value)\n+\t: type_(ControlTypeInteger64), integer64_(value), pvoid_(nullptr),\n+\t  numElements_(1)\n {\n }\n \n@@ -107,8 +120,73 @@ ControlValue::ControlValue(int64_t value)\n  * \\param[in] value Float value to store\n  */\n ControlValue::ControlValue(float value)\n-\t: type_(ControlTypeFloat), float_(value)\n+\t: type_(ControlTypeFloat), float_(value), pvoid_(nullptr),\n+\t  numElements_(1)\n+{\n+}\n+\n+/**\n+ * \\brief Construct a ControlValue with a Span of boolean elements\n+ * \\param[in] values Span of boolean values to store\n+ */\n+ControlValue::ControlValue(Span<bool> &values)\n+\t: type_(ControlTypeCompoundBool), numElements_(values.size())\n {\n+\tpbool_ = new bool[numElements_];\n+\tmemcpy(pbool_, values.data(), sizeof(bool) * numElements_);\n+}\n+\n+/**\n+ * \\brief Construct a ControlValue with a Span of 32 bit integers elements\n+ * \\param[in] values Span of 32 bit integer values to store\n+ */\n+ControlValue::ControlValue(Span<int32_t> &values)\n+\t: type_(ControlTypeCompoundInt32), numElements_(values.size())\n+{\n+\tp32_ = new int32_t[numElements_];\n+\tmemcpy(p32_, values.data(), sizeof(int32_t) * numElements_);\n+}\n+\n+/**\n+ * \\brief Construct a ControlValue with a Span of 64 bit integers elements\n+ * \\param[in] values Span of 64 bit integer values to store\n+ */\n+ControlValue::ControlValue(Span<int64_t> &values)\n+\t: type_(ControlTypeCompoundInt64), numElements_(values.size())\n+{\n+\tp64_ = new int64_t[numElements_];\n+\tmemcpy(p64_, values.data(), sizeof(int64_t) * numElements_);\n+}\n+\n+/**\n+ * \\brief Construct a ControlValue with a Span of float elements\n+ * \\param[in] values Span of float values to store\n+ */\n+ControlValue::ControlValue(Span<float> &values)\n+\t: type_(ControlTypeCompoundFloat), numElements_(values.size())\n+{\n+\tpfloat_ = new float[numElements_];\n+\tmemcpy(pfloat_, values.data(), sizeof(float) * numElements_);\n+}\n+\n+void ControlValue::release()\n+{\n+\tswitch (type_) {\n+\tcase ControlTypeCompoundBool:\n+\tcase ControlTypeCompoundInt32:\n+\tcase ControlTypeCompoundInt64:\n+\tcase ControlTypeCompoundFloat:\n+\t\tdelete[] pbool_;\n+\t\tpbool_ = nullptr;\n+\t\t/* fall-through. */\n+\tdefault:\n+\t\treturn;\n+\t}\n+}\n+\n+ControlValue::~ControlValue()\n+{\n+\trelease();\n }\n \n /**\n@@ -124,24 +202,38 @@ ControlValue::ControlValue(float value)\n  */\n \n /**\n- * \\fn template<typename T> const T &ControlValue::get() const\n- * \\brief Get the control value\n+ * \\fn ControlValue::numElements()\n+ * \\brief Retrieve the number of elements stored in the ControlValue\n+ * \\return The number of elements stored in the ControlValue\n+ */\n+\n+/**\n+ * \\fn template<typename T> const T ControlValue::get() const\n+ * \\brief Get the control values\n  *\n  * The control value type shall match the type T, otherwise the behaviour is\n  * undefined.\n  *\n- * \\return The control value\n+ * This function applies to ControlValue instances which store a single or\n+ * multiple values. The ControlValue's elements are returned in a Span in the\n+ * former case.\n+ *\n+ * \\return The control value or a Span of values\n  */\n \n /**\n- * \\fn template<typename T> void ControlValue::set(const T &value)\n- * \\brief Set the control value to \\a value\n- * \\param[in] value The control value\n+ * \\fn template<typename T> void ControlValue::set(const T &values)\n+ * \\brief Set the control values to \\a values\n+ * \\param[in] values The control values\n+ *\n+ * This function can be used to set the ControlValue to a single value, or\n+ * to store multiple values by providing a Span<> of elements to the\n+ * function.\n  */\n \n #ifndef __DOXYGEN__\n template<>\n-const bool &ControlValue::get<bool>() const\n+bool ControlValue::get<bool>() const\n {\n \tASSERT(type_ == ControlTypeBool);\n \n@@ -149,7 +241,19 @@ const bool &ControlValue::get<bool>() const\n }\n \n template<>\n-const int32_t &ControlValue::get<int32_t>() const\n+Span<bool> ControlValue::get<Span<bool>>() const\n+{\n+\tASSERT(type_ == ControlTypeCompoundBool);\n+\n+\t/*\n+\t * Explicitly create a Span<bool> instance, otherwise the compiler\n+\t * tries to match with the Span class initializer_list constructor.\n+\t */\n+\treturn Span<bool>(pbool_, static_cast<std::size_t>(numElements_));\n+}\n+\n+template<>\n+int32_t ControlValue::get<int32_t>() const\n {\n \tASSERT(type_ == ControlTypeInteger32 || type_ == ControlTypeInteger64);\n \n@@ -157,7 +261,16 @@ const int32_t &ControlValue::get<int32_t>() const\n }\n \n template<>\n-const int64_t &ControlValue::get<int64_t>() const\n+Span<int32_t> ControlValue::get<Span<int32_t>>() const\n+{\n+\tASSERT(type_ == ControlTypeCompoundInt32 ||\n+\t       type_ == ControlTypeCompoundInt64);\n+\n+\treturn { p32_, numElements_ };\n+}\n+\n+template<>\n+int64_t ControlValue::get<int64_t>() const\n {\n \tASSERT(type_ == ControlTypeInteger32 || type_ == ControlTypeInteger64);\n \n@@ -165,62 +278,190 @@ const int64_t &ControlValue::get<int64_t>() const\n }\n \n template<>\n-const float &ControlValue::get<float>() const\n+Span<int64_t> ControlValue::get<Span<int64_t>>() const\n+{\n+\tASSERT(type_ == ControlTypeCompoundInt32 ||\n+\t       type_ == ControlTypeCompoundInt64);\n+\n+\treturn { p64_, numElements_ };\n+}\n+\n+template<>\n+float ControlValue::get<float>() const\n {\n \tASSERT(type_ == ControlTypeFloat);\n \n \treturn float_;\n }\n \n+template<>\n+Span<float> ControlValue::get<Span<float>>() const\n+{\n+\tASSERT(type_ == ControlTypeCompoundFloat);\n+\n+\treturn { pfloat_, numElements_ };\n+}\n+\n template<>\n void ControlValue::set<bool>(const bool &value)\n {\n+\trelease();\n+\n \ttype_ = ControlTypeBool;\n \tbool_ = value;\n+\tnumElements_ = 1;\n+}\n+\n+template<>\n+void ControlValue::set<Span<bool>>(const Span<bool> &values)\n+{\n+\trelease();\n+\n+\ttype_ = ControlTypeCompoundBool;\n+\tnumElements_ = values.size();\n+\n+\tpbool_ = new bool[numElements_];\n+\tmemcpy(pbool_, values.data(), sizeof(bool) * numElements_);\n }\n \n template<>\n void ControlValue::set<int32_t>(const int32_t &value)\n {\n+\trelease();\n+\n \ttype_ = ControlTypeInteger32;\n \tinteger32_ = value;\n+\tnumElements_ = 1;\n+}\n+\n+template<>\n+void ControlValue::set<Span<int32_t>>(const Span<int32_t> &values)\n+{\n+\trelease();\n+\n+\ttype_ = ControlTypeCompoundInt32;\n+\tnumElements_ = values.size();\n+\n+\tp32_ = new int32_t[numElements_];\n+\tmemcpy(p32_, values.data(), sizeof(int32_t) * numElements_);\n }\n \n template<>\n void ControlValue::set<int64_t>(const int64_t &value)\n {\n+\trelease();\n+\n \ttype_ = ControlTypeInteger64;\n \tinteger64_ = value;\n+\tnumElements_ = 1;\n+}\n+\n+template<>\n+void ControlValue::set<Span<int64_t>>(const Span<int64_t> &values)\n+{\n+\trelease();\n+\n+\ttype_ = ControlTypeCompoundInt64;\n+\tnumElements_ = values.size();\n+\n+\tp64_ = new int64_t[numElements_];\n+\tmemcpy(p64_, values.data(), sizeof(int64_t) * numElements_);\n }\n \n template<>\n void ControlValue::set<float>(const float &value)\n {\n+\trelease();\n+\n \ttype_ = ControlTypeFloat;\n \tfloat_ = value;\n+\tnumElements_ = 1;\n }\n+\n+template<>\n+void ControlValue::set<Span<float>>(const Span<float> &values)\n+{\n+\trelease();\n+\n+\ttype_ = ControlTypeCompoundFloat;\n+\tnumElements_ = values.size();\n+\n+\tpfloat_ = new float[numElements_];\n+\tmemcpy(pfloat_, values.data(), sizeof(float) * numElements_);\n+}\n+\n #endif /* __DOXYGEN__ */\n \n+std::string ControlValue::elemToString(unsigned int i) const\n+{\n+\tswitch (type_) {\n+\tcase ControlTypeBool:\n+\t\treturn bool_ ? \"True \" : \"False \";\n+\tcase ControlTypeInteger32:\n+\t\treturn std::to_string(integer32_);\n+\tcase ControlTypeInteger64:\n+\t\treturn std::to_string(integer64_);\n+\tcase ControlTypeFloat:\n+\t\treturn std::to_string(float_);\n+\tcase ControlTypeCompoundBool:\n+\t\treturn pbool_[i] ? \"True \" : \"False \";\n+\tcase ControlTypeCompoundInt32:\n+\t\treturn std::to_string(p32_[i]) + \" \";\n+\tcase ControlTypeCompoundInt64:\n+\t\treturn std::to_string(p64_[i]) + \" \";\n+\tcase ControlTypeCompoundFloat:\n+\t\treturn std::to_string(pfloat_[i]) + \" \";\n+\tdefault:\n+\t\treturn \"<None>\";\n+\t}\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+\tif (ControlTypeNone)\n+\t\treturn \"<ValueType Error>\";\n+\n+\tstd::string str;\n+\tfor (unsigned int i = 0; i < numElements_; ++i)\n+\t\tstr += elemToString(i);\n+\n+\treturn str;\n+}\n+\n+bool ControlValue::compareElement(const ControlValue &other) const\n {\n \tswitch (type_) {\n-\tcase ControlTypeNone:\n-\t\treturn \"<None>\";\n \tcase ControlTypeBool:\n-\t\treturn bool_ ? \"True\" : \"False\";\n+\t\treturn bool_ == other.bool_;\n \tcase ControlTypeInteger32:\n-\t\treturn std::to_string(integer32_);\n+\t\treturn integer32_ == other.integer32_;\n \tcase ControlTypeInteger64:\n-\t\treturn std::to_string(integer64_);\n+\t\treturn integer64_ == other.integer64_;\n \tcase ControlTypeFloat:\n-\t\treturn std::to_string(float_);\n+\t\treturn float_ == other.float_;\n+\tdefault:\n+\t\treturn false;\n \t}\n+}\n \n-\treturn \"<ValueType Error>\";\n+bool ControlValue::compareElement(const ControlValue &other, unsigned int i) const\n+{\n+\tswitch (type_) {\n+\tcase ControlTypeCompoundBool:\n+\t\treturn pbool_[i] == other.pbool_[i];\n+\tcase ControlTypeCompoundInt32:\n+\t\treturn p32_[i] == other.p32_[i];\n+\tcase ControlTypeCompoundInt64:\n+\t\treturn p64_[i] == other.p64_[i];\n+\tcase ControlTypeCompoundFloat:\n+\t\treturn pfloat_[i] == other.pfloat_[i];\n+\tdefault:\n+\t\treturn false;\n+\t}\n }\n \n /**\n@@ -232,15 +473,25 @@ bool ControlValue::operator==(const ControlValue &other) const\n \tif (type_ != other.type_)\n \t\treturn false;\n \n+\tif (numElements_ != other.numElements())\n+\t\treturn false;\n+\n \tswitch (type_) {\n \tcase ControlTypeBool:\n-\t\treturn bool_ == other.bool_;\n \tcase ControlTypeInteger32:\n-\t\treturn integer32_ == other.integer32_;\n \tcase ControlTypeInteger64:\n-\t\treturn integer64_ == other.integer64_;\n \tcase ControlTypeFloat:\n-\t\treturn float_ == other.float_;\n+\t\treturn compareElement(other);\n+\tcase ControlTypeCompoundBool:\n+\tcase ControlTypeCompoundInt32:\n+\tcase ControlTypeCompoundInt64:\n+\tcase ControlTypeCompoundFloat:\n+\t\tfor (unsigned int i = 0; i < numElements_; ++i) {\n+\t\t\tif (!compareElement(other, i))\n+\t\t\t\treturn false;\n+\t\t}\n+\n+\t\treturn true;\n \tdefault:\n \t\treturn false;\n \t}\n@@ -360,23 +611,47 @@ Control<bool>::Control(unsigned int id, const char *name)\n {\n }\n \n+template<>\n+Control<Span<bool>>::Control(unsigned int id, const char *name)\n+\t: ControlId(id, name, ControlTypeCompoundBool)\n+{\n+}\n+\n template<>\n Control<int32_t>::Control(unsigned int id, const char *name)\n \t: ControlId(id, name, ControlTypeInteger32)\n {\n }\n \n+template<>\n+Control<Span<int32_t>>::Control(unsigned int id, const char *name)\n+\t: ControlId(id, name, ControlTypeCompoundInt32)\n+{\n+}\n+\n template<>\n Control<int64_t>::Control(unsigned int id, const char *name)\n \t: ControlId(id, name, ControlTypeInteger64)\n {\n }\n \n+template<>\n+Control<Span<int64_t>>::Control(unsigned int id, const char *name)\n+\t: ControlId(id, name, ControlTypeCompoundInt64)\n+{\n+}\n+\n template<>\n Control<float>::Control(unsigned int id, const char *name)\n \t: ControlId(id, name, ControlTypeFloat)\n {\n }\n+\n+template<>\n+Control<Span<float>>::Control(unsigned int id, const char *name)\n+\t: ControlId(id, name, ControlTypeCompoundFloat)\n+{\n+}\n #endif /* __DOXYGEN__ */\n \n /**\n","prefixes":["libcamera-devel","15/23"]}