blob: 03ac6345247c7e04d835ca110493adba05953f5c [file] [log] [blame]
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2019, Google Inc.
*
* controls.cpp - Control handling
*/
#include <libcamera/controls.h>
#include <iomanip>
#include <sstream>
#include <string>
#include <string.h>
#include <libcamera/base/log.h>
#include <libcamera/base/utils.h>
#include "libcamera/internal/control_validator.h"
/**
* \file controls.h
* \brief Framework to manage controls related to an object
*
* A control is a mean to govern or influence the operation of an object, and in
* particular of a camera. Every control is defined by a unique numerical ID, a
* name string and the data type of the value it stores. The libcamera API
* defines a set of standard controls in the libcamera::controls namespace, as
* a set of instances of the Control class.
*
* The main way for applications to interact with controls is through the
* ControlList stored in the Request class:
*
* \code{.cpp}
* Request *req = ...;
* ControlList &controls = req->controls();
* controls->set(controls::AwbEnable, false);
* controls->set(controls::ManualExposure, 1000);
*
* ...
*
* int32_t exposure = controls->get(controls::ManualExposure);
* \endcode
*
* The ControlList::get() and ControlList::set() functions automatically deduce
* the data type based on the control.
*/
namespace libcamera {
LOG_DEFINE_CATEGORY(Controls)
namespace {
static constexpr size_t ControlValueSize[] = {
[ControlTypeNone] = 0,
[ControlTypeBool] = sizeof(bool),
[ControlTypeByte] = sizeof(uint8_t),
[ControlTypeInteger32] = sizeof(int32_t),
[ControlTypeInteger64] = sizeof(int64_t),
[ControlTypeFloat] = sizeof(float),
[ControlTypeString] = sizeof(char),
[ControlTypeRectangle] = sizeof(Rectangle),
[ControlTypeSize] = sizeof(Size),
};
} /* namespace */
/**
* \enum ControlType
* \brief Define the data type of a Control
* \var ControlTypeNone
* Invalid type, for empty values
* \var ControlTypeBool
* The control stores a boolean value
* \var ControlTypeByte
* The control stores a byte value as an unsigned 8-bit integer
* \var ControlTypeInteger32
* The control stores a 32-bit integer value
* \var ControlTypeInteger64
* The control stores a 64-bit integer value
* \var ControlTypeFloat
* The control stores a 32-bit floating point value
* \var ControlTypeString
* The control stores a string value as an array of char
*/
/**
* \class ControlValue
* \brief Abstract type representing the value of a control
*/
/** \todo Revisit the ControlValue layout when stabilizing the ABI */
static_assert(sizeof(ControlValue) == 16, "Invalid size of ControlValue class");
/**
* \brief Construct an empty ControlValue.
*/
ControlValue::ControlValue()
: type_(ControlTypeNone), isArray_(false), numElements_(0)
{
}
/**
* \fn template<typename T> T ControlValue::ControlValue(const T &value)
* \brief Construct a ControlValue of type T
* \param[in] value Initial value
*
* This function constructs a new instance of ControlValue and stores the \a
* value inside it. If the type \a T is equivalent to Span<R>, the instance
* stores an array of values of type \a R. Otherwise the instance stores a
* single value of type \a T. The numElements() and type() are updated to
* reflect the stored value.
*/
void ControlValue::release()
{
std::size_t size = numElements_ * ControlValueSize[type_];
if (size > sizeof(value_)) {
delete[] reinterpret_cast<uint8_t *>(storage_);
storage_ = nullptr;
}
}
ControlValue::~ControlValue()
{
release();
}
/**
* \brief Construct a ControlValue with the content of \a other
* \param[in] other The ControlValue to copy content from
*/
ControlValue::ControlValue(const ControlValue &other)
: type_(ControlTypeNone), numElements_(0)
{
*this = other;
}
/**
* \brief Replace the content of the ControlValue with a copy of the content
* of \a other
* \param[in] other The ControlValue to copy content from
* \return The ControlValue with its content replaced with the one of \a other
*/
ControlValue &ControlValue::operator=(const ControlValue &other)
{
set(other.type_, other.isArray_, other.data().data(),
other.numElements_, ControlValueSize[other.type_]);
return *this;
}
/**
* \fn ControlValue::type()
* \brief Retrieve the data type of the value
* \return The value data type
*/
/**
* \fn ControlValue::isNone()
* \brief Determine if the value is not initialised
* \return True if the value type is ControlTypeNone, false otherwise
*/
/**
* \fn ControlValue::isArray()
* \brief Determine if the value stores an array
* \return True if the value stores an array, false otherwise
*/
/**
* \fn ControlValue::numElements()
* \brief Retrieve the number of elements stored in the ControlValue
*
* For instances storing an array, this function returns the number of elements
* in the array. For instances storing a string, it returns the length of the
* string, not counting the terminating '\0'. Otherwise, it returns 1.
*
* \return The number of elements stored in the ControlValue
*/
/**
* \brief Retrieve the raw data of a control value
* \return The raw data of the control value as a span of uint8_t
*/
Span<const uint8_t> ControlValue::data() const
{
std::size_t size = numElements_ * ControlValueSize[type_];
const uint8_t *data = size > sizeof(value_)
? reinterpret_cast<const uint8_t *>(storage_)
: reinterpret_cast<const uint8_t *>(&value_);
return { data, size };
}
/**
* \copydoc ControlValue::data() const
*/
Span<uint8_t> ControlValue::data()
{
Span<const uint8_t> data = const_cast<const ControlValue *>(this)->data();
return { const_cast<uint8_t *>(data.data()), data.size() };
}
/**
* \brief Assemble and return a string describing the value
* \return A string describing the ControlValue
*/
std::string ControlValue::toString() const
{
if (type_ == ControlTypeNone)
return "<ValueType Error>";
const uint8_t *data = ControlValue::data().data();
if (type_ == ControlTypeString)
return std::string(reinterpret_cast<const char *>(data),
numElements_);
std::string str(isArray_ ? "[ " : "");
for (unsigned int i = 0; i < numElements_; ++i) {
switch (type_) {
case ControlTypeBool: {
const bool *value = reinterpret_cast<const bool *>(data);
str += *value ? "true" : "false";
break;
}
case ControlTypeByte: {
const uint8_t *value = reinterpret_cast<const uint8_t *>(data);
str += std::to_string(*value);
break;
}
case ControlTypeInteger32: {
const int32_t *value = reinterpret_cast<const int32_t *>(data);
str += std::to_string(*value);
break;
}
case ControlTypeInteger64: {
const int64_t *value = reinterpret_cast<const int64_t *>(data);
str += std::to_string(*value);
break;
}
case ControlTypeFloat: {
const float *value = reinterpret_cast<const float *>(data);
str += std::to_string(*value);
break;
}
case ControlTypeRectangle: {
const Rectangle *value = reinterpret_cast<const Rectangle *>(data);
str += value->toString();
break;
}
case ControlTypeSize: {
const Size *value = reinterpret_cast<const Size *>(data);
str += value->toString();
break;
}
case ControlTypeNone:
case ControlTypeString:
break;
}
if (i + 1 != numElements_)
str += ", ";
data += ControlValueSize[type_];
}
if (isArray_)
str += " ]";
return str;
}
/**
* \brief Compare ControlValue instances for equality
* \return True if the values have identical types and values, false otherwise
*/
bool ControlValue::operator==(const ControlValue &other) const
{
if (type_ != other.type_)
return false;
if (numElements_ != other.numElements())
return false;
if (isArray_ != other.isArray_)
return false;
return memcmp(data().data(), other.data().data(), data().size()) == 0;
}
/**
* \fn bool ControlValue::operator!=()
* \brief Compare ControlValue instances for non equality
* \return False if the values have identical types and values, true otherwise
*/
/**
* \fn template<typename T> T ControlValue::get() const
* \brief Get the control value
*
* This function returns the contained value as an instance of \a T. If the
* ControlValue instance stores a single value, the type \a T shall match the
* stored value type(). If the instance stores an array of values, the type
* \a T should be equal to Span<const R>, and the type \a R shall match the
* stored value type(). The behaviour is undefined otherwise.
*
* Note that a ControlValue instance that stores a non-array value is not
* equivalent to an instance that stores an array value containing a single
* element. The latter shall be accessed through a Span<const R> type, while
* the former shall be accessed through a type \a T corresponding to type().
*
* \return The control value
*/
/**
* \fn template<typename T> void ControlValue::set(const T &value)
* \brief Set the control value to \a value
* \param[in] value The control value
*
* This function stores the \a value in the instance. If the type \a T is
* equivalent to Span<R>, the instance stores an array of values of type \a R.
* Otherwise the instance stores a single value of type \a T. The numElements()
* and type() are updated to reflect the stored value.
*
* The entire content of \a value is copied to the instance, no reference to \a
* value or to the data it references is retained. This may be an expensive
* operation for Span<> values that refer to large arrays.
*/
void ControlValue::set(ControlType type, bool isArray, const void *data,
std::size_t numElements, std::size_t elementSize)
{
ASSERT(elementSize == ControlValueSize[type]);
reserve(type, isArray, numElements);
Span<uint8_t> storage = ControlValue::data();
memcpy(storage.data(), data, storage.size());
}
/**
* \brief Set the control type and reserve memory
* \param[in] type The control type
* \param[in] isArray True to make the value an array
* \param[in] numElements The number of elements
*
* This function sets the type of the control value to \a type, and reserves
* memory to store the control value. If \a isArray is true, the instance
* becomes an array control and storage for \a numElements is reserved.
* Otherwise the instance becomes a simple control, numElements is ignored, and
* storage for the single element is reserved.
*/
void ControlValue::reserve(ControlType type, bool isArray, std::size_t numElements)
{
if (!isArray)
numElements = 1;
std::size_t oldSize = numElements_ * ControlValueSize[type_];
std::size_t newSize = numElements * ControlValueSize[type];
if (oldSize != newSize)
release();
type_ = type;
isArray_ = isArray;
numElements_ = numElements;
if (oldSize == newSize)
return;
if (newSize > sizeof(value_))
storage_ = reinterpret_cast<void *>(new uint8_t[newSize]);
}
/**
* \class ControlId
* \brief Control static metadata
*
* The ControlId class stores a control ID, name and data type. It provides
* unique identification of a control, but without support for compile-time
* type deduction that the derived template Control class supports. See the
* Control class for more information.
*/
/**
* \fn ControlId::ControlId(unsigned int id, const std::string &name, ControlType type)
* \brief Construct a ControlId instance
* \param[in] id The control numerical ID
* \param[in] name The control name
* \param[in] type The control data type
*/
/**
* \fn unsigned int ControlId::id() const
* \brief Retrieve the control numerical ID
* \return The control numerical ID
*/
/**
* \fn const char *ControlId::name() const
* \brief Retrieve the control name
* \return The control name
*/
/**
* \fn ControlType ControlId::type() const
* \brief Retrieve the control data type
* \return The control data type
*/
/**
* \fn bool operator==(unsigned int lhs, const ControlId &rhs)
* \brief Compare a ControlId with a control numerical ID
* \param[in] lhs Left-hand side numerical ID
* \param[in] rhs Right-hand side ControlId
*
* \return True if \a lhs is equal to \a rhs.id(), false otherwise
*/
/**
* \fn bool operator==(const ControlId &lhs, unsigned int rhs)
* \brief Compare a ControlId with a control numerical ID
* \param[in] lhs Left-hand side ControlId
* \param[in] rhs Right-hand side numerical ID
*
* \return True if \a lhs.id() is equal to \a rhs, false otherwise
*/
/**
* \class Control
* \brief Describe a control and its intrinsic properties
*
* The Control class models a control exposed by an object. Its template type
* name T refers to the control data type, and allows functions that operate on
* control values to be defined as template functions using the same type T for
* the control value. See for instance how the ControlList::get() function
* returns a value corresponding to the type of the requested control.
*
* While this class is the main means to refer to a control, the control
* identifying information is stored in the non-template base ControlId class.
* This allows code that operates on a set of controls of different types to
* reference those controls through a ControlId instead of a Control. For
* instance, the list of controls supported by a camera is exposed as ControlId
* instead of Control.
*
* Controls of any type can be defined through template specialisation, but
* libcamera only supports the bool, uint8_t, int32_t, int64_t and float types
* natively (this includes types that are equivalent to the supported types,
* such as int and long int).
*
* Controls IDs shall be unique. While nothing prevents multiple instances of
* the Control class to be created with the same ID for the same object, doing
* so may cause undefined behaviour.
*/
/**
* \fn Control::Control(unsigned int id, const char *name)
* \brief Construct a Control instance
* \param[in] id The control numerical ID
* \param[in] name The control name
*
* The control data type is automatically deduced from the template type T.
*/
/**
* \typedef Control::type
* \brief The Control template type T
*/
/**
* \class ControlInfo
* \brief Describe the limits of valid values for a Control
*
* The ControlInfo expresses the constraints on valid values for a control.
* The constraints depend on the object the control applies to, and are
* constant for the lifetime of that object. They are typically constructed by
* pipeline handlers to describe the controls they support.
*/
/**
* \brief Construct a ControlInfo with minimum and maximum range parameters
* \param[in] min The control minimum value
* \param[in] max The control maximum value
* \param[in] def The control default value
*/
ControlInfo::ControlInfo(const ControlValue &min,
const ControlValue &max,
const ControlValue &def)
: min_(min), max_(max), def_(def)
{
}
/**
* \brief Construct a ControlInfo from the list of valid values
* \param[in] values The control valid values
* \param[in] def The control default value
*
* Construct a ControlInfo from a list of valid values. The ControlInfo
* minimum and maximum values are set to the first and last members of the
* values list respectively. The default value is set to \a def if provided, or
* to the minimum value otherwise.
*/
ControlInfo::ControlInfo(Span<const ControlValue> values,
const ControlValue &def)
{
min_ = values.front();
max_ = values.back();
def_ = !def.isNone() ? def : values.front();
values_.reserve(values.size());
for (const ControlValue &value : values)
values_.push_back(value);
}
/**
* \brief Construct a boolean ControlInfo with both boolean values
* \param[in] values The control valid boolean values (both true and false)
* \param[in] def The control default boolean value
*
* Construct a ControlInfo for a boolean control, where both true and false are
* valid values. \a values must be { false, true } (the order is irrelevant).
* The minimum value will always be false, and the maximum always true. The
* default value is \a def.
*/
ControlInfo::ControlInfo(std::set<bool> values, bool def)
: min_(false), max_(true), def_(def), values_({ false, true })
{
ASSERT(values.count(def) && values.size() == 2);
}
/**
* \brief Construct a boolean ControlInfo with only one valid value
* \param[in] value The control valid boolean value
*
* Construct a ControlInfo for a boolean control, where there is only valid
* value. The minimum, maximum, and default values will all be \a value.
*/
ControlInfo::ControlInfo(bool value)
: min_(value), max_(value), def_(value)
{
values_ = { value };
}
/**
* \fn ControlInfo::min()
* \brief Retrieve the minimum value of the control
*
* For string controls, this is the minimum length of the string, not counting
* the terminating '\0'. For all other control types, this is the minimum value
* of each element.
*
* \return A ControlValue with the minimum value for the control
*/
/**
* \fn ControlInfo::max()
* \brief Retrieve the maximum value of the control
*
* For string controls, this is the maximum length of the string, not counting
* the terminating '\0'. For all other control types, this is the maximum value
* of each element.
*
* \return A ControlValue with the maximum value for the control
*/
/**
* \fn ControlInfo::def()
* \brief Retrieve the default value of the control
* \return A ControlValue with the default value for the control
*/
/**
* \fn ControlInfo::values()
* \brief Retrieve the list of valid values
*
* For controls that support a pre-defined number of values, the enumeration of
* those is reported through a vector of ControlValue instances accessible with
* this function.
*
* \return A vector of ControlValue representing the control valid values
*/
/**
* \brief Provide a string representation of the ControlInfo
*/
std::string ControlInfo::toString() const
{
std::stringstream ss;
ss << "[" << min_.toString() << ".." << max_.toString() << "]";
return ss.str();
}
/**
* \fn bool ControlInfo::operator==()
* \brief Compare ControlInfo instances for equality
* \return True if the constraints have identical min and max, false otherwise
*/
/**
* \fn bool ControlInfo::operator!=()
* \brief Compare ControlInfo instances for non equality
* \return True if the constraints have different min and max, false otherwise
*/
/**
* \typedef ControlIdMap
* \brief A map of numerical control ID to ControlId
*
* The map is used by ControlList instances to access controls by numerical
* IDs. A global map of all libcamera controls is provided by
* controls::controls.
*/
/**
* \class ControlInfoMap
* \brief A map of ControlId to ControlInfo
*
* The ControlInfoMap class describes controls supported by an object as an
* unsorted map of ControlId pointers to ControlInfo instances. Unlike the
* standard std::unsorted_map<> class, it is designed to be immutable once
* constructed, and thus only exposes the read accessors of the
* std::unsorted_map<> base class.
*
* The class is constructed with a reference to a ControlIdMap. This allows
* providing access to the mapped elements using numerical ID keys, in addition
* to the features of the standard unsorted map. All ControlId keys in the map
* must appear in the ControlIdMap.
*/
/**
* \typedef ControlInfoMap::Map
* \brief The base std::unsorted_map<> container
*/
/**
* \fn ControlInfoMap::ControlInfoMap(const ControlInfoMap &other)
* \brief Copy constructor, construct a ControlInfoMap from a copy of \a other
* \param[in] other The other ControlInfoMap
*/
/**
* \brief Construct a ControlInfoMap from an initializer list
* \param[in] init The initializer list
* \param[in] idmap The idmap used by the ControlInfoMap
*/
ControlInfoMap::ControlInfoMap(std::initializer_list<Map::value_type> init,
const ControlIdMap &idmap)
: Map(init), idmap_(&idmap)
{
ASSERT(validate());
}
/**
* \brief Construct a ControlInfoMap from a plain map
* \param[in] info The control info plain map
* \param[in] idmap The idmap used by the ControlInfoMap
*
* Construct a new ControlInfoMap and populate its contents with those of
* \a info using move semantics. Upon return the \a info map will be empty.
*/
ControlInfoMap::ControlInfoMap(Map &&info, const ControlIdMap &idmap)
: Map(std::move(info)), idmap_(&idmap)
{
ASSERT(validate());
}
/**
* \fn ControlInfoMap &ControlInfoMap::operator=(const ControlInfoMap &other)
* \brief Copy assignment operator, replace the contents with a copy of \a other
* \param[in] other The other ControlInfoMap
* \return A reference to the ControlInfoMap
*/
bool ControlInfoMap::validate()
{
for (const auto &ctrl : *this) {
const ControlId *id = ctrl.first;
auto it = idmap_->find(id->id());
/*
* Make sure all control ids are part of the idmap and verify
* the control info matches the expected type.
*/
if (it == idmap_->end() || it->second != id) {
LOG(Controls, Error)
<< "Control " << utils::hex(id->id())
<< " not in the idmap";
return false;
}
/*
* For string controls, min and max define the valid
* range for the string size, not for the individual
* values.
*/
ControlType rangeType = id->type() == ControlTypeString
? ControlTypeInteger32 : id->type();
const ControlInfo &info = ctrl.second;
if (info.min().type() != rangeType) {
LOG(Controls, Error)
<< "Control " << utils::hex(id->id())
<< " type and info type mismatch";
return false;
}
}
return true;
}
/**
* \brief Access specified element by numerical ID
* \param[in] id The numerical ID
* \return A reference to the element whose ID is equal to \a id
*/
ControlInfoMap::mapped_type &ControlInfoMap::at(unsigned int id)
{
return at(idmap_->at(id));
}
/**
* \brief Access specified element by numerical ID
* \param[in] id The numerical ID
* \return A const reference to the element whose ID is equal to \a id
*/
const ControlInfoMap::mapped_type &ControlInfoMap::at(unsigned int id) const
{
return at(idmap_->at(id));
}
/**
* \brief Count the number of elements matching a numerical ID
* \param[in] id The numerical ID
* \return The number of elements matching the numerical \a id
*/
ControlInfoMap::size_type ControlInfoMap::count(unsigned int id) const
{
/*
* The ControlInfoMap and its idmap have a 1:1 mapping between their
* entries, we can thus just count the matching entries in idmap to
* avoid an additional lookup.
*/
return idmap_->count(id);
}
/**
* \brief Find the element matching a numerical ID
* \param[in] id The numerical ID
* \return An iterator pointing to the element matching the numerical \a id, or
* end() if no such element exists
*/
ControlInfoMap::iterator ControlInfoMap::find(unsigned int id)
{
auto iter = idmap_->find(id);
if (iter == idmap_->end())
return end();
return find(iter->second);
}
/**
* \brief Find the element matching a numerical ID
* \param[in] id The numerical ID
* \return A const iterator pointing to the element matching the numerical
* \a id, or end() if no such element exists
*/
ControlInfoMap::const_iterator ControlInfoMap::find(unsigned int id) const
{
auto iter = idmap_->find(id);
if (iter == idmap_->end())
return end();
return find(iter->second);
}
/**
* \fn const ControlIdMap &ControlInfoMap::idmap() const
* \brief Retrieve the ControlId map
*
* Constructing ControlList instances for V4L2 controls requires a ControlIdMap
* for the V4L2 device that the control list targets. This helper function
* returns a suitable idmap for that purpose.
*
* \return The ControlId map
*/
/**
* \class ControlList
* \brief Associate a list of ControlId with their values for an object
*
* The ControlList class stores values of controls exposed by an object. The
* lists returned by the Request::controls() and Request::metadata() functions
* refer to the camera that the request belongs to.
*
* Control lists are constructed with a map of all the controls supported by
* their object, and an optional ControlValidator to further validate the
* controls.
*/
/**
* \brief Construct a ControlList not associated with any object
*
* This constructor is meant to support ControlList serialization and shall not
* be used directly by application.
*/
ControlList::ControlList()
: validator_(nullptr), idmap_(nullptr), infoMap_(nullptr)
{
}
/**
* \brief Construct a ControlList with an optional control validator
* \param[in] idmap The ControlId map for the control list target object
* \param[in] validator The validator (may be null)
*
* For ControlList containing libcamera controls, a global map of all libcamera
* controls is provided by controls::controls and can be used as the \a idmap
* argument.
*/
ControlList::ControlList(const ControlIdMap &idmap,
const ControlValidator *validator)
: validator_(validator), idmap_(&idmap), infoMap_(nullptr)
{
}
/**
* \brief Construct a ControlList with the idmap of a control info map
* \param[in] infoMap The ControlInfoMap for the control list target object
* \param[in] validator The validator (may be null)
*/
ControlList::ControlList(const ControlInfoMap &infoMap,
const ControlValidator *validator)
: validator_(validator), idmap_(&infoMap.idmap()), infoMap_(&infoMap)
{
}
/**
* \typedef ControlList::iterator
* \brief Iterator for the controls contained within the list
*/
/**
* \typedef ControlList::const_iterator
* \brief Const iterator for the controls contained within the list
*/
/**
* \fn iterator ControlList::begin()
* \brief Retrieve an iterator to the first Control in the list
* \return An iterator to the first Control in the list
*/
/**
* \fn const_iterator ControlList::begin() const
* \brief Retrieve a const_iterator to the first Control in the list
* \return A const_iterator to the first Control in the list
*/
/**
* \fn iterator ControlList::end()
* \brief Retrieve an iterator pointing to the past-the-end control in the list
* \return An iterator to the element following the last control in the list
*/
/**
* \fn const_iterator ControlList::end() const
* \brief Retrieve a const iterator pointing to the past-the-end control in the
* list
* \return A const iterator to the element following the last control in the
* list
*/
/**
* \fn ControlList::empty()
* \brief Identify if the list is empty
* \return True if the list does not contain any control, false otherwise
*/
/**
* \fn ControlList::size()
* \brief Retrieve the number of controls in the list
* \return The number of Control entries stored in the list
*/
/**
* \fn ControlList::clear()
* \brief Removes all controls from the list
*/
/**
* \brief Merge the \a source into the ControlList
* \param[in] source The ControlList to merge into this object
*
* Merging two control lists copies elements from the \a source and inserts
* them in *this. If the \a source contains elements whose key is already
* present in *this, then those elements are not overwritten.
*
* Only control lists created from the same ControlIdMap or ControlInfoMap may
* be merged. Attempting to do otherwise results in undefined behaviour.
*
* \todo Reimplement or implement an overloaded version which internally uses
* std::unordered_map::merge() and accepts a non-const argument.
*/
void ControlList::merge(const ControlList &source)
{
/**
* \todo: ASSERT that the current and source ControlList are derived
* from a compatible ControlIdMap, to prevent undefined behaviour due to
* id collisions.
*
* This can not currently be a direct pointer comparison due to the
* duplication of the ControlIdMaps in the isolated IPA use cases.
* Furthermore, manually checking each entry of the id map is identical
* is expensive.
* See https://bugs.libcamera.org/show_bug.cgi?id=31 for further details
*/
for (const auto &ctrl : source) {
if (contains(ctrl.first)) {
const ControlId *id = idmap_->at(ctrl.first);
LOG(Controls, Warning)
<< "Control " << id->name() << " not overwritten";
continue;
}
set(ctrl.first, ctrl.second);
}
}
/**
* \brief Check if the list contains a control with the specified \a id
* \param[in] id The control ID
*
* \return True if the list contains a matching control, false otherwise
*/
bool ControlList::contains(const ControlId &id) const
{
return controls_.find(id.id()) != controls_.end();
}
/**
* \brief Check if the list contains a control with the specified \a id
* \param[in] id The control numerical ID
*
* \return True if the list contains a matching control, false otherwise
*/
bool ControlList::contains(unsigned int id) const
{
return controls_.find(id) != controls_.end();
}
/**
* \fn template<typename T> T ControlList::get(const Control<T> &ctrl) const
* \brief Get the value of control \a ctrl
* \param[in] ctrl The control
*
* The behaviour is undefined if the control \a ctrl is not present in the
* list. Use ControlList::contains() to test for the presence of a control in
* the list before retrieving its value.
*
* The control value type shall match the type T, otherwise the behaviour is
* undefined.
*
* \return The control value
*/
/**
* \fn template<typename T, typename V> void ControlList::set(const Control<T> &ctrl, const V &value)
* \brief Set the control \a ctrl value to \a value
* \param[in] ctrl The control
* \param[in] value The control value
*
* This function sets the value of a control in the control list. If the control
* is already present in the list, its value is updated, otherwise it is added
* to the list.
*
* The behaviour is undefined if the control \a ctrl is not supported by the
* object that the list refers to.
*/
/**
* \fn template<typename T, typename V> \
* void ControlList::set(const Control<T> &ctrl, const std::initializer_list<V> &value)
* \copydoc ControlList::set(const Control<T> &ctrl, const V &value)
*/
/**
* \brief Get the value of control \a id
* \param[in] id The control numerical ID
*
* The behaviour is undefined if the control \a id is not present in the list.
* Use ControlList::contains() to test for the presence of a control in the
* list before retrieving its value.
*
* \return The control value
*/
const ControlValue &ControlList::get(unsigned int id) const
{
static const ControlValue zero;
const ControlValue *val = find(id);
if (!val)
return zero;
return *val;
}
/**
* \brief Set the value of control \a id to \a value
* \param[in] id The control ID
* \param[in] value The control value
*
* This function sets the value of a control in the control list. If the control
* is already present in the list, its value is updated, otherwise it is added
* to the list.
*
* The behaviour is undefined if the control \a id is not supported by the
* object that the list refers to.
*/
void ControlList::set(unsigned int id, const ControlValue &value)
{
ControlValue *val = find(id);
if (!val)
return;
*val = value;
}
/**
* \fn ControlList::infoMap()
* \brief Retrieve the ControlInfoMap used to construct the ControlList
*
* \return The ControlInfoMap used to construct the ControlList. ControlList
* instances constructed with ControlList() or
* ControlList(const ControlIdMap &idmap, ControlValidator *validator) have no
* associated ControlInfoMap, nullptr is returned in that case.
*/
/**
* \fn ControlList::idMap()
* \brief Retrieve the ControlId map used to construct the ControlList
* \return The ControlId map used to construct the ControlList. ControlList
* instances constructed with the default contructor have no associated idmap,
* nullptr is returned in that case.
*/
const ControlValue *ControlList::find(unsigned int id) const
{
const auto iter = controls_.find(id);
if (iter == controls_.end()) {
LOG(Controls, Error)
<< "Control " << utils::hex(id) << " not found";
return nullptr;
}
return &iter->second;
}
ControlValue *ControlList::find(unsigned int id)
{
if (validator_ && !validator_->validate(id)) {
LOG(Controls, Error)
<< "Control " << utils::hex(id)
<< " is not valid for " << validator_->name();
return nullptr;
}
return &controls_[id];
}
} /* namespace libcamera */