diff options
author | Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> | 2022-05-27 17:44:29 +0300 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2022-05-27 22:03:34 +0300 |
commit | 3c82ae3821798794873be939bb46c507d4ebde7c (patch) | |
tree | 13ec729394b33b59a544bd3afee00ff9b674ab15 /src/py/libcamera/gen-py-controls.py | |
parent | 6eb1143e27d284200a672f957c8e5efbf87aafcc (diff) |
py: Re-implement controls geneneration
The Python bindings controls generation was not very good. It only
covered the enums and they were in the main namespace.
This adds the controls somewhat similarly to the C++ side. We will have
e.g.:
libcamera.controls.Brightness
libcamera.controls.AeMeteringModeEnum.CentreWeighted
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Diffstat (limited to 'src/py/libcamera/gen-py-controls.py')
-rwxr-xr-x | src/py/libcamera/gen-py-controls.py | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/src/py/libcamera/gen-py-controls.py b/src/py/libcamera/gen-py-controls.py new file mode 100755 index 00000000..4c072e60 --- /dev/null +++ b/src/py/libcamera/gen-py-controls.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Generate Python bindings controls from YAML + +import argparse +import string +import sys +import yaml + + +def find_common_prefix(strings): + prefix = strings[0] + + for string in strings[1:]: + while string[:len(prefix)] != prefix and prefix: + prefix = prefix[:len(prefix) - 1] + if not prefix: + break + + return prefix + + +def generate_py(controls): + out = '' + + for ctrl in controls: + name, ctrl = ctrl.popitem() + + if ctrl.get('draft'): + ns = 'libcamera::controls::draft::' + container = 'draft' + else: + ns = 'libcamera::controls::' + container = 'controls' + + out += f'\t{container}.def_readonly_static("{name}", static_cast<const libcamera::ControlId *>(&{ns}{name}));\n\n' + + enum = ctrl.get('enum') + if not enum: + continue + + cpp_enum = name + 'Enum' + + out += '\tpy::enum_<{}{}>({}, \"{}\")\n'.format(ns, cpp_enum, container, cpp_enum) + + if name == 'LensShadingMapMode': + prefix = 'LensShadingMapMode' + elif name == 'SceneFlicker': + # If we strip the prefix, we would get '50Hz', which is illegal name + prefix = '' + else: + prefix = find_common_prefix([e['name'] for e in enum]) + + 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;\n\n' + + return {'controls': out} + + +def fill_template(template, data): + template = open(template, 'rb').read() + template = template.decode('utf-8') + template = string.Template(template) + return template.substitute(data) + + +def main(argv): + # Parse command line arguments + parser = argparse.ArgumentParser() + parser.add_argument('-o', dest='output', 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() + controls = yaml.safe_load(data)['controls'] + + data = generate_py(controls) + + data = fill_template(args.template, data) + + if args.output: + output = open(args.output, 'wb') + output.write(data.encode('utf-8')) + output.close() + else: + sys.stdout.write(data) + + return 0 + + +if __name__ == '__main__': + sys.exit(main(sys.argv)) |