Show a patch.

GET /api/patches/2423/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2423,
    "url": "https://patchwork.libcamera.org/api/patches/2423/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/2423/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20191211145327.58633-2-jacopo@jmondi.org>",
    "date": "2019-12-11T14:53:27",
    "name": "[libcamera-devel,RFC,2/2] controls: Define controls as compound",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "97056bfe4f7e845e5f89d290e7d2553fe1ead797",
    "submitter": {
        "id": 3,
        "url": "https://patchwork.libcamera.org/api/people/3/?format=api",
        "name": "Jacopo Mondi",
        "email": "jacopo@jmondi.org"
    },
    "delegate": {
        "id": 15,
        "url": "https://patchwork.libcamera.org/api/users/15/?format=api",
        "username": "jmondi",
        "first_name": "Jacopo",
        "last_name": "Mondi",
        "email": "jacopo@jmondi.org"
    },
    "mbox": "https://patchwork.libcamera.org/patch/2423/mbox/",
    "series": [
        {
            "id": 587,
            "url": "https://patchwork.libcamera.org/api/series/587/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=587",
            "date": "2019-12-11T14:53:26",
            "name": "[libcamera-devel,RFC,1/2] WIP libcamera: controls: Support compound controls",
            "version": 1,
            "mbox": "https://patchwork.libcamera.org/series/587/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/2423/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/2423/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<jacopo@jmondi.org>",
        "Received": [
            "from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net\n\t[217.70.183.199])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id D74A2600F5\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 11 Dec 2019 15:51:19 +0100 (CET)",
            "from uno.lan (93-34-114-233.ip49.fastwebnet.it [93.34.114.233])\n\t(Authenticated sender: jacopo@jmondi.org)\n\tby relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 6DE0AFF80F;\n\tWed, 11 Dec 2019 14:51:19 +0000 (UTC)"
        ],
        "X-Originating-IP": "93.34.114.233",
        "From": "Jacopo Mondi <jacopo@jmondi.org>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Wed, 11 Dec 2019 15:53:27 +0100",
        "Message-Id": "<20191211145327.58633-2-jacopo@jmondi.org>",
        "X-Mailer": "git-send-email 2.24.0",
        "In-Reply-To": "<20191211145327.58633-1-jacopo@jmondi.org>",
        "References": "<20191211145327.58633-1-jacopo@jmondi.org>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[libcamera-devel] [RFC 2/2] controls: Define controls as compound",
        "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": "Wed, 11 Dec 2019 14:51:20 -0000"
    },
    "content": "Add 'isCompound' flag to the control framework.\n\nSigned-off-by: Jacopo Mondi <jacopo@jmondi.org>\n---\n include/libcamera/controls.h         | 12 +++++--\n src/libcamera/control_ids.yaml       |  3 +-\n src/libcamera/control_serializer.cpp |  4 ++-\n src/libcamera/controls.cpp           | 24 +++++++-------\n src/libcamera/gen-controls.py        | 12 ++++++-\n src/libcamera/v4l2_controls.cpp      |  4 ++-\n test/controls/compound_controls.cpp  | 48 +++++++++++++++++-----------\n 7 files changed, 70 insertions(+), 37 deletions(-)",
    "diff": "diff --git a/include/libcamera/controls.h b/include/libcamera/controls.h\nindex b9f8d4db0bea..ddd641e01655 100644\n--- a/include/libcamera/controls.h\n+++ b/include/libcamera/controls.h\n@@ -94,14 +94,16 @@ private:\n class ControlId\n {\n public:\n-\tControlId(unsigned int id, const std::string &name, ControlType type)\n-\t\t: id_(id), name_(name), type_(type)\n+\tControlId(unsigned int id, const std::string &name, ControlType type,\n+\t\t  bool isCompound)\n+\t\t: id_(id), name_(name), type_(type), isCompound_(isCompound)\n \t{\n \t}\n \n \tunsigned int id() const { return id_; }\n \tconst std::string &name() const { return name_; }\n \tControlType type() const { return type_; }\n+\tbool isCompound() const { return isCompound_; }\n \n private:\n \tControlId &operator=(const ControlId &) = delete;\n@@ -110,6 +112,7 @@ private:\n \tunsigned int id_;\n \tstd::string name_;\n \tControlType type_;\n+\tbool isCompound_;\n };\n \n static inline bool operator==(unsigned int lhs, const ControlId &rhs)\n@@ -138,7 +141,7 @@ class Control : public ControlId\n public:\n \tusing type = T;\n \n-\tControl(unsigned int id, const char *name);\n+\tControl(unsigned int id, const char *name, bool isCompound = false);\n \n private:\n \tControl(const Control &) = delete;\n@@ -272,6 +275,9 @@ public:\n \ttemplate<typename T>\n \tvoid set(const Control<T> &ctrl, const Span<T> &values)\n \t{\n+\t\tif (!ctrl.isCompound())\n+\t\t\treturn;\n+\n \t\tControlValue *val = find(ctrl.id());\n \t\tif (!val)\n \t\t\treturn;\ndiff --git a/src/libcamera/control_ids.yaml b/src/libcamera/control_ids.yaml\nindex b72e81dae060..1bdece651638 100644\n--- a/src/libcamera/control_ids.yaml\n+++ b/src/libcamera/control_ids.yaml\n@@ -51,7 +51,8 @@ controls:\n       description: Specify a fixed gain parameter\n \n   - CompoundControl:\n-      type: int8_t\n+      type: int32_t\n       description: A fictional compound control\n+      compound: true\n \n ...\ndiff --git a/src/libcamera/control_serializer.cpp b/src/libcamera/control_serializer.cpp\nindex 2140d3a5dd3f..82502285c5ca 100644\n--- a/src/libcamera/control_serializer.cpp\n+++ b/src/libcamera/control_serializer.cpp\n@@ -415,8 +415,10 @@ ControlInfoMap ControlSerializer::deserialize<ControlInfoMap>(ByteStreamBuffer &\n \t\t/**\n \t\t * \\todo Find a way to preserve the control name for debugging\n \t\t * purpose.\n+\t\t *\n+\t\t * FIXME: set isCompound to false unconditionally\n \t\t */\n-\t\tcontrolIds_.emplace_back(utils::make_unique<ControlId>(entry.id, \"\", type));\n+\t\tcontrolIds_.emplace_back(utils::make_unique<ControlId>(entry.id, \"\", type, false));\n \n \t\tif (entry.offset != values.offset()) {\n \t\t\tLOG(Serializer, Error)\ndiff --git a/src/libcamera/controls.cpp b/src/libcamera/controls.cpp\nindex 64d99f7669b6..8fb0088150d0 100644\n--- a/src/libcamera/controls.cpp\n+++ b/src/libcamera/controls.cpp\n@@ -581,38 +581,38 @@ bool ControlValue::operator==(const ControlValue &other) const\n \n #ifndef __DOXYGEN__\n template<>\n-Control<void>::Control(unsigned int id, const char *name)\n-\t: ControlId(id, name, ControlTypeNone)\n+Control<void>::Control(unsigned int id, const char *name, bool isCompound)\n+\t: ControlId(id, name, ControlTypeNone, isCompound)\n {\n }\n \n template<>\n-Control<bool>::Control(unsigned int id, const char *name)\n-\t: ControlId(id, name, ControlTypeBool)\n+Control<bool>::Control(unsigned int id, const char *name, bool isCompound)\n+\t: ControlId(id, name, ControlTypeBool, isCompound)\n {\n }\n \n template<>\n-Control<int8_t>::Control(unsigned int id, const char *name)\n-\t: ControlId(id, name, ControlTypeInteger8)\n+Control<int8_t>::Control(unsigned int id, const char *name, bool isCompound)\n+\t: ControlId(id, name, ControlTypeInteger8, isCompound)\n {\n }\n \n template<>\n-Control<int32_t>::Control(unsigned int id, const char *name)\n-\t: ControlId(id, name, ControlTypeInteger32)\n+Control<int32_t>::Control(unsigned int id, const char *name, bool isCompound)\n+\t: ControlId(id, name, ControlTypeInteger32, isCompound)\n {\n }\n \n template<>\n-Control<int64_t>::Control(unsigned int id, const char *name)\n-\t: ControlId(id, name, ControlTypeInteger64)\n+Control<int64_t>::Control(unsigned int id, const char *name, bool isCompound)\n+\t: ControlId(id, name, ControlTypeInteger64, isCompound)\n {\n }\n \n template<>\n-Control<float>::Control(unsigned int id, const char *name)\n-\t: ControlId(id, name, ControlTypeFloat)\n+Control<float>::Control(unsigned int id, const char *name, bool isCompound)\n+\t: ControlId(id, name, ControlTypeFloat, isCompound)\n {\n }\n #endif /* __DOXYGEN__ */\ndiff --git a/src/libcamera/gen-controls.py b/src/libcamera/gen-controls.py\nindex 4a1ee52cdb04..820b862dcf01 100755\n--- a/src/libcamera/gen-controls.py\n+++ b/src/libcamera/gen-controls.py\n@@ -26,6 +26,7 @@ ${description}\\n *\\n''')\n ${description}\n  */''')\n     def_template = string.Template('extern const Control<${type}> ${name}(${id_name}, \"${name}\");')\n+    def_compound_template = string.Template('extern const Control<${type}> ${name}(${id_name}, \"${name}\", true);')\n \n     ctrls_doc = []\n     ctrls_def = []\n@@ -67,8 +68,17 @@ ${description}\n         except KeyError:\n             pass\n \n+        try:\n+            compound = ctrl['compound']\n+            isCompound = True\n+        except KeyError:\n+            isCompound = False\n+\n         ctrls_doc.append(doc_template.substitute(info))\n-        ctrls_def.append(def_template.substitute(info))\n+        if isCompound:\n+            ctrls_def.append(def_compound_template.substitute(info))\n+        else:\n+            ctrls_def.append(def_template.substitute(info))\n         ctrls_map.append('\\t{ ' + id_name + ', &' + name + ' },')\n \n     return {\ndiff --git a/src/libcamera/v4l2_controls.cpp b/src/libcamera/v4l2_controls.cpp\nindex 7446c3880330..cd1b39a1a4b3 100644\n--- a/src/libcamera/v4l2_controls.cpp\n+++ b/src/libcamera/v4l2_controls.cpp\n@@ -97,9 +97,11 @@ ControlType v4l2_ctrl_type(const struct v4l2_query_ext_ctrl &ctrl)\n /**\n  * \\brief Construct a V4L2ControlId from a struct v4l2_query_ext_ctrl\n  * \\param[in] ctrl The struct v4l2_query_ext_ctrl as returned by the kernel\n+ *\n+ * FIXME: set isCompound to false unconditionally\n  */\n V4L2ControlId::V4L2ControlId(const struct v4l2_query_ext_ctrl &ctrl)\n-\t: ControlId(ctrl.id, v4l2_ctrl_name(ctrl), v4l2_ctrl_type(ctrl))\n+\t: ControlId(ctrl.id, v4l2_ctrl_name(ctrl), v4l2_ctrl_type(ctrl), false)\n {\n }\n \ndiff --git a/test/controls/compound_controls.cpp b/test/controls/compound_controls.cpp\nindex de00573df141..0ca72f683d1f 100644\n--- a/test/controls/compound_controls.cpp\n+++ b/test/controls/compound_controls.cpp\n@@ -53,40 +53,52 @@ protected:\n \t\tcout << span[0] << endl;\n \n \t\t/*\n-\t\t * Compound Controls\n-\t\t *\n-\t\t * As of now, all Controls are now 'compounds' when set with a\n-\t\t * Span<> of values.\n-\t\t *\n-\t\t * We need to define how to establish that a Control is actually\n-\t\t * a compound or supports a single value.\n+\t\t * Compound Controls: can be set with a span of values\n \t\t */\n-\t\tlist.set(controls::Brightness, {0, 125, 255});\n-\t\tSpan<int32_t> iSpan = list.get(controls::Brightness);\n+\t\tlist.set(controls::CompoundControl, { 0, 125, 253 });\n+\t\tSpan<int32_t> iSpan = list.get(controls::CompoundControl);\n \n \t\tcout << iSpan.size() << endl;\n \t\tfor (uint32_t i : iSpan)\n \t\t\tcout << i << endl;\n \n \t\t/*\n-\t\t * But they can still be accessed and operated with a single\n-\t\t * value.\n+\t\t * But they can still be accessed and operated as a single\n+\t\t * value control.\n \t\t */\n-\t\tlist.set(controls::Brightness, 112);\n-\t\tcout << list.get(controls::Brightness) << endl;\n+\t\tlist.set(controls::CompoundControl, 112);\n+\t\tcout << list.get(controls::CompoundControl) << endl;\n \n \t\t/*\n \t\t * Or set with a Span and accessed by value. The first item\n-\t\t * is returned.\n+\t\t * is returned in this case.\n \t\t */\n-\t\tlist.set(controls::Brightness, {50, 125});\n-\t\tcout << list.get(controls::Brightness) << endl;\n+\t\tlist.set(controls::CompoundControl, { 50, 125 });\n+\t\tcout << list.get(controls::CompoundControl) << endl;\n \n \t\t/* The other way around works as well. */\n-\t\tlist.set(controls::Brightness, 133);\n-\t\tSpan<int32_t> s = list.get(controls::Brightness);\n+\t\tlist.set(controls::CompoundControl, 133);\n+\t\tSpan<int32_t> s = list.get(controls::CompoundControl);\n \t\tcout << s << endl;\n \n+\t\t/*\n+\t\t * Try to set a non-compound control with a span<> and make\n+\t\t * sure it fails.\n+\t\t */\n+\t\tlist.set(controls::Brightness, 55);\n+\t\tuint32_t brightness = list.get(controls::Brightness);\n+\t\tif (brightness != 55) {\n+\t\t\tcerr << \"Failed to set non-compound control\" << endl;\n+\t\t\treturn TestFail;\n+\t\t}\n+\n+\t\tlist.set(controls::Brightness, { 45, 30 });\n+\t\tbrightness = list.get(controls::Brightness);\n+\t\tif (brightness != 55) {\n+\t\t\tcerr << \"non-compound control set with span<>\" << endl;\n+\t\t\treturn TestFail;\n+\t\t}\n+\n \t\treturn TestPass;\n \t}\n };\n",
    "prefixes": [
        "libcamera-devel",
        "RFC",
        "2/2"
    ]
}