summaryrefslogtreecommitdiff
path: root/src/ipa/rpi/cam_helper/cam_helper_imx219.cpp
blob: 91461f7af7b6072e4793d59beb5e1e821a9c6393 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/* SPDX-License-Identifier: BSD-2-Clause */
/*
 * Copyright (C) 2019, Raspberry Pi Ltd
 *
 * camera helper for imx219 sensor
 */

#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

/*
 * We have observed that the imx219 embedded data stream randomly returns junk
 * register values. Do not rely on embedded data until this has been resolved.
 */
#define ENABLE_EMBEDDED_DATA 0

#include "cam_helper.h"
#if ENABLE_EMBEDDED_DATA
#include "md_parser.h"
#endif

using namespace RPiController;

/*
 * We care about one gain register and a pair of exposure registers. Their I2C
 * addresses from the Sony IMX219 datasheet:
 */
constexpr uint32_t gainReg = 0x157;
constexpr uint32_t expHiReg = 0x15a;
constexpr uint32_t expLoReg = 0x15b;
constexpr uint32_t frameLengthHiReg = 0x160;
constexpr uint32_t frameLengthLoReg = 0x161;
constexpr uint32_t lineLengthHiReg = 0x162;
constexpr uint32_t lineLengthLoReg = 0x163;
constexpr std::initializer_list<uint32_t> registerList [[maybe_unused]]
	= { expHiReg, expLoReg, gainReg, frameLengthHiReg, frameLengthLoReg,
	    lineLengthHiReg, lineLengthLoReg };

class CamHelperImx219 : public CamHelper
{
public:
	CamHelperImx219();
	uint32_t gainCode(double gain) const override;
	double gain(uint32_t gainCode) const override;
	unsigned int mistrustFramesModeSwitch() const override;
	bool sensorEmbeddedDataPresent() const override;

private:
	/*
	 * Smallest difference between the frame length and integration time,
	 * in units of lines.
	 */
	static constexpr int frameIntegrationDiff = 4;

	void populateMetadata(const MdParser::RegisterMap &registers,
			      Metadata &metadata) const override;
};

CamHelperImx219::CamHelperImx219()
#if ENABLE_EMBEDDED_DATA
	: CamHelper(std::make_unique<MdParserSmia>(registerList), frameIntegrationDiff)
#else
	: CamHelper({}, frameIntegrationDiff)
#endif
{
}

uint32_t CamHelperImx219::gainCode(double gain) const
{
	return (uint32_t)(256 - 256 / gain);
}

double CamHelperImx219::gain(uint32_t gainCode) const
{
	return 256.0 / (256 - gainCode);
}

unsigned int CamHelperImx219::mistrustFramesModeSwitch() const
{
	/*
	 * For reasons unknown, we do occasionally get a bogus metadata frame
	 * at a mode switch (though not at start-up). Possibly warrants some
	 * investigation, though not a big deal.
	 */
	return 1;
}

bool CamHelperImx219::sensorEmbeddedDataPresent() const
{
	return ENABLE_EMBEDDED_DATA;
}

void CamHelperImx219::populateMetadata(const MdParser::RegisterMap &registers,
				       Metadata &metadata) const
{
	DeviceStatus deviceStatus;

	deviceStatus.lineLength = lineLengthPckToDuration(registers.at(lineLengthHiReg) * 256 +
							  registers.at(lineLengthLoReg));
	deviceStatus.shutterSpeed = exposure(registers.at(expHiReg) * 256 + registers.at(expLoReg),
					     deviceStatus.lineLength);
	deviceStatus.analogueGain = gain(registers.at(gainReg));
	deviceStatus.frameLength = registers.at(frameLengthHiReg) * 256 + registers.at(frameLengthLoReg);

	metadata.set("device.status", deviceStatus);
}

static CamHelper *create()
{
	return new CamHelperImx219();
}

static RegisterCamHelper reg("imx219", &create);
7 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
 * Copyright (C) 2020, Google Inc.
 *
 * Image Processing Algorithm data serializer
 */

#include "libcamera/internal/ipa_data_serializer.h"

#include <unistd.h>

#include <libcamera/base/log.h>

/**
 * \file ipa_data_serializer.h
 * \brief IPA Data Serializer
 */

namespace libcamera {

LOG_DEFINE_CATEGORY(IPADataSerializer)

/**
 * \class IPADataSerializer
 * \brief IPA Data Serializer
 *
 * Static template class that provides functions for serializing and
 * deserializing IPA data.
 *
 * \todo Switch to Span instead of byte and fd vector
 *
 * \todo Harden the vector and map deserializer
 *
 * \todo For SharedFDs, instead of storing a validity flag, store an
 * index into the fd array. This will allow us to use views instead of copying.
 */

namespace {

/**
 * \fn template<typename T> void appendPOD(std::vector<uint8_t> &vec, T val)
 * \brief Append POD to end of byte vector, in little-endian order
 * \tparam T Type of POD to append
 * \param[in] vec Byte vector to append to
 * \param[in] val Value to append
 *
 * This function is meant to be used by the IPA data serializer, and the
 * generated IPA proxies.
 */

/**
 * \fn template<typename T> T readPOD(std::vector<uint8_t>::iterator it, size_t pos,
 * 				      std::vector<uint8_t>::iterator end)
 * \brief Read POD from byte vector, in little-endian order
 * \tparam T Type of POD to read
 * \param[in] it Iterator of byte vector to read from
 * \param[in] pos Index in byte vector to read from
 * \param[in] end Iterator marking end of byte vector
 *
 * This function is meant to be used by the IPA data serializer, and the
 * generated IPA proxies.
 *
 * If the \a pos plus the byte-width of the desired POD is past \a end, it is
 * a fata error will occur, as it means there is insufficient data for
 * deserialization, which should never happen.
 *
 * \return The POD read from \a it at index \a pos
 */

/**
 * \fn template<typename T> T readPOD(std::vector<uint8_t> &vec, size_t pos)
 * \brief Read POD from byte vector, in little-endian order
 * \tparam T Type of POD to read
 * \param[in] vec Byte vector to read from
 * \param[in] pos Index in vec to start reading from
 *
 * This function is meant to be used by the IPA data serializer, and the
 * generated IPA proxies.
 *
 * If the \a pos plus the byte-width of the desired POD is past the end of
 * \a vec, a fatal error will occur, as it means there is insufficient data
 * for deserialization, which should never happen.
 *
 * \return The POD read from \a vec at index \a pos
 */

} /* namespace */

/**
 * \fn template<typename T> IPADataSerializer<T>::serialize(
 * 	T data,
 * 	ControlSerializer *cs = nullptr)
 * \brief Serialize an object into byte vector and fd vector
 * \tparam T Type of object to serialize
 * \param[in] data Object to serialize
 * \param[in] cs ControlSerializer
 *
 * \a cs is only necessary if the object type \a T or its members contain
 * ControlList or ControlInfoMap.
 *
 * \return Tuple of byte vector and fd vector, that is the serialized form
 * of \a data
 */

/**
 * \fn template<typename T> IPADataSerializer<T>::deserialize(
 * 	const std::vector<uint8_t> &data,
 * 	ControlSerializer *cs = nullptr)
 * \brief Deserialize byte vector into an object
 * \tparam T Type of object to deserialize to
 * \param[in] data Byte vector to deserialize from
 * \param[in] cs ControlSerializer
 *
 * This version of deserialize() can be used if the object type \a T and its
 * members don't have any SharedFD.
 *
 * \a cs is only necessary if the object type \a T or its members contain
 * ControlList or ControlInfoMap.
 *
 * \return The deserialized object
 */

/**
 * \fn template<typename T> IPADataSerializer<T>::deserialize(
 * 	std::vector<uint8_t>::const_iterator dataBegin,
 * 	std::vector<uint8_t>::const_iterator dataEnd,
 * 	ControlSerializer *cs = nullptr)
 * \brief Deserialize byte vector into an object
 * \tparam T Type of object to deserialize to
 * \param[in] dataBegin Begin iterator of byte vector to deserialize from
 * \param[in] dataEnd End iterator of byte vector to deserialize from
 * \param[in] cs ControlSerializer
 *
 * This version of deserialize() can be used if the object type \a T and its
 * members don't have any SharedFD.
 *
 * \a cs is only necessary if the object type \a T or its members contain
 * ControlList or ControlInfoMap.
 *
 * \return The deserialized object
 */

/**
 * \fn template<typename T> IPADataSerializer<T>::deserialize(
 * 	const std::vector<uint8_t> &data,
 * 	const std::vector<SharedFD> &fds,
 * 	ControlSerializer *cs = nullptr)
 * \brief Deserialize byte vector and fd vector into an object
 * \tparam T Type of object to deserialize to
 * \param[in] data Byte vector to deserialize from
 * \param[in] fds Fd vector to deserialize from
 * \param[in] cs ControlSerializer
 *
 * This version of deserialize() (or the iterator version) must be used if
 * the object type \a T or its members contain SharedFD.
 *
 * \a cs is only necessary if the object type \a T or its members contain
 * ControlList or ControlInfoMap.
 *
 * \return The deserialized object
 */

/**
 * \fn template<typename T> IPADataSerializer::deserialize(
 * 	std::vector<uint8_t>::const_iterator dataBegin,
 * 	std::vector<uint8_t>::const_iterator dataEnd,
 * 	std::vector<SharedFD>::const_iterator fdsBegin,
 * 	std::vector<SharedFD>::const_iterator fdsEnd,
 * 	ControlSerializer *cs = nullptr)
 * \brief Deserialize byte vector and fd vector into an object
 * \tparam T Type of object to deserialize to
 * \param[in] dataBegin Begin iterator of byte vector to deserialize from
 * \param[in] dataEnd End iterator of byte vector to deserialize from
 * \param[in] fdsBegin Begin iterator of fd vector to deserialize from
 * \param[in] fdsEnd End iterator of fd vector to deserialize from
 * \param[in] cs ControlSerializer
 *
 * This version of deserialize() (or the vector version) must be used if
 * the object type \a T or its members contain SharedFD.
 *
 * \a cs is only necessary if the object type \a T or its members contain
 * ControlList or ControlInfoMap.
 *
 * \return The deserialized object
 */

#ifndef __DOXYGEN__

#define DEFINE_POD_SERIALIZER(type)					\
									\
template<>								\
std::tuple<std::vector<uint8_t>, std::vector<SharedFD>>		\
IPADataSerializer<type>::serialize(const type &data,			\
				  [[maybe_unused]] ControlSerializer *cs) \
{									\
	std::vector<uint8_t> dataVec;					\
	dataVec.reserve(sizeof(type));					\
	appendPOD<type>(dataVec, data);					\
									\
	return { dataVec, {} };						\
}									\
									\
template<>								\
type IPADataSerializer<type>::deserialize(std::vector<uint8_t>::const_iterator dataBegin, \
					  std::vector<uint8_t>::const_iterator dataEnd, \
					  [[maybe_unused]] ControlSerializer *cs) \
{									\
	return readPOD<type>(dataBegin, 0, dataEnd);			\
}									\
									\
template<>								\
type IPADataSerializer<type>::deserialize(const std::vector<uint8_t> &data, \
					  ControlSerializer *cs)	\
{									\
	return deserialize(data.cbegin(), data.end(), cs);		\
}									\
									\
template<>								\
type IPADataSerializer<type>::deserialize(const std::vector<uint8_t> &data, \
					  [[maybe_unused]] const std::vector<SharedFD> &fds, \
					  ControlSerializer *cs)	\
{									\
	return deserialize(data.cbegin(), data.end(), cs);		\
}									\
									\
template<>								\
type IPADataSerializer<type>::deserialize(std::vector<uint8_t>::const_iterator dataBegin, \
					  std::vector<uint8_t>::const_iterator dataEnd, \
					  [[maybe_unused]] std::vector<SharedFD>::const_iterator fdsBegin, \
					  [[maybe_unused]] std::vector<SharedFD>::const_iterator fdsEnd, \
					  ControlSerializer *cs)	\
{									\
	return deserialize(dataBegin, dataEnd, cs);			\
}

DEFINE_POD_SERIALIZER(bool)
DEFINE_POD_SERIALIZER(uint8_t)
DEFINE_POD_SERIALIZER(uint16_t)
DEFINE_POD_SERIALIZER(uint32_t)
DEFINE_POD_SERIALIZER(uint64_t)
DEFINE_POD_SERIALIZER(int8_t)
DEFINE_POD_SERIALIZER(int16_t)
DEFINE_POD_SERIALIZER(int32_t)
DEFINE_POD_SERIALIZER(int64_t)
DEFINE_POD_SERIALIZER(float)
DEFINE_POD_SERIALIZER(double)

/*
 * Strings are serialized simply by converting by {string.cbegin(), string.end()}.
 * The size of the string is recorded by the container (struct, vector, map, or
 * function parameter serdes).
 */
template<>
std::tuple<std::vector<uint8_t>, std::vector<SharedFD>>
IPADataSerializer<std::string>::serialize(const std::string &data,
					  [[maybe_unused]] ControlSerializer *cs)
{
	return { { data.cbegin(), data.end() }, {} };
}

template<>
std::string
IPADataSerializer<std::string>::deserialize(const std::vector<uint8_t> &data,
					    [[maybe_unused]] ControlSerializer *cs)
{
	return { data.cbegin(), data.cend() };
}

template<>
std::string
IPADataSerializer<std::string>::deserialize(std::vector<uint8_t>::const_iterator dataBegin,
					    std::vector<uint8_t>::const_iterator dataEnd,
					    [[maybe_unused]] ControlSerializer *cs)
{
	return { dataBegin, dataEnd };
}

template<>
std::string
IPADataSerializer<std::string>::deserialize(const std::vector<uint8_t> &data,
					    [[maybe_unused]] const std::vector<SharedFD> &fds,
					    [[maybe_unused]] ControlSerializer *cs)
{
	return { data.cbegin(), data.cend() };
}

template<>
std::string
IPADataSerializer<std::string>::deserialize(std::vector<uint8_t>::const_iterator dataBegin,
					    std::vector<uint8_t>::const_iterator dataEnd,
					    [[maybe_unused]] std::vector<SharedFD>::const_iterator fdsBegin,
					    [[maybe_unused]] std::vector<SharedFD>::const_iterator fdsEnd,
					    [[maybe_unused]] ControlSerializer *cs)
{
	return { dataBegin, dataEnd };
}

/*
 * ControlList is serialized as:
 *
 * 4 bytes - uint32_t Size of serialized ControlInfoMap, in bytes
 * 4 bytes - uint32_t Size of serialized ControlList, in bytes
 * X bytes - Serialized ControlInfoMap (using ControlSerializer)
 * X bytes - Serialized ControlList (using ControlSerializer)
 *
 * If data.infoMap() is nullptr, then the default controls::controls will
 * be used. The serialized ControlInfoMap will have zero length.
 */
template<>
std::tuple<std::vector<uint8_t>, std::vector<SharedFD>>
IPADataSerializer<ControlList>::serialize(const ControlList &data, ControlSerializer *cs)
{
	if (!cs)
		LOG(IPADataSerializer, Fatal)
			<< "ControlSerializer not provided for serialization of ControlList";

	size_t size;
	std::vector<uint8_t> infoData;
	int ret;

	/*
	 * \todo Revisit this opportunistic serialization of the
	 * ControlInfoMap, as it could be fragile
	 */
	if (data.infoMap() && !cs->isCached(*data.infoMap())) {
		size = cs->binarySize(*data.infoMap());
		infoData.resize(size);
		ByteStreamBuffer buffer(infoData.data(), infoData.size());
		ret = cs->serialize(*data.infoMap(), buffer);

		if (ret < 0 || buffer.overflow()) {
			LOG(IPADataSerializer, Error) << "Failed to serialize ControlList's ControlInfoMap";
			return { {}, {} };
		}
	}

	size = cs->binarySize(data);
	std::vector<uint8_t> listData(size);
	ByteStreamBuffer buffer(listData.data(), listData.size());
	ret = cs->serialize(data, buffer);

	if (ret < 0 || buffer.overflow()) {
		LOG(IPADataSerializer, Error) << "Failed to serialize ControlList";
		return { {}, {} };
	}

	std::vector<uint8_t> dataVec;
	dataVec.reserve(8 + infoData.size() + listData.size());
	appendPOD<uint32_t>(dataVec, infoData.size());
	appendPOD<uint32_t>(dataVec, listData.size());
	dataVec.insert(dataVec.end(), infoData.begin(), infoData.end());
	dataVec.insert(dataVec.end(), listData.begin(), listData.end());

	return { dataVec, {} };
}

template<>
ControlList
IPADataSerializer<ControlList>::deserialize(std::vector<uint8_t>::const_iterator dataBegin,
					    std::vector<uint8_t>::const_iterator dataEnd,
					    ControlSerializer *cs)
{
	if (!cs)
		LOG(IPADataSerializer, Fatal)
			<< "ControlSerializer not provided for deserialization of ControlList";

	if (std::distance(dataBegin, dataEnd) < 8)
		return {};

	uint32_t infoDataSize = readPOD<uint32_t>(dataBegin, 0, dataEnd);
	uint32_t listDataSize = readPOD<uint32_t>(dataBegin, 4, dataEnd);