Show a patch.

GET /api/patches/16600/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 16600,
    "url": "https://patchwork.libcamera.org/api/patches/16600/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/16600/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20220713084317.24268-3-dse@thaumatec.com>",
    "date": "2022-07-13T08:43:08",
    "name": "[libcamera-devel,v2,02/11] ipa: Add class that implements base AF control algorithm",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "1ff9c5dc0afa306706ba54fa8226db2286b5331e",
    "submitter": {
        "id": 126,
        "url": "https://patchwork.libcamera.org/api/people/126/?format=api",
        "name": "Daniel Semkowicz",
        "email": "dse@thaumatec.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/16600/mbox/",
    "series": [
        {
            "id": 3276,
            "url": "https://patchwork.libcamera.org/api/series/3276/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=3276",
            "date": "2022-07-13T08:43:06",
            "name": "ipa: rkisp1: Add autofocus algorithm",
            "version": 2,
            "mbox": "https://patchwork.libcamera.org/series/3276/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/16600/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/16600/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<libcamera-devel-bounces@lists.libcamera.org>",
        "X-Original-To": "parsemail@patchwork.libcamera.org",
        "Delivered-To": "parsemail@patchwork.libcamera.org",
        "Received": [
            "from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 0D41EBD1F1\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 13 Jul 2022 08:43:38 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 9E5E463319;\n\tWed, 13 Jul 2022 10:43:37 +0200 (CEST)",
            "from mail-wr1-x436.google.com (mail-wr1-x436.google.com\n\t[IPv6:2a00:1450:4864:20::436])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id E228B6330A\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 13 Jul 2022 10:43:33 +0200 (CEST)",
            "by mail-wr1-x436.google.com with SMTP id a5so14461594wrx.12\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 13 Jul 2022 01:43:33 -0700 (PDT)",
            "from localhost.localdomain (ip092042140082.rev.nessus.at.\n\t[92.42.140.82]) by smtp.gmail.com with ESMTPSA id\n\tbg32-20020a05600c3ca000b003a04d19dab3sm5667468wmb.3.2022.07.13.01.43.32\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tWed, 13 Jul 2022 01:43:33 -0700 (PDT)"
        ],
        "DKIM-Signature": [
            "v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1657701817;\n\tbh=xJQKTbPa0U71qrWmVARk9zMH1wWKhZ5GxYAjkWdD+fM=;\n\th=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:\n\tFrom;\n\tb=k2miVst9SL3hCwD8lYMldzrU3Of9RoBla66gD8GFtGMGCB6UyI4e8aXSdY+UBRM83\n\tdv3eY67H5cpuV37TEaGCUYjiTCqqQ3TIH7qwClWabWDBabWnoSziRjJLwV1/VDIlJv\n\t1ljbnivMRMdza2+3M4BMV6XxyzRVsoZ7w6JDQ5dAw0eJbLk445MIuvU812CN034zn7\n\tg/nLZg9sR9KyKtGBVCF9hHroohCi6exInNk/UaKWe7xPa1QSSvl6OR22eECjno9J4j\n\tMXCUMQMiGwUJh6o5K/OBI/Wd3s9iLfgy1YSUHBlR8Bs6gHPD9uLo4ypu8aLD0k8l4L\n\tIf91KjjTIP8XA==",
            "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=thaumatec-com.20210112.gappssmtp.com; s=20210112;\n\th=from:to:cc:subject:date:message-id:in-reply-to:references\n\t:mime-version:content-transfer-encoding;\n\tbh=3vGUXRY/JNfBGnbAekBFLY5gOvcKq1MkRAcEHZoXKQA=;\n\tb=LvjrvfO6Q5m96JEft2bQ8SMvLJ81RkS1+hSF2oBC/k6z/yu//Vs16g0fiMcHoOZMJP\n\tN+RK7DM9YjO3vySdEKDU88KOzhC8LON7XcNpkyJvVPeB//t0IBJnnF53NQwfSoRyebXD\n\toKKc9PAiWLCKcyJSkfQsaHMCxuHQS3IBRjR48TTAksJbqFhbkdda8eU68uvX/GUsGmgd\n\t0TYl7cuYd0Tw5QQcjB0p0gUEDA+8TFAhWPohwdYG4AK0Ja64jWcWgELFiykveY+X2AuE\n\tKzB4W9AI7qyiVsi0/kEJPfvh6kKkCw02QNgP/xId2OAlKlYR08EYdZ/2b/U7p4YlrVDg\n\ti1Aw=="
        ],
        "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (2048-bit key; \n\tunprotected)\n\theader.d=thaumatec-com.20210112.gappssmtp.com\n\theader.i=@thaumatec-com.20210112.gappssmtp.com header.b=\"LvjrvfO6\"; \n\tdkim-atps=neutral",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20210112;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references:mime-version:content-transfer-encoding;\n\tbh=3vGUXRY/JNfBGnbAekBFLY5gOvcKq1MkRAcEHZoXKQA=;\n\tb=ks5IAxtMkZV/Ty8Ub0U/GvmD5C2wlKg8nAUHHVrr12zK35k/yUOfRhZJA8rjHLB9zY\n\t7kWraipFIR9qZzEJLUFbaZmsr+ri4MmF9NS9H142GM3JOMagMRtoaTHcVcDkAxYkYqDo\n\tg3YLcg6+RcTJSxWEm0cgIjXoRBpvkQEg2jQ9tbT3qPjjg6lgW9dcMAFK/NV+K+mGg4mx\n\tCfTBonfWL5/qc9UW1W5BTKubsGDik5Ur8RmNKJQWpIhhK/i+GIykcfsXv3nIukZpZ++R\n\tiSrxOQTgU5A016Tz0/nhNSp1dFPvH9Rl3WcUg83OAdkxg6BuR1Zh5J9ik+Cl2l3gwLO6\n\th3mw==",
        "X-Gm-Message-State": "AJIora8yXNxb4p7nWbA+bnSrAyk36zkDDWZ7+Q/4CYxfrk8dp5s1r/XV\n\tt97kXyj1Enq4gGFbBtXDlCWfgFJiE/G3/w==",
        "X-Google-Smtp-Source": "AGRyM1uRW8Gkln72M96GJjPnrTxGNIb/K6x21RPSP8VyMNcfKwBQsY6dIpPtmUpsoc4KWx7V+rxIYg==",
        "X-Received": "by 2002:adf:fd02:0:b0:21d:6f22:7857 with SMTP id\n\te2-20020adffd02000000b0021d6f227857mr2118398wrr.633.1657701813553; \n\tWed, 13 Jul 2022 01:43:33 -0700 (PDT)",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Wed, 13 Jul 2022 10:43:08 +0200",
        "Message-Id": "<20220713084317.24268-3-dse@thaumatec.com>",
        "X-Mailer": "git-send-email 2.34.1",
        "In-Reply-To": "<20220713084317.24268-1-dse@thaumatec.com>",
        "References": "<20220713084317.24268-1-dse@thaumatec.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[libcamera-devel] [PATCH v2 02/11] ipa: Add class that implements\n\tbase AF control algorithm",
        "X-BeenThere": "libcamera-devel@lists.libcamera.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "<libcamera-devel.lists.libcamera.org>",
        "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>",
        "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>",
        "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>",
        "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>",
        "From": "Daniel Semkowicz via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>",
        "Reply-To": "Daniel Semkowicz <dse@thaumatec.com>",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "Move the code that was common for IPU3 and RPi AF algorithms to\na separate class independent of platform specific code.\nThis way each platform can just implement contrast calculation and\nrun the AF control loop basing on this class.\n\nSigned-off-by: Daniel Semkowicz <dse@thaumatec.com>\n---\n .../libipa/algorithms/af_hill_climbing.cpp    |  89 +++++++\n src/ipa/libipa/algorithms/af_hill_climbing.h  | 251 ++++++++++++++++++\n src/ipa/libipa/algorithms/meson.build         |   2 +\n 3 files changed, 342 insertions(+)\n create mode 100644 src/ipa/libipa/algorithms/af_hill_climbing.cpp\n create mode 100644 src/ipa/libipa/algorithms/af_hill_climbing.h",
    "diff": "diff --git a/src/ipa/libipa/algorithms/af_hill_climbing.cpp b/src/ipa/libipa/algorithms/af_hill_climbing.cpp\nnew file mode 100644\nindex 00000000..f666c6c2\n--- /dev/null\n+++ b/src/ipa/libipa/algorithms/af_hill_climbing.cpp\n@@ -0,0 +1,89 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2021, Red Hat\n+ * Copyright (C) 2022, Ideas On Board\n+ * Copyright (C) 2022, Theobroma Systems\n+ *\n+ * af_hill_climbing.cpp - AF Hill Climbing common algorithm\n+ */\n+\n+#include \"af_hill_climbing.h\"\n+\n+/**\n+ * \\file af_hill_climbing.h\n+ * \\brief AF Hill Climbing common algorithm\n+ */\n+\n+namespace libcamera {\n+\n+LOG_DEFINE_CATEGORY(Af)\n+\n+namespace ipa::common::algorithms {\n+\n+/**\n+ * \\class AfHillClimbing\n+ * \\brief The base class implementing hill climbing AF control algorithm\n+ * \\tparam Module The IPA module type for this class of algorithms\n+ *\n+ * Control part of auto focus algorithm. It calculates the lens position basing\n+ * on contrast measure supplied by the higher level. This way it is independent\n+ * from the platform.\n+ *\n+ * Derived class should call processAutofocus() for each measured contrast value\n+ * and set the lens to the calculated position.\n+ */\n+\n+/**\n+ * \\fn AfHillClimbing::setMode()\n+ * \\copydoc libcamera::ipa::common::algorithms::AfAlgorithm::setMode\n+ */\n+\n+/**\n+ * \\fn AfHillClimbing::setRange()\n+ * \\copydoc libcamera::ipa::common::algorithms::AfAlgorithm::setRange\n+ */\n+\n+/**\n+ * \\fn AfHillClimbing::setSpeed()\n+ * \\copydoc libcamera::ipa::common::algorithms::AfAlgorithm::setSpeed\n+ */\n+\n+/**\n+ * \\fn AfHillClimbing::setMetering()\n+ * \\copydoc libcamera::ipa::common::algorithms::AfAlgorithm::setMetering\n+ */\n+\n+/**\n+ * \\fn AfHillClimbing::setWindows()\n+ * \\copydoc libcamera::ipa::common::algorithms::AfAlgorithm::setWindows\n+ */\n+\n+/**\n+ * \\fn AfHillClimbing::setTrigger()\n+ * \\copydoc libcamera::ipa::common::algorithms::AfAlgorithm::setTrigger\n+ */\n+\n+/**\n+ * \\fn AfHillClimbing::setPause()\n+ * \\copydoc libcamera::ipa::common::algorithms::AfAlgorithm::setPause\n+ */\n+\n+/**\n+ * \\fn AfHillClimbing::setLensPosition()\n+ * \\copydoc libcamera::ipa::common::algorithms::AfAlgorithm::setLensPosition\n+ */\n+\n+/**\n+ * \\fn AfHillClimbing::processAutofocus()\n+ * \\brief Run the auto focus algorithm loop\n+ * \\param[in] currentContrast New value of contrast measured for current frame\n+ *\n+ * This method should be called for each new contrast value that was measured,\n+ * usually in the process() method.\n+ *\n+ * \\return New lens position calculated by AF algorithm\n+ */\n+\n+} /* namespace ipa::common::algorithms */\n+\n+} /* namespace libcamera */\ndiff --git a/src/ipa/libipa/algorithms/af_hill_climbing.h b/src/ipa/libipa/algorithms/af_hill_climbing.h\nnew file mode 100644\nindex 00000000..db9fc058\n--- /dev/null\n+++ b/src/ipa/libipa/algorithms/af_hill_climbing.h\n@@ -0,0 +1,251 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2021, Red Hat\n+ * Copyright (C) 2022, Ideas On Board\n+ * Copyright (C) 2022, Theobroma Systems\n+ *\n+ * af_hill_climbing.h - AF Hill Climbing common algorithm\n+ */\n+\n+#pragma once\n+\n+#include <libcamera/base/log.h>\n+\n+#include \"af_algorithm.h\"\n+\n+namespace libcamera {\n+\n+LOG_DECLARE_CATEGORY(Af)\n+\n+namespace ipa::common::algorithms {\n+\n+template<typename Module>\n+class AfHillClimbing : public AfAlgorithm<Module>\n+{\n+public:\n+\tAfHillClimbing()\n+\t\t: mode_(controls::AfModeAuto), state_(controls::AfStateIdle),\n+\t\t  pauseState_(controls::AfPauseStateRunning),\n+\t\t  lensPosition_(0), bestPosition_(0), currentContrast_(0.0),\n+\t\t  previousContrast_(0.0), maxContrast_(0.0), maxStep_(0),\n+\t\t  coarseCompleted_(false), fineCompleted_(false),\n+\t\t  lowStep_(0), highStep_(kMaxFocusSteps)\n+\t{\n+\t}\n+\n+\tvirtual ~AfHillClimbing() {}\n+\n+\tvoid setMode(controls::AfModeEnum mode) final\n+\t{\n+\t\tif (mode != mode_) {\n+\t\t\tLOG(Af, Debug) << \"Switched AF mode from \" << mode_\n+\t\t\t\t       << \" to \" << mode;\n+\t\t\tpauseState_ = libcamera::controls::AfPauseStateRunning;\n+\t\t\tmode_ = mode;\n+\t\t}\n+\t}\n+\n+\tvoid setRange([[maybe_unused]] controls::AfRangeEnum range) final\n+\t{\n+\t\tLOG(Af, Error) << __FUNCTION__ << \" not implemented!\";\n+\t}\n+\n+\tvoid setSpeed([[maybe_unused]] controls::AfSpeedEnum speed) final\n+\t{\n+\t\tLOG(Af, Error) << __FUNCTION__ << \" not implemented!\";\n+\t}\n+\n+\tvoid setTrigger(controls::AfTriggerEnum trigger) final\n+\t{\n+\t\tLOG(Af, Debug) << \"Trigger called in mode \" << mode_\n+\t\t\t       << \" with \" << trigger;\n+\t\tif (mode_ == libcamera::controls::AfModeAuto) {\n+\t\t\tif (trigger == libcamera::controls::AfTriggerStart)\n+\t\t\t\tafReset();\n+\t\t\telse\n+\t\t\t\tstate_ = libcamera::controls::AfStateIdle;\n+\t\t}\n+\t}\n+\n+\tvoid setPause(controls::AfPauseEnum pause) final\n+\t{\n+\t\t/* \\todo: add the AfPauseDeferred mode */\n+\t\tif (mode_ == libcamera::controls::AfModeContinuous) {\n+\t\t\tif (pause == libcamera::controls::AfPauseImmediate)\n+\t\t\t\tpauseState_ = libcamera::controls::AfPauseStatePaused;\n+\t\t\telse if (pause == libcamera::controls::AfPauseResume)\n+\t\t\t\tpauseState_ = libcamera::controls::AfPauseStateRunning;\n+\t\t}\n+\t}\n+\n+\tvoid setLensPosition([[maybe_unused]] float lensPosition) final\n+\t{\n+\t\tLOG(Af, Error) << __FUNCTION__ << \" not implemented!\";\n+\t}\n+\n+\t/* These methods should be implemented by derived class */\n+\tvirtual void setMetering(controls::AfMeteringEnum metering) = 0;\n+\tvirtual void setWindows(Span<const Rectangle> windows) = 0;\n+\n+protected:\n+\tuint32_t processAutofocus(double currentContrast)\n+\t{\n+\t\tcurrentContrast_ = currentContrast;\n+\n+\t\t/* If we are in a paused state, we won't process the stats */\n+\t\tif (pauseState_ == libcamera::controls::AfPauseStatePaused)\n+\t\t\treturn lensPosition_;\n+\n+\t\t/* Depending on the mode, we may or may not process the stats */\n+\t\tif (state_ == libcamera::controls::AfStateIdle)\n+\t\t\treturn lensPosition_;\n+\n+\t\tif (state_ != libcamera::controls::AfStateFocused) {\n+\t\t\tafCoarseScan();\n+\t\t\tafFineScan();\n+\t\t} else {\n+\t\t\t/* We can re-start the scan at any moment in AfModeContinuous */\n+\t\t\tif (mode_ == libcamera::controls::AfModeContinuous)\n+\t\t\t\tif (afIsOutOfFocus())\n+\t\t\t\t\tafReset();\n+\t\t}\n+\n+\t\treturn lensPosition_;\n+\t}\n+\n+private:\n+\tvoid afCoarseScan()\n+\t{\n+\t\tif (coarseCompleted_)\n+\t\t\treturn;\n+\n+\t\tif (afScan(kCoarseSearchStep)) {\n+\t\t\tcoarseCompleted_ = true;\n+\t\t\tmaxContrast_ = 0;\n+\t\t\tlensPosition_ = lensPosition_ - (lensPosition_ * kFineRange);\n+\t\t\tpreviousContrast_ = 0;\n+\t\t\tmaxStep_ = std::clamp(lensPosition_ + static_cast<uint32_t>((lensPosition_ * kFineRange)),\n+\t\t\t\t\t      0U, highStep_);\n+\t\t}\n+\t}\n+\n+\tvoid afFineScan()\n+\t{\n+\t\tif (!coarseCompleted_)\n+\t\t\treturn;\n+\n+\t\tif (afScan(kFineSearchStep)) {\n+\t\t\tLOG(Af, Debug) << \"AF found the best focus position !\";\n+\t\t\tstate_ = libcamera::controls::AfStateFocused;\n+\t\t\tfineCompleted_ = true;\n+\t\t}\n+\t}\n+\n+\tbool afScan(uint32_t minSteps)\n+\t{\n+\t\tif (lensPosition_ + minSteps > maxStep_) {\n+\t\t\t/* If the max step is reached, move lens to the position. */\n+\t\t\tlensPosition_ = bestPosition_;\n+\t\t\treturn true;\n+\t\t} else {\n+\t\t\t/*\n+\t\t\t* Find the maximum of the variance by estimating its\n+\t\t\t* derivative. If the direction changes, it means we have passed\n+\t\t\t* a maximum one step before.\n+\t\t\t*/\n+\t\t\tif ((currentContrast_ - maxContrast_) >= -(maxContrast_ * 0.1)) {\n+\t\t\t\t/*\n+\t\t\t\t* Positive and zero derivative:\n+\t\t\t\t* The variance is still increasing. The focus could be\n+\t\t\t\t* increased for the next comparison. Also, the max\n+\t\t\t\t* variance and previous focus value are updated.\n+\t\t\t\t*/\n+\t\t\t\tbestPosition_ = lensPosition_;\n+\t\t\t\tlensPosition_ += minSteps;\n+\t\t\t\tmaxContrast_ = currentContrast_;\n+\t\t\t} else {\n+\t\t\t\t/*\n+\t\t\t\t* Negative derivative:\n+\t\t\t\t* The variance starts to decrease which means the maximum\n+\t\t\t\t* variance is found. Set focus step to previous good one\n+\t\t\t\t* then return immediately.\n+\t\t\t\t*/\n+\t\t\t\tlensPosition_ = bestPosition_;\n+\t\t\t\treturn true;\n+\t\t\t}\n+\t\t}\n+\n+\t\tpreviousContrast_ = currentContrast_;\n+\t\tLOG(Af, Debug) << \" Previous step is \" << bestPosition_\n+\t\t\t       << \" Current step is \" << lensPosition_;\n+\t\treturn false;\n+\t}\n+\n+\tvoid afReset()\n+\t{\n+\t\tLOG(Af, Debug) << \"Reset AF parameters\";\n+\t\tlensPosition_ = lowStep_;\n+\t\tmaxStep_ = highStep_;\n+\t\tstate_ = libcamera::controls::AfStateScanning;\n+\t\tpreviousContrast_ = 0.0;\n+\t\tcoarseCompleted_ = false;\n+\t\tfineCompleted_ = false;\n+\t\tmaxContrast_ = 0.0;\n+\t}\n+\n+\tbool afIsOutOfFocus()\n+\t{\n+\t\tconst uint32_t diff_var = std::abs(currentContrast_ -\n+\t\t\t\t\t\t   maxContrast_);\n+\t\tconst double var_ratio = diff_var / maxContrast_;\n+\t\tLOG(Af, Debug) << \"Variance change rate: \" << var_ratio\n+\t\t\t       << \" Current VCM step: \" << lensPosition_;\n+\t\tif (var_ratio > kMaxChange)\n+\t\t\treturn true;\n+\t\telse\n+\t\t\treturn false;\n+\t}\n+\n+\tcontrols::AfModeEnum mode_;\n+\tcontrols::AfStateEnum state_;\n+\tcontrols::AfPauseStateEnum pauseState_;\n+\n+\t/* VCM step configuration. It is the current setting of the VCM step. */\n+\tuint32_t lensPosition_;\n+\t/* The best VCM step. It is a local optimum VCM step during scanning. */\n+\tuint32_t bestPosition_;\n+\n+\t/* Current AF statistic contrast. */\n+\tdouble currentContrast_;\n+\t/* It is used to determine the derivative during scanning */\n+\tdouble previousContrast_;\n+\tdouble maxContrast_;\n+\t/* The designated maximum range of focus scanning. */\n+\tuint32_t maxStep_;\n+\t/* If the coarse scan completes, it is set to true. */\n+\tbool coarseCompleted_;\n+\t/* If the fine scan completes, it is set to true. */\n+\tbool fineCompleted_;\n+\n+\tuint32_t lowStep_;\n+\tuint32_t highStep_;\n+\n+\t/*\n+\t* Maximum focus steps of the VCM control\n+\t* \\todo should be obtained from the VCM driver\n+\t*/\n+\tstatic constexpr uint32_t kMaxFocusSteps = 1023;\n+\n+\t/* Minimum focus step for searching appropriate focus */\n+\tstatic constexpr uint32_t kCoarseSearchStep = 30;\n+\tstatic constexpr uint32_t kFineSearchStep = 1;\n+\n+\t/* Max ratio of variance change, 0.0 < kMaxChange < 1.0 */\n+\tstatic constexpr double kMaxChange = 0.5;\n+\n+\t/* Fine scan range 0 < kFineRange < 1 */\n+\tstatic constexpr double kFineRange = 0.05;\n+};\n+\n+} /* namespace ipa::common::algorithms */\n+} /* namespace libcamera */\ndiff --git a/src/ipa/libipa/algorithms/meson.build b/src/ipa/libipa/algorithms/meson.build\nindex ab8da13a..860dc199 100644\n--- a/src/ipa/libipa/algorithms/meson.build\n+++ b/src/ipa/libipa/algorithms/meson.build\n@@ -2,8 +2,10 @@\n \n common_ipa_algorithms_headers = files([\n     'af_algorithm.h',\n+    'af_hill_climbing.h',\n ])\n \n common_ipa_algorithms_sources = files([\n     'af_algorithm.cpp',\n+    'af_hill_climbing.cpp',\n ])\n",
    "prefixes": [
        "libcamera-devel",
        "v2",
        "02/11"
    ]
}