/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
 * Copyright (C) 2019, Google Inc.
 *
 * camera_sensor.cpp - A camera sensor
 */

#include "libcamera/internal/camera_sensor.h"
#include "libcamera/internal/media_device.h"

#include <algorithm>
#include <float.h>
#include <iomanip>
#include <limits.h>
#include <math.h>
#include <string.h>

#include <libcamera/camera.h>
#include <libcamera/orientation.h>
#include <libcamera/property_ids.h>

#include <libcamera/base/utils.h>

#include "libcamera/internal/bayer_format.h"
#include "libcamera/internal/camera_lens.h"
#include "libcamera/internal/camera_sensor_properties.h"
#include "libcamera/internal/formats.h"
#include "libcamera/internal/sysfs.h"

/**
 * \file camera_sensor.h
 * \brief A camera sensor
 */

namespace libcamera {

LOG_DEFINE_CATEGORY(CameraSensor)

/**
 * \class CameraSensor
 * \brief A camera sensor based on V4L2 subdevices
 *
 * The CameraSensor class eases handling of sensors for pipeline handlers by
 * hiding the details of the V4L2 subdevice kernel API and caching sensor
 * information.
 *
 * The implementation is currently limited to sensors that expose a single V4L2
 * subdevice with a single pad. It will be extended to support more complex
 * devices as the needs arise.
 */

/**
 * \brief Construct a CameraSensor
 * \param[in] entity The media entity backing the camera sensor
 *
 * Once constructed the instance must be initialized with init().
 */
CameraSensor::CameraSensor(const MediaEntity *entity)
	: entity_(entity), pad_(UINT_MAX), staticProps_(nullptr),
	  bayerFormat_(nullptr), supportFlips_(false),
	  properties_(properties::properties)
{
}

/**
 * \brief Destroy a CameraSensor
 */
CameraSensor::~CameraSensor()
{
}

/**
 * \brief Initialize the camera sensor instance
 *
 * This function performs the initialisation steps of the CameraSensor that may
 * fail. It shall be called once and only once after constructing the instance.
 *
 * \return 0 on success or a negative error code otherwise
 */
int CameraSensor::init()
{
	for (const MediaPad *pad : entity_->pads()) {
		if (pad->flags() & MEDIA_PAD_FL_SOURCE) {
			pad_ = pad->index();
			break;
		}
	}

	if (pad_ == UINT_MAX) {
		LOG(CameraSensor, Error)
			<< "Sensors with more than one pad are not supported";
		return -EINVAL;
	}

	switch (entity_->function()) {
	case MEDIA_ENT_F_CAM_SENSOR:
	case MEDIA_ENT_F_PROC_VIDEO_ISP:
		break;

	default:
		LOG(CameraSensor, Error)
			<< "Invalid sensor function "
			<< utils::hex(entity_->function());
		return -EINVAL;
	}

	/* Create and open the subdev. */
	subdev_ = std::make_unique<V4L2Subdevice>(entity_);
	int ret = subdev_->open();
	if (ret < 0)
		return ret;

	/*
	 * Clear any flips to be sure we get the "native" Bayer order. This is
	 * harmless for sensors where the flips don't affect the Bayer order.
	 */
	ControlList ctrls(subdev_->controls());
	if (subdev_->controls().find(V4L2_CID_HFLIP) != subdev_->controls().end())
		ctrls.set(V4L2_CID_HFLIP, 0);
	if (subdev_->controls().find(V4L2_CID_VFLIP) != subdev_->controls().end())
		ctrls.set(V4L2_CID_VFLIP, 0);
	subdev_->setControls(&ctrls);

	/* Enumerate, sort and cache media bus codes and sizes. */
	formats_ = subdev_->formats(pad_);
	if (formats_.empty()) {
		LOG(CameraSensor, Error) << "No image format found";
		return -EINVAL;
	}

	mbusCodes_ = utils::map_keys(formats_);
	std::sort(mbusCodes_.begin(), mbusCodes_.end());

	for (const auto &format : formats_) {
		const std::vector<SizeRange> &ranges = format.second;
		std::transform(ranges.begin(), ranges.end(), std::back_inserter(sizes_),
			       [](const SizeRange &range) { return range.max; });
	}

	std::sort(sizes_.begin(), sizes_.end());

	/* Remove duplicates. */
	auto last = std::unique(sizes_.begin(), sizes_.end());
	sizes_.erase(last, sizes_.end());

	/*
	 * VIMC is a bit special, as it does not yet support all the mandatory
	 * requirements regular sensors have to respect.
	 *
	 * Do not validate the driver if it's VIMC and initialize the sensor
	 * properties with static information.
	 *
	 * \todo Remove the special case once the VIMC driver has been
	 * updated in all test platforms.
	 */
	if (entity_->device()->driver() == "vimc") {
		initVimcDefaultProperties();

		ret = initProperties();
		if (ret)
			return ret;

		return discoverAncillaryDevices();
	}

	/* Get the color filter array pattern (only for RAW sensors). */
	for (unsigned int mbusCode : mbusCodes_) {
		const BayerFormat &bayerFormat = BayerFormat::fromMbusCode(mbusCode);
		if (bayerFormat.isValid()) {
			bayerFormat_ = &bayerFormat;
			break;
		}
	}

	ret = validateSensorDriver();
	if (ret)
		return ret;

	ret = initProperties();
	if (ret)
		return ret;

	ret = discoverAncillaryDevices();
	if (ret)
		return ret;

	/*
	 * Set HBLANK to the minimum to start with a well-defined line length,
	 * allowing IPA modules that do not modify HBLANK to use the sensor
	 * minimum line length in their calculations.
	 *
	 * At present, there is no way of knowing if a control is read-only.
	 * As a workaround, assume that if the minimum and maximum values of
	 * the V4L2_CID_HBLANK control are the same, it implies the control
	 * is read-only.
	 *
	 * \todo The control API ought to have a flag to specify if a control
	 * is read-only which could be used below.
	 */
	if (ctrls.infoMap()->find(V4L2_CID_HBLANK) != ctrls.infoMap()->end()) {
		const ControlInfo hblank = ctrls.infoMap()->at(V4L2_CID_HBLANK);
		const int32_t hblankMin = hblank.min().get<int32_t>();
		const int32_t hblankMax = hblank.max().get<int32_t>();

		if (hblankMin != hblankMax) {
			ControlList ctrl(subdev_->controls());

			ctrl.set(V4L2_CID_HBLANK, hblankMin);
			ret = subdev_->setControls(&ctrl);
			if (ret)
				return ret;
		}
	}

	return applyTestPatternMode(controls::draft::TestPatternModeEnum::TestPatternModeOff);
}

int CameraSensor::validateSensorDriver()
{
	int err = 0;

	/*
	 * Optional controls are used to register optional sensor properties. If
	 * not present, some values will be defaulted.
	 */
	static constexpr uint32_t optionalControls[] = {
		V4L2_CID_CAMERA_SENSOR_ROTATION,
	};

	const ControlIdMap &controls = subdev_->controls().idmap();
	for (uint32_t ctrl : optionalControls) {
		if (!controls.count(ctrl))
			LOG(CameraSensor, Debug)
				<< "Optional V4L2 control " << utils::hex(ctrl)
				<< " not supported";
	}

	/*
	 * Recommended controls are similar to optional controls, but will
	 * become mandatory in the near future. Be loud if they're missing.
	 */
	static constexpr uint32_t recommendedControls[] = {
		V4L2_CID_CAMERA_ORIENTATION,
	};

	for (uint32_t ctrl : recommendedControls) {
		if (!controls.count(ctrl)) {
			LOG(CameraSensor, Warning)
				<< "Recommended V4L2 control " << utils::hex(ctrl)
				<< " not supported";
			err = -EINVAL;
		}
	}

	/*
	 * Verify if sensor supports horizontal/vertical flips
	 *
	 * \todo Handle horizontal and vertical flips independently.
	 */
	const struct v4l2_query_ext_ctrl *hflipInfo = subdev_->controlInfo(V4L2_CID_HFLIP);
	const struct v4l2_query_ext_ctrl *vflipInfo = subdev_->controlInfo(V4L2_CID_VFLIP);
	if (hflipInfo && !(hflipInfo->flags & V4L2_CTRL_FLAG_READ_ONLY) &&
	    vflipInfo && !(vflipInfo->flags & V4L2_CTRL_FLAG_READ_ONLY))
		supportFlips_ = true;

	if (!supportFlips_)
		LOG(CameraSensor, Debug)
			<< "Camera sensor does not support horizontal/vertical flip";

	/*
	 * Make sure the required selection targets are supported.
	 *
	 * Failures in reading any of the targets are not deemed to be fatal,
	 * but some properties and features, like constructing a
	 * IPACameraSensorInfo for the IPA module, won't be supported.
	 *
	 * \todo Make support for selection targets mandatory as soon as all
	 * test platforms have been updated.
	 */
	Rectangle rect;
	int ret = subdev_->getSelection(pad_, V4L2_SEL_TGT_CROP_BOUNDS, &rect);
	if (ret) {
		/*
		 * Default the pixel array size to the largest size supported
		 * by the sensor. The sizes_ vector is sorted in ascending
		 * order, the largest size is thus the last element.
		 */
		pixelArraySize_ = sizes_.back();

		LOG(CameraSensor, Warning)
			<< "The PixelArraySize property has been defaulted to "
			<< pixelArraySize_;
		err = -EINVAL;
	} else {
		pixelArraySize_ = rect.size();
	}

	ret = subdev_->getSelection(pad_, V4L2_SEL_TGT_CROP_DEFAULT, &activeArea_);
	if (ret) {
		activeArea_ = Rectangle(pixelArraySize_);
		LOG(CameraSensor, Warning)
			<< "The PixelArrayActiveAreas property has been defaulted to "
			<< activeArea_;
		err = -EINVAL;
	}

	ret = subdev_->getSelection(pad_, V4L2_SEL_TGT_CROP, &rect);
	if (ret) {
		LOG(CameraSensor, Warning)
			<< "Failed to retrieve the sensor crop rectangle";
		err = -EINVAL;
	}

	if (err) {
		LOG(CameraSensor, Warning)
			<< "The sensor kernel driver needs to be fixed";
		LOG(CameraSensor, Warning)
			<< "See Documentation/sensor_driver_requirements.rst in the libcamera sources for more information";
	}

	if (!bayerFormat_)
		return 0;

	/*
	 * For raw sensors, make sure the sensor driver supports the controls
	 * required by the CameraSensor class.
	 */
	static constexpr uint32_t mandatoryControls[] = {
		V4L2_CID_ANALOGUE_GAIN,
		V4L2_CID_EXPOSURE,
		V4L2_CID_HBLANK,
		V4L2_CID_PIXEL_RATE,
		V4L2_CID_VBLANK,
	};

	err = 0;
	for (uint32_t ctrl : mandatoryControls) {
		if (!controls.count(ctrl)) {
			LOG(CameraSensor, Error)
				<< "Mandatory V4L2 control " << utils::hex(ctrl)
				<< " not available";
			err = -EINVAL;
		}
	}

	if (err) {
		LOG(CameraSensor, Error)
			<< "The sensor kernel driver needs to be fixed";
		LOG(CameraSensor, Error)
			<< "See Documentation/sensor_driver_requirements.rst in the libcamera sources for more information";
		return err;
	}

	return 0;
}

/*
 * \brief Initialize properties that cannot be intialized by the
 * regular initProperties() function for VIMC
 */
void CameraSensor::initVimcDefaultProperties()
{
	/* Use the largest supported size. */
	pixelArraySize_ = sizes_.back();
	activeArea_ = Rectangle(pixelArraySize_);
}

void CameraSensor::initStaticProperties()
{
	staticProps_ = CameraSensorProperties::get(model_);
	if (!staticProps_)
		return;

	/* Register the properties retrieved from the sensor database. */
	properties_.set(properties::UnitCellSize, staticProps_->unitCellSize);

	initTestPatternModes();
}

void CameraSensor::initTestPatternModes()
{
	const auto &v4l2TestPattern = controls().find(V4L2_CID_TEST_PATTERN);
	if (v4l2TestPattern == controls().end()) {
		LOG(CameraSensor, Debug) << "V4L2_CID_TEST_PATTERN is not supported";
		return;
	}

	const auto &testPatternModes = staticProps_->testPatternModes;
	if (testPatternModes.empty()) {
		/*
		 * The camera sensor supports test patterns but we don't know
		 * how to map them so this should be fixed.
		 */
		LOG(CameraSensor, Debug) << "No static test pattern map for \'"
					 << model() << "\'";
		return;
	}

	/*
	 * Create a map that associates the V4L2 control index to the test
	 * pattern mode by reversing the testPatternModes map provided by the
	 * camera sensor properties. This makes it easier to verify if the
	 * control index is supported in the below for loop that creates the
	 * list of supported test patterns.
	 */
	std::map<int32_t, controls::draft::TestPatternModeEnum> indexToTestPatternMode;
	for (const auto &it : testPatternModes)
		indexToTestPatternMode[it.second] = it.first;

	for (const ControlValue &value : v4l2TestPattern->second.values()) {
		const int32_t index = value.get<int32_t>();

		const auto it = indexToTestPatternMode.find(index);
		if (it == indexToTestPatternMode.end()) {
			LOG(CameraSensor, Debug)
				<< "Test pattern mode " << index << " ignored";
			continue;
		}

		testPatternModes_.push_back(it->second);
	}
}

int CameraSensor::initProperties()
{
	model_ = subdev_->model();
	properties_.set(properties::Model, utils::toAscii(model_));

	/* Generate a unique ID for the sensor. */
	int ret = generateId();
	if (ret)
		return ret;

	/* Initialize the static properties from the sensor database. */
	initStaticProperties();

	/* Retrieve and register properties from the kernel interface. */
	const ControlInfoMap &controls = subdev_->controls();

	const auto &orientation = controls.find(V4L2_CID_CAMERA_ORIENTATION);
	if (orientation != controls.end()) {
		int32_t v4l2Orientation = orientation->second.def().get<int32_t>();
		int32_t propertyValue;

		switch (v4l2Orientation) {
		default:
			LOG(CameraSensor, Warning)
				<< "Unsupported camera location "
				<< v4l2Orientation << ", setting to External";
			[[fallthrough]];
		case V4L2_CAMERA_ORIENTATION_EXTERNAL:
			propertyValue = properties::CameraLocationExternal;
			break;
		case V4L2_CAMERA_ORIENTATION_FRONT:
			propertyValue = properties::CameraLocationFront;
			break;
		case V4L2_CAMERA_ORIENTATION_BACK:
			propertyValue = properties::CameraLocationBack;
			break;
		}
		properties_.set(properties::Location, propertyValue);
	} else {
		LOG(CameraSensor, Warning) << "Failed to retrieve the camera location";
	}

	const auto &rotationControl = controls.find(V4L2_CID_CAMERA_SENSOR_ROTATION);
	if (rotationControl != controls.end()) {
		int32_t propertyValue = rotationControl->second.def().get<int32_t>();

		/*
		 * Cache the Transform associated with the camera mounting
		 * rotation for later use in computeTransform().
		 */
		bool success;
		mountingOrientation_ = orientationFromRotation(propertyValue, &success);
		if (!success) {
			LOG(CameraSensor, Warning)
				<< "Invalid rotation of " << propertyValue
				<< " degrees - ignoring";
			mountingOrientation_ = Orientation::Rotate0;
		}

		properties_.set(properties::Rotation, propertyValue);
	} else {
		LOG(CameraSensor, Warning)
			<< "Rotation control not available, default to 0 degrees";
		properties_.set(properties::Rotation, 0);
		mountingOrientation_ = Orientation::Rotate0;
	}

	properties_.set(properties::PixelArraySize, pixelArraySize_);
	properties_.set(properties::PixelArrayActiveAreas, { activeArea_ });

	/* Color filter array pattern, register only for RAW sensors. */
	if (bayerFormat_) {
		int32_t cfa;
		switch (bayerFormat_->order) {
		case BayerFormat::BGGR:
			cfa = properties::draft::BGGR;
			break;
		case BayerFormat::GBRG:
			cfa = properties::draft::GBRG;
			break;
		case BayerFormat::GRBG:
			cfa = properties::draft::GRBG;
			break;
		case BayerFormat::RGGB:
			cfa = properties::draft::RGGB;
			break;
		case BayerFormat::MONO:
			cfa = properties::draft::MONO;
			break;
		}

		properties_.set(properties::draft::ColorFilterArrangement, cfa);
	}

	return 0;
}

/**
 * \brief Check for and initialise any ancillary devices
 *
 * Sensors sometimes have ancillary devices such as a Lens or Flash that could
 * be linked to their MediaEntity by the kernel. Search for and handle any
 * such device.
 *
 * \todo Handle MEDIA_ENT_F_FLASH too.
 */
int CameraSensor::discoverAncillaryDevices()
{
	int ret;

	for (MediaEntity *ancillary : entity_->ancillaryEntities()) {
		switch (ancillary->function()) {
		case MEDIA_ENT_F_LENS:
			focusLens_ = std::make_unique<CameraLens>(ancillary);
			ret = focusLens_->init();
			if (ret) {
				LOG(CameraSensor, Error)
					<< "Lens initialisation failed, lens disabled";
				focusLens_.reset();
			}
			break;

		default:
			LOG(CameraSensor, Warning)
				<< "Unsupported ancillary entity function "
				<< ancillary->function();
			break;
		}
	}

	return 0;
}

/**
 * \fn CameraSensor::model()
 * \brief Retrieve the sensor model name
 *
 * The sensor model name is a free-formed string that uniquely identifies the
 * sensor model.
 *
 * \return The sensor model name
 */

/**
 * \fn CameraSensor::id()
 * \brief Retrieve the sensor ID
 *
 * The sensor ID is a free-form string that uniquely identifies the sensor in
 * the system. The ID satisfies the requirements to be used as a camera ID.
 *
 * \return The sensor ID
 */

/**
 * \fn CameraSensor::entity()
 * \brief Retrieve the sensor media entity
 * \return The sensor media entity
 */

/**
 * \fn CameraSensor::mbusCodes()
 * \brief Retrieve the media bus codes supported by the camera sensor
 *
 * Any Bayer formats are listed using the sensor's native Bayer order,
 * that is, with the effect of V4L2_CID_HFLIP and V4L2_CID_VFLIP undone
 * (where these controls exist).
 *
 * \return The supported media bus codes sorted in increasing order
 */

/**
 * \brief Retrieve the supported frame sizes for a media bus code
 * \param[in] mbusCode The media bus code for which sizes are requested
 *
 * \return The supported frame sizes for \a mbusCode sorted in increasing order
 */
std::vector<Size> CameraSensor::sizes(unsigned int mbusCode) const
{
	std::vector<Size> sizes;

	const auto &format = formats_.find(mbusCode);
	if (format == formats_.end())
		return sizes;

	const std::vector<SizeRange> &ranges = format->second;
	std::transform(ranges.begin(), ranges.end(), std::back_inserter(sizes),
		       [](const SizeRange &range) { return range.max; });

	std::sort(sizes.begin(), sizes.end());

	return sizes;
}

/**
 * \brief Retrieve the camera sensor resolution
 *
 * The camera sensor resolution is the active pixel area size, clamped to the
 * maximum frame size the sensor can produce if it is smaller than the active
 * pixel area.
 *
 * \todo Consider if it desirable to distinguish between the maximum resolution
 * the sensor can produce (also including upscaled ones) and the actual pixel
 * array size by splitting this function in two.
 *
 * \return The camera sensor resolution in pixels
 */
Size CameraSensor::resolution() const
{
	return std::min(sizes_.back(), activeArea_.size());
}

/**
 * \fn CameraSensor::testPatternModes()
 * \brief Retrieve all the supported test pattern modes of the camera sensor
 * The test pattern mode values correspond to the controls::TestPattern control.
 *
 * \return The list of test pattern modes
 */

/**
 * \brief Set the test pattern mode for the camera sensor
 * \param[in] mode The test pattern mode
 *
 * The new \a mode is applied to the sensor if it differs from the active test
 * pattern mode. Otherwise, this function is a no-op. Setting the same test
 * pattern mode for every frame thus incurs no performance penalty.
 */
int CameraSensor::setTestPatternMode(controls::draft::TestPatternModeEnum mode)
{
	if (testPatternMode_ == mode)
		return 0;

	if (testPatternModes_.empty()) {
		LOG(CameraSensor, Error)
			<< "Camera sensor does not support test pattern modes.";
		return -EINVAL;
	}

	return applyTestPatternMode(mode);
}

int CameraSensor::applyTestPatternMode(controls::draft::TestPatternModeEnum mode)
{
	if (testPatternModes_.empty())
		return 0;

	auto it = std::find(testPatternModes_.begin(), testPatternModes_.end(),
			    mode);
	if (it == testPatternModes_.end()) {
		LOG(CameraSensor, Error) << "Unsupported test pattern mode "
					 << mode;
		return -EINVAL;
	}

	LOG(CameraSensor, Debug) << "Apply test pattern mode " << mode;

	int32_t index = staticProps_->testPatternModes.at(mode);
	ControlList ctrls{ controls() };
	ctrls.set(V4L2_CID_TEST_PATTERN, index);

	int ret = setControls(&ctrls);
	if (ret)
		return ret;

	testPatternMode_ = mode;

	return 0;
}

/**
 * \brief Retrieve the best sensor format for a desired output
 * \param[in] mbusCodes The list of acceptable media bus codes
 * \param[in] size The desired size
 *
 * Media bus codes are selected from \a mbusCodes, which lists all acceptable
 * codes in decreasing order of preference. Media bus codes supported by the
 * sensor but not listed in \a mbusCodes are ignored. If none of the desired
 * codes is supported, it returns an error.
 *
 * \a size indicates the desired size at the output of the sensor. This function
 * selects the best media bus code and size supported by the sensor according
 * to the following criteria.
 *
 * - The desired \a size shall fit in the sensor output size to avoid the need
 *   to up-scale.
 * - The sensor output size shall match the desired aspect ratio to avoid the
 *   need to crop the field of view.
 * - The sensor output size shall be as small as possible to lower the required
 *   bandwidth.
 * - The desired \a size shall be supported by one of the media bus code listed
 *   in \a mbusCodes.
 *
 * When multiple media bus codes can produce the same size, the code at the
 * lowest position in \a mbusCodes is selected.
 *
 * The use of this function is optional, as the above criteria may not match the
 * needs of all pipeline handlers. Pipeline handlers may implement custom
 * sensor format selection when needed.
 *
 * The returned sensor output format is guaranteed to be acceptable by the
 * setFormat() function without any modification.
 *
 * \return The best sensor output format matching the desired media bus codes
 * and size on success, or an empty format otherwise.
 */
V4L2SubdeviceFormat CameraSensor::getFormat(const std::vector<unsigned int> &mbusCodes,
					    const Size &size) const
{
	unsigned int desiredArea = size.width * size.height;
	unsigned int bestArea = UINT_MAX;
	float desiredRatio = static_cast<float>(size.width) / size.height;
	float bestRatio = FLT_MAX;
	const Size *bestSize = nullptr;
	uint32_t bestCode = 0;

	for (unsigned int code : mbusCodes) {
		const auto formats = formats_.find(code);
		if (formats == formats_.end())
			continue;

		for (const SizeRange &range : formats->second) {
			const Size &sz = range.max;

			if (sz.width < size.width || sz.height < size.height)
				continue;

			float ratio = static_cast<float>(sz.width) / sz.height;
			float ratioDiff = fabsf(ratio - desiredRatio);
			unsigned int area = sz.width * sz.height;
			unsigned int areaDiff = area - desiredArea;

			if (ratioDiff > bestRatio)
				continue;

			if (ratioDiff < bestRatio || areaDiff < bestArea) {
				bestRatio = ratioDiff;
				bestArea = areaDiff;
				bestSize = &sz;
				bestCode = code;
			}
		}
	}

	if (!bestSize) {
		LOG(CameraSensor, Debug) << "No supported format or size found";
		return {};
	}

	V4L2SubdeviceFormat format{
		.mbus_code = bestCode,
		.size = *bestSize,
		.colorSpace = ColorSpace::Raw,
	};

	return format;
}

/**
 * \brief Set the sensor output format
 * \param[in] format The desired sensor output format
 * \param[in] transform The transform to be applied on the sensor.
 * Defaults to Identity.
 *
 * If flips are writable they are configured according to the desired Transform.
 * Transform::Identity always corresponds to H/V flip being disabled if the
 * controls are writable. Flips are set before the new format is applied as
 * they can effectively change the Bayer pattern ordering.
 *
 * The ranges of any controls associated with the sensor are also updated.
 *
 * \return 0 on success or a negative error code otherwise
 */
int CameraSensor::setFormat(V4L2SubdeviceFormat *format, Transform transform)
{
	/* Configure flips if the sensor supports that. */
	if (supportFlips_) {
		ControlList flipCtrls(subdev_->controls());

		flipCtrls.set(V4L2_CID_HFLIP,
			      static_cast<int32_t>(!!(transform & Transform::HFlip)));
		flipCtrls.set(V4L2_CID_VFLIP,
			      static_cast<int32_t>(!!(transform & Transform::VFlip)));

		int ret = subdev_->setControls(&flipCtrls);
		if (ret)
			return ret;
	}

	/* Apply format on the subdev. */
	int ret = subdev_->setFormat(pad_, format);
	if (ret)
		return ret;

	updateControlInfo();
	return 0;
}

/**
 * \brief Try the sensor output format
 * \param[in] format The desired sensor output format
 *
 * The ranges of any controls associated with the sensor are not updated.
 *
 * \todo Add support for Transform by changing the format's Bayer ordering
 * before calling subdev_->setFormat().
 *
 * \return 0 on success or a negative error code otherwise
 */
int CameraSensor::tryFormat(V4L2SubdeviceFormat *format) const
{
	return subdev_->setFormat(pad_, format,
				  V4L2Subdevice::Whence::TryFormat);
}

/**
 * \brief Apply a sensor configuration to the camera sensor
 * \param[in] config The sensor configuration
 * \param[in] transform The transform to be applied on the sensor.
 * Defaults to Identity
 * \param[out] sensorFormat Format applied to the sensor (optional)
 *
 * Apply to the camera sensor the configuration \a config.
 *
 * \todo The configuration shall be fully populated and if any of the fields
 * specified cannot be applied exactly, an error code is returned.
 *
 * \return 0 if \a config is applied correctly to the camera sensor, a negative
 * error code otherwise
 */
int CameraSensor::applyConfiguration(const SensorConfiguration &config,
				     Transform transform,
				     V4L2SubdeviceFormat *sensorFormat)
{
	if (!config.isValid()) {
		LOG(CameraSensor, Error) << "Invalid sensor configuration";
		return -EINVAL;
	}

	std::vector<unsigned int> filteredCodes;
	std::copy_if(mbusCodes_.begin(), mbusCodes_.end(),
		     std::back_inserter(filteredCodes),
		     [&config](unsigned int mbusCode) {
			     BayerFormat bayer = BayerFormat::fromMbusCode(mbusCode);
			     if (bayer.bitDepth == config.bitDepth)
				     return true;
			     return false;
		     });
	if (filteredCodes.empty()) {
		LOG(CameraSensor, Error)
			<< "Cannot find any format with bit depth "
			<< config.bitDepth;
		return -EINVAL;
	}

	/*
	 * Compute the sensor's data frame size by applying the cropping
	 * rectangle, subsampling and output crop to the sensor's pixel array
	 * size.
	 *
	 * \todo The actual size computation is for now ignored and only the
	 * output size is considered. This implies that resolutions obtained
	 * with two different cropping/subsampling will look identical and
	 * only the first found one will be considered.
	 */
	V4L2SubdeviceFormat subdevFormat = {};
	for (unsigned int code : filteredCodes) {
		for (const Size &size : sizes(code)) {
			if (size.width != config.outputSize.width ||
			    size.height != config.outputSize.height)
				continue;

			subdevFormat.mbus_code = code;
			subdevFormat.size = size;
			break;
		}
	}
	if (!subdevFormat.mbus_code) {
		LOG(CameraSensor, Error) << "Invalid output size in sensor configuration";
		return -EINVAL;
	}

	int ret = setFormat(&subdevFormat, transform);
	if (ret)
		return ret;

	/*
	 * Return to the caller the format actually applied to the sensor.
	 * This is relevant if transform has changed the bayer pattern order.
	 */
	if (sensorFormat)
		*sensorFormat = subdevFormat;

	/* \todo Handle AnalogCrop. Most sensors do not support set_selection */
	/* \todo Handle scaling in the digital domain. */

	return 0;
}

/**
 * \brief Retrieve the supported V4L2 controls and their information
 *
 * Control information is updated automatically to reflect the current sensor
 * configuration when the setFormat() function is called, without invalidating
 * any iterator on the ControlInfoMap. A manual update can also be forced by
 * calling the updateControlInfo() function for pipeline handlers that change
 * the sensor configuration wihtout using setFormat().
 *
 * \return A map of the V4L2 controls supported by the sensor
 */
const ControlInfoMap &CameraSensor::controls() const
{
	return subdev_->controls();
}

/**
 * \brief Read V4L2 controls from the sensor
 * \param[in] ids The list of controls to read, specified by their ID
 *
 * This function reads the value of all controls contained in \a ids, and
 * returns their values as a ControlList. The control identifiers are defined by
 * the V4L2 specification (V4L2_CID_*).
 *
 * If any control in \a ids is not supported by the device, is disabled (i.e.
 * has the V4L2_CTRL_FLAG_DISABLED flag set), or if any other error occurs
 * during validation of the requested controls, no control is read and this
 * function returns an empty control list.
 *
 * \sa V4L2Device::getControls()
 *
 * \return The control values in a ControlList on success, or an empty list on
 * error
 */
ControlList CameraSensor::getControls(const std::vector<uint32_t> &ids)
{
	return subdev_->getControls(ids);
}

/**
 * \brief Write V4L2 controls to the sensor
 * \param[in] ctrls The list of controls to write
 *
 * This function writes the value of all controls contained in \a ctrls, and
 * stores the values actually applied to the device in the corresponding \a
 * ctrls entry. The control identifiers are defined by the V4L2 specification
 * (V4L2_CID_*).
 *
 * If any control in \a ctrls is not supported by the device, is disabled (i.e.
 * has the V4L2_CTRL_FLAG_DISABLED flag set), is read-only, or if any other
 * error occurs during validation of the requested controls, no control is
 * written and this function returns -EINVAL.
 *
 * If an error occurs while writing the controls, the index of the first
 * control that couldn't be written is returned. All controls below that index
 * are written and their values are updated in \a ctrls, while all other
 * controls are not written and their values are not changed.
 *
 * \sa V4L2Device::setControls()
 *
 * \return 0 on success or an error code otherwise
 * \retval -EINVAL One of the control is not supported or not accessible
 * \retval i The index of the control that failed
 */
int CameraSensor::setControls(ControlList *ctrls)
{
	return subdev_->setControls(ctrls);
}

/**
 * \fn CameraSensor::device()
 * \brief Retrieve the camera sensor device
 * \todo Remove this function by integrating DelayedControl with CameraSensor
 * \return The camera sensor device
 */

/**
 * \fn CameraSensor::properties()
 * \brief Retrieve the camera sensor properties
 * \return The list of camera sensor properties
 */

/**
 * \brief Assemble and return the camera sensor info
 * \param[out] info The camera sensor info
 *
 * This function fills \a info with information that describes the camera sensor
 * and its current configuration. The information combines static data (such as
 * the the sensor model or active pixel array size) and data specific to the
 * current sensor configuration (such as the line length and pixel rate).
 *
 * Sensor information is only available for raw sensors. When called for a YUV
 * sensor, this function returns -EINVAL.
 *
 * Pipeline handlers that do not change the sensor format using the setFormat()
 * function may need to call updateControlInfo() beforehand, to ensure all the
 * control ranges are up to date.
 *
 * \return 0 on success, a negative error code otherwise
 */
int CameraSensor::sensorInfo(IPACameraSensorInfo *info) const
{
	if (!bayerFormat_)
		return -EINVAL;

	info->model = model();

	/*
	 * The active area size is a static property, while the crop
	 * rectangle needs to be re-read as it depends on the sensor
	 * configuration.
	 */
	info->activeAreaSize = { activeArea_.width, activeArea_.height };

	/*
	 * \todo Support for retreiving the crop rectangle is scheduled to
	 * become mandatory. For the time being use the default value if it has
	 * been initialized at sensor driver validation time.
	 */
	int ret = subdev_->getSelection(pad_, V4L2_SEL_TGT_CROP, &info->analogCrop);
	if (ret) {
		info->analogCrop = activeArea_;
		LOG(CameraSensor, Warning)
			<< "The analogue crop rectangle has been defaulted to the active area size";
	}

	/*
	 * IPACameraSensorInfo::analogCrop::x and IPACameraSensorInfo::analogCrop::y
	 * are defined relatively to the active pixel area, while V4L2's
	 * TGT_CROP target is defined in respect to the full pixel array.
	 *
	 * Compensate it by subtracting the active area offset.
	 */
	info->analogCrop.x -= activeArea_.x;
	info->analogCrop.y -= activeArea_.y;

	/* The bit depth and image size depend on the currently applied format. */
	V4L2SubdeviceFormat format{};
	ret = subdev_->getFormat(pad_, &format);
	if (ret)
		return ret;
	info->bitsPerPixel = format.bitsPerPixel();
	info->outputSize = format.size;

	std::optional<int32_t> cfa = properties_.get(properties::draft::ColorFilterArrangement);
	info->cfaPattern = cfa ? *cfa : properties::draft::RGB;

	/*
	 * Retrieve the pixel rate, line length and minimum/maximum frame
	 * duration through V4L2 controls. Support for the V4L2_CID_PIXEL_RATE,
	 * V4L2_CID_HBLANK and V4L2_CID_VBLANK controls is mandatory.
	 */
	ControlList ctrls = subdev_->getControls({ V4L2_CID_PIXEL_RATE,
						   V4L2_CID_HBLANK,
						   V4L2_CID_VBLANK });
	if (ctrls.empty()) {
		LOG(CameraSensor, Error)
			<< "Failed to retrieve camera info controls";
		return -EINVAL;
	}

	info->pixelRate = ctrls.get(V4L2_CID_PIXEL_RATE).get<int64_t>();

	const ControlInfo hblank = ctrls.infoMap()->at(V4L2_CID_HBLANK);
	info->minLineLength = info->outputSize.width + hblank.min().get<int32_t>();
	info->maxLineLength = info->outputSize.width + hblank.max().get<int32_t>();

	const ControlInfo vblank = ctrls.infoMap()->at(V4L2_CID_VBLANK);
	info->minFrameLength = info->outputSize.height + vblank.min().get<int32_t>();
	info->maxFrameLength = info->outputSize.height + vblank.max().get<int32_t>();

	return 0;
}

/**
 * \fn void CameraSensor::updateControlInfo()
 * \brief Update the sensor's ControlInfoMap in case they have changed
 * \sa V4L2Device::updateControlInfo()
 */
void CameraSensor::updateControlInfo()
{
	subdev_->updateControlInfo();
}

/**
 * \fn CameraSensor::focusLens()
 * \brief Retrieve the focus lens controller
 *
 * \return The focus lens controller. nullptr if no focus lens controller is
 * connected to the sensor
 */

/**
 * \brief Compute the Transform that gives the requested \a orientation
 * \param[inout] orientation The desired image orientation
 *
 * This function computes the Transform that the pipeline handler should apply
 * to the CameraSensor to obtain the requested \a orientation.
 *
 * The intended caller of this function is the validate() implementation of
 * pipeline handlers, that pass in the application requested
 * CameraConfiguration::orientation and obtain a Transform to apply to the
 * camera sensor, likely at configure() time.
 *
 * If the requested \a orientation cannot be obtained, the \a orientation
 * parameter is adjusted to report the current image orientation and
 * Transform::Identity is returned.
 *
 * If the requested \a orientation can be obtained, the function computes a
 * Transform and does not adjust \a orientation.
 *
 * Pipeline handlers are expected to verify if \a orientation has been
 * adjusted by this function and set the CameraConfiguration::status to
 * Adjusted accordingly.
 *
 * \return A Transform instance that applied to the CameraSensor produces images
 * with \a orientation
 */
Transform CameraSensor::computeTransform(Orientation *orientation) const
{
	/*
	 * If we cannot do any flips we cannot change the native camera mounting
	 * orientation.
	 */
	if (!supportFlips_) {
		*orientation = mountingOrientation_;
		return Transform::Identity;
	}

	/*
	 * Now compute the required transform to obtain 'orientation' starting
	 * from the mounting rotation.
	 *
	 * As a note:
	 * 	orientation / mountingOrientation_ = transform
	 * 	mountingOrientation_ * transform = orientation
	 */
	Transform transform = *orientation / mountingOrientation_;

	/*
	 * If transform contains any Transpose we cannot do it, so adjust
	 * 'orientation' to report the image native orientation and return Identity.
	 */
	if (!!(transform & Transform::Transpose)) {
		*orientation = mountingOrientation_;
		return Transform::Identity;
	}

	return transform;
}

std::string CameraSensor::logPrefix() const
{
	return "'" + entity_->name() + "'";
}

int CameraSensor::generateId()
{
	const std::string devPath = subdev_->devicePath();

	/* Try to get ID from firmware description. */
	id_ = sysfs::firmwareNodePath(devPath);
	if (!id_.empty())
		return 0;

	/*
	 * Virtual sensors not described in firmware
	 *
	 * Verify it's a platform device and construct ID from the device path
	 * and model of sensor.
	 */
	if (devPath.find("/sys/devices/platform/", 0) == 0) {
		id_ = devPath.substr(strlen("/sys/devices/")) + " " + model();
		return 0;
	}

	LOG(CameraSensor, Error) << "Can't generate sensor ID";
	return -EINVAL;
}

} /* namespace libcamera */
