{"id":12584,"url":"https://patchwork.libcamera.org/api/1.1/patches/12584/?format=json","web_url":"https://patchwork.libcamera.org/patch/12584/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20210614095340.3051816-7-naush@raspberrypi.com>","date":"2021-06-14T09:53:40","name":"[libcamera-devel,6/6] ipa: raspberrypi: Generalise the SMIA metadata parser","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"3213623cf29bb8781f309b2049a4080356668137","submitter":{"id":34,"url":"https://patchwork.libcamera.org/api/1.1/people/34/?format=json","name":"Naushir Patuck","email":"naush@raspberrypi.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/12584/mbox/","series":[{"id":2128,"url":"https://patchwork.libcamera.org/api/1.1/series/2128/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=2128","date":"2021-06-14T09:53:34","name":"Raspberry Pi: Metadata parsing improvements","version":1,"mbox":"https://patchwork.libcamera.org/series/2128/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/12584/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/12584/checks/","tags":{},"headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 2ADFCC3218\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 14 Jun 2021 09:53:57 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id C8A1A68933;\n\tMon, 14 Jun 2021 11:53:56 +0200 (CEST)","from mail-wm1-x32b.google.com (mail-wm1-x32b.google.com\n\t[IPv6:2a00:1450:4864:20::32b])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 3144768937\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 14 Jun 2021 11:53:50 +0200 (CEST)","by mail-wm1-x32b.google.com with SMTP id b205so7061152wmb.3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 14 Jun 2021 02:53:50 -0700 (PDT)","from naush-laptop.pitowers.org\n\t([2a00:1098:3142:14:fd93:d554:2dff:83ca])\n\tby smtp.gmail.com with ESMTPSA id\n\tc2sm19834891wmf.24.2021.06.14.02.53.48\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tMon, 14 Jun 2021 02:53:48 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=raspberrypi.com header.i=@raspberrypi.com\n\theader.b=\"Dhk43McI\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google;\n\th=from:to:cc:subject:date:message-id:in-reply-to:references\n\t:mime-version:content-transfer-encoding;\n\tbh=zdn6EoWhiSuHC85PVxRu8OiYwIw3pJWhCuzsm/sYzZ8=;\n\tb=Dhk43McIElE50QB17wAX7E0cU12M8wLYzHmyUwNetylOSCA7dBS/yVf59byYAOxysq\n\tm0Lr26fV+PELrhQtoOvpbyUfwccvCmNkVxNEpE8ZsTnk+TLLNDEuGXsXVlGh0M/Mqt+a\n\tqJkE+YgYsDit79O4TB/VSFtgXYdJDuKskRRSJ1BJ+oviECsuFU6FuEKAMAw5bF/+J8Nd\n\tN6PldwmjFpl35BIeBJhNQpksVwnZah9nqmFx+nOxM1mYzKJVxWfxZhbxWIRPUWKwu9LM\n\twS6r7NPnZ4kBD4py+P7ru/bcp0FAsZ+bQqsqX6NT9byivS/yq20M8j/Z6rhquSOjdWiM\n\taTGA==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references:mime-version:content-transfer-encoding;\n\tbh=zdn6EoWhiSuHC85PVxRu8OiYwIw3pJWhCuzsm/sYzZ8=;\n\tb=j8vt9jwoy5ZFBSAXayT/AJpw3Bq2yYimvVNpeQkFCBkOmu+azEYxudC/lOpu2Nu+30\n\tNCESp4cF2b/hTffh+Q1vfVgmSKNL8dmXZmgO39gwZlAt8s+1hSBGBp8Wz+XWAH0iDYvO\n\tPb7NOw5RDDBIKWOTbOcY820DQ7JQvFPE+8hGlyQ86FdzCNaSlk8YFgnU0deeO9qofx2b\n\t6uniH05N8DpTTuiaIgcLTC8QgMFnat+qwZMB/NsVCP5o7sYt99VtwEhxlQzOQEjA+SkL\n\t77YjcEzp5AdXdiYvlXtkKKk3sXS5ZoG3b75in+EUJN5WryC8cPTw60WPcAsWsWVi0/cA\n\tUjuw==","X-Gm-Message-State":"AOAM5320PWMc8OUy5rxmZTeUKR3WOG2/jGQi6NB9iI/Pm64soZJ1Bebh\n\tI94PLcyuOXg56Zq8TFh1uu8PxTho7h4Wlw==","X-Google-Smtp-Source":"ABdhPJz8abpU5A0xGM0NyYNg0CYbXLsMPeehknLPv/+0iHFJWL03hC1njrzb8qfILu0nyElGVX2CAQ==","X-Received":"by 2002:a1c:7210:: with SMTP id\n\tn16mr30886583wmc.75.1623664429324; \n\tMon, 14 Jun 2021 02:53:49 -0700 (PDT)","From":"Naushir Patuck <naush@raspberrypi.com>","To":"libcamera-devel@lists.libcamera.org","Date":"Mon, 14 Jun 2021 10:53:40 +0100","Message-Id":"<20210614095340.3051816-7-naush@raspberrypi.com>","X-Mailer":"git-send-email 2.25.1","In-Reply-To":"<20210614095340.3051816-1-naush@raspberrypi.com>","References":"<20210614095340.3051816-1-naush@raspberrypi.com>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","Subject":"[libcamera-devel] [PATCH 6/6] ipa: raspberrypi: Generalise the SMIA\n\tmetadata parser","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"},"content":"Instead of having each CamHelper subclass the MdParserSmia, change the\nimplementation of MdParserSmia to be more generic. The MdParserSmia now gets\ngiven a list of registers to search for and helper functions are used to compute\nexposure lines and gain codes from these registers.\n\nUpdate the imx219 and imx477 CamHelpers by using this new mechanism.\n\nAs a drive-by change, fixup a possible buffer overrun in the parsing code.\n\nSigned-off-by: Naushir Patuck <naush@raspberrypi.com>\n---\n src/ipa/raspberrypi/cam_helper_imx219.cpp | 117 ++++----------------\n src/ipa/raspberrypi/cam_helper_imx477.cpp | 125 ++++------------------\n src/ipa/raspberrypi/md_parser.hpp         |  42 ++++++--\n src/ipa/raspberrypi/md_parser_smia.cpp    |  89 ++++++++++++---\n 4 files changed, 153 insertions(+), 220 deletions(-)","diff":"diff --git a/src/ipa/raspberrypi/cam_helper_imx219.cpp b/src/ipa/raspberrypi/cam_helper_imx219.cpp\nindex 36dbe8cd941a..72c1042ad6be 100644\n--- a/src/ipa/raspberrypi/cam_helper_imx219.cpp\n+++ b/src/ipa/raspberrypi/cam_helper_imx219.cpp\n@@ -23,21 +23,13 @@\n \n using namespace RPiController;\n \n-/* Metadata parser implementation specific to Sony IMX219 sensors. */\n-\n-class MdParserImx219 : public MdParserSmia\n-{\n-public:\n-\tMdParserImx219();\n-\tStatus Parse(libcamera::Span<const uint8_t> buffer) override;\n-\tStatus GetExposureLines(unsigned int &lines) override;\n-\tStatus GetGainCode(unsigned int &gain_code) override;\n-private:\n-\t/* Offset of the register's value in the metadata block. */\n-\tint reg_offsets_[3];\n-\t/* Value of the register, once read from the metadata block. */\n-\tint reg_values_[3];\n-};\n+/*\n+ * We care about one gain register and a pair of exposure registers. Their I2C\n+ * addresses from the Sony IMX219 datasheet:\n+ */\n+constexpr uint32_t gainReg = 0x157;\n+constexpr uint32_t expHiReg = 0x15A;\n+constexpr uint32_t expLoReg = 0x15B;\n \n class CamHelperImx219 : public CamHelper\n {\n@@ -55,11 +47,23 @@ private:\n \t */\n \tstatic constexpr int frameIntegrationDiff = 4;\n \n-\tMdParserImx219 imx219_parser;\n+\tMdParserSmia imx219_parser;\n+\n+\tstatic uint32_t ParseExposureLines(const MdParserSmia::RegMap &map)\n+\t{\n+\t\treturn map.at(expHiReg).value * 256 + map.at(expLoReg).value;\n+\t}\n+\n+\tstatic uint32_t ParseGainCode(const MdParserSmia::RegMap &map)\n+\t{\n+\t\treturn map.at(gainReg).value;\n+\t}\n };\n \n CamHelperImx219::CamHelperImx219()\n-\t: CamHelper(frameIntegrationDiff)\n+\t: CamHelper(frameIntegrationDiff),\n+\t  imx219_parser({ expHiReg, expLoReg, gainReg },\n+\t\t\tParseGainCode, ParseExposureLines)\n {\n #if ENABLE_EMBEDDED_DATA\n \tparser_ = &imx219_parser;\n@@ -97,82 +101,3 @@ static CamHelper *Create()\n }\n \n static RegisterCamHelper reg(\"imx219\", &Create);\n-\n-/*\n- * We care about one gain register and a pair of exposure registers. Their I2C\n- * addresses from the Sony IMX219 datasheet:\n- */\n-#define GAIN_REG 0x157\n-#define EXPHI_REG 0x15A\n-#define EXPLO_REG 0x15B\n-\n-/*\n- * Index of each into the reg_offsets and reg_values arrays. Must be in\n- * register address order.\n- */\n-#define GAIN_INDEX 0\n-#define EXPHI_INDEX 1\n-#define EXPLO_INDEX 2\n-\n-MdParserImx219::MdParserImx219()\n-{\n-\treg_offsets_[0] = reg_offsets_[1] = reg_offsets_[2] = -1;\n-}\n-\n-MdParser::Status MdParserImx219::Parse(libcamera::Span<const uint8_t> buffer)\n-{\n-\tbool try_again = false;\n-\n-\tif (reset_) {\n-\t\t/*\n-\t\t * Search again through the metadata for the gain and exposure\n-\t\t * registers.\n-\t\t */\n-\t\tassert(bits_per_pixel_);\n-\t\t/* Need to be ordered */\n-\t\tuint32_t regs[3] = { GAIN_REG, EXPHI_REG, EXPLO_REG };\n-\t\treg_offsets_[0] = reg_offsets_[1] = reg_offsets_[2] = -1;\n-\t\tint ret = static_cast<int>(findRegs(buffer,\n-\t\t\t\t\t\t    regs, reg_offsets_, 3));\n-\t\t/*\n-\t\t * > 0 means \"worked partially but parse again next time\",\n-\t\t * < 0 means \"hard error\".\n-\t\t */\n-\t\tif (ret > 0)\n-\t\t\ttry_again = true;\n-\t\telse if (ret < 0)\n-\t\t\treturn ERROR;\n-\t}\n-\n-\tfor (int i = 0; i < 3; i++) {\n-\t\tif (reg_offsets_[i] == -1)\n-\t\t\tcontinue;\n-\n-\t\treg_values_[i] = buffer[reg_offsets_[i]];\n-\t}\n-\n-\t/* Re-parse next time if we were unhappy in some way. */\n-\treset_ = try_again;\n-\n-\treturn OK;\n-}\n-\n-MdParser::Status MdParserImx219::GetExposureLines(unsigned int &lines)\n-{\n-\tif (reg_offsets_[EXPHI_INDEX] == -1 || reg_offsets_[EXPLO_INDEX] == -1)\n-\t\treturn NOTFOUND;\n-\n-\tlines = reg_values_[EXPHI_INDEX] * 256 + reg_values_[EXPLO_INDEX];\n-\n-\treturn OK;\n-}\n-\n-MdParser::Status MdParserImx219::GetGainCode(unsigned int &gain_code)\n-{\n-\tif (reg_offsets_[GAIN_INDEX] == -1)\n-\t\treturn NOTFOUND;\n-\n-\tgain_code = reg_values_[GAIN_INDEX];\n-\n-\treturn OK;\n-}\ndiff --git a/src/ipa/raspberrypi/cam_helper_imx477.cpp b/src/ipa/raspberrypi/cam_helper_imx477.cpp\nindex 038a8583d311..7a1100c25afc 100644\n--- a/src/ipa/raspberrypi/cam_helper_imx477.cpp\n+++ b/src/ipa/raspberrypi/cam_helper_imx477.cpp\n@@ -15,21 +15,14 @@\n \n using namespace RPiController;\n \n-/* Metadata parser implementation specific to Sony IMX477 sensors. */\n-\n-class MdParserImx477 : public MdParserSmia\n-{\n-public:\n-\tMdParserImx477();\n-\tStatus Parse(libcamera::Span<const uint8_t> buffer) override;\n-\tStatus GetExposureLines(unsigned int &lines) override;\n-\tStatus GetGainCode(unsigned int &gain_code) override;\n-private:\n-\t/* Offset of the register's value in the metadata block. */\n-\tint reg_offsets_[4];\n-\t/* Value of the register, once read from the metadata block. */\n-\tint reg_values_[4];\n-};\n+/*\n+ * We care about two gain registers and a pair of exposure registers. Their\n+ * I2C addresses from the Sony IMX477 datasheet:\n+ */\n+constexpr uint32_t expHiReg = 0x0202;\n+constexpr uint32_t expLoReg = 0x0203;\n+constexpr uint32_t gainHiReg = 0x0204;\n+constexpr uint32_t gainLoReg = 0x0205;\n \n class CamHelperImx477 : public CamHelper\n {\n@@ -48,11 +41,23 @@ private:\n \t */\n \tstatic constexpr int frameIntegrationDiff = 22;\n \n-\tMdParserImx477 imx477_parser;\n+\tMdParserSmia imx477_parser;\n+\n+\tstatic uint32_t ParseExposureLines(const MdParserSmia::RegMap &map)\n+\t{\n+\t\treturn map.at(expHiReg).value * 256 + map.at(expLoReg).value;\n+\t}\n+\n+\tstatic uint32_t ParseGainCode(const MdParserSmia::RegMap &map)\n+\t{\n+\t\treturn map.at(gainHiReg).value * 256 + map.at(gainLoReg).value;\n+\t}\n };\n \n CamHelperImx477::CamHelperImx477()\n-\t: CamHelper(frameIntegrationDiff)\n+\t: CamHelper(frameIntegrationDiff),\n+\t  imx477_parser({ expHiReg, expLoReg, gainHiReg, gainLoReg },\n+\t\t\tParseGainCode, ParseExposureLines)\n {\n \tparser_ = &imx477_parser;\n }\n@@ -86,89 +91,3 @@ static CamHelper *Create()\n }\n \n static RegisterCamHelper reg(\"imx477\", &Create);\n-\n-/*\n- * We care about two gain registers and a pair of exposure registers. Their\n- * I2C addresses from the Sony IMX477 datasheet:\n- */\n-#define EXPHI_REG 0x0202\n-#define EXPLO_REG 0x0203\n-#define GAINHI_REG 0x0204\n-#define GAINLO_REG 0x0205\n-\n-/*\n- * Index of each into the reg_offsets and reg_values arrays. Must be in register\n- * address order.\n- */\n-#define EXPHI_INDEX 0\n-#define EXPLO_INDEX 1\n-#define GAINHI_INDEX 2\n-#define GAINLO_INDEX 3\n-\n-MdParserImx477::MdParserImx477()\n-{\n-\treg_offsets_[0] = reg_offsets_[1] = reg_offsets_[2] = reg_offsets_[3] = -1;\n-}\n-\n-MdParser::Status MdParserImx477::Parse(libcamera::Span<const uint8_t> buffer)\n-{\n-\tbool try_again = false;\n-\n-\tif (reset_) {\n-\t\t/*\n-\t\t * Search again through the metadata for the gain and exposure\n-\t\t * registers.\n-\t\t */\n-\t\tassert(bits_per_pixel_);\n-\t\t/* Need to be ordered */\n-\t\tuint32_t regs[4] = {\n-\t\t\tEXPHI_REG,\n-\t\t\tEXPLO_REG,\n-\t\t\tGAINHI_REG,\n-\t\t\tGAINLO_REG\n-\t\t};\n-\t\treg_offsets_[0] = reg_offsets_[1] = reg_offsets_[2] = reg_offsets_[3] = -1;\n-\t\tint ret = static_cast<int>(findRegs(buffer,\n-\t\t\t\t\t\t    regs, reg_offsets_, 4));\n-\t\t/*\n-\t\t * > 0 means \"worked partially but parse again next time\",\n-\t\t * < 0 means \"hard error\".\n-\t\t */\n-\t\tif (ret > 0)\n-\t\t\ttry_again = true;\n-\t\telse if (ret < 0)\n-\t\t\treturn ERROR;\n-\t}\n-\n-\tfor (int i = 0; i < 4; i++) {\n-\t\tif (reg_offsets_[i] == -1)\n-\t\t\tcontinue;\n-\n-\t\treg_values_[i] = buffer[reg_offsets_[i]];\n-\t}\n-\n-\t/* Re-parse next time if we were unhappy in some way. */\n-\treset_ = try_again;\n-\n-\treturn OK;\n-}\n-\n-MdParser::Status MdParserImx477::GetExposureLines(unsigned int &lines)\n-{\n-\tif (reg_offsets_[EXPHI_INDEX] == -1 || reg_offsets_[EXPLO_INDEX] == -1)\n-\t\treturn NOTFOUND;\n-\n-\tlines = reg_values_[EXPHI_INDEX] * 256 + reg_values_[EXPLO_INDEX];\n-\n-\treturn OK;\n-}\n-\n-MdParser::Status MdParserImx477::GetGainCode(unsigned int &gain_code)\n-{\n-\tif (reg_offsets_[GAINHI_INDEX] == -1 || reg_offsets_[GAINLO_INDEX] == -1)\n-\t\treturn NOTFOUND;\n-\n-\tgain_code = reg_values_[GAINHI_INDEX] * 256 + reg_values_[GAINLO_INDEX];\n-\n-\treturn OK;\n-}\ndiff --git a/src/ipa/raspberrypi/md_parser.hpp b/src/ipa/raspberrypi/md_parser.hpp\nindex 25ba0e7c9400..6bbcdec0830b 100644\n--- a/src/ipa/raspberrypi/md_parser.hpp\n+++ b/src/ipa/raspberrypi/md_parser.hpp\n@@ -6,6 +6,10 @@\n  */\n #pragma once\n \n+#include <functional>\n+#include <map>\n+#include <vector>\n+\n #include <libcamera/span.h>\n \n /* Camera metadata parser class. Usage as shown below.\n@@ -16,7 +20,8 @@\n  * application code doesn't have to worry which to kind to instantiate. But for\n  * the sake of example let's suppose we're parsing imx219 metadata.\n  *\n- * MdParser *parser = new MdParserImx219();  // for example\n+ * MdParser *parser = new MdParserSmia({ expHiReg, expLoReg, gainReg },\n+\t\t\t\t       ParseGainCode, ParseExposureLines));\n  * parser->SetBitsPerPixel(bpp);\n  * parser->SetLineLengthBytes(pitch);\n  * parser->SetNumLines(2);\n@@ -113,14 +118,32 @@ protected:\n  * md_parser_imx219.cpp for an example).\n  */\n \n-class MdParserSmia : public MdParser\n+class MdParserSmia final : public MdParser\n {\n public:\n-\tMdParserSmia() : MdParser()\n-\t{\n-\t}\n+\tstruct Register {\n+\t\tRegister()\n+\t\t\t: offset(0), value(0), found(false)\n+\t\t{\n+\t\t}\n+\n+\t\tuint32_t offset;\n+\t\tuint32_t value;\n+\t\tbool found;\n+\t};\n \n-protected:\n+\t/* Maps register address to offset in the buffer. */\n+\tusing RegMap = std::map<uint32_t, Register>;\n+\tusing GetFn = std::function<uint32_t(const RegMap&)>;\n+\n+\tMdParserSmia(const std::vector<uint32_t> &regs, GetFn gain_fn,\n+\t\t     GetFn exposureFn);\n+\n+\tMdParser::Status Parse(libcamera::Span<const uint8_t> buffer) override;\n+\tStatus GetExposureLines(unsigned int &lines) override;\n+\tStatus GetGainCode(unsigned int &gain_code) override;\n+\n+private:\n \t/*\n \t * Note that error codes > 0 are regarded as non-fatal; codes < 0\n \t * indicate a bad data buffer. Status codes are:\n@@ -138,8 +161,11 @@ protected:\n \t\tBAD_PADDING   = -5\n \t};\n \n-\tParseStatus findRegs(libcamera::Span<const uint8_t> buffer, uint32_t regs[],\n-\t\t\t     int offsets[], unsigned int num_regs);\n+\tParseStatus findRegs(libcamera::Span<const uint8_t> buffer);\n+\n+\tRegMap map_;\n+\tGetFn gain_fn_;\n+\tGetFn exposure_fn_;\n };\n \n } // namespace RPi\ndiff --git a/src/ipa/raspberrypi/md_parser_smia.cpp b/src/ipa/raspberrypi/md_parser_smia.cpp\nindex 65ffbe00c76e..f4748dd535d0 100644\n--- a/src/ipa/raspberrypi/md_parser_smia.cpp\n+++ b/src/ipa/raspberrypi/md_parser_smia.cpp\n@@ -8,9 +8,11 @@\n #include <map>\n #include <string>\n \n+#include \"libcamera/internal/log.h\"\n #include \"md_parser.hpp\"\n \n using namespace RPiController;\n+using namespace libcamera;\n \n /*\n  * This function goes through the embedded data to find the offsets (not\n@@ -28,18 +30,79 @@ constexpr unsigned int REG_LOW_BITS = 0xa5;\n constexpr unsigned int REG_VALUE = 0x5a;\n constexpr unsigned int REG_SKIP = 0x55;\n \n-MdParserSmia::ParseStatus MdParserSmia::findRegs(libcamera::Span<const uint8_t> buffer,\n-\t\t\t\t\t\t uint32_t regs[], int offsets[],\n-\t\t\t\t\t\t unsigned int num_regs)\n+MdParserSmia::MdParserSmia(const std::vector<uint32_t> &registers,\n+\t\t\t   GetFn gain_fn, GetFn exposure_fn)\n+\t: gain_fn_(gain_fn), exposure_fn_(exposure_fn)\n {\n-\tassert(num_regs > 0);\n+\tfor (auto r : registers)\n+\t\tmap_[r] = {};\n+}\n+\n+MdParser::Status MdParserSmia::Parse(libcamera::Span<const uint8_t> buffer)\n+{\n+\tif (reset_) {\n+\t\t/*\n+\t\t * Search again through the metadata for the gain and exposure\n+\t\t * registers.\n+\t\t */\n+\t\tASSERT(bits_per_pixel_);\n+\n+\t\tParseStatus ret = findRegs(buffer);\n+\t\t/*\n+\t\t * > 0 means \"worked partially but parse again next time\",\n+\t\t * < 0 means \"hard error\".\n+\t\t *\n+\t\t * In either case, we retry parsing on the next frame.\n+\t\t */\n+\t\tif (ret != PARSE_OK)\n+\t\t\treturn ERROR;\n+\n+\t\treset_ = false;\n+\t}\n+\n+\t/* Populate the register values requested. */\n+\tfor (auto &kv : map_) {\n+\t\tRegister &reg = kv.second;\n+\n+\t\tif (!reg.found) {\n+\t\t\treset_ = true;\n+\t\t\treturn NOTFOUND;\n+\t\t}\n+\n+\t\treg.value = buffer[reg.offset];\n+\t}\n+\n+\treturn OK;\n+}\n+\n+MdParser::Status MdParserSmia::GetExposureLines(unsigned int &lines)\n+{\n+\tif (reset_)\n+\t\treturn NOTFOUND;\n+\n+\tlines = exposure_fn_(map_);\n+\treturn OK;\n+}\n+\n+MdParser::Status MdParserSmia::GetGainCode(unsigned int &gain_code)\n+{\n+\tif (reset_)\n+\t\treturn NOTFOUND;\n+\n+\tgain_code = gain_fn_(map_);\n+\treturn OK;\n+}\n+\n+MdParserSmia::ParseStatus MdParserSmia::findRegs(libcamera::Span<const uint8_t> buffer)\n+{\n+\tASSERT(map_.size());\n \n \tif (buffer[0] != LINE_START)\n \t\treturn NO_LINE_START;\n \n \tunsigned int current_offset = 1; /* after the LINE_START */\n \tunsigned int current_line_start = 0, current_line = 0;\n-\tunsigned int reg_num = 0, first_reg = 0;\n+\tunsigned int reg_num = 0, regs_done = 0;\n \n \twhile (1) {\n \t\tint tag = buffer[current_offset++];\n@@ -73,8 +136,8 @@ MdParserSmia::ParseStatus MdParserSmia::findRegs(libcamera::Span<const uint8_t>\n \t\t\t\t\treturn NO_LINE_START;\n \t\t\t} else {\n \t\t\t\t/* allow a zero line length to mean \"hunt for the next line\" */\n-\t\t\t\twhile (buffer[current_offset] != LINE_START &&\n-\t\t\t\t       current_offset < buffer.size())\n+\t\t\t\twhile (current_offset < buffer.size() &&\n+\t\t\t\t       buffer[current_offset] != LINE_START)\n \t\t\t\t\tcurrent_offset++;\n \n \t\t\t\tif (current_offset == buffer.size())\n@@ -91,13 +154,13 @@ MdParserSmia::ParseStatus MdParserSmia::findRegs(libcamera::Span<const uint8_t>\n \t\t\telse if (tag == REG_SKIP)\n \t\t\t\treg_num++;\n \t\t\telse if (tag == REG_VALUE) {\n-\t\t\t\twhile (reg_num >=\n-\t\t\t\t       /* assumes registers are in order... */\n-\t\t\t\t       regs[first_reg]) {\n-\t\t\t\t\tif (reg_num == regs[first_reg])\n-\t\t\t\t\t\toffsets[first_reg] = current_offset - 1;\n+\t\t\t\tauto reg = map_.find(reg_num);\n+\n+\t\t\t\tif (reg != map_.end()) {\n+\t\t\t\t\tmap_[reg_num].offset = current_offset - 1;\n+\t\t\t\t\tmap_[reg_num].found = true;\n \n-\t\t\t\t\tif (++first_reg == num_regs)\n+\t\t\t\t\tif (++regs_done == map_.size())\n \t\t\t\t\t\treturn PARSE_OK;\n \t\t\t\t}\n \t\t\t\treg_num++;\n","prefixes":["libcamera-devel","6/6"]}