Show a patch.

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

{
    "id": 12312,
    "url": "https://patchwork.libcamera.org/api/patches/12312/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/12312/",
    "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": "<20210518100706.578526-5-naush@raspberrypi.com>",
    "date": "2021-05-18T10:07:06",
    "name": "[libcamera-devel,4/4] ipa: raspberrypi: Switch the AGC/Lux code to use RPiController::Duration",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "71d3aa5e6e4756098e77f02ed2be70ee53f70530",
    "submitter": {
        "id": 34,
        "url": "https://patchwork.libcamera.org/api/people/34/?format=api",
        "name": "Naushir Patuck",
        "email": "naush@raspberrypi.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/12312/mbox/",
    "series": [
        {
            "id": 2034,
            "url": "https://patchwork.libcamera.org/api/series/2034/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=2034",
            "date": "2021-05-18T10:07:02",
            "name": "Switch RaspberryPi IPA to use std::chrono::duration",
            "version": 1,
            "mbox": "https://patchwork.libcamera.org/series/2034/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/12312/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/12312/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 ED2DEC31FF\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 18 May 2021 10:09:18 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 5C51A68927;\n\tTue, 18 May 2021 12:09:18 +0200 (CEST)",
            "from mail-wr1-x42d.google.com (mail-wr1-x42d.google.com\n\t[IPv6:2a00:1450:4864:20::42d])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 516936891C\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 18 May 2021 12:09:14 +0200 (CEST)",
            "by mail-wr1-x42d.google.com with SMTP id h4so9516598wrt.12\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 18 May 2021 03:09:14 -0700 (PDT)",
            "from naush-laptop.pitowers.org\n\t([2a00:1098:3142:14:34e4:187b:f2:ed28])\n\tby smtp.gmail.com with ESMTPSA id\n\to11sm6566682wrq.93.2021.05.18.03.09.12\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tTue, 18 May 2021 03:09:12 -0700 (PDT)"
        ],
        "Authentication-Results": "lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=raspberrypi.com header.i=@raspberrypi.com\n\theader.b=\"SQBMqvwR\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google;\n\th=from:to:cc:subject:date:message-id:in-reply-to:references\n\t:mime-version:content-transfer-encoding;\n\tbh=rzqUqXRYodsYfDJ7fMhpwHw1+0YrwlbKRdZNyEcHcLc=;\n\tb=SQBMqvwRii7trYwarsZxcMZyNKvYCF0mH675a/jq0FnNfgxDaUHzDYKNMPs7lOjfkY\n\t1sJapq8qD9o5/+LYXwP5BB6miV1wbo/2dxD8F1RGK2C/dQQvtuqYMdDBySQfRITmaHzv\n\tKbdsFhoOdtT6UYIHwCce9rx7jeBzG0RYIivJSk1WDH/gCoA3ul5LGKODHN25T7T9CRcL\n\trEDEL7J5JHYy3mczt3wa1cM442y8aKrb6fk5aW9V68OTxEupRKQFqkwxl4W6P01NuXwa\n\tu5N1ZN1uJaD6PVSuemjXbumh7aoR19YSmZxwwkUfPWRl8FHt8gHimLjCh/U1ZfXN0kFD\n\t9HOw==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\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=rzqUqXRYodsYfDJ7fMhpwHw1+0YrwlbKRdZNyEcHcLc=;\n\tb=ABV3GJjeVwLaDWiaqysz5q8uzLF4lZcxA7rjCK/lIChQydeSIB2Dzg/0Tpw8PHBvXl\n\tEUylHu/G4nwGNo9IMKFFn5m1Ep2AdiqZ/HJmoLlWeN/e/rxKNjssc3zHhdqcJesTUj27\n\te7vzxDjEl6M0T7jruaoPso2VdhISuYWPR2uAdeTT9A1Fm8zwi9ttvGdobF9HqXv0tRuq\n\ttENdasYymChMD3ZMA2IoLBCrsyVPwywlAkza3+pluIKMmMifjybZPjTCtreEd5RZnDz2\n\tTYU2TNmtnkRNkCO6M9ztt9FYEqPsq9G0ppXsF2ZIwpNBS8BZdse4RHV7qz/DnuhIzxSk\n\tV3Vw==",
        "X-Gm-Message-State": "AOAM532Ck/qqxxqfRNKpJqr+cUtZclrMY42n4PR+S3zvMgz5eE6qdAAr\n\t2G8ZVGyrfNziYOs3D6IgcFbvpL7URLJz+A==",
        "X-Google-Smtp-Source": "ABdhPJwG73kgoEbGUOE543HOHhdiqrek1eUZR/qrGnRTMpafueq+S6SP4//WKa2oxodiCIshLmDz/g==",
        "X-Received": "by 2002:adf:c002:: with SMTP id z2mr5900906wre.100.1621332553210;\n\tTue, 18 May 2021 03:09:13 -0700 (PDT)",
        "From": "Naushir Patuck <naush@raspberrypi.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Tue, 18 May 2021 11:07:06 +0100",
        "Message-Id": "<20210518100706.578526-5-naush@raspberrypi.com>",
        "X-Mailer": "git-send-email 2.25.1",
        "In-Reply-To": "<20210518100706.578526-1-naush@raspberrypi.com>",
        "References": "<20210518100706.578526-1-naush@raspberrypi.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[libcamera-devel] [PATCH 4/4] ipa: raspberrypi: Switch the AGC/Lux\n\tcode to use RPiController::Duration",
        "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>",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "Convert the core AGC and Lux controller code to use\nRPiController::Duration for all exposure time related variables and\ncalculations.\n\nConvert the exposure/shutter time fields in AgcStatus and DeviceStatus\nto use RPiController::Duration.\n\nSigned-off-by: Naushir Patuck <naush@raspberrypi.com>\n---\n src/ipa/raspberrypi/cam_helper.cpp            |  2 +-\n src/ipa/raspberrypi/controller/agc_status.h   | 12 +--\n .../raspberrypi/controller/device_status.h    |  6 +-\n src/ipa/raspberrypi/controller/rpi/agc.cpp    | 89 ++++++++++---------\n src/ipa/raspberrypi/controller/rpi/agc.hpp    | 26 +++---\n src/ipa/raspberrypi/controller/rpi/lux.cpp    | 17 ++--\n src/ipa/raspberrypi/controller/rpi/lux.hpp    |  2 +-\n src/ipa/raspberrypi/raspberrypi.cpp           | 13 +--\n 8 files changed, 91 insertions(+), 76 deletions(-)",
    "diff": "diff --git a/src/ipa/raspberrypi/cam_helper.cpp b/src/ipa/raspberrypi/cam_helper.cpp\nindex e2b6c8eb8e03..c399987e47bf 100644\n--- a/src/ipa/raspberrypi/cam_helper.cpp\n+++ b/src/ipa/raspberrypi/cam_helper.cpp\n@@ -183,7 +183,7 @@ void CamHelper::parseEmbeddedData(Span<const uint8_t> buffer,\n \t\treturn;\n \t}\n \n-\tdeviceStatus.shutter_speed = DurationValue<std::micro>(Exposure(exposureLines));\n+\tdeviceStatus.shutter_speed = Exposure(exposureLines);\n \tdeviceStatus.analogue_gain = Gain(gainCode);\n \n \tLOG(IPARPI, Debug) << \"Metadata updated - Exposure : \"\ndiff --git a/src/ipa/raspberrypi/controller/agc_status.h b/src/ipa/raspberrypi/controller/agc_status.h\nindex 10381c90a313..b2a64ce562fa 100644\n--- a/src/ipa/raspberrypi/controller/agc_status.h\n+++ b/src/ipa/raspberrypi/controller/agc_status.h\n@@ -6,6 +6,8 @@\n  */\n #pragma once\n \n+#include \"duration.hpp\"\n+\n // The AGC algorithm should post the following structure into the image's\n // \"agc.status\" metadata.\n \n@@ -18,17 +20,17 @@ extern \"C\" {\n // ignored until then.\n \n struct AgcStatus {\n-\tdouble total_exposure_value; // value for all exposure and gain for this image\n-\tdouble target_exposure_value; // (unfiltered) target total exposure AGC is aiming for\n-\tdouble shutter_time;\n+\tRPiController::Duration total_exposure_value; // value for all exposure and gain for this image\n+\tRPiController::Duration target_exposure_value; // (unfiltered) target total exposure AGC is aiming for\n+\tRPiController::Duration shutter_time;\n \tdouble analogue_gain;\n \tchar exposure_mode[32];\n \tchar constraint_mode[32];\n \tchar metering_mode[32];\n \tdouble ev;\n-\tdouble flicker_period;\n+\tRPiController::Duration flicker_period;\n \tint floating_region_enable;\n-\tdouble fixed_shutter;\n+\tRPiController::Duration fixed_shutter;\n \tdouble fixed_analogue_gain;\n \tdouble digital_gain;\n \tint locked;\ndiff --git a/src/ipa/raspberrypi/controller/device_status.h b/src/ipa/raspberrypi/controller/device_status.h\nindex aa08608b5d40..a8496176eb92 100644\n--- a/src/ipa/raspberrypi/controller/device_status.h\n+++ b/src/ipa/raspberrypi/controller/device_status.h\n@@ -6,6 +6,8 @@\n  */\n #pragma once\n \n+#include \"duration.hpp\"\n+\n // Definition of \"device metadata\" which stores things like shutter time and\n // analogue gain that downstream control algorithms will want to know.\n \n@@ -14,8 +16,8 @@ extern \"C\" {\n #endif\n \n struct DeviceStatus {\n-\t// time shutter is open, in microseconds\n-\tdouble shutter_speed;\n+\t// time shutter is open\n+\tRPiController::Duration shutter_speed;\n \tdouble analogue_gain;\n \t// 1.0/distance-in-metres, or 0 if unknown\n \tdouble lens_position;\ndiff --git a/src/ipa/raspberrypi/controller/rpi/agc.cpp b/src/ipa/raspberrypi/controller/rpi/agc.cpp\nindex 1cb4472b2691..3af2ef3cf6ed 100644\n--- a/src/ipa/raspberrypi/controller/rpi/agc.cpp\n+++ b/src/ipa/raspberrypi/controller/rpi/agc.cpp\n@@ -21,6 +21,7 @@\n \n using namespace RPiController;\n using namespace libcamera;\n+using namespace std::literals::chrono_literals;\n \n LOG_DEFINE_CATEGORY(RPiAgc)\n \n@@ -55,19 +56,27 @@ read_metering_modes(std::map<std::string, AgcMeteringMode> &metering_modes,\n \treturn first;\n }\n \n-static int read_double_list(std::vector<double> &list,\n-\t\t\t    boost::property_tree::ptree const &params)\n+static int read_list(std::vector<double> &list,\n+\t\t     boost::property_tree::ptree const &params)\n {\n \tfor (auto &p : params)\n \t\tlist.push_back(p.second.get_value<double>());\n \treturn list.size();\n }\n \n+static int read_list(std::vector<Duration> &list,\n+\t\t     boost::property_tree::ptree const &params)\n+{\n+\tfor (auto &p : params)\n+\t\tlist.push_back(p.second.get_value<double>() * 1us);\n+\treturn list.size();\n+}\n+\n void AgcExposureMode::Read(boost::property_tree::ptree const &params)\n {\n \tint num_shutters =\n-\t\tread_double_list(shutter, params.get_child(\"shutter\"));\n-\tint num_ags = read_double_list(gain, params.get_child(\"gain\"));\n+\t\tread_list(shutter, params.get_child(\"shutter\"));\n+\tint num_ags = read_list(gain, params.get_child(\"gain\"));\n \tif (num_shutters < 2 || num_ags < 2)\n \t\tthrow std::runtime_error(\n \t\t\t\"AgcConfig: must have at least two entries in exposure profile\");\n@@ -147,7 +156,7 @@ void AgcConfig::Read(boost::property_tree::ptree const &params)\n \t\tparams.get<double>(\"fast_reduce_threshold\", 0.4);\n \tbase_ev = params.get<double>(\"base_ev\", 1.0);\n \t// Start with quite a low value as ramping up is easier than ramping down.\n-\tdefault_exposure_time = params.get<double>(\"default_exposure_time\", 1000);\n+\tdefault_exposure_time = params.get<double>(\"default_exposure_time\", 1000) * 1us;\n \tdefault_analogue_gain = params.get<double>(\"default_analogue_gain\", 1.0);\n }\n \n@@ -157,7 +166,7 @@ Agc::Agc(Controller *controller)\n \t  frame_count_(0), lock_count_(0),\n \t  last_target_exposure_(0.0),\n \t  ev_(1.0), flicker_period_(0.0),\n-\t  max_shutter_(0), fixed_shutter_(0), fixed_analogue_gain_(0.0)\n+\t  max_shutter_(0.0s), fixed_shutter_(0.0s), fixed_analogue_gain_(0.0)\n {\n \tmemset(&awb_, 0, sizeof(awb_));\n \t// Setting status_.total_exposure_value_ to zero initially tells us\n@@ -203,7 +212,7 @@ void Agc::Pause()\n \n void Agc::Resume()\n {\n-\tfixed_shutter_ = 0;\n+\tfixed_shutter_ = 0.0s;\n \tfixed_analogue_gain_ = 0;\n }\n \n@@ -211,7 +220,7 @@ unsigned int Agc::GetConvergenceFrames() const\n {\n \t// If shutter and gain have been explicitly set, there is no\n \t// convergence to happen, so no need to drop any frames - return zero.\n-\tif (fixed_shutter_ && fixed_analogue_gain_)\n+\tif (fixed_shutter_ > 0.0s && fixed_analogue_gain_)\n \t\treturn 0;\n \telse\n \t\treturn config_.convergence_frames;\n@@ -224,17 +233,17 @@ void Agc::SetEv(double ev)\n \n void Agc::SetFlickerPeriod(Duration flicker_period)\n {\n-\tflicker_period_ = DurationValue<std::micro>(flicker_period);\n+\tflicker_period_ = flicker_period;\n }\n \n void Agc::SetMaxShutter(Duration max_shutter)\n {\n-\tmax_shutter_ = DurationValue<std::micro>(max_shutter);\n+\tmax_shutter_ = max_shutter;\n }\n \n void Agc::SetFixedShutter(Duration fixed_shutter)\n {\n-\tfixed_shutter_ = DurationValue<std::micro>(fixed_shutter);\n+\tfixed_shutter_ = fixed_shutter;\n \t// Set this in case someone calls Pause() straight after.\n \tstatus_.shutter_time = clipShutter(fixed_shutter_);\n }\n@@ -266,8 +275,8 @@ void Agc::SwitchMode([[maybe_unused]] CameraMode const &camera_mode,\n {\n \thousekeepConfig();\n \n-\tdouble fixed_shutter = clipShutter(fixed_shutter_);\n-\tif (fixed_shutter != 0.0 && fixed_analogue_gain_ != 0.0) {\n+\tDuration fixed_shutter = clipShutter(fixed_shutter_);\n+\tif (fixed_shutter != 0.0s && fixed_analogue_gain_ != 0.0) {\n \t\t// We're going to reset the algorithm here with these fixed values.\n \n \t\tfetchAwbStatus(metadata);\n@@ -284,7 +293,7 @@ void Agc::SwitchMode([[maybe_unused]] CameraMode const &camera_mode,\n \t\t// Equivalent of divideUpExposure.\n \t\tfiltered_.shutter = fixed_shutter;\n \t\tfiltered_.analogue_gain = fixed_analogue_gain_;\n-\t} else if (status_.total_exposure_value) {\n+\t} else if (status_.total_exposure_value > 0.0s) {\n \t\t// On a mode switch, it's possible the exposure profile could change,\n \t\t// or a fixed exposure/gain might be set so we divide up the exposure/\n \t\t// gain again, but we don't change any target values.\n@@ -296,7 +305,7 @@ void Agc::SwitchMode([[maybe_unused]] CameraMode const &camera_mode,\n \t\t// for any that weren't set.\n \n \t\t// Equivalent of divideUpExposure.\n-\t\tfiltered_.shutter = fixed_shutter ? fixed_shutter : config_.default_exposure_time;\n+\t\tfiltered_.shutter = fixed_shutter > 0.0s ? fixed_shutter : config_.default_exposure_time;\n \t\tfiltered_.analogue_gain = fixed_analogue_gain_ ? fixed_analogue_gain_ : config_.default_analogue_gain;\n \t}\n \n@@ -308,13 +317,12 @@ void Agc::Prepare(Metadata *image_metadata)\n \tstatus_.digital_gain = 1.0;\n \tfetchAwbStatus(image_metadata); // always fetch it so that Process knows it's been done\n \n-\tif (status_.total_exposure_value) {\n+\tif (status_.total_exposure_value > 0.0s) {\n \t\t// Process has run, so we have meaningful values.\n \t\tDeviceStatus device_status;\n \t\tif (image_metadata->Get(\"device.status\", device_status) == 0) {\n-\t\t\tdouble actual_exposure = device_status.shutter_speed *\n-\t\t\t\t\t\t device_status.analogue_gain;\n-\t\t\tif (actual_exposure) {\n+\t\t\tDuration actual_exposure = device_status.shutter_speed * device_status.analogue_gain;\n+\t\t\tif (actual_exposure > 0.0s) {\n \t\t\t\tstatus_.digital_gain =\n \t\t\t\t\tstatus_.total_exposure_value /\n \t\t\t\t\tactual_exposure;\n@@ -370,9 +378,9 @@ void Agc::updateLockStatus(DeviceStatus const &device_status)\n \tconst double RESET_MARGIN = 1.5;\n \n \t// Add 200us to the exposure time error to allow for line quantisation.\n-\tdouble exposure_error = last_device_status_.shutter_speed * ERROR_FACTOR + 200;\n+\tDuration exposure_error = last_device_status_.shutter_speed * ERROR_FACTOR + 200us;\n \tdouble gain_error = last_device_status_.analogue_gain * ERROR_FACTOR;\n-\tdouble target_error = last_target_exposure_ * ERROR_FACTOR;\n+\tDuration target_error = last_target_exposure_ * ERROR_FACTOR;\n \n \t// Note that we don't know the exposure/gain limits of the sensor, so\n \t// the values we keep requesting may be unachievable. For this reason\n@@ -462,7 +470,7 @@ void Agc::fetchCurrentExposure(Metadata *image_metadata)\n \tcurrent_.analogue_gain = device_status->analogue_gain;\n \tAgcStatus *agc_status =\n \t\timage_metadata->GetLocked<AgcStatus>(\"agc.status\");\n-\tcurrent_.total_exposure = agc_status ? agc_status->total_exposure_value : 0;\n+\tcurrent_.total_exposure = agc_status ? agc_status->total_exposure_value : 0s;\n \tcurrent_.total_exposure_no_dg = current_.shutter * current_.analogue_gain;\n }\n \n@@ -573,7 +581,7 @@ void Agc::computeGain(bcm2835_isp_stats *statistics, Metadata *image_metadata,\n \n void Agc::computeTargetExposure(double gain)\n {\n-\tif (status_.fixed_shutter != 0.0 && status_.fixed_analogue_gain != 0.0) {\n+\tif (status_.fixed_shutter != 0.0s && status_.fixed_analogue_gain != 0.0) {\n \t\t// When ag and shutter are both fixed, we need to drive the\n \t\t// total exposure so that we end up with a digital gain of at least\n \t\t// 1/min_colour_gain. Otherwise we'd desaturate channels causing\n@@ -588,11 +596,11 @@ void Agc::computeTargetExposure(double gain)\n \t\ttarget_.total_exposure = current_.total_exposure_no_dg * gain;\n \t\t// The final target exposure is also limited to what the exposure\n \t\t// mode allows.\n-\t\tdouble max_shutter = status_.fixed_shutter != 0.0\n+\t\tDuration max_shutter = status_.fixed_shutter != 0.0s\n \t\t\t\t   ? status_.fixed_shutter\n \t\t\t\t   : exposure_mode_->shutter.back();\n \t\tmax_shutter = clipShutter(max_shutter);\n-\t\tdouble max_total_exposure =\n+\t\tDuration max_total_exposure =\n \t\t\tmax_shutter *\n \t\t\t(status_.fixed_analogue_gain != 0.0\n \t\t\t\t ? status_.fixed_analogue_gain\n@@ -634,10 +642,10 @@ void Agc::filterExposure(bool desaturate)\n \tdouble speed = config_.speed;\n \t// AGC adapts instantly if both shutter and gain are directly specified\n \t// or we're in the startup phase.\n-\tif ((status_.fixed_shutter && status_.fixed_analogue_gain) ||\n+\tif ((status_.fixed_shutter > 0.0s && status_.fixed_analogue_gain) ||\n \t    frame_count_ <= config_.startup_frames)\n \t\tspeed = 1.0;\n-\tif (filtered_.total_exposure == 0.0) {\n+\tif (filtered_.total_exposure == 0.0s) {\n \t\tfiltered_.total_exposure = target_.total_exposure;\n \t\tfiltered_.total_exposure_no_dg = target_.total_exposure_no_dg;\n \t} else {\n@@ -674,9 +682,10 @@ void Agc::divideUpExposure()\n \t// Sending the fixed shutter/gain cases through the same code may seem\n \t// unnecessary, but it will make more sense when extend this to cover\n \t// variable aperture.\n-\tdouble exposure_value = filtered_.total_exposure_no_dg;\n-\tdouble shutter_time, analogue_gain;\n-\tshutter_time = status_.fixed_shutter != 0.0\n+\tDuration exposure_value = filtered_.total_exposure_no_dg;\n+\tDuration shutter_time;\n+\tdouble analogue_gain;\n+\tshutter_time = status_.fixed_shutter != 0.0s\n \t\t\t       ? status_.fixed_shutter\n \t\t\t       : exposure_mode_->shutter[0];\n \tshutter_time = clipShutter(shutter_time);\n@@ -686,8 +695,8 @@ void Agc::divideUpExposure()\n \tif (shutter_time * analogue_gain < exposure_value) {\n \t\tfor (unsigned int stage = 1;\n \t\t     stage < exposure_mode_->gain.size(); stage++) {\n-\t\t\tif (status_.fixed_shutter == 0.0) {\n-\t\t\t\tdouble stage_shutter =\n+\t\t\tif (status_.fixed_shutter == 0.0s) {\n+\t\t\t\tDuration stage_shutter =\n \t\t\t\t\tclipShutter(exposure_mode_->shutter[stage]);\n \t\t\t\tif (stage_shutter * analogue_gain >=\n \t\t\t\t    exposure_value) {\n@@ -713,12 +722,12 @@ void Agc::divideUpExposure()\n \t\t\t   << analogue_gain;\n \t// Finally adjust shutter time for flicker avoidance (require both\n \t// shutter and gain not to be fixed).\n-\tif (status_.fixed_shutter == 0.0 &&\n+\tif (status_.fixed_shutter == 0.0s &&\n \t    status_.fixed_analogue_gain == 0.0 &&\n-\t    status_.flicker_period != 0.0) {\n-\t\tint flicker_periods = shutter_time / status_.flicker_period;\n-\t\tif (flicker_periods > 0) {\n-\t\t\tdouble new_shutter_time = flicker_periods * status_.flicker_period;\n+\t    status_.flicker_period != 0.0s) {\n+\t\tdouble flicker_periods = shutter_time / status_.flicker_period;\n+\t\tif (flicker_periods > 0.0) {\n+\t\t\tDuration new_shutter_time = flicker_periods * status_.flicker_period;\n \t\t\tanalogue_gain *= shutter_time / new_shutter_time;\n \t\t\t// We should still not allow the ag to go over the\n \t\t\t// largest value in the exposure mode. Note that this\n@@ -738,7 +747,7 @@ void Agc::divideUpExposure()\n void Agc::writeAndFinish(Metadata *image_metadata, bool desaturate)\n {\n \tstatus_.total_exposure_value = filtered_.total_exposure;\n-\tstatus_.target_exposure_value = desaturate ? 0 : target_.total_exposure_no_dg;\n+\tstatus_.target_exposure_value = desaturate ? 0s : target_.total_exposure_no_dg;\n \tstatus_.shutter_time = filtered_.shutter;\n \tstatus_.analogue_gain = filtered_.analogue_gain;\n \t// Write to metadata as well, in case anyone wants to update the camera\n@@ -750,9 +759,9 @@ void Agc::writeAndFinish(Metadata *image_metadata, bool desaturate)\n \t\t\t   << \" analogue gain \" << filtered_.analogue_gain;\n }\n \n-double Agc::clipShutter(double shutter)\n+Duration Agc::clipShutter(Duration shutter)\n {\n-\tif (max_shutter_)\n+\tif (max_shutter_ > 0.0s)\n \t\tshutter = std::min(shutter, max_shutter_);\n \treturn shutter;\n }\ndiff --git a/src/ipa/raspberrypi/controller/rpi/agc.hpp b/src/ipa/raspberrypi/controller/rpi/agc.hpp\nindex cb79bf61ba42..68b97ce91c99 100644\n--- a/src/ipa/raspberrypi/controller/rpi/agc.hpp\n+++ b/src/ipa/raspberrypi/controller/rpi/agc.hpp\n@@ -22,13 +22,15 @@\n \n namespace RPiController {\n \n+using namespace std::literals::chrono_literals;\n+\n struct AgcMeteringMode {\n \tdouble weights[AGC_STATS_SIZE];\n \tvoid Read(boost::property_tree::ptree const &params);\n };\n \n struct AgcExposureMode {\n-\tstd::vector<double> shutter;\n+\tstd::vector<Duration> shutter;\n \tstd::vector<double> gain;\n \tvoid Read(boost::property_tree::ptree const &params);\n };\n@@ -61,7 +63,7 @@ struct AgcConfig {\n \tstd::string default_exposure_mode;\n \tstd::string default_constraint_mode;\n \tdouble base_ev;\n-\tdouble default_exposure_time;\n+\tDuration default_exposure_time;\n \tdouble default_analogue_gain;\n };\n \n@@ -101,19 +103,19 @@ private:\n \tvoid filterExposure(bool desaturate);\n \tvoid divideUpExposure();\n \tvoid writeAndFinish(Metadata *image_metadata, bool desaturate);\n-\tdouble clipShutter(double shutter);\n+\tDuration clipShutter(Duration shutter);\n \tAgcMeteringMode *metering_mode_;\n \tAgcExposureMode *exposure_mode_;\n \tAgcConstraintMode *constraint_mode_;\n \tuint64_t frame_count_;\n \tAwbStatus awb_;\n \tstruct ExposureValues {\n-\t\tExposureValues() : shutter(0), analogue_gain(0),\n-\t\t\t\t   total_exposure(0), total_exposure_no_dg(0) {}\n-\t\tdouble shutter;\n+\t\tExposureValues() : shutter(0.0s), analogue_gain(0),\n+\t\t\t\t   total_exposure(0.0s), total_exposure_no_dg(0.0s) {}\n+\t\tDuration shutter;\n \t\tdouble analogue_gain;\n-\t\tdouble total_exposure;\n-\t\tdouble total_exposure_no_dg; // without digital gain\n+\t\tDuration total_exposure;\n+\t\tDuration total_exposure_no_dg; // without digital gain\n \t};\n \tExposureValues current_;  // values for the current frame\n \tExposureValues target_;   // calculate the values we want here\n@@ -121,15 +123,15 @@ private:\n \tAgcStatus status_;\n \tint lock_count_;\n \tDeviceStatus last_device_status_;\n-\tdouble last_target_exposure_;\n+\tDuration last_target_exposure_;\n \t// Below here the \"settings\" that applications can change.\n \tstd::string metering_mode_name_;\n \tstd::string exposure_mode_name_;\n \tstd::string constraint_mode_name_;\n \tdouble ev_;\n-\tdouble flicker_period_;\n-\tdouble max_shutter_;\n-\tdouble fixed_shutter_;\n+\tDuration flicker_period_;\n+\tDuration max_shutter_;\n+\tDuration fixed_shutter_;\n \tdouble fixed_analogue_gain_;\n };\n \ndiff --git a/src/ipa/raspberrypi/controller/rpi/lux.cpp b/src/ipa/raspberrypi/controller/rpi/lux.cpp\nindex f74381cab2b4..46d3f3fab2c6 100644\n--- a/src/ipa/raspberrypi/controller/rpi/lux.cpp\n+++ b/src/ipa/raspberrypi/controller/rpi/lux.cpp\n@@ -16,6 +16,7 @@\n \n using namespace RPiController;\n using namespace libcamera;\n+using namespace std::literals::chrono_literals;\n \n LOG_DEFINE_CATEGORY(RPiLux)\n \n@@ -38,7 +39,7 @@ char const *Lux::Name() const\n void Lux::Read(boost::property_tree::ptree const &params)\n {\n \treference_shutter_speed_ =\n-\t\tparams.get<double>(\"reference_shutter_speed\");\n+\t\tparams.get<double>(\"reference_shutter_speed\") * 1us;\n \treference_gain_ = params.get<double>(\"reference_gain\");\n \treference_aperture_ = params.get<double>(\"reference_aperture\", 1.0);\n \treference_Y_ = params.get<double>(\"reference_Y\");\n@@ -60,15 +61,13 @@ void Lux::Prepare(Metadata *image_metadata)\n void Lux::Process(StatisticsPtr &stats, Metadata *image_metadata)\n {\n \t// set some initial values to shut the compiler up\n-\tDeviceStatus device_status =\n-\t\t{ .shutter_speed = 1.0,\n-\t\t  .analogue_gain = 1.0,\n-\t\t  .lens_position = 0.0,\n-\t\t  .aperture = 0.0,\n-\t\t  .flash_intensity = 0.0 };\n+\tDeviceStatus device_status = { .shutter_speed = 1.0ms,\n+\t\t\t\t       .analogue_gain = 1.0,\n+\t\t\t\t       .lens_position = 0.0,\n+\t\t\t\t       .aperture = 0.0,\n+\t\t\t\t       .flash_intensity = 0.0 };\n \tif (image_metadata->Get(\"device.status\", device_status) == 0) {\n \t\tdouble current_gain = device_status.analogue_gain;\n-\t\tdouble current_shutter_speed = device_status.shutter_speed;\n \t\tdouble current_aperture = device_status.aperture;\n \t\tif (current_aperture == 0)\n \t\t\tcurrent_aperture = current_aperture_;\n@@ -83,7 +82,7 @@ void Lux::Process(StatisticsPtr &stats, Metadata *image_metadata)\n \t\tdouble current_Y = sum / (double)num + .5;\n \t\tdouble gain_ratio = reference_gain_ / current_gain;\n \t\tdouble shutter_speed_ratio =\n-\t\t\treference_shutter_speed_ / current_shutter_speed;\n+\t\t\treference_shutter_speed_ / device_status.shutter_speed;\n \t\tdouble aperture_ratio = reference_aperture_ / current_aperture;\n \t\tdouble Y_ratio = current_Y * (65536 / num_bins) / reference_Y_;\n \t\tdouble estimated_lux = shutter_speed_ratio * gain_ratio *\ndiff --git a/src/ipa/raspberrypi/controller/rpi/lux.hpp b/src/ipa/raspberrypi/controller/rpi/lux.hpp\nindex f9090484a136..726a7f7ca627 100644\n--- a/src/ipa/raspberrypi/controller/rpi/lux.hpp\n+++ b/src/ipa/raspberrypi/controller/rpi/lux.hpp\n@@ -28,7 +28,7 @@ public:\n private:\n \t// These values define the conditions of the reference image, against\n \t// which we compare the new image.\n-\tdouble reference_shutter_speed_; // in micro-seconds\n+\tDuration reference_shutter_speed_;\n \tdouble reference_gain_;\n \tdouble reference_aperture_; // units of 1/f\n \tdouble reference_Y_; // out of 65536\ndiff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp\nindex f080f2e53bac..15f51162afec 100644\n--- a/src/ipa/raspberrypi/raspberrypi.cpp\n+++ b/src/ipa/raspberrypi/raspberrypi.cpp\n@@ -227,11 +227,11 @@ void IPARPi::start(const ControlList &controls, ipa::RPi::StartConfig *startConf\n \n \t/* SwitchMode may supply updated exposure/gain values to use. */\n \tAgcStatus agcStatus;\n-\tagcStatus.shutter_time = 0.0;\n+\tagcStatus.shutter_time = 0.0s;\n \tagcStatus.analogue_gain = 0.0;\n \n \tmetadata.Get(\"agc.status\", agcStatus);\n-\tif (agcStatus.shutter_time != 0.0 && agcStatus.analogue_gain != 0.0) {\n+\tif (agcStatus.shutter_time != 0.0s && agcStatus.analogue_gain != 0.0) {\n \t\tControlList ctrls(sensorCtrls_);\n \t\tapplyAGC(&agcStatus, ctrls);\n \t\tstartConfig->controls = std::move(ctrls);\n@@ -394,7 +394,7 @@ int IPARPi::configure(const CameraSensorInfo &sensorInfo,\n \t\t/* Supply initial values for gain and exposure. */\n \t\tControlList ctrls(sensorCtrls_);\n \t\tAgcStatus agcStatus;\n-\t\tagcStatus.shutter_time = DurationValue<std::micro>(DefaultExposureTime);\n+\t\tagcStatus.shutter_time = DefaultExposureTime;\n \t\tagcStatus.analogue_gain = DefaultAnalogueGain;\n \t\tapplyAGC(&agcStatus, ctrls);\n \n@@ -466,7 +466,8 @@ void IPARPi::reportMetadata()\n \t */\n \tDeviceStatus *deviceStatus = rpiMetadata_.GetLocked<DeviceStatus>(\"device.status\");\n \tif (deviceStatus) {\n-\t\tlibcameraMetadata_.set(controls::ExposureTime, deviceStatus->shutter_speed);\n+\t\tlibcameraMetadata_.set(controls::ExposureTime,\n+\t\t\t\t       DurationValue<std::micro>(deviceStatus->shutter_speed));\n \t\tlibcameraMetadata_.set(controls::AnalogueGain, deviceStatus->analogue_gain);\n \t}\n \n@@ -1019,7 +1020,7 @@ void IPARPi::fillDeviceStatus(const ControlList &sensorControls)\n \tint32_t exposureLines = sensorControls.get(V4L2_CID_EXPOSURE).get<int32_t>();\n \tint32_t gainCode = sensorControls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>();\n \n-\tdeviceStatus.shutter_speed = DurationValue<std::micro>(helper_->Exposure(exposureLines));\n+\tdeviceStatus.shutter_speed = helper_->Exposure(exposureLines);\n \tdeviceStatus.analogue_gain = helper_->Gain(gainCode);\n \n \tLOG(IPARPI, Debug) << \"Metadata - Exposure : \"\n@@ -1105,7 +1106,7 @@ void IPARPi::applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls)\n \tint32_t gainCode = helper_->GainCode(agcStatus->analogue_gain);\n \n \t/* GetVBlanking might clip exposure time to the fps limits. */\n-\tDuration exposure = agcStatus->shutter_time * 1.0us;\n+\tDuration exposure = agcStatus->shutter_time;\n \tint32_t vblanking = helper_->GetVBlanking(exposure, minFrameDuration_, maxFrameDuration_);\n \tint32_t exposureLines = helper_->ExposureLines(exposure);\n \n",
    "prefixes": [
        "libcamera-devel",
        "4/4"
    ]
}