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 /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2019, Google Inc. * * event-dispatcher.cpp - Event dispatcher test */ #include <iostream> #include <signal.h> #include <sys/time.h> #include <libcamera/camera_manager.h> #include <libcamera/event_dispatcher.h> #include <libcamera/timer.h> #include "test.h" using namespace std; using namespace libcamera; static EventDispatcher *dispatcher; static bool interrupt; class EventDispatcherTest : public Test { protected: static void sigAlarmHandler(int) { cout << "SIGALARM received" << endl; if (interrupt) dispatcher->interrupt(); } int init() { dispatcher = CameraManager::instance()->eventDispatcher(); struct sigaction sa = {}; sa.sa_handler = &sigAlarmHandler; sigaction(SIGALRM, &sa, nullptr); return 0; } /* SPDX-License-Identifier: BSD-2-Clause */ /* * Copyright (C) 2020, Raspberry Pi (Trading) Limited * * cam_helper_imx477.cpp - camera helper for imx477 sensor */ #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; namespace libcamera { LOG_DECLARE_CATEGORY(IPARPI) } /* * 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 { 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 ®isters, Metadata &metadata) const override; }; CamHelperImx477::CamHelperImx477() : CamHelper(std::make_unique<MdParserSmia>(registerList), frameIntegrationDiff) { } uint32_t CamHelperImx477::GainCode(double gain) const { return static_cast<uint32_t>(1024 - 1024 / gain); } double CamHelperImx477::Gain(uint32_t gain_code) const { return 1024.0 / (1024 - gain_code); } void CamHelperImx477::Prepare(libcamera::Span<const uint8_t> buffer, Metadata &metadata) { MdParser::RegisterMap registers; DeviceStatus deviceStatus; if (metadata.Get("device.status", deviceStatus)) { LOG(IPARPI, Error) << "DeviceStatus not found from DelayedControls"; return; } 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; } } uint32_t CamHelperImx477::GetVBlanking(Duration &exposure, Duration minFrameDuration, Duration maxFrameDuration) const { 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; } 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); } return frameLength - mode_.height; } void CamHelperImx477::GetDelays(int &exposure_delay, int &gain_delay, int &vblank_delay) const { exposure_delay = 2; gain_delay = 2; vblank_delay = 3; } bool CamHelperImx477::SensorEmbeddedDataPresent() const { return true; } void CamHelperImx477::PopulateMetadata(const MdParser::RegisterMap ®isters, Metadata &metadata) const { DeviceStatus deviceStatus; 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); metadata.Set("device.status", deviceStatus); } static CamHelper *Create() { return new CamHelperImx477(); } static RegisterCamHelper reg("imx477", &Create);