@@ -11,6 +11,8 @@
#include <string>
#include <unordered_map>
+#include <libcamera/span.h>
+
namespace libcamera {
class ControlValidator;
@@ -18,8 +20,15 @@ class ControlValidator;
enum ControlType {
ControlTypeNone,
ControlTypeBool,
+ ControlTypeInteger8,
ControlTypeInteger32,
ControlTypeInteger64,
+ ControlTypeFloat,
+ ControlTypeCompoundBool,
+ ControlTypeCompoundInt8,
+ ControlTypeCompoundInt32,
+ ControlTypeCompoundInt64,
+ ControlTypeCompoundFloat,
};
class ControlValue
@@ -27,16 +36,28 @@ class ControlValue
public:
ControlValue();
ControlValue(bool value);
+ ControlValue(int8_t value);
ControlValue(int32_t value);
ControlValue(int64_t value);
+ ControlValue(float value);
+ ControlValue(Span<bool> &values);
+ ControlValue(Span<int8_t> &values);
+ ControlValue(Span<int32_t> &values);
+ ControlValue(Span<int64_t> &values);
+ ControlValue(Span<float> &values);
+ ~ControlValue();
ControlType type() const { return type_; }
bool isNone() const { return type_ == ControlTypeNone; }
+ std::size_t numElements() const { return numElements_; }
template<typename T>
- const T &get() const;
+ const Span<T> get() const;
+
template<typename T>
void set(const T &value);
+ template<typename T>
+ void set(const Span<T> &values);
std::string toString() const;
@@ -51,9 +72,23 @@ private:
union {
bool bool_;
+ int8_t integer8_;
int32_t integer32_;
int64_t integer64_;
+ float float_;
};
+
+ bool *pbool_;
+ int8_t *p8_;
+ int32_t *p32_;
+ int64_t *p64_;
+ float *pfloat_;
+
+ std::size_t numElements_;
+
+ void release();
+ bool compareElement(const ControlValue &other, unsigned int i) const;
+ std::string elemToString(unsigned int i) const;
};
class ControlId
@@ -182,6 +217,7 @@ public:
private:
void generateIdmap();
+ bool matchRangeType(enum ControlType type1, enum ControlType type2);
ControlIdMap idmap_;
};
@@ -212,7 +248,7 @@ public:
bool contains(unsigned int id) const;
template<typename T>
- const T &get(const Control<T> &ctrl) const
+ const Span<T> get(const Control<T> &ctrl) const
{
const ControlValue *val = find(ctrl.id());
if (!val) {
@@ -233,6 +269,16 @@ public:
val->set<T>(value);
}
+ template<typename T>
+ void set(const Control<T> &ctrl, const Span<T> &values)
+ {
+ ControlValue *val = find(ctrl.id());
+ if (!val)
+ return;
+
+ val->set<T>(values);
+ }
+
const ControlValue &get(unsigned int id) const;
void set(unsigned int id, const ControlValue &value);
new file mode 100644
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * span.h - C++20 std::span<> implementation for C++11
+ */
+
+#ifndef __LIBCAMERA_SPAN_H__
+#define __LIBCAMERA_SPAN_H__
+
+#include <iostream>
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+
+namespace libcamera {
+
+template <typename T>
+class Span
+{
+private:
+ using iterator = T *;
+ using const_iterator = const T *;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ class Storage
+ {
+ public:
+ Storage(T *ptr, std::size_t size)
+ : ptr_(ptr), size_(size)
+ {
+ }
+
+ T *ptr() const { return ptr_; }
+ std::size_t size() const { return size_; }
+
+ private:
+ T *ptr_;
+ std::size_t size_;
+ };
+
+public:
+ Span(T &v)
+ : storage_(&v, 1)
+ {
+ }
+
+ Span(const T &v)
+ : storage_(const_cast<T *>(&v), 1)
+ {
+ }
+
+ Span(T *v, std::size_t s)
+ : storage_(v, s)
+ {
+ }
+
+ Span(const T *v, std::size_t s)
+ : storage_(const_cast<T *>(v), s)
+ {
+ }
+
+ Span(std::initializer_list<T> list)
+ : storage_(const_cast<T *>(list.begin()), list.size())
+ {
+ }
+
+ Span(const Span &other) = default;
+
+ Span &operator=(const Span &other) = default;
+ operator T() const { return *data(); }
+ T &operator[](unsigned int index) const
+ {
+ if (index >= size())
+ return *(end() - 1);
+ return *(data() + index);
+ }
+
+ T *data() const { return storage_.ptr(); }
+ std::size_t size() const { return storage_.size(); }
+
+ constexpr iterator begin() const { return data(); }
+ constexpr iterator end() const { return data() + size(); }
+ constexpr iterator cbegin() const { return begin(); }
+ constexpr iterator cend() const { return end(); }
+ constexpr reverse_iterator rbegin() const
+ {
+ return reverse_iterator(end());
+ }
+ constexpr reverse_iterator rend() const
+ {
+ return reverse_iterator(begin());
+ }
+ constexpr const_reverse_iterator crbegin() const
+ {
+ return const_reverse_iterator(end());
+ }
+ constexpr const_reverse_iterator crend() const
+ {
+ return const_reverse_iterator(begin());
+ }
+
+private:
+ Storage storage_;
+};
+
+}; /* namespace libcamera */
+
+#endif /* __LIBCAMERA_SPAN_H__ */
new file mode 100644
@@ -50,4 +50,8 @@ controls:
type: int32_t
description: Specify a fixed gain parameter
+ - CompoundControl:
+ type: int8_t
+ description: A fictional compound control
+
...
@@ -30,10 +30,17 @@ LOG_DEFINE_CATEGORY(Serializer)
namespace {
static constexpr size_t ControlValueSize[] = {
- [ControlTypeNone] = 1,
- [ControlTypeBool] = sizeof(bool),
- [ControlTypeInteger32] = sizeof(int32_t),
- [ControlTypeInteger64] = sizeof(int64_t),
+ [ControlTypeNone] = 1,
+ [ControlTypeBool] = sizeof(bool),
+ [ControlTypeInteger8] = sizeof(int8_t),
+ [ControlTypeInteger32] = sizeof(int32_t),
+ [ControlTypeInteger64] = sizeof(int64_t),
+ [ControlTypeFloat] = sizeof(float),
+ [ControlTypeCompoundBool] = sizeof(bool *),
+ [ControlTypeCompoundInt8] = sizeof(int8_t *),
+ [ControlTypeCompoundInt32] = sizeof(int32_t *),
+ [ControlTypeCompoundInt64] = sizeof(int64_t *),
+ [ControlTypeCompoundFloat] = sizeof(float *),
};
} /* namespace */
@@ -9,7 +9,9 @@
#include <iomanip>
#include <sstream>
-#include <string>
+#include <string.h>
+
+#include <libcamera/span.h>
#include "control_validator.h"
#include "log.h"
@@ -69,7 +71,8 @@ LOG_DEFINE_CATEGORY(Controls)
* \brief Construct an empty ControlValue.
*/
ControlValue::ControlValue()
- : type_(ControlTypeNone)
+ : type_(ControlTypeNone), pbool_(nullptr), p8_(nullptr), p32_(nullptr),
+ p64_(nullptr), pfloat_(nullptr), numElements_(0)
{
}
@@ -78,7 +81,15 @@ ControlValue::ControlValue()
* \param[in] value Boolean value to store
*/
ControlValue::ControlValue(bool value)
- : type_(ControlTypeBool), bool_(value)
+ : type_(ControlTypeBool), bool_(value), pbool_(nullptr), p8_(nullptr),
+ p32_(nullptr), p64_(nullptr), pfloat_(nullptr), numElements_(1)
+{
+}
+
+ControlValue::ControlValue(int8_t value)
+ : type_(ControlTypeInteger8), integer8_(value), pbool_(nullptr),
+ p8_(nullptr), p32_(nullptr), p64_(nullptr), pfloat_(nullptr),
+ numElements_(1)
{
}
@@ -87,7 +98,9 @@ ControlValue::ControlValue(bool value)
* \param[in] value Integer value to store
*/
ControlValue::ControlValue(int32_t value)
- : type_(ControlTypeInteger32), integer32_(value)
+ : type_(ControlTypeInteger32), integer32_(value), pbool_(nullptr),
+ p8_(nullptr), p32_(nullptr), p64_(nullptr), pfloat_(nullptr),
+ numElements_(1)
{
}
@@ -96,8 +109,87 @@ ControlValue::ControlValue(int32_t value)
* \param[in] value Integer value to store
*/
ControlValue::ControlValue(int64_t value)
- : type_(ControlTypeInteger64), integer64_(value)
+ : type_(ControlTypeInteger64), integer64_(value), pbool_(nullptr),
+ p8_(nullptr), p32_(nullptr), p64_(nullptr), pfloat_(nullptr),
+ numElements_(1)
+{
+}
+
+ControlValue::ControlValue(float value)
+ : type_(ControlTypeInteger64), float_(value), pbool_(nullptr),
+ p8_(nullptr), p32_(nullptr), p64_(nullptr), pfloat_(nullptr),
+ numElements_(1)
+{
+}
+
+ControlValue::ControlValue(Span<bool> &values)
+ : type_(ControlTypeCompoundBool), pbool_(nullptr), p8_(nullptr),
+ p32_(nullptr), p64_(nullptr), pfloat_(nullptr),
+ numElements_(values.size())
+{
+ pbool_ = new bool[numElements_];
+ memcpy(pbool_, values.data(), sizeof(bool) * numElements_);
+}
+
+ControlValue::ControlValue(Span<int8_t> &values)
+ : type_(ControlTypeCompoundInt8),pbool_(nullptr), p8_(nullptr),
+ p32_(nullptr), p64_(nullptr), pfloat_(nullptr),
+ numElements_(values.size())
+{
+ p8_ = new int8_t[numElements_];
+ memcpy(p8_, values.data(), sizeof(int8_t) * numElements_);
+}
+
+ControlValue::ControlValue(Span<int32_t> &values)
+ : type_(ControlTypeCompoundInt32), pbool_(nullptr), p8_(nullptr),
+ p32_(nullptr), p64_(nullptr), pfloat_(nullptr),
+ numElements_(values.size())
+{
+ p32_ = new int32_t[numElements_];
+ memcpy(p32_, values.data(), sizeof(int32_t) * numElements_);
+}
+
+ControlValue::ControlValue(Span<int64_t> &values)
+ : type_(ControlTypeCompoundInt64), pbool_(nullptr), p8_(nullptr),
+ p32_(nullptr), p64_(nullptr), pfloat_(nullptr),
+ numElements_(values.size())
{
+ p64_ = new int64_t[numElements_];
+ memcpy(p64_, values.data(), sizeof(int64_t) * numElements_);
+}
+
+ControlValue::ControlValue(Span<float> &values)
+ : type_(ControlTypeCompoundFloat), pbool_(nullptr), p8_(nullptr),
+ p32_(nullptr), p64_(nullptr), pfloat_(nullptr),
+ numElements_(values.size())
+{
+ pfloat_ = new float[numElements_];
+ memcpy(pfloat_, values.data(), sizeof(float) * numElements_);
+}
+
+void ControlValue::release()
+{
+ if (pbool_)
+ delete[] pbool_;
+ if (p8_)
+ delete[] p8_;
+ if (p32_)
+ delete[] p32_;
+ if (p64_)
+ delete[] p64_;
+ if (pfloat_)
+ delete[] pfloat_;
+
+ pbool_ = nullptr;
+ p8_ = nullptr;
+ p32_ = nullptr;
+ p64_ = nullptr;
+ pfloat_ = nullptr;
+}
+
+ControlValue::~ControlValue()
+{
+ release();
}
/**
@@ -130,69 +222,225 @@ ControlValue::ControlValue(int64_t value)
#ifndef __DOXYGEN__
template<>
-const bool &ControlValue::get<bool>() const
+const Span<bool> ControlValue::get<bool>() const
{
- ASSERT(type_ == ControlTypeBool);
+ ASSERT(type_ == ControlTypeBool || type_ == ControlTypeCompoundBool);
- return bool_;
+ const bool *p = pbool_ ? pbool_ : &bool_;
+ /*
+ * Explicitly create a Span<bool> instance, otherwise the compiler
+ * tries to match the "{ p, numElements_}" construct used in other get()
+ * operation specialization with the initializer_list constructor of
+ * class Span (clang++ 8.0.1)
+ */
+ return Span<bool>(p, static_cast<std::size_t>(numElements_));
}
template<>
-const int32_t &ControlValue::get<int32_t>() const
+const Span<int8_t> ControlValue::get<int8_t>() const
{
- ASSERT(type_ == ControlTypeInteger32 || type_ == ControlTypeInteger64);
+ ASSERT(type_ == ControlTypeInteger8 ||
+ type_ == ControlTypeCompoundInt8);
- return integer32_;
+ const int8_t *p = p8_ ? p8_ : &integer8_;
+ return { p, static_cast<std::size_t>(numElements_) };
}
template<>
-const int64_t &ControlValue::get<int64_t>() const
+const Span<int32_t> ControlValue::get<int32_t>() const
{
- ASSERT(type_ == ControlTypeInteger32 || type_ == ControlTypeInteger64);
+ ASSERT(type_ == ControlTypeInteger32 ||
+ type_ == ControlTypeInteger64 ||
+ type_ == ControlTypeCompoundInt32 ||
+ type_ == ControlTypeCompoundInt64);
- return integer64_;
+ const int32_t *p = p32_ ? p32_ : &integer32_;
+ return { p, numElements_ };
+}
+
+template<>
+const Span<int64_t> ControlValue::get<int64_t>() const
+{
+ ASSERT(type_ == ControlTypeInteger32 ||
+ type_ == ControlTypeInteger64 ||
+ type_ == ControlTypeCompoundInt32 ||
+ type_ == ControlTypeCompoundInt64);
+
+ const int64_t *p = p64_ ? p64_ : &integer64_;
+ return { p, numElements_ };
+}
+
+template<>
+const Span<float> ControlValue::get<float>() const
+{
+ ASSERT(type_ == ControlTypeFloat || type_ == ControlTypeCompoundFloat);
+
+ const float *p = pfloat_ ? pfloat_ : &float_;
+ return { p, numElements_ };
}
template<>
void ControlValue::set<bool>(const bool &value)
{
+ release();
+
type_ = ControlTypeBool;
bool_ = value;
+ numElements_ = 1;
}
template<>
void ControlValue::set<int32_t>(const int32_t &value)
{
+ release();
+
type_ = ControlTypeInteger32;
integer32_ = value;
+ numElements_ = 1;
}
template<>
void ControlValue::set<int64_t>(const int64_t &value)
{
+ release();
+
type_ = ControlTypeInteger64;
integer64_ = value;
+ numElements_ = 1;
}
+
+template<>
+void ControlValue::set<bool>(const Span<bool> &values)
+{
+ release();
+
+ type_ = ControlTypeCompoundBool;
+ numElements_ = values.size();
+
+ pbool_ = new bool[numElements_];
+ memcpy(pbool_, values.data(), sizeof(bool) * numElements_);
+}
+
+template<>
+void ControlValue::set<int8_t>(const Span<int8_t> &values)
+{
+ release();
+
+ type_ = ControlTypeCompoundInt8;
+ numElements_ = values.size();
+
+ p8_ = new int8_t[numElements_];
+ memcpy(p8_, values.data(), sizeof(int8_t) * numElements_);
+}
+
+template<>
+void ControlValue::set<int32_t>(const Span<int32_t> &values)
+{
+ release();
+
+ type_ = ControlTypeCompoundInt32;
+ numElements_ = values.size();
+
+ p32_ = new int32_t[numElements_];
+ memcpy(p32_, values.data(), sizeof(int32_t) * numElements_);
+}
+
+template<>
+void ControlValue::set<int64_t>(const Span<int64_t> &values)
+{
+ release();
+
+ type_ = ControlTypeCompoundInt64;
+ numElements_ = values.size();
+
+ p64_ = new int64_t[numElements_];
+ memcpy(p64_, values.data(), sizeof(int64_t) * numElements_);
+}
+
+template<>
+void ControlValue::set<float>(const Span<float> &values)
+{
+ release();
+
+ type_ = ControlTypeCompoundFloat;
+ numElements_ = values.size();
+
+ pfloat_ = new float[numElements_];
+ memcpy(pfloat_, values.data(), sizeof(float) * numElements_);
+}
+
#endif /* __DOXYGEN__ */
/**
* \brief Assemble and return a string describing the value
* \return A string describing the ControlValue
*/
-std::string ControlValue::toString() const
+std::string ControlValue::elemToString(unsigned int i) const
{
switch (type_) {
- case ControlTypeNone:
- return "<None>";
case ControlTypeBool:
- return bool_ ? "True" : "False";
+ return bool_ ? "True " : "False ";
+ case ControlTypeInteger8:
+ return std::to_string(integer8_);
case ControlTypeInteger32:
return std::to_string(integer32_);
case ControlTypeInteger64:
return std::to_string(integer64_);
+ case ControlTypeFloat:
+ return std::to_string(float_);
+ case ControlTypeCompoundBool:
+ return pbool_[i] ? "True " : "False ";
+ case ControlTypeCompoundInt8:
+ return std::to_string(p8_[i]) + " ";
+ case ControlTypeCompoundInt32:
+ return std::to_string(p32_[i]) + " ";
+ case ControlTypeCompoundInt64:
+ return std::to_string(p64_[i]) + " ";
+ case ControlTypeCompoundFloat:
+ return std::to_string(pfloat_[i]) + " ";
+ default:
+ return "<None>";
}
+}
+
+std::string ControlValue::toString() const
+{
+ if (ControlTypeNone)
+ return "<ValueType Error>";
+
+ std::string str;
+ for (unsigned int i = 0; i < numElements_; ++i)
+ str += elemToString(i);
+
+ return str;
+}
- return "<ValueType Error>";
+bool ControlValue::compareElement(const ControlValue &other, unsigned int i) const
+{
+ switch (type_) {
+ case ControlTypeBool:
+ return bool_ == other.bool_;
+ case ControlTypeInteger8:
+ return integer8_ == other.integer8_;
+ case ControlTypeInteger32:
+ return integer32_ == other.integer32_;
+ case ControlTypeInteger64:
+ return integer64_ == other.integer64_;
+ case ControlTypeFloat:
+ return float_ == other.float_;
+ case ControlTypeCompoundBool:
+ return pbool_[i] == other.pbool_[i];
+ case ControlTypeCompoundInt8:
+ return p8_[i] == other.p8_[i];
+ case ControlTypeCompoundInt32:
+ return p32_[i] == other.p32_[i];
+ case ControlTypeCompoundInt64:
+ return p64_[i] == other.p64_[i];
+ case ControlTypeCompoundFloat:
+ return pfloat_[i] == other.pfloat_[i];
+ default:
+ return false;
+ }
}
/**
@@ -204,13 +452,27 @@ bool ControlValue::operator==(const ControlValue &other) const
if (type_ != other.type_)
return false;
+ if (numElements_ != other.numElements())
+ return false;
+
switch (type_) {
case ControlTypeBool:
- return bool_ == other.bool_;
+ case ControlTypeInteger8:
case ControlTypeInteger32:
- return integer32_ == other.integer32_;
case ControlTypeInteger64:
- return integer64_ == other.integer64_;
+ case ControlTypeFloat:
+ return compareElement(other, 0);
+ case ControlTypeCompoundBool:
+ case ControlTypeCompoundInt8:
+ case ControlTypeCompoundInt32:
+ case ControlTypeCompoundInt64:
+ case ControlTypeCompoundFloat:
+ for (unsigned int i = 0; i < numElements_; ++i) {
+ if (!compareElement(other, i))
+ return false;
+ }
+
+ return true;
default:
return false;
}
@@ -330,6 +592,12 @@ Control<bool>::Control(unsigned int id, const char *name)
{
}
+template<>
+Control<int8_t>::Control(unsigned int id, const char *name)
+ : ControlId(id, name, ControlTypeInteger8)
+{
+}
+
template<>
Control<int32_t>::Control(unsigned int id, const char *name)
: ControlId(id, name, ControlTypeInteger32)
@@ -341,6 +609,12 @@ Control<int64_t>::Control(unsigned int id, const char *name)
: ControlId(id, name, ControlTypeInteger64)
{
}
+
+template<>
+Control<float>::Control(unsigned int id, const char *name)
+ : ControlId(id, name, ControlTypeFloat)
+{
+}
#endif /* __DOXYGEN__ */
/**
@@ -583,15 +857,37 @@ ControlInfoMap::const_iterator ControlInfoMap::find(unsigned int id) const
* \return The ControlId map
*/
+bool ControlInfoMap::matchRangeType(enum ControlType type1, enum ControlType type2)
+{
+ if (type1 == type2)
+ return true;
+
+ switch (type1) {
+ case ControlTypeCompoundInt8:
+ return type2 == ControlTypeInteger8;
+ case ControlTypeCompoundInt32:
+ return type2 == ControlTypeInteger32;
+ case ControlTypeCompoundInt64:
+ return type2 == ControlTypeInteger64;
+ case ControlTypeCompoundFloat:
+ return type2 == ControlTypeFloat;
+ default:
+ return false;
+ }
+}
+
void ControlInfoMap::generateIdmap()
{
idmap_.clear();
for (const auto &ctrl : *this) {
- if (ctrl.first->type() != ctrl.second.min().type()) {
+ if (!matchRangeType(ctrl.first->type(),
+ ctrl.second.min().type())) {
LOG(Controls, Error)
<< "Control " << utils::hex(ctrl.first->id())
- << " type and range type mismatch";
+ << " type and range type mismatch: "
+ << ctrl.first->type() << " - "
+ << ctrl.second.min().type();
idmap_.clear();
clear();
return;
@@ -453,6 +453,13 @@ int VimcCameraData::init(MediaDevice *media)
std::forward_as_tuple(range));
}
+ /* Register a compound control. */
+ ctrls.emplace(std::piecewise_construct,
+ std::forward_as_tuple(&controls::CompoundControl),
+ std::forward_as_tuple(0, 100));
+
+
+
controlInfo_ = std::move(ctrls);
/* Initialize the camera properties. */
new file mode 100644
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * compound_controls.cpp - CompoundControls test
+ */
+
+#include <iostream>
+#include <vector>
+
+#include <libcamera/camera.h>
+#include <libcamera/camera_manager.h>
+#include <libcamera/control_ids.h>
+#include <libcamera/controls.h>
+#include <libcamera/span.h>
+
+#include "camera_controls.h"
+
+#include "camera_test.h"
+#include "test.h"
+
+using namespace std;
+using namespace libcamera;
+
+class CompoundControlsTest : public CameraTest, public Test
+{
+public:
+ CompoundControlsTest()
+ : CameraTest("VIMC Sensor B")
+ {
+ }
+
+protected:
+ int init() override
+ {
+ return status_;
+ }
+
+ int run() override
+ {
+ CameraControlValidator validator(camera_.get());
+ ControlList list(controls::controls, &validator);
+
+ /*
+ * Span
+ *
+ * A Span can be initialized with an initializer list
+ * and sequentially or random accessed
+ */
+ Span<int32_t> span = { 1, 2, 3 };
+ for (uint32_t i : span)
+ cout << i << endl;
+ cout << span[0] << endl;
+
+ /*
+ * Compound Controls
+ *
+ * As of now, all Controls are now 'compounds' when set with a
+ * Span<> of values.
+ *
+ * We need to define how to establish that a Control is actually
+ * a compound or supports a single value.
+ */
+ list.set(controls::Brightness, {0, 125, 255});
+ Span<int32_t> iSpan = list.get(controls::Brightness);
+
+ cout << iSpan.size() << endl;
+ for (uint32_t i : iSpan)
+ cout << i << endl;
+
+ /*
+ * But they can still be accessed and operated with a single
+ * value.
+ */
+ list.set(controls::Brightness, 112);
+ cout << list.get(controls::Brightness) << endl;
+
+ /*
+ * Or set with a Span and accessed by value. The first item
+ * is returned.
+ */
+ list.set(controls::Brightness, {50, 125});
+ cout << list.get(controls::Brightness) << endl;
+
+ /* The other way around works as well. */
+ list.set(controls::Brightness, 133);
+ Span<int32_t> s = list.get(controls::Brightness);
+ cout << s << endl;
+
+ return TestPass;
+ }
+};
+
+TEST_REGISTER(CompoundControlsTest)
@@ -3,6 +3,7 @@ control_tests = [
[ 'control_list', 'control_list.cpp' ],
[ 'control_range', 'control_range.cpp' ],
[ 'control_value', 'control_value.cpp' ],
+ [ 'compound_controls', 'compound_controls.cpp'],
]
foreach t : control_tests
A compound control transports an array of data values. Add support to compound controls to the ControlValue class. Signed-off-by: Jacopo Mondi <jacopo@jmondi.org> --- include/libcamera/controls.h | 50 +++- include/libcamera/span.h | 111 +++++++++ src/libcamera/control_ids.in | 0 src/libcamera/control_ids.yaml | 4 + src/libcamera/control_serializer.cpp | 15 +- src/libcamera/controls.cpp | 344 +++++++++++++++++++++++++-- src/libcamera/pipeline/vimc.cpp | 7 + test/controls/compound_controls.cpp | 94 ++++++++ test/controls/meson.build | 1 + 9 files changed, 596 insertions(+), 30 deletions(-) create mode 100644 include/libcamera/span.h create mode 100644 src/libcamera/control_ids.in create mode 100644 test/controls/compound_controls.cpp