summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rwxr-xr-xutils/abi-compat.sh13
-rwxr-xr-xutils/checkstyle.py328
-rw-r--r--utils/codegen/controls.py142
-rwxr-xr-xutils/codegen/gen-controls.py109
-rwxr-xr-xutils/codegen/gen-formats.py (renamed from utils/gen-formats.py)0
-rwxr-xr-xutils/codegen/gen-gst-controls.py183
-rwxr-xr-xutils/codegen/gen-header.sh (renamed from utils/gen-header.sh)7
-rwxr-xr-xutils/codegen/gen-ipa-pub-key.py (renamed from utils/gen-ipa-pub-key.py)0
-rwxr-xr-xutils/codegen/gen-tp-header.py (renamed from utils/tracepoints/gen-tp-header.py)4
-rwxr-xr-xutils/codegen/ipc/extract-docs.py (renamed from utils/ipc/extract-docs.py)0
-rwxr-xr-xutils/codegen/ipc/generate.py (renamed from utils/ipc/generate.py)3
-rw-r--r--utils/codegen/ipc/generators/__init__.py (renamed from utils/ipc/generators/__init__.py)0
-rw-r--r--utils/codegen/ipc/generators/libcamera_templates/core_ipa_interface.h.tmpl (renamed from utils/ipc/generators/libcamera_templates/core_ipa_interface.h.tmpl)5
-rw-r--r--utils/codegen/ipc/generators/libcamera_templates/core_ipa_serializer.h.tmpl (renamed from utils/ipc/generators/libcamera_templates/core_ipa_serializer.h.tmpl)0
-rw-r--r--utils/codegen/ipc/generators/libcamera_templates/definition_functions.tmpl (renamed from utils/ipc/generators/libcamera_templates/definition_functions.tmpl)0
-rw-r--r--utils/codegen/ipc/generators/libcamera_templates/meson.build (renamed from utils/ipc/generators/libcamera_templates/meson.build)0
-rw-r--r--utils/codegen/ipc/generators/libcamera_templates/module_ipa_interface.h.tmpl (renamed from utils/ipc/generators/libcamera_templates/module_ipa_interface.h.tmpl)14
-rw-r--r--utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl (renamed from utils/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl)5
-rw-r--r--utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl (renamed from utils/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl)9
-rw-r--r--utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy_worker.cpp.tmpl (renamed from utils/ipc/generators/libcamera_templates/module_ipa_proxy_worker.cpp.tmpl)0
-rw-r--r--utils/codegen/ipc/generators/libcamera_templates/module_ipa_serializer.h.tmpl (renamed from utils/ipc/generators/libcamera_templates/module_ipa_serializer.h.tmpl)0
-rw-r--r--utils/codegen/ipc/generators/libcamera_templates/proxy_functions.tmpl (renamed from utils/ipc/generators/libcamera_templates/proxy_functions.tmpl)2
-rw-r--r--utils/codegen/ipc/generators/libcamera_templates/serializer.tmpl (renamed from utils/ipc/generators/libcamera_templates/serializer.tmpl)0
-rw-r--r--utils/codegen/ipc/generators/meson.build (renamed from utils/ipc/generators/meson.build)0
-rw-r--r--utils/codegen/ipc/generators/mojom_libcamera_generator.py (renamed from utils/ipc/generators/mojom_libcamera_generator.py)2
-rw-r--r--utils/codegen/ipc/meson.build (renamed from utils/ipc/meson.build)3
-rw-r--r--utils/codegen/ipc/mojo/README (renamed from utils/ipc/mojo/README)0
-rw-r--r--utils/codegen/ipc/mojo/public/LICENSE (renamed from utils/ipc/mojo/public/LICENSE)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/.style.yapf (renamed from utils/ipc/mojo/public/tools/.style.yapf)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/BUILD.gn (renamed from utils/ipc/mojo/public/tools/BUILD.gn)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/bindings/BUILD.gn (renamed from utils/ipc/mojo/public/tools/bindings/BUILD.gn)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/bindings/README.md (renamed from utils/ipc/mojo/public/tools/bindings/README.md)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/bindings/checks/__init__.py (renamed from utils/ipc/mojo/public/tools/bindings/checks/__init__.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/bindings/checks/mojom_attributes_check.py (renamed from utils/ipc/mojo/public/tools/bindings/checks/mojom_attributes_check.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/bindings/checks/mojom_attributes_check_unittest.py (renamed from utils/ipc/mojo/public/tools/bindings/checks/mojom_attributes_check_unittest.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/bindings/checks/mojom_definitions_check.py (renamed from utils/ipc/mojo/public/tools/bindings/checks/mojom_definitions_check.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/bindings/checks/mojom_interface_feature_check.py (renamed from utils/ipc/mojo/public/tools/bindings/checks/mojom_interface_feature_check.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/bindings/checks/mojom_interface_feature_check_unittest.py (renamed from utils/ipc/mojo/public/tools/bindings/checks/mojom_interface_feature_check_unittest.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/bindings/checks/mojom_restrictions_check.py (renamed from utils/ipc/mojo/public/tools/bindings/checks/mojom_restrictions_check.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/bindings/checks/mojom_restrictions_checks_unittest.py (renamed from utils/ipc/mojo/public/tools/bindings/checks/mojom_restrictions_checks_unittest.py)0
-rwxr-xr-xutils/codegen/ipc/mojo/public/tools/bindings/concatenate-files.py (renamed from utils/ipc/mojo/public/tools/bindings/concatenate-files.py)0
-rwxr-xr-xutils/codegen/ipc/mojo/public/tools/bindings/concatenate_and_replace_closure_exports.py (renamed from utils/ipc/mojo/public/tools/bindings/concatenate_and_replace_closure_exports.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/bindings/gen_data_files_list.py (renamed from utils/ipc/mojo/public/tools/bindings/gen_data_files_list.py)0
-rwxr-xr-xutils/codegen/ipc/mojo/public/tools/bindings/generate_type_mappings.py (renamed from utils/ipc/mojo/public/tools/bindings/generate_type_mappings.py)0
-rwxr-xr-xutils/codegen/ipc/mojo/public/tools/bindings/minify_with_terser.py (renamed from utils/ipc/mojo/public/tools/bindings/minify_with_terser.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/bindings/mojom.gni (renamed from utils/ipc/mojo/public/tools/bindings/mojom.gni)0
-rwxr-xr-xutils/codegen/ipc/mojo/public/tools/bindings/mojom_bindings_generator.py (renamed from utils/ipc/mojo/public/tools/bindings/mojom_bindings_generator.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py (renamed from utils/ipc/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py)0
-rwxr-xr-xutils/codegen/ipc/mojo/public/tools/bindings/validate_typemap_config.py (renamed from utils/ipc/mojo/public/tools/bindings/validate_typemap_config.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/BUILD.gn (renamed from utils/ipc/mojo/public/tools/mojom/BUILD.gn)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/README.md (renamed from utils/ipc/mojo/public/tools/mojom/README.md)0
-rwxr-xr-xutils/codegen/ipc/mojo/public/tools/mojom/check_stable_mojom_compatibility.py (renamed from utils/ipc/mojo/public/tools/mojom/check_stable_mojom_compatibility.py)0
-rwxr-xr-xutils/codegen/ipc/mojo/public/tools/mojom/check_stable_mojom_compatibility_unittest.py (renamed from utils/ipc/mojo/public/tools/mojom/check_stable_mojom_compatibility_unittest.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/const_unittest.py (renamed from utils/ipc/mojo/public/tools/mojom/const_unittest.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/enum_unittest.py (renamed from utils/ipc/mojo/public/tools/mojom/enum_unittest.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/feature_unittest.py (renamed from utils/ipc/mojo/public/tools/mojom/feature_unittest.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/BUILD.gn (renamed from utils/ipc/mojo/public/tools/mojom/mojom/BUILD.gn)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/__init__.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom/__init__.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/error.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom/error.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/fileutil.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom/fileutil.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/fileutil_unittest.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom/fileutil_unittest.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/__init__.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom/generate/__init__.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/check.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom/generate/check.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/generator.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom/generate/generator.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/generator_unittest.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom/generate/generator_unittest.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/module.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom/generate/module.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/module_unittest.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom/generate/module_unittest.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/pack.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom/generate/pack.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/pack_unittest.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom/generate/pack_unittest.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/template_expander.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom/generate/template_expander.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/translate.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom/generate/translate.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/translate_unittest.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom/generate/translate_unittest.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/__init__.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom/parse/__init__.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/ast.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom/parse/ast.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/ast_unittest.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom/parse/ast_unittest.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/conditional_features.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom/parse/conditional_features.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/conditional_features_unittest.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom/parse/conditional_features_unittest.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/lexer.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom/parse/lexer.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/lexer_unittest.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom/parse/lexer_unittest.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/parser.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom/parse/parser.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/parser_unittest.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom/parse/parser_unittest.py)0
-rwxr-xr-xutils/codegen/ipc/mojo/public/tools/mojom/mojom_parser.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom_parser.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom_parser_test_case.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom_parser_test_case.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/mojom_parser_unittest.py (renamed from utils/ipc/mojo/public/tools/mojom/mojom_parser_unittest.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/stable_attribute_unittest.py (renamed from utils/ipc/mojo/public/tools/mojom/stable_attribute_unittest.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/union_unittest.py (renamed from utils/ipc/mojo/public/tools/mojom/union_unittest.py)0
-rw-r--r--utils/codegen/ipc/mojo/public/tools/mojom/version_compatibility_unittest.py (renamed from utils/ipc/mojo/public/tools/mojom/version_compatibility_unittest.py)0
-rwxr-xr-xutils/codegen/ipc/mojo/public/tools/run_all_python_unittests.py (renamed from utils/ipc/mojo/public/tools/run_all_python_unittests.py)0
-rwxr-xr-xutils/codegen/ipc/parser.py (renamed from utils/ipc/parser.py)3
-rw-r--r--utils/codegen/ipc/tools/README (renamed from utils/ipc/tools/README)0
-rw-r--r--utils/codegen/ipc/tools/diagnosis/crbug_1001171.py (renamed from utils/ipc/tools/diagnosis/crbug_1001171.py)0
-rw-r--r--utils/codegen/meson.build19
-rwxr-xr-xutils/gen-controls.py389
-rwxr-xr-xutils/gen-debug-controls.py163
-rwxr-xr-xutils/hooks/pre-push11
-rw-r--r--utils/meson.build10
-rwxr-xr-xutils/rkisp1/gen-csc-table.py24
-rw-r--r--utils/tracepoints/meson.build5
-rw-r--r--utils/tuning/config-example.yaml44
-rw-r--r--utils/tuning/libtuning/ctt_awb.py58
-rw-r--r--utils/tuning/libtuning/image.py2
-rw-r--r--utils/tuning/libtuning/libtuning.py5
-rw-r--r--utils/tuning/libtuning/modules/agc/rkisp1.py4
-rw-r--r--utils/tuning/libtuning/modules/awb/__init__.py6
-rw-r--r--utils/tuning/libtuning/modules/awb/awb.py40
-rw-r--r--utils/tuning/libtuning/modules/awb/rkisp1.py36
-rw-r--r--utils/tuning/libtuning/modules/lux/__init__.py6
-rw-r--r--utils/tuning/libtuning/modules/lux/lux.py70
-rw-r--r--utils/tuning/libtuning/modules/lux/rkisp1.py22
-rwxr-xr-xutils/tuning/rkisp1.py26
-rwxr-xr-xutils/update-kernel-headers.sh2
111 files changed, 1096 insertions, 678 deletions
diff --git a/utils/abi-compat.sh b/utils/abi-compat.sh
index c936ac05..31f61e32 100755
--- a/utils/abi-compat.sh
+++ b/utils/abi-compat.sh
@@ -156,15 +156,16 @@ create_abi_dump() {
# Generate a minimal libcamera build. "lib" and "prefix" are
# defined explicitly to avoid system default ambiguities.
meson setup "$build" "$worktree" \
- -Dlibdir=lib \
- -Dprefix=/usr/local/ \
- -Ddocumentation=disabled \
-Dcam=disabled \
- -Dqcam=disabled \
+ -Ddocumentation=disabled \
-Dgstreamer=disabled \
-Dlc-compliance=disabled \
- -Dtracing=disabled \
- -Dpipelines=
+ -Dlibdir=lib \
+ -Dpipelines= \
+ -Dprefix=/usr/local/ \
+ -Dpycamera=disabled \
+ -Dqcam=disabled \
+ -Dtracing=disabled
ninja -C "$build"
DESTDIR="$install" ninja -C "$build" install
diff --git a/utils/checkstyle.py b/utils/checkstyle.py
index c9e41d41..f6229bbd 100755
--- a/utils/checkstyle.py
+++ b/utils/checkstyle.py
@@ -23,7 +23,6 @@ import subprocess
import sys
dependencies = {
- 'clang-format': True,
'git': True,
}
@@ -334,43 +333,79 @@ class Amendment(Commit):
class ClassRegistry(type):
def __new__(cls, clsname, bases, attrs):
newclass = super().__new__(cls, clsname, bases, attrs)
- if bases:
- bases[0].subclasses.append(newclass)
- bases[0].subclasses.sort(key=lambda x: getattr(x, 'priority', 0),
- reverse=True)
+ if bases and bases[0] != CheckerBase:
+ base = bases[0]
+
+ if not hasattr(base, 'subclasses'):
+ base.subclasses = []
+ base.subclasses.append(newclass)
+ base.subclasses.sort(key=lambda x: getattr(x, 'priority', 0),
+ reverse=True)
return newclass
-# ------------------------------------------------------------------------------
-# Commit Checkers
-#
+class CheckerBase(metaclass=ClassRegistry):
+ @classmethod
+ def instances(cls, obj, names):
+ for instance in cls.subclasses:
+ if names and instance.__name__ not in names:
+ continue
+ if instance.supports(obj):
+ yield instance
-class CommitChecker(metaclass=ClassRegistry):
- subclasses = []
+ @classmethod
+ def supports(cls, obj):
+ if hasattr(cls, 'commit_types'):
+ return type(obj) in cls.commit_types
- def __init__(self):
- pass
+ if hasattr(cls, 'patterns'):
+ for pattern in cls.patterns:
+ if fnmatch.fnmatch(os.path.basename(obj), pattern):
+ return True
+
+ return False
- #
- # Class methods
- #
@classmethod
- def checkers(cls, commit, names):
- for checker in cls.subclasses:
- if names and checker.__name__ not in names:
- continue
- if checker.supports(commit):
- yield checker
+ def all_patterns(cls):
+ patterns = set()
+ for instance in cls.subclasses:
+ if hasattr(instance, 'patterns'):
+ patterns.update(instance.patterns)
+
+ return patterns
@classmethod
- def supports(cls, commit):
- return type(commit) in cls.commit_types
+ def check_dependencies(cls):
+ if not hasattr(cls, 'dependencies'):
+ return []
+
+ issues = []
+
+ for command in cls.dependencies:
+ if command not in dependencies:
+ dependencies[command] = shutil.which(command)
+
+ if not dependencies[command]:
+ issues.append(CommitIssue(f'Missing {command} to run {cls.__name__}'))
+
+ return issues
+
+
+# ------------------------------------------------------------------------------
+# Commit Checkers
+#
+
+class CommitChecker(CheckerBase):
+ pass
class CommitIssue(object):
def __init__(self, msg):
self.msg = msg
+ def __str__(self):
+ return f'{Colours.fg(Colours.Yellow)}{self.msg}{Colours.reset()}'
+
class HeaderAddChecker(CommitChecker):
commit_types = (Commit, StagedChanges, Amendment)
@@ -561,37 +596,8 @@ class TrailersChecker(CommitChecker):
# Style Checkers
#
-class StyleChecker(metaclass=ClassRegistry):
- subclasses = []
-
- def __init__(self):
- pass
-
- #
- # Class methods
- #
- @classmethod
- def checkers(cls, filename, names):
- for checker in cls.subclasses:
- if names and checker.__name__ not in names:
- continue
- if checker.supports(filename):
- yield checker
-
- @classmethod
- def supports(cls, filename):
- for pattern in cls.patterns:
- if fnmatch.fnmatch(os.path.basename(filename), pattern):
- return True
- return False
-
- @classmethod
- def all_patterns(cls):
- patterns = set()
- for checker in cls.subclasses:
- patterns.update(checker.patterns)
-
- return patterns
+class StyleChecker(CheckerBase):
+ pass
class StyleIssue(object):
@@ -601,21 +607,36 @@ class StyleIssue(object):
self.line = line
self.msg = msg
+ def __str__(self):
+ s = []
+ s.append(f'{Colours.fg(Colours.Yellow)}#{self.line_number}: {self.msg}{Colours.reset()}')
+ if self.line is not None:
+ s.append(f'{Colours.fg(Colours.Yellow)}+{self.line.rstrip()}{Colours.reset()}')
+
+ if self.position is not None:
+ # Align the position marker by using the original line with
+ # all characters except for tabs replaced with spaces. This
+ # ensures proper alignment regardless of how the code is
+ # indented.
+ start = self.position[0]
+ prefix = ''.join([c if c == '\t' else ' ' for c in self.line[:start]])
+ length = self.position[1] - start - 1
+ s.append(f' {prefix}^{"~" * length}')
+
+ return '\n'.join(s)
+
class HexValueChecker(StyleChecker):
patterns = ('*.c', '*.cpp', '*.h')
regex = re.compile(r'\b0[xX][0-9a-fA-F]+\b')
- def __init__(self, content):
- super().__init__()
- self.__content = content
-
- def check(self, line_numbers):
+ @classmethod
+ def check(cls, content, line_numbers):
issues = []
for line_number in line_numbers:
- line = self.__content[line_number - 1]
+ line = content[line_number - 1]
match = HexValueChecker.regex.search(line)
if not match:
continue
@@ -639,15 +660,12 @@ class IncludeChecker(StyleChecker):
'cwchar', 'cwctype', 'math.h')
include_regex = re.compile(r'^#include <([a-z.]*)>')
- def __init__(self, content):
- super().__init__()
- self.__content = content
-
- def check(self, line_numbers):
+ @classmethod
+ def check(self, content, line_numbers):
issues = []
for line_number in line_numbers:
- line = self.__content[line_number - 1]
+ line = content[line_number - 1]
match = IncludeChecker.include_regex.match(line)
if not match:
continue
@@ -673,14 +691,11 @@ class LogCategoryChecker(StyleChecker):
log_regex = re.compile(r'\bLOG\((Debug|Info|Warning|Error|Fatal)\)')
patterns = ('*.cpp',)
- def __init__(self, content):
- super().__init__()
- self.__content = content
-
- def check(self, line_numbers):
+ @classmethod
+ def check(cls, content, line_numbers):
issues = []
for line_number in line_numbers:
- line = self.__content[line_number-1]
+ line = content[line_number - 1]
match = LogCategoryChecker.log_regex.search(line)
if not match:
continue
@@ -694,14 +709,11 @@ class LogCategoryChecker(StyleChecker):
class MesonChecker(StyleChecker):
patterns = ('meson.build',)
- def __init__(self, content):
- super().__init__()
- self.__content = content
-
- def check(self, line_numbers):
+ @classmethod
+ def check(cls, content, line_numbers):
issues = []
for line_number in line_numbers:
- line = self.__content[line_number-1]
+ line = content[line_number - 1]
pos = line.find('\t')
if pos != -1:
issues.append(StyleIssue(line_number, [pos, pos], line,
@@ -709,57 +721,18 @@ class MesonChecker(StyleChecker):
return issues
-class Pep8Checker(StyleChecker):
- patterns = ('*.py',)
- results_regex = re.compile(r'stdin:([0-9]+):([0-9]+)(.*)')
-
- def __init__(self, content):
- super().__init__()
- self.__content = content
-
- def check(self, line_numbers):
- issues = []
- data = ''.join(self.__content).encode('utf-8')
-
- try:
- ret = subprocess.run(['pycodestyle', '--ignore=E501', '-'],
- input=data, stdout=subprocess.PIPE)
- except FileNotFoundError:
- issues.append(StyleIssue(0, None, None, 'Please install pycodestyle to validate python additions'))
- return issues
-
- results = ret.stdout.decode('utf-8').splitlines()
- for item in results:
- search = re.search(Pep8Checker.results_regex, item)
- line_number = int(search.group(1))
- position = int(search.group(2))
- msg = search.group(3)
-
- if line_number in line_numbers:
- line = self.__content[line_number - 1]
- issues.append(StyleIssue(line_number, None, line, msg))
-
- return issues
-
-
class ShellChecker(StyleChecker):
+ dependencies = ('shellcheck',)
patterns = ('*.sh',)
results_line_regex = re.compile(r'In - line ([0-9]+):')
- def __init__(self, content):
- super().__init__()
- self.__content = content
-
- def check(self, line_numbers):
+ @classmethod
+ def check(cls, content, line_numbers):
issues = []
- data = ''.join(self.__content).encode('utf-8')
+ data = ''.join(content).encode('utf-8')
- try:
- ret = subprocess.run(['shellcheck', '-Cnever', '-'],
- input=data, stdout=subprocess.PIPE)
- except FileNotFoundError:
- issues.append(StyleIssue(0, None, None, 'Please install shellcheck to validate shell script additions'))
- return issues
+ ret = subprocess.run(['shellcheck', '-Cnever', '-'],
+ input=data, stdout=subprocess.PIPE)
results = ret.stdout.decode('utf-8').splitlines()
for nr, item in enumerate(results):
@@ -781,40 +754,12 @@ class ShellChecker(StyleChecker):
# Formatters
#
-class Formatter(metaclass=ClassRegistry):
- subclasses = []
-
- def __init__(self):
- pass
-
- #
- # Class methods
- #
- @classmethod
- def formatters(cls, filename, names):
- for formatter in cls.subclasses:
- if names and formatter.__name__ not in names:
- continue
- if formatter.supports(filename):
- yield formatter
-
- @classmethod
- def supports(cls, filename):
- for pattern in cls.patterns:
- if fnmatch.fnmatch(os.path.basename(filename), pattern):
- return True
- return False
-
- @classmethod
- def all_patterns(cls):
- patterns = set()
- for formatter in cls.subclasses:
- patterns.update(formatter.patterns)
-
- return patterns
+class Formatter(CheckerBase):
+ pass
class CLangFormatter(Formatter):
+ dependencies = ('clang-format',)
patterns = ('*.c', '*.cpp', '*.h')
priority = -1
@@ -943,6 +888,17 @@ class IncludeOrderFormatter(Formatter):
return '\n'.join(lines)
+class Pep8Formatter(Formatter):
+ dependencies = ('autopep8',)
+ patterns = ('*.py',)
+
+ @classmethod
+ def format(cls, filename, data):
+ ret = subprocess.run(['autopep8', '--ignore=E501', '-'],
+ input=data.encode('utf-8'), stdout=subprocess.PIPE)
+ return ret.stdout.decode('utf-8')
+
+
class StripTrailingSpaceFormatter(Formatter):
patterns = ('*.c', '*.cpp', '*.h', '*.py', 'meson.build')
@@ -958,6 +914,24 @@ class StripTrailingSpaceFormatter(Formatter):
# Style checking
#
+def check_commit(top_level, commit, checkers):
+ issues = []
+
+ # Apply the commit checkers first.
+ for checker in CommitChecker.instances(commit, checkers):
+ issues_ = checker.check_dependencies()
+ if issues_:
+ issues += issues_
+ continue
+
+ issues += checker.check(commit, top_level)
+
+ for issue in issues:
+ print(issue)
+
+ return len(issues)
+
+
def check_file(top_level, commit, filename, checkers):
# Extract the line numbers touched by the commit.
commit_diff = commit.get_diff(top_level, filename)
@@ -973,9 +947,15 @@ def check_file(top_level, commit, filename, checkers):
# Format the file after the commit with all formatters and compute the diff
# between the unformatted and formatted contents.
after = commit.get_file(filename)
+ issues = []
formatted = after
- for formatter in Formatter.formatters(filename, checkers):
+ for formatter in Formatter.instances(filename, checkers):
+ issues_ = formatter.check_dependencies()
+ if issues_:
+ issues += issues_
+ continue
+
formatted = formatter.format(filename, formatted)
after = after.splitlines(True)
@@ -988,11 +968,14 @@ def check_file(top_level, commit, filename, checkers):
formatted_diff = [hunk for hunk in formatted_diff if hunk.intersects(lines)]
# Check for code issues not related to formatting.
- issues = []
- for checker in StyleChecker.checkers(filename, checkers):
- checker = checker(after)
+ for checker in StyleChecker.instances(filename, checkers):
+ issues_ = checker.check_dependencies()
+ if issues_:
+ issues += issues_
+ continue
+
for hunk in commit_diff:
- issues += checker.check(hunk.side('to').touched)
+ issues += checker.check(after, hunk.side('to').touched)
# Print the detected issues.
if len(issues) == 0 and len(formatted_diff) == 0:
@@ -1006,23 +989,9 @@ def check_file(top_level, commit, filename, checkers):
print(hunk)
if len(issues):
- issues = sorted(issues, key=lambda i: i.line_number)
+ issues = sorted(issues, key=lambda i: getattr(i, 'line_number', -1))
for issue in issues:
- print('%s#%u: %s%s' % (Colours.fg(Colours.Yellow), issue.line_number,
- issue.msg, Colours.reset()))
- if issue.line is not None:
- print('%s+%s%s' % (Colours.fg(Colours.Yellow), issue.line.rstrip(),
- Colours.reset()))
-
- if issue.position is not None:
- # Align the position marker by using the original line with
- # all characters except for tabs replaced with spaces. This
- # ensures proper alignment regardless of how the code is
- # indented.
- start = issue.position[0]
- prefix = ''.join([c if c == '\t' else ' ' for c in issue.line[:start]])
- length = issue.position[1] - start - 1
- print(' ' + prefix + '^' + '~' * length)
+ print(issue)
return len(formatted_diff) + len(issues)
@@ -1034,13 +1003,8 @@ def check_style(top_level, commit, checkers):
print(title)
print(separator)
- issues = 0
-
# Apply the commit checkers first.
- for checker in CommitChecker.checkers(commit, checkers):
- for issue in checker.check(commit, top_level):
- print('%s%s%s' % (Colours.fg(Colours.Yellow), issue.msg, Colours.reset()))
- issues += 1
+ issues = check_commit(top_level, commit, checkers)
# Filter out files we have no checker for.
patterns = set()
@@ -1112,7 +1076,7 @@ def main(argv):
if args.checkers:
args.checkers = args.checkers.split(',')
- # Check for required dependencies.
+ # Check for required common dependencies.
for command, mandatory in dependencies.items():
found = shutil.which(command)
if mandatory and not found:
diff --git a/utils/codegen/controls.py b/utils/codegen/controls.py
new file mode 100644
index 00000000..e5161048
--- /dev/null
+++ b/utils/codegen/controls.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2019, Google Inc.
+#
+# Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+#
+# Helper classes to handle source code generation for libcamera controls
+
+
+class ControlEnum(object):
+ def __init__(self, data):
+ self.__data = data
+
+ @property
+ def description(self):
+ """The enum description"""
+ return self.__data.get('description')
+
+ @property
+ def name(self):
+ """The enum name"""
+ return self.__data.get('name')
+
+ @property
+ def value(self):
+ """The enum value"""
+ return self.__data.get('value')
+
+
+class Control(object):
+ def __init__(self, name, data, vendor, mode):
+ 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:
+ self.__enum_values = [ControlEnum(enum) for enum in enum_values]
+
+ size = self.__data.get('size')
+ if size is not None:
+ if len(size) == 0:
+ raise RuntimeError(f'Control `{self.__name}` size must have at least one dimension')
+
+ # Compute the total number of elements in the array. If any of the
+ # array dimension is a string, the array is variable-sized.
+ num_elems = 1
+ for dim in size:
+ if type(dim) is str:
+ num_elems = 0
+ break
+
+ dim = int(dim)
+ if dim <= 0:
+ raise RuntimeError(f'Control `{self.__name}` size must have positive values only')
+
+ num_elems *= dim
+
+ self.__size = num_elems
+
+ if mode == 'properties':
+ self.__direction = 'out'
+ else:
+ direction = self.__data.get('direction')
+ if direction is None:
+ raise RuntimeError(f'Control `{self.__name}` missing required field `direction`')
+ if direction not in ['in', 'out', 'inout']:
+ raise RuntimeError(f'Control `{self.__name}` direction `{direction}` is invalid; must be one of `in`, `out`, or `inout`')
+ self.__direction = direction
+
+ @property
+ def description(self):
+ """The control description"""
+ return self.__data.get('description')
+
+ @property
+ def enum_values(self):
+ """The enum values, if the control is an enumeration"""
+ if self.__enum_values is None:
+ return
+ for enum in self.__enum_values:
+ yield enum
+
+ @property
+ def enum_values_count(self):
+ """The number of enum values, if the control is an enumeration"""
+ if self.__enum_values is None:
+ return 0
+ return len(self.__enum_values)
+
+ @property
+ def is_enum(self):
+ """Is the control an enumeration"""
+ return self.__enum_values is not None
+
+ @property
+ def vendor(self):
+ """The vendor string, or None"""
+ return self.__vendor
+
+ @property
+ def name(self):
+ """The control name (CamelCase)"""
+ return self.__name
+
+ @property
+ def type(self):
+ typ = self.__data.get('type')
+ size = self.__data.get('size')
+
+ if typ == 'string':
+ return 'std::string'
+
+ if self.__size is None:
+ return typ
+
+ if self.__size:
+ return f"Span<const {typ}, {self.__size}>"
+ else:
+ return f"Span<const {typ}>"
+
+ @property
+ def direction(self):
+ in_flag = 'ControlId::Direction::In'
+ out_flag = 'ControlId::Direction::Out'
+
+ if self.__direction == 'inout':
+ return f'{in_flag} | {out_flag}'
+ if self.__direction == 'in':
+ return in_flag
+ if self.__direction == 'out':
+ return out_flag
+
+ @property
+ def element_type(self):
+ return self.__data.get('type')
+
+ @property
+ def size(self):
+ return self.__size
diff --git a/utils/codegen/gen-controls.py b/utils/codegen/gen-controls.py
new file mode 100755
index 00000000..59b716c1
--- /dev/null
+++ b/utils/codegen/gen-controls.py
@@ -0,0 +1,109 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2019, Google Inc.
+#
+# Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+#
+# Generate control definitions from YAML
+
+import argparse
+import jinja2
+import os
+import sys
+import yaml
+
+from controls import Control
+
+
+def snake_case(s):
+ return ''.join([c.isupper() and ('_' + c) or c for c in s]).strip('_')
+
+
+def format_description(description):
+ description = description.strip('\n').split('\n')
+ for i in range(1, len(description)):
+ line = description[i]
+ description[i] = (line and ' * ' or ' *') + line
+ return '\n'.join(description)
+
+
+def extend_control(ctrl, id, ranges):
+ ctrl.id = ranges[ctrl.vendor] + id + 1
+
+ if ctrl.vendor != 'libcamera':
+ ctrl.namespace = f'{ctrl.vendor}::'
+ else:
+ ctrl.namespace = ''
+
+ return ctrl
+
+
+def main(argv):
+
+ # Parse command line arguments
+ parser = argparse.ArgumentParser()
+ 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('--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='+',
+ help='Input file name.')
+
+ 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:
+ data = yaml.safe_load(open(input, 'rb').read())
+
+ vendor = data['vendor']
+ if vendor not in ranges.keys():
+ raise RuntimeError(f'Control id range is not defined for vendor {vendor}')
+
+ ctrls = controls.setdefault(vendor, [])
+
+ for i, ctrl in enumerate(data['controls']):
+ ctrl = Control(*ctrl.popitem(), vendor, args.mode)
+ ctrls.append(extend_control(ctrl, i, ranges))
+
+ # Sort the vendors by range numerical value
+ controls = [[vendor, ctrls] for vendor, ctrls in controls.items()]
+ controls.sort(key=lambda item: ranges[item[0]])
+
+ filename = {
+ 'controls': 'control_ids',
+ 'properties': 'property_ids',
+ }[args.mode]
+
+ data = {
+ 'filename': filename,
+ 'mode': args.mode,
+ 'controls': controls,
+ }
+
+ env = jinja2.Environment()
+ env.filters['format_description'] = format_description
+ env.filters['snake_case'] = snake_case
+ template = env.from_string(open(args.template, 'r', encoding='utf-8').read())
+ string = template.render(data)
+
+ if args.output:
+ output = open(args.output, 'w', encoding='utf-8')
+ output.write(string)
+ output.close()
+ else:
+ sys.stdout.write(string)
+
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
diff --git a/utils/gen-formats.py b/utils/codegen/gen-formats.py
index 0c0932a5..0c0932a5 100755
--- a/utils/gen-formats.py
+++ b/utils/codegen/gen-formats.py
diff --git a/utils/codegen/gen-gst-controls.py b/utils/codegen/gen-gst-controls.py
new file mode 100755
index 00000000..4ca76049
--- /dev/null
+++ b/utils/codegen/gen-gst-controls.py
@@ -0,0 +1,183 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2019, Google Inc.
+# Copyright (C) 2024, Jaslo Ziska
+#
+# Authors:
+# Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+# Jaslo Ziska <jaslo@ziska.de>
+#
+# Generate gstreamer control properties from YAML
+
+import argparse
+import jinja2
+import re
+import sys
+import yaml
+
+from controls import Control
+
+
+exposed_controls = [
+ 'AeEnable', 'AeMeteringMode', 'AeConstraintMode', 'AeExposureMode',
+ 'ExposureValue', 'ExposureTime', 'ExposureTimeMode',
+ 'AnalogueGain', 'AnalogueGainMode', 'AeFlickerPeriod',
+ 'Brightness', 'Contrast', 'AwbEnable', 'AwbMode', 'ColourGains',
+ 'Saturation', 'Sharpness', 'ColourCorrectionMatrix', 'ScalerCrop',
+ 'DigitalGain', 'AfMode', 'AfRange', 'AfSpeed', 'AfMetering', 'AfWindows',
+ 'LensPosition', 'Gamma',
+]
+
+
+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 format_description(description):
+ # Substitute doxygen keywords \sa (see also) and \todo
+ description = re.sub(r'\\sa((?: \w+)+)',
+ lambda match: 'See also: ' + ', '.join(
+ map(kebab_case, match.group(1).strip().split(' '))
+ ) + '.', description)
+ description = re.sub(r'\\todo', 'Todo:', description)
+
+ description = description.strip().split('\n')
+ return '\n'.join([
+ '"' + line.replace('\\', r'\\').replace('"', r'\"') + ' "' for line in description if line
+ ]).rstrip()
+
+
+# Custom filter to allow indenting by a string prior to Jinja version 3.0
+#
+# This function can be removed and the calls to indent_str() replaced by the
+# built-in indent() filter when dropping Jinja versions older than 3.0
+def indent_str(s, indention):
+ s += '\n'
+
+ lines = s.splitlines()
+ rv = lines.pop(0)
+
+ if lines:
+ rv += '\n' + '\n'.join(
+ indention + line if line else line for line in lines
+ )
+
+ return rv
+
+
+def snake_case(s):
+ return ''.join([
+ c.isupper() and ('_' + c.lower()) or c for c in s
+ ]).strip('_')
+
+
+def kebab_case(s):
+ return snake_case(s).replace('_', '-')
+
+
+def extend_control(ctrl):
+ if ctrl.vendor != 'libcamera':
+ ctrl.namespace = f'{ctrl.vendor}::'
+ ctrl.vendor_prefix = f'{ctrl.vendor}-'
+ else:
+ ctrl.namespace = ''
+ ctrl.vendor_prefix = ''
+
+ ctrl.is_array = ctrl.size is not None
+
+ if ctrl.is_enum:
+ # Remove common prefix from enum variant names
+ prefix = find_common_prefix([enum.name for enum in ctrl.enum_values])
+ for enum in ctrl.enum_values:
+ enum.gst_name = kebab_case(enum.name.removeprefix(prefix))
+
+ ctrl.gtype = 'enum'
+ ctrl.default = '0'
+ elif ctrl.element_type == 'bool':
+ ctrl.gtype = 'boolean'
+ ctrl.default = 'false'
+ elif ctrl.element_type == 'float':
+ ctrl.gtype = 'float'
+ ctrl.default = '0'
+ ctrl.min = '-G_MAXFLOAT'
+ ctrl.max = 'G_MAXFLOAT'
+ elif ctrl.element_type == 'int32_t':
+ ctrl.gtype = 'int'
+ ctrl.default = '0'
+ ctrl.min = 'G_MININT'
+ ctrl.max = 'G_MAXINT'
+ elif ctrl.element_type == 'int64_t':
+ ctrl.gtype = 'int64'
+ ctrl.default = '0'
+ ctrl.min = 'G_MININT64'
+ ctrl.max = 'G_MAXINT64'
+ elif ctrl.element_type == 'uint8_t':
+ ctrl.gtype = 'uchar'
+ ctrl.default = '0'
+ ctrl.min = '0'
+ ctrl.max = 'G_MAXUINT8'
+ elif ctrl.element_type == 'Rectangle':
+ ctrl.is_rectangle = True
+ ctrl.default = '0'
+ ctrl.min = '0'
+ ctrl.max = 'G_MAXINT'
+ else:
+ raise RuntimeError(f'The type `{ctrl.element_type}` is unknown')
+
+ return ctrl
+
+
+def main(argv):
+ # Parse command line arguments
+ parser = argparse.ArgumentParser()
+ 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, nargs='+',
+ help='Input file name.')
+
+ args = parser.parse_args(argv[1:])
+
+ controls = {}
+ for input in args.input:
+ data = yaml.safe_load(open(input, 'rb').read())
+
+ vendor = data['vendor']
+ ctrls = controls.setdefault(vendor, [])
+
+ for ctrl in data['controls']:
+ ctrl = Control(*ctrl.popitem(), vendor, mode='controls')
+
+ if ctrl.name in exposed_controls:
+ ctrls.append(extend_control(ctrl))
+
+ data = {'controls': list(controls.items())}
+
+ env = jinja2.Environment()
+ env.filters['format_description'] = format_description
+ env.filters['indent_str'] = indent_str
+ env.filters['snake_case'] = snake_case
+ env.filters['kebab_case'] = kebab_case
+ template = env.from_string(open(args.template, 'r', encoding='utf-8').read())
+ string = template.render(data)
+
+ if args.output:
+ with open(args.output, 'w', encoding='utf-8') as output:
+ output.write(string)
+ else:
+ sys.stdout.write(string)
+
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
diff --git a/utils/gen-header.sh b/utils/codegen/gen-header.sh
index d4692758..c78f0859 100755
--- a/utils/gen-header.sh
+++ b/utils/codegen/gen-header.sh
@@ -1,7 +1,7 @@
#!/bin/sh
-src_dir="$1"
-dst_file="$2"
+dst_file="$1"
+shift
cat <<EOF > "$dst_file"
/* SPDX-License-Identifier: LGPL-2.1-or-later */
@@ -16,9 +16,8 @@ cat <<EOF > "$dst_file"
EOF
-headers=$(for header in "$src_dir"/*.h "$src_dir"/*.h.in ; do
+headers=$(for header in "$@" ; do
header=$(basename "$header")
- header="${header%.in}"
echo "$header"
done | sort)
diff --git a/utils/gen-ipa-pub-key.py b/utils/codegen/gen-ipa-pub-key.py
index dc3e7d5f..dc3e7d5f 100755
--- a/utils/gen-ipa-pub-key.py
+++ b/utils/codegen/gen-ipa-pub-key.py
diff --git a/utils/tracepoints/gen-tp-header.py b/utils/codegen/gen-tp-header.py
index 83606c32..6769c7ce 100755
--- a/utils/tracepoints/gen-tp-header.py
+++ b/utils/codegen/gen-tp-header.py
@@ -6,7 +6,6 @@
#
# Generate header file to contain lttng tracepoints
-import datetime
import jinja2
import pathlib
import os
@@ -20,7 +19,6 @@ def main(argv):
output = argv[2]
template = argv[3]
- year = datetime.datetime.now().year
path = pathlib.Path(output).absolute().relative_to(argv[1])
source = ''
@@ -28,7 +26,7 @@ def main(argv):
source += open(fname, 'r', encoding='utf-8').read() + '\n\n'
template = jinja2.Template(open(template, 'r', encoding='utf-8').read())
- string = template.render(year=year, path=path, source=source)
+ string = template.render(path=path, source=source)
f = open(output, 'w', encoding='utf-8').write(string)
diff --git a/utils/ipc/extract-docs.py b/utils/codegen/ipc/extract-docs.py
index 61f44cae..61f44cae 100755
--- a/utils/ipc/extract-docs.py
+++ b/utils/codegen/ipc/extract-docs.py
diff --git a/utils/ipc/generate.py b/utils/codegen/ipc/generate.py
index c2b3fcb7..dfbe659b 100755
--- a/utils/ipc/generate.py
+++ b/utils/codegen/ipc/generate.py
@@ -9,9 +9,6 @@
import os
import sys
-# TODO set sys.pycache_prefix for >= python3.8
-sys.dont_write_bytecode = True
-
sys.path.insert(0, f'{os.path.dirname(__file__)}/mojo/public/tools/bindings')
import mojo.public.tools.bindings.mojom_bindings_generator as generator
diff --git a/utils/ipc/generators/__init__.py b/utils/codegen/ipc/generators/__init__.py
index e69de29b..e69de29b 100644
--- a/utils/ipc/generators/__init__.py
+++ b/utils/codegen/ipc/generators/__init__.py
diff --git a/utils/ipc/generators/libcamera_templates/core_ipa_interface.h.tmpl b/utils/codegen/ipc/generators/libcamera_templates/core_ipa_interface.h.tmpl
index 7f2d0810..3942e570 100644
--- a/utils/ipc/generators/libcamera_templates/core_ipa_interface.h.tmpl
+++ b/utils/codegen/ipc/generators/libcamera_templates/core_ipa_interface.h.tmpl
@@ -15,8 +15,13 @@
#pragma once
{% if has_map %}#include <map>{% endif %}
+{% if has_string %}#include <string>{% endif %}
{% if has_array %}#include <vector>{% endif %}
+#include <libcamera/controls.h>
+#include <libcamera/framebuffer.h>
+#include <libcamera/geometry.h>
+
#include <libcamera/ipa/ipa_interface.h>
namespace libcamera {
diff --git a/utils/ipc/generators/libcamera_templates/core_ipa_serializer.h.tmpl b/utils/codegen/ipc/generators/libcamera_templates/core_ipa_serializer.h.tmpl
index 036518f6..036518f6 100644
--- a/utils/ipc/generators/libcamera_templates/core_ipa_serializer.h.tmpl
+++ b/utils/codegen/ipc/generators/libcamera_templates/core_ipa_serializer.h.tmpl
diff --git a/utils/ipc/generators/libcamera_templates/definition_functions.tmpl b/utils/codegen/ipc/generators/libcamera_templates/definition_functions.tmpl
index 8b8509f3..8b8509f3 100644
--- a/utils/ipc/generators/libcamera_templates/definition_functions.tmpl
+++ b/utils/codegen/ipc/generators/libcamera_templates/definition_functions.tmpl
diff --git a/utils/ipc/generators/libcamera_templates/meson.build b/utils/codegen/ipc/generators/libcamera_templates/meson.build
index 70664eab..70664eab 100644
--- a/utils/ipc/generators/libcamera_templates/meson.build
+++ b/utils/codegen/ipc/generators/libcamera_templates/meson.build
diff --git a/utils/ipc/generators/libcamera_templates/module_ipa_interface.h.tmpl b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_interface.h.tmpl
index 4d88a3d7..5d70ea6a 100644
--- a/utils/ipc/generators/libcamera_templates/module_ipa_interface.h.tmpl
+++ b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_interface.h.tmpl
@@ -14,12 +14,20 @@
#pragma once
-#include <libcamera/ipa/core_ipa_interface.h>
-#include <libcamera/ipa/ipa_interface.h>
-
{% if has_map %}#include <map>{% endif %}
+{% if has_string %}#include <string>{% endif %}
{% if has_array %}#include <vector>{% endif %}
+#include <libcamera/base/flags.h>
+#include <libcamera/base/signal.h>
+
+#include <libcamera/controls.h>
+#include <libcamera/framebuffer.h>
+#include <libcamera/geometry.h>
+
+#include <libcamera/ipa/core_ipa_interface.h>
+#include <libcamera/ipa/ipa_interface.h>
+
namespace libcamera {
{%- if has_namespace %}
{% for ns in namespace %}
diff --git a/utils/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl
index ce3cc5ab..07165821 100644
--- a/utils/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl
+++ b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.cpp.tmpl
@@ -239,10 +239,7 @@ void {{proxy_name}}::{{method.mojom_name}}IPC(
[[maybe_unused]] size_t dataSize,
[[maybe_unused]] const std::vector<SharedFD> &fds)
{
-{%- for param in method.parameters %}
- {{param|name}} {{param.mojom_name}};
-{%- endfor %}
-{{proxy_funcs.deserialize_call(method.parameters, 'data', 'fds', false, false, true, 'dataSize')}}
+{{proxy_funcs.deserialize_call(method.parameters, 'data', 'fds', false, true, true, 'dataSize')}}
{{method.mojom_name}}.emit({{method.parameters|params_comma_sep}});
}
{% endfor %}
diff --git a/utils/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl
index e213b18a..a0312a7c 100644
--- a/utils/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl
+++ b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy.h.tmpl
@@ -44,15 +44,6 @@ public:
{{proxy_funcs.func_sig(proxy_name, method, "", false, true)|indent(8, true)}};
{% endfor %}
-{%- for method in interface_event.methods %}
- Signal<
-{%- for param in method.parameters -%}
- {{"const " if not param|is_pod}}{{param|name}}{{" &" if not param|is_pod and not param|is_enum}}
- {{- ", " if not loop.last}}
-{%- endfor -%}
-> {{method.mojom_name}};
-{% endfor %}
-
private:
void recvMessage(const IPCMessage &data);
diff --git a/utils/ipc/generators/libcamera_templates/module_ipa_proxy_worker.cpp.tmpl b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy_worker.cpp.tmpl
index 1f990d3f..1f990d3f 100644
--- a/utils/ipc/generators/libcamera_templates/module_ipa_proxy_worker.cpp.tmpl
+++ b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_proxy_worker.cpp.tmpl
diff --git a/utils/ipc/generators/libcamera_templates/module_ipa_serializer.h.tmpl b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_serializer.h.tmpl
index cd5a65a9..cd5a65a9 100644
--- a/utils/ipc/generators/libcamera_templates/module_ipa_serializer.h.tmpl
+++ b/utils/codegen/ipc/generators/libcamera_templates/module_ipa_serializer.h.tmpl
diff --git a/utils/ipc/generators/libcamera_templates/proxy_functions.tmpl b/utils/codegen/ipc/generators/libcamera_templates/proxy_functions.tmpl
index b5797b14..25476990 100644
--- a/utils/ipc/generators/libcamera_templates/proxy_functions.tmpl
+++ b/utils/codegen/ipc/generators/libcamera_templates/proxy_functions.tmpl
@@ -34,7 +34,7 @@
thread_.exit();
thread_.wait();
- Thread::current()->dispatchMessages(Message::Type::InvokeMessage);
+ Thread::current()->dispatchMessages(Message::Type::InvokeMessage, this);
state_ = ProxyStopped;
{%- endmacro -%}
diff --git a/utils/ipc/generators/libcamera_templates/serializer.tmpl b/utils/codegen/ipc/generators/libcamera_templates/serializer.tmpl
index 323e1293..323e1293 100644
--- a/utils/ipc/generators/libcamera_templates/serializer.tmpl
+++ b/utils/codegen/ipc/generators/libcamera_templates/serializer.tmpl
diff --git a/utils/ipc/generators/meson.build b/utils/codegen/ipc/generators/meson.build
index 504f1a46..504f1a46 100644
--- a/utils/ipc/generators/meson.build
+++ b/utils/codegen/ipc/generators/meson.build
diff --git a/utils/ipc/generators/mojom_libcamera_generator.py b/utils/codegen/ipc/generators/mojom_libcamera_generator.py
index b8209e51..d9c620a0 100644
--- a/utils/ipc/generators/mojom_libcamera_generator.py
+++ b/utils/codegen/ipc/generators/mojom_libcamera_generator.py
@@ -467,6 +467,7 @@ class Generator(generator.Generator):
'enums': self.module.enums,
'has_array': len([x for x in self.module.kinds.keys() if x[0] == 'a']) > 0,
'has_map': len([x for x in self.module.kinds.keys() if x[0] == 'm']) > 0,
+ 'has_string': len([x for x in self.module.kinds.keys() if x[0] == 's']) > 0,
'has_namespace': self.module.mojom_namespace != '',
'interface_event': GetEventInterface(self.module.interfaces),
'interface_main': GetMainInterface(self.module.interfaces),
@@ -486,6 +487,7 @@ class Generator(generator.Generator):
'enums_gen_header': [x for x in self.module.enums if x.attributes is None or 'skipHeader' not in x.attributes],
'has_array': len([x for x in self.module.kinds.keys() if x[0] == 'a']) > 0,
'has_map': len([x for x in self.module.kinds.keys() if x[0] == 'm']) > 0,
+ 'has_string': len([x for x in self.module.kinds.keys() if x[0] == 's']) > 0,
'structs_gen_header': [x for x in self.module.structs if x.attributes is None or 'skipHeader' not in x.attributes],
'structs_gen_serializer': [x for x in self.module.structs if x.attributes is None or 'skipSerdes' not in x.attributes],
}
diff --git a/utils/ipc/meson.build b/utils/codegen/ipc/meson.build
index 973a5417..f77bf324 100644
--- a/utils/ipc/meson.build
+++ b/utils/codegen/ipc/meson.build
@@ -13,6 +13,7 @@ mojom_docs_extractor = find_program('./extract-docs.py')
mojom_templates = custom_target('mojom_templates',
input : mojom_template_files,
output : 'libcamera_templates.zip',
- command : [mojom_generator, '-o', '@OUTDIR@', 'precompile'])
+ command : [mojom_generator, '-o', '@OUTDIR@', 'precompile'],
+ env : py_build_env)
mojom_templates_dir = meson.current_build_dir()
diff --git a/utils/ipc/mojo/README b/utils/codegen/ipc/mojo/README
index 961cabd2..961cabd2 100644
--- a/utils/ipc/mojo/README
+++ b/utils/codegen/ipc/mojo/README
diff --git a/utils/ipc/mojo/public/LICENSE b/utils/codegen/ipc/mojo/public/LICENSE
index 513e8a6a..513e8a6a 100644
--- a/utils/ipc/mojo/public/LICENSE
+++ b/utils/codegen/ipc/mojo/public/LICENSE
diff --git a/utils/ipc/mojo/public/tools/.style.yapf b/utils/codegen/ipc/mojo/public/tools/.style.yapf
index b4ebbe24..b4ebbe24 100644
--- a/utils/ipc/mojo/public/tools/.style.yapf
+++ b/utils/codegen/ipc/mojo/public/tools/.style.yapf
diff --git a/utils/ipc/mojo/public/tools/BUILD.gn b/utils/codegen/ipc/mojo/public/tools/BUILD.gn
index 5328a34a..5328a34a 100644
--- a/utils/ipc/mojo/public/tools/BUILD.gn
+++ b/utils/codegen/ipc/mojo/public/tools/BUILD.gn
diff --git a/utils/ipc/mojo/public/tools/bindings/BUILD.gn b/utils/codegen/ipc/mojo/public/tools/bindings/BUILD.gn
index eeca73ea..eeca73ea 100644
--- a/utils/ipc/mojo/public/tools/bindings/BUILD.gn
+++ b/utils/codegen/ipc/mojo/public/tools/bindings/BUILD.gn
diff --git a/utils/ipc/mojo/public/tools/bindings/README.md b/utils/codegen/ipc/mojo/public/tools/bindings/README.md
index b27b2d01..b27b2d01 100644
--- a/utils/ipc/mojo/public/tools/bindings/README.md
+++ b/utils/codegen/ipc/mojo/public/tools/bindings/README.md
diff --git a/utils/ipc/mojo/public/tools/bindings/checks/__init__.py b/utils/codegen/ipc/mojo/public/tools/bindings/checks/__init__.py
index e69de29b..e69de29b 100644
--- a/utils/ipc/mojo/public/tools/bindings/checks/__init__.py
+++ b/utils/codegen/ipc/mojo/public/tools/bindings/checks/__init__.py
diff --git a/utils/ipc/mojo/public/tools/bindings/checks/mojom_attributes_check.py b/utils/codegen/ipc/mojo/public/tools/bindings/checks/mojom_attributes_check.py
index e6e4f2c9..e6e4f2c9 100644
--- a/utils/ipc/mojo/public/tools/bindings/checks/mojom_attributes_check.py
+++ b/utils/codegen/ipc/mojo/public/tools/bindings/checks/mojom_attributes_check.py
diff --git a/utils/ipc/mojo/public/tools/bindings/checks/mojom_attributes_check_unittest.py b/utils/codegen/ipc/mojo/public/tools/bindings/checks/mojom_attributes_check_unittest.py
index f1a50a4a..f1a50a4a 100644
--- a/utils/ipc/mojo/public/tools/bindings/checks/mojom_attributes_check_unittest.py
+++ b/utils/codegen/ipc/mojo/public/tools/bindings/checks/mojom_attributes_check_unittest.py
diff --git a/utils/ipc/mojo/public/tools/bindings/checks/mojom_definitions_check.py b/utils/codegen/ipc/mojo/public/tools/bindings/checks/mojom_definitions_check.py
index 702d41c3..702d41c3 100644
--- a/utils/ipc/mojo/public/tools/bindings/checks/mojom_definitions_check.py
+++ b/utils/codegen/ipc/mojo/public/tools/bindings/checks/mojom_definitions_check.py
diff --git a/utils/ipc/mojo/public/tools/bindings/checks/mojom_interface_feature_check.py b/utils/codegen/ipc/mojo/public/tools/bindings/checks/mojom_interface_feature_check.py
index 07f51a64..07f51a64 100644
--- a/utils/ipc/mojo/public/tools/bindings/checks/mojom_interface_feature_check.py
+++ b/utils/codegen/ipc/mojo/public/tools/bindings/checks/mojom_interface_feature_check.py
diff --git a/utils/ipc/mojo/public/tools/bindings/checks/mojom_interface_feature_check_unittest.py b/utils/codegen/ipc/mojo/public/tools/bindings/checks/mojom_interface_feature_check_unittest.py
index e96152fd..e96152fd 100644
--- a/utils/ipc/mojo/public/tools/bindings/checks/mojom_interface_feature_check_unittest.py
+++ b/utils/codegen/ipc/mojo/public/tools/bindings/checks/mojom_interface_feature_check_unittest.py
diff --git a/utils/ipc/mojo/public/tools/bindings/checks/mojom_restrictions_check.py b/utils/codegen/ipc/mojo/public/tools/bindings/checks/mojom_restrictions_check.py
index d570e26c..d570e26c 100644
--- a/utils/ipc/mojo/public/tools/bindings/checks/mojom_restrictions_check.py
+++ b/utils/codegen/ipc/mojo/public/tools/bindings/checks/mojom_restrictions_check.py
diff --git a/utils/ipc/mojo/public/tools/bindings/checks/mojom_restrictions_checks_unittest.py b/utils/codegen/ipc/mojo/public/tools/bindings/checks/mojom_restrictions_checks_unittest.py
index a6cd71e2..a6cd71e2 100644
--- a/utils/ipc/mojo/public/tools/bindings/checks/mojom_restrictions_checks_unittest.py
+++ b/utils/codegen/ipc/mojo/public/tools/bindings/checks/mojom_restrictions_checks_unittest.py
diff --git a/utils/ipc/mojo/public/tools/bindings/concatenate-files.py b/utils/codegen/ipc/mojo/public/tools/bindings/concatenate-files.py
index 4dd26d4a..4dd26d4a 100755
--- a/utils/ipc/mojo/public/tools/bindings/concatenate-files.py
+++ b/utils/codegen/ipc/mojo/public/tools/bindings/concatenate-files.py
diff --git a/utils/ipc/mojo/public/tools/bindings/concatenate_and_replace_closure_exports.py b/utils/codegen/ipc/mojo/public/tools/bindings/concatenate_and_replace_closure_exports.py
index 7d56c9f9..7d56c9f9 100755
--- a/utils/ipc/mojo/public/tools/bindings/concatenate_and_replace_closure_exports.py
+++ b/utils/codegen/ipc/mojo/public/tools/bindings/concatenate_and_replace_closure_exports.py
diff --git a/utils/ipc/mojo/public/tools/bindings/gen_data_files_list.py b/utils/codegen/ipc/mojo/public/tools/bindings/gen_data_files_list.py
index c6daff03..c6daff03 100644
--- a/utils/ipc/mojo/public/tools/bindings/gen_data_files_list.py
+++ b/utils/codegen/ipc/mojo/public/tools/bindings/gen_data_files_list.py
diff --git a/utils/ipc/mojo/public/tools/bindings/generate_type_mappings.py b/utils/codegen/ipc/mojo/public/tools/bindings/generate_type_mappings.py
index 4a53e2bf..4a53e2bf 100755
--- a/utils/ipc/mojo/public/tools/bindings/generate_type_mappings.py
+++ b/utils/codegen/ipc/mojo/public/tools/bindings/generate_type_mappings.py
diff --git a/utils/ipc/mojo/public/tools/bindings/minify_with_terser.py b/utils/codegen/ipc/mojo/public/tools/bindings/minify_with_terser.py
index cefee7a4..cefee7a4 100755
--- a/utils/ipc/mojo/public/tools/bindings/minify_with_terser.py
+++ b/utils/codegen/ipc/mojo/public/tools/bindings/minify_with_terser.py
diff --git a/utils/ipc/mojo/public/tools/bindings/mojom.gni b/utils/codegen/ipc/mojo/public/tools/bindings/mojom.gni
index 3f6e54e0..3f6e54e0 100644
--- a/utils/ipc/mojo/public/tools/bindings/mojom.gni
+++ b/utils/codegen/ipc/mojo/public/tools/bindings/mojom.gni
diff --git a/utils/ipc/mojo/public/tools/bindings/mojom_bindings_generator.py b/utils/codegen/ipc/mojo/public/tools/bindings/mojom_bindings_generator.py
index 8c641c2a..8c641c2a 100755
--- a/utils/ipc/mojo/public/tools/bindings/mojom_bindings_generator.py
+++ b/utils/codegen/ipc/mojo/public/tools/bindings/mojom_bindings_generator.py
diff --git a/utils/ipc/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py b/utils/codegen/ipc/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py
index 761922b6..761922b6 100644
--- a/utils/ipc/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py
+++ b/utils/codegen/ipc/mojo/public/tools/bindings/mojom_bindings_generator_unittest.py
diff --git a/utils/ipc/mojo/public/tools/bindings/validate_typemap_config.py b/utils/codegen/ipc/mojo/public/tools/bindings/validate_typemap_config.py
index 6bb7a209..6bb7a209 100755
--- a/utils/ipc/mojo/public/tools/bindings/validate_typemap_config.py
+++ b/utils/codegen/ipc/mojo/public/tools/bindings/validate_typemap_config.py
diff --git a/utils/ipc/mojo/public/tools/mojom/BUILD.gn b/utils/codegen/ipc/mojo/public/tools/mojom/BUILD.gn
index eafb95a1..eafb95a1 100644
--- a/utils/ipc/mojo/public/tools/mojom/BUILD.gn
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/BUILD.gn
diff --git a/utils/ipc/mojo/public/tools/mojom/README.md b/utils/codegen/ipc/mojo/public/tools/mojom/README.md
index e5d17ab0..e5d17ab0 100644
--- a/utils/ipc/mojo/public/tools/mojom/README.md
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/README.md
diff --git a/utils/ipc/mojo/public/tools/mojom/check_stable_mojom_compatibility.py b/utils/codegen/ipc/mojo/public/tools/mojom/check_stable_mojom_compatibility.py
index 35cd1cfd..35cd1cfd 100755
--- a/utils/ipc/mojo/public/tools/mojom/check_stable_mojom_compatibility.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/check_stable_mojom_compatibility.py
diff --git a/utils/ipc/mojo/public/tools/mojom/check_stable_mojom_compatibility_unittest.py b/utils/codegen/ipc/mojo/public/tools/mojom/check_stable_mojom_compatibility_unittest.py
index 06769c95..06769c95 100755
--- a/utils/ipc/mojo/public/tools/mojom/check_stable_mojom_compatibility_unittest.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/check_stable_mojom_compatibility_unittest.py
diff --git a/utils/ipc/mojo/public/tools/mojom/const_unittest.py b/utils/codegen/ipc/mojo/public/tools/mojom/const_unittest.py
index e8ed36a7..e8ed36a7 100644
--- a/utils/ipc/mojo/public/tools/mojom/const_unittest.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/const_unittest.py
diff --git a/utils/ipc/mojo/public/tools/mojom/enum_unittest.py b/utils/codegen/ipc/mojo/public/tools/mojom/enum_unittest.py
index 9269cde5..9269cde5 100644
--- a/utils/ipc/mojo/public/tools/mojom/enum_unittest.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/enum_unittest.py
diff --git a/utils/ipc/mojo/public/tools/mojom/feature_unittest.py b/utils/codegen/ipc/mojo/public/tools/mojom/feature_unittest.py
index 5f014e1c..5f014e1c 100644
--- a/utils/ipc/mojo/public/tools/mojom/feature_unittest.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/feature_unittest.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/BUILD.gn b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/BUILD.gn
index a0edf0eb..a0edf0eb 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/BUILD.gn
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/BUILD.gn
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/__init__.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/__init__.py
index e69de29b..e69de29b 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/__init__.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/__init__.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/error.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/error.py
index dd53b835..dd53b835 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/error.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/error.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/fileutil.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/fileutil.py
index 124f12c1..124f12c1 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/fileutil.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/fileutil.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/fileutil_unittest.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/fileutil_unittest.py
index c93d2289..c93d2289 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/fileutil_unittest.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/fileutil_unittest.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/generate/__init__.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/__init__.py
index e69de29b..e69de29b 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/generate/__init__.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/__init__.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/generate/check.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/check.py
index 1efe2022..1efe2022 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/generate/check.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/check.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/generate/generator.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/generator.py
index 96fe3a2d..96fe3a2d 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/generate/generator.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/generator.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/generate/generator_unittest.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/generator_unittest.py
index 7143e07c..7143e07c 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/generate/generator_unittest.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/generator_unittest.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/generate/module.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/module.py
index ca71059d..ca71059d 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/generate/module.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/module.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/generate/module_unittest.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/module_unittest.py
index 2a4e852c..2a4e852c 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/generate/module_unittest.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/module_unittest.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/generate/pack.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/pack.py
index 61240426..61240426 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/generate/pack.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/pack.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/generate/pack_unittest.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/pack_unittest.py
index 7d8e4e01..7d8e4e01 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/generate/pack_unittest.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/pack_unittest.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/generate/template_expander.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/template_expander.py
index 807e2a4f..807e2a4f 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/generate/template_expander.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/template_expander.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/generate/translate.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/translate.py
index 83bb297f..83bb297f 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/generate/translate.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/translate.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/generate/translate_unittest.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/translate_unittest.py
index b4fea924..b4fea924 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/generate/translate_unittest.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/generate/translate_unittest.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/parse/__init__.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/__init__.py
index e69de29b..e69de29b 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/parse/__init__.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/__init__.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/parse/ast.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/ast.py
index aae9cdb6..aae9cdb6 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/parse/ast.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/ast.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/parse/ast_unittest.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/ast_unittest.py
index b289f7b1..b289f7b1 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/parse/ast_unittest.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/ast_unittest.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/parse/conditional_features.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/conditional_features.py
index 9687edbf..9687edbf 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/parse/conditional_features.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/conditional_features.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/parse/conditional_features_unittest.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/conditional_features_unittest.py
index cca1764b..cca1764b 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/parse/conditional_features_unittest.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/conditional_features_unittest.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/parse/lexer.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/lexer.py
index 00136a8b..00136a8b 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/parse/lexer.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/lexer.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/parse/lexer_unittest.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/lexer_unittest.py
index bc9f8354..bc9f8354 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/parse/lexer_unittest.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/lexer_unittest.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/parse/parser.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/parser.py
index 1dffd98b..1dffd98b 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/parse/parser.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/parser.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom/parse/parser_unittest.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/parser_unittest.py
index 0a26307b..0a26307b 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom/parse/parser_unittest.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom/parse/parser_unittest.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom_parser.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom_parser.py
index 9693090e..9693090e 100755
--- a/utils/ipc/mojo/public/tools/mojom/mojom_parser.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom_parser.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom_parser_test_case.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom_parser_test_case.py
index f0ee6966..f0ee6966 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom_parser_test_case.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom_parser_test_case.py
diff --git a/utils/ipc/mojo/public/tools/mojom/mojom_parser_unittest.py b/utils/codegen/ipc/mojo/public/tools/mojom/mojom_parser_unittest.py
index 353a2b6e..353a2b6e 100644
--- a/utils/ipc/mojo/public/tools/mojom/mojom_parser_unittest.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/mojom_parser_unittest.py
diff --git a/utils/ipc/mojo/public/tools/mojom/stable_attribute_unittest.py b/utils/codegen/ipc/mojo/public/tools/mojom/stable_attribute_unittest.py
index d10d69c6..d10d69c6 100644
--- a/utils/ipc/mojo/public/tools/mojom/stable_attribute_unittest.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/stable_attribute_unittest.py
diff --git a/utils/ipc/mojo/public/tools/mojom/union_unittest.py b/utils/codegen/ipc/mojo/public/tools/mojom/union_unittest.py
index 6b2525e5..6b2525e5 100644
--- a/utils/ipc/mojo/public/tools/mojom/union_unittest.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/union_unittest.py
diff --git a/utils/ipc/mojo/public/tools/mojom/version_compatibility_unittest.py b/utils/codegen/ipc/mojo/public/tools/mojom/version_compatibility_unittest.py
index 45e45ec5..45e45ec5 100644
--- a/utils/ipc/mojo/public/tools/mojom/version_compatibility_unittest.py
+++ b/utils/codegen/ipc/mojo/public/tools/mojom/version_compatibility_unittest.py
diff --git a/utils/ipc/mojo/public/tools/run_all_python_unittests.py b/utils/codegen/ipc/mojo/public/tools/run_all_python_unittests.py
index 98bce18c..98bce18c 100755
--- a/utils/ipc/mojo/public/tools/run_all_python_unittests.py
+++ b/utils/codegen/ipc/mojo/public/tools/run_all_python_unittests.py
diff --git a/utils/ipc/parser.py b/utils/codegen/ipc/parser.py
index cb5608b7..8e70322d 100755
--- a/utils/ipc/parser.py
+++ b/utils/codegen/ipc/parser.py
@@ -9,9 +9,6 @@
import os
import sys
-# TODO set sys.pycache_prefix for >= python3.8
-sys.dont_write_bytecode = True
-
# Make sure that mojom_parser.py can import mojom
sys.path.insert(0, f'{os.path.dirname(__file__)}/mojo/public/tools/mojom')
diff --git a/utils/ipc/tools/README b/utils/codegen/ipc/tools/README
index 961cabd2..961cabd2 100644
--- a/utils/ipc/tools/README
+++ b/utils/codegen/ipc/tools/README
diff --git a/utils/ipc/tools/diagnosis/crbug_1001171.py b/utils/codegen/ipc/tools/diagnosis/crbug_1001171.py
index 40900d10..40900d10 100644
--- a/utils/ipc/tools/diagnosis/crbug_1001171.py
+++ b/utils/codegen/ipc/tools/diagnosis/crbug_1001171.py
diff --git a/utils/codegen/meson.build b/utils/codegen/meson.build
new file mode 100644
index 00000000..904dd66d
--- /dev/null
+++ b/utils/codegen/meson.build
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: CC0-1.0
+
+## Code generation
+
+py_build_env = environment()
+# \todo Investigate usage of PYTHONPYCACHEPREFIX for Python >= 3.8
+py_build_env.set('PYTHONDONTWRITEBYTECODE', '1')
+py_build_env.prepend('PYTHONPATH', meson.current_source_dir())
+
+py_modules += ['jinja2', 'yaml']
+
+gen_controls = files('gen-controls.py')
+gen_formats = files('gen-formats.py')
+gen_gst_controls = files('gen-gst-controls.py')
+gen_header = files('gen-header.sh')
+gen_ipa_pub_key = files('gen-ipa-pub-key.py')
+gen_tracepoints = files('gen-tp-header.py')
+
+subdir('ipc')
diff --git a/utils/gen-controls.py b/utils/gen-controls.py
deleted file mode 100755
index 56315f50..00000000
--- a/utils/gen-controls.py
+++ /dev/null
@@ -1,389 +0,0 @@
-#!/usr/bin/env python3
-# SPDX-License-Identifier: GPL-2.0-or-later
-# Copyright (C) 2019, Google Inc.
-#
-# Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-#
-# Generate control definitions from YAML
-
-import argparse
-from functools import reduce
-import operator
-import string
-import sys
-import yaml
-import os
-
-
-class ControlEnum(object):
- def __init__(self, data):
- self.__data = data
-
- @property
- def description(self):
- """The enum description"""
- return self.__data.get('description')
-
- @property
- def name(self):
- """The enum name"""
- return self.__data.get('name')
-
- @property
- def value(self):
- """The enum value"""
- return self.__data.get('value')
-
-
-class Control(object):
- 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:
- self.__enum_values = [ControlEnum(enum) for enum in enum_values]
-
- size = self.__data.get('size')
- if size is not None:
- if len(size) == 0:
- raise RuntimeError(f'Control `{self.__name}` size must have at least one dimension')
-
- # Compute the total number of elements in the array. If any of the
- # array dimension is a string, the array is variable-sized.
- num_elems = 1
- for dim in size:
- if type(dim) is str:
- num_elems = 0
- break
-
- dim = int(dim)
- if dim <= 0:
- raise RuntimeError(f'Control `{self.__name}` size must have positive values only')
-
- num_elems *= dim
-
- self.__size = num_elems
-
- @property
- def description(self):
- """The control description"""
- return self.__data.get('description')
-
- @property
- def enum_values(self):
- """The enum values, if the control is an enumeration"""
- if self.__enum_values is None:
- return
- for enum in self.__enum_values:
- yield enum
-
- @property
- def is_enum(self):
- """Is the control an enumeration"""
- return self.__enum_values is not None
-
- @property
- def vendor(self):
- """The vendor string, or None"""
- return self.__vendor
-
- @property
- def name(self):
- """The control name (CamelCase)"""
- return self.__name
-
- @property
- def type(self):
- typ = self.__data.get('type')
- size = self.__data.get('size')
-
- if typ == 'string':
- return 'std::string'
-
- if self.__size is None:
- return typ
-
- if self.__size:
- return f"Span<const {typ}, {self.__size}>"
- else:
- return f"Span<const {typ}>"
-
-
-def snake_case(s):
- return ''.join([c.isupper() and ('_' + c) or c for c in s]).strip('_')
-
-
-def format_description(description):
- description = description.strip('\n').split('\n')
- description[0] = '\\brief ' + description[0]
- return '\n'.join([(line and ' * ' or ' *') + line for line in description])
-
-
-def generate_cpp(controls):
- enum_doc_start_template = string.Template('''/**
- * \\enum ${name}Enum
- * \\brief Supported ${name} values''')
- enum_doc_value_template = string.Template(''' * \\var ${value}
-${description}''')
- doc_template = string.Template('''/**
- * \\var ${name}
-${description}
- */''')
- def_template = string.Template('extern const Control<${type}> ${name}(${id_name}, "${name}");')
- enum_values_doc = string.Template('''/**
- * \\var ${name}Values
- * \\brief List of all $name supported values
- */''')
- enum_values_start = string.Template('''extern const std::array<const ControlValue, ${size}> ${name}Values = {''')
- enum_values_values = string.Template('''\tstatic_cast<int32_t>(${name}),''')
- name_value_map_doc = string.Template('''/**
- * \\var ${name}NameValueMap
- * \\brief Map of all $name supported value names (in std::string format) to value
- */''')
- name_value_map_start = string.Template('''extern const std::map<std::string, ${type}> ${name}NameValueMap = {''')
- name_value_values = string.Template('''\t{ "${name}", ${name} },''')
-
- ctrls_doc = {}
- ctrls_def = {}
- ctrls_map = []
-
- for ctrl in controls:
- id_name = snake_case(ctrl.name).upper()
-
- vendor = ctrl.vendor
- if vendor not in ctrls_doc:
- ctrls_doc[vendor] = []
- ctrls_def[vendor] = []
-
- info = {
- 'name': ctrl.name,
- 'type': ctrl.type,
- 'description': format_description(ctrl.description),
- 'id_name': id_name,
- }
-
- target_doc = ctrls_doc[vendor]
- target_def = ctrls_def[vendor]
-
- if ctrl.is_enum:
- enum_doc = []
- enum_doc.append(enum_doc_start_template.substitute(info))
-
- num_entries = 0
- for enum in ctrl.enum_values:
- value_info = {
- 'name': ctrl.name,
- 'value': enum.name,
- 'description': format_description(enum.description),
- }
- enum_doc.append(enum_doc_value_template.substitute(value_info))
- num_entries += 1
-
- enum_doc = '\n *\n'.join(enum_doc)
- enum_doc += '\n */'
- target_doc.append(enum_doc)
-
- values_info = {
- 'name': info['name'],
- 'type': ctrl.type,
- 'size': num_entries,
- }
- target_doc.append(enum_values_doc.substitute(values_info))
- target_def.append(enum_values_start.substitute(values_info))
- for enum in ctrl.enum_values:
- value_info = {
- 'name': enum.name
- }
- target_def.append(enum_values_values.substitute(value_info))
- target_def.append("};")
-
- target_doc.append(name_value_map_doc.substitute(values_info))
- target_def.append(name_value_map_start.substitute(values_info))
- for enum in ctrl.enum_values:
- value_info = {
- 'name': enum.name
- }
- target_def.append(name_value_values.substitute(value_info))
- target_def.append("};")
-
- target_doc.append(doc_template.substitute(info))
- target_def.append(def_template.substitute(info))
-
- 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('''
-/**
- * \\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']]:
- 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']]:
- 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']),
- '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, 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<const ControlValue, ${size}> ${name}Values;''')
- name_value_map_template = string.Template('''extern const std::map<std::string, ${type}> ${name}NameValueMap;''')
- template = string.Template('''extern const Control<${type}> ${name};''')
-
- ctrls = {}
- ids = {}
- id_value = {}
-
- for ctrl in controls:
- id_name = snake_case(ctrl.name).upper()
-
- 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}')
- id_value[vendor] = ranges[vendor] + 1
- ids[vendor] = []
- ctrls[vendor] = []
-
- target_ids = ids[vendor]
- target_ids.append('\t' + id_name + ' = ' + str(id_value[vendor]) + ',')
-
- info = {
- 'name': ctrl.name,
- 'type': ctrl.type,
- }
-
- target_ctrls = ctrls[vendor]
-
- if ctrl.is_enum:
- target_ctrls.append(enum_template_start.substitute(info))
-
- num_entries = 0
- for enum in ctrl.enum_values:
- value_info = {
- 'name': enum.name,
- 'value': enum.value,
- }
- target_ctrls.append(enum_value_template.substitute(value_info))
- num_entries += 1
- target_ctrls.append("};")
-
- values_info = {
- 'name': info['name'],
- 'type': ctrl.type,
- 'size': num_entries,
- }
- target_ctrls.append(enum_values_template.substitute(values_info))
- target_ctrls.append(name_value_map_template.substitute(values_info))
-
- target_ctrls.append(template.substitute(info))
- 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 != 'libcamera']:
- 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['libcamera']),
- 'controls': '\n'.join(ctrls['libcamera']),
- 'vendor_controls': '\n'.join(vendor_sub)
- }
-
-
-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('--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('--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='+',
- help='Input file name.')
-
- 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:
- 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)
- elif args.template.endswith('.h.in'):
- data = generate_h(controls, args.mode, ranges)
- else:
- raise RuntimeError('Unknown template type')
-
- 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))
diff --git a/utils/gen-debug-controls.py b/utils/gen-debug-controls.py
new file mode 100755
index 00000000..272597f4
--- /dev/null
+++ b/utils/gen-debug-controls.py
@@ -0,0 +1,163 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2024, Google Inc.
+#
+# Author: Stefan Klug <stefan.klug@ideasonboard.com>
+#
+# This script looks for occurrences of the debug metadata controls in the source
+# tree and updates src/libcamera/control_ids_debug.yaml accordingly. It is meant
+# to be used during development to ease updating of the yaml file while
+# debugging.
+
+import argparse
+import logging
+import os
+import re
+import sys
+from dataclasses import dataclass
+from pathlib import Path
+
+logger = logging.getLogger(__name__)
+logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')
+
+try:
+ import ruamel.yaml as ruyaml
+except:
+ logger.error(
+ f'Failed to import ruamel.yaml. Please install the ruamel.yaml package.')
+ sys.exit(1)
+
+@dataclass
+class FoundMatch:
+ file: os.PathLike
+ whole_match: str
+ line: int
+ type: str
+ name: str
+ size: str = None
+
+
+def get_control_name(control):
+ k = list(control.keys())
+ if len(k) != 1:
+ raise Exception(f"Can't handle control entry with {len(k)} keys")
+ return k[0]
+
+
+def find_debug_controls(dir):
+ extensions = ['.cpp', '.h']
+ files = [p for p in dir.rglob('*') if p.suffix in extensions]
+
+ # The following regex was tested on
+ # set<Span<type>>( controls::debug::something , static_cast<type>(var) )
+ # set<>( controls::debug::something , static_cast<type>(var) )
+ # set( controls::debug::something , static_cast<type> (var) )
+ exp = re.compile(r'set' # set function
+ r'(?:\<((?:[^)(])*)\>)?' # followed by a optional template param
+ r'\(\s*controls::debug::(\w+)\s*,' # referencing a debug control
+ )
+ matches = []
+ for p in files:
+ with p.open('r') as f:
+ for idx, line in enumerate(f):
+ match = exp.search(line)
+ if match:
+ m = FoundMatch(file=p, line=idx, type=match.group(1),
+ name=match.group(2), whole_match=match.group(0))
+ if m.type is not None and m.type.startswith('Span'):
+ # Simple span type detection treating the last word
+ # inside <> as type.
+ r = re.match(r'Span<(?:.*\s+)(.*)>', m.type)
+ m.type = r.group(1)
+ m.size = '[n]'
+ matches.append(m)
+ return matches
+
+
+def main(argv):
+ parser = argparse.ArgumentParser(
+ description='Automatically updates control_ids_debug.yaml')
+ parser.parse_args(argv[1:])
+
+ yaml = ruyaml.YAML()
+ root_dir = Path(__file__).resolve().parent.parent
+ ctrl_file = root_dir.joinpath('src/libcamera/control_ids_debug.yaml')
+
+ matches = find_debug_controls(root_dir.joinpath('src'))
+
+ doc = yaml.load(ctrl_file)
+
+ controls = doc['controls']
+
+ # Create a map of names in the existing yaml for easier updating.
+ controls_map = {}
+ for control in controls:
+ for k, v in control.items():
+ controls_map[k] = v
+
+ obsolete_names = list(controls_map.keys())
+
+ for m in matches:
+ if not m.type:
+ p = m.file.relative_to(Path.cwd(), walk_up=True)
+ logger.warning(
+ f'{p}:{m.line + 1}: Failed to deduce type from {m.whole_match} ... skipping')
+ continue
+
+ p = m.file.relative_to(root_dir)
+ desc = {'type': m.type,
+ 'direction': 'out',
+ 'description': f'Debug control {m.name} found in {p}:{m.line}'}
+ if m.size is not None:
+ desc['size'] = m.size
+
+ if m.name in controls_map:
+ # Can't use == for modified check because of the special yaml dicts.
+ update_needed = False
+ if list(controls_map[m.name].keys()) != list(desc.keys()):
+ update_needed = True
+ else:
+ for k, v in controls_map[m.name].items():
+ if v != desc[k]:
+ update_needed = True
+ break
+
+ if update_needed:
+ logger.info(f"Update control '{m.name}'")
+ controls_map[m.name].clear()
+ controls_map[m.name].update(desc)
+
+ obsolete_names.remove(m.name)
+ else:
+ logger.info(f"Add control '{m.name}'")
+ insert_before = len(controls)
+ for idx, control in enumerate(controls):
+ if get_control_name(control).lower() > m.name.lower():
+ insert_before = idx
+ break
+ controls.insert(insert_before, {m.name: desc})
+
+ # Remove elements from controls without recreating the list (to keep
+ # comments etc.).
+ idx = 0
+ while idx < len(controls):
+ name = get_control_name(controls[idx])
+ if name in obsolete_names:
+ logger.info(f"Remove control '{name}'")
+ controls.pop(idx)
+ else:
+ idx += 1
+
+ with ctrl_file.open('w') as f:
+ # Ruyaml looses the header.
+ f.write(("# SPDX-License-Identifier: LGPL-2.1-or-later\n"
+ "#\n"
+ "# This file was generated by utils/gen-debug-controls.py\n"
+ "#\n"))
+ yaml.dump(doc, f)
+
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
diff --git a/utils/hooks/pre-push b/utils/hooks/pre-push
index 9918b286..68dcbd0c 100755
--- a/utils/hooks/pre-push
+++ b/utils/hooks/pre-push
@@ -68,7 +68,7 @@ do
fi
# 2. The commit message shall have Signed-off-by lines
- # corresponding the committer and the author.
+ # corresponding the committer, author, and all co-developers.
committer=$(echo "$msg" | grep '^committer ' | head -1 | \
cut -d ' ' -f 2- | rev | cut -d ' ' -f 3- | rev)
if ! echo -E "$msg" | grep -F -q "Signed-off-by: ${committer}"
@@ -85,6 +85,15 @@ do
errors=$((errors+1))
fi
+ while read -r codev
+ do
+ if ! echo -E "$msg" | grep -F -q "Signed-off-by: ${codev}"
+ then
+ echo >&2 "Missing co-developer '${codev}' Signed-off-by in commit $commit"
+ errors=$((errors+1))
+ fi
+ done < <(echo "$msg" | grep '^Co-developed-by: ' | cut -d ' ' -f 2-)
+
# 3. A Reviewed-by or Acked-by is required.
if ! echo -E "$msg" | grep -q '^\(Reviewed\|Acked\)-by: '
then
diff --git a/utils/meson.build b/utils/meson.build
index 8e28ada7..95d657ac 100644
--- a/utils/meson.build
+++ b/utils/meson.build
@@ -1,15 +1,7 @@
# SPDX-License-Identifier: CC0-1.0
-subdir('ipc')
+subdir('codegen')
subdir('ipu3')
-subdir('tracepoints')
-
-## Code generation
-py_modules += ['yaml']
-gen_controls = files('gen-controls.py')
-gen_formats = files('gen-formats.py')
-gen_header = files('gen-header.sh')
## Module signing
gen_ipa_priv_key = files('gen-ipa-priv-key.sh')
-gen_ipa_pub_key = files('gen-ipa-pub-key.py')
diff --git a/utils/rkisp1/gen-csc-table.py b/utils/rkisp1/gen-csc-table.py
index ffc0370a..2db84feb 100755
--- a/utils/rkisp1/gen-csc-table.py
+++ b/utils/rkisp1/gen-csc-table.py
@@ -147,6 +147,8 @@ def main(argv):
description='Generate color space conversion table coefficients with '
'configurable fixed-point precision.'
)
+ parser.add_argument('--format', '-f', choices=['dec', 'hex'], default='hex',
+ help='Number format')
parser.add_argument('--invert', '-i', action='store_true',
help='Invert the color space conversion (YUV -> RGB)')
parser.add_argument('--precision', '-p', default='Q1.7',
@@ -190,19 +192,29 @@ def main(argv):
else:
line = round_array(line)
- # Convert coefficients to the number of bits selected by the precision.
- # Negative values will be turned into positive integers using 2's
- # complement.
- line = [coeff & ((1 << precision.total) - 1) for coeff in line]
+ if args.format == 'hex':
+ # Convert coefficients to the number of bits selected by the precision.
+ # Negative values will be turned into positive integers using 2's
+ # complement.
+ line = [coeff & ((1 << precision.total) - 1) for coeff in line]
+
rounded_coeffs.append(line)
# Print the result as C code.
nbits = 1 << (precision.total - 1).bit_length()
nbytes = nbits // 4
- print(f'static const u{nbits} {"yuv2rgb" if args.invert else "rgb2yuv"}_{args.encoding}_{quantization.name.lower()}_coeffs[] = {{')
+
+ if args.format == 'hex':
+ coeff_fmt = '0x{0:0' + str(nbytes) + 'x}'
+ sign = 'u'
+ else:
+ coeff_fmt = '{0}'
+ sign = 's'
+
+ print(f'static const {sign}{nbits} {"yuv2rgb" if args.invert else "rgb2yuv"}_{args.encoding}_{quantization.name.lower()}_coeffs[] = {{')
for line in rounded_coeffs:
- line = [f'0x{coeff:0{nbytes}x}' for coeff in line]
+ line = [coeff_fmt.format(coeff) for coeff in line]
print(f'\t{", ".join(line)},')
diff --git a/utils/tracepoints/meson.build b/utils/tracepoints/meson.build
deleted file mode 100644
index 807230fc..00000000
--- a/utils/tracepoints/meson.build
+++ /dev/null
@@ -1,5 +0,0 @@
-# SPDX-License-Identifier: CC0-1.0
-
-py_modules += ['jinja2']
-
-gen_tracepoints_header = find_program('./gen-tp-header.py')
diff --git a/utils/tuning/config-example.yaml b/utils/tuning/config-example.yaml
index 1b7f52cd..5593eaef 100644
--- a/utils/tuning/config-example.yaml
+++ b/utils/tuning/config-example.yaml
@@ -5,7 +5,49 @@ general:
do_alsc_colour: 1
luminance_strength: 0.5
awb:
- greyworld: 0
+ # Algorithm can either be 'grey' or 'bayes'
+ algorithm: bayes
+ # Priors is only used for the bayes algorithm. They are defined in linear
+ # space. A good staring point is:
+ # - lux: 0
+ # ct: [ 2000, 3000, 13000 ]
+ # probability: [ 1.005, 1.0, 1.0 ]
+ # - lux: 800
+ # ct: [ 2000, 6000, 13000 ]
+ # probability: [ 1.0, 1.01, 1.01 ]
+ # - lux: 1500
+ # ct: [ 2000, 4000, 6000, 6500, 7000, 13000 ]
+ # probability: [ 1.0, 1.005, 1.032, 1.037, 1.01, 1.01 ]
+ priors:
+ - lux: 0
+ ct: [ 2000, 13000 ]
+ probability: [ 1.0, 1.0 ]
+ AwbMode:
+ AwbAuto:
+ lo: 2500
+ hi: 8000
+ AwbIncandescent:
+ lo: 2500
+ hi: 3000
+ AwbTungsten:
+ lo: 3000
+ hi: 3500
+ AwbFluorescent:
+ lo: 4000
+ hi: 4700
+ AwbIndoor:
+ lo: 3000
+ hi: 5000
+ AwbDaylight:
+ lo: 5500
+ hi: 6500
+ AwbCloudy:
+ lo: 6500
+ hi: 8000
+ # One custom mode can be defined if needed
+ #AwbCustom:
+ # lo: 2000
+ # hi: 1300
macbeth:
small: 1
show: 0
diff --git a/utils/tuning/libtuning/ctt_awb.py b/utils/tuning/libtuning/ctt_awb.py
index abf22321..240f37e6 100644
--- a/utils/tuning/libtuning/ctt_awb.py
+++ b/utils/tuning/libtuning/ctt_awb.py
@@ -4,6 +4,8 @@
#
# camera tuning tool for AWB
+import logging
+
import matplotlib.pyplot as plt
from bisect import bisect_left
from scipy.optimize import fmin
@@ -11,12 +13,12 @@ import numpy as np
from .image import Image
+logger = logging.getLogger(__name__)
"""
obtain piecewise linear approximation for colour curve
"""
-def awb(Cam, cal_cr_list, cal_cb_list, plot):
- imgs = Cam.imgs
+def awb(imgs, cal_cr_list, cal_cb_list, plot):
"""
condense alsc calibration tables into one dictionary
"""
@@ -39,7 +41,7 @@ def awb(Cam, cal_cr_list, cal_cb_list, plot):
rb_raw = []
rbs_hat = []
for Img in imgs:
- Cam.log += '\nProcessing '+Img.name
+ logger.info(f'Processing {Img.name}')
"""
get greyscale patches with alsc applied if alsc enabled.
Note: if alsc is disabled then colour_cals will be set to None and the
@@ -51,7 +53,7 @@ def awb(Cam, cal_cr_list, cal_cb_list, plot):
"""
r_g = np.mean(r_patchs/g_patchs)
b_g = np.mean(b_patchs/g_patchs)
- Cam.log += '\n r : {:.4f} b : {:.4f}'.format(r_g, b_g)
+ logger.info(f' r : {r_g:.4f} b : {b_g:.4f}')
"""
The curve tends to be better behaved in so-called hatspace.
R, B, G represent the individual channels. The colour curve is plotted in
@@ -74,12 +76,11 @@ def awb(Cam, cal_cr_list, cal_cb_list, plot):
"""
r_g_hat = r_g/(1+r_g+b_g)
b_g_hat = b_g/(1+r_g+b_g)
- Cam.log += '\n r_hat : {:.4f} b_hat : {:.4f}'.format(r_g_hat, b_g_hat)
- rbs_hat.append((r_g_hat, b_g_hat, Img.col))
+ logger.info(f' r_hat : {r_g_hat:.4f} b_hat : {b_g_hat:.4f}')
+ rbs_hat.append((r_g_hat, b_g_hat, Img.color))
rb_raw.append((r_g, b_g))
- Cam.log += '\n'
- Cam.log += '\nFinished processing images'
+ logger.info('Finished processing images')
"""
sort all lits simultaneously by r_hat
"""
@@ -95,7 +96,7 @@ def awb(Cam, cal_cr_list, cal_cb_list, plot):
fit quadratic fit to r_g hat and b_g_hat
"""
a, b, c = np.polyfit(rbs_hat[0], rbs_hat[1], 2)
- Cam.log += '\nFit quadratic curve in hatspace'
+ logger.info('Fit quadratic curve in hatspace')
"""
the algorithm now approximates the shortest distance from each point to the
curve in dehatspace. Since the fit is done in hatspace, it is easier to
@@ -151,14 +152,14 @@ def awb(Cam, cal_cr_list, cal_cb_list, plot):
if (x+y) > (rr+bb):
dist *= -1
dists.append(dist)
- Cam.log += '\nFound closest point on fit line to each point in dehatspace'
+ logger.info('Found closest point on fit line to each point in dehatspace')
"""
calculate wiggle factors in awb. 10% added since this is an upper bound
"""
transverse_neg = - np.min(dists) * 1.1
transverse_pos = np.max(dists) * 1.1
- Cam.log += '\nTransverse pos : {:.5f}'.format(transverse_pos)
- Cam.log += '\nTransverse neg : {:.5f}'.format(transverse_neg)
+ logger.info(f'Transverse pos : {transverse_pos:.5f}')
+ logger.info(f'Transverse neg : {transverse_neg:.5f}')
"""
set minimum transverse wiggles to 0.1 .
Wiggle factors dictate how far off of the curve the algorithm searches. 0.1
@@ -167,10 +168,10 @@ def awb(Cam, cal_cr_list, cal_cb_list, plot):
"""
if transverse_pos < 0.01:
transverse_pos = 0.01
- Cam.log += '\nForced transverse pos to 0.01'
+ logger.info('Forced transverse pos to 0.01')
if transverse_neg < 0.01:
transverse_neg = 0.01
- Cam.log += '\nForced transverse neg to 0.01'
+ logger.info('Forced transverse neg to 0.01')
"""
generate new b_hat values at each r_hat according to fit
@@ -202,25 +203,25 @@ def awb(Cam, cal_cr_list, cal_cb_list, plot):
i = len(c_fit) - 1
while i > 0:
if c_fit[i] > c_fit[i-1]:
- Cam.log += '\nColour temperature increase found\n'
- Cam.log += '{} K at r = {} to '.format(c_fit[i-1], r_fit[i-1])
- Cam.log += '{} K at r = {}'.format(c_fit[i], r_fit[i])
+ logger.info('Colour temperature increase found')
+ logger.info(f'{c_fit[i - 1]} K at r = {r_fit[i - 1]} to ')
+ logger.info(f'{c_fit[i]} K at r = {r_fit[i]}')
"""
if colour temperature increases then discard point furthest from
the transformed fit (dehatspace)
"""
error_1 = abs(dists[i-1])
error_2 = abs(dists[i])
- Cam.log += '\nDistances from fit:\n'
- Cam.log += '{} K : {:.5f} , '.format(c_fit[i], error_1)
- Cam.log += '{} K : {:.5f}'.format(c_fit[i-1], error_2)
+ logger.info('Distances from fit:')
+ logger.info(f'{c_fit[i]} K : {error_1:.5f}')
+ logger.info(f'{c_fit[i - 1]} K : {error_2:.5f}')
"""
find bad index
note that in python false = 0 and true = 1
"""
bad = i - (error_1 < error_2)
- Cam.log += '\nPoint at {} K deleted as '.format(c_fit[bad])
- Cam.log += 'it is furthest from fit'
+ logger.info(f'Point at {c_fit[bad]} K deleted as ')
+ logger.info('it is furthest from fit')
"""
delete bad point
"""
@@ -239,12 +240,12 @@ def awb(Cam, cal_cr_list, cal_cb_list, plot):
return formatted ct curve, ordered by increasing colour temperature
"""
ct_curve = list(np.array(list(zip(b_fit, r_fit, c_fit))).flatten())[::-1]
- Cam.log += '\nFinal CT curve:'
+ logger.info('Final CT curve:')
for i in range(len(ct_curve)//3):
j = 3*i
- Cam.log += '\n ct: {} '.format(ct_curve[j])
- Cam.log += ' r: {} '.format(ct_curve[j+1])
- Cam.log += ' b: {} '.format(ct_curve[j+2])
+ logger.info(f' ct: {ct_curve[j]} ')
+ logger.info(f' r: {ct_curve[j + 1]} ')
+ logger.info(f' b: {ct_curve[j + 2]} ')
"""
plotting code for debug
@@ -301,10 +302,10 @@ def get_alsc_patches(Img, colour_cals, grey=True):
patches for each channel, remembering to subtract blacklevel
If grey then only greyscale patches considered
"""
+ patches = Img.patches
if grey:
cen_coords = Img.cen_coords[3::4]
- col = Img.col
- patches = [np.array(Img.patches[i]) for i in Img.order]
+ col = Img.color
r_patchs = patches[0][3::4] - Img.blacklevel_16
b_patchs = patches[3][3::4] - Img.blacklevel_16
"""
@@ -314,7 +315,6 @@ def get_alsc_patches(Img, colour_cals, grey=True):
else:
cen_coords = Img.cen_coords
col = Img.color
- patches = [np.array(Img.patches[i]) for i in Img.order]
r_patchs = patches[0] - Img.blacklevel_16
b_patchs = patches[3] - Img.blacklevel_16
g_patchs = (patches[1]+patches[2])/2 - Img.blacklevel_16
diff --git a/utils/tuning/libtuning/image.py b/utils/tuning/libtuning/image.py
index c8911a0f..ecd334bd 100644
--- a/utils/tuning/libtuning/image.py
+++ b/utils/tuning/libtuning/image.py
@@ -135,6 +135,6 @@ class Image:
all_patches.append(ch_patches)
- self.patches = all_patches
+ self.patches = np.array(all_patches)
return not saturated
diff --git a/utils/tuning/libtuning/libtuning.py b/utils/tuning/libtuning/libtuning.py
index e7c63535..bac57323 100644
--- a/utils/tuning/libtuning/libtuning.py
+++ b/utils/tuning/libtuning/libtuning.py
@@ -95,7 +95,10 @@ class Tuner(object):
self.output = {}
def add(self, module):
- self.modules.append(module)
+ if isinstance(module, list):
+ self.modules.extend(module)
+ else:
+ self.modules.append(module)
def set_input_parser(self, parser):
self.parser = parser
diff --git a/utils/tuning/libtuning/modules/agc/rkisp1.py b/utils/tuning/libtuning/modules/agc/rkisp1.py
index 7147028a..2dad3a09 100644
--- a/utils/tuning/libtuning/modules/agc/rkisp1.py
+++ b/utils/tuning/libtuning/modules/agc/rkisp1.py
@@ -47,9 +47,9 @@ class AGCRkISP1(AGC):
}
def _generate_exposure_modes(self) -> dict:
- normal = {'shutter': [100, 10000, 30000, 60000, 120000],
+ normal = {'exposureTime': [100, 10000, 30000, 60000, 120000],
'gain': [2.0, 4.0, 6.0, 6.0, 6.0]}
- short = {'shutter': [100, 5000, 10000, 20000, 120000],
+ short = {'exposureTime': [100, 5000, 10000, 20000, 120000],
'gain': [2.0, 4.0, 6.0, 6.0, 6.0]}
return {'ExposureNormal': normal, 'ExposureShort': short}
diff --git a/utils/tuning/libtuning/modules/awb/__init__.py b/utils/tuning/libtuning/modules/awb/__init__.py
new file mode 100644
index 00000000..2d67f10c
--- /dev/null
+++ b/utils/tuning/libtuning/modules/awb/__init__.py
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (C) 2024, Ideas On Board
+
+from libtuning.modules.awb.awb import AWB
+from libtuning.modules.awb.rkisp1 import AWBRkISP1
diff --git a/utils/tuning/libtuning/modules/awb/awb.py b/utils/tuning/libtuning/modules/awb/awb.py
new file mode 100644
index 00000000..0dc4f59d
--- /dev/null
+++ b/utils/tuning/libtuning/modules/awb/awb.py
@@ -0,0 +1,40 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (C) 2024, Ideas On Board
+
+import logging
+
+from ..module import Module
+
+from libtuning.ctt_awb import awb
+import numpy as np
+
+logger = logging.getLogger(__name__)
+
+
+class AWB(Module):
+ type = 'awb'
+ hr_name = 'AWB (Base)'
+ out_name = 'GenericAWB'
+
+ def __init__(self, *, debug: list):
+ super().__init__()
+
+ self.debug = debug
+
+ def do_calculation(self, images):
+ logger.info('Starting AWB calculation')
+
+ imgs = [img for img in images if img.macbeth is not None]
+
+ ct_curve, transverse_pos, transverse_neg = awb(imgs, None, None, False)
+ ct_curve = np.reshape(ct_curve, (-1, 3))
+ gains = [{
+ 'ct': int(v[0]),
+ 'gains': [float(1.0 / v[1]), float(1.0 / v[2])]
+ } for v in ct_curve]
+
+ return {'colourGains': gains,
+ 'transversePos': transverse_pos,
+ 'transverseNeg': transverse_neg}
+
diff --git a/utils/tuning/libtuning/modules/awb/rkisp1.py b/utils/tuning/libtuning/modules/awb/rkisp1.py
new file mode 100644
index 00000000..d562d26e
--- /dev/null
+++ b/utils/tuning/libtuning/modules/awb/rkisp1.py
@@ -0,0 +1,36 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (C) 2024, Ideas On Board
+#
+# AWB module for tuning rkisp1
+
+from .awb import AWB
+
+class AWBRkISP1(AWB):
+ hr_name = 'AWB (RkISP1)'
+ out_name = 'Awb'
+
+ def __init__(self, **kwargs):
+ super().__init__(**kwargs)
+
+ def validate_config(self, config: dict) -> bool:
+ return True
+
+ def process(self, config: dict, images: list, outputs: dict) -> dict:
+ if not 'awb' in config['general']:
+ raise ValueError('AWB configuration missing')
+ awb_config = config['general']['awb']
+ algorithm = awb_config['algorithm']
+
+ output = {'algorithm': algorithm}
+ data = self.do_calculation(images)
+ if algorithm == 'grey':
+ output['colourGains'] = data['colourGains']
+ elif algorithm == 'bayes':
+ output['AwbMode'] = awb_config['AwbMode']
+ output['priors'] = awb_config['priors']
+ output.update(data)
+ else:
+ raise ValueError(f"Unknown AWB algorithm {output['algorithm']}")
+
+ return output
diff --git a/utils/tuning/libtuning/modules/lux/__init__.py b/utils/tuning/libtuning/modules/lux/__init__.py
new file mode 100644
index 00000000..af9d4e08
--- /dev/null
+++ b/utils/tuning/libtuning/modules/lux/__init__.py
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (C) 2025, Ideas on Board
+
+from libtuning.modules.lux.lux import Lux
+from libtuning.modules.lux.rkisp1 import LuxRkISP1
diff --git a/utils/tuning/libtuning/modules/lux/lux.py b/utils/tuning/libtuning/modules/lux/lux.py
new file mode 100644
index 00000000..4bad429a
--- /dev/null
+++ b/utils/tuning/libtuning/modules/lux/lux.py
@@ -0,0 +1,70 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (C) 2019, Raspberry Pi Ltd
+# Copyright (C) 2025, Ideas on Board
+#
+# Base Lux tuning module
+
+from ..module import Module
+
+import logging
+import numpy as np
+
+logger = logging.getLogger(__name__)
+
+
+class Lux(Module):
+ type = 'lux'
+ hr_name = 'Lux (Base)'
+ out_name = 'GenericLux'
+
+ def __init__(self, debug: list):
+ super().__init__()
+
+ self.debug = debug
+
+ def calculate_lux_reference_values(self, images):
+ # The lux calibration is done on a single image. For best effects, the
+ # image with lux level closest to 1000 is chosen.
+ imgs = [img for img in images if img.macbeth is not None]
+ lux_values = [img.lux for img in imgs]
+ index = lux_values.index(min(lux_values, key=lambda l: abs(1000 - l)))
+ img = imgs[index]
+ logger.info(f'Selected image {img.name} for lux calibration')
+
+ if img.lux < 50:
+ logger.warning(f'A Lux level of {img.lux} is very low for proper lux calibration')
+
+ ref_y = self.calculate_y(img)
+ exposure_time = img.exposure
+ gain = img.againQ8_norm
+ aperture = 1
+ logger.info(f'RefY:{ref_y} Exposure time:{exposure_time}µs Gain:{gain} Aperture:{aperture}')
+ return {'referenceY': ref_y,
+ 'referenceExposureTime': exposure_time,
+ 'referenceAnalogueGain': gain,
+ 'referenceDigitalGain': 1.0,
+ 'referenceLux': img.lux}
+
+ def calculate_y(self, img):
+ max16Bit = 0xffff
+ # Average over all grey patches.
+ ap_r = np.mean(img.patches[0][3::4]) / max16Bit
+ ap_g = (np.mean(img.patches[1][3::4]) + np.mean(img.patches[2][3::4])) / 2 / max16Bit
+ ap_b = np.mean(img.patches[3][3::4]) / max16Bit
+ logger.debug(f'Averaged grey patches: Red: {ap_r}, Green: {ap_g}, Blue: {ap_b}')
+
+ # Calculate white balance gains.
+ gr = ap_g / ap_r
+ gb = ap_g / ap_b
+ logger.debug(f'WB gains: Red: {gr} Blue: {gb}')
+
+ # Calculate the mean Y value of the whole image
+ a_r = np.mean(img.channels[0]) * gr
+ a_g = (np.mean(img.channels[1]) + np.mean(img.channels[2])) / 2
+ a_b = np.mean(img.channels[3]) * gb
+ y = 0.299 * a_r + 0.587 * a_g + 0.114 * a_b
+ y /= max16Bit
+
+ return y
+
diff --git a/utils/tuning/libtuning/modules/lux/rkisp1.py b/utils/tuning/libtuning/modules/lux/rkisp1.py
new file mode 100644
index 00000000..62d3f94c
--- /dev/null
+++ b/utils/tuning/libtuning/modules/lux/rkisp1.py
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (C) 2024, Ideas on Board
+#
+# Lux module for tuning rkisp1
+
+from .lux import Lux
+
+
+class LuxRkISP1(Lux):
+ hr_name = 'Lux (RkISP1)'
+ out_name = 'Lux'
+
+ def __init__(self, **kwargs):
+ super().__init__(**kwargs)
+
+ # We don't need anything from the config file.
+ def validate_config(self, config: dict) -> bool:
+ return True
+
+ def process(self, config: dict, images: list, outputs: dict) -> dict:
+ return self.calculate_lux_reference_values(images)
diff --git a/utils/tuning/rkisp1.py b/utils/tuning/rkisp1.py
index 5d7a69fc..207b717a 100755
--- a/utils/tuning/rkisp1.py
+++ b/utils/tuning/rkisp1.py
@@ -2,25 +2,28 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Copyright (C) 2022, Paul Elder <paul.elder@ideasonboard.com>
+# Copyright (C) 2024, Ideas On Board
#
# Tuning script for rkisp1
-import coloredlogs
import logging
import sys
+import coloredlogs
import libtuning as lt
-from libtuning.parsers import YamlParser
from libtuning.generators import YamlOutput
-from libtuning.modules.lsc import LSCRkISP1
from libtuning.modules.agc import AGCRkISP1
+from libtuning.modules.awb import AWBRkISP1
from libtuning.modules.ccm import CCMRkISP1
+from libtuning.modules.lsc import LSCRkISP1
+from libtuning.modules.lux import LuxRkISP1
from libtuning.modules.static import StaticModule
+from libtuning.parsers import YamlParser
coloredlogs.install(level=logging.INFO, fmt='%(name)s %(levelname)s %(message)s')
agc = AGCRkISP1(debug=[lt.Debug.Plot])
-awb = StaticModule('Awb')
+awb = AWBRkISP1(debug=[lt.Debug.Plot])
blc = StaticModule('BlackLevelCorrection')
ccm = CCMRkISP1(debug=[lt.Debug.Plot])
color_processing = StaticModule('ColorProcessing')
@@ -43,20 +46,15 @@ lsc = LSCRkISP1(debug=[lt.Debug.Plot],
# This is the function that will be used to smooth the color ratio
# values. This can also be a custom function.
smoothing_function=lt.smoothing.MedianBlur(3),)
+lux = LuxRkISP1(debug=[lt.Debug.Plot])
tuner = lt.Tuner('RkISP1')
-tuner.add(agc)
-tuner.add(awb)
-tuner.add(blc)
-tuner.add(ccm)
-tuner.add(color_processing)
-tuner.add(filter)
-tuner.add(gamma_out)
-tuner.add(lsc)
-
+tuner.add([agc, awb, blc, ccm, color_processing, filter, gamma_out, lsc, lux])
tuner.set_input_parser(YamlParser())
tuner.set_output_formatter(YamlOutput())
-tuner.set_output_order([agc, awb, blc, ccm, color_processing,
+
+# Bayesian AWB uses the lux value, so insert the lux algorithm before AWB.
+tuner.set_output_order([agc, lux, awb, blc, ccm, color_processing,
filter, gamma_out, lsc])
if __name__ == '__main__':
diff --git a/utils/update-kernel-headers.sh b/utils/update-kernel-headers.sh
index 8405be0a..9a64dfb5 100755
--- a/utils/update-kernel-headers.sh
+++ b/utils/update-kernel-headers.sh
@@ -9,7 +9,7 @@ if [ $# != 1 ] ; then
fi
header_dir="$(dirname "$(realpath "$0")")/../include/linux"
-kernel_dir="$1"
+kernel_dir="$(realpath "$1")"
# Bail out if the directory doesn't contain kernel sources
line=$(head -3 "${kernel_dir}/Kbuild" 2>/dev/null | tail -1)