py: gen-py-controls: Use Control class

Replace manual extraction of data from YAML with the Control helper
class. This centralizes YAML parsing and avoids manual mistakes.

In order to import the controls module, add the utils/codegen/ directory
to the PYTHONPATH through the Python build environment.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
This commit is contained in:
Laurent Pinchart 2024-08-08 02:16:19 +03:00
parent 6a96113107
commit 5c1cb5e5bc
3 changed files with 21 additions and 18 deletions

View file

@ -8,6 +8,8 @@ import string
import sys import sys
import yaml import yaml
from controls import Control
def find_common_prefix(strings): def find_common_prefix(strings):
prefix = strings[0] prefix = strings[0]
@ -28,9 +30,7 @@ def generate_py(controls, mode):
vendor_defs = [] vendor_defs = []
vendors = [] vendors = []
for vendor, ctrl_list in controls.items(): for vendor, ctrl_list in controls.items():
for ctrls in ctrl_list: for ctrl in ctrl_list:
name, ctrl = ctrls.popitem()
if vendor not in vendors and vendor != 'libcamera': if vendor not in vendors and vendor != 'libcamera':
vendor_mode_str = f'{vendor.capitalize()}{mode.capitalize()}' vendor_mode_str = f'{vendor.capitalize()}{mode.capitalize()}'
vendors_class_def.append('class Py{}\n{{\n}};\n'.format(vendor_mode_str)) vendors_class_def.append('class Py{}\n{{\n}};\n'.format(vendor_mode_str))
@ -44,29 +44,28 @@ def generate_py(controls, mode):
ns = 'libcamera::{}::'.format(mode) ns = 'libcamera::{}::'.format(mode)
container = 'controls' container = 'controls'
out += f'\t{container}.def_readonly_static("{name}", static_cast<const libcamera::ControlId *>(&{ns}{name}));\n\n' out += f'\t{container}.def_readonly_static("{ctrl.name}", static_cast<const libcamera::ControlId *>(&{ns}{ctrl.name}));\n\n'
enum = ctrl.get('enum') if not ctrl.is_enum:
if not enum:
continue continue
cpp_enum = name + 'Enum' cpp_enum = ctrl.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': if mode == 'controls':
# Adjustments for controls # Adjustments for controls
if name == 'LensShadingMapMode': if ctrl.name == 'LensShadingMapMode':
prefix = 'LensShadingMapMode' prefix = 'LensShadingMapMode'
else: else:
prefix = find_common_prefix([e['name'] for e in enum]) prefix = find_common_prefix([e.name for e in ctrl.enum_values])
else: else:
# Adjustments for properties # Adjustments for properties
prefix = find_common_prefix([e['name'] for e in enum]) prefix = find_common_prefix([e.name for e in ctrl.enum_values])
for entry in enum: for entry in ctrl.enum_values:
cpp_enum = entry['name'] cpp_enum = entry.name
py_enum = entry['name'][len(prefix):] 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)
@ -103,9 +102,10 @@ def main(argv):
controls = {} controls = {}
for input in args.input: for input in args.input:
data = open(input, 'rb').read() data = yaml.safe_load(open(input, 'rb').read())
vendor = yaml.safe_load(data)['vendor'] vendor = data['vendor']
controls[vendor] = yaml.safe_load(data)['controls'] ctrls = data['controls']
controls[vendor] = [Control(*ctrl.popitem(), vendor) for ctrl in ctrls]
data = generate_py(controls, args.mode) data = generate_py(controls, args.mode)

View file

@ -35,7 +35,8 @@ pycamera_sources += custom_target('py_gen_controls',
input : controls_files, input : controls_files,
output : ['py_controls_generated.cpp'], output : ['py_controls_generated.cpp'],
command : [gen_py_controls, '--mode', 'controls', '-o', '@OUTPUT@', command : [gen_py_controls, '--mode', 'controls', '-o', '@OUTPUT@',
'-t', gen_py_controls_template, '@INPUT@']) '-t', gen_py_controls_template, '@INPUT@'],
env : py_build_env)
# Generate properties # Generate properties
@ -45,7 +46,8 @@ pycamera_sources += custom_target('py_gen_properties',
input : properties_files, input : properties_files,
output : ['py_properties_generated.cpp'], output : ['py_properties_generated.cpp'],
command : [gen_py_controls, '--mode', 'properties', '-o', '@OUTPUT@', command : [gen_py_controls, '--mode', 'properties', '-o', '@OUTPUT@',
'-t', gen_py_properties_template, '@INPUT@']) '-t', gen_py_properties_template, '@INPUT@'],
env : py_build_env)
# Generate formats # Generate formats

View file

@ -5,6 +5,7 @@
py_build_env = environment() py_build_env = environment()
# \todo Investigate usage of PYTHONPYCACHEPREFIX for Python >= 3.8 # \todo Investigate usage of PYTHONPYCACHEPREFIX for Python >= 3.8
py_build_env.set('PYTHONDONTWRITEBYTECODE', '1') py_build_env.set('PYTHONDONTWRITEBYTECODE', '1')
py_build_env.prepend('PYTHONPATH', meson.current_source_dir())
py_modules += ['jinja2', 'yaml'] py_modules += ['jinja2', 'yaml']