Patch Detail
Show a patch.
GET /api/1.1/patches/20857/?format=api
{ "id": 20857, "url": "https://patchwork.libcamera.org/api/1.1/patches/20857/?format=api", "web_url": "https://patchwork.libcamera.org/patch/20857/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/1.1/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": "<20240809005914.20662-8-laurent.pinchart@ideasonboard.com>", "date": "2024-08-09T00:59:11", "name": "[07/10] utils: codegen: gen-controls.py: Convert to jinja2 templates", "commit_ref": null, "pull_url": null, "state": "accepted", "archived": false, "hash": "a35f51c23655389f19f72f47ac17c4c0c96abba1", "submitter": { "id": 2, "url": "https://patchwork.libcamera.org/api/1.1/people/2/?format=api", "name": "Laurent Pinchart", "email": "laurent.pinchart@ideasonboard.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/20857/mbox/", "series": [ { "id": 4506, "url": "https://patchwork.libcamera.org/api/1.1/series/4506/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=4506", "date": "2024-08-09T00:59:04", "name": "libcamera: Improve code generation for controls", "version": 1, "mbox": "https://patchwork.libcamera.org/series/4506/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/20857/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/20857/checks/", "tags": {}, "headers": { "Return-Path": "<libcamera-devel-bounces@lists.libcamera.org>", "X-Original-To": "parsemail@patchwork.libcamera.org", "Delivered-To": "parsemail@patchwork.libcamera.org", "Received": [ "from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 19578C324E\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 9 Aug 2024 00:59:55 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id C177A633CA;\n\tFri, 9 Aug 2024 02:59:54 +0200 (CEST)", "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 57226633C1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 9 Aug 2024 02:59:49 +0200 (CEST)", "from pendragon.ideasonboard.com (81-175-209-231.bb.dnainternet.fi\n\t[81.175.209.231])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 3B239B7E\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 9 Aug 2024 02:58:55 +0200 (CEST)" ], "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"RfscQgkX\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1723165135;\n\tbh=m2BDCSxnwKOufznelIctS8HRcKjM8GxloMDipDWtv5Q=;\n\th=From:To:Subject:Date:In-Reply-To:References:From;\n\tb=RfscQgkX7URDYY3kAEUOnlpgQT/fmrr+N/C/z1v+fGv+HE23t3ZvscwCK7lI9o3Ta\n\tXlOvw6RnpWg6PmA0t9i8v0UyA3lF09HHvAk7MZTBhYL6QKTYw1tJ/DT2ZHAR1d9YBr\n\twUkBtbYGg945u5lYZotuJUI8uQYrmXNoX6MTpOgI=", "From": "Laurent Pinchart <laurent.pinchart@ideasonboard.com>", "To": "libcamera-devel@lists.libcamera.org", "Subject": "[PATCH 07/10] utils: codegen: gen-controls.py: Convert to jinja2\n\ttemplates", "Date": "Fri, 9 Aug 2024 03:59:11 +0300", "Message-ID": "<20240809005914.20662-8-laurent.pinchart@ideasonboard.com>", "X-Mailer": "git-send-email 2.44.2", "In-Reply-To": "<20240809005914.20662-1-laurent.pinchart@ideasonboard.com>", "References": "<20240809005914.20662-1-laurent.pinchart@ideasonboard.com>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "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>", "Errors-To": "libcamera-devel-bounces@lists.libcamera.org", "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>" }, "content": "Jinja2 templates help separating the logic related to the template from\nthe generation of the data. The python code gets much clearer as a\nresult.\n\nAs an added bonus, we can use a single template file for both controls\nand properties.\n\nSigned-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n---\n include/libcamera/control_ids.h.in | 40 +++-\n include/libcamera/meson.build | 2 +-\n include/libcamera/property_ids.h.in | 34 ----\n src/libcamera/control_ids.cpp.in | 101 ++++++++--\n src/libcamera/meson.build | 5 +-\n src/libcamera/property_ids.cpp.in | 48 -----\n utils/codegen/gen-controls.py | 285 ++++++----------------------\n 7 files changed, 176 insertions(+), 339 deletions(-)\n delete mode 100644 include/libcamera/property_ids.h.in\n delete mode 100644 src/libcamera/property_ids.cpp.in", "diff": "diff --git a/include/libcamera/control_ids.h.in b/include/libcamera/control_ids.h.in\nindex 293ba966fbc4..858ef872e9ee 100644\n--- a/include/libcamera/control_ids.h.in\n+++ b/include/libcamera/control_ids.h.in\n@@ -2,7 +2,7 @@\n /*\n * Copyright (C) 2019, Google Inc.\n *\n- * Control ID list\n+ * {{mode|capitalize}} ID list\n *\n * This file is auto-generated. Do not edit.\n */\n@@ -18,18 +18,42 @@\n \n namespace libcamera {\n \n-namespace controls {\n+namespace {{mode}} {\n+\n+extern const ControlIdMap {{mode}};\n+\n+{%- for vendor, ctrls in controls -%}\n+\n+{% if vendor != 'libcamera' %}\n+namespace {{vendor}} {\n+\n+#define LIBCAMERA_HAS_{{vendor|upper}}_VENDOR_{{mode|upper}}\n+{%- endif %}\n \n enum {\n-${ids}\n+{%- for ctrl in ctrls %}\n+\t{{ctrl.name|snake_case|upper}} = {{ctrl.id}},\n+{%- endfor %}\n };\n \n-${controls}\n+{% for ctrl in ctrls -%}\n+{% if ctrl.is_enum -%}\n+enum {{ctrl.name}}Enum {\n+{%- for enum in ctrl.enum_values %}\n+\t{{enum.name}} = {{enum.value}},\n+{%- endfor %}\n+};\n+extern const std::array<const ControlValue, {{ctrl.enum_values_count}}> {{ctrl.name}}Values;\n+extern const std::map<std::string, {{ctrl.type}}> {{ctrl.name}}NameValueMap;\n+{% endif -%}\n+extern const Control<{{ctrl.type}}> {{ctrl.name}};\n+{% endfor -%}\n \n-extern const ControlIdMap controls;\n+{% if vendor != 'libcamera' %}\n+} /* namespace {{vendor}} */\n+{% endif -%}\n \n-${vendor_controls}\n-\n-} /* namespace controls */\n+{% endfor %}\n+} /* namespace {{mode}} */\n \n } /* namespace libcamera */\ndiff --git a/include/libcamera/meson.build b/include/libcamera/meson.build\nindex 87b9a9412fe7..d90a8615e52d 100644\n--- a/include/libcamera/meson.build\n+++ b/include/libcamera/meson.build\n@@ -80,7 +80,7 @@ foreach mode, entry : controls_map\n properties_files_names += files_list\n endif\n \n- template_file = files(outfile + '.in')\n+ template_file = files('control_ids.h.in')\n ranges_file = files('../../src/libcamera/control_ranges.yaml')\n control_headers += custom_target(header + '_h',\n input : input_files,\ndiff --git a/include/libcamera/property_ids.h.in b/include/libcamera/property_ids.h.in\ndeleted file mode 100644\nindex e6edabca771f..000000000000\n--- a/include/libcamera/property_ids.h.in\n+++ /dev/null\n@@ -1,34 +0,0 @@\n-/* SPDX-License-Identifier: LGPL-2.1-or-later */\n-/*\n- * Copyright (C) 2019, Google Inc.\n- *\n- * Property ID list\n- *\n- * This file is auto-generated. Do not edit.\n- */\n-\n-#pragma once\n-\n-#include <map>\n-#include <stdint.h>\n-#include <string>\n-\n-#include <libcamera/controls.h>\n-\n-namespace libcamera {\n-\n-namespace properties {\n-\n-enum {\n-${ids}\n-};\n-\n-${controls}\n-\n-extern const ControlIdMap properties;\n-\n-${vendor_controls}\n-\n-} /* namespace properties */\n-\n-} /* namespace libcamera */\ndiff --git a/src/libcamera/control_ids.cpp.in b/src/libcamera/control_ids.cpp.in\nindex 0b028c92d852..05c8fb385d20 100644\n--- a/src/libcamera/control_ids.cpp.in\n+++ b/src/libcamera/control_ids.cpp.in\n@@ -2,51 +2,120 @@\n /*\n * Copyright (C) 2019, Google Inc.\n *\n- * Control ID list\n+ * {{mode}} ID list\n *\n * This file is auto-generated. Do not edit.\n */\n \n-#include <libcamera/control_ids.h>\n+#include <libcamera/{{filename}}.h>\n #include <libcamera/controls.h>\n \n /**\n- * \\file control_ids.h\n- * \\brief Camera control identifiers\n+ * \\file {{filename}}.h\n+ * \\brief Camera {{mode}} identifiers\n */\n \n namespace libcamera {\n \n /**\n- * \\brief Namespace for libcamera controls\n+ * \\brief Namespace for libcamera {{mode}}\n */\n-namespace controls {\n+namespace {{mode}} {\n \n-${controls_doc}\n+{%- for vendor, ctrls in controls -%}\n \n-${vendor_controls_doc}\n+{%- if vendor != 'libcamera' %}\n+/**\n+ * \\brief Namespace for {{vendor}} {{mode}}\n+ */\n+namespace {{vendor}} {\n+{%- endif -%}\n+\n+{% for ctrl in ctrls %}\n+\n+{% if ctrl.is_enum -%}\n+/**\n+ * \\enum {{ctrl.name}}Enum\n+ * \\brief Supported {{ctrl.name}} values\n+{%- for enum in ctrl.enum_values %}\n+ *\n+ * \\var {{enum.name}}\n+ * \\brief {{enum.description|format_description}}\n+{%- endfor %}\n+ */\n+\n+/**\n+ * \\var {{ctrl.name}}Values\n+ * \\brief List of all {{ctrl.name}} supported values\n+ */\n+\n+/**\n+ * \\var {{ctrl.name}}NameValueMap\n+ * \\brief Map of all {{ctrl.name}} supported value names (in std::string format) to value\n+ */\n+\n+{% endif -%}\n+/**\n+ * \\var {{ctrl.name}}\n+ * \\brief {{ctrl.description|format_description}}\n+ */\n+{%- endfor %}\n+{% if vendor != 'libcamera' %}\n+} /* namespace {{vendor}} */\n+{% endif -%}\n+\n+{%- endfor %}\n \n #ifndef __DOXYGEN__\n /*\n- * Keep the controls definitions hidden from doxygen as it incorrectly parses\n+ * Keep the {{mode}} definitions hidden from doxygen as it incorrectly parses\n * them as functions.\n */\n-${controls_def}\n+{% for vendor, ctrls in controls -%}\n \n-${vendor_controls_def}\n+{% if vendor != 'libcamera' %}\n+namespace {{vendor}} {\n+{% endif %}\n \n-#endif\n+{%- for ctrl in ctrls %}\n+{% if ctrl.is_enum -%}\n+extern const std::array<const ControlValue, {{ctrl.enum_values_count}}> {{ctrl.name}}Values = {\n+{%- for enum in ctrl.enum_values %}\n+\tstatic_cast<{{ctrl.type}}>({{enum.name}}),\n+{%- endfor %}\n+};\n+extern const std::map<std::string, {{ctrl.type}}> {{ctrl.name}}NameValueMap = {\n+{%- for enum in ctrl.enum_values %}\n+\t{ \"{{enum.name}}\", {{enum.name}} },\n+{%- endfor %}\n+};\n+{% endif -%}\n+extern const Control<{{ctrl.type}}> {{ctrl.name}}({{ctrl.name|snake_case|upper}}, \"{{ctrl.name}}\");\n+{%- endfor %}\n+\n+{% if vendor != 'libcamera' %}\n+} /* namespace {{vendor}} */\n+{% endif -%}\n+\n+{%- endfor %}\n+#endif /* __DOXYGEN__ */\n \n /**\n- * \\brief List of all supported libcamera controls\n+ * \\brief List of all supported libcamera {{mode}}\n+{%- if mode == 'controls' %}\n *\n * Unless otherwise stated, all controls are bi-directional, i.e. they can be\n * set through Request::controls() and returned out through Request::metadata().\n+{%- endif %}\n */\n-extern const ControlIdMap controls {\n-${controls_map}\n+extern const ControlIdMap {{mode}} {\n+{%- for vendor, ctrls in controls -%}\n+{%- for ctrl in ctrls %}\n+\t{ {{ctrl.namespace}}{{ctrl.name|snake_case|upper}}, &{{ctrl.namespace}}{{ctrl.name}} },\n+{%- endfor -%}\n+{%- endfor %}\n };\n \n-} /* namespace controls */\n+} /* namespace {{mode}} */\n \n } /* namespace libcamera */\ndiff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\nindex e5e959d9c7bd..3fd3a87e9f95 100644\n--- a/src/libcamera/meson.build\n+++ b/src/libcamera/meson.build\n@@ -143,9 +143,10 @@ foreach mode, inout_files : controls_mode_files\n input_files = inout_files[0]\n output_file = inout_files[1]\n \n- template_file = files(output_file + '.in')\n+ template_file = files('control_ids.cpp.in')\n ranges_file = files('control_ranges.yaml')\n- control_sources += custom_target(mode + '_cpp',\n+\n+ control_sources += custom_target(mode + '_ids_cpp',\n input : input_files,\n output : output_file,\n command : [gen_controls, '-o', '@OUTPUT@',\ndiff --git a/src/libcamera/property_ids.cpp.in b/src/libcamera/property_ids.cpp.in\ndeleted file mode 100644\nindex 2d3f192eb6ef..000000000000\n--- a/src/libcamera/property_ids.cpp.in\n+++ /dev/null\n@@ -1,48 +0,0 @@\n-/* SPDX-License-Identifier: LGPL-2.1-or-later */\n-/*\n- * Copyright (C) 2019, Google Inc.\n- *\n- * Property ID list\n- *\n- * This file is auto-generated. Do not edit.\n- */\n-\n-#include <libcamera/property_ids.h>\n-\n-/**\n- * \\file property_ids.h\n- * \\brief Camera property identifiers\n- */\n-\n-namespace libcamera {\n-\n-/**\n- * \\brief Namespace for libcamera properties\n- */\n-namespace properties {\n-\n-${controls_doc}\n-\n-${vendor_controls_doc}\n-\n-#ifndef __DOXYGEN__\n-/*\n- * Keep the properties definitions hidden from doxygen as it incorrectly parses\n- * them as functions.\n- */\n-${controls_def}\n-\n-${vendor_controls_def}\n-\n-#endif\n-\n-/**\n- * \\brief List of all supported libcamera properties\n- */\n-extern const ControlIdMap properties {\n-${controls_map}\n-};\n-\n-} /* namespace properties */\n-\n-} /* namespace libcamera */\ndiff --git a/utils/codegen/gen-controls.py b/utils/codegen/gen-controls.py\nindex 56315f5089b4..685ef7a00d5f 100755\n--- a/utils/codegen/gen-controls.py\n+++ b/utils/codegen/gen-controls.py\n@@ -7,12 +7,10 @@\n # Generate control definitions from YAML\n \n import argparse\n-from functools import reduce\n-import operator\n-import string\n+import jinja2\n+import os\n import sys\n import yaml\n-import os\n \n \n class ControlEnum(object):\n@@ -81,6 +79,13 @@ class Control(object):\n for enum in self.__enum_values:\n yield enum\n \n+ @property\n+ def enum_values_count(self):\n+ \"\"\"The number of enum values, if the control is an enumeration\"\"\"\n+ if self.__enum_values is None:\n+ return 0\n+ return len(self.__enum_values)\n+\n @property\n def is_enum(self):\n \"\"\"Is the control an enumeration\"\"\"\n@@ -119,221 +124,23 @@ def snake_case(s):\n \n def format_description(description):\n description = description.strip('\\n').split('\\n')\n- description[0] = '\\\\brief ' + description[0]\n- return '\\n'.join([(line and ' * ' or ' *') + line for line in description])\n+ for i in range(1, len(description)):\n+ line = description[i]\n+ description[i] = (line and ' * ' or ' *') + line\n+ return '\\n'.join(description)\n \n \n-def generate_cpp(controls):\n- enum_doc_start_template = string.Template('''/**\n- * \\\\enum ${name}Enum\n- * \\\\brief Supported ${name} values''')\n- enum_doc_value_template = string.Template(''' * \\\\var ${value}\n-${description}''')\n- doc_template = string.Template('''/**\n- * \\\\var ${name}\n-${description}\n- */''')\n- def_template = string.Template('extern const Control<${type}> ${name}(${id_name}, \"${name}\");')\n- enum_values_doc = string.Template('''/**\n- * \\\\var ${name}Values\n- * \\\\brief List of all $name supported values\n- */''')\n- enum_values_start = string.Template('''extern const std::array<const ControlValue, ${size}> ${name}Values = {''')\n- enum_values_values = string.Template('''\\tstatic_cast<int32_t>(${name}),''')\n- name_value_map_doc = string.Template('''/**\n- * \\\\var ${name}NameValueMap\n- * \\\\brief Map of all $name supported value names (in std::string format) to value\n- */''')\n- name_value_map_start = string.Template('''extern const std::map<std::string, ${type}> ${name}NameValueMap = {''')\n- name_value_values = string.Template('''\\t{ \"${name}\", ${name} },''')\n+def extend_control(ctrl, id, ranges):\n+ ctrl.id = ranges[ctrl.vendor] + id + 1\n \n- ctrls_doc = {}\n- ctrls_def = {}\n- ctrls_map = []\n+ if ctrl.vendor != 'libcamera':\n+ ctrl.namespace = f'{ctrl.vendor}::'\n+ else:\n+ ctrl.namespace = ''\n \n- for ctrl in controls:\n- id_name = snake_case(ctrl.name).upper()\n+ ctrl.documentation = format_description(ctrl.description)\n \n- vendor = ctrl.vendor\n- if vendor not in ctrls_doc:\n- ctrls_doc[vendor] = []\n- ctrls_def[vendor] = []\n-\n- info = {\n- 'name': ctrl.name,\n- 'type': ctrl.type,\n- 'description': format_description(ctrl.description),\n- 'id_name': id_name,\n- }\n-\n- target_doc = ctrls_doc[vendor]\n- target_def = ctrls_def[vendor]\n-\n- if ctrl.is_enum:\n- enum_doc = []\n- enum_doc.append(enum_doc_start_template.substitute(info))\n-\n- num_entries = 0\n- for enum in ctrl.enum_values:\n- value_info = {\n- 'name': ctrl.name,\n- 'value': enum.name,\n- 'description': format_description(enum.description),\n- }\n- enum_doc.append(enum_doc_value_template.substitute(value_info))\n- num_entries += 1\n-\n- enum_doc = '\\n *\\n'.join(enum_doc)\n- enum_doc += '\\n */'\n- target_doc.append(enum_doc)\n-\n- values_info = {\n- 'name': info['name'],\n- 'type': ctrl.type,\n- 'size': num_entries,\n- }\n- target_doc.append(enum_values_doc.substitute(values_info))\n- target_def.append(enum_values_start.substitute(values_info))\n- for enum in ctrl.enum_values:\n- value_info = {\n- 'name': enum.name\n- }\n- target_def.append(enum_values_values.substitute(value_info))\n- target_def.append(\"};\")\n-\n- target_doc.append(name_value_map_doc.substitute(values_info))\n- target_def.append(name_value_map_start.substitute(values_info))\n- for enum in ctrl.enum_values:\n- value_info = {\n- 'name': enum.name\n- }\n- target_def.append(name_value_values.substitute(value_info))\n- target_def.append(\"};\")\n-\n- target_doc.append(doc_template.substitute(info))\n- target_def.append(def_template.substitute(info))\n-\n- vendor_ns = vendor + '::' if vendor != \"libcamera\" else ''\n- ctrls_map.append('\\t{ ' + vendor_ns + id_name + ', &' + vendor_ns + ctrl.name + ' },')\n-\n- vendor_ctrl_doc_sub = []\n- vendor_ctrl_template = string.Template('''\n-/**\n- * \\\\brief Namespace for ${vendor} controls\n- */\n-namespace ${vendor} {\n-\n-${vendor_controls_str}\n-\n-} /* namespace ${vendor} */''')\n-\n- for vendor in [v for v in ctrls_doc.keys() if v not in ['libcamera']]:\n- vendor_ctrl_doc_sub.append(vendor_ctrl_template.substitute({'vendor': vendor, 'vendor_controls_str': '\\n\\n'.join(ctrls_doc[vendor])}))\n-\n- vendor_ctrl_def_sub = []\n- for vendor in [v for v in ctrls_def.keys() if v not in ['libcamera']]:\n- vendor_ctrl_def_sub.append(vendor_ctrl_template.substitute({'vendor': vendor, 'vendor_controls_str': '\\n'.join(ctrls_def[vendor])}))\n-\n- return {\n- 'controls_doc': '\\n\\n'.join(ctrls_doc['libcamera']),\n- 'controls_def': '\\n'.join(ctrls_def['libcamera']),\n- 'controls_map': '\\n'.join(ctrls_map),\n- 'vendor_controls_doc': '\\n'.join(vendor_ctrl_doc_sub),\n- 'vendor_controls_def': '\\n'.join(vendor_ctrl_def_sub),\n- }\n-\n-\n-def generate_h(controls, mode, ranges):\n- enum_template_start = string.Template('''enum ${name}Enum {''')\n- enum_value_template = string.Template('''\\t${name} = ${value},''')\n- enum_values_template = string.Template('''extern const std::array<const ControlValue, ${size}> ${name}Values;''')\n- name_value_map_template = string.Template('''extern const std::map<std::string, ${type}> ${name}NameValueMap;''')\n- template = string.Template('''extern const Control<${type}> ${name};''')\n-\n- ctrls = {}\n- ids = {}\n- id_value = {}\n-\n- for ctrl in controls:\n- id_name = snake_case(ctrl.name).upper()\n-\n- vendor = ctrl.vendor\n- if vendor not in ctrls:\n- if vendor not in ranges.keys():\n- raise RuntimeError(f'Control id range is not defined for vendor {vendor}')\n- id_value[vendor] = ranges[vendor] + 1\n- ids[vendor] = []\n- ctrls[vendor] = []\n-\n- target_ids = ids[vendor]\n- target_ids.append('\\t' + id_name + ' = ' + str(id_value[vendor]) + ',')\n-\n- info = {\n- 'name': ctrl.name,\n- 'type': ctrl.type,\n- }\n-\n- target_ctrls = ctrls[vendor]\n-\n- if ctrl.is_enum:\n- target_ctrls.append(enum_template_start.substitute(info))\n-\n- num_entries = 0\n- for enum in ctrl.enum_values:\n- value_info = {\n- 'name': enum.name,\n- 'value': enum.value,\n- }\n- target_ctrls.append(enum_value_template.substitute(value_info))\n- num_entries += 1\n- target_ctrls.append(\"};\")\n-\n- values_info = {\n- 'name': info['name'],\n- 'type': ctrl.type,\n- 'size': num_entries,\n- }\n- target_ctrls.append(enum_values_template.substitute(values_info))\n- target_ctrls.append(name_value_map_template.substitute(values_info))\n-\n- target_ctrls.append(template.substitute(info))\n- id_value[vendor] += 1\n-\n- vendor_template = string.Template('''\n-namespace ${vendor} {\n-\n-#define LIBCAMERA_HAS_${vendor_def}_VENDOR_${mode}\n-\n-enum {\n-${vendor_enums}\n-};\n-\n-${vendor_controls}\n-\n-} /* namespace ${vendor} */\n-''')\n-\n- vendor_sub = []\n- for vendor in [v for v in ctrls.keys() if v != 'libcamera']:\n- vendor_sub.append(vendor_template.substitute({'mode': mode.upper(),\n- 'vendor': vendor,\n- 'vendor_def': vendor.upper(),\n- 'vendor_enums': '\\n'.join(ids[vendor]),\n- 'vendor_controls': '\\n'.join(ctrls[vendor])}))\n-\n- return {\n- 'ids': '\\n'.join(ids['libcamera']),\n- 'controls': '\\n'.join(ctrls['libcamera']),\n- 'vendor_controls': '\\n'.join(vendor_sub)\n- }\n-\n-\n-def fill_template(template, data):\n-\n- template = open(template, 'rb').read()\n- template = template.decode('utf-8')\n- template = string.Template(template)\n- return template.substitute(data)\n+ return ctrl\n \n \n def main(argv):\n@@ -358,29 +165,47 @@ def main(argv):\n data = open(args.ranges, 'rb').read()\n ranges = yaml.safe_load(data)['ranges']\n \n- controls = []\n+ controls = {}\n for input in args.input:\n- with open(input, 'rb') as f:\n- data = f.read()\n- vendor = yaml.safe_load(data)['vendor']\n- ctrls = yaml.safe_load(data)['controls']\n- controls = controls + [Control(*ctrl.popitem(), vendor) for ctrl in ctrls]\n+ data = yaml.safe_load(open(input, 'rb').read())\n \n- if args.template.endswith('.cpp.in'):\n- data = generate_cpp(controls)\n- elif args.template.endswith('.h.in'):\n- data = generate_h(controls, args.mode, ranges)\n- else:\n- raise RuntimeError('Unknown template type')\n+ vendor = data['vendor']\n+ if vendor not in ranges.keys():\n+ raise RuntimeError(f'Control id range is not defined for vendor {vendor}')\n \n- data = fill_template(args.template, data)\n+ ctrls = controls.setdefault(vendor, [])\n+\n+ for i, ctrl in enumerate(data['controls']):\n+ ctrl = Control(*ctrl.popitem(), vendor)\n+ ctrls.append(extend_control(ctrl, i, ranges))\n+\n+ # Sort the vendors by range numerical value\n+ controls = [[vendor, ctrls] for vendor, ctrls in controls.items()]\n+ controls.sort(key=lambda item: ranges[item[0]])\n+\n+ filename = {\n+ 'controls': 'control_ids',\n+ 'properties': 'property_ids',\n+ }[args.mode]\n+\n+ data = {\n+ 'filename': filename,\n+ 'mode': args.mode,\n+ 'controls': controls,\n+ }\n+\n+ env = jinja2.Environment()\n+ env.filters['format_description'] = format_description\n+ env.filters['snake_case'] = snake_case\n+ template = env.from_string(open(args.template, 'r', encoding='utf-8').read())\n+ string = template.render(data)\n \n if args.output:\n- output = open(args.output, 'wb')\n- output.write(data.encode('utf-8'))\n+ output = open(args.output, 'w', encoding='utf-8')\n+ output.write(string)\n output.close()\n else:\n- sys.stdout.write(data)\n+ sys.stdout.write(string)\n \n return 0\n \n", "prefixes": [ "07/10" ] }