From patchwork Thu Nov 30 14:25:29 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 19249 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id D6B46C31E9 for ; Thu, 30 Nov 2023 14:25:44 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 94F41629CD; Thu, 30 Nov 2023 15:25:44 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1701354344; bh=hWwJvQIla4E4o7cA8Xck5prE6HSe3kgfzabjf5wbjts=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=LWErJrJ3akWvqVgj8BWJEvXF1qbQvC6cUVQHhSonkPydVsOHZfTffQcXWuSr9oQk0 a9onQKoKoVlASzsrfaxms4BDdrI50zsGjO4ie04+jJdo/czDDs7J+hg00ku/ycSiTf dO+6Ub86MpCEoxSFRVQ5DmXqi/h/p9+ousBfxDx83M6Ljne+ESlAcjbu8HPJ3niaJq WHYcfc4kGBwagghiKtdVUVWzcIIRJbJ++DAok7rUZznrHDSAaD7Y3f6YKrTVOGHTqf Kpc0X/6cmhkcF6GrEGPLRqyn5FMTZ1Q0hwatmNrJnqDqRCuHxZVLpDbST0Xii0+4jN BgsAw1FN15ysw== Received: from mail-ej1-x634.google.com (mail-ej1-x634.google.com [IPv6:2a00:1450:4864:20::634]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4B3C5629CF for ; Thu, 30 Nov 2023 15:25:42 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="qmh+92Z8"; dkim-atps=neutral Received: by mail-ej1-x634.google.com with SMTP id a640c23a62f3a-a185fb3aa18so161512066b.1 for ; Thu, 30 Nov 2023 06:25:42 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1701354341; x=1701959141; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=1as9CqKuBwDA0ze/S2hVDpPSbAmZ+RvLPwY8MNxamMk=; b=qmh+92Z8oLLmaOh3TsvlpBeO/Da103D+gLZNW7hyObwP2C5fAhiEKSBok0I3g6/2sW yerZNssM9LhsQrqEPL3yZvjqIHFR7rZ6R5vgmoot34YK2pov0R3/WWWdM27Z/GrwsfBK Ku+gOqX4sAWJhYcVV4x6UrA7XqZZkUVmF/z9w1qxBDzx6m85QJ0bSW4G/A/V7iXJjeb/ TqjtD5CJ10W5+ZI1Mb1T002B1DFDSWhUKOztjWBlLkSbLX5AxYE+f/dafmEa9Ayg94JE l1FL4fePnxSEZCIS3KNJBSxqHzTlk5J5iCtuF912PvtVhwNbabd8LQ3BjFq40iS44BUw 27Ag== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1701354341; x=1701959141; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=1as9CqKuBwDA0ze/S2hVDpPSbAmZ+RvLPwY8MNxamMk=; b=T0TFs5MHndPbbsI/nu2cPGVy7dIN6UGbJYzdeTNICI1C7aWs7AHyAg6Y2TxCqTQUBa B0//uGb6KdzdPUQoOU2yLJvkDVt/mGQOxwaQbRdgbKLsV+EFEmbzCJBGFf4HroW/cYJ0 msy4ArMcNlIoHJdPT/qqXdWtg3bef5xRPiQXhw2QTLWykP5OEwQl1zjgv+HSbL4BVFIF 5ciwDVGauLokQy9+6mFayieFHwCdcu0b/VhVsVSA2NZ8EzEiZwWgEgJSGX1qp+sNWqrw dOve8eX37jsFF3unsP9iIthLzyUSF4Lg16MBscROdDCSRc9TP9DqNsfq549xuFBPSISU hU9w== X-Gm-Message-State: AOJu0Yzr1EhZOkNuQTlJK24vsMqXbp2PfvXuBLZwA2boGE4xYkMpVJEP hnTLJtOZQBd82lNtqz6OhR0CLwzc7zTc9qbK06aXtQ== X-Google-Smtp-Source: AGHT+IHgSLkF5v9tsEhpAXkx4AsRm+2wEVA0jEUtO20/u+m2RqeEyuUt2rIjK7YwIyKL06X4ddBKpA== X-Received: by 2002:a17:906:7390:b0:9e5:26b2:b38d with SMTP id f16-20020a170906739000b009e526b2b38dmr20553305ejl.10.1701354341383; Thu, 30 Nov 2023 06:25:41 -0800 (PST) Received: from localhost.localdomain ([88.97.53.79]) by smtp.gmail.com with ESMTPSA id a5-20020a17090640c500b009e50ea0a05asm725577ejk.99.2023.11.30.06.25.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 30 Nov 2023 06:25:41 -0800 (PST) To: libcamera-devel@lists.libcamera.org Date: Thu, 30 Nov 2023 14:25:29 +0000 Message-Id: <20231130142534.2075-2-naush@raspberrypi.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231130142534.2075-1-naush@raspberrypi.com> References: <20231130142534.2075-1-naush@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 1/6] controls: Add vendor control/property support to generation scripts X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Naushir Patuck via libcamera-devel From: Naushir Patuck Reply-To: Naushir Patuck Cc: Jacopo Mondi Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add support for vendor-specific controls and properties to libcamera. The controls/properties are defined by a "vendor" tag in the YAML control description file, for example: vendor: rpi controls: - MyExampleControl: type: string description: | Test for libcamera vendor-specific controls. This will now generate a control id in the libcamera::controls::rpi namespace, ensuring no id conflict between different vendors, core or draft libcamera controls. Similarly, a ControlIdMap control is generated in the libcamera::controls::rpi namespace. A #define LIBCAMERA_HAS_RPI_VENDOR_CONTROLS is also generated to allow applications to conditionally compile code if the specific vendor controls are present. For the python bindings, the control is available with libcamera.controls.rpi.MyExampleControl. The above controls example applies similarly to properties. Existing libcamera controls defined in control_ids.yaml are given the "libcamera" vendor tag. A new --mode flag is added to gen-controls.py to specify the mode of operation, either 'controls' or 'properties' to allow the code generator to correctly set the #define string. As a drive-by, sort and redefine the output command line argument in gen-controls.py and gen-py-controls.py to ('--output', '-o') for consistency. Signed-off-by: Naushir Patuck Reviewed-by: Jacopo Mondi Reviewed-by: Kieran Bingham --- include/libcamera/control_ids.h.in | 2 + include/libcamera/meson.build | 15 ++- include/libcamera/property_ids.h.in | 2 + src/libcamera/control_ids.cpp.in | 5 + src/libcamera/control_ids.yaml | 1 + src/libcamera/meson.build | 5 +- src/libcamera/property_ids.cpp.in | 5 + src/libcamera/property_ids.yaml | 1 + src/py/libcamera/gen-py-controls.py | 81 +++++++----- src/py/libcamera/py_controls_generated.cpp.in | 3 + .../libcamera/py_properties_generated.cpp.in | 3 + utils/gen-controls.py | 120 +++++++++++++----- 12 files changed, 173 insertions(+), 70 deletions(-) diff --git a/include/libcamera/control_ids.h.in b/include/libcamera/control_ids.h.in index 0718a8886f6c..c97b09a82450 100644 --- a/include/libcamera/control_ids.h.in +++ b/include/libcamera/control_ids.h.in @@ -32,6 +32,8 @@ ${draft_controls} } /* namespace draft */ +${vendor_controls} + } /* namespace controls */ } /* namespace libcamera */ diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build index a24c50d66a82..2c8c0258c95e 100644 --- a/include/libcamera/meson.build +++ b/include/libcamera/meson.build @@ -32,20 +32,21 @@ install_headers(libcamera_public_headers, libcamera_headers_install_dir = get_option('includedir') / libcamera_include_dir -# control_ids.h and property_ids.h -control_source_files = [ - 'control_ids', - 'property_ids', -] +# control_ids.h and property_ids.h and associated modes +control_source_files = { + 'control_ids': 'controls', + 'property_ids': 'properties', +} control_headers = [] -foreach header : control_source_files +foreach header, mode : control_source_files input_files = files('../../src/libcamera/' + header +'.yaml', header + '.h.in') control_headers += custom_target(header + '_h', input : input_files, output : header + '.h', - command : [gen_controls, '-o', '@OUTPUT@', '@INPUT@'], + command : [gen_controls, '-o', '@OUTPUT@', '@INPUT@', + '--mode', mode], install : true, install_dir : libcamera_headers_install_dir) endforeach diff --git a/include/libcamera/property_ids.h.in b/include/libcamera/property_ids.h.in index ff0194083af0..47c5d6bf2e28 100644 --- a/include/libcamera/property_ids.h.in +++ b/include/libcamera/property_ids.h.in @@ -31,6 +31,8 @@ ${draft_controls} extern const ControlIdMap properties; +${vendor_controls} + } /* namespace properties */ } /* namespace libcamera */ diff --git a/src/libcamera/control_ids.cpp.in b/src/libcamera/control_ids.cpp.in index 5fb1c2c30558..bdb312759eb1 100644 --- a/src/libcamera/control_ids.cpp.in +++ b/src/libcamera/control_ids.cpp.in @@ -33,6 +33,8 @@ ${draft_controls_doc} } /* namespace draft */ +${vendor_controls_doc} + #ifndef __DOXYGEN__ /* * Keep the controls definitions hidden from doxygen as it incorrectly parses @@ -45,6 +47,9 @@ namespace draft { ${draft_controls_def} } /* namespace draft */ + +${vendor_controls_def} + #endif /** diff --git a/src/libcamera/control_ids.yaml b/src/libcamera/control_ids.yaml index 5827d7ecef49..ff74ce1deedb 100644 --- a/src/libcamera/control_ids.yaml +++ b/src/libcamera/control_ids.yaml @@ -6,6 +6,7 @@ --- # Unless otherwise stated, all controls are bi-directional, i.e. they can be # set through Request::controls() and returned out through Request::metadata(). +vendor: libcamera controls: - AeEnable: type: bool diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index d0e26f6b4141..e49bf850b355 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -127,12 +127,13 @@ endif control_sources = [] -foreach source : control_source_files +foreach source, mode : control_source_files input_files = files(source +'.yaml', source + '.cpp.in') control_sources += custom_target(source + '_cpp', input : input_files, output : source + '.cpp', - command : [gen_controls, '-o', '@OUTPUT@', '@INPUT@']) + command : [gen_controls, '-o', '@OUTPUT@', '@INPUT@', + '--mode', mode]) endforeach libcamera_sources += control_sources diff --git a/src/libcamera/property_ids.cpp.in b/src/libcamera/property_ids.cpp.in index f917e3349766..eed1124f3eb7 100644 --- a/src/libcamera/property_ids.cpp.in +++ b/src/libcamera/property_ids.cpp.in @@ -32,6 +32,8 @@ ${draft_controls_doc} } /* namespace draft */ +${vendor_controls_doc} + #ifndef __DOXYGEN__ /* * Keep the properties definitions hidden from doxygen as it incorrectly parses @@ -44,6 +46,9 @@ namespace draft { ${draft_controls_def} } /* namespace draft */ + +${vendor_controls_def} + #endif /** diff --git a/src/libcamera/property_ids.yaml b/src/libcamera/property_ids.yaml index f35563842a5a..45f3609b4236 100644 --- a/src/libcamera/property_ids.yaml +++ b/src/libcamera/property_ids.yaml @@ -4,6 +4,7 @@ # %YAML 1.1 --- +vendor: libcamera controls: - Location: type: int32_t diff --git a/src/py/libcamera/gen-py-controls.py b/src/py/libcamera/gen-py-controls.py index 9948c41e42b1..dfd7c179a883 100755 --- a/src/py/libcamera/gen-py-controls.py +++ b/src/py/libcamera/gen-py-controls.py @@ -24,45 +24,59 @@ def find_common_prefix(strings): def generate_py(controls, mode): out = '' - for ctrl in controls: - name, ctrl = ctrl.popitem() - - if ctrl.get('draft'): - ns = 'libcamera::{}::draft::'.format(mode) - container = 'draft' - else: - ns = 'libcamera::{}::'.format(mode) - container = 'controls' + vendors_class_def = [] + vendor_defs = [] + vendors = [] + for vendor, ctrl_list in controls.items(): + for ctrls in ctrl_list: + name, ctrl = ctrls.popitem() + + if vendor not in vendors and vendor != 'libcamera': + vendors_class_def.append('class Py{}Controls\n{{\n}};\n'.format(vendor)) + vendor_defs.append('\tauto {} = py::class_(controls, \"{}\");'.format(vendor, vendor, vendor)) + vendors.append(vendor) + + if ctrl.get('draft'): + ns = 'libcamera::{}::draft::'.format(mode) + container = 'draft' + elif vendor != 'libcamera': + ns = 'libcamera::{}::{}::'.format(mode, vendor) + container = vendor + else: + ns = 'libcamera::{}::'.format(mode) + container = 'controls' - out += f'\t{container}.def_readonly_static("{name}", static_cast(&{ns}{name}));\n\n' + out += f'\t{container}.def_readonly_static("{name}", static_cast(&{ns}{name}));\n\n' - enum = ctrl.get('enum') - if not enum: - continue + enum = ctrl.get('enum') + if not enum: + continue - cpp_enum = name + 'Enum' + cpp_enum = name + 'Enum' - out += '\tpy::enum_<{}{}>({}, \"{}\")\n'.format(ns, cpp_enum, container, cpp_enum) + out += '\tpy::enum_<{}{}>({}, \"{}\")\n'.format(ns, cpp_enum, container, cpp_enum) - if mode == 'controls': - # Adjustments for controls - if name == 'LensShadingMapMode': - prefix = 'LensShadingMapMode' + if mode == 'controls': + # Adjustments for controls + if name == 'LensShadingMapMode': + prefix = 'LensShadingMapMode' + else: + prefix = find_common_prefix([e['name'] for e in enum]) else: + # Adjustments for properties prefix = find_common_prefix([e['name'] for e in enum]) - else: - # Adjustments for properties - prefix = find_common_prefix([e['name'] for e in enum]) - for entry in enum: - cpp_enum = entry['name'] - py_enum = entry['name'][len(prefix):] + for entry in enum: + cpp_enum = entry['name'] + py_enum = entry['name'][len(prefix):] - out += '\t\t.value(\"{}\", {}{})\n'.format(py_enum, ns, cpp_enum) + out += '\t\t.value(\"{}\", {}{})\n'.format(py_enum, ns, cpp_enum) - out += '\t;\n\n' + out += '\t;\n\n' - return {'controls': out} + return {'controls': out, + 'vendors_class_def': '\n'.join(vendors_class_def), + 'vendors_defs': '\n'.join(vendor_defs)} def fill_template(template, data): @@ -75,14 +89,14 @@ def fill_template(template, data): def main(argv): # Parse command line arguments parser = argparse.ArgumentParser() - parser.add_argument('-o', dest='output', metavar='file', type=str, + parser.add_argument('--mode', '-m', type=str, required=True, + help='Mode is either "controls" or "properties"') + parser.add_argument('--output', '-o', metavar='file', type=str, help='Output file name. Defaults to standard output if not specified.') parser.add_argument('input', type=str, help='Input file name.') parser.add_argument('template', type=str, help='Template file name.') - parser.add_argument('--mode', type=str, required=True, - help='Mode is either "controls" or "properties"') args = parser.parse_args(argv[1:]) if args.mode not in ['controls', 'properties']: @@ -90,7 +104,10 @@ def main(argv): return -1 data = open(args.input, 'rb').read() - controls = yaml.safe_load(data)['controls'] + + controls = {} + vendor = yaml.safe_load(data)['vendor'] + controls[vendor] = yaml.safe_load(data)['controls'] data = generate_py(controls, args.mode) diff --git a/src/py/libcamera/py_controls_generated.cpp.in b/src/py/libcamera/py_controls_generated.cpp.in index 18fa57d948ea..ec4b55ef2011 100644 --- a/src/py/libcamera/py_controls_generated.cpp.in +++ b/src/py/libcamera/py_controls_generated.cpp.in @@ -21,10 +21,13 @@ class PyDraftControls { }; +${vendors_class_def} + void init_py_controls_generated(py::module& m) { auto controls = py::class_(m, "controls"); auto draft = py::class_(controls, "draft"); +${vendors_defs} ${controls} } diff --git a/src/py/libcamera/py_properties_generated.cpp.in b/src/py/libcamera/py_properties_generated.cpp.in index e49b6e91bb83..f7b5ec8c635d 100644 --- a/src/py/libcamera/py_properties_generated.cpp.in +++ b/src/py/libcamera/py_properties_generated.cpp.in @@ -21,10 +21,13 @@ class PyDraftProperties { }; +${vendors_class_def} + void init_py_properties_generated(py::module& m) { auto controls = py::class_(m, "properties"); auto draft = py::class_(controls, "draft"); +${vendors_defs} ${controls} } diff --git a/utils/gen-controls.py b/utils/gen-controls.py index 1075ae302ce1..c1172cb26e7b 100755 --- a/utils/gen-controls.py +++ b/utils/gen-controls.py @@ -35,11 +35,12 @@ class ControlEnum(object): class Control(object): - def __init__(self, name, data): + def __init__(self, name, data, vendor): self.__name = name self.__data = data self.__enum_values = None self.__size = None + self.__vendor = vendor enum_values = data.get('enum') if enum_values is not None: @@ -89,6 +90,11 @@ class Control(object): """Is the control a draft control""" return self.__data.get('draft') is not None + @property + def vendor(self): + """The vendor string, or None""" + return self.__vendor + @property def name(self): """The control name (CamelCase)""" @@ -145,15 +151,18 @@ ${description} enum_values_start = string.Template('''extern const std::array ${name}Values = {''') enum_values_values = string.Template('''\tstatic_cast(${name}),''') - ctrls_doc = [] - ctrls_def = [] - draft_ctrls_doc = [] - draft_ctrls_def = [] + ctrls_doc = {} + ctrls_def = {} ctrls_map = [] for ctrl in controls: id_name = snake_case(ctrl.name).upper() + vendor = 'draft' if ctrl.is_draft else ctrl.vendor + if vendor not in ctrls_doc: + ctrls_doc[vendor] = [] + ctrls_def[vendor] = [] + info = { 'name': ctrl.name, 'type': ctrl.type, @@ -161,11 +170,8 @@ ${description} 'id_name': id_name, } - target_doc = ctrls_doc - target_def = ctrls_def - if ctrl.is_draft: - target_doc = draft_ctrls_doc - target_def = draft_ctrls_def + target_doc = ctrls_doc[vendor] + target_def = ctrls_def[vendor] if ctrl.is_enum: enum_doc = [] @@ -203,39 +209,68 @@ ${description} ctrls_map.append('\t{ ' + id_name + ', &' + ctrl.q_name + ' },') + vendor_ctrl_doc_sub = [] + vendor_ctrl_template = string.Template(''' +/** + * \\brief Namespace for ${vendor} controls + */ +namespace ${vendor} { + +${vendor_controls_str} + +} /* namespace ${vendor} */''') + + for vendor in [v for v in ctrls_doc.keys() if v not in ['libcamera', 'draft']]: + vendor_ctrl_doc_sub.append(vendor_ctrl_template.substitute({'vendor': vendor, 'vendor_controls_str': '\n\n'.join(ctrls_doc[vendor])})) + + vendor_ctrl_def_sub = [] + for vendor in [v for v in ctrls_def.keys() if v not in ['libcamera', 'draft']]: + vendor_ctrl_def_sub.append(vendor_ctrl_template.substitute({'vendor': vendor, 'vendor_controls_str': '\n'.join(ctrls_def[vendor])})) + return { - 'controls_doc': '\n\n'.join(ctrls_doc), - 'controls_def': '\n'.join(ctrls_def), - 'draft_controls_doc': '\n\n'.join(draft_ctrls_doc), - 'draft_controls_def': '\n\n'.join(draft_ctrls_def), + 'controls_doc': '\n\n'.join(ctrls_doc['libcamera']), + 'controls_def': '\n'.join(ctrls_def['libcamera']), + 'draft_controls_doc': '\n\n'.join(ctrls_doc['draft']), + 'draft_controls_def': '\n\n'.join(ctrls_def['draft']), 'controls_map': '\n'.join(ctrls_map), + 'vendor_controls_doc': '\n'.join(vendor_ctrl_doc_sub), + 'vendor_controls_def': '\n'.join(vendor_ctrl_def_sub), } -def generate_h(controls): +def generate_h(controls, mode): enum_template_start = string.Template('''enum ${name}Enum {''') enum_value_template = string.Template('''\t${name} = ${value},''') enum_values_template = string.Template('''extern const std::array ${name}Values;''') template = string.Template('''extern const Control<${type}> ${name};''') - ctrls = [] - draft_ctrls = [] - ids = [] - id_value = 1 + ctrls = {} + ids = {} + id_value = {} for ctrl in controls: id_name = snake_case(ctrl.name).upper() - ids.append('\t' + id_name + ' = ' + str(id_value) + ',') + vendor = 'draft' if ctrl.is_draft else ctrl.vendor + if vendor not in ctrls: + ids[vendor] = [] + id_value[vendor] = 1 + ctrls[vendor] = [] + + # Core and draft controls use the same ID value + target_ids = ids['libcamera'] if vendor in ['libcamera', 'draft'] else ids[vendor] + target_ids.append('\t' + id_name + ' = ' + str(id_value[vendor]) + ',') info = { 'name': ctrl.name, 'type': ctrl.type, } - target_ctrls = ctrls + target_ctrls = ctrls['libcamera'] if ctrl.is_draft: - target_ctrls = draft_ctrls + target_ctrls = ctrls['draft'] + elif vendor != 'libcamera': + target_ctrls = ctrls[vendor] if ctrl.is_enum: target_ctrls.append(enum_template_start.substitute(info)) @@ -257,12 +292,35 @@ def generate_h(controls): target_ctrls.append(enum_values_template.substitute(values_info)) target_ctrls.append(template.substitute(info)) - id_value += 1 + id_value[vendor] += 1 + + vendor_template = string.Template(''' +namespace ${vendor} { + +#define LIBCAMERA_HAS_${vendor_def}_VENDOR_${mode} + +enum { +${vendor_enums} +}; + +${vendor_controls} + +} /* namespace ${vendor} */ +''') + + vendor_sub = [] + for vendor in [v for v in ctrls.keys() if v not in ['libcamera', 'draft']]: + vendor_sub.append(vendor_template.substitute({'mode': mode.upper(), + 'vendor': vendor, + 'vendor_def': vendor.upper(), + 'vendor_enums': '\n'.join(ids[vendor]), + 'vendor_controls': '\n'.join(ctrls[vendor])})) return { - 'ids': '\n'.join(ids), - 'controls': '\n'.join(ctrls), - 'draft_controls': '\n'.join(draft_ctrls) + 'ids': '\n'.join(ids['libcamera']), + 'controls': '\n'.join(ctrls['libcamera']), + 'draft_controls': '\n'.join(ctrls['draft']), + 'vendor_controls': '\n'.join(vendor_sub) } @@ -278,22 +336,26 @@ def main(argv): # Parse command line arguments parser = argparse.ArgumentParser() - parser.add_argument('-o', dest='output', metavar='file', type=str, + parser.add_argument('--mode', '-m', type=str, required=True, choices=['controls', 'properties'], + help='Mode of operation') + parser.add_argument('--output', '-o', metavar='file', type=str, help='Output file name. Defaults to standard output if not specified.') parser.add_argument('input', type=str, help='Input file name.') parser.add_argument('template', type=str, help='Template file name.') + args = parser.parse_args(argv[1:]) data = open(args.input, 'rb').read() + vendor = yaml.safe_load(data)['vendor'] controls = yaml.safe_load(data)['controls'] - controls = [Control(*ctrl.popitem()) for ctrl in controls] + controls = [Control(*ctrl.popitem(), vendor) for ctrl in controls] if args.template.endswith('.cpp.in'): data = generate_cpp(controls) elif args.template.endswith('.h.in'): - data = generate_h(controls) + data = generate_h(controls, args.mode) else: raise RuntimeError('Unknown template type') From patchwork Thu Nov 30 14:25:30 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 19250 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 1B851C32B5 for ; Thu, 30 Nov 2023 14:25:46 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 2ECFD629C2; Thu, 30 Nov 2023 15:25:45 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1701354345; bh=fMpws5UIx7BYKu/3NzHLaLEyUquyAuud/to7nZFElPc=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=Frw4pot4HBsgdGPndmw8CYKZfvToPnSIduXWPzOmlFLa5ji/XBwCrSpsmsWL7zkBk EcoAYi1AZFunAHx6k2iUKZ2xURWBFKVXA5myaeMDfw2PXG8/TeqFu9XdqtfweifZz5 vHBa9yoEViuG09hwPTRdwPE9umWznl9G64UHBK4Pc67BKjAJNK6bnXuOR36ErK6Il4 jW2dVjfa0Lo5j968MT0CKUqnWkhl+7IQnnw6DGhCcfeYojsEZFfG0atMvs0IkaBOwg ekvL5TKNC2BlVPB+H+PyX2bDI8Yle59TqPb7PeMjE2FXNXwQwtLGOe/+1W89FhJwpf GRQLiS92CywEA== Received: from mail-ej1-x629.google.com (mail-ej1-x629.google.com [IPv6:2a00:1450:4864:20::629]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8D6ED629C2 for ; Thu, 30 Nov 2023 15:25:43 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="Q3swp61b"; dkim-atps=neutral Received: by mail-ej1-x629.google.com with SMTP id a640c23a62f3a-a18f732dc83so83227666b.1 for ; Thu, 30 Nov 2023 06:25:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1701354343; x=1701959143; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=5b5WNA8sbB0SjEir0c+PWNwpUQepvRCeAHvgloft+lQ=; b=Q3swp61bu/Z5O+Q4GLhcMBFKVGF2AzL72Ybww7DD+gTitcY9BfG0UydqzC17axoWqi DUldaoIVW6nKiHo/maK0Zb6fubUGJwdP3rRTE99R4tAhEDTnKvev5cOAL/ZzeCL9B18Y mFS1yZaOljEXBKT1UiZpz6jVgn8Y4tMtqbfrc4zbNCcx7W9Yo4JOks/zIHCQECv8mjtx ac3R7ok0xZzkONiFDDDvpZv4Pkr590AhTvKDMdr14Irtyr12lz7D2603HOTU0Ef9gYSy 8LZYZo9Q3cHJHBUp0iXuv78N+KPkz4ebGd0VHUCE483ewGjADAWaVnWIOvuZcD4KeNYM H3dw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1701354343; x=1701959143; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=5b5WNA8sbB0SjEir0c+PWNwpUQepvRCeAHvgloft+lQ=; b=wFHacr/tiS3+UWraDqaNcK6QH1gkRtQYrYTOvu5byvGij0GqDI7kUyZ5lcPGdYGZ5L LPHF+smnaGV/w4CFlCefuMbRFA0lWw09ezxMB+05heW7Z74qzT0i8TaVsekfOvQyZXWZ 9cJvwBmM4Mjbboc0kmgwQ+Zm8rakX6iaHdB8xvVEqi+Y5Ktz54Llv1jnJ6lE7Ndu9fKE nbF7rF/taz8SxSeUKEi9B1wL0zqYnI4y47T8Dc8Ocsnjz/PWGDgkiyeTqEKavMtx9RLo 6BTg4uPtBo2i/dTTX3her1FUXvmsgqv87KiUhgcvDuH2LyTqsdcSGXrf1KQJTMXaCjZ0 hMVg== X-Gm-Message-State: AOJu0YyzjicwWLxJ7+Z4tGAQ5Id11PtJZuRYYiZWMjHVc7eVmGZX7r68 MgR/paDycHKielK6eG1oEozLVRjlriJOjblSOkiTVA== X-Google-Smtp-Source: AGHT+IEkKp0dYo/dc+H/8/fp1fzi62esKp6xEmZxPcwU3m0bjac9nLkO5dTas9+hILONfBaVs0VXPA== X-Received: by 2002:a17:906:220b:b0:a0e:3ba4:4eac with SMTP id s11-20020a170906220b00b00a0e3ba44eacmr14143011ejs.27.1701354342732; Thu, 30 Nov 2023 06:25:42 -0800 (PST) Received: from localhost.localdomain ([88.97.53.79]) by smtp.gmail.com with ESMTPSA id a5-20020a17090640c500b009e50ea0a05asm725577ejk.99.2023.11.30.06.25.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 30 Nov 2023 06:25:42 -0800 (PST) To: libcamera-devel@lists.libcamera.org Date: Thu, 30 Nov 2023 14:25:30 +0000 Message-Id: <20231130142534.2075-3-naush@raspberrypi.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231130142534.2075-1-naush@raspberrypi.com> References: <20231130142534.2075-1-naush@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 2/6] controls: Update argument handling for controls generation scripts X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Naushir Patuck via libcamera-devel From: Naushir Patuck Reply-To: Naushir Patuck Cc: Jacopo Mondi Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The template file to the gen-controls.py and gen-py-controls.py is now passed in through the '-t' or '--template' command line argument instead of being a positional argument. This will allow multiple input files to be provided to the scripts in a future commit. Signed-off-by: Naushir Patuck Reviewed-by: Jacopo Mondi Reviewed-by: Kieran Bingham --- include/libcamera/meson.build | 7 ++++--- src/libcamera/meson.build | 7 ++++--- src/py/libcamera/gen-py-controls.py | 4 ++-- src/py/libcamera/meson.build | 18 ++++++++---------- utils/gen-controls.py | 4 ++-- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build index 2c8c0258c95e..5fb772e6dd14 100644 --- a/include/libcamera/meson.build +++ b/include/libcamera/meson.build @@ -41,12 +41,13 @@ control_source_files = { control_headers = [] foreach header, mode : control_source_files - input_files = files('../../src/libcamera/' + header +'.yaml', header + '.h.in') + input_files = files('../../src/libcamera/' + header +'.yaml') + template_file = files(header + '.h.in') control_headers += custom_target(header + '_h', input : input_files, output : header + '.h', - command : [gen_controls, '-o', '@OUTPUT@', '@INPUT@', - '--mode', mode], + command : [gen_controls, '-o', '@OUTPUT@', + '--mode', mode, '-t', template_file, '@INPUT@'], install : true, install_dir : libcamera_headers_install_dir) endforeach diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index e49bf850b355..05ee38daf22b 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -128,12 +128,13 @@ endif control_sources = [] foreach source, mode : control_source_files - input_files = files(source +'.yaml', source + '.cpp.in') + input_files = files(source +'.yaml') + template_file = files(source + '.cpp.in') control_sources += custom_target(source + '_cpp', input : input_files, output : source + '.cpp', - command : [gen_controls, '-o', '@OUTPUT@', '@INPUT@', - '--mode', mode]) + command : [gen_controls, '-o', '@OUTPUT@', + '--mode', mode, '-t', template_file, '@INPUT@']) endforeach libcamera_sources += control_sources diff --git a/src/py/libcamera/gen-py-controls.py b/src/py/libcamera/gen-py-controls.py index dfd7c179a883..cfcfd4d16acf 100755 --- a/src/py/libcamera/gen-py-controls.py +++ b/src/py/libcamera/gen-py-controls.py @@ -93,10 +93,10 @@ def main(argv): help='Mode is either "controls" or "properties"') parser.add_argument('--output', '-o', metavar='file', type=str, help='Output file name. Defaults to standard output if not specified.') + parser.add_argument('--template', '-t', type=str, required=True, + help='Template file name.') parser.add_argument('input', type=str, help='Input file name.') - parser.add_argument('template', type=str, - help='Template file name.') args = parser.parse_args(argv[1:]) if args.mode not in ['controls', 'properties']: diff --git a/src/py/libcamera/meson.build b/src/py/libcamera/meson.build index f58c7198ee9e..1c3ea1843ac0 100644 --- a/src/py/libcamera/meson.build +++ b/src/py/libcamera/meson.build @@ -28,29 +28,27 @@ pycamera_sources = files([ # Generate controls -gen_py_controls_input_files = files([ - '../../libcamera/control_ids.yaml', - 'py_controls_generated.cpp.in', -]) +gen_py_controls_input_files = files('../../libcamera/control_ids.yaml') +gen_py_controls_template = files('py_controls_generated.cpp.in') gen_py_controls = files('gen-py-controls.py') pycamera_sources += custom_target('py_gen_controls', input : gen_py_controls_input_files, output : ['py_controls_generated.cpp'], - command : [gen_py_controls, '--mode', 'controls', '-o', '@OUTPUT@', '@INPUT@']) + command : [gen_py_controls, '--mode', 'controls', '-o', '@OUTPUT@', + '-t', gen_py_controls_template, '@INPUT@']) # Generate properties -gen_py_property_enums_input_files = files([ - '../../libcamera/property_ids.yaml', - 'py_properties_generated.cpp.in', -]) +gen_py_property_enums_input_files = files('../../libcamera/property_ids.yaml') +gen_py_properties_template = files('py_properties_generated.cpp.in') pycamera_sources += custom_target('py_gen_properties', input : gen_py_property_enums_input_files, output : ['py_properties_generated.cpp'], - command : [gen_py_controls, '--mode', 'properties', '-o', '@OUTPUT@', '@INPUT@']) + command : [gen_py_controls, '--mode', 'properties', '-o', '@OUTPUT@', + '-t', gen_py_properties_template, '@INPUT@']) # Generate formats diff --git a/utils/gen-controls.py b/utils/gen-controls.py index c1172cb26e7b..56e0c7ba98f2 100755 --- a/utils/gen-controls.py +++ b/utils/gen-controls.py @@ -340,10 +340,10 @@ def main(argv): help='Mode of operation') parser.add_argument('--output', '-o', metavar='file', type=str, help='Output file name. Defaults to standard output if not specified.') + parser.add_argument('--template', '-t', dest='template', type=str, required=True, + help='Template file name.') parser.add_argument('input', type=str, help='Input file name.') - parser.add_argument('template', type=str, - help='Template file name.') args = parser.parse_args(argv[1:]) From patchwork Thu Nov 30 14:25:31 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 19251 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id E95C8C31E9 for ; Thu, 30 Nov 2023 14:25:46 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id EBC03629D3; Thu, 30 Nov 2023 15:25:45 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1701354346; bh=OQvnV1gK6BNSShRThLob5xSE1uIM3pEQPeydc5K8CSM=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=FuW4CMrrLe/vJ4AuTkYWilSf1OYxrii1gM69JIgxoRZXbjWJ+nYhYLIrYR1ajH2EV WZk+EZaafX/rYcYAbTgxmlcaCn0SPR4+4ULzxLxenO88E6O+58JgjYgUt17m7ky5pr tQ8BoVp5/w/3JI2E1aW/0yDD0gGUHTR979Uy+Zv/ckNUjUAWo9WJZX8vD89v4MYe4T ixqk26KMVloZN1lelsRheGeZ+DPAZdJu3Fo2kZb5NsoR+1EN5fc1ePFkZOq48AvkQ+ YpaEN6sG7Nmdznm/OZ1Lqx5zbAqJ7TQf0nrsyjENj2NQyozG0w/o2FtPbQEOes7Bl+ BrZJVu9DFngjQ== Received: from mail-ej1-x630.google.com (mail-ej1-x630.google.com [IPv6:2a00:1450:4864:20::630]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 75823629C2 for ; Thu, 30 Nov 2023 15:25:44 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="lrNs3Big"; dkim-atps=neutral Received: by mail-ej1-x630.google.com with SMTP id a640c23a62f3a-a06e59384b6so147040666b.1 for ; Thu, 30 Nov 2023 06:25:44 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1701354344; x=1701959144; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=FesQa8IGx1toANo6uMQtuuDPNiO8Dh6SuN9++vhdB9g=; b=lrNs3BigT/frhWjkFKhbLeLCL5NHBtJZe4cOJqdl8YeUWirV1ibH91IiPFpkonsYM8 4/z1abr/eL2I1fct2xNKRk6LsI8OiViXGKtWmzLi6cSN0ZEgF3pLGKJwZ0sQY57hdZ28 TyoHpa8SlFZJLX/+jfURBjYXARjV64xXOWfekBqAXBoxQbPwo3059adPS3q6Q5MvOg6n bP2IsnnLTzyNHJWzKe0LGYmWdNOLzxJ5UkGkugxnJn9o0kziRWr74lEjsvaeus/dYLz2 TcgiwQvckDL9ZpWtYEi7wC0fQz4iNSx5zeK5f1rq0ZOT2vd+1bYszts+yvoLlUde+WYl Oghw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1701354344; x=1701959144; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=FesQa8IGx1toANo6uMQtuuDPNiO8Dh6SuN9++vhdB9g=; b=myGB2MMRc9pjaGmE/jvAFOJDJSblsqIzd9J2vIZWixwCID/Kp11zPcKRha0t9xhJn7 d2bCwyAOjK59TRAVlMs+TnZkZCBImhiHTmpBeSaakRrBxCt8HmdYVurP24+4YMJ0jM7F aT/xuoCme3ldTTA7taKLHOVOiXqFRILgFCkpONyNm/N099N6BUzQbpeXLFuXpWzdxXoJ ogTDuwlwofqq4ZPsTxgZtm7tq9DcB8fMElgeL07JDg7ubdxbGel/5vYkZexkQ3LUa/jH qkXSNOTy73eAoAoz7pMi+zQ7bBdtA3JCpZIKNOkiZt7Wqf1GOMEEkDqoSEpnEUtNf3Xa 4AVA== X-Gm-Message-State: AOJu0Yy9TXTAIh5GPbz3npESuAVcAJdNeLk7S5eJ5a7WlhiwW24lAYL1 mB8FDNG7ETc6aJwISExbjfOSjfJyPUsJ4iaH4WoNlg== X-Google-Smtp-Source: AGHT+IG3+4XhkrglrpGMu6SQeshK27oL9V3hnmJkDu4PDnJj6YqkhMRyd8wlasXPp4qkjX8Y2NErbw== X-Received: by 2002:a17:906:1e8f:b0:9ff:aeea:89a7 with SMTP id e15-20020a1709061e8f00b009ffaeea89a7mr15662990ejj.39.1701354343769; Thu, 30 Nov 2023 06:25:43 -0800 (PST) Received: from localhost.localdomain ([88.97.53.79]) by smtp.gmail.com with ESMTPSA id a5-20020a17090640c500b009e50ea0a05asm725577ejk.99.2023.11.30.06.25.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 30 Nov 2023 06:25:43 -0800 (PST) To: libcamera-devel@lists.libcamera.org Date: Thu, 30 Nov 2023 14:25:31 +0000 Message-Id: <20231130142534.2075-4-naush@raspberrypi.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231130142534.2075-1-naush@raspberrypi.com> References: <20231130142534.2075-1-naush@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 3/6] build: controls: Rework how controls and properties are generated X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Naushir Patuck via libcamera-devel From: Naushir Patuck Reply-To: Naushir Patuck Cc: Jacopo Mondi Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add support for using separate YAML files for controls and properties generation. The mapping of vendor/pipeline handler to control file is done through the controls_map variable in include/libcamera/meson.build. This simplifies management of vendor control definitions and avoids possible merge conflicts when changing the control_ids.yaml file for core and draft controls. With this change, libcamera and draft controls and properties files are designated the 'libcamera' vendor tag. In this change, we also rename control_ids.yaml -> control_ids_core.yaml and property_ids.yaml -> property_ids_core.yaml to designate these as core libcamera controls. Signed-off-by: Naushir Patuck Reviewed-by: Jacopo Mondi Reviewed-by: Kieran Bingham --- Documentation/guides/pipeline-handler.rst | 8 +-- include/libcamera/meson.build | 50 +++++++++++++++---- meson.build | 2 + ...control_ids.yaml => control_ids_core.yaml} | 0 src/libcamera/meson.build | 21 ++++++-- ...operty_ids.yaml => property_ids_core.yaml} | 0 src/py/libcamera/gen-py-controls.py | 10 ++-- src/py/libcamera/meson.build | 12 ++++- utils/gen-controls.py | 14 ++++-- 9 files changed, 87 insertions(+), 30 deletions(-) rename src/libcamera/{control_ids.yaml => control_ids_core.yaml} (100%) rename src/libcamera/{property_ids.yaml => property_ids_core.yaml} (100%) diff --git a/Documentation/guides/pipeline-handler.rst b/Documentation/guides/pipeline-handler.rst index 10b9c75c2a7f..66d428a19c4f 100644 --- a/Documentation/guides/pipeline-handler.rst +++ b/Documentation/guides/pipeline-handler.rst @@ -587,12 +587,12 @@ immutable properties of the ``Camera`` device. The libcamera controls and properties are defined in YAML form which is processed to automatically generate documentation and interfaces. Controls are -defined by the src/libcamera/`control_ids.yaml`_ file and camera properties -are defined by src/libcamera/`properties_ids.yaml`_. +defined by the src/libcamera/`control_ids_core.yaml`_ file and camera properties +are defined by src/libcamera/`properties_ids_core.yaml`_. .. _controls framework: https://libcamera.org/api-html/controls_8h.html -.. _control_ids.yaml: https://libcamera.org/api-html/control__ids_8h.html -.. _properties_ids.yaml: https://libcamera.org/api-html/property__ids_8h.html +.. _control_ids_core.yaml: https://libcamera.org/api-html/control__ids_8h.html +.. _properties_ids_core.yaml: https://libcamera.org/api-html/property__ids_8h.html Pipeline handlers can optionally register the list of controls an application can set as well as a list of immutable camera properties. Being both diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build index 5fb772e6dd14..c46a4e701ac4 100644 --- a/include/libcamera/meson.build +++ b/include/libcamera/meson.build @@ -32,22 +32,54 @@ install_headers(libcamera_public_headers, libcamera_headers_install_dir = get_option('includedir') / libcamera_include_dir -# control_ids.h and property_ids.h and associated modes -control_source_files = { - 'control_ids': 'controls', - 'property_ids': 'properties', +controls_map = { + 'controls': { + 'core': 'control_ids_core.yaml', + }, + + 'properties': { + 'core': 'property_ids_core.yaml', + } } control_headers = [] +controls_files = [] +properties_files = [] + +foreach mode, entry : controls_map + files_list = [] + input_files = [] + foreach vendor, header : entry + if vendor != 'core' and vendor != 'draft' + if vendor not in pipelines + continue + endif + endif + + if header in files_list + continue + endif + + files_list += header + input_files += files('../../src/libcamera/' + header) + endforeach + + outfile = '' + if mode == 'controls' + outfile = 'control_ids.h' + controls_files += files_list + else + outfile = 'property_ids.h' + properties_files += files_list + endif -foreach header, mode : control_source_files - input_files = files('../../src/libcamera/' + header +'.yaml') - template_file = files(header + '.h.in') + template_file = files(outfile + '.in') control_headers += custom_target(header + '_h', input : input_files, - output : header + '.h', + output : outfile, command : [gen_controls, '-o', '@OUTPUT@', - '--mode', mode, '-t', template_file, '@INPUT@'], + '--mode', mode, '-t', template_file, + '@INPUT@'], install : true, install_dir : libcamera_headers_install_dir) endforeach diff --git a/meson.build b/meson.build index e9a1c7e360ce..ee57cb780149 100644 --- a/meson.build +++ b/meson.build @@ -267,6 +267,8 @@ py_mod.find_installation('python3', modules : py_modules) summary({ 'Enabled pipelines': pipelines, 'Enabled IPA modules': enabled_ipa_names, + 'Controls files': controls_files, + 'Properties files': properties_files, 'Hotplug support': libudev.found(), 'Tracing support': tracing_enabled, 'Android support': android_enabled, diff --git a/src/libcamera/control_ids.yaml b/src/libcamera/control_ids_core.yaml similarity index 100% rename from src/libcamera/control_ids.yaml rename to src/libcamera/control_ids_core.yaml diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 05ee38daf22b..6d9902e6ffd1 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -127,12 +127,23 @@ endif control_sources = [] -foreach source, mode : control_source_files - input_files = files(source +'.yaml') - template_file = files(source + '.cpp.in') - control_sources += custom_target(source + '_cpp', +controls_mode_files = { + 'controls' : controls_files, + 'properties' : properties_files, +} + +foreach mode, input_files : controls_mode_files + input_files = files(input_files) + + if mode == 'controls' + template_file = files('control_ids.cpp.in') + else + template_file = files('property_ids.cpp.in') + endif + + control_sources += custom_target(mode + '_cpp', input : input_files, - output : source + '.cpp', + output : mode + '_ids.cpp', command : [gen_controls, '-o', '@OUTPUT@', '--mode', mode, '-t', template_file, '@INPUT@']) endforeach diff --git a/src/libcamera/property_ids.yaml b/src/libcamera/property_ids_core.yaml similarity index 100% rename from src/libcamera/property_ids.yaml rename to src/libcamera/property_ids_core.yaml diff --git a/src/py/libcamera/gen-py-controls.py b/src/py/libcamera/gen-py-controls.py index cfcfd4d16acf..8ae8d5126e39 100755 --- a/src/py/libcamera/gen-py-controls.py +++ b/src/py/libcamera/gen-py-controls.py @@ -95,7 +95,7 @@ def main(argv): help='Output file name. Defaults to standard output if not specified.') parser.add_argument('--template', '-t', type=str, required=True, help='Template file name.') - parser.add_argument('input', type=str, + parser.add_argument('input', type=str, nargs='+', help='Input file name.') args = parser.parse_args(argv[1:]) @@ -103,11 +103,11 @@ def main(argv): print(f'Invalid mode option "{args.mode}"', file=sys.stderr) return -1 - data = open(args.input, 'rb').read() - controls = {} - vendor = yaml.safe_load(data)['vendor'] - controls[vendor] = yaml.safe_load(data)['controls'] + for input in args.input: + data = open(input, 'rb').read() + vendor = yaml.safe_load(data)['vendor'] + controls[vendor] = yaml.safe_load(data)['controls'] data = generate_py(controls, args.mode) diff --git a/src/py/libcamera/meson.build b/src/py/libcamera/meson.build index 1c3ea1843ac0..31af63ec0dc6 100644 --- a/src/py/libcamera/meson.build +++ b/src/py/libcamera/meson.build @@ -28,11 +28,15 @@ pycamera_sources = files([ # Generate controls -gen_py_controls_input_files = files('../../libcamera/control_ids.yaml') +gen_py_controls_input_files = [] gen_py_controls_template = files('py_controls_generated.cpp.in') gen_py_controls = files('gen-py-controls.py') +foreach file : controls_files + gen_py_controls_input_files += files('../../libcamera/' + file) +endforeach + pycamera_sources += custom_target('py_gen_controls', input : gen_py_controls_input_files, output : ['py_controls_generated.cpp'], @@ -41,9 +45,13 @@ pycamera_sources += custom_target('py_gen_controls', # Generate properties -gen_py_property_enums_input_files = files('../../libcamera/property_ids.yaml') +gen_py_property_enums_input_files = [] gen_py_properties_template = files('py_properties_generated.cpp.in') +foreach file : properties_files + gen_py_property_enums_input_files += files('../../libcamera/' + file) +endforeach + pycamera_sources += custom_target('py_gen_properties', input : gen_py_property_enums_input_files, output : ['py_properties_generated.cpp'], diff --git a/utils/gen-controls.py b/utils/gen-controls.py index 56e0c7ba98f2..2a633cc0aba9 100755 --- a/utils/gen-controls.py +++ b/utils/gen-controls.py @@ -12,6 +12,7 @@ import operator import string import sys import yaml +import os class ControlEnum(object): @@ -342,15 +343,18 @@ def main(argv): help='Output file name. Defaults to standard output if not specified.') parser.add_argument('--template', '-t', dest='template', type=str, required=True, help='Template file name.') - parser.add_argument('input', type=str, + parser.add_argument('input', type=str, nargs='+', help='Input file name.') args = parser.parse_args(argv[1:]) - data = open(args.input, 'rb').read() - vendor = yaml.safe_load(data)['vendor'] - controls = yaml.safe_load(data)['controls'] - controls = [Control(*ctrl.popitem(), vendor) for ctrl in controls] + controls = [] + for input in args.input: + with open(input, 'rb') as f: + data = f.read() + vendor = yaml.safe_load(data)['vendor'] + ctrls = yaml.safe_load(data)['controls'] + controls = controls + [Control(*ctrl.popitem(), vendor) for ctrl in ctrls] if args.template.endswith('.cpp.in'): data = generate_cpp(controls) From patchwork Thu Nov 30 14:25:32 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 19252 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id C8D91C32B5 for ; Thu, 30 Nov 2023 14:25:48 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7FE44629CF; Thu, 30 Nov 2023 15:25:48 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1701354348; bh=2cqMmfpJysqXAMnIJX1SsnoAlqgYBQFtjEQO/6n7xZ0=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=gmTIeNCwIQas6JPTF/RHMZThk8X2upF+sWYjVINIQ2NyS/pvcKdpkJbx+kVyTYgtv +Aqllc00FLjAH2VtwIv3xtrDAhtxquR9nOPHmAZ1W0GgzG6JoDnKMQNCl75lyEGEd+ rmjCZO2RAHPUwXkC07zYNuWggTqV9nVgk0byfNyXwUL2wAaNkJWscYRo/KGtThhxFI B78RhthrFwS6T+RY7PAvZu94o5s0Lpfh65sWvZo8bJPTs6DRBWlueyommIKb66apZR YWpfFrrZBI3R0FCxRmz2SV+/YHuc+JLFvjZuUaJJEhQU8N/w3hH/GEbYIyRvEVtylS xb53Uj6gTvaLA== Received: from mail-ej1-x631.google.com (mail-ej1-x631.google.com [IPv6:2a00:1450:4864:20::631]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 36C75629D5 for ; Thu, 30 Nov 2023 15:25:45 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="Sy1476eS"; dkim-atps=neutral Received: by mail-ej1-x631.google.com with SMTP id a640c23a62f3a-9fa45e75ed9so142167866b.1 for ; Thu, 30 Nov 2023 06:25:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1701354344; x=1701959144; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=8MNvkO447TQABbMc0LlAq8P6s+MCZZx+lmqdO0CLVRk=; b=Sy1476eSsVGSwS90kkb6u7G0Wjv2Wgphu77Z/brxgeoBn1953Ps3T6D1V4JyrBeUL2 V1yE9AaW82qlorvtb9mM9lTg7GMI0pXLpQsalaaOhgBZBPzrBwJcqxIofRg30gT8l4ok lue+p62vO6fdafP5hqB+k+BxC0igzOZQQe80JF0zyF+jGr8h1z9gdZPEVp8RNh8dlyiY Yi6vTZmuMoER5hCHWkJLQ3CBl0CCtuBBFqay6js43g2f+oKl+7BHyjka7fgyRj2uko2E 3coYNYd/Ks725rUMOrIPYOsdABd8xjIZkEgEfoAHsXiqzUTFpW57ow1siI0CLpPHRewW iFlA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1701354344; x=1701959144; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=8MNvkO447TQABbMc0LlAq8P6s+MCZZx+lmqdO0CLVRk=; b=XkuQc3nIp51LpnverZVz8p7uFXt9Q/+ZMq+K0ZuCf5Fk15Vgmb30F2bUTyR3dt5Erq 0S7R2CyHZ5sqDEryZMmw/ptouC2dqT7d55YgZ1Pdg/zO29s7vvts35tOk159HvgeBqfh cIGTh1StdLTWmNBYeSv62ioqeolCzXnDJwRAkeXJDxa7+udh3zYXhnQB4d9Vm0a6DVrp 6nnph6Vz0N1PDMF7Nd6+XL4UBoZj1j/nPqJ8/biUFNSbIWXn1OHpqIzzYC1RD84vcEK2 LGfH9HZbEIHeZVsPGb6bTTDb+DHLNPMlvb8uPnne+1fXiOR8oGNHS3pPXaz9jHfARNSN 5GQA== X-Gm-Message-State: AOJu0Yxe0RkTiXxNyS6VJFFWuoH5KsKDW3K5A3CTpYvt3qyEx/jaOR03 b0jsk4JDqImUCaksj/59Pd4HGwbjsuLkA4Q2ODl8kQ== X-Google-Smtp-Source: AGHT+IFSPmOsHRHyZ09FPi8s5EAmI4Fgme0XA37LlW2Vd+LDDZo+9zCMDIrNkKDgO7hW5R4sxJ/Iig== X-Received: by 2002:a17:906:f806:b0:a0e:3a12:a62a with SMTP id kh6-20020a170906f80600b00a0e3a12a62amr8461100ejb.59.1701354344643; Thu, 30 Nov 2023 06:25:44 -0800 (PST) Received: from localhost.localdomain ([88.97.53.79]) by smtp.gmail.com with ESMTPSA id a5-20020a17090640c500b009e50ea0a05asm725577ejk.99.2023.11.30.06.25.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 30 Nov 2023 06:25:44 -0800 (PST) To: libcamera-devel@lists.libcamera.org Date: Thu, 30 Nov 2023 14:25:32 +0000 Message-Id: <20231130142534.2075-5-naush@raspberrypi.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231130142534.2075-1-naush@raspberrypi.com> References: <20231130142534.2075-1-naush@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 4/6] libcamera: control: Add vendor control id range reservation X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Naushir Patuck via libcamera-devel From: Naushir Patuck Reply-To: Naushir Patuck Cc: Jacopo Mondi Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add a new control_ranges.yaml file that is used to reserve control id ranges/offsets for libcamera and vendor specific controls. This file is used by the gen-controls.py script to generate control id values for each control. Draft controls now have a separate range from core libcamera controls, breaking the existing numbering behaviour. Signed-off-by: Naushir Patuck Reviewed-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Jacopo Mondi --- include/libcamera/meson.build | 3 ++- src/libcamera/control_ranges.yaml | 18 ++++++++++++++++++ src/libcamera/meson.build | 4 +++- utils/gen-controls.py | 15 ++++++++++++--- 4 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 src/libcamera/control_ranges.yaml diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build index c46a4e701ac4..a2bb5d163ece 100644 --- a/include/libcamera/meson.build +++ b/include/libcamera/meson.build @@ -74,12 +74,13 @@ foreach mode, entry : controls_map endif template_file = files(outfile + '.in') + ranges_file = files('../../src/libcamera/control_ranges.yaml') control_headers += custom_target(header + '_h', input : input_files, output : outfile, command : [gen_controls, '-o', '@OUTPUT@', '--mode', mode, '-t', template_file, - '@INPUT@'], + '-r', ranges_file, '@INPUT@'], install : true, install_dir : libcamera_headers_install_dir) endforeach diff --git a/src/libcamera/control_ranges.yaml b/src/libcamera/control_ranges.yaml new file mode 100644 index 000000000000..d42447d04647 --- /dev/null +++ b/src/libcamera/control_ranges.yaml @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# Copyright (C) 2023, Raspberry Pi Ltd +# +%YAML 1.1 +--- +# Specifies the control id ranges/offsets for core/draft libcamera and vendor +# controls and properties. +ranges: + # Core libcamera controls + libcamera: 0 + # Draft designated libcamera controls + draft: 10000 + # Raspberry Pi vendor controls + rpi: 20000 + # Next range starts at 30000 + +... diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 6d9902e6ffd1..45f63e932e4f 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -141,11 +141,13 @@ foreach mode, input_files : controls_mode_files template_file = files('property_ids.cpp.in') endif + ranges_file = files('control_ranges.yaml') control_sources += custom_target(mode + '_cpp', input : input_files, output : mode + '_ids.cpp', command : [gen_controls, '-o', '@OUTPUT@', - '--mode', mode, '-t', template_file, '@INPUT@']) + '--mode', mode, '-t', template_file, + '-r', ranges_file, '@INPUT@']) endforeach libcamera_sources += control_sources diff --git a/utils/gen-controls.py b/utils/gen-controls.py index 2a633cc0aba9..8e592148af3d 100755 --- a/utils/gen-controls.py +++ b/utils/gen-controls.py @@ -239,7 +239,7 @@ ${vendor_controls_str} } -def generate_h(controls, mode): +def generate_h(controls, mode, ranges): enum_template_start = string.Template('''enum ${name}Enum {''') enum_value_template = string.Template('''\t${name} = ${value},''') enum_values_template = string.Template('''extern const std::array ${name}Values;''') @@ -254,8 +254,10 @@ def generate_h(controls, mode): vendor = 'draft' if ctrl.is_draft else ctrl.vendor if vendor not in ctrls: + if vendor not in ranges.keys(): + raise RuntimeError(f'Control id range is not defined for vendor {vendor}') + id_value[vendor] = ranges[vendor] + 1 ids[vendor] = [] - id_value[vendor] = 1 ctrls[vendor] = [] # Core and draft controls use the same ID value @@ -341,6 +343,8 @@ def main(argv): help='Mode of operation') parser.add_argument('--output', '-o', metavar='file', type=str, help='Output file name. Defaults to standard output if not specified.') + parser.add_argument('--ranges', '-r', type=str, required=True, + help='Control id range reservation file.') parser.add_argument('--template', '-t', dest='template', type=str, required=True, help='Template file name.') parser.add_argument('input', type=str, nargs='+', @@ -348,6 +352,11 @@ def main(argv): args = parser.parse_args(argv[1:]) + ranges = {} + with open(args.ranges, 'rb') as f: + data = open(args.ranges, 'rb').read() + ranges = yaml.safe_load(data)['ranges'] + controls = [] for input in args.input: with open(input, 'rb') as f: @@ -359,7 +368,7 @@ def main(argv): if args.template.endswith('.cpp.in'): data = generate_cpp(controls) elif args.template.endswith('.h.in'): - data = generate_h(controls, args.mode) + data = generate_h(controls, args.mode, ranges) else: raise RuntimeError('Unknown template type') From patchwork Thu Nov 30 14:25:33 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 19253 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 7A02EC31E9 for ; Thu, 30 Nov 2023 14:25:50 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 268C9629CD; Thu, 30 Nov 2023 15:25:50 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1701354350; bh=OfkS80bDxpPLiQFo7/s2nNGfbJprdOgu2A0lUVDzufQ=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=reQ5cNj8yeOVHvtTqW2PFV+5/0udZ1RDyk8y34cRkji6XqFrZ34hiGjuQKgGGWKvF 6GdGGGrHG/fQ2ntRFa0qQmIrYQ/SMq49o53ISvw2tBZNwNU04NkDrvXOJhbPT5RtgK eGCT3ZiMnv2qO8u882jALHaxJ7Jlqgyt5UiODZuu8vT32Y35aqomFCuBDvXsd2cEOm C1KMO9mnLsyRUsq0Hvgz+tr/0N9NDXJdmXbBOYZ4b7fKZ7uDLOSXN/uZLnSS5PSlIn Gv29LTt+CRiGY0XRenf8R4oAVJHDTM5N/vtHpEqSpIzEWBpzPp5VUOWHBbGM7vQ5AA Rn4ZGfvRCNWTw== Received: from mail-ed1-x532.google.com (mail-ed1-x532.google.com [IPv6:2a00:1450:4864:20::532]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 88CA6629CF for ; Thu, 30 Nov 2023 15:25:46 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="fpvJ+sxD"; dkim-atps=neutral Received: by mail-ed1-x532.google.com with SMTP id 4fb4d7f45d1cf-54b0073d50fso1045069a12.2 for ; Thu, 30 Nov 2023 06:25:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1701354346; x=1701959146; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=JySX0keog5rCmfsQOpUf57BclqOiVUVVM1eEKysW46M=; b=fpvJ+sxDA/fu4exlnqcZZ9JBVzb6heK2YW8Y2saDFX1M1sxXVbS6x0tudpGEj+pz16 yRPNDYT7XQ/2wR19I6UIhCJQ7X/0LCSyDG5+axWH0manoP+dZITJhx+jte15jRWwZnpP /qrXwYOUGTJ/P/l49Fb+XtPSN73U0wvFTx5gY3QMTNJ5SgsG3rn2ruFylU8IJeND5/3r y+cmZFo4XGBgoQaekQXhqG86MaiqVhM30DzjOpSgrEM4oA50EyC0bUHrE8FG1FO0Si8z RNjEQkIwoUU3EOZBX3Ii8radgWAKxlctB+mfg11l2IaKxrjP1PFToK/v+PrlQ0QfCXkh vcIA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1701354346; x=1701959146; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=JySX0keog5rCmfsQOpUf57BclqOiVUVVM1eEKysW46M=; b=asc5AzIf4JHWYzcmQfBQbAzGk+eoLsyAYR7GnoWzN4XY+LnWk7HNRkga8pH8Mo/xJO ZOARe9tuHZ9GLrzSpg0v2zGTindP6qHBsrFxihNotYqCmeK5X4K6549Wff65qcvwIOBz 1Rf5NfvSC27VHuh/UltvpCI08AT533QQspvp3gxeiqwcMNFHjyUOT4kO4nye/IX5Vm4t E4N1P2i1ZKHyQPgsKtJC8TlbjcduJ2U+VIJTkXNv8sNUBReUvXLPgKQzW4LVbRDmzC2r dG4+uWCAyGpS0j+/rlNw7qcUD/+Ped178lhyIlJB78C6l1Wlqvd9V90lIQxUM/8/RRYN SACw== X-Gm-Message-State: AOJu0Yw3QDOk2fiq5Kaq2n4DXYpETO8d8vh8uxvhYzPUG4ijq4TS/neH OXH5VutVKqNVYzNwb+VVOrJhbKNyW6lMo1t4R56FUQ== X-Google-Smtp-Source: AGHT+IFZm0wUJDWnwbBRHK1t/p/mVa36jSfhd7tFcpabr4s2HdspreqiXoyDg1rpe3dTTOkj8ChLzQ== X-Received: by 2002:a17:906:190:b0:a17:29b0:573e with SMTP id 16-20020a170906019000b00a1729b0573emr4555303ejb.37.1701354345410; Thu, 30 Nov 2023 06:25:45 -0800 (PST) Received: from localhost.localdomain ([88.97.53.79]) by smtp.gmail.com with ESMTPSA id a5-20020a17090640c500b009e50ea0a05asm725577ejk.99.2023.11.30.06.25.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 30 Nov 2023 06:25:45 -0800 (PST) To: libcamera-devel@lists.libcamera.org Date: Thu, 30 Nov 2023 14:25:33 +0000 Message-Id: <20231130142534.2075-6-naush@raspberrypi.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231130142534.2075-1-naush@raspberrypi.com> References: <20231130142534.2075-1-naush@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 5/6] libcamera: controls: Use vendor tags for draft controls and properties X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Naushir Patuck via libcamera-devel From: Naushir Patuck Reply-To: Naushir Patuck Cc: Jacopo Mondi Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Label draft controls and properties through the "draft" vendor tag and deprecate the existing "draft: true" mechanism. This uses the new vendor tags mechanism to place draft controls in the same libcamera::controls::draft namespace and provide a defined control id range for these controls. This requires moving all draft controls from control_ids.yaml to control_ids_draft.yaml. One breaking change in this commit is that draft control ids also move to the libcamera::controls::draft namespace from the existing libcamera::controls namespace. This is desirable to avoid API breakages when adding new libcamera controls. So, for example, the use of controls::NOISE_REDUCTION_MODE will need to be replaced with controls::draft::NOISE_REDUCTION_MODE. Signed-off-by: Naushir Patuck Reviewed-by: Jacopo Mondi Reviewed-by: Kieran Bingham --- include/libcamera/control_ids.h.in | 6 - include/libcamera/meson.build | 2 + include/libcamera/property_ids.h.in | 6 - src/ipa/rpi/common/ipa_base.cpp | 2 +- src/ipa/rpi/vc4/vc4.cpp | 2 +- src/libcamera/control_ids.cpp.in | 15 -- src/libcamera/control_ids_core.yaml | 232 ------------------ src/libcamera/control_ids_draft.yaml | 230 +++++++++++++++++ src/libcamera/property_ids.cpp.in | 15 -- src/libcamera/property_ids_core.yaml | 33 --- src/libcamera/property_ids_draft.yaml | 39 +++ src/py/libcamera/gen-py-controls.py | 10 +- src/py/libcamera/py_controls_generated.cpp.in | 5 - .../libcamera/py_properties_generated.cpp.in | 5 - utils/gen-controls.py | 36 +-- 15 files changed, 286 insertions(+), 352 deletions(-) create mode 100644 src/libcamera/control_ids_draft.yaml create mode 100644 src/libcamera/property_ids_draft.yaml diff --git a/include/libcamera/control_ids.h.in b/include/libcamera/control_ids.h.in index c97b09a82450..d53b1cf7beb2 100644 --- a/include/libcamera/control_ids.h.in +++ b/include/libcamera/control_ids.h.in @@ -26,12 +26,6 @@ ${controls} extern const ControlIdMap controls; -namespace draft { - -${draft_controls} - -} /* namespace draft */ - ${vendor_controls} } /* namespace controls */ diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build index a2bb5d163ece..bab858a3790f 100644 --- a/include/libcamera/meson.build +++ b/include/libcamera/meson.build @@ -34,10 +34,12 @@ libcamera_headers_install_dir = get_option('includedir') / libcamera_include_dir controls_map = { 'controls': { + 'draft': 'control_ids_draft.yaml', 'core': 'control_ids_core.yaml', }, 'properties': { + 'draft': 'property_ids_draft.yaml', 'core': 'property_ids_core.yaml', } } diff --git a/include/libcamera/property_ids.h.in b/include/libcamera/property_ids.h.in index 47c5d6bf2e28..43372c718fc9 100644 --- a/include/libcamera/property_ids.h.in +++ b/include/libcamera/property_ids.h.in @@ -23,12 +23,6 @@ ${ids} ${controls} -namespace draft { - -${draft_controls} - -} /* namespace draft */ - extern const ControlIdMap properties; ${vendor_controls} diff --git a/src/ipa/rpi/common/ipa_base.cpp b/src/ipa/rpi/common/ipa_base.cpp index a1fec3aa3dd1..6ac9d5de2f88 100644 --- a/src/ipa/rpi/common/ipa_base.cpp +++ b/src/ipa/rpi/common/ipa_base.cpp @@ -1024,7 +1024,7 @@ void IpaBase::applyControls(const ControlList &controls) break; } - case controls::NOISE_REDUCTION_MODE: + case controls::draft::NOISE_REDUCTION_MODE: /* Handled below in handleControls() */ libcameraMetadata_.set(controls::draft::NoiseReductionMode, ctrl.second.get()); diff --git a/src/ipa/rpi/vc4/vc4.cpp b/src/ipa/rpi/vc4/vc4.cpp index c4baf04fb1e7..c165a5b8b0b6 100644 --- a/src/ipa/rpi/vc4/vc4.cpp +++ b/src/ipa/rpi/vc4/vc4.cpp @@ -260,7 +260,7 @@ void IpaVc4::handleControls(const ControlList &controls) for (auto const &ctrl : controls) { switch (ctrl.first) { - case controls::NOISE_REDUCTION_MODE: { + case controls::draft::NOISE_REDUCTION_MODE: { RPiController::DenoiseAlgorithm *sdn = dynamic_cast( controller_.getAlgorithm("SDN")); /* Some platforms may have a combined "denoise" algorithm instead. */ diff --git a/src/libcamera/control_ids.cpp.in b/src/libcamera/control_ids.cpp.in index bdb312759eb1..d283c1c1f401 100644 --- a/src/libcamera/control_ids.cpp.in +++ b/src/libcamera/control_ids.cpp.in @@ -24,15 +24,6 @@ namespace controls { ${controls_doc} -/** - * \brief Namespace for libcamera draft controls - */ -namespace draft { - -${draft_controls_doc} - -} /* namespace draft */ - ${vendor_controls_doc} #ifndef __DOXYGEN__ @@ -42,12 +33,6 @@ ${vendor_controls_doc} */ ${controls_def} -namespace draft { - -${draft_controls_def} - -} /* namespace draft */ - ${vendor_controls_def} #endif diff --git a/src/libcamera/control_ids_core.yaml b/src/libcamera/control_ids_core.yaml index ff74ce1deedb..76fb9347d8e3 100644 --- a/src/libcamera/control_ids_core.yaml +++ b/src/libcamera/control_ids_core.yaml @@ -865,236 +865,4 @@ controls: description: | This is a long exposure image. - # ---------------------------------------------------------------------------- - # Draft controls section - - - AePrecaptureTrigger: - type: int32_t - draft: true - description: | - Control for AE metering trigger. Currently identical to - ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER. - - Whether the camera device will trigger a precapture metering sequence - when it processes this request. - enum: - - name: AePrecaptureTriggerIdle - value: 0 - description: The trigger is idle. - - name: AePrecaptureTriggerStart - value: 1 - description: The pre-capture AE metering is started by the camera. - - name: AePrecaptureTriggerCancel - value: 2 - description: | - The camera will cancel any active or completed metering sequence. - The AE algorithm is reset to its initial state. - - - NoiseReductionMode: - type: int32_t - draft: true - description: | - Control to select the noise reduction algorithm mode. Currently - identical to ANDROID_NOISE_REDUCTION_MODE. - - Mode of operation for the noise reduction algorithm. - enum: - - name: NoiseReductionModeOff - value: 0 - description: No noise reduction is applied - - name: NoiseReductionModeFast - value: 1 - description: | - Noise reduction is applied without reducing the frame rate. - - name: NoiseReductionModeHighQuality - value: 2 - description: | - High quality noise reduction at the expense of frame rate. - - name: NoiseReductionModeMinimal - value: 3 - description: | - Minimal noise reduction is applied without reducing the frame rate. - - name: NoiseReductionModeZSL - value: 4 - description: | - Noise reduction is applied at different levels to different streams. - - - ColorCorrectionAberrationMode: - type: int32_t - draft: true - description: | - Control to select the color correction aberration mode. Currently - identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE. - - Mode of operation for the chromatic aberration correction algorithm. - enum: - - name: ColorCorrectionAberrationOff - value: 0 - description: No aberration correction is applied. - - name: ColorCorrectionAberrationFast - value: 1 - description: Aberration correction will not slow down the frame rate. - - name: ColorCorrectionAberrationHighQuality - value: 2 - description: | - High quality aberration correction which might reduce the frame - rate. - - - AeState: - type: int32_t - draft: true - description: | - Control to report the current AE algorithm state. Currently identical to - ANDROID_CONTROL_AE_STATE. - - Current state of the AE algorithm. - enum: - - name: AeStateInactive - value: 0 - description: The AE algorithm is inactive. - - name: AeStateSearching - value: 1 - description: The AE algorithm has not converged yet. - - name: AeStateConverged - value: 2 - description: The AE algorithm has converged. - - name: AeStateLocked - value: 3 - description: The AE algorithm is locked. - - name: AeStateFlashRequired - value: 4 - description: The AE algorithm would need a flash for good results - - name: AeStatePrecapture - value: 5 - description: | - The AE algorithm has started a pre-capture metering session. - \sa AePrecaptureTrigger - - - AwbState: - type: int32_t - draft: true - description: | - Control to report the current AWB algorithm state. Currently identical - to ANDROID_CONTROL_AWB_STATE. - - Current state of the AWB algorithm. - enum: - - name: AwbStateInactive - value: 0 - description: The AWB algorithm is inactive. - - name: AwbStateSearching - value: 1 - description: The AWB algorithm has not converged yet. - - name: AwbConverged - value: 2 - description: The AWB algorithm has converged. - - name: AwbLocked - value: 3 - description: The AWB algorithm is locked. - - - SensorRollingShutterSkew: - type: int64_t - draft: true - description: | - Control to report the time between the start of exposure of the first - row and the start of exposure of the last row. Currently identical to - ANDROID_SENSOR_ROLLING_SHUTTER_SKEW - - - LensShadingMapMode: - type: int32_t - draft: true - description: | - Control to report if the lens shading map is available. Currently - identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE. - enum: - - name: LensShadingMapModeOff - value: 0 - description: No lens shading map mode is available. - - name: LensShadingMapModeOn - value: 1 - description: The lens shading map mode is available. - - - PipelineDepth: - type: int32_t - draft: true - description: | - Specifies the number of pipeline stages the frame went through from when - it was exposed to when the final completed result was available to the - framework. Always less than or equal to PipelineMaxDepth. Currently - identical to ANDROID_REQUEST_PIPELINE_DEPTH. - - The typical value for this control is 3 as a frame is first exposed, - captured and then processed in a single pass through the ISP. Any - additional processing step performed after the ISP pass (in example face - detection, additional format conversions etc) count as an additional - pipeline stage. - - - MaxLatency: - type: int32_t - draft: true - description: | - The maximum number of frames that can occur after a request (different - than the previous) has been submitted, and before the result's state - becomes synchronized. A value of -1 indicates unknown latency, and 0 - indicates per-frame control. Currently identical to - ANDROID_SYNC_MAX_LATENCY. - - - TestPatternMode: - type: int32_t - draft: true - description: | - Control to select the test pattern mode. Currently identical to - ANDROID_SENSOR_TEST_PATTERN_MODE. - enum: - - name: TestPatternModeOff - value: 0 - description: | - No test pattern mode is used. The camera device returns frames from - the image sensor. - - name: TestPatternModeSolidColor - value: 1 - description: | - Each pixel in [R, G_even, G_odd, B] is replaced by its respective - color channel provided in test pattern data. - \todo Add control for test pattern data. - - name: TestPatternModeColorBars - value: 2 - description: | - All pixel data is replaced with an 8-bar color pattern. The vertical - bars (left-to-right) are as follows; white, yellow, cyan, green, - magenta, red, blue and black. Each bar should take up 1/8 of the - sensor pixel array width. When this is not possible, the bar size - should be rounded down to the nearest integer and the pattern can - repeat on the right side. Each bar's height must always take up the - full sensor pixel array height. - - name: TestPatternModeColorBarsFadeToGray - value: 3 - description: | - The test pattern is similar to TestPatternModeColorBars, - except that each bar should start at its specified color at the top - and fade to gray at the bottom. Furthermore each bar is further - subdevided into a left and right half. The left half should have a - smooth gradient, and the right half should have a quantized - gradient. In particular, the right half's should consist of blocks - of the same color for 1/16th active sensor pixel array width. The - least significant bits in the quantized gradient should be copied - from the most significant bits of the smooth gradient. The height of - each bar should always be a multiple of 128. When this is not the - case, the pattern should repeat at the bottom of the image. - - name: TestPatternModePn9 - value: 4 - description: | - All pixel data is replaced by a pseudo-random sequence generated - from a PN9 512-bit sequence (typically implemented in hardware with - a linear feedback shift register). The generator should be reset at - the beginning of each frame, and thus each subsequent raw frame with - this test pattern should be exactly the same as the last. - - name: TestPatternModeCustom1 - value: 256 - description: | - The first custom test pattern. All custom patterns that are - available only on this camera device are at least this numeric - value. All of the custom test patterns will be static (that is the - raw image must not vary from frame to frame). - ... diff --git a/src/libcamera/control_ids_draft.yaml b/src/libcamera/control_ids_draft.yaml new file mode 100644 index 000000000000..9bef5bf15238 --- /dev/null +++ b/src/libcamera/control_ids_draft.yaml @@ -0,0 +1,230 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# Copyright (C) 2019, Google Inc. +# +%YAML 1.1 +--- +# Unless otherwise stated, all controls are bi-directional, i.e. they can be +# set through Request::controls() and returned out through Request::metadata(). +vendor: draft +controls: + - AePrecaptureTrigger: + type: int32_t + description: | + Control for AE metering trigger. Currently identical to + ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER. + + Whether the camera device will trigger a precapture metering sequence + when it processes this request. + enum: + - name: AePrecaptureTriggerIdle + value: 0 + description: The trigger is idle. + - name: AePrecaptureTriggerStart + value: 1 + description: The pre-capture AE metering is started by the camera. + - name: AePrecaptureTriggerCancel + value: 2 + description: | + The camera will cancel any active or completed metering sequence. + The AE algorithm is reset to its initial state. + + - NoiseReductionMode: + type: int32_t + description: | + Control to select the noise reduction algorithm mode. Currently + identical to ANDROID_NOISE_REDUCTION_MODE. + + Mode of operation for the noise reduction algorithm. + enum: + - name: NoiseReductionModeOff + value: 0 + description: No noise reduction is applied + - name: NoiseReductionModeFast + value: 1 + description: | + Noise reduction is applied without reducing the frame rate. + - name: NoiseReductionModeHighQuality + value: 2 + description: | + High quality noise reduction at the expense of frame rate. + - name: NoiseReductionModeMinimal + value: 3 + description: | + Minimal noise reduction is applied without reducing the frame rate. + - name: NoiseReductionModeZSL + value: 4 + description: | + Noise reduction is applied at different levels to different streams. + + - ColorCorrectionAberrationMode: + type: int32_t + description: | + Control to select the color correction aberration mode. Currently + identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE. + + Mode of operation for the chromatic aberration correction algorithm. + enum: + - name: ColorCorrectionAberrationOff + value: 0 + description: No aberration correction is applied. + - name: ColorCorrectionAberrationFast + value: 1 + description: Aberration correction will not slow down the frame rate. + - name: ColorCorrectionAberrationHighQuality + value: 2 + description: | + High quality aberration correction which might reduce the frame + rate. + + - AeState: + type: int32_t + description: | + Control to report the current AE algorithm state. Currently identical to + ANDROID_CONTROL_AE_STATE. + + Current state of the AE algorithm. + enum: + - name: AeStateInactive + value: 0 + description: The AE algorithm is inactive. + - name: AeStateSearching + value: 1 + description: The AE algorithm has not converged yet. + - name: AeStateConverged + value: 2 + description: The AE algorithm has converged. + - name: AeStateLocked + value: 3 + description: The AE algorithm is locked. + - name: AeStateFlashRequired + value: 4 + description: The AE algorithm would need a flash for good results + - name: AeStatePrecapture + value: 5 + description: | + The AE algorithm has started a pre-capture metering session. + \sa AePrecaptureTrigger + + - AwbState: + type: int32_t + description: | + Control to report the current AWB algorithm state. Currently identical + to ANDROID_CONTROL_AWB_STATE. + + Current state of the AWB algorithm. + enum: + - name: AwbStateInactive + value: 0 + description: The AWB algorithm is inactive. + - name: AwbStateSearching + value: 1 + description: The AWB algorithm has not converged yet. + - name: AwbConverged + value: 2 + description: The AWB algorithm has converged. + - name: AwbLocked + value: 3 + description: The AWB algorithm is locked. + + - SensorRollingShutterSkew: + type: int64_t + description: | + Control to report the time between the start of exposure of the first + row and the start of exposure of the last row. Currently identical to + ANDROID_SENSOR_ROLLING_SHUTTER_SKEW + + - LensShadingMapMode: + type: int32_t + description: | + Control to report if the lens shading map is available. Currently + identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE. + enum: + - name: LensShadingMapModeOff + value: 0 + description: No lens shading map mode is available. + - name: LensShadingMapModeOn + value: 1 + description: The lens shading map mode is available. + + - PipelineDepth: + type: int32_t + description: | + Specifies the number of pipeline stages the frame went through from when + it was exposed to when the final completed result was available to the + framework. Always less than or equal to PipelineMaxDepth. Currently + identical to ANDROID_REQUEST_PIPELINE_DEPTH. + + The typical value for this control is 3 as a frame is first exposed, + captured and then processed in a single pass through the ISP. Any + additional processing step performed after the ISP pass (in example face + detection, additional format conversions etc) count as an additional + pipeline stage. + + - MaxLatency: + type: int32_t + description: | + The maximum number of frames that can occur after a request (different + than the previous) has been submitted, and before the result's state + becomes synchronized. A value of -1 indicates unknown latency, and 0 + indicates per-frame control. Currently identical to + ANDROID_SYNC_MAX_LATENCY. + + - TestPatternMode: + type: int32_t + description: | + Control to select the test pattern mode. Currently identical to + ANDROID_SENSOR_TEST_PATTERN_MODE. + enum: + - name: TestPatternModeOff + value: 0 + description: | + No test pattern mode is used. The camera device returns frames from + the image sensor. + - name: TestPatternModeSolidColor + value: 1 + description: | + Each pixel in [R, G_even, G_odd, B] is replaced by its respective + color channel provided in test pattern data. + \todo Add control for test pattern data. + - name: TestPatternModeColorBars + value: 2 + description: | + All pixel data is replaced with an 8-bar color pattern. The vertical + bars (left-to-right) are as follows; white, yellow, cyan, green, + magenta, red, blue and black. Each bar should take up 1/8 of the + sensor pixel array width. When this is not possible, the bar size + should be rounded down to the nearest integer and the pattern can + repeat on the right side. Each bar's height must always take up the + full sensor pixel array height. + - name: TestPatternModeColorBarsFadeToGray + value: 3 + description: | + The test pattern is similar to TestPatternModeColorBars, + except that each bar should start at its specified color at the top + and fade to gray at the bottom. Furthermore each bar is further + subdevided into a left and right half. The left half should have a + smooth gradient, and the right half should have a quantized + gradient. In particular, the right half's should consist of blocks + of the same color for 1/16th active sensor pixel array width. The + least significant bits in the quantized gradient should be copied + from the most significant bits of the smooth gradient. The height of + each bar should always be a multiple of 128. When this is not the + case, the pattern should repeat at the bottom of the image. + - name: TestPatternModePn9 + value: 4 + description: | + All pixel data is replaced by a pseudo-random sequence generated + from a PN9 512-bit sequence (typically implemented in hardware with + a linear feedback shift register). The generator should be reset at + the beginning of each frame, and thus each subsequent raw frame with + this test pattern should be exactly the same as the last. + - name: TestPatternModeCustom1 + value: 256 + description: | + The first custom test pattern. All custom patterns that are + available only on this camera device are at least this numeric + value. All of the custom test patterns will be static (that is the + raw image must not vary from frame to frame). + +... diff --git a/src/libcamera/property_ids.cpp.in b/src/libcamera/property_ids.cpp.in index eed1124f3eb7..8b274c38c74b 100644 --- a/src/libcamera/property_ids.cpp.in +++ b/src/libcamera/property_ids.cpp.in @@ -23,15 +23,6 @@ namespace properties { ${controls_doc} -/** - * \brief Namespace for libcamera draft properties - */ -namespace draft { - -${draft_controls_doc} - -} /* namespace draft */ - ${vendor_controls_doc} #ifndef __DOXYGEN__ @@ -41,12 +32,6 @@ ${vendor_controls_doc} */ ${controls_def} -namespace draft { - -${draft_controls_def} - -} /* namespace draft */ - ${vendor_controls_def} #endif diff --git a/src/libcamera/property_ids_core.yaml b/src/libcamera/property_ids_core.yaml index 45f3609b4236..834454a4e087 100644 --- a/src/libcamera/property_ids_core.yaml +++ b/src/libcamera/property_ids_core.yaml @@ -701,37 +701,4 @@ controls: Different cameras may report identical devices. - # ---------------------------------------------------------------------------- - # Draft properties section - - - ColorFilterArrangement: - type: int32_t - draft: true - description: | - The arrangement of color filters on sensor; represents the colors in the - top-left 2x2 section of the sensor, in reading order. Currently - identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT. - enum: - - name: RGGB - value: 0 - description: RGGB Bayer pattern - - name: GRBG - value: 1 - description: GRBG Bayer pattern - - name: GBRG - value: 2 - description: GBRG Bayer pattern - - name: BGGR - value: 3 - description: BGGR Bayer pattern - - name: RGB - value: 4 - description: | - Sensor is not Bayer; output has 3 16-bit values for each pixel, - instead of just 1 16-bit value per pixel. - - name: MONO - value: 5 - description: | - Sensor is not Bayer; output consists of a single colour channel. - ... diff --git a/src/libcamera/property_ids_draft.yaml b/src/libcamera/property_ids_draft.yaml new file mode 100644 index 000000000000..62f0e242d0c6 --- /dev/null +++ b/src/libcamera/property_ids_draft.yaml @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# Copyright (C) 2019, Google Inc. +# +%YAML 1.1 +--- +vendor: draft +controls: + - ColorFilterArrangement: + type: int32_t + vendor: draft + description: | + The arrangement of color filters on sensor; represents the colors in the + top-left 2x2 section of the sensor, in reading order. Currently + identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT. + enum: + - name: RGGB + value: 0 + description: RGGB Bayer pattern + - name: GRBG + value: 1 + description: GRBG Bayer pattern + - name: GBRG + value: 2 + description: GBRG Bayer pattern + - name: BGGR + value: 3 + description: BGGR Bayer pattern + - name: RGB + value: 4 + description: | + Sensor is not Bayer; output has 3 16-bit values for each pixel, + instead of just 1 16-bit value per pixel. + - name: MONO + value: 5 + description: | + Sensor is not Bayer; output consists of a single colour channel. + +... diff --git a/src/py/libcamera/gen-py-controls.py b/src/py/libcamera/gen-py-controls.py index 8ae8d5126e39..8efbf95b9433 100755 --- a/src/py/libcamera/gen-py-controls.py +++ b/src/py/libcamera/gen-py-controls.py @@ -32,14 +32,12 @@ def generate_py(controls, mode): name, ctrl = ctrls.popitem() if vendor not in vendors and vendor != 'libcamera': - vendors_class_def.append('class Py{}Controls\n{{\n}};\n'.format(vendor)) - vendor_defs.append('\tauto {} = py::class_(controls, \"{}\");'.format(vendor, vendor, vendor)) + vendor_mode_str = f'{vendor.capitalize()}{mode.capitalize()}' + vendors_class_def.append('class Py{}\n{{\n}};\n'.format(vendor_mode_str)) + vendor_defs.append('\tauto {} = py::class_(controls, \"{}\");'.format(vendor, vendor_mode_str, vendor)) vendors.append(vendor) - if ctrl.get('draft'): - ns = 'libcamera::{}::draft::'.format(mode) - container = 'draft' - elif vendor != 'libcamera': + if vendor != 'libcamera': ns = 'libcamera::{}::{}::'.format(mode, vendor) container = vendor else: diff --git a/src/py/libcamera/py_controls_generated.cpp.in b/src/py/libcamera/py_controls_generated.cpp.in index ec4b55ef2011..8d282ce51856 100644 --- a/src/py/libcamera/py_controls_generated.cpp.in +++ b/src/py/libcamera/py_controls_generated.cpp.in @@ -17,16 +17,11 @@ class PyControls { }; -class PyDraftControls -{ -}; - ${vendors_class_def} void init_py_controls_generated(py::module& m) { auto controls = py::class_(m, "controls"); - auto draft = py::class_(controls, "draft"); ${vendors_defs} ${controls} diff --git a/src/py/libcamera/py_properties_generated.cpp.in b/src/py/libcamera/py_properties_generated.cpp.in index f7b5ec8c635d..e3802b81a075 100644 --- a/src/py/libcamera/py_properties_generated.cpp.in +++ b/src/py/libcamera/py_properties_generated.cpp.in @@ -17,16 +17,11 @@ class PyProperties { }; -class PyDraftProperties -{ -}; - ${vendors_class_def} void init_py_properties_generated(py::module& m) { auto controls = py::class_(m, "properties"); - auto draft = py::class_(controls, "draft"); ${vendors_defs} ${controls} diff --git a/utils/gen-controls.py b/utils/gen-controls.py index 8e592148af3d..6cd5e362c66f 100755 --- a/utils/gen-controls.py +++ b/utils/gen-controls.py @@ -86,11 +86,6 @@ class Control(object): """Is the control an enumeration""" return self.__enum_values is not None - @property - def is_draft(self): - """Is the control a draft control""" - return self.__data.get('draft') is not None - @property def vendor(self): """The vendor string, or None""" @@ -101,12 +96,6 @@ class Control(object): """The control name (CamelCase)""" return self.__name - @property - def q_name(self): - """The control name, qualified with a namespace""" - ns = 'draft::' if self.is_draft else '' - return ns + self.__name - @property def type(self): typ = self.__data.get('type') @@ -159,7 +148,7 @@ ${description} for ctrl in controls: id_name = snake_case(ctrl.name).upper() - vendor = 'draft' if ctrl.is_draft else ctrl.vendor + vendor = ctrl.vendor if vendor not in ctrls_doc: ctrls_doc[vendor] = [] ctrls_def[vendor] = [] @@ -208,7 +197,8 @@ ${description} target_doc.append(doc_template.substitute(info)) target_def.append(def_template.substitute(info)) - ctrls_map.append('\t{ ' + id_name + ', &' + ctrl.q_name + ' },') + vendor_ns = vendor + '::' if vendor != "libcamera" else '' + ctrls_map.append('\t{ ' + vendor_ns + id_name + ', &' + vendor_ns + ctrl.name + ' },') vendor_ctrl_doc_sub = [] vendor_ctrl_template = string.Template(''' @@ -221,18 +211,16 @@ ${vendor_controls_str} } /* namespace ${vendor} */''') - for vendor in [v for v in ctrls_doc.keys() if v not in ['libcamera', 'draft']]: + for vendor in [v for v in ctrls_doc.keys() if v not in ['libcamera']]: vendor_ctrl_doc_sub.append(vendor_ctrl_template.substitute({'vendor': vendor, 'vendor_controls_str': '\n\n'.join(ctrls_doc[vendor])})) vendor_ctrl_def_sub = [] - for vendor in [v for v in ctrls_def.keys() if v not in ['libcamera', 'draft']]: + for vendor in [v for v in ctrls_def.keys() if v not in ['libcamera']]: vendor_ctrl_def_sub.append(vendor_ctrl_template.substitute({'vendor': vendor, 'vendor_controls_str': '\n'.join(ctrls_def[vendor])})) return { 'controls_doc': '\n\n'.join(ctrls_doc['libcamera']), 'controls_def': '\n'.join(ctrls_def['libcamera']), - 'draft_controls_doc': '\n\n'.join(ctrls_doc['draft']), - 'draft_controls_def': '\n\n'.join(ctrls_def['draft']), 'controls_map': '\n'.join(ctrls_map), 'vendor_controls_doc': '\n'.join(vendor_ctrl_doc_sub), 'vendor_controls_def': '\n'.join(vendor_ctrl_def_sub), @@ -252,7 +240,7 @@ def generate_h(controls, mode, ranges): for ctrl in controls: id_name = snake_case(ctrl.name).upper() - vendor = 'draft' if ctrl.is_draft else ctrl.vendor + vendor = ctrl.vendor if vendor not in ctrls: if vendor not in ranges.keys(): raise RuntimeError(f'Control id range is not defined for vendor {vendor}') @@ -260,8 +248,7 @@ def generate_h(controls, mode, ranges): ids[vendor] = [] ctrls[vendor] = [] - # Core and draft controls use the same ID value - target_ids = ids['libcamera'] if vendor in ['libcamera', 'draft'] else ids[vendor] + target_ids = ids[vendor] target_ids.append('\t' + id_name + ' = ' + str(id_value[vendor]) + ',') info = { @@ -269,11 +256,7 @@ def generate_h(controls, mode, ranges): 'type': ctrl.type, } - target_ctrls = ctrls['libcamera'] - if ctrl.is_draft: - target_ctrls = ctrls['draft'] - elif vendor != 'libcamera': - target_ctrls = ctrls[vendor] + target_ctrls = ctrls[vendor] if ctrl.is_enum: target_ctrls.append(enum_template_start.substitute(info)) @@ -312,7 +295,7 @@ ${vendor_controls} ''') vendor_sub = [] - for vendor in [v for v in ctrls.keys() if v not in ['libcamera', 'draft']]: + for vendor in [v for v in ctrls.keys() if v != 'libcamera']: vendor_sub.append(vendor_template.substitute({'mode': mode.upper(), 'vendor': vendor, 'vendor_def': vendor.upper(), @@ -322,7 +305,6 @@ ${vendor_controls} return { 'ids': '\n'.join(ids['libcamera']), 'controls': '\n'.join(ctrls['libcamera']), - 'draft_controls': '\n'.join(ctrls['draft']), 'vendor_controls': '\n'.join(vendor_sub) } From patchwork Thu Nov 30 14:25:34 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 19254 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 1DA3EC32BC for ; Thu, 30 Nov 2023 14:25:51 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C5037629DF; Thu, 30 Nov 2023 15:25:50 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1701354350; bh=aYEL16EU4f1meZaubhLC/2GV16YruyYUTEjQrOaXxfA=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=pBapQ6ijXWapbLET7srysUUHw6++kE/83FOlvhsR9GfCNK4VDF3qfvV0LH3OOLmS4 CZHe1SQyLcFf1FjDy1JykboQs0aMYYjvdeXnXSjlH6x7uEawc5CTsKglg8lNXuoU6k EbMpLaO2gxJnUh9IUu9yFlk5LCVyjko12MeVhmevHdjop6dRffix8mIe3ParZOHxJx jY0md3KspU4KEyzDVrFgdLN2nCrPYO0jB+5/mP//zi6WXtbs5Ne4EosqPU3k2SCBGe A65w1875D9CkEG7/Ibm8sJFNk90d4b9hyIY17F78W0d6qGsbgp/kvYcw0S60pWhzer RyQ5hcYeLMhVg== Received: from mail-ej1-x62a.google.com (mail-ej1-x62a.google.com [IPv6:2a00:1450:4864:20::62a]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 03A04629D8 for ; Thu, 30 Nov 2023 15:25:47 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="I0iB4DvH"; dkim-atps=neutral Received: by mail-ej1-x62a.google.com with SMTP id a640c23a62f3a-a013d22effcso145617666b.2 for ; Thu, 30 Nov 2023 06:25:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1701354346; x=1701959146; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=WwhMFv7q7fH7OsEGATrEeBD17BE3B4zAPb96dSvEZdg=; b=I0iB4DvHT9cYKdwk8zEJ49AGCe/iKF63NoDd0+KF3xH+c1WwMQpuh3QtC4ptLf7WNT U/jjeGuBAAItjeqdABkJxKbP+cxTqHyjke+lBxVBOWfqlec5U/vnZ4TwaRIFSJbO5Jok Xi9s14g9aHUDd25sNWrDVukncAQBmhoL7c3O3SAt4yWTq6qVoXnr+2CfP0Yd5q+9U/AT aTuBthDTWC+3XCYcbJ8RJ61aTYCkz0rqGUFbNL/VinhvVYAM5/+rqUiY+cLzgHZImg1s 4HyyJbivqccSI5PzJjcFsMquxru9xD0hL22OEmuLf8fOkcHvCySd1+OVS6VUF/1jUNHL 5icw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1701354346; x=1701959146; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=WwhMFv7q7fH7OsEGATrEeBD17BE3B4zAPb96dSvEZdg=; b=eVtYeTg2elcC+Q522vGqe0xaCiRLMC2pEovSCsnCN1pWwJfFgT6EQkgBqK6SN9PCAc tuNJvL8ZXjS8eRbGxwzAeqBOK/bXSz5wfMBrvvvao41FYW8s7ci+Ya75rQ5FRlIHd+k1 wpWjXvpJudTt8BNJSFZ2NNyHCCLlj7JnmMfv3qkyUarpSLFwC1FpSmUXApa0he6W9AyU NJq/c7hahzWCJzi6Ee2KgrXM7/pvpYPXxOoSgKtwAZ4nksONDmE0dK8rBZIaKtjtZfz6 zwBp9tPUm4hJj9Mlk0CqtnUK7HveMroUnTqROOhbV7qGKrzEumrXOipikdSiR3sepCiG dg7A== X-Gm-Message-State: AOJu0Yy0qSCiybehWEdaoXJ9222nSXEv1wS7MhBTIq8xjdV/Myid93Yf m706nXNMN/HrC6YJ81JROLT6Xc6aasBTRQrf8iCJrA== X-Google-Smtp-Source: AGHT+IFlkPwSH52DXn5fq8LIqnBROsVa9Vkp4ZH+vKBVeZSMPcH917fA6biqlulbCNrFobuWFxPfqg== X-Received: by 2002:a17:906:2d7:b0:a14:d6e2:fb1f with SMTP id 23-20020a17090602d700b00a14d6e2fb1fmr6772295ejk.10.1701354346273; Thu, 30 Nov 2023 06:25:46 -0800 (PST) Received: from localhost.localdomain ([88.97.53.79]) by smtp.gmail.com with ESMTPSA id a5-20020a17090640c500b009e50ea0a05asm725577ejk.99.2023.11.30.06.25.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 30 Nov 2023 06:25:45 -0800 (PST) To: libcamera-devel@lists.libcamera.org Date: Thu, 30 Nov 2023 14:25:34 +0000 Message-Id: <20231130142534.2075-7-naush@raspberrypi.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231130142534.2075-1-naush@raspberrypi.com> References: <20231130142534.2075-1-naush@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 6/6] documentation: Document vendor specific controls and properties handling X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Naushir Patuck via libcamera-devel From: Naushir Patuck Reply-To: Naushir Patuck Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add some documentation to the pipeline handler file describing how to implement and handle vendor specific controls and properties with a small example. Signed-off-by: Naushir Patuck Reviewed-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- Documentation/guides/pipeline-handler.rst | 52 +++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/Documentation/guides/pipeline-handler.rst b/Documentation/guides/pipeline-handler.rst index 66d428a19c4f..26dc93589382 100644 --- a/Documentation/guides/pipeline-handler.rst +++ b/Documentation/guides/pipeline-handler.rst @@ -672,6 +672,58 @@ handling controls: #include #include +Vendor-specific controls and properties +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Vendor-specific controls and properties must be defined in a separate YAML file +and included in the build by defining the pipeline handler to file mapping in +include/libcamera/meson.build. These YAML files live in the src/libcamera +directory. + +For example, adding a Raspberry Pi vendor control file for the PiSP pipeline +handler is done with the following mapping: + +.. code-block:: meson + + controls_map = { + 'controls': { + 'draft': 'control_ids_draft.yaml', + 'libcamera': 'control_ids_core.yaml', + 'rpi/pisp': 'control_ids_rpi.yaml', + }, + + 'properties': { + 'draft': 'property_ids_draft.yaml', + 'libcamera': 'property_ids_core.yaml', + } + } + +The pipeline handler named above must match the pipeline handler option string +specified in the meson build configuration. + +Vendor-specific controls and properties must contain a `vendor: ` +tag in the YAML file. Every unique vendor tag must define a unique and +non-overlapping range of reserved control IDs in src/libcamera/control_ranges.yaml. + +For example, the following block defines a vendor-specific control with the +`rpi` vendor tag: + +.. code-block:: yaml + + vendor: rpi + controls: + - PispConfigDumpFile: + type: string + description: | + Triggers the Raspberry Pi PiSP pipeline handler to generate a JSON + formatted dump of the Backend configuration to the filename given by the + value of the control. + +The controls will be generated in the vendor-specific namespace +`libcamera::controls::rpi`. Additionally a `#define +LIBCAMERA_HAS_RPI_VENDOR_CONTROLS` will be available to allow applications to +test for the availability of these controls. + Generating a default configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~