@@ -233,25 +233,6 @@ int32_t IpaBase::configure(const IPACameraSensorInfo &sensorInfo, const ConfigPa
agcStatus.analogueGain = defaultAnalogueGain;
applyAGC(&agcStatus, ctrls);
- /*
- * Set the lens to the default (typically hyperfocal) position
- * on first start.
- */
- if (lensPresent_) {
- RPiController::AfAlgorithm *af =
- dynamic_cast<RPiController::AfAlgorithm *>(controller_.getAlgorithm("af"));
-
- if (af) {
- float defaultPos =
- ipaAfControls.at(&controls::LensPosition).def().get<float>();
- ControlList lensCtrl(lensCtrls_);
- int32_t hwpos;
-
- af->setLensPosition(defaultPos, &hwpos);
- lensCtrl.set(V4L2_CID_FOCUS_ABSOLUTE, hwpos);
- result->lensControls = std::move(lensCtrl);
- }
- }
}
result->sensorControls = std::move(ctrls);
@@ -281,8 +262,20 @@ int32_t IpaBase::configure(const IPACameraSensorInfo &sensorInfo, const ConfigPa
ctrlMap.merge(ControlInfoMap::Map(ipaColourControls));
/* Declare Autofocus controls, only if we have a controllable lens */
- if (lensPresent_)
+ if (lensPresent_) {
ctrlMap.merge(ControlInfoMap::Map(ipaAfControls));
+ RPiController::AfAlgorithm *af =
+ dynamic_cast<RPiController::AfAlgorithm *>(controller_.getAlgorithm("af"));
+ if (af) {
+ double min, max, dflt;
+ af->getLensLimits(min, max);
+ dflt = af->getDefaultLensPosition();
+ ctrlMap[&controls::LensPosition] =
+ ControlInfo(static_cast<float>(min),
+ static_cast<float>(max),
+ static_cast<float>(dflt));
+ }
+ }
result->controlInfo = ControlInfoMap(std::move(ctrlMap), controls::controls);
@@ -320,6 +313,26 @@ void IpaBase::start(const ControlList &controls, StartResult *result)
/* Make a note of this as it tells us the HDR status of the first few frames. */
hdrStatus_ = agcStatus.hdr;
+ /*
+ * AF: If no lens position was specified, drive lens to a default position.
+ * This had to be deferred (not initialised by a constructor) until here
+ * to ensure that exactly ONE starting position is sent to the lens driver.
+ * It should be the static API default, not dependent on AF range or mode.
+ */
+ if (firstStart_ && lensPresent_) {
+ RPiController::AfAlgorithm *af = dynamic_cast<RPiController::AfAlgorithm *>(
+ controller_.getAlgorithm("af"));
+ if (af && !af->getLensPosition()) {
+ int32_t hwpos;
+ double pos = af->getDefaultLensPosition();
+ if (af->setLensPosition(pos, &hwpos, true)) {
+ ControlList lensCtrls(lensCtrls_);
+ lensCtrls.set(V4L2_CID_FOCUS_ABSOLUTE, hwpos);
+ setLensControls.emit(lensCtrls);
+ }
+ }
+ }
+
/*
* Initialise frame counts, and decide how many frames must be hidden or
* "mistrusted", which depends on whether this is a startup from cold,
@@ -33,6 +33,10 @@ public:
*
* getMode() is provided mainly for validating controls.
* getLensPosition() is provided for populating DeviceStatus.
+ *
+ * getDefaultlensPosition() and getLensLimits() were added for
+ * populating ControlInfoMap. They return the static API limits
+ * which should be independent of the current range or mode.
*/
enum AfRange { AfRangeNormal = 0,
@@ -66,7 +70,9 @@ public:
}
virtual void setMode(AfMode mode) = 0;
virtual AfMode getMode() const = 0;
- virtual bool setLensPosition(double dioptres, int32_t *hwpos) = 0;
+ virtual double getDefaultLensPosition() const = 0;
+ virtual void getLensLimits(double &min, double &max) const = 0;
+ virtual bool setLensPosition(double dioptres, int32_t *hwpos, bool force = false) = 0;
virtual std::optional<double> getLensPosition() const = 0;
virtual void triggerScan() = 0;
virtual void cancelScan() = 0;
@@ -715,11 +715,23 @@ void Af::setWindows(libcamera::Span<libcamera::Rectangle const> const &wins)
invalidateWeights();
}
-bool Af::setLensPosition(double dioptres, int *hwpos)
+double Af::getDefaultLensPosition() const
+{
+ return cfg_.ranges[AfRangeNormal].focusDefault;
+}
+
+void Af::getLensLimits(double &min, double &max) const
+{
+ /* Limits for manual focus are set by map, not by ranges */
+ min = cfg_.map.domain().start;
+ max = cfg_.map.domain().end;
+}
+
+bool Af::setLensPosition(double dioptres, int *hwpos, bool force)
{
bool changed = false;
- if (mode_ == AfModeManual) {
+ if (mode_ == AfModeManual || force) {
LOG(RPiAf, Debug) << "setLensPosition: " << dioptres;
ftarget_ = cfg_.map.domain().clamp(dioptres);
changed = !(initted_ && fsmooth_ == ftarget_);
@@ -54,7 +54,9 @@ public:
void setWindows(libcamera::Span<libcamera::Rectangle const> const &wins) override;
void setMode(AfMode mode) override;
AfMode getMode() const override;
- bool setLensPosition(double dioptres, int32_t *hwpos) override;
+ double getDefaultLensPosition() const override;
+ void getLensLimits(double &min, double &max) const override;
+ bool setLensPosition(double dioptres, int32_t *hwpos, bool force) override;
std::optional<double> getLensPosition() const override;
void triggerScan() override;
void cancelScan() override;