[{"id":17027,"web_url":"https://patchwork.libcamera.org/comment/17027/","msgid":"<CAHW6GYJDY36AzrkjtLXD66aBF5PpoiHs_bovavsyuddf1O7dbA@mail.gmail.com>","date":"2021-05-19T15:28:15","subject":"Re: [libcamera-devel] [PATCH 4/4] ipa: raspberrypi: Switch the\n\tAGC/Lux code to use RPiController::Duration","submitter":{"id":42,"url":"https://patchwork.libcamera.org/api/people/42/","name":"David Plowman","email":"david.plowman@raspberrypi.com"},"content":"Hi Naush\n\nThanks for all this work!\n\nOn Tue, 18 May 2021 at 11:09, Naushir Patuck <naush@raspberrypi.com> wrote:\n>\n> Convert the core AGC and Lux controller code to use\n> RPiController::Duration for all exposure time related variables and\n> calculations.\n\nI wonder if I might have tried to keep the AGC and Lux patches\nseparate? Having said that, they both *have* to change as soon as you\ntouch the DeviceStatus, so maybe that would be difficult. Hmm, I think\nI'll leave that up to you!\n>\n> Convert the exposure/shutter time fields in AgcStatus and DeviceStatus\n> to use RPiController::Duration.\n>\n> Signed-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(-)\n>\n> diff --git a/src/ipa/raspberrypi/cam_helper.cpp b/src/ipa/raspberrypi/cam_helper.cpp\n> index 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>                 return;\n>         }\n>\n> -       deviceStatus.shutter_speed = DurationValue<std::micro>(Exposure(exposureLines));\n> +       deviceStatus.shutter_speed = Exposure(exposureLines);\n\nMuch nicer again!\n\n>         deviceStatus.analogue_gain = Gain(gainCode);\n>\n>         LOG(IPARPI, Debug) << \"Metadata updated - Exposure : \"\n> diff --git a/src/ipa/raspberrypi/controller/agc_status.h b/src/ipa/raspberrypi/controller/agc_status.h\n> index 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> -       double total_exposure_value; // value for all exposure and gain for this image\n> -       double target_exposure_value; // (unfiltered) target total exposure AGC is aiming for\n> -       double shutter_time;\n> +       RPiController::Duration total_exposure_value; // value for all exposure and gain for this image\n> +       RPiController::Duration target_exposure_value; // (unfiltered) target total exposure AGC is aiming for\n> +       RPiController::Duration shutter_time;\n>         double analogue_gain;\n>         char exposure_mode[32];\n>         char constraint_mode[32];\n>         char metering_mode[32];\n>         double ev;\n> -       double flicker_period;\n> +       RPiController::Duration flicker_period;\n>         int floating_region_enable;\n> -       double fixed_shutter;\n> +       RPiController::Duration fixed_shutter;\n>         double fixed_analogue_gain;\n>         double digital_gain;\n>         int locked;\n> diff --git a/src/ipa/raspberrypi/controller/device_status.h b/src/ipa/raspberrypi/controller/device_status.h\n> index 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> -       // time shutter is open, in microseconds\n> -       double shutter_speed;\n> +       // time shutter is open\n> +       RPiController::Duration shutter_speed;\n>         double analogue_gain;\n>         // 1.0/distance-in-metres, or 0 if unknown\n>         double lens_position;\n> diff --git a/src/ipa/raspberrypi/controller/rpi/agc.cpp b/src/ipa/raspberrypi/controller/rpi/agc.cpp\n> index 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>         return first;\n>  }\n>\n> -static int read_double_list(std::vector<double> &list,\n> -                           boost::property_tree::ptree const &params)\n> +static int read_list(std::vector<double> &list,\n> +                    boost::property_tree::ptree const &params)\n>  {\n>         for (auto &p : params)\n>                 list.push_back(p.second.get_value<double>());\n>         return list.size();\n>  }\n>\n> +static int read_list(std::vector<Duration> &list,\n> +                    boost::property_tree::ptree const &params)\n> +{\n> +       for (auto &p : params)\n> +               list.push_back(p.second.get_value<double>() * 1us);\n> +       return list.size();\n> +}\n> +\n\nI wonder if there's a template-y way to do these in one go?  (sorry!)\n\n>  void AgcExposureMode::Read(boost::property_tree::ptree const &params)\n>  {\n>         int num_shutters =\n> -               read_double_list(shutter, params.get_child(\"shutter\"));\n> -       int num_ags = read_double_list(gain, params.get_child(\"gain\"));\n> +               read_list(shutter, params.get_child(\"shutter\"));\n> +       int num_ags = read_list(gain, params.get_child(\"gain\"));\n>         if (num_shutters < 2 || num_ags < 2)\n>                 throw std::runtime_error(\n>                         \"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>                 params.get<double>(\"fast_reduce_threshold\", 0.4);\n>         base_ev = params.get<double>(\"base_ev\", 1.0);\n>         // Start with quite a low value as ramping up is easier than ramping down.\n> -       default_exposure_time = params.get<double>(\"default_exposure_time\", 1000);\n> +       default_exposure_time = params.get<double>(\"default_exposure_time\", 1000) * 1us;\n\nMostly I notice that you write, for example, \"1.0us\" rather than \"1us\"\nas you have here. I take it that it makes no difference, right?\n\n>         default_analogue_gain = params.get<double>(\"default_analogue_gain\", 1.0);\n>  }\n>\n> @@ -157,7 +166,7 @@ Agc::Agc(Controller *controller)\n>           frame_count_(0), lock_count_(0),\n>           last_target_exposure_(0.0),\n>           ev_(1.0), flicker_period_(0.0),\n> -         max_shutter_(0), fixed_shutter_(0), fixed_analogue_gain_(0.0)\n> +         max_shutter_(0.0s), fixed_shutter_(0.0s), fixed_analogue_gain_(0.0)\n>  {\n>         memset(&awb_, 0, sizeof(awb_));\n>         // 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> -       fixed_shutter_ = 0;\n> +       fixed_shutter_ = 0.0s;\n>         fixed_analogue_gain_ = 0;\n>  }\n>\n> @@ -211,7 +220,7 @@ unsigned int Agc::GetConvergenceFrames() const\n>  {\n>         // If shutter and gain have been explicitly set, there is no\n>         // convergence to happen, so no need to drop any frames - return zero.\n> -       if (fixed_shutter_ && fixed_analogue_gain_)\n> +       if (fixed_shutter_ > 0.0s && fixed_analogue_gain_)\n\nNo implicit bool conversion for Durations, I take it. I notice that\nthroughout this file we sometimes use \"> 0.0s\", sometimes \"!= 0.0s\". I\nassume that they're effectively interchangeable for us (and that the\nunits don't matter when we compare for zero!), so should we be\nconsistent?\n\nApart from that nothing much to add, so:\n\nReviewed-by: David Plowman <david.plowman@raspberrypi.com>\n\nThanks!\nDavid\n\n>                 return 0;\n>         else\n>                 return config_.convergence_frames;\n> @@ -224,17 +233,17 @@ void Agc::SetEv(double ev)\n>\n>  void Agc::SetFlickerPeriod(Duration flicker_period)\n>  {\n> -       flicker_period_ = DurationValue<std::micro>(flicker_period);\n> +       flicker_period_ = flicker_period;\n>  }\n>\n>  void Agc::SetMaxShutter(Duration max_shutter)\n>  {\n> -       max_shutter_ = DurationValue<std::micro>(max_shutter);\n> +       max_shutter_ = max_shutter;\n>  }\n>\n>  void Agc::SetFixedShutter(Duration fixed_shutter)\n>  {\n> -       fixed_shutter_ = DurationValue<std::micro>(fixed_shutter);\n> +       fixed_shutter_ = fixed_shutter;\n>         // Set this in case someone calls Pause() straight after.\n>         status_.shutter_time = clipShutter(fixed_shutter_);\n>  }\n> @@ -266,8 +275,8 @@ void Agc::SwitchMode([[maybe_unused]] CameraMode const &camera_mode,\n>  {\n>         housekeepConfig();\n>\n> -       double fixed_shutter = clipShutter(fixed_shutter_);\n> -       if (fixed_shutter != 0.0 && fixed_analogue_gain_ != 0.0) {\n> +       Duration fixed_shutter = clipShutter(fixed_shutter_);\n> +       if (fixed_shutter != 0.0s && fixed_analogue_gain_ != 0.0) {\n>                 // We're going to reset the algorithm here with these fixed values.\n>\n>                 fetchAwbStatus(metadata);\n> @@ -284,7 +293,7 @@ void Agc::SwitchMode([[maybe_unused]] CameraMode const &camera_mode,\n>                 // Equivalent of divideUpExposure.\n>                 filtered_.shutter = fixed_shutter;\n>                 filtered_.analogue_gain = fixed_analogue_gain_;\n> -       } else if (status_.total_exposure_value) {\n> +       } else if (status_.total_exposure_value > 0.0s) {\n>                 // On a mode switch, it's possible the exposure profile could change,\n>                 // or a fixed exposure/gain might be set so we divide up the exposure/\n>                 // 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>                 // for any that weren't set.\n>\n>                 // Equivalent of divideUpExposure.\n> -               filtered_.shutter = fixed_shutter ? fixed_shutter : config_.default_exposure_time;\n> +               filtered_.shutter = fixed_shutter > 0.0s ? fixed_shutter : config_.default_exposure_time;\n>                 filtered_.analogue_gain = fixed_analogue_gain_ ? fixed_analogue_gain_ : config_.default_analogue_gain;\n>         }\n>\n> @@ -308,13 +317,12 @@ void Agc::Prepare(Metadata *image_metadata)\n>         status_.digital_gain = 1.0;\n>         fetchAwbStatus(image_metadata); // always fetch it so that Process knows it's been done\n>\n> -       if (status_.total_exposure_value) {\n> +       if (status_.total_exposure_value > 0.0s) {\n>                 // Process has run, so we have meaningful values.\n>                 DeviceStatus device_status;\n>                 if (image_metadata->Get(\"device.status\", device_status) == 0) {\n> -                       double actual_exposure = device_status.shutter_speed *\n> -                                                device_status.analogue_gain;\n> -                       if (actual_exposure) {\n> +                       Duration actual_exposure = device_status.shutter_speed * device_status.analogue_gain;\n> +                       if (actual_exposure > 0.0s) {\n>                                 status_.digital_gain =\n>                                         status_.total_exposure_value /\n>                                         actual_exposure;\n> @@ -370,9 +378,9 @@ void Agc::updateLockStatus(DeviceStatus const &device_status)\n>         const double RESET_MARGIN = 1.5;\n>\n>         // Add 200us to the exposure time error to allow for line quantisation.\n> -       double exposure_error = last_device_status_.shutter_speed * ERROR_FACTOR + 200;\n> +       Duration exposure_error = last_device_status_.shutter_speed * ERROR_FACTOR + 200us;\n>         double gain_error = last_device_status_.analogue_gain * ERROR_FACTOR;\n> -       double target_error = last_target_exposure_ * ERROR_FACTOR;\n> +       Duration target_error = last_target_exposure_ * ERROR_FACTOR;\n>\n>         // Note that we don't know the exposure/gain limits of the sensor, so\n>         // the values we keep requesting may be unachievable. For this reason\n> @@ -462,7 +470,7 @@ void Agc::fetchCurrentExposure(Metadata *image_metadata)\n>         current_.analogue_gain = device_status->analogue_gain;\n>         AgcStatus *agc_status =\n>                 image_metadata->GetLocked<AgcStatus>(\"agc.status\");\n> -       current_.total_exposure = agc_status ? agc_status->total_exposure_value : 0;\n> +       current_.total_exposure = agc_status ? agc_status->total_exposure_value : 0s;\n>         current_.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> -       if (status_.fixed_shutter != 0.0 && status_.fixed_analogue_gain != 0.0) {\n> +       if (status_.fixed_shutter != 0.0s && status_.fixed_analogue_gain != 0.0) {\n>                 // When ag and shutter are both fixed, we need to drive the\n>                 // total exposure so that we end up with a digital gain of at least\n>                 // 1/min_colour_gain. Otherwise we'd desaturate channels causing\n> @@ -588,11 +596,11 @@ void Agc::computeTargetExposure(double gain)\n>                 target_.total_exposure = current_.total_exposure_no_dg * gain;\n>                 // The final target exposure is also limited to what the exposure\n>                 // mode allows.\n> -               double max_shutter = status_.fixed_shutter != 0.0\n> +               Duration max_shutter = status_.fixed_shutter != 0.0s\n>                                    ? status_.fixed_shutter\n>                                    : exposure_mode_->shutter.back();\n>                 max_shutter = clipShutter(max_shutter);\n> -               double max_total_exposure =\n> +               Duration max_total_exposure =\n>                         max_shutter *\n>                         (status_.fixed_analogue_gain != 0.0\n>                                  ? status_.fixed_analogue_gain\n> @@ -634,10 +642,10 @@ void Agc::filterExposure(bool desaturate)\n>         double speed = config_.speed;\n>         // AGC adapts instantly if both shutter and gain are directly specified\n>         // or we're in the startup phase.\n> -       if ((status_.fixed_shutter && status_.fixed_analogue_gain) ||\n> +       if ((status_.fixed_shutter > 0.0s && status_.fixed_analogue_gain) ||\n>             frame_count_ <= config_.startup_frames)\n>                 speed = 1.0;\n> -       if (filtered_.total_exposure == 0.0) {\n> +       if (filtered_.total_exposure == 0.0s) {\n>                 filtered_.total_exposure = target_.total_exposure;\n>                 filtered_.total_exposure_no_dg = target_.total_exposure_no_dg;\n>         } else {\n> @@ -674,9 +682,10 @@ void Agc::divideUpExposure()\n>         // Sending the fixed shutter/gain cases through the same code may seem\n>         // unnecessary, but it will make more sense when extend this to cover\n>         // variable aperture.\n> -       double exposure_value = filtered_.total_exposure_no_dg;\n> -       double shutter_time, analogue_gain;\n> -       shutter_time = status_.fixed_shutter != 0.0\n> +       Duration exposure_value = filtered_.total_exposure_no_dg;\n> +       Duration shutter_time;\n> +       double analogue_gain;\n> +       shutter_time = status_.fixed_shutter != 0.0s\n>                                ? status_.fixed_shutter\n>                                : exposure_mode_->shutter[0];\n>         shutter_time = clipShutter(shutter_time);\n> @@ -686,8 +695,8 @@ void Agc::divideUpExposure()\n>         if (shutter_time * analogue_gain < exposure_value) {\n>                 for (unsigned int stage = 1;\n>                      stage < exposure_mode_->gain.size(); stage++) {\n> -                       if (status_.fixed_shutter == 0.0) {\n> -                               double stage_shutter =\n> +                       if (status_.fixed_shutter == 0.0s) {\n> +                               Duration stage_shutter =\n>                                         clipShutter(exposure_mode_->shutter[stage]);\n>                                 if (stage_shutter * analogue_gain >=\n>                                     exposure_value) {\n> @@ -713,12 +722,12 @@ void Agc::divideUpExposure()\n>                            << analogue_gain;\n>         // Finally adjust shutter time for flicker avoidance (require both\n>         // shutter and gain not to be fixed).\n> -       if (status_.fixed_shutter == 0.0 &&\n> +       if (status_.fixed_shutter == 0.0s &&\n>             status_.fixed_analogue_gain == 0.0 &&\n> -           status_.flicker_period != 0.0) {\n> -               int flicker_periods = shutter_time / status_.flicker_period;\n> -               if (flicker_periods > 0) {\n> -                       double new_shutter_time = flicker_periods * status_.flicker_period;\n> +           status_.flicker_period != 0.0s) {\n> +               double flicker_periods = shutter_time / status_.flicker_period;\n> +               if (flicker_periods > 0.0) {\n> +                       Duration new_shutter_time = flicker_periods * status_.flicker_period;\n>                         analogue_gain *= shutter_time / new_shutter_time;\n>                         // We should still not allow the ag to go over the\n>                         // 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>         status_.total_exposure_value = filtered_.total_exposure;\n> -       status_.target_exposure_value = desaturate ? 0 : target_.total_exposure_no_dg;\n> +       status_.target_exposure_value = desaturate ? 0s : target_.total_exposure_no_dg;\n>         status_.shutter_time = filtered_.shutter;\n>         status_.analogue_gain = filtered_.analogue_gain;\n>         // 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>                            << \" analogue gain \" << filtered_.analogue_gain;\n>  }\n>\n> -double Agc::clipShutter(double shutter)\n> +Duration Agc::clipShutter(Duration shutter)\n>  {\n> -       if (max_shutter_)\n> +       if (max_shutter_ > 0.0s)\n>                 shutter = std::min(shutter, max_shutter_);\n>         return shutter;\n>  }\n> diff --git a/src/ipa/raspberrypi/controller/rpi/agc.hpp b/src/ipa/raspberrypi/controller/rpi/agc.hpp\n> index 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>         double weights[AGC_STATS_SIZE];\n>         void Read(boost::property_tree::ptree const &params);\n>  };\n>\n>  struct AgcExposureMode {\n> -       std::vector<double> shutter;\n> +       std::vector<Duration> shutter;\n>         std::vector<double> gain;\n>         void Read(boost::property_tree::ptree const &params);\n>  };\n> @@ -61,7 +63,7 @@ struct AgcConfig {\n>         std::string default_exposure_mode;\n>         std::string default_constraint_mode;\n>         double base_ev;\n> -       double default_exposure_time;\n> +       Duration default_exposure_time;\n>         double default_analogue_gain;\n>  };\n>\n> @@ -101,19 +103,19 @@ private:\n>         void filterExposure(bool desaturate);\n>         void divideUpExposure();\n>         void writeAndFinish(Metadata *image_metadata, bool desaturate);\n> -       double clipShutter(double shutter);\n> +       Duration clipShutter(Duration shutter);\n>         AgcMeteringMode *metering_mode_;\n>         AgcExposureMode *exposure_mode_;\n>         AgcConstraintMode *constraint_mode_;\n>         uint64_t frame_count_;\n>         AwbStatus awb_;\n>         struct ExposureValues {\n> -               ExposureValues() : shutter(0), analogue_gain(0),\n> -                                  total_exposure(0), total_exposure_no_dg(0) {}\n> -               double shutter;\n> +               ExposureValues() : shutter(0.0s), analogue_gain(0),\n> +                                  total_exposure(0.0s), total_exposure_no_dg(0.0s) {}\n> +               Duration shutter;\n>                 double analogue_gain;\n> -               double total_exposure;\n> -               double total_exposure_no_dg; // without digital gain\n> +               Duration total_exposure;\n> +               Duration total_exposure_no_dg; // without digital gain\n>         };\n>         ExposureValues current_;  // values for the current frame\n>         ExposureValues target_;   // calculate the values we want here\n> @@ -121,15 +123,15 @@ private:\n>         AgcStatus status_;\n>         int lock_count_;\n>         DeviceStatus last_device_status_;\n> -       double last_target_exposure_;\n> +       Duration last_target_exposure_;\n>         // Below here the \"settings\" that applications can change.\n>         std::string metering_mode_name_;\n>         std::string exposure_mode_name_;\n>         std::string constraint_mode_name_;\n>         double ev_;\n> -       double flicker_period_;\n> -       double max_shutter_;\n> -       double fixed_shutter_;\n> +       Duration flicker_period_;\n> +       Duration max_shutter_;\n> +       Duration fixed_shutter_;\n>         double fixed_analogue_gain_;\n>  };\n>\n> diff --git a/src/ipa/raspberrypi/controller/rpi/lux.cpp b/src/ipa/raspberrypi/controller/rpi/lux.cpp\n> index 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>         reference_shutter_speed_ =\n> -               params.get<double>(\"reference_shutter_speed\");\n> +               params.get<double>(\"reference_shutter_speed\") * 1us;\n>         reference_gain_ = params.get<double>(\"reference_gain\");\n>         reference_aperture_ = params.get<double>(\"reference_aperture\", 1.0);\n>         reference_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>         // set some initial values to shut the compiler up\n> -       DeviceStatus device_status =\n> -               { .shutter_speed = 1.0,\n> -                 .analogue_gain = 1.0,\n> -                 .lens_position = 0.0,\n> -                 .aperture = 0.0,\n> -                 .flash_intensity = 0.0 };\n> +       DeviceStatus device_status = { .shutter_speed = 1.0ms,\n> +                                      .analogue_gain = 1.0,\n> +                                      .lens_position = 0.0,\n> +                                      .aperture = 0.0,\n> +                                      .flash_intensity = 0.0 };\n>         if (image_metadata->Get(\"device.status\", device_status) == 0) {\n>                 double current_gain = device_status.analogue_gain;\n> -               double current_shutter_speed = device_status.shutter_speed;\n>                 double current_aperture = device_status.aperture;\n>                 if (current_aperture == 0)\n>                         current_aperture = current_aperture_;\n> @@ -83,7 +82,7 @@ void Lux::Process(StatisticsPtr &stats, Metadata *image_metadata)\n>                 double current_Y = sum / (double)num + .5;\n>                 double gain_ratio = reference_gain_ / current_gain;\n>                 double shutter_speed_ratio =\n> -                       reference_shutter_speed_ / current_shutter_speed;\n> +                       reference_shutter_speed_ / device_status.shutter_speed;\n>                 double aperture_ratio = reference_aperture_ / current_aperture;\n>                 double Y_ratio = current_Y * (65536 / num_bins) / reference_Y_;\n>                 double estimated_lux = shutter_speed_ratio * gain_ratio *\n> diff --git a/src/ipa/raspberrypi/controller/rpi/lux.hpp b/src/ipa/raspberrypi/controller/rpi/lux.hpp\n> index 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>         // These values define the conditions of the reference image, against\n>         // which we compare the new image.\n> -       double reference_shutter_speed_; // in micro-seconds\n> +       Duration reference_shutter_speed_;\n>         double reference_gain_;\n>         double reference_aperture_; // units of 1/f\n>         double reference_Y_; // out of 65536\n> diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp\n> index 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>         /* SwitchMode may supply updated exposure/gain values to use. */\n>         AgcStatus agcStatus;\n> -       agcStatus.shutter_time = 0.0;\n> +       agcStatus.shutter_time = 0.0s;\n>         agcStatus.analogue_gain = 0.0;\n>\n>         metadata.Get(\"agc.status\", agcStatus);\n> -       if (agcStatus.shutter_time != 0.0 && agcStatus.analogue_gain != 0.0) {\n> +       if (agcStatus.shutter_time != 0.0s && agcStatus.analogue_gain != 0.0) {\n>                 ControlList ctrls(sensorCtrls_);\n>                 applyAGC(&agcStatus, ctrls);\n>                 startConfig->controls = std::move(ctrls);\n> @@ -394,7 +394,7 @@ int IPARPi::configure(const CameraSensorInfo &sensorInfo,\n>                 /* Supply initial values for gain and exposure. */\n>                 ControlList ctrls(sensorCtrls_);\n>                 AgcStatus agcStatus;\n> -               agcStatus.shutter_time = DurationValue<std::micro>(DefaultExposureTime);\n> +               agcStatus.shutter_time = DefaultExposureTime;\n>                 agcStatus.analogue_gain = DefaultAnalogueGain;\n>                 applyAGC(&agcStatus, ctrls);\n>\n> @@ -466,7 +466,8 @@ void IPARPi::reportMetadata()\n>          */\n>         DeviceStatus *deviceStatus = rpiMetadata_.GetLocked<DeviceStatus>(\"device.status\");\n>         if (deviceStatus) {\n> -               libcameraMetadata_.set(controls::ExposureTime, deviceStatus->shutter_speed);\n> +               libcameraMetadata_.set(controls::ExposureTime,\n> +                                      DurationValue<std::micro>(deviceStatus->shutter_speed));\n>                 libcameraMetadata_.set(controls::AnalogueGain, deviceStatus->analogue_gain);\n>         }\n>\n> @@ -1019,7 +1020,7 @@ void IPARPi::fillDeviceStatus(const ControlList &sensorControls)\n>         int32_t exposureLines = sensorControls.get(V4L2_CID_EXPOSURE).get<int32_t>();\n>         int32_t gainCode = sensorControls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>();\n>\n> -       deviceStatus.shutter_speed = DurationValue<std::micro>(helper_->Exposure(exposureLines));\n> +       deviceStatus.shutter_speed = helper_->Exposure(exposureLines);\n>         deviceStatus.analogue_gain = helper_->Gain(gainCode);\n>\n>         LOG(IPARPI, Debug) << \"Metadata - Exposure : \"\n> @@ -1105,7 +1106,7 @@ void IPARPi::applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls)\n>         int32_t gainCode = helper_->GainCode(agcStatus->analogue_gain);\n>\n>         /* GetVBlanking might clip exposure time to the fps limits. */\n> -       Duration exposure = agcStatus->shutter_time * 1.0us;\n> +       Duration exposure = agcStatus->shutter_time;\n>         int32_t vblanking = helper_->GetVBlanking(exposure, minFrameDuration_, maxFrameDuration_);\n>         int32_t exposureLines = helper_->ExposureLines(exposure);\n>\n> --\n> 2.25.1\n>","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 68BA4C31FB\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 19 May 2021 15:28:31 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id CB8F36891A;\n\tWed, 19 May 2021 17:28:30 +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 E46B968915\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 19 May 2021 17:28:28 +0200 (CEST)","by mail-wr1-x436.google.com with SMTP id q5so14466078wrs.4\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 19 May 2021 08:28:28 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=raspberrypi.com header.i=@raspberrypi.com\n\theader.b=\"TH8GJBdE\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google;\n\th=mime-version:references:in-reply-to:from:date:message-id:subject:to\n\t:cc; bh=A42KIP7SgbXeIt+SZNlNnZu3pqHh6qNAm3jIXjaBBhQ=;\n\tb=TH8GJBdE4sHSSZ5Mc9UGi2u9KLqzLGgEVFaC9N7W4j9KT8WzyQHPGvIEpWtc6okA0j\n\tkFFoZ8QskXRvISWnO9PkzWIXyRPcKsUg/1Yv+qhHWWwnVKyr+7gGsJYd5U15Ky7f/ZkR\n\tWpNX+vTcg0AlpHuaz/5TWDWQoCh0e18FaUSV8W5Fa9KeiPrpSRk6cQLqmNnuCiEk67iv\n\tl3t+bHKlU62tF3J2qBOnK77N1ij1AFh8PBQ+gO6ytDpylZNZw3oVgcCVPLk4sv4qcEq8\n\tD2xf/A4TWcTU1qkYVl9x9M3cCLSFSd8oPIFIzuEFRtZLXN55WL7j7o5u1gXaN11vS/WE\n\tLi0w==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:mime-version:references:in-reply-to:from:date\n\t:message-id:subject:to:cc;\n\tbh=A42KIP7SgbXeIt+SZNlNnZu3pqHh6qNAm3jIXjaBBhQ=;\n\tb=CZXBGHTk1hifCbJi73mLkaUvDDrVGCiXBn0SKSPLBSKQGvOHLOUUO5p7QrY2P4ShOw\n\tc1rED3MTvlREGh/lDftitiwJvkngAgtkCZPyfpoERa4vGSFdCb+S4krTk38mP6WlwR5Y\n\tT06vlIFro77SYpD+h//dMND5T2tdB5owgvrnwW0i5e4wr3vXru2HZ5AVpoxFexZN7+pw\n\tvkOc4Mn0DUhcQFGt7MoEELdXPt5B7TBfTE2pFOL4RFbxjmHAdZs7kHoNds0SH75Vp+lj\n\tCCGaRLIRHE8D6E6FSno0jQlDlI6sxUh+0ETt80Pgm3asZ2kBq/nGAo8lQAnnR65GFQFN\n\tafHg==","X-Gm-Message-State":"AOAM531DAHjPdLf02fRk146AUDV2OV2V/T3NkNSfqiIIVwBwOyFh0tUe\n\tMNZfJlBtaNlX5XP4/rjVnhdqurdQMEpGa4JsgVWWWA==","X-Google-Smtp-Source":"ABdhPJyIzjVkNDS3DYOCBVPAowTNj/pnYI/ZjMuuudf07a4aJPJCfbS86Z5KCb5QeNe+HyK90Rlzfm/PODUK5KyIBng=","X-Received":"by 2002:a05:6000:18a4:: with SMTP id\n\tb4mr14894337wri.86.1621438108376; \n\tWed, 19 May 2021 08:28:28 -0700 (PDT)","MIME-Version":"1.0","References":"<20210518100706.578526-1-naush@raspberrypi.com>\n\t<20210518100706.578526-5-naush@raspberrypi.com>","In-Reply-To":"<20210518100706.578526-5-naush@raspberrypi.com>","From":"David Plowman <david.plowman@raspberrypi.com>","Date":"Wed, 19 May 2021 16:28:15 +0100","Message-ID":"<CAHW6GYJDY36AzrkjtLXD66aBF5PpoiHs_bovavsyuddf1O7dbA@mail.gmail.com>","To":"Naushir Patuck <naush@raspberrypi.com>","Content-Type":"text/plain; charset=\"UTF-8\"","Subject":"Re: [libcamera-devel] [PATCH 4/4] ipa: raspberrypi: Switch the\n\tAGC/Lux code 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>","Cc":"libcamera devel <libcamera-devel@lists.libcamera.org>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":17028,"web_url":"https://patchwork.libcamera.org/comment/17028/","msgid":"<CAEmqJPrz_iH0Kj1fYGJmzRUY0M58t+Y+Q6zBL4C100XN=d4jDA@mail.gmail.com>","date":"2021-05-19T15:32:44","subject":"Re: [libcamera-devel] [PATCH 4/4] ipa: raspberrypi: Switch the\n\tAGC/Lux code to use RPiController::Duration","submitter":{"id":34,"url":"https://patchwork.libcamera.org/api/people/34/","name":"Naushir Patuck","email":"naush@raspberrypi.com"},"content":"Hi David,\n\nThank you for your feedback.\n\nOn Wed, 19 May 2021 at 16:28, David Plowman <david.plowman@raspberrypi.com>\nwrote:\n\n> Hi Naush\n>\n> Thanks for all this work!\n>\n> On Tue, 18 May 2021 at 11:09, Naushir Patuck <naush@raspberrypi.com>\n> wrote:\n> >\n> > Convert the core AGC and Lux controller code to use\n> > RPiController::Duration for all exposure time related variables and\n> > calculations.\n>\n> I wonder if I might have tried to keep the AGC and Lux patches\n> separate? Having said that, they both *have* to change as soon as you\n> touch the DeviceStatus, so maybe that would be difficult. Hmm, I think\n> I'll leave that up to you!\n> >\n> > Convert the exposure/shutter time fields in AgcStatus and DeviceStatus\n> > to use RPiController::Duration.\n> >\n> > Signed-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(-)\n> >\n> > diff --git a/src/ipa/raspberrypi/cam_helper.cpp\n> b/src/ipa/raspberrypi/cam_helper.cpp\n> > index 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\n> uint8_t> buffer,\n> >                 return;\n> >         }\n> >\n> > -       deviceStatus.shutter_speed =\n> DurationValue<std::micro>(Exposure(exposureLines));\n> > +       deviceStatus.shutter_speed = Exposure(exposureLines);\n>\n> Much nicer again!\n>\n> >         deviceStatus.analogue_gain = Gain(gainCode);\n> >\n> >         LOG(IPARPI, Debug) << \"Metadata updated - Exposure : \"\n> > diff --git a/src/ipa/raspberrypi/controller/agc_status.h\n> b/src/ipa/raspberrypi/controller/agc_status.h\n> > index 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\n> image's\n> >  // \"agc.status\" metadata.\n> >\n> > @@ -18,17 +20,17 @@ extern \"C\" {\n> >  // ignored until then.\n> >\n> >  struct AgcStatus {\n> > -       double total_exposure_value; // value for all exposure and gain\n> for this image\n> > -       double target_exposure_value; // (unfiltered) target total\n> exposure AGC is aiming for\n> > -       double shutter_time;\n> > +       RPiController::Duration total_exposure_value; // value for all\n> exposure and gain for this image\n> > +       RPiController::Duration target_exposure_value; // (unfiltered)\n> target total exposure AGC is aiming for\n> > +       RPiController::Duration shutter_time;\n> >         double analogue_gain;\n> >         char exposure_mode[32];\n> >         char constraint_mode[32];\n> >         char metering_mode[32];\n> >         double ev;\n> > -       double flicker_period;\n> > +       RPiController::Duration flicker_period;\n> >         int floating_region_enable;\n> > -       double fixed_shutter;\n> > +       RPiController::Duration fixed_shutter;\n> >         double fixed_analogue_gain;\n> >         double digital_gain;\n> >         int locked;\n> > diff --git a/src/ipa/raspberrypi/controller/device_status.h\n> b/src/ipa/raspberrypi/controller/device_status.h\n> > index 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\n> 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> > -       // time shutter is open, in microseconds\n> > -       double shutter_speed;\n> > +       // time shutter is open\n> > +       RPiController::Duration shutter_speed;\n> >         double analogue_gain;\n> >         // 1.0/distance-in-metres, or 0 if unknown\n> >         double lens_position;\n> > diff --git a/src/ipa/raspberrypi/controller/rpi/agc.cpp\n> b/src/ipa/raspberrypi/controller/rpi/agc.cpp\n> > index 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,\n> AgcMeteringMode> &metering_modes,\n> >         return first;\n> >  }\n> >\n> > -static int read_double_list(std::vector<double> &list,\n> > -                           boost::property_tree::ptree const &params)\n> > +static int read_list(std::vector<double> &list,\n> > +                    boost::property_tree::ptree const &params)\n> >  {\n> >         for (auto &p : params)\n> >                 list.push_back(p.second.get_value<double>());\n> >         return list.size();\n> >  }\n> >\n> > +static int read_list(std::vector<Duration> &list,\n> > +                    boost::property_tree::ptree const &params)\n> > +{\n> > +       for (auto &p : params)\n> > +               list.push_back(p.second.get_value<double>() * 1us);\n> > +       return list.size();\n> > +}\n> > +\n>\n> I wonder if there's a template-y way to do these in one go?  (sorry!)\n>\n\nI did consider that, but I do not know how to translate the \"* 1us\" with a\nsimple\ntemplate.  Any ideas?\n\n\n>\n> >  void AgcExposureMode::Read(boost::property_tree::ptree const &params)\n> >  {\n> >         int num_shutters =\n> > -               read_double_list(shutter, params.get_child(\"shutter\"));\n> > -       int num_ags = read_double_list(gain, params.get_child(\"gain\"));\n> > +               read_list(shutter, params.get_child(\"shutter\"));\n> > +       int num_ags = read_list(gain, params.get_child(\"gain\"));\n> >         if (num_shutters < 2 || num_ags < 2)\n> >                 throw std::runtime_error(\n> >                         \"AgcConfig: must have at least two entries in\n> exposure profile\");\n> > @@ -147,7 +156,7 @@ void AgcConfig::Read(boost::property_tree::ptree\n> const &params)\n> >                 params.get<double>(\"fast_reduce_threshold\", 0.4);\n> >         base_ev = params.get<double>(\"base_ev\", 1.0);\n> >         // Start with quite a low value as ramping up is easier than\n> ramping down.\n> > -       default_exposure_time =\n> params.get<double>(\"default_exposure_time\", 1000);\n> > +       default_exposure_time =\n> params.get<double>(\"default_exposure_time\", 1000) * 1us;\n>\n> Mostly I notice that you write, for example, \"1.0us\" rather than \"1us\"\n> as you have here. I take it that it makes no difference, right?\n>\n\nNo difference.  But I will try to be consistent :-)\n\n\n>\n> >         default_analogue_gain =\n> params.get<double>(\"default_analogue_gain\", 1.0);\n> >  }\n> >\n> > @@ -157,7 +166,7 @@ Agc::Agc(Controller *controller)\n> >           frame_count_(0), lock_count_(0),\n> >           last_target_exposure_(0.0),\n> >           ev_(1.0), flicker_period_(0.0),\n> > -         max_shutter_(0), fixed_shutter_(0), fixed_analogue_gain_(0.0)\n> > +         max_shutter_(0.0s), fixed_shutter_(0.0s),\n> fixed_analogue_gain_(0.0)\n> >  {\n> >         memset(&awb_, 0, sizeof(awb_));\n> >         // Setting status_.total_exposure_value_ to zero initially tells\n> us\n> > @@ -203,7 +212,7 @@ void Agc::Pause()\n> >\n> >  void Agc::Resume()\n> >  {\n> > -       fixed_shutter_ = 0;\n> > +       fixed_shutter_ = 0.0s;\n> >         fixed_analogue_gain_ = 0;\n> >  }\n> >\n> > @@ -211,7 +220,7 @@ unsigned int Agc::GetConvergenceFrames() const\n> >  {\n> >         // If shutter and gain have been explicitly set, there is no\n> >         // convergence to happen, so no need to drop any frames - return\n> zero.\n> > -       if (fixed_shutter_ && fixed_analogue_gain_)\n> > +       if (fixed_shutter_ > 0.0s && fixed_analogue_gain_)\n>\n> No implicit bool conversion for Durations, I take it. I notice that\n> throughout this file we sometimes use \"> 0.0s\", sometimes \"!= 0.0s\". I\n> assume that they're effectively interchangeable for us (and that the\n> units don't matter when we compare for zero!), so should we be\n> consistent?\n>\n\nMy next revision with the formal class definition for Duration will have\nan operator bool() so this (and other) statements can now be simplified and\nbe consistent!\n\nRegards,\nNaush\n\n\n>\n> Apart from that nothing much to add, so:\n>\n> Reviewed-by: David Plowman <david.plowman@raspberrypi.com>\n>\n> Thanks!\n> David\n>\n> >                 return 0;\n> >         else\n> >                 return config_.convergence_frames;\n> > @@ -224,17 +233,17 @@ void Agc::SetEv(double ev)\n> >\n> >  void Agc::SetFlickerPeriod(Duration flicker_period)\n> >  {\n> > -       flicker_period_ = DurationValue<std::micro>(flicker_period);\n> > +       flicker_period_ = flicker_period;\n> >  }\n> >\n> >  void Agc::SetMaxShutter(Duration max_shutter)\n> >  {\n> > -       max_shutter_ = DurationValue<std::micro>(max_shutter);\n> > +       max_shutter_ = max_shutter;\n> >  }\n> >\n> >  void Agc::SetFixedShutter(Duration fixed_shutter)\n> >  {\n> > -       fixed_shutter_ = DurationValue<std::micro>(fixed_shutter);\n> > +       fixed_shutter_ = fixed_shutter;\n> >         // Set this in case someone calls Pause() straight after.\n> >         status_.shutter_time = clipShutter(fixed_shutter_);\n> >  }\n> > @@ -266,8 +275,8 @@ void Agc::SwitchMode([[maybe_unused]] CameraMode\n> const &camera_mode,\n> >  {\n> >         housekeepConfig();\n> >\n> > -       double fixed_shutter = clipShutter(fixed_shutter_);\n> > -       if (fixed_shutter != 0.0 && fixed_analogue_gain_ != 0.0) {\n> > +       Duration fixed_shutter = clipShutter(fixed_shutter_);\n> > +       if (fixed_shutter != 0.0s && fixed_analogue_gain_ != 0.0) {\n> >                 // We're going to reset the algorithm here with these\n> fixed values.\n> >\n> >                 fetchAwbStatus(metadata);\n> > @@ -284,7 +293,7 @@ void Agc::SwitchMode([[maybe_unused]] CameraMode\n> const &camera_mode,\n> >                 // Equivalent of divideUpExposure.\n> >                 filtered_.shutter = fixed_shutter;\n> >                 filtered_.analogue_gain = fixed_analogue_gain_;\n> > -       } else if (status_.total_exposure_value) {\n> > +       } else if (status_.total_exposure_value > 0.0s) {\n> >                 // On a mode switch, it's possible the exposure profile\n> could change,\n> >                 // or a fixed exposure/gain might be set so we divide up\n> the exposure/\n> >                 // gain again, but we don't change any target values.\n> > @@ -296,7 +305,7 @@ void Agc::SwitchMode([[maybe_unused]] CameraMode\n> const &camera_mode,\n> >                 // for any that weren't set.\n> >\n> >                 // Equivalent of divideUpExposure.\n> > -               filtered_.shutter = fixed_shutter ? fixed_shutter :\n> config_.default_exposure_time;\n> > +               filtered_.shutter = fixed_shutter > 0.0s ? fixed_shutter\n> : config_.default_exposure_time;\n> >                 filtered_.analogue_gain = fixed_analogue_gain_ ?\n> fixed_analogue_gain_ : config_.default_analogue_gain;\n> >         }\n> >\n> > @@ -308,13 +317,12 @@ void Agc::Prepare(Metadata *image_metadata)\n> >         status_.digital_gain = 1.0;\n> >         fetchAwbStatus(image_metadata); // always fetch it so that\n> Process knows it's been done\n> >\n> > -       if (status_.total_exposure_value) {\n> > +       if (status_.total_exposure_value > 0.0s) {\n> >                 // Process has run, so we have meaningful values.\n> >                 DeviceStatus device_status;\n> >                 if (image_metadata->Get(\"device.status\", device_status)\n> == 0) {\n> > -                       double actual_exposure =\n> device_status.shutter_speed *\n> > -\n> device_status.analogue_gain;\n> > -                       if (actual_exposure) {\n> > +                       Duration actual_exposure =\n> device_status.shutter_speed * device_status.analogue_gain;\n> > +                       if (actual_exposure > 0.0s) {\n> >                                 status_.digital_gain =\n> >                                         status_.total_exposure_value /\n> >                                         actual_exposure;\n> > @@ -370,9 +378,9 @@ void Agc::updateLockStatus(DeviceStatus const\n> &device_status)\n> >         const double RESET_MARGIN = 1.5;\n> >\n> >         // Add 200us to the exposure time error to allow for line\n> quantisation.\n> > -       double exposure_error = last_device_status_.shutter_speed *\n> ERROR_FACTOR + 200;\n> > +       Duration exposure_error = last_device_status_.shutter_speed *\n> ERROR_FACTOR + 200us;\n> >         double gain_error = last_device_status_.analogue_gain *\n> ERROR_FACTOR;\n> > -       double target_error = last_target_exposure_ * ERROR_FACTOR;\n> > +       Duration target_error = last_target_exposure_ * ERROR_FACTOR;\n> >\n> >         // Note that we don't know the exposure/gain limits of the\n> sensor, so\n> >         // the values we keep requesting may be unachievable. For this\n> reason\n> > @@ -462,7 +470,7 @@ void Agc::fetchCurrentExposure(Metadata\n> *image_metadata)\n> >         current_.analogue_gain = device_status->analogue_gain;\n> >         AgcStatus *agc_status =\n> >                 image_metadata->GetLocked<AgcStatus>(\"agc.status\");\n> > -       current_.total_exposure = agc_status ?\n> agc_status->total_exposure_value : 0;\n> > +       current_.total_exposure = agc_status ?\n> agc_status->total_exposure_value : 0s;\n> >         current_.total_exposure_no_dg = current_.shutter *\n> current_.analogue_gain;\n> >  }\n> >\n> > @@ -573,7 +581,7 @@ void Agc::computeGain(bcm2835_isp_stats *statistics,\n> Metadata *image_metadata,\n> >\n> >  void Agc::computeTargetExposure(double gain)\n> >  {\n> > -       if (status_.fixed_shutter != 0.0 && status_.fixed_analogue_gain\n> != 0.0) {\n> > +       if (status_.fixed_shutter != 0.0s && status_.fixed_analogue_gain\n> != 0.0) {\n> >                 // When ag and shutter are both fixed, we need to drive\n> the\n> >                 // total exposure so that we end up with a digital gain\n> of at least\n> >                 // 1/min_colour_gain. Otherwise we'd desaturate channels\n> causing\n> > @@ -588,11 +596,11 @@ void Agc::computeTargetExposure(double gain)\n> >                 target_.total_exposure = current_.total_exposure_no_dg *\n> gain;\n> >                 // The final target exposure is also limited to what the\n> exposure\n> >                 // mode allows.\n> > -               double max_shutter = status_.fixed_shutter != 0.0\n> > +               Duration max_shutter = status_.fixed_shutter != 0.0s\n> >                                    ? status_.fixed_shutter\n> >                                    : exposure_mode_->shutter.back();\n> >                 max_shutter = clipShutter(max_shutter);\n> > -               double max_total_exposure =\n> > +               Duration max_total_exposure =\n> >                         max_shutter *\n> >                         (status_.fixed_analogue_gain != 0.0\n> >                                  ? status_.fixed_analogue_gain\n> > @@ -634,10 +642,10 @@ void Agc::filterExposure(bool desaturate)\n> >         double speed = config_.speed;\n> >         // AGC adapts instantly if both shutter and gain are directly\n> specified\n> >         // or we're in the startup phase.\n> > -       if ((status_.fixed_shutter && status_.fixed_analogue_gain) ||\n> > +       if ((status_.fixed_shutter > 0.0s &&\n> status_.fixed_analogue_gain) ||\n> >             frame_count_ <= config_.startup_frames)\n> >                 speed = 1.0;\n> > -       if (filtered_.total_exposure == 0.0) {\n> > +       if (filtered_.total_exposure == 0.0s) {\n> >                 filtered_.total_exposure = target_.total_exposure;\n> >                 filtered_.total_exposure_no_dg =\n> target_.total_exposure_no_dg;\n> >         } else {\n> > @@ -674,9 +682,10 @@ void Agc::divideUpExposure()\n> >         // Sending the fixed shutter/gain cases through the same code\n> may seem\n> >         // unnecessary, but it will make more sense when extend this to\n> cover\n> >         // variable aperture.\n> > -       double exposure_value = filtered_.total_exposure_no_dg;\n> > -       double shutter_time, analogue_gain;\n> > -       shutter_time = status_.fixed_shutter != 0.0\n> > +       Duration exposure_value = filtered_.total_exposure_no_dg;\n> > +       Duration shutter_time;\n> > +       double analogue_gain;\n> > +       shutter_time = status_.fixed_shutter != 0.0s\n> >                                ? status_.fixed_shutter\n> >                                : exposure_mode_->shutter[0];\n> >         shutter_time = clipShutter(shutter_time);\n> > @@ -686,8 +695,8 @@ void Agc::divideUpExposure()\n> >         if (shutter_time * analogue_gain < exposure_value) {\n> >                 for (unsigned int stage = 1;\n> >                      stage < exposure_mode_->gain.size(); stage++) {\n> > -                       if (status_.fixed_shutter == 0.0) {\n> > -                               double stage_shutter =\n> > +                       if (status_.fixed_shutter == 0.0s) {\n> > +                               Duration stage_shutter =\n> >\n>  clipShutter(exposure_mode_->shutter[stage]);\n> >                                 if (stage_shutter * analogue_gain >=\n> >                                     exposure_value) {\n> > @@ -713,12 +722,12 @@ void Agc::divideUpExposure()\n> >                            << analogue_gain;\n> >         // Finally adjust shutter time for flicker avoidance (require\n> both\n> >         // shutter and gain not to be fixed).\n> > -       if (status_.fixed_shutter == 0.0 &&\n> > +       if (status_.fixed_shutter == 0.0s &&\n> >             status_.fixed_analogue_gain == 0.0 &&\n> > -           status_.flicker_period != 0.0) {\n> > -               int flicker_periods = shutter_time /\n> status_.flicker_period;\n> > -               if (flicker_periods > 0) {\n> > -                       double new_shutter_time = flicker_periods *\n> status_.flicker_period;\n> > +           status_.flicker_period != 0.0s) {\n> > +               double flicker_periods = shutter_time /\n> status_.flicker_period;\n> > +               if (flicker_periods > 0.0) {\n> > +                       Duration new_shutter_time = flicker_periods *\n> status_.flicker_period;\n> >                         analogue_gain *= shutter_time / new_shutter_time;\n> >                         // We should still not allow the ag to go over\n> the\n> >                         // largest value in the exposure mode. Note that\n> this\n> > @@ -738,7 +747,7 @@ void Agc::divideUpExposure()\n> >  void Agc::writeAndFinish(Metadata *image_metadata, bool desaturate)\n> >  {\n> >         status_.total_exposure_value = filtered_.total_exposure;\n> > -       status_.target_exposure_value = desaturate ? 0 :\n> target_.total_exposure_no_dg;\n> > +       status_.target_exposure_value = desaturate ? 0s :\n> target_.total_exposure_no_dg;\n> >         status_.shutter_time = filtered_.shutter;\n> >         status_.analogue_gain = filtered_.analogue_gain;\n> >         // Write to metadata as well, in case anyone wants to update the\n> camera\n> > @@ -750,9 +759,9 @@ void Agc::writeAndFinish(Metadata *image_metadata,\n> bool desaturate)\n> >                            << \" analogue gain \" <<\n> filtered_.analogue_gain;\n> >  }\n> >\n> > -double Agc::clipShutter(double shutter)\n> > +Duration Agc::clipShutter(Duration shutter)\n> >  {\n> > -       if (max_shutter_)\n> > +       if (max_shutter_ > 0.0s)\n> >                 shutter = std::min(shutter, max_shutter_);\n> >         return shutter;\n> >  }\n> > diff --git a/src/ipa/raspberrypi/controller/rpi/agc.hpp\n> b/src/ipa/raspberrypi/controller/rpi/agc.hpp\n> > index 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> >         double weights[AGC_STATS_SIZE];\n> >         void Read(boost::property_tree::ptree const &params);\n> >  };\n> >\n> >  struct AgcExposureMode {\n> > -       std::vector<double> shutter;\n> > +       std::vector<Duration> shutter;\n> >         std::vector<double> gain;\n> >         void Read(boost::property_tree::ptree const &params);\n> >  };\n> > @@ -61,7 +63,7 @@ struct AgcConfig {\n> >         std::string default_exposure_mode;\n> >         std::string default_constraint_mode;\n> >         double base_ev;\n> > -       double default_exposure_time;\n> > +       Duration default_exposure_time;\n> >         double default_analogue_gain;\n> >  };\n> >\n> > @@ -101,19 +103,19 @@ private:\n> >         void filterExposure(bool desaturate);\n> >         void divideUpExposure();\n> >         void writeAndFinish(Metadata *image_metadata, bool desaturate);\n> > -       double clipShutter(double shutter);\n> > +       Duration clipShutter(Duration shutter);\n> >         AgcMeteringMode *metering_mode_;\n> >         AgcExposureMode *exposure_mode_;\n> >         AgcConstraintMode *constraint_mode_;\n> >         uint64_t frame_count_;\n> >         AwbStatus awb_;\n> >         struct ExposureValues {\n> > -               ExposureValues() : shutter(0), analogue_gain(0),\n> > -                                  total_exposure(0),\n> total_exposure_no_dg(0) {}\n> > -               double shutter;\n> > +               ExposureValues() : shutter(0.0s), analogue_gain(0),\n> > +                                  total_exposure(0.0s),\n> total_exposure_no_dg(0.0s) {}\n> > +               Duration shutter;\n> >                 double analogue_gain;\n> > -               double total_exposure;\n> > -               double total_exposure_no_dg; // without digital gain\n> > +               Duration total_exposure;\n> > +               Duration total_exposure_no_dg; // without digital gain\n> >         };\n> >         ExposureValues current_;  // values for the current frame\n> >         ExposureValues target_;   // calculate the values we want here\n> > @@ -121,15 +123,15 @@ private:\n> >         AgcStatus status_;\n> >         int lock_count_;\n> >         DeviceStatus last_device_status_;\n> > -       double last_target_exposure_;\n> > +       Duration last_target_exposure_;\n> >         // Below here the \"settings\" that applications can change.\n> >         std::string metering_mode_name_;\n> >         std::string exposure_mode_name_;\n> >         std::string constraint_mode_name_;\n> >         double ev_;\n> > -       double flicker_period_;\n> > -       double max_shutter_;\n> > -       double fixed_shutter_;\n> > +       Duration flicker_period_;\n> > +       Duration max_shutter_;\n> > +       Duration fixed_shutter_;\n> >         double fixed_analogue_gain_;\n> >  };\n> >\n> > diff --git a/src/ipa/raspberrypi/controller/rpi/lux.cpp\n> b/src/ipa/raspberrypi/controller/rpi/lux.cpp\n> > index 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> >         reference_shutter_speed_ =\n> > -               params.get<double>(\"reference_shutter_speed\");\n> > +               params.get<double>(\"reference_shutter_speed\") * 1us;\n> >         reference_gain_ = params.get<double>(\"reference_gain\");\n> >         reference_aperture_ = params.get<double>(\"reference_aperture\",\n> 1.0);\n> >         reference_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> >         // set some initial values to shut the compiler up\n> > -       DeviceStatus device_status =\n> > -               { .shutter_speed = 1.0,\n> > -                 .analogue_gain = 1.0,\n> > -                 .lens_position = 0.0,\n> > -                 .aperture = 0.0,\n> > -                 .flash_intensity = 0.0 };\n> > +       DeviceStatus device_status = { .shutter_speed = 1.0ms,\n> > +                                      .analogue_gain = 1.0,\n> > +                                      .lens_position = 0.0,\n> > +                                      .aperture = 0.0,\n> > +                                      .flash_intensity = 0.0 };\n> >         if (image_metadata->Get(\"device.status\", device_status) == 0) {\n> >                 double current_gain = device_status.analogue_gain;\n> > -               double current_shutter_speed =\n> device_status.shutter_speed;\n> >                 double current_aperture = device_status.aperture;\n> >                 if (current_aperture == 0)\n> >                         current_aperture = current_aperture_;\n> > @@ -83,7 +82,7 @@ void Lux::Process(StatisticsPtr &stats, Metadata\n> *image_metadata)\n> >                 double current_Y = sum / (double)num + .5;\n> >                 double gain_ratio = reference_gain_ / current_gain;\n> >                 double shutter_speed_ratio =\n> > -                       reference_shutter_speed_ / current_shutter_speed;\n> > +                       reference_shutter_speed_ /\n> device_status.shutter_speed;\n> >                 double aperture_ratio = reference_aperture_ /\n> current_aperture;\n> >                 double Y_ratio = current_Y * (65536 / num_bins) /\n> reference_Y_;\n> >                 double estimated_lux = shutter_speed_ratio * gain_ratio *\n> > diff --git a/src/ipa/raspberrypi/controller/rpi/lux.hpp\n> b/src/ipa/raspberrypi/controller/rpi/lux.hpp\n> > index 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> >         // These values define the conditions of the reference image,\n> against\n> >         // which we compare the new image.\n> > -       double reference_shutter_speed_; // in micro-seconds\n> > +       Duration reference_shutter_speed_;\n> >         double reference_gain_;\n> >         double reference_aperture_; // units of 1/f\n> >         double reference_Y_; // out of 65536\n> > diff --git a/src/ipa/raspberrypi/raspberrypi.cpp\n> b/src/ipa/raspberrypi/raspberrypi.cpp\n> > index 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,\n> ipa::RPi::StartConfig *startConf\n> >\n> >         /* SwitchMode may supply updated exposure/gain values to use. */\n> >         AgcStatus agcStatus;\n> > -       agcStatus.shutter_time = 0.0;\n> > +       agcStatus.shutter_time = 0.0s;\n> >         agcStatus.analogue_gain = 0.0;\n> >\n> >         metadata.Get(\"agc.status\", agcStatus);\n> > -       if (agcStatus.shutter_time != 0.0 && agcStatus.analogue_gain !=\n> 0.0) {\n> > +       if (agcStatus.shutter_time != 0.0s && agcStatus.analogue_gain !=\n> 0.0) {\n> >                 ControlList ctrls(sensorCtrls_);\n> >                 applyAGC(&agcStatus, ctrls);\n> >                 startConfig->controls = std::move(ctrls);\n> > @@ -394,7 +394,7 @@ int IPARPi::configure(const CameraSensorInfo\n> &sensorInfo,\n> >                 /* Supply initial values for gain and exposure. */\n> >                 ControlList ctrls(sensorCtrls_);\n> >                 AgcStatus agcStatus;\n> > -               agcStatus.shutter_time =\n> DurationValue<std::micro>(DefaultExposureTime);\n> > +               agcStatus.shutter_time = DefaultExposureTime;\n> >                 agcStatus.analogue_gain = DefaultAnalogueGain;\n> >                 applyAGC(&agcStatus, ctrls);\n> >\n> > @@ -466,7 +466,8 @@ void IPARPi::reportMetadata()\n> >          */\n> >         DeviceStatus *deviceStatus =\n> rpiMetadata_.GetLocked<DeviceStatus>(\"device.status\");\n> >         if (deviceStatus) {\n> > -               libcameraMetadata_.set(controls::ExposureTime,\n> deviceStatus->shutter_speed);\n> > +               libcameraMetadata_.set(controls::ExposureTime,\n> > +\n> DurationValue<std::micro>(deviceStatus->shutter_speed));\n> >                 libcameraMetadata_.set(controls::AnalogueGain,\n> deviceStatus->analogue_gain);\n> >         }\n> >\n> > @@ -1019,7 +1020,7 @@ void IPARPi::fillDeviceStatus(const ControlList\n> &sensorControls)\n> >         int32_t exposureLines =\n> sensorControls.get(V4L2_CID_EXPOSURE).get<int32_t>();\n> >         int32_t gainCode =\n> sensorControls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>();\n> >\n> > -       deviceStatus.shutter_speed =\n> DurationValue<std::micro>(helper_->Exposure(exposureLines));\n> > +       deviceStatus.shutter_speed = helper_->Exposure(exposureLines);\n> >         deviceStatus.analogue_gain = helper_->Gain(gainCode);\n> >\n> >         LOG(IPARPI, Debug) << \"Metadata - Exposure : \"\n> > @@ -1105,7 +1106,7 @@ void IPARPi::applyAGC(const struct AgcStatus\n> *agcStatus, ControlList &ctrls)\n> >         int32_t gainCode = helper_->GainCode(agcStatus->analogue_gain);\n> >\n> >         /* GetVBlanking might clip exposure time to the fps limits. */\n> > -       Duration exposure = agcStatus->shutter_time * 1.0us;\n> > +       Duration exposure = agcStatus->shutter_time;\n> >         int32_t vblanking = helper_->GetVBlanking(exposure,\n> minFrameDuration_, maxFrameDuration_);\n> >         int32_t exposureLines = helper_->ExposureLines(exposure);\n> >\n> > --\n> > 2.25.1\n> >\n>","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 D5B0FC31FF\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 19 May 2021 15:33:04 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id E25176891F;\n\tWed, 19 May 2021 17:33:03 +0200 (CEST)","from mail-lj1-x230.google.com (mail-lj1-x230.google.com\n\t[IPv6:2a00:1450:4864:20::230])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id B864568915\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 19 May 2021 17:33:01 +0200 (CEST)","by mail-lj1-x230.google.com with SMTP id p20so16142232ljj.8\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 19 May 2021 08:33:01 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=raspberrypi.com header.i=@raspberrypi.com\n\theader.b=\"OhC/we3e\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google;\n\th=mime-version:references:in-reply-to:from:date:message-id:subject:to\n\t:cc; bh=d1rnXZJ0tNmkqZqP4i0sjzUvlY5FGfU4PHum0X4UkGo=;\n\tb=OhC/we3en1Y9A6cYfx23QUBHqHYeKB58bWlA+dnsqcTee9sd45NCOvplzY2yfgiiAA\n\tNN9if/zYBDndCHvXqm92h+ehiLUc97/luS8bsTD/3ZZkKyGxVlDjR5a2HQzqUL6GatEe\n\tOlvUDbxpwRAH8qXyfw7rSyOiVT/ZVBQSxhyAMQfNwKkaZQf0/mjcpmc6guN8AT+csRZG\n\thnnnEnXWNKGghr5jsQwFCVwdpm8YfDZD6wbkjl6hVVcu2XRMUo26HwVy+tvtsHjeKTKF\n\tEEcj+8Ez1qTXXSUbql8rM1DzIniVR2GKw15eOd92Wpu3RMtsx6FcZn1+Kfb1wyTIMnSF\n\tpywA==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:mime-version:references:in-reply-to:from:date\n\t:message-id:subject:to:cc;\n\tbh=d1rnXZJ0tNmkqZqP4i0sjzUvlY5FGfU4PHum0X4UkGo=;\n\tb=goRYJ0dmajGderAhb72BJclO6PdT0COrm2Xqahxk3EudnzCvswd8rzy0L1dCY1ecU2\n\tV83Iq43JIb5BIMdpFp17MQTA2yQLvonID5Qico/zria5n1NyMAFtdUKmCuwuSEIgfttp\n\t0Us68eFVE4dI0FKqJUE4OoVFLDQwqTf7gQACC0fRYOymfEwEZ5g4xkAy0YsFPV+16YBc\n\twaDdn20c3z0OvvXJi1od+FcvbxTGQVevIP3U/xac9HbDithik5RhaDmJywuhUC8BzHtw\n\tA3EP5wb1v5p80+x29N821XmNdlPgSJST9XpZBWvcEr44qnwbKGIlHbTxjzaUNjE1B/l/\n\t88Ig==","X-Gm-Message-State":"AOAM531EhJzDbSVJATr1VESUxpMGLqLPufFW9VZmcG8aTslD1mQT0tnv\n\t4bAE9/icGn0OF6a09E30mFsa2wKaZnM+moT6Ym2F5tyAbs4=","X-Google-Smtp-Source":"ABdhPJwdOIYQsPwyqXqxnffxYvk0Ym3/hgVEcR/rLfT+nVRTDpLjXP6LlifZ+vSOWl/JTxOJlqhiDqg/+r4f+6rZqlg=","X-Received":"by 2002:a2e:9b58:: with SMTP id\n\to24mr9145514ljj.253.1621438380992; \n\tWed, 19 May 2021 08:33:00 -0700 (PDT)","MIME-Version":"1.0","References":"<20210518100706.578526-1-naush@raspberrypi.com>\n\t<20210518100706.578526-5-naush@raspberrypi.com>\n\t<CAHW6GYJDY36AzrkjtLXD66aBF5PpoiHs_bovavsyuddf1O7dbA@mail.gmail.com>","In-Reply-To":"<CAHW6GYJDY36AzrkjtLXD66aBF5PpoiHs_bovavsyuddf1O7dbA@mail.gmail.com>","From":"Naushir Patuck <naush@raspberrypi.com>","Date":"Wed, 19 May 2021 16:32:44 +0100","Message-ID":"<CAEmqJPrz_iH0Kj1fYGJmzRUY0M58t+Y+Q6zBL4C100XN=d4jDA@mail.gmail.com>","To":"David Plowman <david.plowman@raspberrypi.com>","Content-Type":"multipart/alternative; boundary=\"000000000000b9807d05c2b08aee\"","Subject":"Re: [libcamera-devel] [PATCH 4/4] ipa: raspberrypi: Switch the\n\tAGC/Lux code 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>","Cc":"libcamera devel <libcamera-devel@lists.libcamera.org>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]