summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2020-01-12 01:29:50 +0200
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2020-03-06 18:10:18 +0200
commit9c6d32fcf3198cc83cff6af3c9393e94c88bf9b9 (patch)
tree12c54865325dcf8a73c84f2abe1c190068d7ffd0
parentdd0923960040a0a8832b581c7a7e8d3a14b5061f (diff)
libcamera: controls: Don't convert 32-bit and 64-bit implicitly
The ControlValue::get<T>() method verifies that the T type corresponds to the ControlValue type. It however accepts int32_t as a return type for 64-bit integer controls, and int64_t as a return type for 32-bit integer controls. There's no reason to do so anymore, make the type check stricter. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
-rw-r--r--src/libcamera/controls.cpp4
1 files changed, 2 insertions, 2 deletions
diff --git a/src/libcamera/controls.cpp b/src/libcamera/controls.cpp
index 613e6d76..f632d60a 100644
--- a/src/libcamera/controls.cpp
+++ b/src/libcamera/controls.cpp
@@ -187,7 +187,7 @@ const bool &ControlValue::get<bool>() const
template<>
const int32_t &ControlValue::get<int32_t>() const
{
- ASSERT(type_ == ControlTypeInteger32 || type_ == ControlTypeInteger64);
+ ASSERT(type_ == ControlTypeInteger32);
return integer32_;
}
@@ -195,7 +195,7 @@ const int32_t &ControlValue::get<int32_t>() const
template<>
const int64_t &ControlValue::get<int64_t>() const
{
- ASSERT(type_ == ControlTypeInteger32 || type_ == ControlTypeInteger64);
+ ASSERT(type_ == ControlTypeInteger64);
return integer64_;
}
='#n203'>203 204 205 206 207 208
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Copyright (C) 2022, Paul Elder <paul.elder@ideasonboard.com>
#
# libtuning.py - An infrastructure for camera tuning tools

import argparse

import libtuning as lt
import libtuning.utils as utils
from libtuning.utils import eprint

from enum import Enum, IntEnum


class Color(IntEnum):
    R = 0
    GR = 1
    GB = 2
    B = 3


class Debug(Enum):
    Plot = 1


# @brief What to do with the leftover pixels after dividing them into ALSC
#        sectors, when the division gradient is uniform
# @var Float Force floating point division so all sectors divide equally
# @var DistributeFront Divide the remainder equally (until running out,
#      obviously) into the existing sectors, starting from the front
# @var DistributeBack Same as DistributeFront but starting from the back
class Remainder(Enum):
    Float = 0
    DistributeFront = 1
    DistributeBack = 2


# @brief A helper class to contain a default value for a module configuration
# parameter
class Param(object):
    # @var Required The value contained in this instance is irrelevant, and the
    #      value must be provided by the tuning configuration file.
    # @var Optional If the value is not provided by the tuning configuration
    #      file, then the value contained in this instance will be used instead.
    # @var Hardcode The value contained in this instance will be used
    class Mode(Enum):
        Required = 0
        Optional = 1
        Hardcode = 2

    # @param name Name of the parameter. Shall match the name used in the
    #        configuration file for the parameter
    # @param required Whether or not a value is required in the config
    #        parameter of get_value()
    # @param val Default value (only relevant if mode is Optional)
    def __init__(self, name: str, required: Mode, val=None):
        self.name = name
        self.__required = required
        self.val = val

    def get_value(self, config: dict):
        if self.__required is self.Mode.Hardcode:
            return self.val

        if self.__required is self.Mode.Required and self.name not in config:
            raise ValueError(f'Parameter {self.name} is required but not provided in the configuration')

        return config[self.name] if self.required else self.val

    @property
    def required(self):
        return self.__required is self.Mode.Required

    # @brief Used by libtuning to auto-generate help information for the tuning
    #        script on the available parameters for the configuration file
    # \todo Implement this
    @property
    def info(self):
        raise NotImplementedError


class Tuner(object):

    # External functions

    def __init__(self, platform_name):
        self.name = platform_name
        self.modules = []
        self.parser = None
        self.generator = None
        self.output_order = []
        self.config = {}
        self.output = {}

    def add(self, module):
        self.modules.append(module)

    def set_input_parser(self, parser):
        self.parser = parser

    def set_output_formatter(self, output):
        self.generator = output

    def set_output_order(self, modules):
        self.output_order = modules

    # @brief Convert classes in self.output_order to the instances in self.modules
    def _prepare_output_order(self):
        output_order = self.output_order
        self.output_order = []
        for module_type in output_order:
            modules = [module for module in self.modules if module.type == module_type.type]
            if len(modules) > 1:
                eprint(f'Multiple modules found for module type "{module_type.type}"')
                return False
            if len(modules) < 1:
                eprint(f'No module found for module type "{module_type.type}"')
                return False
            self.output_order.append(modules[0])

        return True

    # \todo Validate parser and generator at Tuner construction time?
    def _validate_settings(self):
        if self.parser is None:
            eprint('Missing parser')
            return False

        if self.generator is None:
            eprint('Missing generator')
            return False

        if len(self.modules) == 0:
            eprint('No modules added')
            return False

        if len(self.output_order) != len(self.modules):
            eprint('Number of outputs does not match number of modules')
            return False

        return True

    def _process_args(self, argv, platform_name):
        parser = argparse.ArgumentParser(description=f'Camera Tuning for {platform_name}')
        parser.add_argument('-i', '--input', type=str, required=True,
                            help='''Directory containing calibration images (required).
                                    Images for ALSC must be named "alsc_{Color Temperature}k_1[u].dng",
                                    and all other images must be named "{Color Temperature}k_{Lux Level}l.dng"''')
        parser.add_argument('-o', '--output', type=str, required=True,
                            help='Output file (required)')
        # It is not our duty to scan all modules to figure out their default
        # options, so simply return an empty configuration if none is provided.
        parser.add_argument('-c', '--config', type=str, default='',
                            help='Config file (optional)')
        # \todo Check if we really need this or if stderr is good enough, or if
        # we want a better logging infrastructure with log levels
        parser.add_argument('-l', '--log', type=str, default=None,
                            help='Output log file (optional)')
        return parser.parse_args(argv[1:])

    def run(self, argv):
        args = self._process_args(argv, self.name)
        if args is None:
            return -1

        if not self._validate_settings():
            return -1

        if not self._prepare_output_order():
            return -1

        if len(args.config) > 0:
            self.config, disable = self.parser.parse(args.config, self.modules)
        else:
            self.config = {'general': {}}
            disable = []

        # Remove disabled modules
        for module in disable:
            if module in self.modules:
                self.modules.remove(module)

        for module in self.modules: