[{"id":38839,"web_url":"https://patchwork.libcamera.org/comment/38839/","msgid":"<20260510170122.GD2386704@killaraus.ideasonboard.com>","date":"2026-05-10T17:01:22","subject":"Re: [PATCH v2 3/3] utils: tuning: Add AIQB parser for Intel IPU6\n\tsensors","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Javier,\n\nOn Fri, May 08, 2026 at 10:53:36AM -0600, Javier Tia wrote:\n> Add a Python script to extract CCMs and AWB chromaticity limits from\n> Intel AIQB binary calibration files, producing a ready-to-use\n> libcamera Simple IPA tuning YAML.\n> \n> AIQB is Intel's proprietary calibration format shipped with Windows\n> camera drivers for Intel IPU6 sensors. Files for Alder Lake and Tiger\n> Lake sensors are available in the ipu6-camera-hal repository under\n> config/linux/ipu6ep/, or can be extracted from OEM Windows driver\n> installers using p7zip and innoextract.\n> \n> The script supports record id=25 (advanced color matrices, float\n> format with CCT in Kelvin directly) and falls back to record id=18\n> (integer matrices with autodetected scale). Record id=25 is preferred\n> and present in all Alder Lake AIQB files examined.\n> \n> Tested against OV2740_CJFLE23_ADL.aiqb (Lenovo ThinkPad X1 Carbon\n> Gen 10, extracted from n3ace31w.exe). Other AIQB files may require\n> adjustments if the record layout differs.\n> \n> Signed-off-by: Javier Tia <floss@jetm.me>\n> ---\n>  utils/tuning/parse_aiqb.py | 276 +++++++++++++++++++++++++++++++++++++\n>  1 file changed, 276 insertions(+)\n>  create mode 100644 utils/tuning/parse_aiqb.py\n> \n> diff --git a/utils/tuning/parse_aiqb.py b/utils/tuning/parse_aiqb.py\n> new file mode 100644\n> index 00000000..12948f75\n> --- /dev/null\n> +++ b/utils/tuning/parse_aiqb.py\n> @@ -0,0 +1,276 @@\n> +#!/usr/bin/env python3\n> +# SPDX-License-Identifier: GPL-2.0-or-later\n> +#\n> +# Parse an Intel AIQB (CPFF) binary to extract CCMs and AWB chromaticity\n> +# limits for use in a libcamera Simple IPA tuning YAML file.\n> +#\n> +# Tested against OV2740_CJFLE23_ADL.aiqb (Alder Lake, Intel ipu6-camera-hal).\n> +# Other sensors and AIQB versions may require adjustments to the record\n> +# layout assumptions.\n> +#\n> +# AIQB files for Intel IPU6 sensors are available in the ipu6-camera-hal\n> +# repository at config/linux/ipu6ep/. Alternatively, extract from the OEM\n> +# Windows camera driver installer using p7zip and innoextract.\n> +#\n> +# Usage:\n> +#   python3 parse_aiqb.py <sensor>.aiqb [--sensor-name <name>] \\\n> +#       [--black-level <value>]\n> +#\n\nPart of this text is redundant, it's included in the help text (in\nargparse) below.\n\nIt would be useful to indicate somewhere, here or in the commit message,\nwhere you found information about the file format.\n\n> +# The black level is NOT extracted from the AIQB. Pass --black-level with the\n> +# sensor's black level in 16-bit convention (value >> 8 = 8-bit black level).\n> +# Check the sensor datasheet or kernel driver for the correct value.\n> +# Example: OV2740 has 0x40 at 10-bit (64 ADU), which is 4096 in 16-bit conv.\n\nThe black level should really be specified in the CameraSensorHelper, so\nI'd avoid handling it here.\n\n> +import argparse\n> +import os\n> +import struct\n> +import sys\n> +\n> +# ia_mkn_record_header: size(u32), fmt_id(u8), key_id(u8), name_id(u16)\n> +REC_HDR = struct.Struct('<IBBH')\n> +REC_HDR_SIZE = 8\n> +\n> +# cmc_name_id enum values\n> +CMC_GENERAL_DATA       = 2\n> +CMC_SENSITIVITY        = 7\n> +CMC_COLOR_MATRICES     = 18\n> +CMC_ADV_COLOR_MATRICES = 25\n> +\n> +# cmc_color_matrix_t (84 bytes):\n> +#   int32 light_src_type\n> +#   uint16 r_per_g, b_per_g\n> +#   uint16 cie_x, cie_y\n> +#   int32 matrix_accurate[9]\n> +#   int32 matrix_preferred[9]\n> +COLOR_MATRIX = struct.Struct('<i HH HH 9i 9i')\n\nIs there any facility in Python to deserialize a C struct into a data\nclass (with named fields) instead of a tuple ?\n\n> +assert COLOR_MATRIX.size == 84\n> +\n> +# Light source enum -> approximate CCT in Kelvin\n> +LIGHT_SOURCE_CCT = {\n> +    1:  2856,   # A - Incandescent/Tungsten\n> +    4:  5003,   # D50\n> +    5:  5503,   # D55\n> +    6:  6504,   # D65\n> +    7:  7504,   # D75\n> +    8:  5454,   # E (equal energy)\n> +    9:  6430,   # F1 daylight fluorescent\n> +    10: 4230,   # F2 cool white\n> +    11: 3450,   # F3 white\n> +    12: 3000,   # F4 warm white\n> +    13: 6350,   # F5\n> +    14: 4150,   # F6\n> +    15: 6500,   # F7 D65 sim\n> +    16: 5000,   # F8 D50 sim\n> +    17: 4150,   # F9\n> +    18: 5000,   # F10\n> +    19: 4000,   # F11\n> +    20: 3000,   # F12\n> +    22: 2300,   # HZ horizon\n> +}\n> +\n> +# Record chain starts here in all AIQB files checked so far\n> +FIRST_RECORD_OFFSET = 0x50\n> +\n> +def walk_records(data):\n> +    records = {}\n> +    offset = FIRST_RECORD_OFFSET\n> +    while offset + REC_HDR_SIZE <= len(data):\n> +        size, fmt_id, key_id, name_id = REC_HDR.unpack_from(data, offset)\n> +        if size < REC_HDR_SIZE or offset + size > len(data):\n> +            break\n> +        records[name_id] = (offset, size)\n> +        offset += size\n> +    return records\n> +\n> +def extract_general_data(data, offset):\n> +    w, h, bd, co = struct.unpack_from('<HHHH', data, offset + REC_HDR_SIZE)\n> +    return {'width': w, 'height': h, 'bit_depth': bd, 'color_order': co}\n> +\n> +def extract_sensitivity(data, offset):\n> +    iso, = struct.unpack_from('<H', data, offset + REC_HDR_SIZE)\n> +    return iso\n> +\n> +def extract_color_matrices(data, offset):\n> +    num, = struct.unpack_from('<H', data, offset + REC_HDR_SIZE)\n> +    matrices = []\n> +    mat_offset = offset + REC_HDR_SIZE + 2\n> +    for i in range(num):\n> +        fields = COLOR_MATRIX.unpack_from(data, mat_offset + i * 84)\n> +        light_src = fields[0]\n> +        matrices.append({\n> +            'light_src': light_src,\n> +            'cct': LIGHT_SOURCE_CCT.get(light_src),\n> +            'r_per_g_raw': fields[1],\n> +            'b_per_g_raw': fields[2],\n> +            'matrix_raw': fields[5:14],\n> +        })\n> +    return matrices\n> +\n> +def extract_advanced_color_matrices(data, offset):\n> +    \"\"\"Parse cmc_advanced_color_matrix_correction (record id=25).\n> +\n> +    Layout after the 8-byte record header:\n> +      uint16  num_light_srcs\n> +      uint16  num_sectors\n> +      uint32  hue_of_sectors[num_sectors]\n> +      Per light source (24-byte cmc_acm_color_matrices_info_v101_t):\n> +        uint32  src_type\n> +        float   r_per_g\n> +        float   b_per_g\n> +        float   cie_x\n> +        float   cie_y\n> +        uint32  cct              (Kelvin, directly)\n> +        float   traditional[9]   (3x3 CCM, rows sum to 1.0)\n> +        float   advanced[num_sectors][9]   (per-sector CCMs, skipped)\n> +    \"\"\"\n> +    pos = offset + REC_HDR_SIZE\n> +    num_ls, num_sectors = struct.unpack_from('<HH', data, pos)\n> +    pos += 4\n> +    pos += num_sectors * 4  # skip hue_of_sectors\n> +\n> +    INFO = struct.Struct('<IffffI')  # 24 bytes\n> +    CCM  = struct.Struct('<9f')     # 36 bytes\n> +\n> +    matrices = []\n> +    for _ in range(num_ls):\n> +        src_type, rg, bg, cie_x, cie_y, cct_k = INFO.unpack_from(data, pos)\n> +        pos += 24\n> +        trad = CCM.unpack_from(data, pos)\n> +        pos += 36\n> +        pos += num_sectors * 36  # skip per-sector advanced CCMs\n> +        matrices.append({\n> +            'light_src': src_type,\n> +            'cct': cct_k,\n> +            'r_per_g': rg,\n> +            'b_per_g': bg,\n> +            'matrix_float': trad,\n> +        })\n> +    return matrices\n> +\n> +def guess_ccm_scale(matrices):\n> +    for scale in (8192, 4096, 2048, 1024):\n> +        errors = []\n> +        for m in matrices:\n> +            for row in range(3):\n> +                s = sum(m['matrix_raw'][row * 3:(row + 1) * 3]) / scale\n> +                errors.append(abs(s - 1.0))\n> +        if max(errors) < 0.05:\n> +            return scale\n> +    return 8192\n> +\n> +def format_ccm(vals):\n> +    rows = []\n> +    for row in range(3):\n> +        r = vals[row * 3:(row + 1) * 3]\n> +        rows.append(f\"          {r[0]:8.4f}, {r[1]:8.4f}, {r[2]:8.4f}\")\n> +    return '[\\n' + ',\\n'.join(rows) + ' ]'\n> +\n> +def main():\n> +    parser = argparse.ArgumentParser(\n> +        description='Parse Intel AIQB binary for libcamera Simple IPA YAML',\n> +        epilog='Tested on OV2740_CJFLE23_ADL.aiqb only. Other sensors may '\n> +               'require adjustments.')\n> +    parser.add_argument('aiqb', help='Path to .aiqb file')\n> +    parser.add_argument('--sensor-name',\n> +                        help='Sensor name for YAML output (default: derived '\n> +                             'from filename)')\n> +    parser.add_argument('--black-level', type=int, default=0,\n> +                        help='Black level in 16-bit convention, e.g. 4096 for '\n> +                             'OV2740 (default: 0 = unknown, emits placeholder)')\n> +    parser.add_argument('--ccm-scale', type=int, default=0,\n> +                        help='Integer CCM scale for record id=18 (0=autodetect)')\n> +    args = parser.parse_args()\n> +\n> +    sensor_name = args.sensor_name or os.path.basename(args.aiqb).split('_')[0].lower()\n> +\n> +    with open(args.aiqb, 'rb') as f:\n> +        data = f.read()\n> +\n> +    print(f\"File: {args.aiqb} ({len(data)} bytes)\")\n> +\n> +    records = walk_records(data)\n> +    print(f\"Records found: {sorted(records.keys())}\\n\")\n> +\n> +    if CMC_GENERAL_DATA in records:\n> +        gd = extract_general_data(data, records[CMC_GENERAL_DATA][0])\n> +        print(f\"Sensor: {gd['width']}x{gd['height']}, {gd['bit_depth']}-bit, \"\n> +              f\"color_order={gd['color_order']}\")\n> +\n> +    if CMC_SENSITIVITY in records:\n> +        iso = extract_sensitivity(data, records[CMC_SENSITIVITY][0])\n> +        print(f\"Base ISO: {iso}\")\n> +\n> +    adv_mode = False\n> +    if CMC_ADV_COLOR_MATRICES in records:\n> +        matrices = extract_advanced_color_matrices(data, records[CMC_ADV_COLOR_MATRICES][0])\n> +        adv_mode = True\n> +        print(f\"\\nAdvanced color matrices (id=25, {len(matrices)} entries, float CCMs):\")\n> +    elif CMC_COLOR_MATRICES in records:\n> +        matrices = extract_color_matrices(data, records[CMC_COLOR_MATRICES][0])\n> +        print(f\"\\nColor matrices (id=18, {len(matrices)} entries):\")\n> +    else:\n> +        print(\"ERROR: no color_matrices record found (id=18 or id=25)\")\n> +        sys.exit(1)\n> +\n> +    ccm_scale = args.ccm_scale or (1 if adv_mode else guess_ccm_scale(matrices))\n> +\n> +    valid_matrices = []\n> +    for m in matrices:\n> +        cct = m['cct']\n> +        if not cct:\n> +            continue\n> +        if adv_mode:\n> +            vals = list(m['matrix_float'])\n> +            rg = m['r_per_g']\n> +            bg = m['b_per_g']\n> +        else:\n> +            vals = [v / ccm_scale for v in m['matrix_raw']]\n> +            rg = m['r_per_g_raw'] / 256.0\n> +            bg = m['b_per_g_raw'] / 256.0\n> +        row_sums = [sum(vals[r * 3:(r + 1) * 3]) for r in range(3)]\n> +        if max(abs(s - 1.0) for s in row_sums) > 0.05:\n> +            print(f\"  WARNING: CCT={cct}K row sums {[round(s, 4) for s in row_sums]}\")\n> +        print(f\"  CCT={cct}K  R/G={rg:.4f}  B/G={bg:.4f}\")\n> +        valid_matrices.append((cct, vals, rg, bg))\n> +\n> +    max_gain_r = max_gain_b = None\n> +    if valid_matrices:\n> +        min_rg = min(m[2] for m in valid_matrices)\n> +        min_bg = min(m[3] for m in valid_matrices)\n> +        max_gain_r = round((1.0 / min_rg) * 1.1, 2) if min_rg > 0 else 2.5\n> +        max_gain_b = round((1.0 / min_bg) * 1.1, 2) if min_bg > 0 else 3.2\n> +        print(f\"\\nSuggested AWB maxGainR={max_gain_r}, maxGainB={max_gain_b} \"\n> +              f\"(from min R/G={min_rg:.4f}, min B/G={min_bg:.4f})\")\n> +\n> +    aiqb_name = os.path.basename(args.aiqb)\n> +    print(\"\\n\" + \"=\" * 60)\n> +    print(f\"# {sensor_name}.yaml for libcamera Simple IPA\")\n> +    print(\"# SPDX-License-Identifier: CC0-1.0\")\n> +    print(f\"# Calibrated from {aiqb_name}\")\n> +    print(\"%YAML 1.1\")\n> +    print(\"---\")\n\nWriting YAML by hand is not a very good practice. Could you instead use\na YAML library ?\n\nThe script should probably output the YAML data to a file, to\ndifferentiate them from all the messages printed above.\n\n> +    print(\"version: 1\")\n> +    print(\"algorithms:\")\n> +    print(\"  - BlackLevel:\")\n> +    if args.black_level:\n> +        print(f\"      blackLevel: {args.black_level}\")\n> +    else:\n> +        print(\"      blackLevel: 0  # TODO: set correct value from sensor datasheet\")\n> +    print(\"  - Awb:\")\n> +    print(f\"      maxGainR: {max_gain_r}\")\n> +    print(f\"      maxGainB: {max_gain_b}\")\n> +    print(\"      speed: 0.25\")\n> +    print(\"  - Ccm:\")\n> +    print(\"      ccms:\")\n> +    for cct, vals, rg, bg in sorted(valid_matrices):\n> +        print(f\"        - ct: {cct}\")\n> +        print(f\"          ccm: {format_ccm(vals)}\")\n> +    print(\"  - Adjust:\")\n> +    print(\"      gamma: 2.2\")\n> +    print(\"      contrast: 1.0\")\n> +    print(\"      saturation: 1.0\")\n> +    print(\"  - Agc:\")\n> +    print(\"...\")\n> +\n> +if __name__ == '__main__':\n> +    main()","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 1366FBDCBD\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSun, 10 May 2026 17:01:27 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id BB5056301E;\n\tSun, 10 May 2026 19:01:25 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 4AA3D62E6A\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 10 May 2026 19:01:24 +0200 (CEST)","from killaraus.ideasonboard.com\n\t(2001-14ba-70f3-e800--a06.rev.dnainternet.fi\n\t[IPv6:2001:14ba:70f3:e800::a06])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 7C5BE191A;\n\tSun, 10 May 2026 19:01:17 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"r5m9jmxl\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1778432477;\n\tbh=YLwjcyUoYe4giC2y1abeijqoFRVAKoANmN6BrVrEZu0=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=r5m9jmxl6nxLYSPqU+3FR18e24igP0d/HHAxM26+obtSN7zeh0fn9JycBMNrnFKqQ\n\tB0qK9zoHOXxYttekswzbGMC1+VzrfsvqjLsuC+AFCV31Gjk2BzxNs4gsJQRPwx9mBl\n\tqIeJtAxmKZZGLzs/tkROJkjxuZPl596LNCX8HMXQ=","Date":"Sun, 10 May 2026 20:01:22 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Javier Tia <floss@jetm.me>","Cc":"libcamera-devel@lists.libcamera.org, mzamazal@redhat.com,\n\tkieran.bingham@ideasonboard.com, barnabas.pocze@ideasonboard.com,\n\tjohannes.goede@oss.qualcomm.com, robert.mader@collabora.com","Subject":"Re: [PATCH v2 3/3] utils: tuning: Add AIQB parser for Intel IPU6\n\tsensors","Message-ID":"<20260510170122.GD2386704@killaraus.ideasonboard.com>","References":"<177826063718.39714.13674874482653763631@jetm.me>\n\t<20260508171724.201811EA006C@mailuser.phl.internal>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20260508171724.201811EA006C@mailuser.phl.internal>","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>"}},{"id":38859,"web_url":"https://patchwork.libcamera.org/comment/38859/","msgid":"<20260511190516.CF0801EA006B@mailuser.phl.internal>","date":"2026-05-11T16:33:47","subject":"Re: [PATCH v2 3/3] utils: tuning: Add AIQB parser for Intel IPU6\n\tsensors","submitter":{"id":261,"url":"https://patchwork.libcamera.org/api/people/261/","name":"Javier Tia","email":"floss@jetm.me"},"content":"Hi Laurent,\n\nThank you for the review. All addressed in v3.\n\nOn Sun, May 10, 2026 at 17:01:30 +0000, Laurent Pinchart wrote:\n> > +# Parse an Intel AIQB (CPFF) binary to extract CCMs and AWB chromaticity\n> > +# limits for use in a libcamera Simple IPA tuning YAML file.\n> > +#\n> > +# Tested against OV2740_CJFLE23_ADL.aiqb (Alder Lake, Intel ipu6-camera-hal).\n> > +# Other sensors and AIQB versions may require adjustments to the record\n> > +# layout assumptions.\n> > +#\n> > +# AIQB files for Intel IPU6 sensors are available in the ipu6-camera-hal\n> > +# repository at config/linux/ipu6ep/. Alternatively, extract from the OEM\n> > +# Windows camera driver installer using p7zip and innoextract.\n> > +#\n> > +# Usage:\n> > +#   python3 parse_aiqb.py <sensor>.aiqb [--sensor-name <name>] \\\n> > +#       [--black-level <value>]\n> > +#\n>\n> Part of this text is redundant, it's included in the help text (in\n> argparse) below.\n>\n> It would be useful to indicate somewhere, here or in the commit message,\n> where you found information about the file format.\n\nTightened the docstring to drop the Usage block and the per-sensor\ncaveats already in the argparse description/epilog. Added a line citing\nipu6-camera-hal's ia_cmc_types.h as the format source:\n\n  # Format reverse-engineered from ipu6-camera-hal headers\n  # (ia_cmc_types.h).\n\n> > +# The black level is NOT extracted from the AIQB. Pass --black-level with the\n> > +# sensor's black level in 16-bit convention (value >> 8 = 8-bit black level).\n> > +# Check the sensor datasheet or kernel driver for the correct value.\n> > +# Example: OV2740 has 0x40 at 10-bit (64 ADU), which is 4096 in 16-bit conv.\n>\n> The black level should really be specified in the CameraSensorHelper, so\n> I'd avoid handling it here.\n\nDropped the --black-level CLI flag entirely. The emitted YAML still\nincludes a BlackLevel algorithm block, but the script now just prints\na note after writing the file telling the user to fill it in from the\nsensor's CameraSensorHelper entry. The OV2740 entry for that already\nlanded in v5 of the AGC series.\n\n> > +COLOR_MATRIX = struct.Struct('<i HH HH 9i 9i')\n>\n> Is there any facility in Python to deserialize a C struct into a data\n> class (with named fields) instead of a tuple ?\n\nSwitched to a @dataclass ColorMatrixRecord populated explicitly from\nthe tuple returned by struct.Struct.unpack_from. struct itself stops\nat tuples, but the dataclass layer makes the field names visible at\nthe call site:\n\n  @dataclass\n  class ColorMatrixRecord:\n      light_src_type: int\n      r_per_g_raw: int\n      ...\n\n  unpacked = COLOR_MATRIX.unpack_from(data, ...)\n  rec = ColorMatrixRecord(light_src_type=unpacked[0],\n                          r_per_g_raw=unpacked[1], ...)\n\n[...]\n\n> > +    print(\"\\n\" + \"=\" * 60)\n> > +    print(f\"# {sensor_name}.yaml for libcamera Simple IPA\")\n> > +    print(\"# SPDX-License-Identifier: CC0-1.0\")\n> > +    print(f\"# Calibrated from {aiqb_name}\")\n> > +    print(\"%YAML 1.1\")\n> > +    print(\"---\")\n> [...]\n>\n> Writing YAML by hand is not a very good practice. Could you instead use\n> a YAML library ?\n>\n> The script should probably output the YAML data to a file, to\n> differentiate them from all the messages printed above.\n\nSwitched to PyYAML. Built a doc dict and pass it through yaml.dump\nwith a Dumper subclass that flow-formats the colourGains/CCM rows on a\nsingle line (keeping the existing inline layout). The result is now\nwritten to <sensor>.yaml; the diagnostic prints remain on stdout so\nthey don't have to be filtered out.","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 E5A03BDB1C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 11 May 2026 19:05:21 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 18B0363025;\n\tMon, 11 May 2026 21:05:21 +0200 (CEST)","from fout-b2-smtp.messagingengine.com\n\t(fout-b2-smtp.messagingengine.com [202.12.124.145])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 996DA62DC4\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 11 May 2026 21:05:19 +0200 (CEST)","from phl-compute-02.internal (phl-compute-02.internal\n\t[10.202.2.42])\n\tby mailfout.stl.internal (Postfix) with ESMTP id C26631D0010C;\n\tMon, 11 May 2026 15:05:17 -0400 (EDT)","from phl-imap-07 ([10.202.2.97])\n\tby phl-compute-02.internal (MEProxy); Mon, 11 May 2026 15:05:18 -0400","by mailuser.phl.internal (Postfix, from userid 501)\n\tid CF0801EA006B; Mon, 11 May 2026 15:05:16 -0400 (EDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=jetm.me header.i=@jetm.me header.b=\"NPHZqRUL\";\n\tdkim=pass (2048-bit key;\n\tunprotected) header.d=messagingengine.com\n\theader.i=@messagingengine.com header.b=\"HiuQbbH9\"; \n\tdkim-atps=neutral","DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/relaxed; d=jetm.me; h=cc:cc\n\t:content-transfer-encoding:content-type:content-type:date:date\n\t:from:from:in-reply-to:in-reply-to:message-id:mime-version\n\t:references:reply-to:subject:subject:to:to; s=fm2; t=1778526317;\n\tx=1778612717; bh=zCg5tM5YJcyd0rsr0vZAfDyOYPpB/jlKa5IFPw6qYMw=; b=\n\tNPHZqRUL4jVjCGXYlnZL5VDqOTvjpfNKOupqZoo1IK7IF8ZSmDpf+SJL/pfWGD8O\n\tepsiLIVbXcgJ4JZ62buJRAMhKR9hyzVILHD1Yb+Y92z62/MNw580Q+isznW97IRw\n\toPOgBGgJuxQdQ4ujsEA7X0ofpa012TJNAz7AZNVPOM7OvpF6yPJ9RLmAgCSbxNMl\n\tDGe1myJFXuyC6o6Gt1CEf/VH0uQqdDYn+yPDhH8lwfWar8wLz2KnLejQnJjv0Ovn\n\t4wTsSfU0M/MFnhxMPtB/UNPLsZeaf1BzLrRsLx5lLoEE3g728AWdrDZXEAqFI61k\n\tj2r7Eh75QgbcqV54AK4eRQ==","v=1; a=rsa-sha256; c=relaxed/relaxed; d=\n\tmessagingengine.com; h=cc:cc:content-transfer-encoding\n\t:content-type:content-type:date:date:feedback-id:feedback-id\n\t:from:from:in-reply-to:in-reply-to:message-id:mime-version\n\t:references:reply-to:subject:subject:to:to:x-me-proxy\n\t:x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t=1778526317; x=\n\t1778612717; bh=zCg5tM5YJcyd0rsr0vZAfDyOYPpB/jlKa5IFPw6qYMw=; b=H\n\tiuQbbH9XOK12SoUvvhSNj7cRTR3uJHbf8SBW0Fq70YvbspAbhdoFEujU3djXf/lw\n\tSF9hl8UZB1fvZmYzxMRREdxtSGXkqfpufT2TbAZFnzI2CqI4f1AQdj9vBtoyQf7+\n\ttJSuNZG/pfeNCjemAcQxdlBHRpTOshA4ly8nb/OXqh+jwkYxhBAWmFj5LuwDw4a9\n\tE2aMgMWAc0TSD6tYitTB2y2gri6hHb711EuZAU2yCXwPlssjGW29f1do0q6VN+oh\n\t6Fm6KrEau5dEuUWLFVmtISUG0AsUluhFf4P7RIrf9WlpuYk+UbA0LqPaZ8cK4xUo\n\ta1rmem7QwFyMQFaBLPr/w=="],"X-ME-Sender":"<xms:bCgCarzgP_Qsb7d-_iUNJ1M6XUulaIHbG6Nmj9GVAGj1wTRokbpJ2A>\n\t<xme:bCgCauFr-nOaAkOwz86QqFEd5pNxN_FJR1xIcjn_jBFHmpIskGB_UWqMLkMDGUqIR\n\tbU5_PItKyYNRBiYGkR0IBegY5n0zkM4TugIvKbY44loH6Xf23i3WRQ>","X-ME-Proxy-Cause":"gggruggvucftvghtrhhoucdtuddrgeefhedrtddtgdduudeljedvucetufdoteggodetrf\n\tdotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu\n\trghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmnegopf\n\thokfffucdluddtmdenucfjughrpefotggggffhvfffufevjghfsehtkedttdertdejnecu\n\thfhrohhmpeflrghvihgvrhcuvfhirgcuoehflhhoshhssehjvghtmhdrmhgvqeenucggtf\n\tfrrghtthgvrhhnpedtudejffejkeekteelueefvdejvdeuhfefteehkeevtddvleduteek\n\tleetvdelhfenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhroh\n\thmpehflhhoshhssehjvghtmhdrmhgvpdhnsggprhgtphhtthhopeekpdhmohguvgepshhm\n\tthhpohhuthdprhgtphhtthhopehrohgsvghrthdrmhgruggvrhestgholhhlrggsohhrrg\n\tdrtghomhdprhgtphhtthhopegsrghrnhgrsggrshdrphhotgiivgesihguvggrshhonhgs\n\tohgrrhgurdgtohhmpdhrtghpthhtohepkhhivghrrghnrdgsihhnghhhrghmsehiuggvrg\n\thsohhnsghorghrugdrtghomhdprhgtphhtthhopehlrghurhgvnhhtrdhpihhntghhrghr\n\tthesihguvggrshhonhgsohgrrhgurdgtohhmpdhrtghpthhtohepfhhlohhsshesjhgvth\n\thmrdhmvgdprhgtphhtthhopehlihgstggrmhgvrhgrqdguvghvvghlsehlihhsthhsrdhl\n\tihgstggrmhgvrhgrrdhorhhgpdhrtghpthhtohepjhhohhgrnhhnvghsrdhgohgvuggvse\n\thoshhsrdhquhgrlhgtohhmmhdrtghomhdprhgtphhtthhopehmiigrmhgriigrlhesrhgv\n\tughhrghtrdgtohhm","X-ME-Proxy":"<xmx:bCgCaqx3aHiD15Ey6VEXvnG8OnMl8omk18xXuto85ddV4yUFz-Fu1w>\n\t<xmx:bCgCaiR6R3sy5yFz7UKjRXwxowaDxTEh3rKODuHPPxzp3vArFYEmJQ>\n\t<xmx:bCgCauipHglyIVYjZANV6yYjDoXSD-TEw-AyBZTcL59RXkOSlydB9Q>\n\t<xmx:bCgCahmoSHOlXa7lPVeOhC6WKd4l-cXYs297G7defjb9ic63CQywzA>\n\t<xmx:bSgCagCs3r7ywR9yUX5IHV5NPgJC_EPFhUmH8eyz3pMDKa9CR6tksWNO>","Feedback-ID":"i9dde48b3:Fastmail","X-Mailer":"MessagingEngine.com Webmail Interface","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","From":"Javier Tia <floss@jetm.me>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Date":"Mon, 11 May 2026 10:33:47 -0600","Subject":"Re: [PATCH v2 3/3] utils: tuning: Add AIQB parser for Intel IPU6\n\tsensors","Cc":"libcamera-devel@lists.libcamera.org, mzamazal@redhat.com,\n\tkieran.bingham@ideasonboard.com, barnabas.pocze@ideasonboard.com,\n\tjohannes.goede@oss.qualcomm.com, robert.mader@collabora.com","In-Reply-To":"<20260510170122.GD2386704@killaraus.ideasonboard.com>","References":"<177826063718.39714.13674874482653763631@jetm.me>\n\t<20260508171724.201811EA006C@mailuser.phl.internal>\n\t<20260510170122.GD2386704@killaraus.ideasonboard.com>","Message-Id":"<20260511190516.CF0801EA006B@mailuser.phl.internal>","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>"}}]