Show a patch.

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

{
    "id": 17080,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/17080/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/17080/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/1.1/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": "<20220811150219.62066-5-jacopo@jmondi.org>",
    "date": "2022-08-11T15:02:17",
    "name": "[libcamera-devel,v2,4/6] ipa: raspberry: Port to the new AEGC controls",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "7405a42a1b92124636e7333c79e39aa64c186222",
    "submitter": {
        "id": 3,
        "url": "https://patchwork.libcamera.org/api/1.1/people/3/?format=api",
        "name": "Jacopo Mondi",
        "email": "jacopo@jmondi.org"
    },
    "delegate": {
        "id": 15,
        "url": "https://patchwork.libcamera.org/api/1.1/users/15/?format=api",
        "username": "jmondi",
        "first_name": "Jacopo",
        "last_name": "Mondi",
        "email": "jacopo@jmondi.org"
    },
    "mbox": "https://patchwork.libcamera.org/patch/17080/mbox/",
    "series": [
        {
            "id": 3404,
            "url": "https://patchwork.libcamera.org/api/1.1/series/3404/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=3404",
            "date": "2022-08-11T15:02:13",
            "name": "AEGC controls",
            "version": 2,
            "mbox": "https://patchwork.libcamera.org/series/3404/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/17080/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/17080/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 D97C5BE173\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 11 Aug 2022 15:02:40 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 9B3C363338;\n\tThu, 11 Aug 2022 17:02:40 +0200 (CEST)",
            "from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net\n\t[IPv6:2001:4b98:dc4:8::228])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id AFA1E63330\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 11 Aug 2022 17:02:38 +0200 (CEST)",
            "(Authenticated sender: jacopo@jmondi.org)\n\tby mail.gandi.net (Postfix) with ESMTPSA id A7ED01BF20A;\n\tThu, 11 Aug 2022 15:02:37 +0000 (UTC)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1660230160;\n\tbh=YBSL0m/ZatXDKFzO1smEbnnzup40c/qz/H/qUpQcA3s=;\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=jM2MgrCzDnOiciKCOggrMHFSRTMIvOQeSsOW6UFW6SzdP5Kwawe5z+fn/FIPqGJzT\n\tjHWdJubcWgvuE+w6tEzQNWcqR1gWIvSjIwLQUitK3UFTYc9Cr0B5CL1yZSthHSfPhN\n\t+2Svzw6bqg2aL4vU0kH87fSioOusXdpprt33pesgYQRx393QIWC1rHIqeeHrEmkDrk\n\tYMQyzTjSeTjVX+dyTs2Ia0KTmAVEwbspmB6z8z4h0DnG53ZKEAYnWZ4goWQ9vzS7yY\n\tDIYCU2p4Ohu2928zLF2svYf543E2VgbRaokHryUiAAA41DeNFb5HYccRsfKddX8ViF\n\tJMPSBjnKFoTmQ==",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Thu, 11 Aug 2022 17:02:17 +0200",
        "Message-Id": "<20220811150219.62066-5-jacopo@jmondi.org>",
        "X-Mailer": "git-send-email 2.37.1",
        "In-Reply-To": "<20220811150219.62066-1-jacopo@jmondi.org>",
        "References": "<20220811150219.62066-1-jacopo@jmondi.org>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[libcamera-devel] [PATCH v2 4/6] ipa: raspberry: Port to the new\n\tAEGC controls",
        "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": "Jacopo Mondi via libcamera-devel <libcamera-devel@lists.libcamera.org>",
        "Reply-To": "Jacopo Mondi <jacopo@jmondi.org>",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "The newly introduced controls to driver the AEGC algorithm allow\nto control the computation of the exposure time and analogue gain\nseparately.\n\nThe RPi AEGC implementation already computes the shutter and gain\nvalues separately but does not expose separate functions to control\nthem.\n\nAugment the AgcAlgorithm interface to allow to pause/resume the shutter\nand gain automatic computations separately and plumb them to the newly\nintroduced controls.\n\nAdd safety checks to ignore ExposureTime and AnalogueGain values if the\nalgorithms are not paused, and report the correct AeState value by\nchecking if both algorithms have been paused or if they have converged.\n\nSigned-off-by: Jacopo Mondi <jacopo@jmondi.org>\n---\n .../raspberrypi/controller/agc_algorithm.h    |  6 ++\n src/ipa/raspberrypi/controller/rpi/agc.cpp    | 24 +++++-\n src/ipa/raspberrypi/controller/rpi/agc.h      |  8 +-\n src/ipa/raspberrypi/raspberrypi.cpp           | 76 ++++++++++++++++---\n 4 files changed, 99 insertions(+), 15 deletions(-)",
    "diff": "diff --git a/src/ipa/raspberrypi/controller/agc_algorithm.h b/src/ipa/raspberrypi/controller/agc_algorithm.h\nindex 3a91444c3a61..bf9c501db553 100644\n--- a/src/ipa/raspberrypi/controller/agc_algorithm.h\n+++ b/src/ipa/raspberrypi/controller/agc_algorithm.h\n@@ -17,6 +17,12 @@ class AgcAlgorithm : public Algorithm\n public:\n \tAgcAlgorithm(Controller *controller) : Algorithm(controller) {}\n \t/* An AGC algorithm must provide the following: */\n+\tvirtual void pauseShutter();\n+\tvirtual void resumeShutter();\n+\tvirtual bool isShutterPaused() const;\n+\tvirtual void pauseGain();\n+\tvirtual void resumeGain();\n+\tvirtual bool isGainPaused() const;\n \tvirtual unsigned int getConvergenceFrames() const = 0;\n \tvirtual void setEv(double ev) = 0;\n \tvirtual void setFlickerPeriod(libcamera::utils::Duration flickerPeriod) = 0;\ndiff --git a/src/ipa/raspberrypi/controller/rpi/agc.cpp b/src/ipa/raspberrypi/controller/rpi/agc.cpp\nindex bd54a639d637..3d04724349f7 100644\n--- a/src/ipa/raspberrypi/controller/rpi/agc.cpp\n+++ b/src/ipa/raspberrypi/controller/rpi/agc.cpp\n@@ -275,18 +275,36 @@ bool Agc::isPaused() const\n \treturn false;\n }\n \n-void Agc::pause()\n+void Agc::pauseShutter()\n {\n \tfixedShutter_ = status_.shutterTime;\n-\tfixedAnalogueGain_ = status_.analogueGain;\n }\n \n-void Agc::resume()\n+void Agc::resumeShutter()\n {\n \tfixedShutter_ = 0s;\n+}\n+\n+bool Agc::isShutterPaused() const\n+{\n+\treturn fixedShutter_ != 0s;\n+}\n+\n+void Agc::pauseGain()\n+{\n+\tfixedAnalogueGain_ = status_.analogueGain;\n+}\n+\n+void Agc::resumeGain()\n+{\n \tfixedAnalogueGain_ = 0;\n }\n \n+bool Agc::isGainPaused() const\n+{\n+\treturn fixedAnalogueGain_ != 0;\n+}\n+\n unsigned int Agc::getConvergenceFrames() const\n {\n \t/*\ndiff --git a/src/ipa/raspberrypi/controller/rpi/agc.h b/src/ipa/raspberrypi/controller/rpi/agc.h\nindex 6d6b0e5ad857..cfb57f41848b 100644\n--- a/src/ipa/raspberrypi/controller/rpi/agc.h\n+++ b/src/ipa/raspberrypi/controller/rpi/agc.h\n@@ -77,8 +77,12 @@ public:\n \tint read(const libcamera::YamlObject &params) override;\n \t/* AGC handles \"pausing\" for itself. */\n \tbool isPaused() const override;\n-\tvoid pause() override;\n-\tvoid resume() override;\n+\tvoid pauseShutter() override;\n+\tvoid resumeShutter() override;\n+\tbool isShutterPaused() const override;\n+\tvoid pauseGain() override;\n+\tvoid resumeGain() override;\n+\tbool isGainPaused() const override;\n \tunsigned int getConvergenceFrames() const override;\n \tvoid setEv(double ev) override;\n \tvoid setFlickerPeriod(libcamera::utils::Duration flickerPeriod) override;\ndiff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp\nindex 69c73f8c780a..c041aac008eb 100644\n--- a/src/ipa/raspberrypi/raspberrypi.cpp\n+++ b/src/ipa/raspberrypi/raspberrypi.cpp\n@@ -74,8 +74,13 @@ constexpr Duration controllerMinFrameDuration = 1.0s / 30.0;\n \n /* List of controls handled by the Raspberry Pi IPA */\n static const ControlInfoMap::Map ipaControls{\n-\t{ &controls::AeEnable, ControlInfo(false, true) },\n+\t{ &controls::ExposureTimeMode,\n+\t  ControlInfo(static_cast<int32_t>(controls::ExposureTimeModeAuto),\n+\t\t      static_cast<int32_t>(controls::ExposureTimeModeManual)) },\n \t{ &controls::ExposureTime, ControlInfo(0, 66666) },\n+\t{ &controls::AnalogueGainMode,\n+\t  ControlInfo(static_cast<int32_t>(controls::AnalogueGainModeAuto),\n+\t\t      static_cast<int32_t>(controls::AnalogueGainModeManual)) },\n \t{ &controls::AnalogueGain, ControlInfo(1.0f, 16.0f) },\n \t{ &controls::AeMeteringMode, ControlInfo(controls::AeMeteringModeValues) },\n \t{ &controls::AeConstraintMode, ControlInfo(controls::AeConstraintModeValues) },\n@@ -556,9 +561,18 @@ void IPARPi::reportMetadata()\n \t}\n \n \tAgcStatus *agcStatus = rpiMetadata_.getLocked<AgcStatus>(\"agc.status\");\n-\tif (agcStatus) {\n-\t\tlibcameraMetadata_.set(controls::AeLocked, agcStatus->locked);\n+\tif (agcStatus)\n \t\tlibcameraMetadata_.set(controls::DigitalGain, agcStatus->digitalGain);\n+\n+\tRPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(\n+\t\tcontroller_.getAlgorithm(\"agc\"));\n+\tif (agc) {\n+\t\tif (agc->isShutterPaused() && agc->isGainPaused())\n+\t\t\tlibcameraMetadata_.set(controls::AeState, controls::AeStateIdle);\n+\t\telse if (agcStatus)\n+\t\t\tlibcameraMetadata_.set(controls::AeState,\n+\t\t\t\t\t       agcStatus->locked ? controls::AeStateConverged\n+\t\t\t\t\t\t\t\t : controls::AeStateSearching);\n \t}\n \n \tLuxStatus *luxStatus = rpiMetadata_.getLocked<LuxStatus>(\"lux.status\");\n@@ -703,20 +717,22 @@ void IPARPi::queueRequest(const ControlList &controls)\n \t\t\t\t   << \" = \" << ctrl.second.toString();\n \n \t\tswitch (ctrl.first) {\n-\t\tcase controls::AE_ENABLE: {\n-\t\t\tRPiController::Algorithm *agc = controller_.getAlgorithm(\"agc\");\n+\t\tcase controls::EXPOSURE_TIME_MODE: {\n+\t\t\tRPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(\n+\t\t\t\tcontroller_.getAlgorithm(\"agc\"));\n \t\t\tif (!agc) {\n \t\t\t\tLOG(IPARPI, Warning)\n-\t\t\t\t\t<< \"Could not set AE_ENABLE - no AGC algorithm\";\n+\t\t\t\t\t<< \"Could not set EXPOSURE_TIME_MODE - no AGC algorithm\";\n \t\t\t\tbreak;\n \t\t\t}\n \n-\t\t\tif (ctrl.second.get<bool>() == false)\n-\t\t\t\tagc->pause();\n+\t\t\tif (ctrl.second.get<int32_t>() == controls::ExposureTimeModeManual)\n+\t\t\t\tagc->pauseShutter();\n \t\t\telse\n-\t\t\t\tagc->resume();\n+\t\t\t\tagc->resumeShutter();\n \n-\t\t\tlibcameraMetadata_.set(controls::AeEnable, ctrl.second.get<bool>());\n+\t\t\tlibcameraMetadata_.set(controls::ExposureTimeMode,\n+\t\t\t\t\t       ctrl.second.get<int32_t>());\n \t\t\tbreak;\n \t\t}\n \n@@ -729,6 +745,13 @@ void IPARPi::queueRequest(const ControlList &controls)\n \t\t\t\tbreak;\n \t\t\t}\n \n+\t\t\t/*\n+\t\t\t * Ignore manual exposure time when the auto exposure\n+\t\t\t * algorithm is running.\n+\t\t\t */\n+\t\t\tif (!agc->isShutterPaused())\n+\t\t\t\tbreak;\n+\n \t\t\t/* The control provides units of microseconds. */\n \t\t\tagc->setFixedShutter(ctrl.second.get<int32_t>() * 1.0us);\n \n@@ -736,6 +759,25 @@ void IPARPi::queueRequest(const ControlList &controls)\n \t\t\tbreak;\n \t\t}\n \n+\t\tcase controls::ANALOGUE_GAIN_MODE: {\n+\t\t\tRPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(\n+\t\t\t\tcontroller_.getAlgorithm(\"agc\"));\n+\t\t\tif (!agc) {\n+\t\t\t\tLOG(IPARPI, Warning)\n+\t\t\t\t\t<< \"Could not set ANALOGUE_GAIN_MODE - no AGC algorithm\";\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\t\tif (ctrl.second.get<int32_t>() == controls::AnalogueGainModeManual)\n+\t\t\t\tagc->pauseGain();\n+\t\t\telse\n+\t\t\t\tagc->resumeGain();\n+\n+\t\t\tlibcameraMetadata_.set(controls::AnalogueGainMode,\n+\t\t\t\t\t       ctrl.second.get<int32_t>());\n+\t\t\tbreak;\n+\t\t}\n+\n \t\tcase controls::ANALOGUE_GAIN: {\n \t\t\tRPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(\n \t\t\t\tcontroller_.getAlgorithm(\"agc\"));\n@@ -745,6 +787,13 @@ void IPARPi::queueRequest(const ControlList &controls)\n \t\t\t\tbreak;\n \t\t\t}\n \n+\t\t\t/*\n+\t\t\t * Ignore manual analogue gain value when the auto gain\n+\t\t\t * algorithm is running.\n+\t\t\t */\n+\t\t\tif (!agc->isGainPaused())\n+\t\t\t\tbreak;\n+\n \t\t\tagc->setFixedAnalogueGain(ctrl.second.get<float>());\n \n \t\t\tlibcameraMetadata_.set(controls::AnalogueGain,\n@@ -801,6 +850,13 @@ void IPARPi::queueRequest(const ControlList &controls)\n \t\t\t\tbreak;\n \t\t\t}\n \n+\t\t\t/*\n+\t\t\t * Ignore AE_EXPOSURE_MODE if the shutter or the gain\n+\t\t\t * are in auto mode.\n+\t\t\t */\n+\t\t\tif (!agc->isShutterPaused() || !agc->isGainPaused())\n+\t\t\t\tbreak;\n+\n \t\t\tint32_t idx = ctrl.second.get<int32_t>();\n \t\t\tif (ExposureModeTable.count(idx)) {\n \t\t\t\tagc->setExposureMode(ExposureModeTable.at(idx));\n",
    "prefixes": [
        "libcamera-devel",
        "v2",
        "4/6"
    ]
}