From patchwork Sun Jun 2 13:04:30 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1330 X-Patchwork-Delegate: jacopo@jmondi.org Return-Path: Received: from relay11.mail.gandi.net (relay11.mail.gandi.net [217.70.178.231]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B1F8460BFA for ; Sun, 2 Jun 2019 15:03:44 +0200 (CEST) Received: from uno.homenet.telecomitalia.it (unknown [79.35.79.123]) (Authenticated sender: jacopo@jmondi.org) by relay11.mail.gandi.net (Postfix) with ESMTPSA id 17E55100005; Sun, 2 Jun 2019 13:03:43 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Sun, 2 Jun 2019 15:04:30 +0200 Message-Id: <20190602130435.18780-2-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190602130435.18780-1-jacopo@jmondi.org> References: <20190602130435.18780-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 1/6] libcamera: camera_sensor: Add dev() operation X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 02 Jun 2019 13:03:44 -0000 Add dev() operation to the CameraSensor class to access the V4L2Subdevice backing the camera sensor. Signed-off-by: Jacopo Mondi --- src/libcamera/camera_sensor.cpp | 6 ++++++ src/libcamera/include/camera_sensor.h | 1 + 2 files changed, 7 insertions(+) diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp index 2b9d8fa593c1..8cbef8bccbef 100644 --- a/src/libcamera/camera_sensor.cpp +++ b/src/libcamera/camera_sensor.cpp @@ -130,6 +130,12 @@ int CameraSensor::init() * \return The sensor media entity */ +/** + * \fn CameraSensor::dev() + * \brief Retrieve the sensor V4L2 subdevice + * \return The sensor V4L2 subdevice + */ + /** * \fn CameraSensor::mbusCodes() * \brief Retrieve the media bus codes supported by the camera sensor diff --git a/src/libcamera/include/camera_sensor.h b/src/libcamera/include/camera_sensor.h index b823480241a7..6cdf833a27bf 100644 --- a/src/libcamera/include/camera_sensor.h +++ b/src/libcamera/include/camera_sensor.h @@ -33,6 +33,7 @@ public: int init(); const MediaEntity *entity() const { return entity_; } + V4L2Subdevice *dev() const { return subdev_; } const std::vector &mbusCodes() const { return mbusCodes_; } const std::vector &sizes() const { return sizes_; } const Size &resolution() const; From patchwork Sun Jun 2 13:04:31 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1331 X-Patchwork-Delegate: jacopo@jmondi.org Return-Path: Received: from relay11.mail.gandi.net (relay11.mail.gandi.net [217.70.178.231]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BC86360BFA for ; Sun, 2 Jun 2019 15:03:45 +0200 (CEST) Received: from uno.homenet.telecomitalia.it (unknown [79.35.79.123]) (Authenticated sender: jacopo@jmondi.org) by relay11.mail.gandi.net (Postfix) with ESMTPSA id E76B6100005; Sun, 2 Jun 2019 13:03:44 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Sun, 2 Jun 2019 15:04:31 +0200 Message-Id: <20190602130435.18780-3-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190602130435.18780-1-jacopo@jmondi.org> References: <20190602130435.18780-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 2/6] libcamera: Provide a V4L2Base class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 02 Jun 2019 13:03:45 -0000 Provide a base class for V4L2 Devices and Subdevices to group common methods and fields. At the moment the code shared between V4L2Device and V4L2Subdevice is quite limited, but with the forthcoming introduction of control it will grow consistently. Signed-off-by: Jacopo Mondi --- src/libcamera/include/v4l2_base.h | 31 +++++++++++++ src/libcamera/include/v4l2_device.h | 9 ++-- src/libcamera/include/v4l2_subdevice.h | 9 ++-- src/libcamera/meson.build | 2 + src/libcamera/v4l2_base.cpp | 64 ++++++++++++++++++++++++++ src/libcamera/v4l2_device.cpp | 13 ++---- src/libcamera/v4l2_subdevice.cpp | 12 +---- 7 files changed, 110 insertions(+), 30 deletions(-) create mode 100644 src/libcamera/include/v4l2_base.h create mode 100644 src/libcamera/v4l2_base.cpp diff --git a/src/libcamera/include/v4l2_base.h b/src/libcamera/include/v4l2_base.h new file mode 100644 index 000000000000..2fda81a960d2 --- /dev/null +++ b/src/libcamera/include/v4l2_base.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * v4l2_base.h - Common base for V4L2 devices and subdevices + */ +#ifndef __LIBCAMERA_V4L2_BASE__ +#define __LIBCAMERA_V4L2_BASE__ + +#include + +namespace libcamera { + +class V4L2Base +{ +public: + virtual ~V4L2Base() + { + } + + virtual int open() = 0; + virtual void close() = 0; + bool isOpen() const; + +protected: + int fd_; +}; + +}; /* namespace libcamera */ + +#endif /* __LIBCAMERA_V4L2_BASE__ */ diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h index bdecc087fe5a..d9bcdb921b8c 100644 --- a/src/libcamera/include/v4l2_device.h +++ b/src/libcamera/include/v4l2_device.h @@ -17,6 +17,7 @@ #include #include "log.h" +#include "v4l2_base.h" namespace libcamera { @@ -111,7 +112,7 @@ public: const std::string toString() const; }; -class V4L2Device : protected Loggable +class V4L2Device : public V4L2Base, protected Loggable { public: explicit V4L2Device(const std::string &deviceNode); @@ -121,9 +122,8 @@ public: V4L2Device &operator=(const V4L2Device &) = delete; - int open(); - bool isOpen() const; - void close(); + int open() override; + void close() override; const char *driverName() const { return caps_.driver(); } const char *deviceName() const { return caps_.card(); } @@ -167,7 +167,6 @@ private: void bufferAvailable(EventNotifier *notifier); std::string deviceNode_; - int fd_; V4L2Capability caps_; enum v4l2_buf_type bufferType_; diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h index 3e4e5107aebe..bdef3e69dd8c 100644 --- a/src/libcamera/include/v4l2_subdevice.h +++ b/src/libcamera/include/v4l2_subdevice.h @@ -16,6 +16,7 @@ #include "formats.h" #include "log.h" #include "media_object.h" +#include "v4l2_base.h" namespace libcamera { @@ -28,7 +29,7 @@ struct V4L2SubdeviceFormat { const std::string toString() const; }; -class V4L2Subdevice : protected Loggable +class V4L2Subdevice : public V4L2Base, protected Loggable { public: explicit V4L2Subdevice(const MediaEntity *entity); @@ -36,9 +37,8 @@ public: V4L2Subdevice &operator=(const V4L2Subdevice &) = delete; ~V4L2Subdevice(); - int open(); - bool isOpen() const; - void close(); + int open() override; + void close() override; const MediaEntity *entity() const { return entity_; } @@ -64,7 +64,6 @@ private: Rectangle *rect); const MediaEntity *entity_; - int fd_; }; } /* namespace libcamera */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 6a73580d71f5..6d858a22531e 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -21,6 +21,7 @@ libcamera_sources = files([ 'stream.cpp', 'timer.cpp', 'utils.cpp', + 'v4l2_base.cpp', 'v4l2_device.cpp', 'v4l2_subdevice.cpp', ]) @@ -38,6 +39,7 @@ libcamera_headers = files([ 'include/media_object.h', 'include/pipeline_handler.h', 'include/utils.h', + 'include/v4l2_base.h', 'include/v4l2_device.h', 'include/v4l2_subdevice.h', ]) diff --git a/src/libcamera/v4l2_base.cpp b/src/libcamera/v4l2_base.cpp new file mode 100644 index 000000000000..7d05a3c82e4d --- /dev/null +++ b/src/libcamera/v4l2_base.cpp @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * v4l2_base.cpp - Common base for V4L2 devices and subdevices + */ + +#include "v4l2_base.h" + +/** + * \file v4l2_base.h + * \brief Common base for V4L2 devices and subdevices + */ + +namespace libcamera { + +/** + * \class V4L2Base + * \brief Base class for V4L2Device and V4L2Subdevice + * + * The V4L2Base class groups together the methods and fields common to + * both V4L2Device and V4L2Subdevice, and provide a base abstract class which + * defines a streamlined interface that both the derived class have to implement. + * + * The interface defined by V4L2Base only requires derived classes to implement + * methods that modifies the status of the file descriptor associated with + * the video device or subdevice, such as \a open() and \a close(). + * + * Methods common to V4L2Device and V4L2Subdevice, such as V4L2 controls + * support are implemented in the base class to maximize code re-use. + */ + +/** + * \brief Open a V4L2 device or subdevice + * + * Pure virtual method to be implemented by the derived classes. + * + * \return 0 on success or a negative error code otherwise + */ + +/** + * \brief Close the device or subdevice + * + * Pure virtual method to be implemented by the derived classes. + */ + +/** + * \brief Check if the V4L2 device or subdevice is open + * \return True if the V4L2 device or subdevice is open, false otherwise + */ +bool V4L2Base::isOpen() const +{ + return fd_ != -1; +} + +/** + * \var V4L2Base::fd_ + * \brief The V4L2 device or subdevice device node file descriptor + * + * The file descriptor is initialized to -1 and reset to this value once + * the device or subdevice gets closed. + */ + +}; /* namespace libcamera */ diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp index 0821bd75fb42..64533e88a512 100644 --- a/src/libcamera/v4l2_device.cpp +++ b/src/libcamera/v4l2_device.cpp @@ -270,9 +270,11 @@ const std::string V4L2DeviceFormat::toString() const * \param[in] deviceNode The file-system path to the video device node */ V4L2Device::V4L2Device(const std::string &deviceNode) - : deviceNode_(deviceNode), fd_(-1), bufferPool_(nullptr), + : deviceNode_(deviceNode), bufferPool_(nullptr), queuedBuffersCount_(0), fdEvent_(nullptr) { + fd_ = -1; + /* * We default to an MMAP based CAPTURE device, however this will be * updated based upon the device capabilities. @@ -368,15 +370,6 @@ int V4L2Device::open() return 0; } -/** - * \brief Check if device is successfully opened - * \return True if the device is open, false otherwise - */ -bool V4L2Device::isOpen() const -{ - return fd_ != -1; -} - /** * \brief Close the device, releasing any resources acquired by open() */ diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index fceee33156e9..3a053fadb3f6 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -102,8 +102,9 @@ const std::string V4L2SubdeviceFormat::toString() const * path */ V4L2Subdevice::V4L2Subdevice(const MediaEntity *entity) - : entity_(entity), fd_(-1) + : entity_(entity) { + fd_ = -1; } V4L2Subdevice::~V4L2Subdevice() @@ -137,15 +138,6 @@ int V4L2Subdevice::open() return 0; } -/** - * \brief Check if the subdevice is open - * \return True if the subdevice is open, false otherwise - */ -bool V4L2Subdevice::isOpen() const -{ - return fd_ != -1; -} - /** * \brief Close the subdevice, releasing any resources acquired by open() */ From patchwork Sun Jun 2 13:04:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1332 Return-Path: Received: from relay11.mail.gandi.net (relay11.mail.gandi.net [217.70.178.231]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 16A2760BFA for ; Sun, 2 Jun 2019 15:03:47 +0200 (CEST) Received: from uno.homenet.telecomitalia.it (unknown [79.35.79.123]) (Authenticated sender: jacopo@jmondi.org) by relay11.mail.gandi.net (Postfix) with ESMTPSA id EE40C100005; Sun, 2 Jun 2019 13:03:45 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Sun, 2 Jun 2019 15:04:32 +0200 Message-Id: <20190602130435.18780-4-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190602130435.18780-1-jacopo@jmondi.org> References: <20190602130435.18780-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 3/6] libcamera: Add V4L2Controls X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 02 Jun 2019 13:03:47 -0000 Add Libcamera V4L2 control support, implemented using the V4L2 Extended Control APIs. This patch defines the types used to define and manage controls. Signed-off-by: Jacopo Mondi --- src/libcamera/include/v4l2_controls.h | 147 +++++++++++++ src/libcamera/meson.build | 1 + src/libcamera/v4l2_controls.cpp | 301 ++++++++++++++++++++++++++ 3 files changed, 449 insertions(+) create mode 100644 src/libcamera/include/v4l2_controls.h create mode 100644 src/libcamera/v4l2_controls.cpp diff --git a/src/libcamera/include/v4l2_controls.h b/src/libcamera/include/v4l2_controls.h new file mode 100644 index 000000000000..df955c2e10b2 --- /dev/null +++ b/src/libcamera/include/v4l2_controls.h @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * v4l2_controls.h - V4L2 Extended Control Support + */ + +#ifndef __LIBCAMERA_V4L2_CONTROL_H__ +#define __LIBCAMERA_V4L2_CONTROL_H__ + +#include + +#include +#include + +namespace libcamera { + +class V4L2Control +{ +public: + virtual ~V4L2Control() + { + } + + unsigned int id() { return id_; } + unsigned int size() { return size_; } + enum v4l2_ctrl_type type() const { return type_; } + +protected: + V4L2Control(unsigned int id, unsigned int size, + enum v4l2_ctrl_type type) + : id_(id), size_(size), type_(type) + { + } + +private: + unsigned int id_; + unsigned int size_; + enum v4l2_ctrl_type type_; +}; + +template +class V4L2ControlValue : public V4L2Control +{ +public: + T value() const { return value_; } + T *mem() const { return memvalue_; } + +protected: + V4L2ControlValue(unsigned int id, unsigned int size, + enum v4l2_ctrl_type type, T value) + : V4L2Control(id, size, type) + { + value_ = value; + memvalue_ = nullptr; + } + + V4L2ControlValue(unsigned int id, unsigned int size, + enum v4l2_ctrl_type type, T *value) + : V4L2Control(id, size, type) + { + value_ = 0; + memvalue_ = static_cast(new T[size]); + memcpy(memvalue_, value, size); + } + + ~V4L2ControlValue() + { + delete[] memvalue_; + } + +private: + T value_; + T *memvalue_; +}; + +class V4L2IntControl : public V4L2ControlValue +{ +public: + V4L2IntControl(unsigned int id, int32_t value) + : V4L2ControlValue(id, sizeof(int32_t), + V4L2_CTRL_TYPE_INTEGER, value) + { + } +}; + +class V4L2Int64Control : public V4L2ControlValue +{ +public: + V4L2Int64Control(unsigned int id, int64_t value) + : V4L2ControlValue(id, sizeof(int64_t), + V4L2_CTRL_TYPE_INTEGER64, value) + { + } +}; + +class V4L2BoolControl : public V4L2ControlValue +{ +public: + V4L2BoolControl(unsigned int id, bool value) + : V4L2ControlValue(id, sizeof(bool), + V4L2_CTRL_TYPE_BOOLEAN, value) + { + } +}; + +class V4L2StringControl : public V4L2ControlValue +{ +public: + V4L2StringControl(unsigned int id, std::string value) + : V4L2ControlValue(id, value.length(), + V4L2_CTRL_TYPE_STRING, value) + { + } +}; + +class V4L2U8Control : public V4L2ControlValue +{ +public: + V4L2U8Control(unsigned int id, unsigned int size, uint8_t *mem) + : V4L2ControlValue(id, size, V4L2_CTRL_TYPE_U8, mem) + { + } +}; + +class V4L2U16Control : public V4L2ControlValue +{ +public: + V4L2U16Control(unsigned int id, unsigned int size, uint16_t *mem) + : V4L2ControlValue(id, size, V4L2_CTRL_TYPE_U16, mem) + { + } +}; + +class V4L2U32Control : public V4L2ControlValue +{ +public: + V4L2U32Control(unsigned int id, unsigned int size, uint32_t *mem) + : V4L2ControlValue(id, size, V4L2_CTRL_TYPE_U32, mem) + { + } +}; + +}; /* namespace libcamera */ + +#endif /* __LIBCAMERA_V4L2_CONTROL_H__ */ + diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 6d858a22531e..fa1fbcb5faf5 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -22,6 +22,7 @@ libcamera_sources = files([ 'timer.cpp', 'utils.cpp', 'v4l2_base.cpp', + 'v4l2_controls.cpp', 'v4l2_device.cpp', 'v4l2_subdevice.cpp', ]) diff --git a/src/libcamera/v4l2_controls.cpp b/src/libcamera/v4l2_controls.cpp new file mode 100644 index 000000000000..f50f3cdfa7d7 --- /dev/null +++ b/src/libcamera/v4l2_controls.cpp @@ -0,0 +1,301 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * v4l2_controls.cpp - V4L2 Extended Control Support + */ + +/** + * \file v4l2_controls.h + * \brief Support for V4L2 Controls using the V4L2 Extended Controls APIs. + * + * The V4L2 defined "Control API" allows application to inspect and modify set + * of configurable parameters on the video device or subdevice of interest. The + * nature of the parameters an application could modify using the control + * framework depends on what the driver implements support for, and on the + * characteristics of the underlying hardware platform. Generally controls are + * used to modify user visible settings, such as the image brightness and + * exposure time, or non-standard parameters which cannot be controlled through + * the V4L2 format negotiation API. + * + * Controls are identified by a numerical id, defined by the V4L2 kernel headers + * and have an associated type and class. Each control has a 'value', which is + * the data that can be modified with a 'setControl()' operation call or + * retrieved with a 'getControl()' one. + * + * A control class defines the control purpose while its type (along with the + * control's flags) defines the type of the control's value content. Controls + * might transport a single data value stored in variable inside the control, or + * they might as well deal with more complex data types, such as arrays of + * matrixes, stored in a contiguous memory locations associated with the control + * and called 'the payload'. The content have to be opportunely copied into the + * application memory when retrieving a control's value and provided to the V4L2 + * device when setting it. + * + * Libcamera supports control using the V4L2 'Extended Control' framework, which + * allows easier handling of controls with payloads of arbitrary sizes. + * + * The Libcamera V4L2 Controls framework operates on lists of controls, to match + * the V4L2 extended controls framework, but also provides operations to get + * and set single controls. The interface to set and get control is implemented + * by the V4L2Base class, while this file only provides the data type + * definitions. + * + * The Libcamera V4L2 control framework data types define a base class + * V4L2Control that contains the fields common to all controls, regardless of + * their type, such as the control's id, its type and the expected control's + * value data size. The V4L2Control class is not meant to be instantiated + * directly, but is instead used as placeholder to store controls in the + * standard library provided containers. + * + * A parametric derived class V4L2ControlValue stores the control's value and + * provide accessors to the value itself for control with no payload, or to the + * memory area that contains the control's data payload. This class is not + * intended to be directly used and cannot be constructed, but it is used + * instead to define specialized derived classes which specialize the control's + * data value type. + * + * In order to set and get controls, user of the Libcamera V4L2 control + * framework should create instances of the specialized derived classes, + * which are publicly constructible, and use them to access the control's data + * content using the 'value()' method for controls with no payload, or + * retrieving reference to the memory location that contains the data payload + * with the 'mem()' operation for controls which transport a data payload. + * + * \todo Support setting controls with data payload. + */ + +namespace libcamera { + +/** + * \class V4L2Control + * \brief Base class for V4L2 Controls + * + * The V4L2Control base class is the base class that contains the fields common + * to all controls (id, type and size). + * + * This class is not meant to be instantiated directly, but is instead used as a + * place holder to store controls in arrays or other containers. User of the + * libcamera V4L2 control framework should access the controls content by + * instantiating one of the provided specialized derived classes. + */ + +/** + * \fn V4L2Control::V4L2Control + * \brief Construct a V4L2Control instance + * \param id The control's id + * \param size The control's data size + * \param type The control's type + */ + +/** + * \fn V4L2Control::id() + * \brief Retrieve the control's id + * + * Retrieve the control's numerical id value as defined by the V4L2 + * specification. + * + * \return The control's id + */ + +/** + * \fn V4L2Control::size() + * \brief Retrieve the control's data value size in bytes + * + * \todo Better define the value of size() for controls with payload data. + * + * \return The control's size + */ + +/** + * \fn V4L2Control::type() + * \brief Retrieve the control's type + * + * Retrieve the control's type as defined by the V4L2 specification. + * + * \return The control's type + */ + +/** + * \class V4L2ControlValue + * \brief Template base class that represent values of a V4L2 control + * + * The V4L2ControlValue template base class represents a V4L2 control with + * its different value types. + * + * It provides two operations to access the control's value or the pointer + * to the memory location that contains to the control's value data payload. + */ + +/** + * \fn V4L2ControlValue::V4L2ControlValue(unsigned int id, unsigned int size, enum v4l2_ctrl_type type, T value) + * \brief Contruct a V4L2ControlValue with a value + * \param id The control's id + * \param size The control's size + * \param type The control's type + * \param value The control's value + */ + +/** + * \fn V4L2ControlValue::V4L2ControlValue(unsigned int id, unsigned int size, enum v4l2_ctrl_type type, T* value) + * \brief Contruct a V4L2ControlValue with a pointer to a data payload + * \param id The control's id + * \param size The control's size + * \param type The control's type + * \param value The pointer to the control's data payload + */ + +/** + * \fn V4L2ControlValue::~V4L2ControlValue + * \brief Release the memory reserved for the control's data payload, if any + */ + +/** + * \fn V4L2ControlValue::value() + * \brief Retrieve the control's value + * + * Retrieve the control's value. Valid only for controls with no payload. + * Access a control's value by calling the value() operation on instances + * of the specialized derived classes. + */ + +/** + * \fn V4L2ControlValue::mem() + * \brief Retrieve a pointer to the memory location of the control's data + * + * Retrieve a pointer to the memory location that contains the control's data + * payload. Valid only for controls with data payload. Access the memory + * location of the control's data by calling the mem() operation on instances + * of the specialized derived classes. + */ + +/** + * \class V4L2IntControl + * \brief Specialized V4L2Control class that handles controls of + * V4L2_CTRL_TYPE_INTEGER type. + * + * Access the control's data value by using the value() operation. + */ + +/** + * \fn V4L2IntControl::V4L2IntControl() + * \brief Construct a V4L2Control that contains an int value + * \param id The control's id + * \param value The control's value + */ + +/** + * \class V4L2Int64Control + * \brief Specialized V4L2Control class that handles controls of + * V4L2_CTRL_TYPE_INTEGER64 type. + * + * Access the control's data value by using the value() operation. + */ + +/** + * \fn V4L2Int64Control::V4L2Int64Control() + * \brief Construct a V4L2Control that contains an int64 value + * \param id The control's id + * \param value The control's value + */ + +/** + * \class V4L2BoolControl + * \brief Specialized V4L2Control class that handles controls of + * V4L2_CTRL_TYPE_BOOLEAN type. + * + * Access the control's data value by using the value() operation. + */ + +/** + * \fn V4L2BoolControl::V4L2BoolControl() + * \brief Construct a V4L2Control that contains a boolean value + * \param id The control's id + * \param value The control's value + */ + +/** + * \class V4L2StringControl + * \brief Specialized V4L2Control class that handles controls of + * V4L2_CTRL_TYPE_STRING type. + * + * Access the control's data value by using the value() operation. + */ + +/** + * \fn V4L2StringControl::V4L2StringControl() + * \brief Construct a V4L2Control that contains a string value + * \param id The control's id + * \param value The control's value + */ + +/** + * \class V4L2U8Control + * \brief Specialized V4L2Control class that handles controls with payload of + * V4L2_CTRL_TYPE_U8 type. + * + * Access the control's data value by using the retrieving the memory location + * where the data payload is stored with the mem() operation. The size of + * the payload data can be retrieved with the size() operation. + */ + +/** + * \fn V4L2U8Control::V4L2U8Control() + * \brief Construct a V4L2Control with payload of uin8_t data + * \param id The control's id + * \param size The size in bytes of the payload content + * \param mem Pointer to the memory location of the payload content + * + * Memory is reserved in the newly created instance to hold the data payload + * and the data content is copied there. The reserved memory is then freed when + * the Control is destroyed. The memory where the control's payload was copied + * from should be released by the caller. + */ + +/** + * \class V4L2U16Control + * \brief Specialized V4L2Control class that handles controls with payload of + * V4L2_CTRL_TYPE_U16 type. + * + * Access the control's data value by using the retrieving the memory location + * where the data payload is stored with the mem() operation. The size of + * the payload data can be retrieved with the size() operation. + */ + +/** + * \fn V4L2U16Control::V4L2U16Control(unsigned int id, unsigned int size, uint16_t *mem) + * \brief Construct a V4L2Control with payload of uin16_t data + * \param id The control's id + * \param size The size in bytes of the payload content + * \param mem Pointer to the memory location of the payload content + * + * Memory is reserved in the newly created instance to hold the data payload + * and the data content is copied there. The reserved memory is then freed when + * the Control is destroyed. The memory where the control's payload was copied + * from should be released by the caller. + */ + +/** + * \class V4L2U32Control + * \brief Specialized V4L2Control class that handles controls with payload of + * V4L2_CTRL_TYPE_U32 type. + * + * Access the control's data value by using the retrieving the memory location + * where the data payload is stored with the mem() operation. The size of + * the payload data can be retrieved with the size() operation. + */ + +/** + * \fn V4L2U32Control::V4L2U32Control(unsigned int id, unsigned int size, uint32_t *mem) + * \brief Construct a V4L2Control with payload of uin32_t data + * \param id The control's id + * \param size The size in bytes of the payload content + * \param mem Pointer to the memory location of the payload content + * + * Memory is reserved in the newly created instance to hold the data payload + * and the data content is copied there. The reserved memory is then freed when + * the Control is destroyed. The memory where the control's payload was copied + * from should be released by the caller. + */ + +}; /* namespace libcamera */ From patchwork Sun Jun 2 13:04:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1333 X-Patchwork-Delegate: jacopo@jmondi.org Return-Path: Received: from relay11.mail.gandi.net (relay11.mail.gandi.net [217.70.178.231]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3C6F760BFA for ; Sun, 2 Jun 2019 15:03:48 +0200 (CEST) Received: from uno.homenet.telecomitalia.it (unknown [79.35.79.123]) (Authenticated sender: jacopo@jmondi.org) by relay11.mail.gandi.net (Postfix) with ESMTPSA id 4992F100005; Sun, 2 Jun 2019 13:03:47 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Sun, 2 Jun 2019 15:04:33 +0200 Message-Id: <20190602130435.18780-5-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190602130435.18780-1-jacopo@jmondi.org> References: <20190602130435.18780-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 4/6] libcamera: v4l2_base: Add V4L2 control support X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 02 Jun 2019 13:03:48 -0000 Implement operations to set and get V4L2 controls in the V4L2Base class. The operations allow to set and get a single or a list of controls. Signed-off-by: Jacopo Mondi --- src/libcamera/include/v4l2_base.h | 12 ++ src/libcamera/v4l2_base.cpp | 290 ++++++++++++++++++++++++++++++ 2 files changed, 302 insertions(+) diff --git a/src/libcamera/include/v4l2_base.h b/src/libcamera/include/v4l2_base.h index 2fda81a960d2..7d4e238dadfa 100644 --- a/src/libcamera/include/v4l2_base.h +++ b/src/libcamera/include/v4l2_base.h @@ -9,6 +9,8 @@ #include +#include + namespace libcamera { class V4L2Base @@ -22,8 +24,18 @@ public: virtual void close() = 0; bool isOpen() const; + std::vector getControls(std::vector &ctrl_ids); + V4L2Control *getControl(unsigned int ctrl_id); + int setControls(std::vector &ctrls); + int setControl(V4L2Control *ctrl); + protected: int fd_; + +private: + int queryControl(unsigned int ctrl_id, + struct v4l2_query_ext_ctrl *qext_ctrl); + }; }; /* namespace libcamera */ diff --git a/src/libcamera/v4l2_base.cpp b/src/libcamera/v4l2_base.cpp index 7d05a3c82e4d..423a4d84e276 100644 --- a/src/libcamera/v4l2_base.cpp +++ b/src/libcamera/v4l2_base.cpp @@ -5,7 +5,13 @@ * v4l2_base.cpp - Common base for V4L2 devices and subdevices */ +#include +#include +#include + +#include "log.h" #include "v4l2_base.h" +#include "v4l2_controls.h" /** * \file v4l2_base.h @@ -14,6 +20,8 @@ namespace libcamera { +LOG_DEFINE_CATEGORY(V4L2Base) + /** * \class V4L2Base * \brief Base class for V4L2Device and V4L2Subdevice @@ -31,6 +39,7 @@ namespace libcamera { */ /** + * \fn V4L2Base::open() * \brief Open a V4L2 device or subdevice * * Pure virtual method to be implemented by the derived classes. @@ -39,6 +48,7 @@ namespace libcamera { */ /** + * \fn V4L2Base::close() * \brief Close the device or subdevice * * Pure virtual method to be implemented by the derived classes. @@ -53,6 +63,286 @@ bool V4L2Base::isOpen() const return fd_ != -1; } +int V4L2Base::queryControl(unsigned int id, + struct v4l2_query_ext_ctrl *qext_ctrl) +{ + qext_ctrl->id = id; + + int ret = ioctl(fd_, VIDIOC_QUERY_EXT_CTRL, qext_ctrl); + if (ret) { + ret = -errno; + LOG(V4L2Base, Error) + << "Unable to query extended control 0x" + << std::hex << qext_ctrl->id + << ": " << strerror(-ret); + return ret; + } + + if (qext_ctrl->flags & V4L2_CTRL_FLAG_DISABLED) { + LOG(V4L2Base, Error) + << "Extended control 0x" << std::hex + << qext_ctrl->id << " is disabled"; + return -EINVAL; + } + + return 0; +} + +/** + * \brief Get values of a list of control IDs + * \param ctrl_ids The list of control IDs to retrieve value of + * \return A list of V4L2Control on success or a empty list otherwise + */ +std::vector V4L2Base::getControls(std::vector &ctrl_ids) +{ + unsigned int count = ctrl_ids.size(); + if (!count) + return std::vector {}; + + struct v4l2_ext_control *v4l2_ctrls = static_cast + (new struct v4l2_ext_control[count]); + if (!v4l2_ctrls) + return std::vector {}; + + /* + * Query each control in the vector to get back its type and expected + * size in order to get its current value. + */ + for (unsigned int i = 0; i < count; ++i) { + struct v4l2_ext_control *v4l2_ctrl = &v4l2_ctrls[i]; + unsigned int ctrl_id = ctrl_ids[i]; + struct v4l2_query_ext_ctrl qext_ctrl = {}; + + int ret = queryControl(ctrl_id, &qext_ctrl); + if (ret) + return std::vector {}; + + v4l2_ctrl->id = ctrl_id; + v4l2_ctrl->size = qext_ctrl.elem_size * qext_ctrl.elems; + + /* Reserve memory for controls with payload. */ + if (!(qext_ctrl.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD)) + continue; + + switch (qext_ctrl.type) { + case V4L2_CTRL_TYPE_U8: + v4l2_ctrl->p_u8 = static_cast + (new uint8_t[v4l2_ctrl->size]); + break; + case V4L2_CTRL_TYPE_U16: + v4l2_ctrl->p_u16 = static_cast + (new uint16_t[v4l2_ctrl->size]); + break; + case V4L2_CTRL_TYPE_U32: + v4l2_ctrl->p_u32 = static_cast + (new uint32_t[v4l2_ctrl->size]); + break; + } + } + + struct v4l2_ext_controls v4l2_ext_ctrls = {}; + v4l2_ext_ctrls.which = V4L2_CTRL_WHICH_CUR_VAL; + v4l2_ext_ctrls.count = count; + v4l2_ext_ctrls.controls = v4l2_ctrls; + + int ret = ioctl(fd_, VIDIOC_G_EXT_CTRLS, &v4l2_ext_ctrls); + if (ret) { + ret = -errno; + LOG(V4L2Base, Error) + << "Unable to get extended controls: " << strerror(-ret); + return std::vector {}; + } + + /* + * For each requested control, create a V4L2Control which contains + * the current value and store it in the vector returned to the caller. + */ + std::vector controls = {}; + for (unsigned int i = 0; i < count; ++i) { + struct v4l2_ext_control *v4l2_ctrl = &v4l2_ctrls[i]; + struct v4l2_query_ext_ctrl qext_ctrl = {}; + + int ret = queryControl(v4l2_ctrl->id, &qext_ctrl); + if (ret) + return std::vector {}; + + unsigned int size = qext_ctrl.elem_size * qext_ctrl.elem_size; + if (qext_ctrl.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD) { + /* Control types with payload */ + switch (qext_ctrl.type) { + case V4L2_CTRL_TYPE_U8: + { + V4L2U8Control *c = + new V4L2U8Control(v4l2_ctrl->id, size, + v4l2_ctrl->p_u8); + controls.push_back(c); + } + break; + case V4L2_CTRL_TYPE_U16: + { + V4L2U16Control *c = + new V4L2U16Control(v4l2_ctrl->id, size, + v4l2_ctrl->p_u16); + controls.push_back(c); + } + break; + case V4L2_CTRL_TYPE_U32: + { + V4L2U32Control *c = + new V4L2U32Control(v4l2_ctrl->id, size, + v4l2_ctrl->p_u32); + controls.push_back(c); + } + break; + default: + LOG(V4L2Base, Error) + << "Compound control types not supported: " + << std::hex << qext_ctrl.type; + return std::vector {}; + } + } else { + /* Control types without payload. */ + switch (qext_ctrl.type) { + case V4L2_CTRL_TYPE_INTEGER64: + { + V4L2Int64Control *c = + new V4L2Int64Control(v4l2_ctrl->id, + v4l2_ctrl->value64); + controls.push_back(c); + } + break; + case V4L2_CTRL_TYPE_INTEGER: + case V4L2_CTRL_TYPE_BOOLEAN: + case V4L2_CTRL_TYPE_MENU: + case V4L2_CTRL_TYPE_BUTTON: + { + V4L2IntControl *c = + new V4L2IntControl(v4l2_ctrl->id, + v4l2_ctrl->value); + controls.push_back(c); + } + break; + default: + LOG(V4L2Base, Error) + << "Invalid non-compound control type :" + << std::hex << qext_ctrl.type; + return std::vector {}; + } + } + } + + return controls; +} + +/** + * \brief Get the value of control with id \a ctrl_id + * \param ctrl_id The control id + * \return The V4L2Control which represent the value of the control on success + * nullptr otherwise + */ +V4L2Control *V4L2Base::getControl(unsigned int ctrl_id) +{ + std::vector v = { ctrl_id, }; + std::vector ctrls = getControls(v); + + if (ctrls.empty()) + return nullptr; + + return ctrls[0]; +} + +/** + * \brief Apply a list of controls to the device + * \param ctrls The list of controls to apply + * \return 0 on success or a negative error code otherwise + */ +int V4L2Base::setControls(std::vector &ctrls) +{ + unsigned int count = ctrls.size(); + if (!count) + return -EINVAL; + + struct v4l2_ext_control *v4l2_ctrls = static_cast + (new struct v4l2_ext_control[count]); + if (!v4l2_ctrls) + return -ENOMEM; + + /* + * Query each control in the vector to get back its type and expected + * size and set the new desired value in each v4l2_ext_control member. + */ + for (unsigned int i = 0; i < count; ++i) { + struct v4l2_ext_control *v4l2_ctrl = &v4l2_ctrls[i]; + struct v4l2_query_ext_ctrl qext_ctrl = {}; + V4L2Control *ctrl = ctrls[i]; + + int ret = queryControl(ctrl->id(), &qext_ctrl); + if (ret) + return ret; + + v4l2_ctrl->id = ctrl->id(); + v4l2_ctrl->size = qext_ctrl.elem_size * qext_ctrl.elems; + + if (qext_ctrl.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD) { + /** \todo: Support set controls with payload. */ + LOG(V4L2Base, Error) + << "Controls with payload not supported"; + return -EINVAL; + } else { + switch (qext_ctrl.type) { + case V4L2_CTRL_TYPE_INTEGER64: + { + V4L2Int64Control *c = + static_cast(ctrl); + v4l2_ctrl->value64 = c->value(); + } + break; + case V4L2_CTRL_TYPE_INTEGER: + case V4L2_CTRL_TYPE_BOOLEAN: + case V4L2_CTRL_TYPE_MENU: + case V4L2_CTRL_TYPE_BUTTON: + { + V4L2IntControl *c = + static_cast(ctrl); + v4l2_ctrl->value = c->value(); + } + break; + default: + LOG(V4L2Base, Error) + << "Invalid non-compound control type :" + << qext_ctrl.type; + return -EINVAL; + } + } + } + + struct v4l2_ext_controls v4l2_ext_ctrls = {}; + v4l2_ext_ctrls.which = V4L2_CTRL_WHICH_CUR_VAL; + v4l2_ext_ctrls.count = count; + v4l2_ext_ctrls.controls = v4l2_ctrls; + + int ret = ioctl(fd_, VIDIOC_S_EXT_CTRLS, &v4l2_ext_ctrls); + if (ret) { + ret = -errno; + LOG(V4L2Base, Error) + << "Unable to set extended controls: " << strerror(-ret); + return ret; + } + + return 0; +} + +/** + * \brief Apply the control \a ctrl to the device + * \param ctrl The control to apply to the device + * \return 0 on success, a negative error code otherwise + */ +int V4L2Base::setControl(V4L2Control *ctrl) +{ + std::vector v = { ctrl, }; + return setControls(v); +} + /** * \var V4L2Base::fd_ * \brief The V4L2 device or subdevice device node file descriptor From patchwork Sun Jun 2 13:04:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1334 Return-Path: Received: from relay11.mail.gandi.net (relay11.mail.gandi.net [217.70.178.231]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 087E761905 for ; Sun, 2 Jun 2019 15:03:49 +0200 (CEST) Received: from uno.homenet.telecomitalia.it (unknown [79.35.79.123]) (Authenticated sender: jacopo@jmondi.org) by relay11.mail.gandi.net (Postfix) with ESMTPSA id 61584100009; Sun, 2 Jun 2019 13:03:48 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Sun, 2 Jun 2019 15:04:34 +0200 Message-Id: <20190602130435.18780-6-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190602130435.18780-1-jacopo@jmondi.org> References: <20190602130435.18780-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 5/6] libcamera: ipu3: Set pipe_mode based on stream configuration X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 02 Jun 2019 13:03:49 -0000 Set the ImgU pipe_mode control based on the active stream configuration. Use 'Video' pipe mode unless the viewfinder stream is not active. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 30 ++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 05005c42106b..0a50b6159782 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -22,6 +22,7 @@ #include "media_device.h" #include "pipeline_handler.h" #include "utils.h" +#include "v4l2_controls.h" #include "v4l2_device.h" #include "v4l2_subdevice.h" @@ -29,6 +30,10 @@ namespace libcamera { LOG_DEFINE_CATEGORY(IPU3) +#define IPU3_PIPE_MODE_CTRL 0x009819c1 +static V4L2IntControl IPU3PipeModeStillCapture(IPU3_PIPE_MODE_CTRL, 1); +static V4L2IntControl IPU3PipeModeVideo(IPU3_PIPE_MODE_CTRL, 0); + class ImgUDevice { public: @@ -485,6 +490,7 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c) IPU3Stream *vfStream = &data->vfStream_; CIO2Device *cio2 = &data->cio2_; ImgUDevice *imgu = data->imgu_; + V4L2IntControl *pipeMode; int ret; /* @@ -536,6 +542,7 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c) * the configuration of the active one for that purpose (there should * be at least one active stream in the configuration request). */ + pipeMode = &IPU3PipeModeVideo; if (!outStream->active_) { ret = imgu->configureOutput(outStream->device_, config->at(0)); if (ret) @@ -546,6 +553,12 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c) ret = imgu->configureOutput(vfStream->device_, config->at(0)); if (ret) return ret; + + /* + * \todo: This works as long as only two concurrent streams + * per pipe are supported. + */ + pipeMode = &IPU3PipeModeStillCapture; } /* @@ -559,6 +572,23 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c) if (ret) return ret; + /* Apply the "pipe_mode" control to the ImgU subdevice. */ + ret = imgu->imgu_->setControl(pipeMode); + if (ret) { + LOG(IPU3, Error) << "Unable to set pipe_mode control"; + return ret; + } + + V4L2Control *pipeModeCtrl = imgu->imgu_->getControl(IPU3_PIPE_MODE_CTRL); + if (!pipeModeCtrl) { + LOG(IPU3, Error) << "Unable to get pipe_mode control value"; + return ret; + } + + pipeMode = static_cast(pipeModeCtrl); + LOG(IPU3, Debug) << "ImgU pipe mode set to: " + << (pipeMode->value() ? "'Still Capture'" + : "'Video'"); return 0; } From patchwork Sun Jun 2 13:04:35 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1335 X-Patchwork-Delegate: jacopo@jmondi.org Return-Path: Received: from relay11.mail.gandi.net (relay11.mail.gandi.net [217.70.178.231]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id DB93861905 for ; Sun, 2 Jun 2019 15:03:49 +0200 (CEST) Received: from uno.homenet.telecomitalia.it (unknown [79.35.79.123]) (Authenticated sender: jacopo@jmondi.org) by relay11.mail.gandi.net (Postfix) with ESMTPSA id 39FBE100003; Sun, 2 Jun 2019 13:03:49 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Sun, 2 Jun 2019 15:04:35 +0200 Message-Id: <20190602130435.18780-7-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190602130435.18780-1-jacopo@jmondi.org> References: <20190602130435.18780-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 6/6] [HACK] ipu3: Set and get a few sensor controls X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 02 Jun 2019 13:03:50 -0000 Not to merge patch to demonstrate how to set controls on the image sensor device. Not-Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 86 ++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 0a50b6159782..7854e5140de8 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -689,6 +689,92 @@ int PipelineHandlerIPU3::start(Camera *camera) ImgUDevice *imgu = data->imgu_; int ret; + /* --- Get control values --- */ + std::vector controlIds = { + V4L2_CID_EXPOSURE, V4L2_CID_ANALOGUE_GAIN, + }; + std::vector controls = + cio2->sensor_->dev()->getControls(controlIds); + if (controls.empty()) { + LOG(Error) << "Failed to get control values"; + return -EINVAL; + } + + for (V4L2Control *ctrl : controls) { + unsigned int id = ctrl->id(); + + switch(ctrl->type()) { + case V4L2_CTRL_TYPE_INTEGER: + case V4L2_CTRL_TYPE_BOOLEAN: + { + V4L2IntControl *c = static_cast(ctrl); + uint32_t val = c->value(); + LOG(Error) << "Control : " << id + << " - value: " << val; + } + break; + case V4L2_CTRL_TYPE_INTEGER64: + { + V4L2Int64Control *c = static_cast(ctrl); + uint64_t val = c->value(); + LOG(Error) << "Control : " << id + << " - value: " << val; + } + break; + default: + LOG(Error) << "Unsupported type: " << ctrl->type(); + return -EINVAL; + } + } + + /* --- Set control values --- */ + V4L2IntControl exposureControl(V4L2_CID_EXPOSURE, 2046); + V4L2IntControl gainControl(V4L2_CID_ANALOGUE_GAIN, 1024); + std::vector sensorControls = { + &exposureControl, &gainControl, + }; + + ret = cio2->sensor_->dev()->setControls(sensorControls); + if (ret) { + LOG(IPU3, Error) << "Failed to set controls"; + return ret; + } + + /* --- Get control values back again and verify they have changed --- */ + std::vector newcontrols = + cio2->sensor_->dev()->getControls(controlIds); + if (newcontrols.empty()) { + LOG(Error) << "Failed to get control values"; + return -EINVAL; + } + + for (V4L2Control *ctrl : newcontrols) { + unsigned int id = ctrl->id(); + + switch(ctrl->type()) { + case V4L2_CTRL_TYPE_INTEGER: + case V4L2_CTRL_TYPE_BOOLEAN: + { + V4L2IntControl *c = static_cast(ctrl); + uint32_t val = c->value(); + LOG(Error) << "Control : " << id + << " - value: " << val; + } + break; + case V4L2_CTRL_TYPE_INTEGER64: + { + V4L2Int64Control *c = static_cast(ctrl); + uint64_t val = c->value(); + LOG(Error) << "Control : " << id + << " - value: " << val; + } + break; + default: + LOG(Error) << "Unsupported type: " << ctrl->type(); + return -EINVAL; + } + } + /* * Start the ImgU video devices, buffers will be queued to the * ImgU output and viewfinder when requests will be queued.