summaryrefslogtreecommitdiff
path: root/src/libcamera/pipeline/raspberrypi/delayed_controls.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcamera/pipeline/raspberrypi/delayed_controls.cpp')
-rw-r--r--src/libcamera/pipeline/raspberrypi/delayed_controls.cpp293
1 files changed, 0 insertions, 293 deletions
diff --git a/src/libcamera/pipeline/raspberrypi/delayed_controls.cpp b/src/libcamera/pipeline/raspberrypi/delayed_controls.cpp
deleted file mode 100644
index 3db92e7d..00000000
--- a/src/libcamera/pipeline/raspberrypi/delayed_controls.cpp
+++ /dev/null
@@ -1,293 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2020, Raspberry Pi Ltd
- *
- * delayed_controls.cpp - Helper to deal with controls that take effect with a delay
- *
- * Note: This has been forked from the libcamera core implementation.
- */
-
-#include "delayed_controls.h"
-
-#include <libcamera/base/log.h>
-
-#include <libcamera/controls.h>
-
-#include "libcamera/internal/v4l2_device.h"
-
-/**
- * \file delayed_controls.h
- * \brief Helper to deal with controls that take effect with a delay
- */
-
-namespace libcamera {
-
-LOG_DEFINE_CATEGORY(RPiDelayedControls)
-
-namespace RPi {
-
-/**
- * \class DelayedControls
- * \brief Helper to deal with controls that take effect with a delay
- *
- * Some sensor controls take effect with a delay as the sensor needs time to
- * adjust, for example exposure and analog gain. This is a helper class to deal
- * with such controls and the intended users are pipeline handlers.
- *
- * The idea is to extend the concept of the buffer depth of a pipeline the
- * application needs to maintain to also cover controls. Just as with buffer
- * depth if the application keeps the number of requests queued above the
- * control depth the controls are guaranteed to take effect for the correct
- * request. The control depth is determined by the control with the greatest
- * delay.
- */
-
-/**
- * \struct DelayedControls::ControlParams
- * \brief Parameters associated with controls handled by the \a DelayedControls
- * helper class
- *
- * \var ControlParams::delay
- * \brief Frame delay from setting the control on a sensor device to when it is
- * consumed during framing.
- *
- * \var ControlParams::priorityWrite
- * \brief Flag to indicate that this control must be applied ahead of, and
- * separately from the other controls.
- *
- * Typically set for the \a V4L2_CID_VBLANK control so that the device driver
- * does not reject \a V4L2_CID_EXPOSURE control values that may be outside of
- * the existing vertical blanking specified bounds, but are within the new
- * blanking bounds.
- */
-
-/**
- * \brief Construct a DelayedControls instance
- * \param[in] device The V4L2 device the controls have to be applied to
- * \param[in] controlParams Map of the numerical V4L2 control ids to their
- * associated control parameters.
- *
- * The control parameters comprise of delays (in frames) and a priority write
- * flag. If this flag is set, the relevant control is written separately from,
- * and ahead of the rest of the batched controls.
- *
- * Only controls specified in \a controlParams are handled. If it's desired to
- * mix delayed controls and controls that take effect immediately the immediate
- * controls must be listed in the \a controlParams map with a delay value of 0.
- */
-DelayedControls::DelayedControls(V4L2Device *device,
- const std::unordered_map<uint32_t, ControlParams> &controlParams)
- : device_(device), maxDelay_(0)
-{
- const ControlInfoMap &controls = device_->controls();
-
- /*
- * Create a map of control ids to delays for controls exposed by the
- * device.
- */
- for (auto const &param : controlParams) {
- auto it = controls.find(param.first);
- if (it == controls.end()) {
- LOG(RPiDelayedControls, Error)
- << "Delay request for control id "
- << utils::hex(param.first)
- << " but control is not exposed by device "
- << device_->deviceNode();
- continue;
- }
-
- const ControlId *id = it->first;
-
- controlParams_[id] = param.second;
-
- LOG(RPiDelayedControls, Debug)
- << "Set a delay of " << controlParams_[id].delay
- << " and priority write flag " << controlParams_[id].priorityWrite
- << " for " << id->name();
-
- maxDelay_ = std::max(maxDelay_, controlParams_[id].delay);
- }
-
- reset(0);
-}
-
-/**
- * \brief Reset state machine
- *
- * Resets the state machine to a starting position based on control values
- * retrieved from the device.
- */
-void DelayedControls::reset(unsigned int cookie)
-{
- queueCount_ = 1;
- writeCount_ = 0;
- cookies_[0] = cookie;
-
- /* Retrieve control as reported by the device. */
- std::vector<uint32_t> ids;
- for (auto const &param : controlParams_)
- ids.push_back(param.first->id());
-
- ControlList controls = device_->getControls(ids);
-
- /* Seed the control queue with the controls reported by the device. */
- values_.clear();
- for (const auto &ctrl : controls) {
- const ControlId *id = device_->controls().idmap().at(ctrl.first);
- /*
- * Do not mark this control value as updated, it does not need
- * to be written to to device on startup.
- */
- values_[id][0] = Info(ctrl.second, false);
- }
-}
-
-/**
- * \brief Push a set of controls on the queue
- * \param[in] controls List of controls to add to the device queue
- *
- * Push a set of controls to the control queue. This increases the control queue
- * depth by one.
- *
- * \returns true if \a controls are accepted, or false otherwise
- */
-bool DelayedControls::push(const ControlList &controls, const unsigned int cookie)
-{
- /* Copy state from previous frame. */
- for (auto &ctrl : values_) {
- Info &info = ctrl.second[queueCount_];
- info = values_[ctrl.first][queueCount_ - 1];
- info.updated = false;
- }
-
- /* Update with new controls. */
- const ControlIdMap &idmap = device_->controls().idmap();
- for (const auto &control : controls) {
- const auto &it = idmap.find(control.first);
- if (it == idmap.end()) {
- LOG(RPiDelayedControls, Warning)
- << "Unknown control " << control.first;
- return false;
- }
-
- const ControlId *id = it->second;
-
- if (controlParams_.find(id) == controlParams_.end())
- return false;
-
- Info &info = values_[id][queueCount_];
-
- info = Info(control.second);
-
- LOG(RPiDelayedControls, Debug)
- << "Queuing " << id->name()
- << " to " << info.toString()
- << " at index " << queueCount_;
- }
-
- cookies_[queueCount_] = cookie;
- queueCount_++;
-
- return true;
-}
-
-/**
- * \brief Read back controls in effect at a sequence number
- * \param[in] sequence The sequence number to get controls for
- *
- * Read back what controls where in effect at a specific sequence number. The
- * history is a ring buffer of 16 entries where new and old values coexist. It's
- * the callers responsibility to not read too old sequence numbers that have been
- * pushed out of the history.
- *
- * Historic values are evicted by pushing new values onto the queue using
- * push(). The max history from the current sequence number that yields valid
- * values are thus 16 minus number of controls pushed.
- *
- * \return The controls at \a sequence number
- */
-std::pair<ControlList, unsigned int> DelayedControls::get(uint32_t sequence)
-{
- unsigned int index = std::max<int>(0, sequence - maxDelay_);
-
- ControlList out(device_->controls());
- for (const auto &ctrl : values_) {
- const ControlId *id = ctrl.first;
- const Info &info = ctrl.second[index];
-
- out.set(id->id(), info);
-
- LOG(RPiDelayedControls, Debug)
- << "Reading " << id->name()
- << " to " << info.toString()
- << " at index " << index;
- }
-
- return { out, cookies_[index] };
-}
-
-/**
- * \brief Inform DelayedControls of the start of a new frame
- * \param[in] sequence Sequence number of the frame that started
- *
- * Inform the state machine that a new frame has started and of its sequence
- * number. Any user of these helpers is responsible to inform the helper about
- * the start of any frame. This can be connected with ease to the start of a
- * exposure (SOE) V4L2 event.
- */
-void DelayedControls::applyControls(uint32_t sequence)
-{
- LOG(RPiDelayedControls, Debug) << "frame " << sequence << " started";
-
- /*
- * Create control list peeking ahead in the value queue to ensure
- * values are set in time to satisfy the sensor delay.
- */
- ControlList out(device_->controls());
- for (auto &ctrl : values_) {
- const ControlId *id = ctrl.first;
- unsigned int delayDiff = maxDelay_ - controlParams_[id].delay;
- unsigned int index = std::max<int>(0, writeCount_ - delayDiff);
- Info &info = ctrl.second[index];
-
- if (info.updated) {
- if (controlParams_[id].priorityWrite) {
- /*
- * This control must be written now, it could
- * affect validity of the other controls.
- */
- ControlList priority(device_->controls());
- priority.set(id->id(), info);
- device_->setControls(&priority);
- } else {
- /*
- * Batch up the list of controls and write them
- * at the end of the function.
- */
- out.set(id->id(), info);
- }
-
- LOG(RPiDelayedControls, Debug)
- << "Setting " << id->name()
- << " to " << info.toString()
- << " at index " << index;
-
- /* Done with this update, so mark as completed. */
- info.updated = false;
- }
- }
-
- writeCount_ = sequence + 1;
-
- while (writeCount_ > queueCount_) {
- LOG(RPiDelayedControls, Debug)
- << "Queue is empty, auto queue no-op.";
- push({}, cookies_[queueCount_ - 1]);
- }
-
- device_->setControls(&out);
-}
-
-} /* namespace RPi */
-
-} /* namespace libcamera */