summaryrefslogtreecommitdiff
path: root/src/ipa/raspberrypi/cam_helper_imx477.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ipa/raspberrypi/cam_helper_imx477.cpp')
-rw-r--r--src/ipa/raspberrypi/cam_helper_imx477.cpp214
1 files changed, 121 insertions, 93 deletions
diff --git a/src/ipa/raspberrypi/cam_helper_imx477.cpp b/src/ipa/raspberrypi/cam_helper_imx477.cpp
index 0e896ac7..338fdc0c 100644
--- a/src/ipa/raspberrypi/cam_helper_imx477.cpp
+++ b/src/ipa/raspberrypi/cam_helper_imx477.cpp
@@ -6,30 +6,36 @@
*/
#include <assert.h>
+#include <cmath>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
+#include <libcamera/base/log.h>
+
#include "cam_helper.hpp"
#include "md_parser.hpp"
using namespace RPiController;
+using namespace libcamera;
+using libcamera::utils::Duration;
-/* Metadata parser implementation specific to Sony IMX477 sensors. */
+namespace libcamera {
+LOG_DECLARE_CATEGORY(IPARPI)
+}
-class MdParserImx477 : public MdParserSmia
-{
-public:
- MdParserImx477();
- Status Parse(void *data) override;
- Status GetExposureLines(unsigned int &lines) override;
- Status GetGainCode(unsigned int &gain_code) override;
-private:
- /* Offset of the register's value in the metadata block. */
- int reg_offsets_[4];
- /* Value of the register, once read from the metadata block. */
- int reg_values_[4];
-};
+/*
+ * We care about two gain registers and a pair of exposure registers. Their
+ * I2C addresses from the Sony IMX477 datasheet:
+ */
+constexpr uint32_t expHiReg = 0x0202;
+constexpr uint32_t expLoReg = 0x0203;
+constexpr uint32_t gainHiReg = 0x0204;
+constexpr uint32_t gainLoReg = 0x0205;
+constexpr uint32_t frameLengthHiReg = 0x0340;
+constexpr uint32_t frameLengthLoReg = 0x0341;
+constexpr std::initializer_list<uint32_t> registerList =
+ { expHiReg, expLoReg, gainHiReg, gainLoReg, frameLengthHiReg, frameLengthLoReg };
class CamHelperImx477 : public CamHelper
{
@@ -37,11 +43,30 @@ public:
CamHelperImx477();
uint32_t GainCode(double gain) const override;
double Gain(uint32_t gain_code) const override;
+ void Prepare(libcamera::Span<const uint8_t> buffer, Metadata &metadata) override;
+ uint32_t GetVBlanking(Duration &exposure, Duration minFrameDuration,
+ Duration maxFrameDuration) const override;
+ void GetDelays(int &exposure_delay, int &gain_delay,
+ int &vblank_delay) const override;
bool SensorEmbeddedDataPresent() const override;
+
+private:
+ /*
+ * Smallest difference between the frame length and integration time,
+ * in units of lines.
+ */
+ static constexpr int frameIntegrationDiff = 22;
+ /* Maximum frame length allowable for long exposure calculations. */
+ static constexpr int frameLengthMax = 0xffdc;
+ /* Largest long exposure scale factor given as a left shift on the frame length. */
+ static constexpr int longExposureShiftMax = 7;
+
+ void PopulateMetadata(const MdParser::RegisterMap &registers,
+ Metadata &metadata) const override;
};
CamHelperImx477::CamHelperImx477()
- : CamHelper(new MdParserImx477())
+ : CamHelper(std::make_unique<MdParserSmia>(registerList), frameIntegrationDiff)
{
}
@@ -55,101 +80,104 @@ double CamHelperImx477::Gain(uint32_t gain_code) const
return 1024.0 / (1024 - gain_code);
}
-bool CamHelperImx477::SensorEmbeddedDataPresent() const
-{
- return true;
-}
-
-static CamHelper *Create()
+void CamHelperImx477::Prepare(libcamera::Span<const uint8_t> buffer, Metadata &metadata)
{
- return new CamHelperImx477();
-}
-
-static RegisterCamHelper reg("imx477", &Create);
-
-/*
- * We care about two gain registers and a pair of exposure registers. Their
- * I2C addresses from the Sony IMX477 datasheet:
- */
-#define EXPHI_REG 0x0202
-#define EXPLO_REG 0x0203
-#define GAINHI_REG 0x0204
-#define GAINLO_REG 0x0205
+ MdParser::RegisterMap registers;
+ DeviceStatus deviceStatus;
-/*
- * Index of each into the reg_offsets and reg_values arrays. Must be in register
- * address order.
- */
-#define EXPHI_INDEX 0
-#define EXPLO_INDEX 1
-#define GAINHI_INDEX 2
-#define GAINLO_INDEX 3
+ if (metadata.Get("device.status", deviceStatus)) {
+ LOG(IPARPI, Error) << "DeviceStatus not found from DelayedControls";
+ return;
+ }
-MdParserImx477::MdParserImx477()
-{
- reg_offsets_[0] = reg_offsets_[1] = reg_offsets_[2] = reg_offsets_[3] = -1;
+ parseEmbeddedData(buffer, metadata);
+
+ /*
+ * The DeviceStatus struct is first populated with values obtained from
+ * DelayedControls. If this reports frame length is > frameLengthMax,
+ * it means we are using a long exposure mode. Since the long exposure
+ * scale factor is not returned back through embedded data, we must rely
+ * on the existing exposure lines and frame length values returned by
+ * DelayedControls.
+ *
+ * Otherwise, all values are updated with what is reported in the
+ * embedded data.
+ */
+ if (deviceStatus.frame_length > frameLengthMax) {
+ DeviceStatus parsedDeviceStatus;
+
+ metadata.Get("device.status", parsedDeviceStatus);
+ parsedDeviceStatus.shutter_speed = deviceStatus.shutter_speed;
+ parsedDeviceStatus.frame_length = deviceStatus.frame_length;
+ metadata.Set("device.status", parsedDeviceStatus);
+
+ LOG(IPARPI, Debug) << "Metadata updated for long exposure: "
+ << parsedDeviceStatus;
+ }
}
-MdParser::Status MdParserImx477::Parse(void *data)
+uint32_t CamHelperImx477::GetVBlanking(Duration &exposure,
+ Duration minFrameDuration,
+ Duration maxFrameDuration) const
{
- bool try_again = false;
-
- if (reset_) {
- /*
- * Search again through the metadata for the gain and exposure
- * registers.
- */
- assert(bits_per_pixel_);
- assert(num_lines_ || buffer_size_bytes_);
- /* Need to be ordered */
- uint32_t regs[4] = {
- EXPHI_REG,
- EXPLO_REG,
- GAINHI_REG,
- GAINLO_REG
- };
- reg_offsets_[0] = reg_offsets_[1] = reg_offsets_[2] = reg_offsets_[3] = -1;
- int ret = static_cast<int>(findRegs(static_cast<uint8_t *>(data),
- regs, reg_offsets_, 4));
- /*
- * > 0 means "worked partially but parse again next time",
- * < 0 means "hard error".
- */
- if (ret > 0)
- try_again = true;
- else if (ret < 0)
- return ERROR;
+ uint32_t frameLength, exposureLines;
+ unsigned int shift = 0;
+
+ frameLength = mode_.height + CamHelper::GetVBlanking(exposure, minFrameDuration,
+ maxFrameDuration);
+ /*
+ * Check if the frame length calculated needs to be setup for long
+ * exposure mode. This will require us to use a long exposure scale
+ * factor provided by a shift operation in the sensor.
+ */
+ while (frameLength > frameLengthMax) {
+ if (++shift > longExposureShiftMax) {
+ shift = longExposureShiftMax;
+ frameLength = frameLengthMax;
+ break;
+ }
+ frameLength >>= 1;
}
- for (int i = 0; i < 4; i++) {
- if (reg_offsets_[i] == -1)
- continue;
-
- reg_values_[i] = static_cast<uint8_t *>(data)[reg_offsets_[i]];
+ if (shift) {
+ /* Account for any rounding in the scaled frame length value. */
+ frameLength <<= shift;
+ exposureLines = ExposureLines(exposure);
+ exposureLines = std::min(exposureLines, frameLength - frameIntegrationDiff);
+ exposure = Exposure(exposureLines);
}
- /* Re-parse next time if we were unhappy in some way. */
- reset_ = try_again;
-
- return OK;
+ return frameLength - mode_.height;
}
-MdParser::Status MdParserImx477::GetExposureLines(unsigned int &lines)
+void CamHelperImx477::GetDelays(int &exposure_delay, int &gain_delay,
+ int &vblank_delay) const
{
- if (reg_offsets_[EXPHI_INDEX] == -1 || reg_offsets_[EXPLO_INDEX] == -1)
- return NOTFOUND;
-
- lines = reg_values_[EXPHI_INDEX] * 256 + reg_values_[EXPLO_INDEX];
+ exposure_delay = 2;
+ gain_delay = 2;
+ vblank_delay = 3;
+}
- return OK;
+bool CamHelperImx477::SensorEmbeddedDataPresent() const
+{
+ return true;
}
-MdParser::Status MdParserImx477::GetGainCode(unsigned int &gain_code)
+void CamHelperImx477::PopulateMetadata(const MdParser::RegisterMap &registers,
+ Metadata &metadata) const
{
- if (reg_offsets_[GAINHI_INDEX] == -1 || reg_offsets_[GAINLO_INDEX] == -1)
- return NOTFOUND;
+ DeviceStatus deviceStatus;
- gain_code = reg_values_[GAINHI_INDEX] * 256 + reg_values_[GAINLO_INDEX];
+ deviceStatus.shutter_speed = Exposure(registers.at(expHiReg) * 256 + registers.at(expLoReg));
+ deviceStatus.analogue_gain = Gain(registers.at(gainHiReg) * 256 + registers.at(gainLoReg));
+ deviceStatus.frame_length = registers.at(frameLengthHiReg) * 256 + registers.at(frameLengthLoReg);
- return OK;
+ metadata.Set("device.status", deviceStatus);
}
+
+static CamHelper *Create()
+{
+ return new CamHelperImx477();
+}
+
+static RegisterCamHelper reg("imx477", &Create);